diff options
Diffstat (limited to 'source4/lib/ldb/common/ldb_modules.c')
-rw-r--r-- | source4/lib/ldb/common/ldb_modules.c | 1146 |
1 files changed, 0 insertions, 1146 deletions
diff --git a/source4/lib/ldb/common/ldb_modules.c b/source4/lib/ldb/common/ldb_modules.c deleted file mode 100644 index 61d1901513..0000000000 --- a/source4/lib/ldb/common/ldb_modules.c +++ /dev/null @@ -1,1146 +0,0 @@ -/* - ldb database library - - Copyright (C) Simo Sorce 2004-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/>. -*/ - -/* - * Name: ldb - * - * Component: ldb modules core - * - * Description: core modules routines - * - * Author: Simo Sorce - */ - -#include "ldb_private.h" -#include "dlinklist.h" -#include "system/dir.h" - -static char *ldb_modules_strdup_no_spaces(TALLOC_CTX *mem_ctx, const char *string) -{ - size_t i, len; - char *trimmed; - - trimmed = talloc_strdup(mem_ctx, string); - if (!trimmed) { - return NULL; - } - - len = strlen(trimmed); - for (i = 0; trimmed[i] != '\0'; i++) { - switch (trimmed[i]) { - case ' ': - case '\t': - case '\n': - memmove(&trimmed[i], &trimmed[i + 1], len -i -1); - break; - } - } - - return trimmed; -} - - -/* modules are called in inverse order on the stack. - Lets place them as an admin would think the right order is. - Modules order is important */ -const char **ldb_modules_list_from_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *string) -{ - char **modules = NULL; - const char **m; - char *modstr, *p; - unsigned int i; - - /* spaces not admitted */ - modstr = ldb_modules_strdup_no_spaces(mem_ctx, string); - if ( ! modstr) { - ldb_debug(ldb, LDB_DEBUG_FATAL, "Out of Memory in ldb_modules_strdup_no_spaces()"); - return NULL; - } - - modules = talloc_realloc(mem_ctx, modules, char *, 2); - if ( ! modules ) { - ldb_debug(ldb, LDB_DEBUG_FATAL, "Out of Memory in ldb_modules_list_from_string()"); - talloc_free(modstr); - return NULL; - } - talloc_steal(modules, modstr); - - if (modstr[0] == '\0') { - modules[0] = NULL; - m = (const char **)modules; - return m; - } - - i = 0; - /* The str*r*chr walks backwards: This is how we get the inverse order mentioned above */ - while ((p = strrchr(modstr, ',')) != NULL) { - *p = '\0'; - p++; - modules[i] = p; - - i++; - modules = talloc_realloc(mem_ctx, modules, char *, i + 2); - if ( ! modules ) { - ldb_debug(ldb, LDB_DEBUG_FATAL, "Out of Memory in ldb_modules_list_from_string()"); - return NULL; - } - - } - modules[i] = modstr; - - modules[i + 1] = NULL; - - m = (const char **)modules; - - return m; -} - -static struct backends_list_entry { - struct ldb_backend_ops *ops; - struct backends_list_entry *prev, *next; -} *ldb_backends = NULL; - -static struct ops_list_entry { - const struct ldb_module_ops *ops; - struct ops_list_entry *next; -} *registered_modules = NULL; - -static struct backends_list_entry *ldb_find_backend(const char *url_prefix) -{ - struct backends_list_entry *backend; - - for (backend = ldb_backends; backend; backend = backend->next) { - if (strcmp(backend->ops->name, url_prefix) == 0) { - return backend; - } - } - - return NULL; -} - -/* - register a new ldb backend - - if override is true, then override any existing backend for this prefix -*/ -int ldb_register_backend(const char *url_prefix, ldb_connect_fn connectfn, bool override) -{ - struct backends_list_entry *be; - - be = ldb_find_backend(url_prefix); - if (be) { - if (!override) { - return LDB_SUCCESS; - } - } else { - be = talloc_zero(ldb_backends, struct backends_list_entry); - if (!be) { - return LDB_ERR_OPERATIONS_ERROR; - } - be->ops = talloc_zero(be, struct ldb_backend_ops); - if (!be->ops) { - talloc_free(be); - return LDB_ERR_OPERATIONS_ERROR; - } - DLIST_ADD_END(ldb_backends, be, struct backends_list_entry); - } - - be->ops->name = url_prefix; - be->ops->connect_fn = connectfn; - - return LDB_SUCCESS; -} - -/* - Return the ldb module form of a database. - The URL can either be one of the following forms - ldb://path - ldapi://path - - flags is made up of LDB_FLG_* - - the options are passed uninterpreted to the backend, and are - backend specific. - - This allows modules to get at only the backend module, for example where a - module may wish to direct certain requests at a particular backend. -*/ -int ldb_module_connect_backend(struct ldb_context *ldb, - const char *url, - const char *options[], - struct ldb_module **backend_module) -{ - int ret; - char *backend; - struct backends_list_entry *be; - - if (strchr(url, ':') != NULL) { - backend = talloc_strndup(ldb, url, strchr(url, ':')-url); - } else { - /* Default to tdb */ - backend = talloc_strdup(ldb, "tdb"); - } - if (backend == NULL) { - return ldb_oom(ldb); - } - - be = ldb_find_backend(backend); - - talloc_free(backend); - - if (be == NULL) { - ldb_debug(ldb, LDB_DEBUG_FATAL, - "Unable to find backend for '%s' - do you need to set LDB_MODULES_PATH?", url); - return LDB_ERR_OTHER; - } - - ret = be->ops->connect_fn(ldb, url, ldb->flags, options, backend_module); - - if (ret != LDB_SUCCESS) { - ldb_debug(ldb, LDB_DEBUG_ERROR, - "Failed to connect to '%s' with backend '%s'", url, be->ops->name); - return ret; - } - return ret; -} - -static struct ldb_hooks { - struct ldb_hooks *next, *prev; - ldb_hook_fn hook_fn; -} *ldb_hooks; - -/* - register a ldb hook function - */ -int ldb_register_hook(ldb_hook_fn hook_fn) -{ - struct ldb_hooks *lc; - lc = talloc_zero(ldb_hooks, struct ldb_hooks); - if (lc == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } - lc->hook_fn = hook_fn; - DLIST_ADD_END(ldb_hooks, lc, struct ldb_hooks); - return LDB_SUCCESS; -} - -/* - call ldb hooks of a given type - */ -int ldb_modules_hook(struct ldb_context *ldb, enum ldb_module_hook_type t) -{ - struct ldb_hooks *lc; - for (lc = ldb_hooks; lc; lc=lc->next) { - int ret = lc->hook_fn(ldb, t); - if (ret != LDB_SUCCESS) { - return ret; - } - } - return LDB_SUCCESS; -} - - -static const struct ldb_module_ops *ldb_find_module_ops(const char *name) -{ - struct ops_list_entry *e; - - for (e = registered_modules; e; e = e->next) { - if (strcmp(e->ops->name, name) == 0) - return e->ops; - } - - return NULL; -} - - -int ldb_register_module(const struct ldb_module_ops *ops) -{ - struct ops_list_entry *entry; - - if (ldb_find_module_ops(ops->name) != NULL) - return LDB_ERR_ENTRY_ALREADY_EXISTS; - - entry = talloc(talloc_autofree_context(), struct ops_list_entry); - if (entry == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } - - entry->ops = ops; - entry->next = registered_modules; - registered_modules = entry; - - return LDB_SUCCESS; -} - -/* - load a list of modules - */ -int ldb_module_load_list(struct ldb_context *ldb, const char **module_list, - struct ldb_module *backend, struct ldb_module **out) -{ - struct ldb_module *module; - unsigned int i; - - module = backend; - - for (i = 0; module_list && module_list[i] != NULL; i++) { - struct ldb_module *current; - const struct ldb_module_ops *ops; - - if (strcmp(module_list[i], "") == 0) { - continue; - } - - ops = ldb_find_module_ops(module_list[i]); - - if (ops == NULL) { - ldb_debug(ldb, LDB_DEBUG_FATAL, "WARNING: Module [%s] not found - do you need to set LDB_MODULES_PATH?", - module_list[i]); - return LDB_ERR_OPERATIONS_ERROR; - } - - current = talloc_zero(ldb, struct ldb_module); - if (current == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } - talloc_set_name(current, "ldb_module: %s", module_list[i]); - - current->ldb = ldb; - current->ops = ops; - - DLIST_ADD(module, current); - } - *out = module; - return LDB_SUCCESS; -} - -/* - initialise a chain of modules - */ -int ldb_module_init_chain(struct ldb_context *ldb, struct ldb_module *module) -{ - while (module && module->ops->init_context == NULL) - module = module->next; - - /* init is different in that it is not an error if modules - * do not require initialization */ - - if (module) { - int ret = module->ops->init_context(module); - if (ret != LDB_SUCCESS) { - ldb_debug(ldb, LDB_DEBUG_FATAL, "module %s initialization failed : %s", - module->ops->name, ldb_strerror(ret)); - return ret; - } - } - - return LDB_SUCCESS; -} - -int ldb_load_modules(struct ldb_context *ldb, const char *options[]) -{ - const char *modules_string; - const char **modules = NULL; - int ret; - TALLOC_CTX *mem_ctx = talloc_new(ldb); - if (!mem_ctx) { - return ldb_oom(ldb); - } - - /* find out which modules we are requested to activate */ - - /* check if we have a custom module list passd as ldb option */ - if (options) { - modules_string = ldb_options_find(ldb, options, "modules"); - if (modules_string) { - modules = ldb_modules_list_from_string(ldb, mem_ctx, modules_string); - } - } - - /* if not overloaded by options and the backend is not ldap try to load the modules list from ldb */ - if ((modules == NULL) && (strcmp("ldap", ldb->modules->ops->name) != 0)) { - const char * const attrs[] = { "@LIST" , NULL}; - struct ldb_result *res = NULL; - struct ldb_dn *mods_dn; - - mods_dn = ldb_dn_new(mem_ctx, ldb, "@MODULES"); - if (mods_dn == NULL) { - talloc_free(mem_ctx); - return ldb_oom(ldb); - } - - ret = ldb_search(ldb, mods_dn, &res, mods_dn, LDB_SCOPE_BASE, attrs, "@LIST=*"); - - if (ret == LDB_ERR_NO_SUCH_OBJECT) { - ldb_debug(ldb, LDB_DEBUG_TRACE, "no modules required by the db"); - } else if (ret != LDB_SUCCESS) { - ldb_debug(ldb, LDB_DEBUG_FATAL, "ldb error (%s) occurred searching for modules, bailing out", ldb_errstring(ldb)); - talloc_free(mem_ctx); - return ret; - } else { - const char *module_list; - if (res->count == 0) { - ldb_debug(ldb, LDB_DEBUG_TRACE, "no modules required by the db"); - } else if (res->count > 1) { - ldb_debug(ldb, LDB_DEBUG_FATAL, "Too many records found (%u), bailing out", res->count); - talloc_free(mem_ctx); - return LDB_ERR_OPERATIONS_ERROR; - } else { - module_list = ldb_msg_find_attr_as_string(res->msgs[0], "@LIST", NULL); - if (!module_list) { - ldb_debug(ldb, LDB_DEBUG_TRACE, "no modules required by the db"); - } - modules = ldb_modules_list_from_string(ldb, mem_ctx, - module_list); - } - } - - talloc_free(mods_dn); - } - - if (modules != NULL) { - ret = ldb_module_load_list(ldb, modules, ldb->modules, &ldb->modules); - if (ret != LDB_SUCCESS) { - talloc_free(mem_ctx); - return ret; - } - } else { - ldb_debug(ldb, LDB_DEBUG_TRACE, "No modules specified for this database"); - } - - ret = ldb_module_init_chain(ldb, ldb->modules); - talloc_free(mem_ctx); - return ret; -} - -/* - by using this we allow ldb modules to only implement the functions they care about, - which makes writing a module simpler, and makes it more likely to keep working - when ldb is extended -*/ -#define FIND_OP_NOERR(module, op) do { \ - module = module->next; \ - while (module && module->ops->op == NULL) module = module->next; \ - if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) { \ - ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_trace_next_request: (%s)->" #op, \ - module->ops->name); \ - } \ -} while (0) - -#define FIND_OP(module, op) do { \ - struct ldb_context *ldb = module->ldb; \ - FIND_OP_NOERR(module, op); \ - if (module == NULL) { \ - ldb_asprintf_errstring(ldb, "Unable to find backend operation for " #op ); \ - return LDB_ERR_OPERATIONS_ERROR; \ - } \ -} while (0) - - -struct ldb_module *ldb_module_new(TALLOC_CTX *memctx, - struct ldb_context *ldb, - const char *module_name, - const struct ldb_module_ops *ops) -{ - struct ldb_module *module; - - module = talloc(memctx, struct ldb_module); - if (!module) { - ldb_oom(ldb); - return NULL; - } - talloc_set_name_const(module, module_name); - module->ldb = ldb; - module->prev = module->next = NULL; - module->ops = ops; - - return module; -} - -const char * ldb_module_get_name(struct ldb_module *module) -{ - return module->ops->name; -} - -struct ldb_context *ldb_module_get_ctx(struct ldb_module *module) -{ - return module->ldb; -} - -const struct ldb_module_ops *ldb_module_get_ops(struct ldb_module *module) -{ - return module->ops; -} - -void *ldb_module_get_private(struct ldb_module *module) -{ - return module->private_data; -} - -void ldb_module_set_private(struct ldb_module *module, void *private_data) -{ - module->private_data = private_data; -} - -/* - helper functions to call the next module in chain -*/ - -int ldb_next_request(struct ldb_module *module, struct ldb_request *request) -{ - int ret; - - if (request->callback == NULL) { - ldb_set_errstring(module->ldb, "Requests MUST define callbacks"); - return LDB_ERR_UNWILLING_TO_PERFORM; - } - - request->handle->nesting++; - - switch (request->operation) { - case LDB_SEARCH: - FIND_OP(module, search); - ret = module->ops->search(module, request); - break; - case LDB_ADD: - FIND_OP(module, add); - ret = module->ops->add(module, request); - break; - case LDB_MODIFY: - FIND_OP(module, modify); - ret = module->ops->modify(module, request); - break; - case LDB_DELETE: - FIND_OP(module, del); - ret = module->ops->del(module, request); - break; - case LDB_RENAME: - FIND_OP(module, rename); - ret = module->ops->rename(module, request); - break; - case LDB_EXTENDED: - FIND_OP(module, extended); - ret = module->ops->extended(module, request); - break; - default: - FIND_OP(module, request); - ret = module->ops->request(module, request); - break; - } - - request->handle->nesting--; - - if (ret == LDB_SUCCESS) { - return ret; - } - if (!ldb_errstring(module->ldb)) { - /* Set a default error string, to place the blame somewhere */ - ldb_asprintf_errstring(module->ldb, "error in module %s: %s (%d)", module->ops->name, ldb_strerror(ret), ret); - } - - if (!(request->handle->flags & LDB_HANDLE_FLAG_DONE_CALLED)) { - /* It is _extremely_ common that a module returns a - * failure without calling ldb_module_done(), but that - * guarantees we will end up hanging in - * ldb_wait(). This fixes it without having to rewrite - * all our modules, and leaves us one less sharp - * corner for module developers to cut themselves on - */ - ret = ldb_module_done(request, NULL, NULL, ret); - } - return ret; -} - -int ldb_next_init(struct ldb_module *module) -{ - module = module->next; - - return ldb_module_init_chain(module->ldb, module); -} - -int ldb_next_start_trans(struct ldb_module *module) -{ - int ret; - FIND_OP(module, start_transaction); - ret = module->ops->start_transaction(module); - if (ret == LDB_SUCCESS) { - return ret; - } - if (!ldb_errstring(module->ldb)) { - /* Set a default error string, to place the blame somewhere */ - ldb_asprintf_errstring(module->ldb, "start_trans error in module %s: %s (%d)", module->ops->name, ldb_strerror(ret), ret); - } - if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) { - ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_next_start_trans error: %s", - ldb_errstring(module->ldb)); - } - return ret; -} - -int ldb_next_end_trans(struct ldb_module *module) -{ - int ret; - FIND_OP(module, end_transaction); - ret = module->ops->end_transaction(module); - if (ret == LDB_SUCCESS) { - return ret; - } - if (!ldb_errstring(module->ldb)) { - /* Set a default error string, to place the blame somewhere */ - ldb_asprintf_errstring(module->ldb, "end_trans error in module %s: %s (%d)", module->ops->name, ldb_strerror(ret), ret); - } - if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) { - ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_next_end_trans error: %s", - ldb_errstring(module->ldb)); - } - return ret; -} - -int ldb_next_prepare_commit(struct ldb_module *module) -{ - int ret; - FIND_OP_NOERR(module, prepare_commit); - if (module == NULL) { - /* we are allowed to have no prepare commit in - backends */ - return LDB_SUCCESS; - } - ret = module->ops->prepare_commit(module); - if (ret == LDB_SUCCESS) { - return ret; - } - if (!ldb_errstring(module->ldb)) { - /* Set a default error string, to place the blame somewhere */ - ldb_asprintf_errstring(module->ldb, "prepare_commit error in module %s: %s (%d)", module->ops->name, ldb_strerror(ret), ret); - } - if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) { - ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_next_prepare_commit error: %s", - ldb_errstring(module->ldb)); - } - return ret; -} - -int ldb_next_del_trans(struct ldb_module *module) -{ - int ret; - FIND_OP(module, del_transaction); - ret = module->ops->del_transaction(module); - if (ret == LDB_SUCCESS) { - return ret; - } - if (!ldb_errstring(module->ldb)) { - /* Set a default error string, to place the blame somewhere */ - ldb_asprintf_errstring(module->ldb, "del_trans error in module %s: %s (%d)", module->ops->name, ldb_strerror(ret), ret); - } - if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) { - ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_next_del_trans error: %s", - ldb_errstring(module->ldb)); - } - return ret; -} - -struct ldb_handle *ldb_handle_new(TALLOC_CTX *mem_ctx, struct ldb_context *ldb) -{ - struct ldb_handle *h; - - h = talloc_zero(mem_ctx, struct ldb_handle); - if (h == NULL) { - ldb_set_errstring(ldb, "Out of Memory"); - return NULL; - } - - h->status = LDB_SUCCESS; - h->state = LDB_ASYNC_INIT; - h->ldb = ldb; - h->flags = 0; - h->location = NULL; - h->parent = NULL; - - return h; -} - -/* calls the request callback to send an entry - * - * params: - * req: the original request passed to your module - * msg: reply message (must be a talloc pointer, and it will be stolen - * on the ldb_reply that is sent to the callback) - * ctrls: controls to send in the reply (must be a talloc pointer, and it will be stolen - * on the ldb_reply that is sent to the callback) - */ - -int ldb_module_send_entry(struct ldb_request *req, - struct ldb_message *msg, - struct ldb_control **ctrls) -{ - struct ldb_reply *ares; - - ares = talloc_zero(req, struct ldb_reply); - if (!ares) { - ldb_oom(req->handle->ldb); - req->callback(req, NULL); - return LDB_ERR_OPERATIONS_ERROR; - } - ares->type = LDB_REPLY_ENTRY; - ares->message = talloc_steal(ares, msg); - ares->controls = talloc_steal(ares, ctrls); - ares->error = LDB_SUCCESS; - - if ((req->handle->ldb->flags & LDB_FLG_ENABLE_TRACING) && - req->handle->nesting == 0) { - char *s; - ldb_debug_add(req->handle->ldb, "ldb_trace_response: ENTRY\n"); - s = ldb_ldif_message_string(req->handle->ldb, msg, LDB_CHANGETYPE_NONE, msg); - ldb_debug_add(req->handle->ldb, "%s\n", s); - talloc_free(s); - ldb_debug_end(req->handle->ldb, LDB_DEBUG_TRACE); - } - - return req->callback(req, ares); -} - -/* calls the request callback to send an referrals - * - * params: - * req: the original request passed to your module - * ref: referral string (must be a talloc pointeri, steal) - */ - -int ldb_module_send_referral(struct ldb_request *req, - char *ref) -{ - struct ldb_reply *ares; - - ares = talloc_zero(req, struct ldb_reply); - if (!ares) { - ldb_oom(req->handle->ldb); - req->callback(req, NULL); - return LDB_ERR_OPERATIONS_ERROR; - } - ares->type = LDB_REPLY_REFERRAL; - ares->referral = talloc_steal(ares, ref); - ares->error = LDB_SUCCESS; - - if ((req->handle->ldb->flags & LDB_FLG_ENABLE_TRACING) && - req->handle->nesting == 0) { - ldb_debug_add(req->handle->ldb, "ldb_trace_response: REFERRAL\n"); - ldb_debug_add(req->handle->ldb, "ref: %s\n", ref); - ldb_debug_end(req->handle->ldb, LDB_DEBUG_TRACE); - } - - return req->callback(req, ares); -} - -/* calls the original request callback - * - * params: - * req: the original request passed to your module - * ctrls: controls to send in the reply (must be a talloc pointer, steal) - * response: results for extended request (steal) - * error: LDB_SUCCESS for a successful return - * any other ldb error otherwise - */ -int ldb_module_done(struct ldb_request *req, - struct ldb_control **ctrls, - struct ldb_extended *response, - int error) -{ - struct ldb_reply *ares; - - ares = talloc_zero(req, struct ldb_reply); - if (!ares) { - ldb_oom(req->handle->ldb); - req->callback(req, NULL); - return LDB_ERR_OPERATIONS_ERROR; - } - ares->type = LDB_REPLY_DONE; - ares->controls = talloc_steal(ares, ctrls); - ares->response = talloc_steal(ares, response); - ares->error = error; - - req->handle->flags |= LDB_HANDLE_FLAG_DONE_CALLED; - - if ((req->handle->ldb->flags & LDB_FLG_ENABLE_TRACING) && - req->handle->nesting == 0) { - ldb_debug_add(req->handle->ldb, "ldb_trace_response: DONE\n"); - ldb_debug_add(req->handle->ldb, "error: %d\n", error); - if (ldb_errstring(req->handle->ldb)) { - ldb_debug_add(req->handle->ldb, "msg: %s\n", - ldb_errstring(req->handle->ldb)); - } - ldb_debug_end(req->handle->ldb, LDB_DEBUG_TRACE); - } - - return req->callback(req, ares); -} - -/* to be used *only* in modules init functions. - * this function is synchronous and will register - * the requested OID in the rootdse module if present - * otherwise it will return an error */ -int ldb_mod_register_control(struct ldb_module *module, const char *oid) -{ - struct ldb_request *req; - int ret; - - req = talloc_zero(module, struct ldb_request); - if (req == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } - - req->operation = LDB_REQ_REGISTER_CONTROL; - req->op.reg_control.oid = oid; - req->callback = ldb_op_default_callback; - - ldb_set_timeout(module->ldb, req, 0); - - req->handle = ldb_handle_new(req, module->ldb); - if (req->handle == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } - - ret = ldb_request(module->ldb, req); - if (ret == LDB_SUCCESS) { - ret = ldb_wait(req->handle, LDB_WAIT_ALL); - } - talloc_free(req); - - return ret; -} - -static int ldb_modules_load_dir(const char *modules_dir, const char *version); - - -/* - load one module. A static list of loaded module inode numbers is - used to prevent a module being loaded twice - - dlopen() is used on the module, and dlsym() is then used to look for - a ldb_init_module() function. If present, that function is called - with the ldb version number as an argument. - - The ldb_init_module() function will typically call - ldb_register_module() and ldb_register_backend() to register a - module or backend, but it may also be used to register command line - handling functions, ldif handlers or any other local - modififications. - - The ldb_init_module() function does not get a ldb_context passed in, - as modules will be used for multiple ldb context handles. The call - from the first ldb_init() is just a convenient way to ensure it is - called early enough. - */ -static int ldb_modules_load_path(const char *path, const char *version) -{ - void *handle; - int (*init_fn)(const char *); - int ret; - struct stat st; - static struct loaded { - struct loaded *next, *prev; - ino_t st_ino; - dev_t st_dev; - } *loaded; - struct loaded *le; - int dlopen_flags; - - ret = stat(path, &st); - if (ret != 0) { - fprintf(stderr, "ldb: unable to stat module %s : %s\n", path, strerror(errno)); - return LDB_ERR_UNAVAILABLE; - } - - for (le=loaded; le; le=le->next) { - if (le->st_ino == st.st_ino && - le->st_dev == st.st_dev) { - /* its already loaded */ - return LDB_SUCCESS; - } - } - - le = talloc(loaded, struct loaded); - if (le == NULL) { - fprintf(stderr, "ldb: unable to allocated loaded entry\n"); - return LDB_ERR_UNAVAILABLE; - } - - le->st_ino = st.st_ino; - le->st_dev = st.st_dev; - - DLIST_ADD_END(loaded, le, struct loaded); - - /* if it is a directory, recurse */ - if (S_ISDIR(st.st_mode)) { - return ldb_modules_load_dir(path, version); - } - - dlopen_flags = RTLD_NOW; -#ifdef RTLD_DEEPBIND - /* use deepbind if possible, to avoid issues with different - system library varients, for example ldb modules may be linked - against Heimdal while the application may use MIT kerberos - - See the dlopen manpage for details - */ - dlopen_flags |= RTLD_DEEPBIND; -#endif - - handle = dlopen(path, dlopen_flags); - if (handle == NULL) { - fprintf(stderr, "ldb: unable to dlopen %s : %s\n", path, dlerror()); - return LDB_SUCCESS; - } - - init_fn = dlsym(handle, "ldb_init_module"); - if (init_fn == NULL) { - /* ignore it, it could be an old-style - * module. Once we've converted all modules we - * could consider this an error */ - dlclose(handle); - return LDB_SUCCESS; - } - - ret = init_fn(version); - if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) { - /* the module is already registered - ignore this, as - * it can happen if LDB_MODULES_PATH points at both - * the build and install directory - */ - ret = LDB_SUCCESS; - } - return ret; -} - -static int qsort_string(const char **s1, const char **s2) -{ - return strcmp(*s1, *s2); -} - - -/* - load all modules from the given ldb modules directory. This is run once - during the first ldb_init() call. - - Modules are loaded in alphabetical order to ensure that any module - load ordering dependencies are reproducible. Modules should avoid - relying on load order - */ -static int ldb_modules_load_dir(const char *modules_dir, const char *version) -{ - DIR *dir; - struct dirent *de; - const char **modlist = NULL; - TALLOC_CTX *tmp_ctx = talloc_new(NULL); - unsigned i, num_modules = 0; - - dir = opendir(modules_dir); - if (dir == NULL) { - if (errno == ENOENT) { - talloc_free(tmp_ctx); - /* we don't have any modules */ - return LDB_SUCCESS; - } - talloc_free(tmp_ctx); - fprintf(stderr, "ldb: unable to open modules directory '%s' - %s\n", - modules_dir, strerror(errno)); - return LDB_ERR_UNAVAILABLE; - } - - - while ((de = readdir(dir))) { - if (ISDOT(de->d_name) || ISDOTDOT(de->d_name)) - continue; - - modlist = talloc_realloc(tmp_ctx, modlist, const char *, num_modules+1); - if (modlist == NULL) { - talloc_free(tmp_ctx); - closedir(dir); - fprintf(stderr, "ldb: unable to allocate modules list\n"); - return LDB_ERR_UNAVAILABLE; - } - modlist[num_modules] = talloc_asprintf(modlist, "%s/%s", modules_dir, de->d_name); - if (modlist[num_modules] == NULL) { - talloc_free(tmp_ctx); - closedir(dir); - fprintf(stderr, "ldb: unable to allocate module list entry\n"); - return LDB_ERR_UNAVAILABLE; - } - num_modules++; - } - - closedir(dir); - - /* sort the directory, so we get consistent load ordering */ - TYPESAFE_QSORT(modlist, num_modules, qsort_string); - - for (i=0; i<num_modules; i++) { - int ret = ldb_modules_load_path(modlist[i], version); - if (ret != LDB_SUCCESS) { - fprintf(stderr, "ldb: failed to initialise module %s : %s\n", - modlist[i], ldb_strerror(ret)); - talloc_free(tmp_ctx); - return ret; - } - } - - talloc_free(tmp_ctx); - - return LDB_SUCCESS; -} - -/* - load any additional modules from the given directory -*/ -void ldb_set_modules_dir(struct ldb_context *ldb, const char *path) -{ - int ret = ldb_modules_load_path(path, LDB_VERSION); - if (ret != LDB_SUCCESS) { - ldb_asprintf_errstring(ldb, "Failed to load modules from: %s\n", path); - } -} - - -/* - load all modules static (builtin) modules - */ -static int ldb_modules_load_static(const char *version) -{ - static bool initialised; -#define _MODULE_PROTO(init) extern int init(const char *); - STATIC_ldb_MODULES_PROTO; - const ldb_module_init_fn static_init_functions[] = { STATIC_ldb_MODULES }; - unsigned i; - - if (initialised) { - return LDB_SUCCESS; - } - initialised = true; - - for (i=0; static_init_functions[i]; i++) { - int ret = static_init_functions[i](version); - if (ret != LDB_SUCCESS) { - return ret; - } - } - return LDB_SUCCESS; -} - -/* - load all modules from the given ldb modules path, colon - separated. - - modules are loaded recursively for all subdirectories in the paths - */ -int ldb_modules_load(const char *modules_path, const char *version) -{ - char *tok, *path, *tok_ptr=NULL; - int ret; - - ret = ldb_modules_load_static(version); - if (ret != LDB_SUCCESS) { - return ret; - } - - path = talloc_strdup(NULL, modules_path); - if (path == NULL) { - fprintf(stderr, "ldb: failed to allocate modules_path\n"); - return LDB_ERR_UNAVAILABLE; - } - - for (tok=strtok_r(path, ":", &tok_ptr); - tok; - tok=strtok_r(NULL, ":", &tok_ptr)) { - ret = ldb_modules_load_path(tok, version); - if (ret != LDB_SUCCESS) { - talloc_free(path); - return ret; - } - } - talloc_free(path); - - return LDB_SUCCESS; -} - - -/* - return a string representation of the calling chain for the given - ldb request - */ -char *ldb_module_call_chain(struct ldb_request *req, TALLOC_CTX *mem_ctx) -{ - char *ret; - unsigned int i = 0; - - ret = talloc_strdup(mem_ctx, ""); - if (ret == NULL) { - return NULL; - } - - while (req && req->handle) { - char *s = talloc_asprintf_append_buffer(ret, "req[%u] %p : %s\n", - i++, req, ldb_req_location(req)); - if (s == NULL) { - talloc_free(ret); - return NULL; - } - ret = s; - req = req->handle->parent; - } - return ret; -} - - -/* - return the next module in the chain - */ -struct ldb_module *ldb_module_next(struct ldb_module *module) -{ - return module->next; -} - -/* - set the next module in the module chain - */ -void ldb_module_set_next(struct ldb_module *module, struct ldb_module *next) -{ - module->next = next; -} - - -/* - get the popt_options pointer in the ldb structure. This allows a ldb - module to change the command line parsing - */ -struct poptOption **ldb_module_popt_options(struct ldb_context *ldb) -{ - return &ldb->popt_options; -} - - -/* - return the current ldb flags LDB_FLG_* - */ -uint32_t ldb_module_flags(struct ldb_context *ldb) -{ - return ldb->flags; -} |