-/*
+/*
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
* Author: Andrew Tridgell
*/
-#include "ldb_includes.h"
-
-/*
- initialise a ldb context
- The mem_ctx is optional
-*/
-struct ldb_context *ldb_init(void *mem_ctx)
-{
- struct ldb_context *ldb = talloc_zero(mem_ctx, struct ldb_context);
- int ret;
-
- ret = ldb_setup_wellknown_attributes(ldb);
- if (ret != 0) {
- talloc_free(ldb);
- return NULL;
- }
-
- ldb_set_utf8_default(ldb);
- ldb_set_create_perms(ldb, 0666);
- ldb_set_modules_dir(ldb, LDB_MODULESDIR);
-
- return ldb;
-}
+#define TEVENT_DEPRECATED 1
+#include "ldb_private.h"
-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_ildap_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)
+static int ldb_context_destructor(void *ptr)
{
- 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;
- }
+ struct ldb_context *ldb = talloc_get_type(ptr, struct ldb_context);
- for (backend = ldb_backends; backend; backend = backend->next) {
- if (strncmp(backend->ops->name, url, strlen(backend->ops->name)) == 0) {
- return backend->ops->connect_fn;
- }
+ if (ldb->transaction_active) {
+ ldb_debug(ldb, LDB_DEBUG_FATAL,
+ "A transaction is still active in ldb context [%p] on %s",
+ ldb, (const char *)ldb_get_opaque(ldb, "ldb_url"));
}
- return NULL;
+ return 0;
}
/*
- register a new ldb backend
+ this is used to catch debug messages from events
*/
-int ldb_register_backend(const char *url_prefix, ldb_connect_fn connectfn)
-{
- struct ldb_backend_ops *backend = talloc(talloc_autofree_context(), struct ldb_backend_ops);
- struct backends_list_entry *entry = talloc(talloc_autofree_context(), struct backends_list_entry);
+static void ldb_tevent_debug(void *context, enum tevent_debug_level level,
+ const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0);
- if (ldb_find_backend(url_prefix)) {
- return LDB_SUCCESS;
- }
-
- /* Maybe check for duplicity here later on? */
+static void ldb_tevent_debug(void *context, enum tevent_debug_level level,
+ const char *fmt, va_list ap)
+{
+ struct ldb_context *ldb = talloc_get_type(context, struct ldb_context);
+ enum ldb_debug_level ldb_level = LDB_DEBUG_FATAL;
+ char *s = NULL;
- backend->name = talloc_strdup(backend, url_prefix);
- backend->connect_fn = connectfn;
- entry->ops = backend;
- DLIST_ADD(ldb_backends, entry);
+ switch (level) {
+ case TEVENT_DEBUG_FATAL:
+ ldb_level = LDB_DEBUG_FATAL;
+ break;
+ case TEVENT_DEBUG_ERROR:
+ ldb_level = LDB_DEBUG_ERROR;
+ break;
+ case TEVENT_DEBUG_WARNING:
+ ldb_level = LDB_DEBUG_WARNING;
+ break;
+ case TEVENT_DEBUG_TRACE:
+ ldb_level = LDB_DEBUG_TRACE;
+ break;
+ };
- return LDB_SUCCESS;
+ vasprintf(&s, fmt, ap);
+ if (!s) return;
+ ldb_debug(ldb, ldb_level, "tevent: %s", s);
+ free(s);
}
-/*
- 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.
+/*
+ initialise a ldb context
+ The mem_ctx is required
+ The event_ctx is required
*/
-int ldb_connect_backend(struct ldb_context *ldb, const char *url, const char *options[],
- struct ldb_module **backend_module)
+struct ldb_context *ldb_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev_ctx)
{
+ struct ldb_context *ldb;
int ret;
- char *backend;
- ldb_connect_fn fn;
- if (strchr(url, ':') != NULL) {
- backend = talloc_strndup(ldb, url, strchr(url, ':')-url);
- } else {
- /* Default to tdb */
- backend = talloc_strdup(ldb, "tdb");
+ 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 = tevent_context_init(talloc_autofree_context());
+ tevent_set_debug(ev_ctx, ldb_tevent_debug, ldb);
+ tevent_loop_allow_nesting(ev_ctx);
}
- 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);
- }
- }
-
- if (fn == NULL) {
- 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);
+ ret = ldb_setup_wellknown_attributes(ldb);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(ldb);
+ return NULL;
}
- talloc_free(backend);
+ 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);
- if (fn == NULL) {
- ldb_debug(ldb, LDB_DEBUG_FATAL, "Unable to find backend for '%s'\n", url);
- return LDB_ERR_OTHER;
- }
+ /* TODO: get timeout from options if available there */
+ ldb->default_timeout = 300; /* set default to 5 minutes */
- ret = fn(ldb, url, ldb->flags, options, backend_module);
+ talloc_set_destructor((TALLOC_CTX *)ldb, ldb_context_destructor);
- if (ret != LDB_SUCCESS) {
- ldb_debug(ldb, LDB_DEBUG_ERROR, "Failed to connect to '%s'\n", url);
- return ret;
- }
- return ret;
+ return ldb;
}
/*
};
tmp_ctx = talloc_new(ldb);
- 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);
- }
+ ret = ldb_search(ldb, tmp_ctx, &res, ldb_dn_new(tmp_ctx, ldb, NULL),
+ LDB_SCOPE_BASE, attrs, "(objectClass=*)");
+ if (ret != LDB_SUCCESS) {
+ talloc_free(tmp_ctx);
+ return;
+ }
- 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 (res->count != 1) {
+ talloc_free(tmp_ctx);
+ return;
+ }
- 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, "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, "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);
+ 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(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 */
+ char *url2;
+ /* We seem to need to do this here, or else some utilities don't
+ * get ldb backends */
ldb->flags = flags;
ldb_oom(ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
- ret = ldb_set_opaque(ldb, "ldb_url", talloc_strdup(ldb, url2));
+ ret = ldb_set_opaque(ldb, "ldb_url", url2);
if (ret != LDB_SUCCESS) {
return ret;
}
}
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",
url, ldb_errstring(ldb));
return LDB_ERR_OTHER;
}
- /* TODO: get timeout from options if available there */
- ldb->default_timeout = 300; /* set default to 5 minutes */
-
/* set the default base dn */
ldb_set_default_dns(ldb);
talloc_free(ldb->err_string);
}
ldb->err_string = talloc_strdup(ldb, err_string);
+ if (ldb->flags & LDB_FLG_ENABLE_TRACING) {
+ ldb_debug(ldb, LDB_DEBUG_TRACE, "ldb_set_errstring: %s", ldb->err_string);
+ }
}
void ldb_asprintf_errstring(struct ldb_context *ldb, const char *format, ...)
}
}
-#define FIRST_OP(ldb, op) do { \
+
+
+/*
+ set an ldb error based on file:line
+*/
+int ldb_error_at(struct ldb_context *ldb, int ecode,
+ const char *reason, const char *file, int line)
+{
+ if (reason == NULL) {
+ reason = ldb_strerror(ecode);
+ }
+ ldb_asprintf_errstring(ldb, "%s at %s:%d", reason, file, line);
+ return ecode;
+}
+
+
+#define FIRST_OP_NOERR(ldb, op) do { \
module = ldb->modules; \
while (module && module->ops->op == NULL) module = module->next; \
- if (module == NULL) { \
+ if ((ldb->flags & LDB_FLG_ENABLE_TRACING) && module) { \
+ ldb_debug(ldb, LDB_DEBUG_TRACE, "ldb_trace_request: (%s)->" #op, \
+ module->ops->name); \
+ } \
+} while (0)
+
+#define FIRST_OP(ldb, op) do { \
+ FIRST_OP_NOERR(ldb, op); \
+ if (module == NULL) { \
ldb_asprintf_errstring(ldb, "unable to find module or backend to handle operation: " #op); \
return LDB_ERR_OPERATIONS_ERROR; \
} \
} while (0)
+
/*
start a transaction
*/
-static int ldb_transaction_start_internal(struct ldb_context *ldb)
+int ldb_transaction_start(struct ldb_context *ldb)
{
struct ldb_module *module;
int status;
+
+ ldb_debug(ldb, LDB_DEBUG_TRACE,
+ "start ldb transaction (nesting: %d)",
+ ldb->transaction_active);
+
+ /* explicit transaction active, count nested requests */
+ if (ldb->transaction_active) {
+ ldb->transaction_active++;
+ return LDB_SUCCESS;
+ }
+
+ /* start a new transaction */
+ ldb->transaction_active++;
+ ldb->prepare_commit_done = false;
+
FIRST_OP(ldb, start_transaction);
ldb_reset_err_string(ldb);
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);
}
}
+ if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
+ ldb_debug(module->ldb, LDB_DEBUG_TRACE, "start ldb transaction error: %s",
+ ldb_errstring(module->ldb));
+ }
return status;
}
/*
- commit a transaction
+ prepare for transaction commit (first phase of two phase commit)
*/
-static int ldb_transaction_commit_internal(struct ldb_context *ldb)
+int ldb_transaction_prepare_commit(struct ldb_context *ldb)
{
struct ldb_module *module;
int status;
- FIRST_OP(ldb, end_transaction);
- ldb_reset_err_string(ldb);
+ if (ldb->prepare_commit_done) {
+ return LDB_SUCCESS;
+ }
- status = module->ops->end_transaction(module);
+ /* commit only when all nested transactions are complete */
+ if (ldb->transaction_active > 1) {
+ return LDB_SUCCESS;
+ }
+
+ ldb->prepare_commit_done = true;
+
+ if (ldb->transaction_active < 0) {
+ ldb_debug(ldb, LDB_DEBUG_FATAL,
+ "prepare commit called but no ldb transactions are active!");
+ ldb->transaction_active = 0;
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ /* call prepare transaction if available */
+ FIRST_OP_NOERR(ldb, prepare_commit);
+ if (module == NULL) {
+ return LDB_SUCCESS;
+ }
+
+ status = module->ops->prepare_commit(module);
if (status != LDB_SUCCESS) {
+ /* if a module fails the prepare then we need
+ to call the end transaction for everyone */
+ FIRST_OP(ldb, del_transaction);
+ module->ops->del_transaction(module);
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 prepare commit: %s (%d)",
+ ldb_strerror(status),
+ status);
+ }
+ if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
+ ldb_debug(module->ldb, LDB_DEBUG_TRACE, "prepare commit transaction error: %s",
+ ldb_errstring(module->ldb));
}
}
+
return status;
}
+
/*
- cancel a transaction
+ commit a transaction
*/
-static int ldb_transaction_cancel_internal(struct ldb_context *ldb)
+int ldb_transaction_commit(struct ldb_context *ldb)
{
struct ldb_module *module;
int status;
- FIRST_OP(ldb, del_transaction);
- status = module->ops->del_transaction(module);
+ status = ldb_transaction_prepare_commit(ldb);
+ if (status != LDB_SUCCESS) {
+ return status;
+ }
+
+ ldb->transaction_active--;
+
+ ldb_debug(ldb, LDB_DEBUG_TRACE,
+ "commit ldb transaction (nesting: %d)",
+ ldb->transaction_active);
+
+ /* commit only when all nested transactions are complete */
+ if (ldb->transaction_active > 0) {
+ return LDB_SUCCESS;
+ }
+
+ if (ldb->transaction_active < 0) {
+ ldb_debug(ldb, LDB_DEBUG_FATAL,
+ "commit called but no ldb transactions are active!");
+ ldb->transaction_active = 0;
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ldb_reset_err_string(ldb);
+
+ FIRST_OP(ldb, end_transaction);
+ status = module->ops->end_transaction(module);
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 commit: %s (%d)",
+ ldb_strerror(status),
+ status);
+ }
+ if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
+ ldb_debug(module->ldb, LDB_DEBUG_TRACE, "commit ldb transaction error: %s",
+ ldb_errstring(module->ldb));
}
+ /* cancel the transaction */
+ FIRST_OP(ldb, del_transaction);
+ module->ops->del_transaction(module);
}
return status;
}
-int ldb_transaction_start(struct ldb_context *ldb)
-{
- /* disable autotransactions */
- ldb->transaction_active++;
-
- return ldb_transaction_start_internal(ldb);
-}
-
-int ldb_transaction_commit(struct ldb_context *ldb)
-{
- /* renable autotransactions (when we reach 0) */
- if (ldb->transaction_active > 0)
- ldb->transaction_active--;
-
- return ldb_transaction_commit_internal(ldb);
-}
+/*
+ cancel a transaction
+*/
int ldb_transaction_cancel(struct ldb_context *ldb)
{
- /* renable autotransactions (when we reach 0) */
- if (ldb->transaction_active > 0)
- ldb->transaction_active--;
+ struct ldb_module *module;
+ int status;
- return ldb_transaction_cancel_internal(ldb);
-}
+ ldb->transaction_active--;
-static int ldb_autotransaction_start(struct ldb_context *ldb)
-{
- /* explicit transaction active, ignore autotransaction request */
- if (ldb->transaction_active)
+ ldb_debug(ldb, LDB_DEBUG_TRACE,
+ "cancel ldb transaction (nesting: %d)",
+ ldb->transaction_active);
+
+ /* really cancel only if all nested transactions are complete */
+ if (ldb->transaction_active > 0) {
return LDB_SUCCESS;
+ }
- return ldb_transaction_start_internal(ldb);
-}
+ if (ldb->transaction_active < 0) {
+ ldb_debug(ldb, LDB_DEBUG_FATAL,
+ "cancel called but no ldb transactions are active!");
+ ldb->transaction_active = 0;
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
-static int ldb_autotransaction_commit(struct ldb_context *ldb)
-{
- /* explicit transaction active, ignore autotransaction request */
- if (ldb->transaction_active)
- return LDB_SUCCESS;
+ FIRST_OP(ldb, del_transaction);
- return ldb_transaction_commit_internal(ldb);
+ status = module->ops->del_transaction(module);
+ 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);
+ }
+ if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
+ ldb_debug(module->ldb, LDB_DEBUG_TRACE, "cancel ldb transaction error: %s",
+ ldb_errstring(module->ldb));
+ }
+ }
+ return status;
}
-static int ldb_autotransaction_cancel(struct ldb_context *ldb)
+/*
+ cancel a transaction with no error if no transaction is pending
+ used when we fork() to clear any parent transactions
+*/
+int ldb_transaction_cancel_noerr(struct ldb_context *ldb)
{
- /* explicit transaction active, ignore autotransaction request */
- if (ldb->transaction_active)
- return LDB_SUCCESS;
-
- return ldb_transaction_cancel_internal(ldb);
+ if (ldb->transaction_active > 0) {
+ return ldb_transaction_cancel(ldb);
+ }
+ return LDB_SUCCESS;
}
+
/* 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;
- ret = ldb_autotransaction_start(ldb);
+ ret = ldb_transaction_start(ldb);
if (ret != LDB_SUCCESS) {
return ret;
}
}
if (ret == LDB_SUCCESS) {
- return ldb_autotransaction_commit(ldb);
+ return ldb_transaction_commit(ldb);
}
- ldb_autotransaction_cancel(ldb);
+ ldb_transaction_cancel(ldb);
if (ldb->err_string == NULL) {
/* no error string was setup by the backend */
int ldb_wait(struct ldb_handle *handle, enum ldb_wait_type type)
{
+ struct tevent_context *ev;
+ int ret;
+
if (!handle) {
- return LDB_SUCCESS;
+ return LDB_ERR_UNAVAILABLE;
+ }
+
+ if (handle->state == LDB_ASYNC_DONE) {
+ return handle->status;
}
- return handle->module->ops->wait(handle, type);
+ ev = ldb_get_event_context(handle->ldb);
+ if (NULL == ev) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ switch (type) {
+ case LDB_WAIT_NONE:
+ ret = tevent_loop_once(ev);
+ if (ret != 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ if (handle->state == LDB_ASYNC_DONE ||
+ handle->status != LDB_SUCCESS) {
+ return handle->status;
+ }
+ break;
+
+ case LDB_WAIT_ALL:
+ while (handle->state != LDB_ASYNC_DONE) {
+ ret = tevent_loop_once(ev);
+ if (ret != 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ if (handle->status != LDB_SUCCESS) {
+ return handle->status;
+ }
+ }
+ return handle->status;
+ }
+
+ return LDB_SUCCESS;
}
/* 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;
-
if (newreq == NULL) return LDB_ERR_OPERATIONS_ERROR;
- now = time(NULL);
-
- if (oldreq == NULL)
+ if (oldreq == NULL) {
return ldb_set_timeout(ldb, newreq, 0);
-
- if ((now - oldreq->starttime) > oldreq->timeout) {
- return LDB_ERR_TIME_LIMIT_EXCEEDED;
}
+
newreq->starttime = oldreq->starttime;
- newreq->timeout = oldreq->timeout - (now - oldreq->starttime);
+ newreq->timeout = oldreq->timeout;
return LDB_SUCCESS;
}
-/*
+/*
set the permissions for new files to be passed to open() in
backends that use local files
*/
ldb->create_perms = perms;
}
+unsigned int ldb_get_create_perms(struct ldb_context *ldb)
+{
+ return ldb->create_perms;
+}
+
+void ldb_set_event_context(struct ldb_context *ldb, struct tevent_context *ev)
+{
+ ldb->ev_ctx = ev;
+}
+
+struct tevent_context * ldb_get_event_context(struct ldb_context *ldb)
+{
+ return ldb->ev_ctx;
+}
+
+void ldb_request_set_state(struct ldb_request *req, int state)
+{
+ req->handle->state = state;
+}
+
+int ldb_request_get_status(struct ldb_request *req)
+{
+ return req->handle->status;
+}
+
+
+/*
+ trace a ldb request
+*/
+static void ldb_trace_request(struct ldb_context *ldb, struct ldb_request *req)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(req);
+ unsigned int i;
+
+ switch (req->operation) {
+ case LDB_SEARCH:
+ ldb_debug_add(ldb, "ldb_trace_request: SEARCH\n");
+ ldb_debug_add(ldb, " dn: %s\n",
+ ldb_dn_is_null(req->op.search.base)?"<rootDSE>":
+ ldb_dn_get_linearized(req->op.search.base));
+ ldb_debug_add(ldb, " scope: %s\n",
+ req->op.search.scope==LDB_SCOPE_BASE?"base":
+ req->op.search.scope==LDB_SCOPE_ONELEVEL?"one":
+ req->op.search.scope==LDB_SCOPE_SUBTREE?"sub":"UNKNOWN");
+ ldb_debug_add(ldb, " expr: %s\n",
+ ldb_filter_from_tree(tmp_ctx, req->op.search.tree));
+ if (req->op.search.attrs == NULL) {
+ ldb_debug_add(ldb, " attr: <ALL>\n");
+ } else {
+ for (i=0; req->op.search.attrs[i]; i++) {
+ ldb_debug_add(ldb, " attr: %s\n", req->op.search.attrs[i]);
+ }
+ }
+ break;
+ case LDB_DELETE:
+ ldb_debug_add(ldb, "ldb_trace_request: DELETE\n");
+ ldb_debug_add(ldb, " dn: %s\n",
+ ldb_dn_get_linearized(req->op.del.dn));
+ break;
+ case LDB_RENAME:
+ ldb_debug_add(ldb, "ldb_trace_request: RENAME\n");
+ ldb_debug_add(ldb, " olddn: %s\n",
+ ldb_dn_get_linearized(req->op.rename.olddn));
+ ldb_debug_add(ldb, " newdn: %s\n",
+ ldb_dn_get_linearized(req->op.rename.newdn));
+ break;
+ case LDB_EXTENDED:
+ ldb_debug_add(ldb, "ldb_trace_request: EXTENDED\n");
+ ldb_debug_add(ldb, " oid: %s\n", req->op.extended.oid);
+ ldb_debug_add(ldb, " data: %s\n", req->op.extended.data?"yes":"no");
+ break;
+ case LDB_ADD:
+ ldb_debug_add(ldb, "ldb_trace_request: ADD\n");
+ ldb_debug_add(req->handle->ldb, "%s\n",
+ ldb_ldif_message_string(req->handle->ldb, tmp_ctx,
+ LDB_CHANGETYPE_ADD,
+ req->op.add.message));
+ break;
+ case LDB_MODIFY:
+ ldb_debug_add(ldb, "ldb_trace_request: MODIFY\n");
+ ldb_debug_add(req->handle->ldb, "%s\n",
+ ldb_ldif_message_string(req->handle->ldb, tmp_ctx,
+ LDB_CHANGETYPE_ADD,
+ req->op.mod.message));
+ break;
+ case LDB_REQ_REGISTER_CONTROL:
+ ldb_debug_add(ldb, "ldb_trace_request: REGISTER_CONTROL\n");
+ ldb_debug_add(req->handle->ldb, "%s\n",
+ req->op.reg_control.oid);
+ break;
+ case LDB_REQ_REGISTER_PARTITION:
+ ldb_debug_add(ldb, "ldb_trace_request: REGISTER_PARTITION\n");
+ ldb_debug_add(req->handle->ldb, "%s\n",
+ ldb_dn_get_linearized(req->op.reg_partition.dn));
+ break;
+ default:
+ ldb_debug_add(ldb, "ldb_trace_request: UNKNOWN(%u)\n",
+ req->operation);
+ break;
+ }
+
+ if (req->controls == NULL) {
+ ldb_debug_add(ldb, " control: <NONE>\n");
+ } else {
+ for (i=0; req->controls && req->controls[i]; i++) {
+ ldb_debug_add(ldb, " control: %s crit:%u data:%s\n",
+ req->controls[i]->oid,
+ req->controls[i]->critical,
+ req->controls[i]->data?"yes":"no");
+ }
+ }
+
+ ldb_debug_end(ldb, LDB_DEBUG_TRACE);
+
+ talloc_free(tmp_ctx);
+}
+
+
/*
start an ldb request
NOTE: the request must be a talloc context.
struct ldb_module *module;
int ret;
+ if (req->callback == NULL) {
+ ldb_set_errstring(ldb, "Requests MUST define callbacks");
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+
ldb_reset_err_string(ldb);
+ if (ldb->flags & LDB_FLG_ENABLE_TRACING) {
+ ldb_trace_request(ldb, req);
+ }
+
/* call the first module in the chain */
switch (req->operation) {
case LDB_SEARCH:
ret = module->ops->search(module, req);
break;
case LDB_ADD:
+ /* we have to canonicalise here, as so many places
+ * in modules and backends assume we don't have two
+ * elements with the same name */
+ ret = ldb_msg_canonicalize_ex(ldb, req->op.add.message,
+ (TALLOC_CTX*)req,
+ discard_const(&req->op.add.message));
+ if (ret != LDB_SUCCESS) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
FIRST_OP(ldb, add);
ret = module->ops->add(module, req);
break;
ret = module->ops->del(module, req);
break;
case LDB_RENAME:
+ if (!ldb_dn_validate(req->op.rename.olddn)) {
+ ldb_asprintf_errstring(ldb, "ldb_rename: invalid olddn '%s'",
+ ldb_dn_get_linearized(req->op.rename.olddn));
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+ if (!ldb_dn_validate(req->op.rename.newdn)) {
+ ldb_asprintf_errstring(ldb, "ldb_rename: invalid newdn '%s'",
+ ldb_dn_get_linearized(req->op.rename.newdn));
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
FIRST_OP(ldb, rename);
ret = module->ops->rename(module, req);
break;
FIRST_OP(ldb, extended);
ret = module->ops->extended(module, req);
break;
- case LDB_SEQUENCE_NUMBER:
- FIRST_OP(ldb, sequence_number);
- ret = module->ops->sequence_number(module, req);
- break;
default:
FIRST_OP(ldb, request);
ret = module->ops->request(module, req);
return ret;
}
+int ldb_request_done(struct ldb_request *req, int status)
+{
+ req->handle->state = LDB_ASYNC_DONE;
+ req->handle->status = status;
+ return status;
+}
+
/*
search the database given a LDAP-like search expression
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_request *req,
+ 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;
- }
+ unsigned int n;
- res = talloc_get_type(context, struct ldb_result);
+ res = talloc_get_type(req->context, struct ldb_result);
- if (!res || !ares) {
- ldb_set_errstring(ldb, "NULL res or ares in callback");
- goto error;
+ if (!ares) {
+ return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_request_done(req, ares->error);
}
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;
+ return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
}
res->msgs[res->count + 1] = NULL;
res->msgs[res->count] = talloc_move(res->msgs, &ares->message);
res->count++;
break;
+
case LDB_REPLY_REFERRAL:
if (res->refs) {
for (n = 0; res->refs[n]; n++) /*noop*/ ;
res->refs = talloc_realloc(res, res->refs, char *, n + 2);
if (! res->refs) {
- goto error;
+ return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
}
res->refs[n] = talloc_move(res->refs, &ares->referral);
res->refs[n + 1] = NULL;
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;
+
+ /* this is the last message, and means the request is done */
+ /* we have to signal and eventual ldb_wait() waiting that the
+ * async request operation was completed */
+ talloc_free(ares);
+ return ldb_request_done(req, LDB_SUCCESS);
}
+
talloc_free(ares);
+
return LDB_SUCCESS;
+}
+
+int ldb_modify_default_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+ struct ldb_result *res;
+ unsigned int n;
+ int ret;
+
+ res = talloc_get_type(req->context, struct ldb_result);
+
+ if (!ares) {
+ return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ if (ares->error != LDB_SUCCESS) {
+ ret = ares->error;
+ talloc_free(ares);
+ return ldb_request_done(req, ret);
+ }
+
+ switch (ares->type) {
+ case LDB_REPLY_REFERRAL:
+ if (res->refs) {
+ for (n = 0; res->refs[n]; n++) /*noop*/ ;
+ } else {
+ n = 0;
+ }
+
+ res->refs = talloc_realloc(res, res->refs, char *, n + 2);
+ if (! res->refs) {
+ return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ res->refs[n] = talloc_move(res->refs, &ares->referral);
+ res->refs[n + 1] = NULL;
+ break;
+
+ case LDB_REPLY_DONE:
+ talloc_free(ares);
+ return ldb_request_done(req, LDB_SUCCESS);
+ default:
+ talloc_free(ares);
+ ldb_set_errstring(req->handle->ldb, "Invalid reply type!");
+ return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+ }
-error:
talloc_free(ares);
- return LDB_ERR_OPERATIONS_ERROR;
+ return ldb_request_done(req, LDB_SUCCESS);
}
-int ldb_build_search_req(struct ldb_request **ret_req,
+int ldb_op_default_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+ int ret;
+
+ if (!ares) {
+ return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ if (ares->error != LDB_SUCCESS) {
+ ret = ares->error;
+ talloc_free(ares);
+ return ldb_request_done(req, ret);
+ }
+
+ if (ares->type != LDB_REPLY_DONE) {
+ talloc_free(ares);
+ ldb_set_errstring(req->handle->ldb, "Invalid reply type!");
+ return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ talloc_free(ares);
+ return ldb_request_done(req, LDB_SUCCESS);
+}
+
+int ldb_build_search_req_ex(struct ldb_request **ret_req,
struct ldb_context *ldb,
void *mem_ctx,
struct ldb_dn *base,
enum ldb_scope scope,
- const char *expression,
+ struct ldb_parse_tree *tree,
const char * const *attrs,
struct ldb_control **controls,
void *context,
- ldb_request_callback_t callback)
+ ldb_request_callback_t callback,
+ struct ldb_request *parent)
{
struct ldb_request *req;
req = talloc(mem_ctx, struct ldb_request);
if (req == NULL) {
- ldb_set_errstring(ldb, "Out of Memory");
+ ldb_oom(ldb);
return LDB_ERR_OPERATIONS_ERROR;
}
}
req->op.search.scope = scope;
- req->op.search.tree = ldb_parse_tree(req, expression);
+ req->op.search.tree = tree;
if (req->op.search.tree == NULL) {
- ldb_set_errstring(ldb, "Unable to parse search expression");
+ ldb_set_errstring(ldb, "'tree' can't be NULL");
talloc_free(req);
return LDB_ERR_OPERATIONS_ERROR;
}
req->context = context;
req->callback = callback;
+ ldb_set_timeout_from_prev_req(ldb, parent, req);
+
+ req->handle = ldb_handle_new(req, ldb);
+ if (req->handle == NULL) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (parent) {
+ req->handle->nesting++;
+ }
+
*ret_req = req;
return LDB_SUCCESS;
}
+int ldb_build_search_req(struct ldb_request **ret_req,
+ struct ldb_context *ldb,
+ void *mem_ctx,
+ struct ldb_dn *base,
+ enum ldb_scope scope,
+ const char *expression,
+ const char * const *attrs,
+ struct ldb_control **controls,
+ void *context,
+ ldb_request_callback_t callback,
+ struct ldb_request *parent)
+{
+ struct ldb_parse_tree *tree;
+ int ret;
+
+ tree = ldb_parse_tree(mem_ctx, expression);
+ if (tree == NULL) {
+ ldb_set_errstring(ldb, "Unable to parse search expression");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = ldb_build_search_req_ex(ret_req, ldb, mem_ctx, base,
+ scope, tree, attrs, controls,
+ context, callback, parent);
+ if (ret == LDB_SUCCESS) {
+ talloc_steal(*ret_req, tree);
+ }
+ return ret;
+}
+
int ldb_build_add_req(struct ldb_request **ret_req,
struct ldb_context *ldb,
void *mem_ctx,
const struct ldb_message *message,
struct ldb_control **controls,
void *context,
- ldb_request_callback_t callback)
+ ldb_request_callback_t callback,
+ struct ldb_request *parent)
{
struct ldb_request *req;
req->context = context;
req->callback = callback;
+ ldb_set_timeout_from_prev_req(ldb, parent, req);
+
+ req->handle = ldb_handle_new(req, ldb);
+ if (req->handle == NULL) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (parent) {
+ req->handle->nesting++;
+ }
+
*ret_req = req;
return LDB_SUCCESS;
const struct ldb_message *message,
struct ldb_control **controls,
void *context,
- ldb_request_callback_t callback)
+ ldb_request_callback_t callback,
+ struct ldb_request *parent)
{
struct ldb_request *req;
req->context = context;
req->callback = callback;
+ ldb_set_timeout_from_prev_req(ldb, parent, req);
+
+ req->handle = ldb_handle_new(req, ldb);
+ if (req->handle == NULL) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (parent) {
+ req->handle->nesting++;
+ }
+
*ret_req = req;
return LDB_SUCCESS;
struct ldb_dn *dn,
struct ldb_control **controls,
void *context,
- ldb_request_callback_t callback)
+ ldb_request_callback_t callback,
+ struct ldb_request *parent)
{
struct ldb_request *req;
req->context = context;
req->callback = callback;
+ ldb_set_timeout_from_prev_req(ldb, parent, req);
+
+ req->handle = ldb_handle_new(req, ldb);
+ if (req->handle == NULL) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (parent) {
+ req->handle->nesting++;
+ }
+
*ret_req = req;
return LDB_SUCCESS;
struct ldb_dn *newdn,
struct ldb_control **controls,
void *context,
- ldb_request_callback_t callback)
+ ldb_request_callback_t callback,
+ struct ldb_request *parent)
{
struct ldb_request *req;
req->context = context;
req->callback = callback;
+ ldb_set_timeout_from_prev_req(ldb, parent, req);
+
+ req->handle = ldb_handle_new(req, ldb);
+ if (req->handle == NULL) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (parent) {
+ req->handle->nesting++;
+ }
+
*ret_req = req;
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_request *req,
+ struct ldb_reply *ares)
{
struct ldb_result *res;
-
- if (!context) {
- ldb_set_errstring(ldb, "NULL Context in callback");
- return LDB_ERR_OPERATIONS_ERROR;
- }
- res = talloc_get_type(context, struct ldb_result);
- if (!res || !ares) {
- ldb_set_errstring(ldb, "NULL res or ares in callback");
- goto error;
+ res = talloc_get_type(req->context, struct ldb_result);
+
+ if (!ares) {
+ return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+ }
+ if (ares->error != LDB_SUCCESS) {
+ return ldb_request_done(req, ares->error);
}
- switch (ares->type) {
- case LDB_REPLY_ENTRY:
- case LDB_REPLY_REFERRAL:
- case LDB_REPLY_DONE:
- ldb_set_errstring(ldb, "invalid ares type in callback");
- goto error;
- case LDB_REPLY_EXTENDED:
+ if (ares->type == LDB_REPLY_DONE) {
+
/* 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;
+
+ talloc_free(ares);
+ return ldb_request_done(req, LDB_SUCCESS);
}
- talloc_free(ares);
- return LDB_SUCCESS;
-error:
talloc_free(ares);
- return LDB_ERR_OPERATIONS_ERROR;
+ ldb_set_errstring(req->handle->ldb, "Invalid reply type!");
+ return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
}
int ldb_build_extended_req(struct ldb_request **ret_req,
void *data,
struct ldb_control **controls,
void *context,
- ldb_request_callback_t callback)
+ ldb_request_callback_t callback,
+ struct ldb_request *parent)
{
struct ldb_request *req;
req->context = context;
req->callback = callback;
+ ldb_set_timeout_from_prev_req(ldb, parent, req);
+
+ req->handle = ldb_handle_new(req, ldb);
+ if (req->handle == NULL) {
+ ldb_oom(ldb);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ if (parent) {
+ req->handle->nesting++;
+ }
+
*ret_req = req;
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)
ret = ldb_build_extended_req(&req, ldb, ldb,
oid, data, NULL,
- res, ldb_extended_default_callback);
+ res, ldb_extended_default_callback,
+ NULL);
if (ret != LDB_SUCCESS) goto done;
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,
- struct ldb_dn *base,
- enum ldb_scope scope,
- const char *expression,
- const char * const *attrs,
- struct ldb_result **_res)
+int ldb_search(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_request *req;
- int ret;
struct ldb_result *res;
+ char *expression;
+ va_list ap;
+ int ret;
- *_res = NULL;
+ expression = NULL;
+ *result = NULL;
+ req = NULL;
- res = talloc_zero(ldb, struct ldb_result);
+ res = talloc_zero(mem_ctx, struct ldb_result);
if (!res) {
return LDB_ERR_OPERATIONS_ERROR;
}
- ret = ldb_build_search_req(&req, ldb, ldb,
+ if (exp_fmt) {
+ va_start(ap, exp_fmt);
+ expression = talloc_vasprintf(mem_ctx, exp_fmt, ap);
+ va_end(ap);
+
+ if (!expression) {
+ talloc_free(res);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+
+ ret = ldb_build_search_req(&req, ldb, mem_ctx,
base?base:ldb_get_default_basedn(ldb),
scope,
expression,
attrs,
NULL,
res,
- ldb_search_default_callback);
+ ldb_search_default_callback,
+ NULL);
if (ret != LDB_SUCCESS) goto done;
- 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);
}
- talloc_free(req);
-
done:
if (ret != LDB_SUCCESS) {
talloc_free(res);
- }
-
- *_res = res;
- return ret;
-}
-
-/*
- a useful search function where you can easily define the expression and that
- 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,
- const char *exp_fmt, ...)
-{
- struct ldb_result *res;
- char *expression;
- va_list ap;
- int ret;
-
- res = NULL;
- *result = NULL;
-
- va_start(ap, exp_fmt);
- expression = talloc_vasprintf(mem_ctx, exp_fmt, ap);
- va_end(ap);
-
- if ( ! expression) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- ret = ldb_search(ldb, base, scope, expression, attrs, &res);
-
- if (ret == LDB_SUCCESS) {
- talloc_steal(mem_ctx, res);
- *result = res;
+ res = NULL;
}
talloc_free(expression);
+ talloc_free(req);
+ *result = res;
return ret;
}
/*
- 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;
message,
NULL,
NULL,
+ ldb_op_default_callback,
NULL);
if (ret != LDB_SUCCESS) return ret;
- ldb_set_timeout(ldb, req, 0); /* use default timeout */
-
/* do request and autostart a transaction */
ret = ldb_autotransaction_request(ldb, 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;
message,
NULL,
NULL,
+ ldb_op_default_callback,
NULL);
if (ret != LDB_SUCCESS) return ret;
- ldb_set_timeout(ldb, req, 0); /* use default timeout */
-
/* do request and autostart a transaction */
ret = ldb_autotransaction_request(ldb, req);
dn,
NULL,
NULL,
+ ldb_op_default_callback,
NULL);
if (ret != LDB_SUCCESS) return ret;
- ldb_set_timeout(ldb, req, 0); /* use default timeout */
-
/* do request and autostart a transaction */
ret = ldb_autotransaction_request(ldb, 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;
newdn,
NULL,
NULL,
+ ldb_op_default_callback,
NULL);
if (ret != LDB_SUCCESS) return ret;
- ldb_set_timeout(ldb, req, 0); /* use default timeout */
-
/* do request and autostart a transaction */
ret = ldb_autotransaction_request(ldb, req);
/*
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;
+ struct ldb_seqnum_request *seq;
+ struct ldb_seqnum_result *seqr;
+ struct ldb_result *res;
+ TALLOC_CTX *tmp_ctx;
int ret;
- req = talloc(ldb, struct ldb_request);
- if (req == NULL) {
+ *seq_num = 0;
+
+ tmp_ctx = talloc_zero(ldb, struct ldb_request);
+ if (tmp_ctx == NULL) {
ldb_set_errstring(ldb, "Out of Memory");
return LDB_ERR_OPERATIONS_ERROR;
}
+ seq = talloc_zero(tmp_ctx, struct ldb_seqnum_request);
+ if (seq == NULL) {
+ ldb_set_errstring(ldb, "Out of Memory");
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto done;
+ }
+ seq->type = type;
- req->operation = LDB_SEQUENCE_NUMBER;
- req->controls = NULL;
- req->context = NULL;
- req->callback = NULL;
- ldb_set_timeout(ldb, req, 0); /* use default timeout */
+ ret = ldb_extended(ldb, LDB_EXTENDED_SEQUENCE_NUMBER, seq, &res);
+ if (ret != LDB_SUCCESS) {
+ goto done;
+ }
+ talloc_steal(tmp_ctx, res);
- 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;
+ if (strcmp(LDB_EXTENDED_SEQUENCE_NUMBER, res->extended->oid) != 0) {
+ ldb_set_errstring(ldb, "Invalid OID in reply");
+ ret = LDB_ERR_OPERATIONS_ERROR;
+ goto done;
}
+ seqr = talloc_get_type(res->extended->data,
+ struct ldb_seqnum_result);
+ *seq_num = seqr->seq_num;
- talloc_free(req);
+done:
+ talloc_free(tmp_ctx);
return ret;
}
-
-
/*
- return extended error information
+ return extended error information
*/
const char *ldb_errstring(struct ldb_context *ldb)
{
}
return NULL;
}
+
+int ldb_global_init(void)
+{
+ /* Provided for compatibility with some older versions of ldb */
+ return 0;
+}
+
+/* return the ldb flags */
+unsigned int ldb_get_flags(struct ldb_context *ldb)
+{
+ return ldb->flags;
+}
+
+/* set the ldb flags */
+void ldb_set_flags(struct ldb_context *ldb, unsigned flags)
+{
+ ldb->flags = flags;
+}