* 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);
/* 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;
}
};
tmp_ctx = talloc_new(ldb);
- ret = ldb_search(ldb, ldb_dn_new(tmp_ctx, ldb, NULL), LDB_SCOPE_BASE,
- "(objectClass=*)", attrs, &res);
+ 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 (res->count != 1) {
- talloc_free(res);
+ talloc_free(tmp_ctx);
return;
}
ldb_set_opaque(ldb, "defaultNamingContext", tmp_dn);
}
- talloc_free(res);
talloc_free(tmp_ctx);
}
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;
}
- /* 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 { \
+#define FIRST_OP_NOERR(ldb, op) do { \
module = ldb->modules; \
while (module && module->ops->op == NULL) module = module->next; \
- if (module == NULL) { \
+} 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);
}
/*
- 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, end_transaction);
+ module->ops->end_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);
}
}
+
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);
}
+ /* 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--;
-
- return ldb_transaction_cancel_internal(ldb);
-}
+ struct ldb_module *module;
+ int status;
-static int ldb_autotransaction_start(struct ldb_context *ldb)
-{
- /* explicit transaction active, ignore autotransaction request */
- if (ldb->transaction_active)
- return LDB_SUCCESS;
+ ldb->transaction_active--;
- return ldb_transaction_start_internal(ldb);
-}
+ ldb_debug(ldb, LDB_DEBUG_TRACE,
+ "cancel ldb transaction (nesting: %d)",
+ ldb->transaction_active);
-static int ldb_autotransaction_commit(struct ldb_context *ldb)
-{
- /* explicit transaction active, ignore autotransaction request */
- if (ldb->transaction_active)
+ /* really cancel only if all nested transactions are complete */
+ if (ldb->transaction_active > 0) {
return LDB_SUCCESS;
+ }
- return ldb_transaction_commit_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_cancel(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_cancel_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);
+ }
+ }
+ return status;
}
/* autostarts a transacion if none active */
{
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;
}
- 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);
+ if (handle->state == LDB_ASYNC_DONE) {
+ return handle->status;
}
- return ret;
+
+ 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)
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;
}
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);
+ 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:
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,
+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;
- }
-
- 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);
+ 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! */
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_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);
+ }
-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_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,
+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(req->context, struct ldb_result);
- res = talloc_get_type(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:
- case LDB_REPLY_REFERRAL:
- case LDB_REPLY_DONE:
- 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! */
+ 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;
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 */
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,
const struct ldb_message *message)
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);
return ret;
}
+ if (message->num_elements == 0) {
+ /* this needs also to be returned when the specified object
+ doesn't exist. Therefore this test is located here. */
+ ldb_asprintf_errstring(ldb, "LDB message has to have elements/attributes (%s)!",
+ ldb_dn_get_linearized(message->dn));
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+
ret = ldb_build_mod_req(&req, ldb, ldb,
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);
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)
+ 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 */
-
- req->op.seq_num.type = type;
- /* do request and autostart a transaction */
- ret = ldb_request(ldb, req);
+ ret = ldb_extended(ldb, LDB_EXTENDED_SEQUENCE_NUMBER, seq, &res);
+ if (ret != LDB_SUCCESS) {
+ goto done;
+ }
+ talloc_steal(tmp_ctx, res);
- 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 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;
+}