* Author: Andrew Tridgell
*/
-#include "ldb_includes.h"
+#define TEVENT_DEPRECATED 1
+#include "ldb_private.h"
+
+static int ldb_context_destructor(void *ptr)
+{
+ struct ldb_context *ldb = talloc_get_type(ptr, struct ldb_context);
+
+ 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 0;
+}
+
+/*
+ this is used to catch debug messages from events
+*/
+static void ldb_tevent_debug(void *context, enum tevent_debug_level level,
+ const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0);
+
+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;
+
+ 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;
+ };
+
+ vasprintf(&s, fmt, ap);
+ if (!s) return;
+ ldb_debug(ldb, ldb_level, "tevent: %s", s);
+ free(s);
+}
/*
initialise a ldb context
The mem_ctx is required
The event_ctx is required
*/
-struct ldb_context *ldb_init(TALLOC_CTX *mem_ctx, struct event_context *ev_ctx)
+struct ldb_context *ldb_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev_ctx)
{
struct ldb_context *ldb;
int ret;
/* 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());
+ ev_ctx = tevent_context_init(talloc_autofree_context());
+ tevent_set_debug(ev_ctx, ldb_tevent_debug, ldb);
+ tevent_loop_allow_nesting(ev_ctx);
}
ret = ldb_setup_wellknown_attributes(ldb);
- if (ret != 0) {
+ if (ret != LDB_SUCCESS) {
talloc_free(ldb);
return NULL;
}
/* TODO: get timeout from options if available there */
ldb->default_timeout = 300; /* set default to 5 minutes */
+ talloc_set_destructor((TALLOC_CTX *)ldb, ldb_context_destructor);
+
return ldb;
}
unsigned int flags, const char *options[])
{
int ret;
- const char *url2;
+ char *url2;
/* We seem to need to do this here, or else some utilities don't
* get ldb backends */
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",
+ "Unable to load modules for %s: %s",
url, ldb_errstring(ldb));
return LDB_ERR_OTHER;
}
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);
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 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 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)
{
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 event_context *ev;
+ struct tevent_context *ev;
+ int ret;
if (!handle) {
return LDB_ERR_UNAVAILABLE;
switch (type) {
case LDB_WAIT_NONE:
- event_loop_once(ev);
+ 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;
case LDB_WAIT_ALL:
while (handle->state != LDB_ASYNC_DONE) {
- event_loop_once(ev);
+ ret = tevent_loop_once(ev);
+ if (ret != 0) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
if (handle->status != LDB_SUCCESS) {
return handle->status;
}
ldb->create_perms = perms;
}
-void ldb_set_event_context(struct ldb_context *ldb, struct event_context *ev)
+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 event_context * ldb_get_event_context(struct ldb_context *ldb)
+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.
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;
struct ldb_reply *ares)
{
struct ldb_result *res;
- int n;
+ unsigned int n;
res = talloc_get_type(req->context, struct ldb_result);
/* 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);
+ }
+
+ talloc_free(ares);
+ return ldb_request_done(req, LDB_SUCCESS);
+}
+
int ldb_op_default_callback(struct ldb_request *req, struct ldb_reply *ares)
{
int ret;
return LDB_ERR_OPERATIONS_ERROR;
}
+ if (parent) {
+ req->handle->nesting++;
+ }
+
*ret_req = req;
return LDB_SUCCESS;
}
return LDB_ERR_OPERATIONS_ERROR;
}
+ if (parent) {
+ req->handle->nesting++;
+ }
+
*ret_req = req;
return LDB_SUCCESS;
return LDB_ERR_OPERATIONS_ERROR;
}
+ if (parent) {
+ req->handle->nesting++;
+ }
+
*ret_req = req;
return LDB_SUCCESS;
return LDB_ERR_OPERATIONS_ERROR;
}
+ if (parent) {
+ req->handle->nesting++;
+ }
+
*ret_req = req;
return LDB_SUCCESS;
return LDB_ERR_OPERATIONS_ERROR;
}
+ if (parent) {
+ req->handle->nesting++;
+ }
+
*ret_req = req;
return LDB_SUCCESS;
return LDB_ERR_OPERATIONS_ERROR;
}
+ if (parent) {
+ req->handle->nesting++;
+ }
+
*ret_req = req;
return LDB_SUCCESS;
}
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;
+}