-/*
+/*
ldb database library
Copyright (C) Andrew Tridgell 2004
- Copyright (C) Simo Sorce 2005-2006
+ Copyright (C) Simo Sorce 2005-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
#include "ldb_includes.h"
-/*
+/*
initialise a ldb context
- The mem_ctx is optional
+ The mem_ctx is required
+ The event_ctx is required
*/
-struct ldb_context *ldb_init(void *mem_ctx)
+struct ldb_context *ldb_init(TALLOC_CTX *mem_ctx, struct event_context *ev_ctx)
{
- struct ldb_context *ldb = talloc_zero(mem_ctx, struct ldb_context);
+ struct ldb_context *ldb;
int ret;
+ ldb = talloc_zero(mem_ctx, struct ldb_context);
+ /* FIXME: Hack a new event context so that CMD line utilities work
+ * until we have them all converted */
+ if (ev_ctx == NULL) {
+ ev_ctx = event_context_init(talloc_autofree_context());
+ }
+
ret = ldb_setup_wellknown_attributes(ldb);
if (ret != 0) {
talloc_free(ldb);
ldb_set_utf8_default(ldb);
ldb_set_create_perms(ldb, 0666);
ldb_set_modules_dir(ldb, LDB_MODULESDIR);
+ ldb_set_event_context(ldb, ev_ctx);
+
+ /* TODO: get timeout from options if available there */
+ ldb->default_timeout = 300; /* set default to 5 minutes */
return ldb;
}
-struct ldb_backend {
- const char *name;
- ldb_connect_fn connect_fn;
- struct ldb_backend *prev, *next;
+static struct backends_list_entry {
+ struct ldb_backend_ops *ops;
+ struct backends_list_entry *prev, *next;
} *ldb_backends = NULL;
+#ifndef STATIC_LIBLDB_BACKENDS
+
+#ifdef HAVE_LDB_LDAP
+#define LDAP_INIT &ldb_ldap_backend_ops, \
+ &ldb_ldapi_backend_ops, \
+ &ldb_ldaps_backend_ops,
+#else
+#define LDAP_INIT
+#endif
+
+#ifdef HAVE_LDB_SQLITE3
+#define SQLITE3_INIT &ldb_sqlite3_backend_ops,
+#else
+#define SQLITE3_INIT
+#endif
+
+#define STATIC_LIBLDB_BACKENDS \
+ LDAP_INIT \
+ SQLITE3_INIT \
+ &ldb_tdb_backend_ops, \
+ NULL
+#endif
+
+const static struct ldb_backend_ops *builtin_backends[] = {
+ STATIC_LIBLDB_BACKENDS
+};
static ldb_connect_fn ldb_find_backend(const char *url)
{
- struct ldb_backend *backend;
+ struct backends_list_entry *backend;
+ int i;
+
+ for (i = 0; builtin_backends[i]; i++) {
+ if (strncmp(builtin_backends[i]->name, url,
+ strlen(builtin_backends[i]->name)) == 0)
+ return builtin_backends[i]->connect_fn;
+ }
for (backend = ldb_backends; backend; backend = backend->next) {
- if (strncmp(backend->name, url, strlen(backend->name)) == 0) {
- return backend->connect_fn;
+ if (strncmp(backend->ops->name, url,
+ strlen(backend->ops->name)) == 0) {
+ return backend->ops->connect_fn;
}
}
*/
int ldb_register_backend(const char *url_prefix, ldb_connect_fn connectfn)
{
- struct ldb_backend *backend = talloc(talloc_autofree_context(), struct ldb_backend);
+ struct ldb_backend_ops *backend;
+ struct backends_list_entry *entry;
+
+ backend = talloc(talloc_autofree_context(), struct ldb_backend_ops);
+ if (!backend) return LDB_ERR_OPERATIONS_ERROR;
+
+ entry = talloc(talloc_autofree_context(), struct backends_list_entry);
+ if (!entry) {
+ talloc_free(backend);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
if (ldb_find_backend(url_prefix)) {
return LDB_SUCCESS;
backend->name = talloc_strdup(backend, url_prefix);
backend->connect_fn = connectfn;
- DLIST_ADD(ldb_backends, backend);
+ entry->ops = backend;
+ DLIST_ADD(ldb_backends, entry);
return LDB_SUCCESS;
}
-/*
- Return the ldb module form of a database. The URL can either be one of the following forms
+/*
+ Return the ldb module form of a database.
+ The URL can either be one of the following forms
ldb://path
ldapi://path
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.
+ 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_connect_backend(struct ldb_context *ldb, const char *url, const char *options[],
+int ldb_connect_backend(struct ldb_context *ldb,
+ const char *url,
+ const char *options[],
struct ldb_module **backend_module)
{
int ret;
fn = ldb_find_backend(backend);
if (fn == NULL) {
- int (*init_fn) (void);
-
- init_fn = ldb_dso_load_symbol(ldb, backend,
- "init_module");
- if (init_fn != NULL && init_fn() == 0) {
- fn = ldb_find_backend(backend);
+ struct ldb_backend_ops *ops;
+ char *symbol_name = talloc_asprintf(ldb, "ldb_%s_backend_ops", backend);
+ if (symbol_name == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ ops = ldb_dso_load_symbol(ldb, backend, symbol_name);
+ if (ops != NULL) {
+ fn = ops->connect_fn;
}
+ talloc_free(symbol_name);
}
talloc_free(backend);
if (fn == NULL) {
- ldb_debug(ldb, LDB_DEBUG_FATAL, "Unable to find backend for '%s'\n", url);
+ ldb_debug(ldb, LDB_DEBUG_FATAL,
+ "Unable to find backend for '%s'\n", url);
return LDB_ERR_OTHER;
}
ret = fn(ldb, url, ldb->flags, options, backend_module);
if (ret != LDB_SUCCESS) {
- ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to connect to '%s'\n", url);
+ ldb_debug(ldb, LDB_DEBUG_ERROR,
+ "Failed to connect to '%s'\n", url);
return ret;
}
return ret;
};
tmp_ctx = talloc_new(ldb);
- ret = ldb_search(ldb, ldb_dn_new(tmp_ctx, ldb, NULL), LDB_SCOPE_BASE,
+ ret = ldb_search(ldb, ldb_dn_new(tmp_ctx, ldb, NULL), LDB_SCOPE_BASE,
"(objectClass=*)", attrs, &res);
- if (ret == LDB_SUCCESS) {
- if (res->count == 1) {
- if (!ldb_get_opaque(ldb, "rootDomainNamingContext")) {
- tmp_dn = ldb_msg_find_attr_as_dn(ldb, ldb, res->msgs[0], "rootDomainNamingContext");
- ldb_set_opaque(ldb, "rootDomainNamingContext", tmp_dn);
- }
-
- if (!ldb_get_opaque(ldb, "configurationNamingContext")) {
- tmp_dn = ldb_msg_find_attr_as_dn(ldb, ldb, res->msgs[0], "configurationNamingContext");
- ldb_set_opaque(ldb, "configurationNamingContext", tmp_dn);
- }
-
- if (!ldb_get_opaque(ldb, "schemaNamingContext")) {
- tmp_dn = ldb_msg_find_attr_as_dn(ldb, ldb, res->msgs[0], "schemaNamingContext");
- ldb_set_opaque(ldb, "schemaNamingContext", tmp_dn);
- }
-
- if (!ldb_get_opaque(ldb, "defaultNamingContext")) {
- tmp_dn = ldb_msg_find_attr_as_dn(ldb, ldb, res->msgs[0], "defaultNamingContext");
- ldb_set_opaque(ldb, "defaultNamingContext", tmp_dn);
- }
- }
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return;
+ }
+
+ if (res->count != 1) {
talloc_free(res);
+ return;
+ }
+
+ if (!ldb_get_opaque(ldb, "rootDomainNamingContext")) {
+ tmp_dn = ldb_msg_find_attr_as_dn(ldb, ldb, res->msgs[0],
+ "rootDomainNamingContext");
+ ldb_set_opaque(ldb, "rootDomainNamingContext", tmp_dn);
+ }
+
+ if (!ldb_get_opaque(ldb, "configurationNamingContext")) {
+ tmp_dn = ldb_msg_find_attr_as_dn(ldb, ldb, res->msgs[0],
+ "configurationNamingContext");
+ ldb_set_opaque(ldb, "configurationNamingContext", tmp_dn);
}
+ if (!ldb_get_opaque(ldb, "schemaNamingContext")) {
+ tmp_dn = ldb_msg_find_attr_as_dn(ldb, ldb, res->msgs[0],
+ "schemaNamingContext");
+ ldb_set_opaque(ldb, "schemaNamingContext", tmp_dn);
+ }
+
+ if (!ldb_get_opaque(ldb, "defaultNamingContext")) {
+ tmp_dn = ldb_msg_find_attr_as_dn(ldb, ldb, res->msgs[0],
+ "defaultNamingContext");
+ ldb_set_opaque(ldb, "defaultNamingContext", tmp_dn);
+ }
+
+ talloc_free(res);
talloc_free(tmp_ctx);
}
struct ldb_dn *ldb_get_root_basedn(struct ldb_context *ldb)
{
- return talloc_get_type(ldb_get_opaque(ldb, "rootDomainNamingContext"), struct ldb_dn);
+ void *opaque = ldb_get_opaque(ldb, "rootDomainNamingContext");
+ return talloc_get_type(opaque, struct ldb_dn);
}
struct ldb_dn *ldb_get_config_basedn(struct ldb_context *ldb)
{
- return talloc_get_type(ldb_get_opaque(ldb, "configurationNamingContext"), struct ldb_dn);
+ void *opaque = ldb_get_opaque(ldb, "configurationNamingContext");
+ return talloc_get_type(opaque, struct ldb_dn);
}
struct ldb_dn *ldb_get_schema_basedn(struct ldb_context *ldb)
{
- return talloc_get_type(ldb_get_opaque(ldb, "schemaNamingContext"), struct ldb_dn);
+ void *opaque = ldb_get_opaque(ldb, "schemaNamingContext");
+ return talloc_get_type(opaque, struct ldb_dn);
}
struct ldb_dn *ldb_get_default_basedn(struct ldb_context *ldb)
{
- return talloc_get_type(ldb_get_opaque(ldb, "defaultNamingContext"), struct ldb_dn);
+ void *opaque = ldb_get_opaque(ldb, "defaultNamingContext");
+ return talloc_get_type(opaque, struct ldb_dn);
}
-/*
- connect to a database. The URL can either be one of the following forms
+/*
+ connect to a database. The URL can either be one of the following forms
ldb://path
ldapi://path
the options are passed uninterpreted to the backend, and are
backend specific
*/
-int ldb_connect(struct ldb_context *ldb, const char *url, unsigned int flags, const char *options[])
+int ldb_connect(struct ldb_context *ldb, const char *url,
+ unsigned int flags, const char *options[])
{
int ret;
const char *url2;
- /* We seem to need to do this here, or else some utilities don't get ldb backends */
- ldb_global_init();
+ /* We seem to need to do this here, or else some utilities don't
+ * get ldb backends */
ldb->flags = flags;
}
if (ldb_load_modules(ldb, options) != LDB_SUCCESS) {
- ldb_debug(ldb, LDB_DEBUG_FATAL, "Unable to load modules for %s: %s\n",
+ ldb_debug(ldb, LDB_DEBUG_FATAL,
+ "Unable to load modules for %s: %s\n",
url, ldb_errstring(ldb));
return LDB_ERR_OTHER;
}
if (ldb->err_string == NULL) {
/* no error string was setup by the backend */
ldb_asprintf_errstring(ldb,
- "ldb transaction start: %s (%d)",
- ldb_strerror(status),
- status);
+ "ldb transaction start: %s (%d)",
+ ldb_strerror(status),
+ status);
}
}
return status;
if (status != LDB_SUCCESS) {
if (ldb->err_string == NULL) {
/* no error string was setup by the backend */
- ldb_asprintf_errstring(ldb,
- "ldb transaction commit: %s (%d)",
- ldb_strerror(status),
- status);
+ ldb_asprintf_errstring(ldb,
+ "ldb transaction commit: %s (%d)",
+ ldb_strerror(status),
+ status);
}
}
return status;
if (status != LDB_SUCCESS) {
if (ldb->err_string == NULL) {
/* no error string was setup by the backend */
- ldb_asprintf_errstring(ldb,
- "ldb transaction cancel: %s (%d)",
- ldb_strerror(status),
- status);
+ ldb_asprintf_errstring(ldb,
+ "ldb transaction cancel: %s (%d)",
+ ldb_strerror(status),
+ status);
}
}
return status;
}
/* autostarts a transacion if none active */
-static int ldb_autotransaction_request(struct ldb_context *ldb, struct ldb_request *req)
+static int ldb_autotransaction_request(struct ldb_context *ldb,
+ struct ldb_request *req)
{
int ret;
int ldb_wait(struct ldb_handle *handle, enum ldb_wait_type type)
{
+ int ret;
if (!handle) {
return LDB_SUCCESS;
}
- return handle->module->ops->wait(handle, type);
+ ret = handle->module->ops->wait(handle, type);
+ if (!ldb_errstring(handle->module->ldb)) {
+ /* Set a default error string, to place the blame somewhere */
+ ldb_asprintf_errstring(handle->module->ldb,
+ "error waiting on module %s: %s (%d)",
+ handle->module->ops->name,
+ ldb_strerror(ret), ret);
+ }
+ return ret;
}
/* set the specified timeout or, if timeout is 0 set the default timeout */
/* timeout == -1 means no timeout */
-int ldb_set_timeout(struct ldb_context *ldb, struct ldb_request *req, int timeout)
+int ldb_set_timeout(struct ldb_context *ldb,
+ struct ldb_request *req,
+ int timeout)
{
if (req == NULL) return LDB_ERR_OPERATIONS_ERROR;
-
+
if (timeout != 0) {
req->timeout = timeout;
} else {
}
/* calculates the new timeout based on the previous starttime and timeout */
-int ldb_set_timeout_from_prev_req(struct ldb_context *ldb, struct ldb_request *oldreq, struct ldb_request *newreq)
+int ldb_set_timeout_from_prev_req(struct ldb_context *ldb,
+ struct ldb_request *oldreq,
+ struct ldb_request *newreq)
{
time_t now;
}
-/*
+/*
set the permissions for new files to be passed to open() in
backends that use local files
*/
ldb->create_perms = perms;
}
+void ldb_set_event_context(struct ldb_context *ldb, struct event_context *ev)
+{
+ ldb->ev_ctx = ev;
+}
+
+struct event_context * ldb_get_event_context(struct ldb_context *ldb)
+{
+ return ldb->ev_ctx;
+}
+
/*
start an ldb request
NOTE: the request must be a talloc context.
Use talloc_free to free the ldb_message returned in 'res', if successful
*/
-int ldb_search_default_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
+int ldb_search_default_callback(struct ldb_context *ldb,
+ void *context,
+ struct ldb_reply *ares)
{
struct ldb_result *res;
int n;
-
+
if (!context) {
ldb_set_errstring(ldb, "NULL Context in callback");
return LDB_ERR_OPERATIONS_ERROR;
- }
+ }
res = talloc_get_type(context, struct ldb_result);
switch (ares->type) {
case LDB_REPLY_ENTRY:
- res->msgs = talloc_realloc(res, res->msgs, struct ldb_message *, res->count + 2);
+ res->msgs = talloc_realloc(res, res->msgs,
+ struct ldb_message *,
+ res->count + 2);
if (! res->msgs) {
goto error;
}
break;
case LDB_REPLY_EXTENDED:
case LDB_REPLY_DONE:
- /* TODO: we should really support controls on entries and referrals too! */
+ /* TODO: we should really support controls on entries
+ * and referrals too! */
res->controls = talloc_move(res, &ares->controls);
- break;
+ break;
}
talloc_free(ares);
return LDB_SUCCESS;
return LDB_SUCCESS;
}
-int ldb_extended_default_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
+int ldb_extended_default_callback(struct ldb_context *ldb,
+ void *context,
+ struct ldb_reply *ares)
{
struct ldb_result *res;
-
+
if (!context) {
ldb_set_errstring(ldb, "NULL Context in callback");
return LDB_ERR_OPERATIONS_ERROR;
ldb_set_errstring(ldb, "invalid ares type in callback");
goto error;
case LDB_REPLY_EXTENDED:
- /* TODO: we should really support controls on entries and referrals too! */
+ /* TODO: we should really support controls on entries and
+ * referrals too! */
res->extended = talloc_move(res, &ares->response);
res->controls = talloc_move(res, &ares->controls);
- break;
+ break;
}
talloc_free(ares);
return LDB_SUCCESS;
return LDB_SUCCESS;
}
-int ldb_extended(struct ldb_context *ldb,
+int ldb_extended(struct ldb_context *ldb,
const char *oid,
void *data,
struct ldb_result **_res)
ldb_set_timeout(ldb, req, 0); /* use default timeout */
ret = ldb_request(ldb, req);
-
+
if (ret == LDB_SUCCESS) {
ret = ldb_wait(req->handle, LDB_WAIT_ALL);
}
}
/*
- note that ldb_search() will automatically replace a NULL 'base' value with the
- defaultNamingContext from the rootDSE if available.
+ note that ldb_search() will automatically replace a NULL 'base' value
+ with the defaultNamingContext from the rootDSE if available.
*/
-int ldb_search(struct ldb_context *ldb,
+int ldb_search(struct ldb_context *ldb,
struct ldb_dn *base,
enum ldb_scope scope,
const char *expression,
- const char * const *attrs,
+ const char * const *attrs,
struct ldb_result **_res)
{
struct ldb_request *req;
ldb_set_timeout(ldb, req, 0); /* use default timeout */
ret = ldb_request(ldb, req);
-
+
if (ret == LDB_SUCCESS) {
ret = ldb_wait(req->handle, LDB_WAIT_ALL);
}
takes a memory context where results are allocated
*/
-int ldb_search_exp_fmt(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_result **result,
- struct ldb_dn *base, enum ldb_scope scope, const char * const *attrs,
+int ldb_search_exp_fmt(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
+ struct ldb_result **result, struct ldb_dn *base,
+ enum ldb_scope scope, const char * const *attrs,
const char *exp_fmt, ...)
{
struct ldb_result *res;
}
/*
- add a record to the database. Will fail if a record with the given class and key
- already exists
+ add a record to the database. Will fail if a record with the
+ given class and key already exists
*/
-int ldb_add(struct ldb_context *ldb,
+int ldb_add(struct ldb_context *ldb,
const struct ldb_message *message)
{
struct ldb_request *req;
/*
modify the specified attributes of a record
*/
-int ldb_modify(struct ldb_context *ldb,
+int ldb_modify(struct ldb_context *ldb,
const struct ldb_message *message)
{
struct ldb_request *req;
/*
rename a record in the database
*/
-int ldb_rename(struct ldb_context *ldb, struct ldb_dn *olddn, struct ldb_dn *newdn)
+int ldb_rename(struct ldb_context *ldb,
+ struct ldb_dn *olddn, struct ldb_dn *newdn)
{
struct ldb_request *req;
int ret;
/*
return the global sequence number
*/
-int ldb_sequence_number(struct ldb_context *ldb, enum ldb_sequence_type type, uint64_t *seq_num)
+int ldb_sequence_number(struct ldb_context *ldb,
+ enum ldb_sequence_type type,
+ uint64_t *seq_num)
{
struct ldb_request *req;
int ret;
req->op.seq_num.type = type;
/* do request and autostart a transaction */
ret = ldb_request(ldb, req);
-
+
if (ret == LDB_SUCCESS) {
*seq_num = req->op.seq_num.seq_num;
}
/*
- return extended error information
+ return extended error information
*/
const char *ldb_errstring(struct ldb_context *ldb)
{