Author: mkhl Date: 2006-06-24 22:00:52 +0000 (Sat, 24 Jun 2006) New Revision: 16505
WebSVN: http://websvn.samba.org/cgi-bin/viewcvs.cgi?view=rev&root=samba&rev=16505 Log: Check incoming DN before performing mappings. Add chunks of searching boilerplate. Martin Modified: branches/SOC/mkhl/ldb-map/modules/ldb_map.c Changeset: Modified: branches/SOC/mkhl/ldb-map/modules/ldb_map.c =================================================================== --- branches/SOC/mkhl/ldb-map/modules/ldb_map.c 2006-06-24 20:38:38 UTC (rev 16504) +++ branches/SOC/mkhl/ldb-map/modules/ldb_map.c 2006-06-24 22:00:52 UTC (rev 16505) @@ -1,25 +1,25 @@ /* - ldb database library - map backend + Mapping ldb module Copyright (C) Jelmer Vernooij 2005 - ** NOTE! The following LGPL license applies to the ldb - ** library. This does NOT imply that all of Samba is released - ** under the LGPL + * NOTICE: this module is NOT released under the GNU LGPL license as + * other ldb code. This module is release under the GNU GPL v2 or + * later license. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. - 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 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, + This program 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, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -27,7 +27,7 @@ * * Component: ldb ldb_map module * - * Description: ... + * Description: Map portions of data into a different format on a remote partition. * * Author: Jelmer Vernooij, Martin Kuehl */ @@ -57,7 +57,7 @@ #define map_oom(module) ldb_set_errstring(module->ldb, talloc_asprintf(module, "Out of Memory")); -/* Private data */ +/* private data */ struct map_private { struct ldb_map_context context; }; @@ -73,9 +73,11 @@ } -/* Async context data */ +/* async context data */ struct map_async_context { enum map_step { + MAP_SEARCH_LOCAL, + MAP_SEARCH_REMOTE, MAP_DO_ADD_REMOTE, MAP_DO_ADD_LOCAL, MAP_SEARCH_SELF_MODIFY, @@ -87,7 +89,7 @@ MAP_SEARCH_SELF_RENAME, MAP_DO_RENAME_REMOTE, MAP_DO_RENAME_FIXUP, - MAP_DO_RENAME_LOCAL, + MAP_DO_RENAME_LOCAL } step; struct ldb_module *module; @@ -104,6 +106,13 @@ struct ldb_async_result *search_res; }; +/* async context data for searches */ +struct map_async_search_context { + struct map_async_context *ac; + struct ldb_async_result *local_res; + struct ldb_async_result *remote_res; +}; + /* create async context and handle */ static struct ldb_async_handle * @@ -191,7 +200,7 @@ return new; } -#define MAP_DN_REBASE(dn) dn = ldb_dn_rebase(request, dn, map->local_base_dn, map->remote_base_dn) +#define MAP_DN_REBASE(dn) dn = ldb_dn_rebase(request, dn, data->local_base_dn, data->remote_base_dn) /* run request in the remote partition */ static @@ -199,7 +208,7 @@ ldb_next_remote_request(struct ldb_module *module, struct ldb_request *request) { - struct ldb_map_context *map = map_get_privdat(module); + struct ldb_map_context *data = map_get_privdat(module); struct ldb_message *msg; switch (request->operation) { @@ -315,24 +324,71 @@ } -/* Checking ldb_messages */ +/* Checking ... stuff */ +/* True if dn is below the local baseDN */ static -int -check_msg_is_mapped(struct ldb_module *module, - const struct ldb_message *msg) +BOOL +check_dn_local(struct ldb_module *module, + const struct ldb_dn *dn) { struct ldb_map_context *data = map_get_privdat(module); + + return ldb_dn_compare_base(module->ldb, data->local_base_dn, dn) == 0; +} + +/* True if attr has an associated mapping that does not ignore it */ +static +BOOL +check_attr_mapped(struct ldb_map_context *data, + const char* attr) +{ struct ldb_map_attribute *map; + + map = find_attr_local(data, attr); + if (map == NULL) + return False; + if (map->type == MAP_IGNORE) + return False; + return True; +} + +/* True if any of attrs is mapped */ +static +BOOL +check_attrs_mapped(struct ldb_module *module, + const char * const *attrs) +{ + struct ldb_map_context *data = map_get_privdat(module); + BOOL ret; int i; + for (i = 0; attrs[i]; i++) { + ret = check_attr_mapped(data, attrs[i]); + if (ret) + return ret; + } + + return False; +} + +/* True if any of the message elements is mapped */ +static +BOOL +check_msg_mapped(struct ldb_module *module, + const struct ldb_message *msg) +{ + struct ldb_map_context *data = map_get_privdat(module); + BOOL ret; + int i; + for (i = 0; i < msg->num_elements; i++) { - map = find_attr_local(data, msg->elements[i].name); - if (map && map->type != MAP_IGNORE) - return 1; + ret = check_attr_mapped(data, msg->elements[i].name); + if (ret) + return ret; } - return 0; + return False; } /* Check whether the given objectClass is contained in the specified @@ -1340,11 +1396,12 @@ } +/* store single search result in async context */ static int -get_self_callback(struct ldb_context *ldb, - void *context, - struct ldb_async_result *ares) +search_self_callback(struct ldb_context *ldb, + void *context, + struct ldb_async_result *ares) { struct map_async_context *ac; @@ -1361,7 +1418,8 @@ return LDB_SUCCESS; } - if (ac->remote_dn != NULL) { + /* we already have a remote DN */ + if (ac->remote_dn) { ldb_set_errstring(ldb, talloc_asprintf(ldb, "Too many results")); talloc_free(ares); @@ -1369,17 +1427,18 @@ } ac->search_res = talloc_steal(ac, ares); - ac->remote_dn - = ldb_dn_explode(ac, ldb_msg_find_string(ares->message, - IS_MAPPED, NULL)); + ac->remote_dn = ldb_dn_explode(ac, + ldb_msg_find_string(ares->message, + IS_MAPPED, NULL)); return LDB_SUCCESS; } +/* create request that searches for DN */ static struct ldb_request * -build_self_req(struct map_async_context *ac, - const struct ldb_dn *dn) +search_self_req(struct map_async_context *ac, + const struct ldb_dn *dn) { /* attrs[] is returned from this function in ac->search_req->op.search.attrs, so it must be static, as @@ -1406,13 +1465,53 @@ req->controls = NULL; req->async.context = ac; - req->async.callback = get_self_callback; + req->async.callback = search_self_callback; ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, req); return req; } +static +int +local_search_callback(struct ldb_context *ldb, + void *context, + struct ldb_async_result *ares) +{ + struct map_async_search_context *sc; + if (context == NULL || ares == NULL) { + ldb_set_errstring(ldb, talloc_asprintf(ldb, "NULL Context or Result in callback")); + return LDB_ERR_OPERATIONS_ERROR; + } + + sc = talloc_get_type(context, struct map_async_search_context); + + switch (ares->type) { + case LDB_REPLY_ENTRY: + /* we already have a local result */ + if (sc->local_res != NULL) { + ldb_set_errstring(ldb, + talloc_asprintf(ldb, + "Too many results")); + talloc_free(ares); + return LDB_ERR_OPERATIONS_ERROR; + } + + sc->local_res = talloc_steal(sc, ares); + + /* don't return the 'IS_MAPPED' attribute */ + ldb_msg_remove_attr(ares->message, IS_MAPPED); + + /* XXX: ... */ + + default: + talloc_free(ares); + ldb_set_errstring(ldb, talloc_asprintf(ldb, "Unexpected result type in search for local record")); + return LDB_ERR_OPERATIONS_ERROR; + } +} + + /* Handling LDB requests */ /* /\* Search fallback database *\/ */ @@ -1612,6 +1711,73 @@ /* } */ +/* Search a record */ +static +int +map_search(struct ldb_module *module, + struct ldb_request *req) +{ + struct ldb_async_handle *h; + struct map_async_context *ac; + const char * const *local_attrs; + int ret; + + /* 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 (!check_dn_local(module, req->op.search.base)) + return ldb_next_request(module, req); + + /* no mapping needed, skip to next module */ + if (req->op.search.attrs + && (!ldb_attr_in_list(req->op.search.attrs, "*")) + && (!check_attrs_mapped(module, req->op.search.attrs))) + return ldb_next_request(module, req); + + /* prepare async context and handle */ + h = map_init_handle(req, module); + if (h == NULL) + return LDB_ERR_OPERATIONS_ERROR; + ac = talloc_get_type(h->private_data, struct map_async_context); + + /* return or own handle to deal with this call */ + /* req->async.handle = h; */ + + /* prepare the local operation */ + ac->local_req = talloc_zero(ac, struct ldb_request); + if (ac->local_req == NULL) { + map_oom(module); + return LDB_ERR_OPERATIONS_ERROR; + } + + *(ac->local_req) = *req; /* copy the request */ + + /* return or own handle to deal with this call */ + ac->local_req->async.handle = h; + + ac->local_req->async.context = ac; + ac->local_req->async.callback = local_search_callback; + + /* XXX: ... */ + + ac->local_req->op.search.attrs = local_attrs; + + ldb_set_timeout_from_prev_req(module->ldb, req, ac->local_req); + + h->state = LDB_ASYNC_INIT; + h->status = LDB_SUCCESS; + + ac->step = MAP_SEARCH_LOCAL; + + ret = ldb_next_request(module, ac->local_req); + if (ret == LDB_SUCCESS) + req->async.handle = ac->local_req->async.handle; + return ret; +} + + /* Add the local record */ static int @@ -1644,8 +1810,12 @@ if (ldb_dn_is_special(msg->dn)) return ldb_next_request(module, req); + /* no mapping requested, skip to next module */ + if (!check_dn_local(module, msg->dn)) + return ldb_next_request(module, req); + /* no mapping needed, skip to next module */ - if (!check_msg_is_mapped(module, msg)) + if (!check_msg_mapped(module, msg)) return ldb_next_request(module, req); /* prepare async context and handle */ @@ -1797,8 +1967,12 @@ if (ldb_dn_is_special(msg->dn)) return ldb_next_request(module, req); + /* no mapping requested, skip to next module */ + if (!check_dn_local(module, msg->dn)) + return ldb_next_request(module, req); + /* no mapping needed, skip to next module */ - if (!check_msg_is_mapped(module, msg)) + if (!check_msg_mapped(module, msg)) return ldb_next_request(module, req); /* prepare async context and handle */ @@ -1860,7 +2034,7 @@ return map_modify_do_local(h); /* prepare the search operation */ - ac->search_req = build_self_req(ac, msg->dn); + ac->search_req = search_self_req(ac, msg->dn); if (ac->search_req == NULL) return LDB_ERR_OPERATIONS_ERROR; @@ -1951,8 +2125,11 @@ if (ldb_dn_is_special(req->op.del.dn)) return ldb_next_request(module, req); - /* TODO: check that DN is under the local baseDN */ + /* no mapping requested, skip to next module */ + if (!check_dn_local(module, req->op.del.dn)) + return ldb_next_request(module, req); + /* prepare async context and handle */ h = map_init_handle(req, module); if (h == NULL) @@ -1963,7 +2140,7 @@ req->async.handle = h; /* prepare the search operation */ - ac->search_req = build_self_req(ac, req->op.del.dn); + ac->search_req = search_self_req(ac, req->op.del.dn); if (ac->search_req == NULL) return LDB_ERR_OPERATIONS_ERROR; @@ -2104,7 +2281,11 @@ if (ldb_dn_is_special(req->op.rename.olddn)) return ldb_next_request(module, req); - /* TODO: check that DN is under the local baseDN */ + /* no mapping requested, skip to next module */ + /* TODO: both? either? neither? what to doin each case? */ + if (!check_dn_local(module, req->op.rename.olddn) || + !check_dn_local(module, req->op.rename.newdn)) + return ldb_next_request(module, req); /* prepare async context and handle */ h = map_init_handle(req, module); @@ -2116,7 +2297,7 @@ req->async.handle = h; /* prepare the search operation */ - ac->search_req = build_self_req(ac, req->op.rename.olddn); + ac->search_req = search_self_req(ac, req->op.rename.olddn); if (ac->search_req == NULL) return LDB_ERR_OPERATIONS_ERROR; @@ -2291,7 +2472,7 @@ .modify = map_modify, .del = map_delete, .rename = map_rename, -/* .search = map_search_bytree, */ + .search = map_search, .async_wait = map_async_wait, };