summaryrefslogtreecommitdiffstats
path: root/ldb/ldb_map/ldb_map_outbound.c
diff options
context:
space:
mode:
Diffstat (limited to 'ldb/ldb_map/ldb_map_outbound.c')
-rw-r--r--ldb/ldb_map/ldb_map_outbound.c1364
1 files changed, 0 insertions, 1364 deletions
diff --git a/ldb/ldb_map/ldb_map_outbound.c b/ldb/ldb_map/ldb_map_outbound.c
deleted file mode 100644
index 5588eaaf4..000000000
--- a/ldb/ldb_map/ldb_map_outbound.c
+++ /dev/null
@@ -1,1364 +0,0 @@
-/*
- ldb database mapping module
-
- Copyright (C) Jelmer Vernooij 2005
- Copyright (C) Martin Kuehl <mkhl@samba.org> 2006
- Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
- Copyright (C) Simo Sorce <idra@samba.org> 2008
-
- ** NOTE! The following LGPL license applies to the ldb
- ** library. This does NOT imply that all of Samba is released
- ** under the LGPL
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 3 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, see <http://www.gnu.org/licenses/>.
-
-*/
-
-#include "ldb_includes.h"
-
-#include "ldb_map.h"
-#include "ldb_map_private.h"
-
-
-/* Mapping attributes
- * ================== */
-
-/* Select attributes that stay in the local partition. */
-static const char **map_attrs_select_local(struct ldb_module *module, void *mem_ctx, const char * const *attrs)
-{
- const struct ldb_map_context *data = map_get_context(module);
- const char **result;
- int i, last;
-
- if (attrs == NULL)
- return NULL;
-
- last = 0;
- result = talloc_array(mem_ctx, const char *, 1);
- if (result == NULL) {
- goto failed;
- }
- result[0] = NULL;
-
- for (i = 0; attrs[i]; i++) {
- /* Wildcards and ignored attributes are kept locally */
- if ((ldb_attr_cmp(attrs[i], "*") == 0) ||
- (!map_attr_check_remote(data, attrs[i]))) {
- result = talloc_realloc(mem_ctx, result, const char *, last+2);
- if (result == NULL) {
- goto failed;
- }
-
- result[last] = talloc_strdup(result, attrs[i]);
- result[last+1] = NULL;
- last++;
- }
- }
-
- return result;
-
-failed:
- talloc_free(result);
- map_oom(module);
- return NULL;
-}
-
-/* Collect attributes that are mapped into the remote partition. */
-static const char **map_attrs_collect_remote(struct ldb_module *module, void *mem_ctx,
- const char * const *attrs)
-{
- const struct ldb_map_context *data = map_get_context(module);
- const char **result;
- const struct ldb_map_attribute *map;
- const char *name=NULL;
- int i, j, last;
- int ret;
-
- last = 0;
- result = talloc_array(mem_ctx, const char *, 1);
- if (result == NULL) {
- goto failed;
- }
- result[0] = NULL;
-
- for (i = 0; attrs[i]; i++) {
- /* Wildcards are kept remotely, too */
- if (ldb_attr_cmp(attrs[i], "*") == 0) {
- const char **new_attrs = NULL;
- ret = map_attrs_merge(module, mem_ctx, &new_attrs, attrs);
- if (ret != LDB_SUCCESS) {
- goto failed;
- }
- ret = map_attrs_merge(module, mem_ctx, &new_attrs, data->wildcard_attributes);
- if (ret != LDB_SUCCESS) {
- goto failed;
- }
-
- attrs = new_attrs;
- break;
- }
- }
-
- for (i = 0; attrs[i]; i++) {
- /* Wildcards are kept remotely, too */
- if (ldb_attr_cmp(attrs[i], "*") == 0) {
- /* Add all 'include in wildcard' attributes */
- name = attrs[i];
- goto named;
- }
-
- /* Add remote names of mapped attrs */
- map = map_attr_find_local(data, attrs[i]);
- if (map == NULL) {
- continue;
- }
-
- switch (map->type) {
- case MAP_IGNORE:
- continue;
-
- case MAP_KEEP:
- name = attrs[i];
- goto named;
-
- case MAP_RENAME:
- case MAP_CONVERT:
- name = map->u.rename.remote_name;
- goto named;
-
- case MAP_GENERATE:
- /* Add all remote names of "generate" attrs */
- for (j = 0; map->u.generate.remote_names[j]; j++) {
- result = talloc_realloc(mem_ctx, result, const char *, last+2);
- if (result == NULL) {
- goto failed;
- }
-
- result[last] = talloc_strdup(result, map->u.generate.remote_names[j]);
- result[last+1] = NULL;
- last++;
- }
- continue;
- }
-
- named: /* We found a single remote name, add that */
- result = talloc_realloc(mem_ctx, result, const char *, last+2);
- if (result == NULL) {
- goto failed;
- }
-
- result[last] = talloc_strdup(result, name);
- result[last+1] = NULL;
- last++;
- }
-
- return result;
-
-failed:
- talloc_free(result);
- map_oom(module);
- return NULL;
-}
-
-/* Split attributes that stay in the local partition from those that
- * are mapped into the remote partition. */
-static int map_attrs_partition(struct ldb_module *module, void *mem_ctx, const char ***local_attrs, const char ***remote_attrs, const char * const *attrs)
-{
- *local_attrs = map_attrs_select_local(module, mem_ctx, attrs);
- *remote_attrs = map_attrs_collect_remote(module, mem_ctx, attrs);
-
- return 0;
-}
-
-/* Mapping message elements
- * ======================== */
-
-/* Add an element to a message, overwriting any old identically named elements. */
-static int ldb_msg_replace(struct ldb_message *msg, const struct ldb_message_element *el)
-{
- struct ldb_message_element *old;
-
- old = ldb_msg_find_element(msg, el->name);
-
- /* no local result, add as new element */
- if (old == NULL) {
- if (ldb_msg_add_empty(msg, el->name, 0, &old) != 0) {
- return -1;
- }
- talloc_free(discard_const_p(char, old->name));
- }
-
- /* copy new element */
- *old = *el;
-
- /* and make sure we reference the contents */
- if (!talloc_reference(msg->elements, el->name)) {
- return -1;
- }
- if (!talloc_reference(msg->elements, el->values)) {
- return -1;
- }
-
- return 0;
-}
-
-/* Map a message element back into the local partition. */
-static struct ldb_message_element *ldb_msg_el_map_remote(struct ldb_module *module,
- void *mem_ctx,
- const struct ldb_map_attribute *map,
- const char *attr_name,
- const struct ldb_message_element *old)
-{
- struct ldb_message_element *el;
- int i;
-
- el = talloc_zero(mem_ctx, struct ldb_message_element);
- if (el == NULL) {
- map_oom(module);
- return NULL;
- }
-
- el->values = talloc_array(el, struct ldb_val, old->num_values);
- if (el->values == NULL) {
- talloc_free(el);
- map_oom(module);
- return NULL;
- }
-
- el->name = talloc_strdup(el, attr_name);
- if (el->name == NULL) {
- talloc_free(el);
- map_oom(module);
- return NULL;
- }
-
- for (i = 0; i < old->num_values; i++) {
- el->values[i] = ldb_val_map_remote(module, el->values, map, &old->values[i]);
- /* Conversions might fail, in which case bail */
- if (!el->values[i].data) {
- talloc_free(el);
- return NULL;
- }
- el->num_values++;
- }
-
- return el;
-}
-
-/* Merge a remote message element into a local message. */
-static int ldb_msg_el_merge(struct ldb_module *module, struct ldb_message *local,
- struct ldb_message *remote, const char *attr_name)
-{
- const struct ldb_map_context *data = map_get_context(module);
- const struct ldb_map_attribute *map;
- struct ldb_message_element *old, *el=NULL;
- const char *remote_name = NULL;
-
- /* We handle wildcards in ldb_msg_el_merge_wildcard */
- if (ldb_attr_cmp(attr_name, "*") == 0) {
- return LDB_SUCCESS;
- }
-
- map = map_attr_find_local(data, attr_name);
-
- /* Unknown attribute in remote message:
- * skip, attribute was probably auto-generated */
- if (map == NULL) {
- return LDB_SUCCESS;
- }
-
- switch (map->type) {
- case MAP_IGNORE:
- break;
- case MAP_CONVERT:
- remote_name = map->u.convert.remote_name;
- break;
- case MAP_KEEP:
- remote_name = attr_name;
- break;
- case MAP_RENAME:
- remote_name = map->u.rename.remote_name;
- break;
- case MAP_GENERATE:
- break;
- }
-
- switch (map->type) {
- case MAP_IGNORE:
- return LDB_SUCCESS;
-
- case MAP_CONVERT:
- if (map->u.convert.convert_remote == NULL) {
- ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: "
- "Skipping attribute '%s': "
- "'convert_remote' not set\n",
- attr_name);
- return LDB_SUCCESS;
- }
- /* fall through */
- case MAP_KEEP:
- case MAP_RENAME:
- old = ldb_msg_find_element(remote, remote_name);
- if (old) {
- el = ldb_msg_el_map_remote(module, local, map, attr_name, old);
- } else {
- return LDB_ERR_NO_SUCH_ATTRIBUTE;
- }
- break;
-
- case MAP_GENERATE:
- if (map->u.generate.generate_local == NULL) {
- ldb_debug(module->ldb, LDB_DEBUG_ERROR, "ldb_map: "
- "Skipping attribute '%s': "
- "'generate_local' not set\n",
- attr_name);
- return LDB_SUCCESS;
- }
-
- el = map->u.generate.generate_local(module, local, attr_name, remote);
- if (!el) {
- /* Generation failure is probably due to lack of source attributes */
- return LDB_ERR_NO_SUCH_ATTRIBUTE;
- }
- break;
- }
-
- if (el == NULL) {
- return LDB_ERR_NO_SUCH_ATTRIBUTE;
- }
-
- return ldb_msg_replace(local, el);
-}
-
-/* Handle wildcard parts of merging a remote message element into a local message. */
-static int ldb_msg_el_merge_wildcard(struct ldb_module *module, struct ldb_message *local,
- struct ldb_message *remote)
-{
- const struct ldb_map_context *data = map_get_context(module);
- const struct ldb_map_attribute *map = map_attr_find_local(data, "*");
- struct ldb_message_element *el=NULL;
- int i, ret;
-
- /* Perhaps we have a mapping for "*" */
- if (map && map->type == MAP_KEEP) {
- /* We copy everything over, and hope that anything with a
- more specific rule is overwritten */
- for (i = 0; i < remote->num_elements; i++) {
- el = ldb_msg_el_map_remote(module, local, map, remote->elements[i].name,
- &remote->elements[i]);
- if (el == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- ret = ldb_msg_replace(local, el);
- if (ret) {
- return ret;
- }
- }
- }
-
- /* Now walk the list of possible mappings, and apply each */
- for (i = 0; data->attribute_maps[i].local_name; i++) {
- ret = ldb_msg_el_merge(module, local, remote,
- data->attribute_maps[i].local_name);
- if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
- continue;
- } else if (ret) {
- return ret;
- } else {
- continue;
- }
- }
-
- return LDB_SUCCESS;
-}
-
-/* Mapping messages
- * ================ */
-
-/* Merge two local messages into a single one. */
-static int ldb_msg_merge_local(struct ldb_module *module, struct ldb_message *msg1, struct ldb_message *msg2)
-{
- int i, ret;
-
- for (i = 0; i < msg2->num_elements; i++) {
- ret = ldb_msg_replace(msg1, &msg2->elements[i]);
- if (ret) {
- return ret;
- }
- }
-
- return LDB_SUCCESS;
-}
-
-/* Merge a local and a remote message into a single local one. */
-static int ldb_msg_merge_remote(struct map_context *ac, struct ldb_message *local,
- struct ldb_message *remote)
-{
- int i, ret;
- const char * const *attrs = ac->all_attrs;
- if (!attrs) {
- ret = ldb_msg_el_merge_wildcard(ac->module, local, remote);
- if (ret) {
- return ret;
- }
- }
-
- for (i = 0; attrs && attrs[i]; i++) {
- if (ldb_attr_cmp(attrs[i], "*") == 0) {
- ret = ldb_msg_el_merge_wildcard(ac->module, local, remote);
- if (ret) {
- return ret;
- }
- break;
- }
- }
-
- /* Try to map each attribute back;
- * Add to local message is possible,
- * Overwrite old local attribute if necessary */
- for (i = 0; attrs && attrs[i]; i++) {
- ret = ldb_msg_el_merge(ac->module, local, remote,
- attrs[i]);
- if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
- } else if (ret) {
- return ret;
- }
- }
-
- return LDB_SUCCESS;
-}
-
-/* Mapping search results
- * ====================== */
-
-/* Map a search result back into the local partition. */
-static int map_reply_remote(struct map_context *ac, struct ldb_reply *ares)
-{
- struct ldb_message *msg;
- struct ldb_dn *dn;
- int ret;
-
- /* There is no result message, skip */
- if (ares->type != LDB_REPLY_ENTRY) {
- return 0;
- }
-
- /* Create a new result message */
- msg = ldb_msg_new(ares);
- if (msg == NULL) {
- map_oom(ac->module);
- return -1;
- }
-
- /* Merge remote message into new message */
- ret = ldb_msg_merge_remote(ac, msg, ares->message);
- if (ret) {
- talloc_free(msg);
- return ret;
- }
-
- /* Create corresponding local DN */
- dn = ldb_dn_map_rebase_remote(ac->module, msg, ares->message->dn);
- if (dn == NULL) {
- talloc_free(msg);
- return -1;
- }
- msg->dn = dn;
-
- /* Store new message with new DN as the result */
- talloc_free(ares->message);
- ares->message = msg;
-
- return 0;
-}
-
-/* Mapping parse trees
- * =================== */
-
-/* Check whether a parse tree can safely be split in two. */
-static bool ldb_parse_tree_check_splittable(const struct ldb_parse_tree *tree)
-{
- const struct ldb_parse_tree *subtree = tree;
- bool negate = false;
-
- while (subtree) {
- switch (subtree->operation) {
- case LDB_OP_NOT:
- negate = !negate;
- subtree = subtree->u.isnot.child;
- continue;
-
- case LDB_OP_AND:
- return !negate; /* if negate: False */
-
- case LDB_OP_OR:
- return negate; /* if negate: True */
-
- default:
- return true; /* simple parse tree */
- }
- }
-
- return true; /* no parse tree */
-}
-
-/* Collect a list of attributes required to match a given parse tree. */
-static int ldb_parse_tree_collect_attrs(struct ldb_module *module, void *mem_ctx, const char ***attrs, const struct ldb_parse_tree *tree)
-{
- const char **new_attrs;
- int i, ret;
-
- if (tree == NULL) {
- return 0;
- }
-
- switch (tree->operation) {
- case LDB_OP_OR:
- case LDB_OP_AND: /* attributes stored in list of subtrees */
- for (i = 0; i < tree->u.list.num_elements; i++) {
- ret = ldb_parse_tree_collect_attrs(module, mem_ctx,
- attrs, tree->u.list.elements[i]);
- if (ret) {
- return ret;
- }
- }
- return 0;
-
- case LDB_OP_NOT: /* attributes stored in single subtree */
- return ldb_parse_tree_collect_attrs(module, mem_ctx, attrs, tree->u.isnot.child);
-
- default: /* single attribute in tree */
- new_attrs = ldb_attr_list_copy_add(mem_ctx, *attrs, tree->u.equality.attr);
- talloc_free(*attrs);
- *attrs = new_attrs;
- return 0;
- }
-
- return -1;
-}
-
-static int map_subtree_select_local(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree);
-
-/* Select a negated subtree that queries attributes in the local partition */
-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)
-{
- struct ldb_parse_tree *child;
- int ret;
-
- /* Prepare new tree */
- *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
- if (*new == NULL) {
- map_oom(module);
- return -1;
- }
-
- /* Generate new subtree */
- ret = map_subtree_select_local(module, *new, &child, tree->u.isnot.child);
- if (ret) {
- talloc_free(*new);
- return ret;
- }
-
- /* Prune tree without subtree */
- if (child == NULL) {
- talloc_free(*new);
- *new = NULL;
- return 0;
- }
-
- (*new)->u.isnot.child = child;
-
- return ret;
-}
-
-/* Select a list of subtrees that query attributes in the local partition */
-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)
-{
- int i, j, ret=0;
-
- /* Prepare new tree */
- *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
- if (*new == NULL) {
- map_oom(module);
- return -1;
- }
-
- /* Prepare list of subtrees */
- (*new)->u.list.num_elements = 0;
- (*new)->u.list.elements = talloc_array(*new, struct ldb_parse_tree *, tree->u.list.num_elements);
- if ((*new)->u.list.elements == NULL) {
- map_oom(module);
- talloc_free(*new);
- return -1;
- }
-
- /* Generate new list of subtrees */
- j = 0;
- for (i = 0; i < tree->u.list.num_elements; i++) {
- struct ldb_parse_tree *child;
- ret = map_subtree_select_local(module, *new, &child, tree->u.list.elements[i]);
- if (ret) {
- talloc_free(*new);
- return ret;
- }
-
- if (child) {
- (*new)->u.list.elements[j] = child;
- j++;
- }
- }
-
- /* Prune tree without subtrees */
- if (j == 0) {
- talloc_free(*new);
- *new = NULL;
- return 0;
- }
-
- /* Fix subtree list size */
- (*new)->u.list.num_elements = j;
- (*new)->u.list.elements = talloc_realloc(*new, (*new)->u.list.elements, struct ldb_parse_tree *, (*new)->u.list.num_elements);
-
- return ret;
-}
-
-/* Select a simple subtree that queries attributes in the local partition */
-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)
-{
- /* Prepare new tree */
- *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
- if (*new == NULL) {
- map_oom(module);
- return -1;
- }
-
- return 0;
-}
-
-/* Select subtrees that query attributes in the local partition */
-static int map_subtree_select_local(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
-{
- const struct ldb_map_context *data = map_get_context(module);
-
- if (tree == NULL) {
- return 0;
- }
-
- if (tree->operation == LDB_OP_NOT) {
- return map_subtree_select_local_not(module, mem_ctx, new, tree);
- }
-
- if (tree->operation == LDB_OP_AND || tree->operation == LDB_OP_OR) {
- return map_subtree_select_local_list(module, mem_ctx, new, tree);
- }
-
- if (map_attr_check_remote(data, tree->u.equality.attr)) {
- *new = NULL;
- return 0;
- }
-
- return map_subtree_select_local_simple(module, mem_ctx, new, tree);
-}
-
-static int map_subtree_collect_remote(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree);
-
-/* Collect a negated subtree that queries attributes in the remote partition */
-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)
-{
- struct ldb_parse_tree *child;
- int ret;
-
- /* Prepare new tree */
- *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
- if (*new == NULL) {
- map_oom(module);
- return -1;
- }
-
- /* Generate new subtree */
- ret = map_subtree_collect_remote(module, *new, &child, tree->u.isnot.child);
- if (ret) {
- talloc_free(*new);
- return ret;
- }
-
- /* Prune tree without subtree */
- if (child == NULL) {
- talloc_free(*new);
- *new = NULL;
- return 0;
- }
-
- (*new)->u.isnot.child = child;
-
- return ret;
-}
-
-/* Collect a list of subtrees that query attributes in the remote partition */
-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)
-{
- int i, j, ret=0;
-
- /* Prepare new tree */
- *new = talloc_memdup(mem_ctx, tree, sizeof(struct ldb_parse_tree));
- if (*new == NULL) {
- map_oom(module);
- return -1;
- }
-
- /* Prepare list of subtrees */
- (*new)->u.list.num_elements = 0;
- (*new)->u.list.elements = talloc_array(*new, struct ldb_parse_tree *, tree->u.list.num_elements);
- if ((*new)->u.list.elements == NULL) {
- map_oom(module);
- talloc_free(*new);
- return -1;
- }
-
- /* Generate new list of subtrees */
- j = 0;
- for (i = 0; i < tree->u.list.num_elements; i++) {
- struct ldb_parse_tree *child;
- ret = map_subtree_collect_remote(module, *new, &child, tree->u.list.elements[i]);
- if (ret) {
- talloc_free(*new);
- return ret;
- }
-
- if (child) {
- (*new)->u.list.elements[j] = child;
- j++;
- }
- }
-
- /* Prune tree without subtrees */
- if (j == 0) {
- talloc_free(*new);
- *new = NULL;
- return 0;
- }
-
- /* Fix subtree list size */
- (*new)->u.list.num_elements = j;
- (*new)->u.list.elements = talloc_realloc(*new, (*new)->u.list.elements, struct ldb_parse_tree *, (*new)->u.list.num_elements);
-
- return ret;
-}
-
-/* Collect a simple subtree that queries attributes in the remote partition */
-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)
-{
- const char *attr;
-
- /* Prepare new tree */
- *new = talloc(mem_ctx, struct ldb_parse_tree);
- if (*new == NULL) {
- map_oom(module);
- return -1;
- }
- **new = *tree;
-
- if (map->type == MAP_KEEP) {
- /* Nothing to do here */
- return 0;
- }
-
- /* Store attribute and value in new tree */
- switch (tree->operation) {
- case LDB_OP_PRESENT:
- attr = map_attr_map_local(*new, map, tree->u.present.attr);
- (*new)->u.present.attr = attr;
- break;
- case LDB_OP_SUBSTRING:
- {
- attr = map_attr_map_local(*new, map, tree->u.substring.attr);
- (*new)->u.substring.attr = attr;
- break;
- }
- case LDB_OP_EQUALITY:
- attr = map_attr_map_local(*new, map, tree->u.equality.attr);
- (*new)->u.equality.attr = attr;
- break;
- case LDB_OP_LESS:
- case LDB_OP_GREATER:
- case LDB_OP_APPROX:
- attr = map_attr_map_local(*new, map, tree->u.comparison.attr);
- (*new)->u.comparison.attr = attr;
- break;
- case LDB_OP_EXTENDED:
- attr = map_attr_map_local(*new, map, tree->u.extended.attr);
- (*new)->u.extended.attr = attr;
- break;
- default: /* unknown kind of simple subtree */
- talloc_free(*new);
- return -1;
- }
-
- if (attr == NULL) {
- talloc_free(*new);
- *new = NULL;
- return 0;
- }
-
- if (map->type == MAP_RENAME) {
- /* Nothing more to do here, the attribute has been renamed */
- return 0;
- }
-
- /* Store attribute and value in new tree */
- switch (tree->operation) {
- case LDB_OP_PRESENT:
- break;
- case LDB_OP_SUBSTRING:
- {
- int i;
- /* Map value */
- (*new)->u.substring.chunks = NULL;
- for (i=0; tree->u.substring.chunks[i]; i++) {
- (*new)->u.substring.chunks = talloc_realloc(*new, (*new)->u.substring.chunks, struct ldb_val *, i+2);
- if (!(*new)->u.substring.chunks) {
- talloc_free(*new);
- *new = NULL;
- return 0;
- }
- (*new)->u.substring.chunks[i] = talloc(*new, struct ldb_val);
- if (!(*new)->u.substring.chunks[i]) {
- talloc_free(*new);
- *new = NULL;
- return 0;
- }
- *(*new)->u.substring.chunks[i] = ldb_val_map_local(module, *new, map, tree->u.substring.chunks[i]);
- (*new)->u.substring.chunks[i+1] = NULL;
- }
- break;
- }
- case LDB_OP_EQUALITY:
- (*new)->u.equality.value = ldb_val_map_local(module, *new, map, &tree->u.equality.value);
- break;
- case LDB_OP_LESS:
- case LDB_OP_GREATER:
- case LDB_OP_APPROX:
- (*new)->u.comparison.value = ldb_val_map_local(module, *new, map, &tree->u.comparison.value);
- break;
- case LDB_OP_EXTENDED:
- (*new)->u.extended.value = ldb_val_map_local(module, *new, map, &tree->u.extended.value);
- (*new)->u.extended.rule_id = talloc_strdup(*new, tree->u.extended.rule_id);
- break;
- default: /* unknown kind of simple subtree */
- talloc_free(*new);
- return -1;
- }
-
- return 0;
-}
-
-/* Collect subtrees that query attributes in the remote partition */
-static int map_subtree_collect_remote(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree)
-{
- const struct ldb_map_context *data = map_get_context(module);
- const struct ldb_map_attribute *map;
-
- if (tree == NULL) {
- return 0;
- }
-
- if (tree->operation == LDB_OP_NOT) {
- return map_subtree_collect_remote_not(module, mem_ctx, new, tree);
- }
-
- if ((tree->operation == LDB_OP_AND) || (tree->operation == LDB_OP_OR)) {
- return map_subtree_collect_remote_list(module, mem_ctx, new, tree);
- }
-
- if (!map_attr_check_remote(data, tree->u.equality.attr)) {
- *new = NULL;
- return 0;
- }
-
- map = map_attr_find_local(data, tree->u.equality.attr);
- if (map->convert_operator) {
- return map->convert_operator(module, mem_ctx, new, tree);
- }
-
- if (map->type == MAP_GENERATE) {
- ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: "
- "Skipping attribute '%s': "
- "'convert_operator' not set\n",
- tree->u.equality.attr);
- *new = NULL;
- return 0;
- }
-
- return map_subtree_collect_remote_simple(module, mem_ctx, new, tree, map);
-}
-
-/* Split subtrees that query attributes in the local partition from
- * those that query the remote partition. */
-static int ldb_parse_tree_partition(struct ldb_module *module,
- void *mem_ctx,
- struct ldb_parse_tree **local_tree,
- struct ldb_parse_tree **remote_tree,
- const struct ldb_parse_tree *tree)
-{
- int ret;
-
- *local_tree = NULL;
- *remote_tree = NULL;
-
- /* No original tree */
- if (tree == NULL) {
- return 0;
- }
-
- /* Generate local tree */
- ret = map_subtree_select_local(module, mem_ctx, local_tree, tree);
- if (ret) {
- return ret;
- }
-
- /* Generate remote tree */
- ret = map_subtree_collect_remote(module, mem_ctx, remote_tree, tree);
- if (ret) {
- talloc_free(*local_tree);
- return ret;
- }
-
- return 0;
-}
-
-/* Collect a list of attributes required either explicitly from a
- * given list or implicitly from a given parse tree; split the
- * collected list into local and remote parts. */
-static int map_attrs_collect_and_partition(struct ldb_module *module, struct map_context *ac,
- const char * const *search_attrs,
- const struct ldb_parse_tree *tree)
-{
- void *tmp_ctx;
- const char **tree_attrs;
- const char **remote_attrs;
- const char **local_attrs;
- int ret;
-
- /* There is no tree, just partition the searched attributes */
- if (tree == NULL) {
- ret = map_attrs_partition(module, ac,
- &local_attrs, &remote_attrs, search_attrs);
- if (ret == 0) {
- ac->local_attrs = local_attrs;
- ac->remote_attrs = remote_attrs;
- ac->all_attrs = search_attrs;
- }
- return ret;
- }
-
- /* Create context for temporary memory */
- tmp_ctx = talloc_new(ac);
- if (tmp_ctx == NULL) {
- goto oom;
- }
-
- /* Prepare list of attributes from tree */
- tree_attrs = talloc_array(tmp_ctx, const char *, 1);
- if (tree_attrs == NULL) {
- talloc_free(tmp_ctx);
- goto oom;
- }
- tree_attrs[0] = NULL;
-
- /* Collect attributes from tree */
- ret = ldb_parse_tree_collect_attrs(module, tmp_ctx, &tree_attrs, tree);
- if (ret) {
- goto done;
- }
-
- /* Merge attributes from search operation */
- ret = map_attrs_merge(module, tmp_ctx, &tree_attrs, search_attrs);
- if (ret) {
- goto done;
- }
-
- /* Split local from remote attributes */
- ret = map_attrs_partition(module, ac, &local_attrs,
- &remote_attrs, tree_attrs);
-
- if (ret == 0) {
- ac->local_attrs = local_attrs;
- ac->remote_attrs = remote_attrs;
- talloc_steal(ac, tree_attrs);
- ac->all_attrs = tree_attrs;
- }
-done:
- /* Free temporary memory */
- talloc_free(tmp_ctx);
- return ret;
-
-oom:
- map_oom(module);
- return -1;
-}
-
-
-/* Outbound requests: search
- * ========================= */
-
-static int map_remote_search_callback(struct ldb_request *req,
- struct ldb_reply *ares);
-static int map_local_merge_callback(struct ldb_request *req,
- struct ldb_reply *ares);
-static int map_search_local(struct map_context *ac);
-
-static int map_save_entry(struct map_context *ac, struct ldb_reply *ares)
-{
- struct map_reply *mr;
-
- mr = talloc_zero(ac, struct map_reply);
- if (mr == NULL) {
- map_oom(ac->module);
- return LDB_ERR_OPERATIONS_ERROR;
- }
- mr->remote = talloc_steal(mr, ares);
- if (ac->r_current) {
- ac->r_current->next = mr;
- } else {
- /* first entry */
- ac->r_list = mr;
- }
- ac->r_current = mr;
-
- return LDB_SUCCESS;
-}
-
-/* Pass a merged search result up the callback chain. */
-int map_return_entry(struct map_context *ac, struct ldb_reply *ares)
-{
- struct ldb_message_element *el;
- const char * const *attrs;
- int i;
-
- /* Merged result doesn't match original query, skip */
- if (!ldb_match_msg(ac->module->ldb, ares->message,
- ac->req->op.search.tree,
- ac->req->op.search.base,
- ac->req->op.search.scope)) {
- ldb_debug(ac->module->ldb, LDB_DEBUG_TRACE, "ldb_map: "
- "Skipping record '%s': "
- "doesn't match original search\n",
- ldb_dn_get_linearized(ares->message->dn));
- return LDB_SUCCESS;
- }
-
- /* Limit result to requested attrs */
- if (ac->req->op.search.attrs &&
- (! ldb_attr_in_list(ac->req->op.search.attrs, "*"))) {
-
- attrs = ac->req->op.search.attrs;
- i = 0;
-
- while (i < ares->message->num_elements) {
-
- el = &ares->message->elements[i];
- if ( ! ldb_attr_in_list(attrs, el->name)) {
- ldb_msg_remove_element(ares->message, el);
- } else {
- i++;
- }
- }
- }
-
- return ldb_module_send_entry(ac->req, ares->message, ares->controls);
-}
-
-/* Search a record. */
-int map_search(struct ldb_module *module, struct ldb_request *req)
-{
- struct ldb_parse_tree *remote_tree;
- struct ldb_parse_tree *local_tree;
- struct ldb_request *remote_req;
- struct map_context *ac;
- int ret;
-
- const char *wildcard[] = { "*", NULL };
- const char * const *attrs;
-
- if (!module->private_data) /* if we're not yet initialized, go to the next module */
- return ldb_next_request(module, req);
-
- /* Do not manipulate our control entries */
- if (ldb_dn_is_special(req->op.search.base)) {
- return ldb_next_request(module, req);
- }
-
- /* No mapping requested, skip to next module */
- if ((req->op.search.base) && (!ldb_dn_check_local(module, req->op.search.base))) {
- return ldb_next_request(module, req);
- }
-
- /* TODO: How can we be sure about which partition we are
- * targetting when there is no search base? */
-
- /* Prepare context and handle */
- ac = map_init_context(module, req);
- if (ac == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- /* It is easier to deal with the two different ways of
- * expressing the wildcard in the same codepath */
- attrs = req->op.search.attrs;
- if (attrs == NULL) {
- attrs = wildcard;
- }
-
- /* Split local from remote attrs */
- ret = map_attrs_collect_and_partition(module, ac,
- attrs, req->op.search.tree);
- if (ret) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- /* Split local from remote tree */
- ret = ldb_parse_tree_partition(module, ac,
- &local_tree, &remote_tree,
- req->op.search.tree);
- if (ret) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- if (((local_tree != NULL) && (remote_tree != NULL)) &&
- (!ldb_parse_tree_check_splittable(req->op.search.tree))) {
- /* The query can't safely be split, enumerate the remote partition */
- local_tree = NULL;
- remote_tree = NULL;
- }
-
- if (local_tree == NULL) {
- /* Construct default local parse tree */
- local_tree = talloc_zero(ac, struct ldb_parse_tree);
- if (local_tree == NULL) {
- map_oom(ac->module);
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- local_tree->operation = LDB_OP_PRESENT;
- local_tree->u.present.attr = talloc_strdup(local_tree, IS_MAPPED);
- }
- if (remote_tree == NULL) {
- /* Construct default remote parse tree */
- remote_tree = ldb_parse_tree(ac, NULL);
- if (remote_tree == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
- }
-
- ac->local_tree = local_tree;
-
- /* Prepare the remote operation */
- ret = ldb_build_search_req_ex(&remote_req, module->ldb, ac,
- req->op.search.base,
- req->op.search.scope,
- remote_tree,
- ac->remote_attrs,
- req->controls,
- ac, map_remote_search_callback,
- req);
- if (ret != LDB_SUCCESS) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- return ldb_next_remote_request(module, remote_req);
-}
-
-/* Now, search the local part of a remote search result. */
-static int map_remote_search_callback(struct ldb_request *req,
- struct ldb_reply *ares)
-{
- struct map_context *ac;
- int ret;
-
- ac = talloc_get_type(req->context, struct map_context);
-
- if (!ares) {
- return ldb_module_done(ac->req, NULL, NULL,
- LDB_ERR_OPERATIONS_ERROR);
- }
- if (ares->error != LDB_SUCCESS) {
- return ldb_module_done(ac->req, ares->controls,
- ares->response, ares->error);
- }
-
- switch (ares->type) {
- case LDB_REPLY_REFERRAL:
-
- /* ignore referrals */
- talloc_free(ares);
- return LDB_SUCCESS;
-
- case LDB_REPLY_ENTRY:
-
- /* Map result record into a local message */
- ret = map_reply_remote(ac, ares);
- if (ret) {
- talloc_free(ares);
- return ldb_module_done(ac->req, NULL, NULL,
- LDB_ERR_OPERATIONS_ERROR);
- }
-
- /* if we have no local db, then we can just return the reply to
- * the upper layer, otherwise we must save it and process it
- * when all replies ahve been gathered */
- if ( ! map_check_local_db(ac->module)) {
- ret = map_return_entry(ac, ares);
- } else {
- ret = map_save_entry(ac,ares);
- }
-
- if (ret != LDB_SUCCESS) {
- talloc_free(ares);
- return ldb_module_done(ac->req, NULL, NULL,
- LDB_ERR_OPERATIONS_ERROR);
- }
- break;
-
- case LDB_REPLY_DONE:
-
- if ( ! map_check_local_db(ac->module)) {
- return ldb_module_done(ac->req, ares->controls,
- ares->response, LDB_SUCCESS);
- }
-
- talloc_free(ares);
-
- /* reset the pointer to the start of the list */
- ac->r_current = ac->r_list;
-
- /* no entry just return */
- if (ac->r_current == NULL) {
- return ldb_module_done(ac->req, ares->controls,
- ares->response, LDB_SUCCESS);
- }
-
- ret = map_search_local(ac);
- if (ret != LDB_SUCCESS) {
- return ldb_module_done(ac->req, NULL, NULL, ret);
- }
- }
-
- return LDB_SUCCESS;
-}
-
-static int map_search_local(struct map_context *ac)
-{
- struct ldb_request *search_req;
-
- if (ac->r_current == NULL || ac->r_current->remote == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- /* Prepare local search request */
- /* TODO: use GUIDs here instead? */
- search_req = map_search_base_req(ac,
- ac->r_current->remote->message->dn,
- NULL, NULL,
- ac, map_local_merge_callback);
- if (search_req == NULL) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- return ldb_next_request(ac->module, search_req);
-}
-
-/* Merge the remote and local parts of a search result. */
-int map_local_merge_callback(struct ldb_request *req, struct ldb_reply *ares)
-{
- struct map_context *ac;
- int ret;
-
- ac = talloc_get_type(req->context, struct map_context);
-
- if (!ares) {
- return ldb_module_done(ac->req, NULL, NULL,
- LDB_ERR_OPERATIONS_ERROR);
- }
- if (ares->error != LDB_SUCCESS) {
- return ldb_module_done(ac->req, ares->controls,
- ares->response, ares->error);
- }
-
- switch (ares->type) {
- case LDB_REPLY_ENTRY:
- /* We have already found a local record */
- if (ac->r_current->local) {
- talloc_free(ares);
- ldb_set_errstring(ac->module->ldb, "ldb_map: Too many results!");
- return ldb_module_done(ac->req, NULL, NULL,
- LDB_ERR_OPERATIONS_ERROR);
- }
-
- /* Store local result */
- ac->r_current->local = talloc_steal(ac->r_current, ares);
-
- break;
-
- case LDB_REPLY_REFERRAL:
- /* ignore referrals */
- talloc_free(ares);
- break;
-
- case LDB_REPLY_DONE:
- talloc_free(ares);
-
- /* No local record found, map and send remote record */
- if (ac->r_current->local != NULL) {
- /* Merge remote into local message */
- ret = ldb_msg_merge_local(ac->module,
- ac->r_current->local->message,
- ac->r_current->remote->message);
- if (ret == LDB_SUCCESS) {
- ret = map_return_entry(ac, ac->r_current->local);
- }
- if (ret != LDB_SUCCESS) {
- return ldb_module_done(ac->req, NULL, NULL,
- LDB_ERR_OPERATIONS_ERROR);
- }
- } else {
- ret = map_return_entry(ac, ac->r_current->remote);
- if (ret != LDB_SUCCESS) {
- return ldb_module_done(ac->req,
- NULL, NULL, ret);
- }
- }
-
- if (ac->r_current->next != NULL) {
- ac->r_current = ac->r_current->next;
- if (ac->r_current->remote->type == LDB_REPLY_ENTRY) {
- ret = map_search_local(ac);
- if (ret != LDB_SUCCESS) {
- return ldb_module_done(ac->req,
- NULL, NULL, ret);
- }
- break;
- }
- }
-
- /* ok we are done with all search, finally it is time to
- * finish operations for this module */
- return ldb_module_done(ac->req,
- ac->r_current->remote->controls,
- ac->r_current->remote->response,
- ac->r_current->remote->error);
- }
-
- return LDB_SUCCESS;
-}