diff options
Diffstat (limited to 'source4/lib/ldb/common')
-rw-r--r-- | source4/lib/ldb/common/ldb.c | 304 | ||||
-rw-r--r-- | source4/lib/ldb/common/ldb_modules.c | 141 |
2 files changed, 349 insertions, 96 deletions
diff --git a/source4/lib/ldb/common/ldb.c b/source4/lib/ldb/common/ldb.c index 3b73947b76..75c8109042 100644 --- a/source4/lib/ldb/common/ldb.c +++ b/source4/lib/ldb/common/ldb.c @@ -193,9 +193,6 @@ int ldb_connect(struct ldb_context *ldb, const char *url, 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); @@ -396,24 +393,44 @@ static int ldb_autotransaction_request(struct ldb_context *ldb, int ldb_wait(struct ldb_handle *handle, enum ldb_wait_type type) { - int ret; + struct event_context *ev; + 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: + event_loop_once(ev); + if (handle->state == LDB_ASYNC_DONE || + handle->status != LDB_SUCCESS) { + return handle->status; + } + break; + + case LDB_WAIT_ALL: + while (handle->state != LDB_ASYNC_DONE) { + event_loop_once(ev); + 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) @@ -435,20 +452,14 @@ 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; } @@ -483,6 +494,11 @@ int ldb_request(struct ldb_context *ldb, struct ldb_request *req) 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); /* call the first module in the chain */ @@ -524,6 +540,13 @@ int ldb_request(struct ldb_context *ldb, struct ldb_request *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 @@ -532,32 +555,27 @@ int ldb_request(struct ldb_context *ldb, struct ldb_request *req) 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(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: 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; @@ -565,6 +583,7 @@ int ldb_search_default_callback(struct ldb_context *ldb, 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*/ ; @@ -574,37 +593,63 @@ int ldb_search_default_callback(struct ldb_context *ldb, 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 */ + 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; @@ -612,7 +657,7 @@ int ldb_build_search_req(struct ldb_request **ret_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; } @@ -624,9 +669,9 @@ int ldb_build_search_req(struct ldb_request **ret_req, } 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; } @@ -636,17 +681,56 @@ int ldb_build_search_req(struct ldb_request **ret_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; + } + *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; @@ -664,6 +748,14 @@ int ldb_build_add_req(struct ldb_request **ret_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; + } + *ret_req = req; return LDB_SUCCESS; @@ -675,7 +767,8 @@ int ldb_build_mod_req(struct ldb_request **ret_req, 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; @@ -693,6 +786,14 @@ int ldb_build_mod_req(struct ldb_request **ret_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; + } + *ret_req = req; return LDB_SUCCESS; @@ -704,7 +805,8 @@ int ldb_build_del_req(struct ldb_request **ret_req, 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; @@ -722,6 +824,14 @@ int ldb_build_del_req(struct ldb_request **ret_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; + } + *ret_req = req; return LDB_SUCCESS; @@ -734,7 +844,8 @@ int ldb_build_rename_req(struct ldb_request **ret_req, 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; @@ -753,47 +864,46 @@ int ldb_build_rename_req(struct ldb_request **ret_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; + } + *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, @@ -803,7 +913,8 @@ 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; @@ -822,6 +933,14 @@ int ldb_build_extended_req(struct ldb_request **ret_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; + } + *ret_req = req; return LDB_SUCCESS; @@ -845,7 +964,8 @@ int ldb_extended(struct ldb_context *ldb, 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 */ @@ -909,12 +1029,11 @@ int ldb_search(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, 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) { @@ -935,8 +1054,8 @@ done: } /* - 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) @@ -953,12 +1072,11 @@ int ldb_add(struct ldb_context *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); @@ -984,12 +1102,11 @@ int ldb_modify(struct ldb_context *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); @@ -1010,12 +1127,11 @@ int ldb_delete(struct ldb_context *ldb, struct ldb_dn *dn) 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); @@ -1037,12 +1153,11 @@ int ldb_rename(struct ldb_context *ldb, 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); @@ -1055,13 +1170,12 @@ int ldb_rename(struct ldb_context *ldb, 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; int ret; - req = talloc(ldb, struct ldb_request); + req = talloc_zero(ldb, struct ldb_request); if (req == NULL) { ldb_set_errstring(ldb, "Out of Memory"); return LDB_ERR_OPERATIONS_ERROR; @@ -1070,7 +1184,7 @@ int ldb_sequence_number(struct ldb_context *ldb, req->operation = LDB_SEQUENCE_NUMBER; req->controls = NULL; req->context = NULL; - req->callback = NULL; + req->callback = ldb_op_default_callback; ldb_set_timeout(ldb, req, 0); /* use default timeout */ req->op.seq_num.type = type; diff --git a/source4/lib/ldb/common/ldb_modules.c b/source4/lib/ldb/common/ldb_modules.c index c0cd616a76..5cc8de29b4 100644 --- a/source4/lib/ldb/common/ldb_modules.c +++ b/source4/lib/ldb/common/ldb_modules.c @@ -1,7 +1,7 @@ /* ldb database library - Copyright (C) Simo Sorce 2004 + Copyright (C) Simo Sorce 2004-2008 ** NOTE! The following LGPL license applies to the ldb ** library. This does NOT imply that all of Samba is released @@ -486,6 +486,12 @@ int ldb_load_modules(struct ldb_context *ldb, const char *options[]) int ldb_next_request(struct ldb_module *module, struct ldb_request *request) { int ret; + + if (request->callback == NULL) { + ldb_set_errstring(module->ldb, "Requests MUST define callbacks"); + return LDB_ERR_UNWILLING_TO_PERFORM; + } + switch (request->operation) { case LDB_SEARCH: FIND_OP(module, search); @@ -555,6 +561,139 @@ int ldb_next_del_trans(struct ldb_module *module) return module->ops->del_transaction(module); } +struct ldb_handle *ldb_handle_new(TALLOC_CTX *mem_ctx, struct ldb_context *ldb) +{ + struct ldb_handle *h; + + h = talloc_zero(mem_ctx, struct ldb_handle); + if (h == NULL) { + ldb_set_errstring(ldb, "Out of Memory"); + return NULL; + } + + h->status = LDB_SUCCESS; + h->state = LDB_ASYNC_INIT; + h->ldb = ldb; + + return h; +} + +/* calls the request callback to send an entry + * + * params: + * req: the original request passed to your module + * msg: reply message (must be a talloc pointer, and it will be stolen + * on the ldb_reply that is sent to the callback) + */ + +int ldb_module_send_entry(struct ldb_request *req, + struct ldb_message *msg) +{ + struct ldb_reply *ares; + + ares = talloc_zero(req, struct ldb_reply); + if (!ares) { + ldb_oom(req->handle->ldb); + req->callback(req, NULL); + return LDB_ERR_OPERATIONS_ERROR; + } + ares->type = LDB_REPLY_ENTRY; + ares->message = talloc_steal(ares, msg); + ares->error = LDB_SUCCESS; + + return req->callback(req, ares); +} + +/* calls the request callback to send an referrals + * + * params: + * req: the original request passed to your module + * ref: referral string (must be a talloc pointeri, steal) + */ + +int ldb_module_send_referral(struct ldb_request *req, + char *ref) +{ + struct ldb_reply *ares; + + ares = talloc_zero(req, struct ldb_reply); + if (!ares) { + ldb_oom(req->handle->ldb); + req->callback(req, NULL); + return LDB_ERR_OPERATIONS_ERROR; + } + ares->type = LDB_REPLY_REFERRAL; + ares->referral = talloc_steal(ares, ref); + ares->error = LDB_SUCCESS; + + return req->callback(req, ares); +} + +/* calls the original request callback + * + * params: + * req: the original request passed to your module + * ctrls: controls to send in the reply (must be a talloc pointer, steal) + * response: results for extended request (steal) + * error: LDB_SUCCESS for a succesful return + * any other ldb error otherwise + */ +int ldb_module_done(struct ldb_request *req, + struct ldb_control **ctrls, + struct ldb_extended *response, + int error) +{ + struct ldb_reply *ares; + + ares = talloc_zero(req, struct ldb_reply); + if (!ares) { + ldb_oom(req->handle->ldb); + req->callback(req, NULL); + return LDB_ERR_OPERATIONS_ERROR; + } + ares->type = LDB_REPLY_DONE; + ares->controls = talloc_steal(ares, ctrls); + ares->response = talloc_steal(ares, response); + ares->error = error; + + req->callback(req, ares); + return error; +} + +/* to be used *only* in modules init functions. + * this function i synchronous and will register + * the requested OID in the rootdse module if present + * otherwise it will return an error */ +int ldb_mod_register_control(struct ldb_module *module, const char *oid) +{ + struct ldb_request *req; + int ret; + + req = talloc_zero(module, struct ldb_request); + if (req == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + req->operation = LDB_REQ_REGISTER_CONTROL; + req->op.reg_control.oid = oid; + req->callback = ldb_op_default_callback; + + ldb_set_timeout(module->ldb, req, 0); + + req->handle = ldb_handle_new(req, module->ldb); + if (req->handle == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ldb_request(module->ldb, req); + if (ret == LDB_SUCCESS) { + ret = ldb_wait(req->handle, LDB_WAIT_ALL); + } + talloc_free(req); + + return ret; +} + #ifndef STATIC_LIBLDB_MODULES #ifdef HAVE_LDB_LDAP |