-
/*
ldb database library
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.
+ 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
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
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
/*
* Author: Simo Sorce
*/
+#include "ldb_includes.h"
+
+#if (_SAMBA_BUILD_ >= 4)
#include "includes.h"
-#include "ldb/include/ldb.h"
-#include "ldb/include/ldb_errors.h"
-#include "ldb/include/ldb_private.h"
-#include "dlinklist.h"
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#ifdef HAVE_DLOPEN_DISABLED
-#include <dlfcn.h>
+#include "build.h"
#endif
#define LDB_MODULE_PREFIX "modules:"
#define LDB_MODULE_PREFIX_LEN 8
-static char *talloc_strdup_no_spaces(struct ldb_context *ldb, const char *string)
+void ldb_set_modules_dir(struct ldb_context *ldb, const char *path)
+{
+ talloc_free(ldb->modules_dir);
+ ldb->modules_dir = talloc_strdup(ldb, path);
+}
+
+static char *ldb_modules_strdup_no_spaces(TALLOC_CTX *mem_ctx, const char *string)
{
int i, len;
char *trimmed;
- trimmed = talloc_strdup(ldb, string);
+ trimmed = talloc_strdup(mem_ctx, string);
if (!trimmed) {
- ldb_debug(ldb, LDB_DEBUG_FATAL, "Out of Memory in talloc_strdup_trim_spaces()\n");
return NULL;
}
/* modules are called in inverse order on the stack.
Lets place them as an admin would think the right order is.
- Modules order is imprtant */
-static char **ldb_modules_list_from_string(struct ldb_context *ldb, const char *string)
+ 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;
int i;
/* spaces not admitted */
- modstr = talloc_strdup_no_spaces(ldb, string);
+ 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()\n");
return NULL;
}
- modules = talloc_realloc(ldb, modules, char *, 2);
+ 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()\n");
talloc_free(modstr);
talloc_steal(modules, modstr);
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(ldb, modules, char *, i + 2);
+ 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()\n");
return NULL;
modules[i + 1] = NULL;
- return modules;
+ m = (const char **)modules;
+
+ return m;
+}
+
+static struct ops_list_entry {
+ const struct ldb_module_ops *ops;
+ struct ops_list_entry *next;
+} *registered_modules = NULL;
+
+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;
+}
+
+#ifndef STATIC_LIBLDB_MODULES
+
+#ifdef HAVE_LDB_LDAP
+#define LDAP_INIT ldb_ldap_init,
+#else
+#define LDAP_INIT
+#endif
+
+#ifdef HAVE_LDB_SQLITE3
+#define SQLITE3_INIT ldb_sqlite3_init,
+#else
+#define SQLITE3_INIT
+#endif
+
+#define STATIC_LIBLDB_MODULES \
+ { \
+ LDAP_INIT \
+ SQLITE3_INIT \
+ ldb_tdb_init, \
+ ldb_operational_init, \
+ ldb_rdn_name_init, \
+ ldb_paged_results_init, \
+ ldb_sort_init, \
+ ldb_asq_init, \
+ NULL \
+ }
+#endif
+
+int ldb_global_init(void)
+{
+ static int (*static_init_fns[])(void) = STATIC_LIBLDB_MODULES;
+
+ static int initialized = 0;
+ int ret = 0, i;
+
+ if (initialized)
+ return 0;
+
+ initialized = 1;
+
+ for (i = 0; static_init_fns[i]; i++) {
+ if (static_init_fns[i]() == -1)
+ ret = -1;
+ }
+
+ return ret;
+}
+
+int ldb_register_module(const struct ldb_module_ops *ops)
+{
+ struct ops_list_entry *entry = talloc(talloc_autofree_context(), struct ops_list_entry);
+
+ if (ldb_find_module_ops(ops->name) != NULL)
+ return -1;
+
+ if (entry == NULL)
+ return -1;
+
+ entry->ops = ops;
+ entry->next = registered_modules;
+ registered_modules = entry;
+
+ return 0;
+}
+
+int ldb_try_load_dso(struct ldb_context *ldb, const char *name)
+{
+ char *path;
+ void *handle;
+ int (*init_fn) (void);
+
+ if (ldb->modules_dir == NULL)
+ return -1;
+
+ path = talloc_asprintf(ldb, "%s/%s.%s", ldb->modules_dir, name,
+ SHLIBEXT);
+
+ ldb_debug(ldb, LDB_DEBUG_TRACE, "trying to load %s from %s\n", name, path);
+
+ handle = dlopen(path, RTLD_NOW);
+ if (handle == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_WARNING, "unable to load %s from %s: %s\n", name, path, dlerror());
+ return -1;
+ }
+
+ init_fn = (int (*)(void))dlsym(handle, "init_module");
+
+ if (init_fn == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_ERROR, "no symbol `init_module' found in %s: %s\n", path, dlerror());
+ return -1;
+ }
+
+ talloc_free(path);
+
+ return init_fn();
+}
+
+int ldb_load_modules_list(struct ldb_context *ldb, const char **module_list, struct ldb_module *backend, struct ldb_module **out)
+{
+ struct ldb_module *module;
+ int i;
+
+ module = backend;
+
+ for (i = 0; module_list[i] != NULL; i++) {
+ struct ldb_module *current;
+ const struct ldb_module_ops *ops;
+
+ ops = ldb_find_module_ops(module_list[i]);
+ if (ops == NULL) {
+ if (ldb_try_load_dso(ldb, module_list[i]) == 0) {
+ ops = ldb_find_module_ops(module_list[i]);
+ }
+ }
+
+ if (ops == NULL) {
+ ldb_debug(ldb, LDB_DEBUG_WARNING, "WARNING: Module [%s] not found\n",
+ module_list[i]);
+ continue;
+ }
+
+ 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;
+}
+
+int ldb_init_module_chain(struct ldb_context *ldb, struct ldb_module *module)
+{
+ while (module && module->ops->init_context == NULL)
+ module = module->next;
+
+ if (module && module->ops->init_context &&
+ module->ops->init_context(module) != LDB_SUCCESS) {
+ ldb_debug(ldb, LDB_DEBUG_FATAL, "module initialization failed\n");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return LDB_SUCCESS;
}
int ldb_load_modules(struct ldb_context *ldb, const char *options[])
{
- char **modules = NULL;
+ const char **modules = NULL;
int i;
- struct {
- const char *name;
- ldb_module_init_t init;
- } well_known_modules[] = {
- { "schema", schema_module_init },
- { "operational", operational_module_init },
- { "rdn_name", rdn_name_module_init },
- { "objectclass", objectclass_module_init },
-#ifdef _SAMBA_BUILD_
- { "objectguid", objectguid_module_init },
- { "samldb", samldb_module_init },
- { "samba3sam", ldb_samba3sam_module_init },
- { "proxy", proxy_module_init },
- { "rootdse", rootdse_module_init },
- { "password_hash", password_hash_module_init },
-#endif
- { NULL, NULL }
- };
+ int ret;
+ TALLOC_CTX *mem_ctx = talloc_new(ldb);
+ if (!mem_ctx) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
/* find out which modules we are requested to activate */
if (options) {
for (i = 0; options[i] != NULL; i++) {
if (strncmp(options[i], LDB_MODULE_PREFIX, LDB_MODULE_PREFIX_LEN) == 0) {
- modules = ldb_modules_list_from_string(ldb, &options[i][LDB_MODULE_PREFIX_LEN]);
+ modules = ldb_modules_list_from_string(ldb, mem_ctx, &options[i][LDB_MODULE_PREFIX_LEN]);
}
}
}
- /* if not overloaded by options and the backend is not ldap try to load the modules list form ldb */
+ /* 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)) {
- int ret;
const char * const attrs[] = { "@LIST" , NULL};
struct ldb_result *res = NULL;
- struct ldb_dn *mods;
+ struct ldb_dn *mods_dn;
- mods = ldb_dn_explode(ldb, "@MODULES");
- if (mods == NULL) {
+ mods_dn = ldb_dn_new(mem_ctx, ldb, "@MODULES");
+ if (mods_dn == NULL) {
+ talloc_free(mem_ctx);
return -1;
}
- ret = ldb_search(ldb, mods, LDB_SCOPE_BASE, "", attrs, &res);
- talloc_free(mods);
+ ret = ldb_search(ldb, mods_dn, LDB_SCOPE_BASE, "", attrs, &res);
+ talloc_steal(mods_dn, res);
if (ret == LDB_SUCCESS && (res->count == 0 || res->msgs[0]->num_elements == 0)) {
- ldb_debug(ldb, LDB_DEBUG_TRACE, "no modules required by the db\n");
+ 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\n", ldb_errstring(ldb));
+ talloc_free(mem_ctx);
return -1;
}
if (res->count > 1) {
ldb_debug(ldb, LDB_DEBUG_FATAL, "Too many records found (%d), bailing out\n", res->count);
- talloc_free(res);
+ talloc_free(mem_ctx);
return -1;
}
- modules = ldb_modules_list_from_string(ldb,
+ modules = ldb_modules_list_from_string(ldb, mem_ctx,
(const char *)res->msgs[0]->elements[0].values[0].data);
}
- talloc_free(res);
+ talloc_free(mods_dn);
}
- if (modules == NULL) {
- ldb_debug(ldb, LDB_DEBUG_TRACE, "No modules specified for this database\n");
- return 0;
- }
-
- for (i = 0; modules[i] != NULL; i++) {
- struct ldb_module *current;
- int m;
- for (m=0;well_known_modules[m].name;m++) {
- if (strcmp(modules[i], well_known_modules[m].name) == 0) {
- current = well_known_modules[m].init(ldb, options);
- if (current == NULL) {
- ldb_debug(ldb, LDB_DEBUG_FATAL, "function 'init_module' in %s fails\n", modules[i]);
- return -1;
- }
- DLIST_ADD(ldb->modules, current);
- break;
- }
- }
- if (well_known_modules[m].name == NULL) {
- ldb_debug(ldb, LDB_DEBUG_WARNING, "WARNING: Module [%s] not found\n",
- modules[i]);
+ if (modules != NULL) {
+ ret = ldb_load_modules_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");
}
- talloc_free(modules);
- return 0;
+ ret = ldb_init_module_chain(ldb, ldb->modules);
+ talloc_free(mem_ctx);
+ return ret;
}
/*
when ldb is extended
*/
#define FIND_OP(module, op) do { \
+ struct ldb_context *ldb = module->ldb; \
module = module->next; \
while (module && module->ops->op == NULL) module = module->next; \
- if (module == NULL) return -1; \
+ if (module == NULL) { \
+ ldb_asprintf_errstring(ldb, "Unable to find backend operation for " #op ); \
+ return LDB_ERR_OPERATIONS_ERROR; \
+ } \
} while (0)
/*
helper functions to call the next module in chain
*/
+
int ldb_next_request(struct ldb_module *module, struct ldb_request *request)
{
- FIND_OP(module, request);
- return module->ops->request(module, request);
+ int ret;
+ 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;
+ case LDB_SEQUENCE_NUMBER:
+ FIND_OP(module, sequence_number);
+ ret = module->ops->sequence_number(module, request);
+ break;
+ default:
+ FIND_OP(module, request);
+ ret = module->ops->request(module, request);
+ break;
+ }
+ 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);
+ }
+ return ret;
+}
+
+int ldb_next_init(struct ldb_module *module)
+{
+ /* init is different in that it is not an error if modules
+ * do not require initialization */
+
+ module = module->next;
+
+ while (module && module->ops->init_context == NULL)
+ module = module->next;
+
+ if (module == NULL)
+ return LDB_SUCCESS;
+
+ return module->ops->init_context(module);
}
int ldb_next_start_trans(struct ldb_module *module)
FIND_OP(module, del_transaction);
return module->ops->del_transaction(module);
}
-
-void ldb_set_errstring(struct ldb_module *module, char *err_string)
-{
- if (module->ldb->err_string) {
- talloc_free(module->ldb->err_string);
- }
-
- module->ldb->err_string = talloc_steal(module->ldb, err_string);
-}
-