diff options
Diffstat (limited to 'source4/lib/ldb')
28 files changed, 2934 insertions, 3289 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_dn.c b/source4/lib/ldb/common/ldb_dn.c index c0d36cfbf3..e36aea4e69 100644 --- a/source4/lib/ldb/common/ldb_dn.c +++ b/source4/lib/ldb/common/ldb_dn.c @@ -91,7 +91,7 @@ struct ldb_dn *ldb_dn_from_ldb_val(void *mem_ctx, struct ldb_context *ldb, const * exploded_dn control is used */ dn->special = true; /* FIXME: add a GUID string to ldb_dn structure */ - } else if (strdn->length >= 8 && strncasecmp((const char *)strdn->data, "<SID=", 8) == 0) { + } else if (strdn->length >= 5 && strncasecmp((const char *)strdn->data, "<SID=", 5) == 0) { /* this is special DN returned when the * exploded_dn control is used */ dn->special = true; @@ -150,7 +150,7 @@ struct ldb_dn *ldb_dn_new_fmt(void *mem_ctx, struct ldb_context *ldb, const char * exploded_dn control is used */ dn->special = true; /* FIXME: add a GUID string to ldb_dn structure */ - } else if (strncasecmp(strdn, "<SID=", 8) == 0) { + } else if (strncasecmp(strdn, "<SID=", 5) == 0) { /* this is special DN returned when the * exploded_dn control is used */ dn->special = true; 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 diff --git a/source4/lib/ldb/include/ldb.h b/source4/lib/ldb/include/ldb.h index 645d7866c5..b1ce3ef70b 100644 --- a/source4/lib/ldb/include/ldb.h +++ b/source4/lib/ldb/include/ldb.h @@ -181,6 +181,7 @@ enum ldb_scope {LDB_SCOPE_DEFAULT=-1, LDB_SCOPE_SUBTREE=2}; struct ldb_context; +struct event_context; /* debugging uses one of the following levels */ enum ldb_debug_level {LDB_DEBUG_FATAL, LDB_DEBUG_ERROR, @@ -659,7 +660,6 @@ enum ldb_request_type { enum ldb_reply_type { LDB_REPLY_ENTRY, LDB_REPLY_REFERRAL, - LDB_REPLY_EXTENDED, LDB_REPLY_DONE }; @@ -693,14 +693,11 @@ struct ldb_reply { struct ldb_extended *response; char *referral; struct ldb_control **controls; + int error; }; -struct ldb_handle { - int status; - enum ldb_state state; - void *private_data; - struct ldb_module *module; -}; +struct ldb_request; +struct ldb_handle; struct ldb_search { struct ldb_dn *base; @@ -747,7 +744,8 @@ struct ldb_sequence_number { uint32_t flags; }; -typedef int (*ldb_request_callback_t)(struct ldb_context *, void *, struct ldb_reply *); +typedef int (*ldb_request_callback_t)(struct ldb_request *, struct ldb_reply *); + struct ldb_request { enum ldb_request_type operation; @@ -775,7 +773,10 @@ struct ldb_request { }; int ldb_request(struct ldb_context *ldb, struct ldb_request *request); +int ldb_request_done(struct ldb_request *req, int status); +bool ldb_request_is_done(struct ldb_request *req); +int ldb_modules_wait(struct ldb_handle *handle); int ldb_wait(struct ldb_handle *handle, enum ldb_wait_type type); int ldb_set_timeout(struct ldb_context *ldb, struct ldb_request *req, int timeout); @@ -831,6 +832,19 @@ struct ldb_context *ldb_init(TALLOC_CTX *mem_ctx, struct event_context *ev_ctx); (that is, with LDB_FLG_RDONLY). However in read-write mode, the database will be created if it does not exist. */ + +typedef void (*ldb_async_timeout_fn) (void *); +typedef bool (*ldb_async_callback_fn) (void *); +typedef int (*ldb_async_ctx_add_op_fn)(void *, time_t, void *, ldb_async_timeout_fn, ldb_async_callback_fn); +typedef int (*ldb_async_ctx_wait_op_fn)(void *); + +void ldb_async_ctx_set_private_data(struct ldb_context *ldb, + void *private_data); +void ldb_async_ctx_set_add_op(struct ldb_context *ldb, + ldb_async_ctx_add_op_fn add_op); +void ldb_async_ctx_set_wait_op(struct ldb_context *ldb, + ldb_async_ctx_wait_op_fn wait_op); + int ldb_connect(struct ldb_context *ldb, const char *url, unsigned int flags, const char *options[]); /* @@ -860,13 +874,12 @@ struct ldb_dn *ldb_get_default_basedn(struct ldb_context *ldb); /** The default async search callback function - \param ldb the context associated with the database (from ldb_init()) - \param context the callback context (struct ldb_result *) + \param req the request we are callback of \param ares a single reply from the async core \return result code (LDB_SUCCESS on success, or a failure code) - \note this function expects the context to always be an struct ldb_result pointer + \note this function expects req->context to always be an struct ldb_result pointer AND a talloc context, this function will steal on the context each message from the ares reply passed on by the async core so that in the end all the messages will be in the context (ldb_result) memory tree. @@ -875,7 +888,18 @@ struct ldb_dn *ldb_get_default_basedn(struct ldb_context *ldb); request that can be freed as sson as the search request is finished) */ -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); + +/** + The default async extended operation callback function + + \param req the request we are callback of + \param ares a single reply from the async core + + \return result code (LDB_SUCCESS on success, or a failure code) +*/ +int ldb_op_default_callback(struct ldb_request *req, struct ldb_reply *ares); + /** Helper function to build a search request @@ -889,7 +913,8 @@ int ldb_search_default_callback(struct ldb_context *ldb, void *context, struct l \param attrs the search attributes for the query (pass NULL if none required) \param controls an array of controls \param context the callback function context - \param callback the callback function to handle the async replies + \param the callback function to handle the async replies + \param the parent request if any \return result code (LDB_SUCCESS on success, or a failure code) */ @@ -903,7 +928,20 @@ int ldb_build_search_req(struct ldb_request **ret_req, const char * const *attrs, struct ldb_control **controls, void *context, - ldb_request_callback_t callback); + ldb_request_callback_t callback, + struct ldb_request *parent); + +int ldb_build_search_req_ex(struct ldb_request **ret_req, + struct ldb_context *ldb, + TALLOC_CTX *mem_ctx, + struct ldb_dn *base, + enum ldb_scope scope, + struct ldb_parse_tree *tree, + const char * const *attrs, + struct ldb_control **controls, + void *context, + ldb_request_callback_t callback, + struct ldb_request *parent); /** Helper function to build an add request @@ -914,7 +952,8 @@ int ldb_build_search_req(struct ldb_request **ret_req, \param message contains the entry to be added \param controls an array of controls \param context the callback function context - \param callback the callback function to handle the async replies + \param the callback function to handle the async replies + \param the parent request if any \return result code (LDB_SUCCESS on success, or a failure code) */ @@ -925,7 +964,8 @@ int ldb_build_add_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); /** Helper function to build a modify request @@ -936,7 +976,8 @@ int ldb_build_add_req(struct ldb_request **ret_req, \param message contains the entry to be modified \param controls an array of controls \param context the callback function context - \param callback the callback function to handle the async replies + \param the callback function to handle the async replies + \param the parent request if any \return result code (LDB_SUCCESS on success, or a failure code) */ @@ -947,7 +988,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); /** Helper function to build a delete request @@ -958,7 +1000,8 @@ int ldb_build_mod_req(struct ldb_request **ret_req, \param dn the DN to be deleted \param controls an array of controls \param context the callback function context - \param callback the callback function to handle the async replies + \param the callback function to handle the async replies + \param the parent request if any \return result code (LDB_SUCCESS on success, or a failure code) */ @@ -969,7 +1012,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); /** Helper function to build a rename request @@ -981,7 +1025,8 @@ int ldb_build_del_req(struct ldb_request **ret_req, \param newdn the new DN \param controls an array of controls \param context the callback function context - \param callback the callback function to handle the async replies + \param the callback function to handle the async replies + \param the parent request if any \return result code (LDB_SUCCESS on success, or a failure code) */ @@ -993,7 +1038,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); /** Add a ldb_control to a ldb_request @@ -1103,13 +1149,12 @@ int ldb_delete(struct ldb_context *ldb, struct ldb_dn *dn); /** The default async extended operation callback function - \param ldb the context associated with the database (from ldb_init()) - \param context the callback context (struct ldb_result *) + \param req the request we are callback of \param ares a single reply from the async core \return result code (LDB_SUCCESS on success, or a failure code) - \note this function expects the context to always be an struct ldb_result pointer + \note this function expects req->context to always be an struct ldb_result pointer AND a talloc context, this function will steal on the context each message from the ares reply passed on by the async core so that in the end all the messages will be in the context (ldb_result) memory tree. @@ -1117,7 +1162,9 @@ int ldb_delete(struct ldb_context *ldb, struct ldb_dn *dn); (the request need to be freed separately and the result doe not depend on the request that can be freed as sson as the search request is finished) */ -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); + /** Helper function to build a extended request @@ -1130,7 +1177,8 @@ int ldb_extended_default_callback(struct ldb_context *ldb, void *context, struct it needs to be NULL or a valid talloc pointer! talloc_get_type() will be used on it \param controls an array of controls \param context the callback function context - \param callback the callback function to handle the async replies + \param the callback function to handle the async replies + \param the parent request if any \return result code (LDB_SUCCESS on success, or a failure code) */ @@ -1141,7 +1189,8 @@ int ldb_build_extended_req(struct ldb_request **ret_req, void *data,/* NULL or a valid talloc pointer! talloc_get_type() will be used on it */ struct ldb_control **controls, void *context, - ldb_request_callback_t callback); + ldb_request_callback_t callback, + struct ldb_request *parent); /** call an extended operation diff --git a/source4/lib/ldb/include/ldb_private.h b/source4/lib/ldb/include/ldb_private.h index 30adadcfdc..a92549d9ce 100644 --- a/source4/lib/ldb/include/ldb_private.h +++ b/source4/lib/ldb/include/ldb_private.h @@ -43,6 +43,12 @@ struct ldb_module_ops; struct ldb_backend_ops; +struct ldb_handle { + int status; + enum ldb_state state; + struct ldb_context *ldb; +}; + /* basic module structure */ struct ldb_module { struct ldb_module *prev, *next; @@ -51,9 +57,8 @@ struct ldb_module { const struct ldb_module_ops *ops; }; -/* - these function pointers define the operations that a ldb module must perform - they correspond exactly to the ldb_*() interface +/* + these function pointers define the operations that a ldb module can intercept */ struct ldb_module_ops { const char *name; @@ -68,23 +73,10 @@ struct ldb_module_ops { int (*start_transaction)(struct ldb_module *); int (*end_transaction)(struct ldb_module *); int (*del_transaction)(struct ldb_module *); - int (*wait)(struct ldb_handle *, enum ldb_wait_type); int (*sequence_number)(struct ldb_module *, struct ldb_request *); void *private_data; }; - -typedef int (*ldb_connect_fn) (struct ldb_context *ldb, const char *url, unsigned int flags, const char *options[], - struct ldb_module **module); - - -struct ldb_backend_ops { - const char *name; - ldb_connect_fn connect_fn; -}; - -const char *ldb_default_modules_dir(void); - /* schema related information needed for matching rules */ @@ -146,27 +138,6 @@ int ldb_connect_backend(struct ldb_context *ldb, const char *url, const char *op struct ldb_module **backend_module); void ldb_set_default_dns(struct ldb_context *ldb); -/* The following definitions come from lib/ldb/common/ldb_modules.c */ - -const char **ldb_modules_list_from_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *string); -int ldb_load_modules_list(struct ldb_context *ldb, const char **module_list, struct ldb_module *backend, struct ldb_module **out); -int ldb_load_modules(struct ldb_context *ldb, const char *options[]); -int ldb_init_module_chain(struct ldb_context *ldb, struct ldb_module *module); -int ldb_next_request(struct ldb_module *module, struct ldb_request *request); -int ldb_next_start_trans(struct ldb_module *module); -int ldb_next_end_trans(struct ldb_module *module); -int ldb_next_del_trans(struct ldb_module *module); -int ldb_next_init(struct ldb_module *module); - -void ldb_set_errstring(struct ldb_context *ldb, const char *err_string); -void ldb_asprintf_errstring(struct ldb_context *ldb, const char *format, ...) PRINTF_ATTRIBUTE(2,3); -void ldb_reset_err_string(struct ldb_context *ldb); - -int ldb_register_module(const struct ldb_module_ops *); -int ldb_register_backend(const char *url_prefix, ldb_connect_fn); -void *ldb_dso_load_symbol(struct ldb_context *ldb, const char *name, - const char *symbol); - /* The following definitions come from lib/ldb/common/ldb_debug.c */ void ldb_debug(struct ldb_context *ldb, enum ldb_debug_level level, const char *fmt, ...) PRINTF_ATTRIBUTE(3, 4); void ldb_debug_set(struct ldb_context *ldb, enum ldb_debug_level level, @@ -249,4 +220,57 @@ int ldb_sequence_number(struct ldb_context *ldb, enum ldb_sequence_type type, ui #define LDB_SEQ_TIMESTAMP_SEQUENCE 0x02 +/* MODULES specific headers -- SSS */ + +/* The following definitions come from lib/ldb/common/ldb_modules.c */ + +const char **ldb_modules_list_from_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *string); +int ldb_load_modules_list(struct ldb_context *ldb, const char **module_list, struct ldb_module *backend, struct ldb_module **out); +int ldb_load_modules(struct ldb_context *ldb, const char *options[]); +int ldb_init_module_chain(struct ldb_context *ldb, struct ldb_module *module); +int ldb_next_request(struct ldb_module *module, struct ldb_request *request); +int ldb_next_start_trans(struct ldb_module *module); +int ldb_next_end_trans(struct ldb_module *module); +int ldb_next_del_trans(struct ldb_module *module); +int ldb_next_init(struct ldb_module *module); + +void ldb_set_errstring(struct ldb_context *ldb, const char *err_string); +void ldb_asprintf_errstring(struct ldb_context *ldb, const char *format, ...) PRINTF_ATTRIBUTE(2,3); +void ldb_reset_err_string(struct ldb_context *ldb); + +const char *ldb_default_modules_dir(void); + +int ldb_register_module(const struct ldb_module_ops *); + +typedef int (*ldb_connect_fn)(struct ldb_context *ldb, const char *url, + unsigned int flags, const char *options[], + struct ldb_module **module); + +struct ldb_backend_ops { + const char *name; + ldb_connect_fn connect_fn; +}; + +const char *ldb_default_modules_dir(void); + +int ldb_register_backend(const char *url_prefix, ldb_connect_fn); + +void *ldb_dso_load_symbol(struct ldb_context *ldb, const char *name, + const char *symbol); + +struct ldb_handle *ldb_handle_new(TALLOC_CTX *mem_ctx, struct ldb_context *ldb); + +int ldb_module_send_entry(struct ldb_request *req, + struct ldb_message *msg); + +int ldb_module_send_referral(struct ldb_request *req, + char *ref); + +int ldb_module_done(struct ldb_request *req, + struct ldb_control **ctrls, + struct ldb_extended *response, + int error); + +int ldb_mod_register_control(struct ldb_module *module, const char *oid); + #endif diff --git a/source4/lib/ldb/ldb.i b/source4/lib/ldb/ldb.i index 45978251f7..024ba1959a 100644 --- a/source4/lib/ldb/ldb.i +++ b/source4/lib/ldb/ldb.i @@ -737,15 +737,14 @@ typedef struct ldb_context { attrs, controls, res, - ldb_search_default_callback); + ldb_search_default_callback, + NULL); if (ret != LDB_SUCCESS) { talloc_free(res); return ret; } - ldb_set_timeout($self, req, 0); /* use default timeout */ - ret = ldb_request($self, req); if (ret == LDB_SUCCESS) { @@ -1220,22 +1219,6 @@ int py_module_del_transaction(struct ldb_module *mod) return LDB_SUCCESS; } -int py_module_wait(struct ldb_handle *mod, enum ldb_wait_type wait_type) -{ - PyObject *py_ldb = mod->private_data; - PyObject *py_result; - - py_result = PyObject_CallMethod(py_ldb, "wait", "i", wait_type); - - if (py_result == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } - - Py_DECREF(py_result); - - return LDB_SUCCESS; -} - int py_module_sequence_number(struct ldb_module *mod, struct ldb_request *req) { PyObject *py_ldb = mod->private_data; @@ -1309,7 +1292,6 @@ int py_module_init (struct ldb_module *mod) $1->start_transaction = py_module_start_transaction; $1->end_transaction = py_module_end_transaction; $1->del_transaction = py_module_del_transaction; - $1->wait = py_module_wait; $1->sequence_number = py_module_sequence_number; } diff --git a/source4/lib/ldb/ldb_ildap/ldb_ildap.c b/source4/lib/ldb/ldb_ildap/ldb_ildap.c index 5ad671ea2e..4aa71e6036 100644 --- a/source4/lib/ldb/ldb_ildap/ldb_ildap.c +++ b/source4/lib/ldb/ldb_ildap/ldb_ildap.c @@ -53,17 +53,57 @@ struct ildb_private { struct ldap_connection *ldap; - struct ldb_module *module; + struct event_context *event_ctx; }; struct ildb_context { + struct ldb_module *module; + struct ldb_request *req; + struct ildb_private *ildb; - struct ldb_handle *handle; - struct ldap_request *req; - void *context; - int (*callback)(struct ldb_context *, void *, struct ldb_reply *); + struct ldap_request *ireq; + + bool done; + + struct ildb_destructor_ctx *dc; }; +static void ildb_request_done(struct ildb_context *ctx, + struct ldb_control **ctrls, int error) +{ + struct ldb_reply *ares; + + ctx->done = true; + + if (ctx->req == NULL) { + /* if the req has been freed already just return */ + return; + } + + ares = talloc_zero(ctx->req, struct ldb_reply); + if (!ares) { + ldb_oom(ctx->req->handle->ldb); + ctx->req->callback(ctx->req, NULL); + return; + } + ares->type = LDB_REPLY_DONE; + ares->controls = talloc_steal(ares, ctrls); + ares->error = error; + + ctx->req->callback(ctx->req, ares); +} + +static void ildb_auto_done_callback(struct event_context *ev, + struct timed_event *te, + struct timeval t, + void *private_data) +{ + struct ildb_context *ac; + + ac = talloc_get_type(private_data, struct ildb_context); + ildb_request_done(ac, NULL, LDB_SUCCESS); +} + /* convert a ldb_message structure to a list of ldap_mod structures ready for ildap_add() or ildap_modify() @@ -122,17 +162,19 @@ failed: /* map an ildap NTSTATUS to a ldb error code */ -static int ildb_map_error(struct ildb_private *ildb, NTSTATUS status) +static int ildb_map_error(struct ldb_module *module, NTSTATUS status) { + struct ildb_private *ildb = talloc_get_type(module->private_data, struct ildb_private); + TALLOC_CTX *mem_ctx = talloc_new(ildb); if (NT_STATUS_IS_OK(status)) { return LDB_SUCCESS; } if (!mem_ctx) { - ldb_oom(ildb->module->ldb); + ldb_oom(module->ldb); return LDB_ERR_OPERATIONS_ERROR; } - ldb_set_errstring(ildb->module->ldb, + ldb_set_errstring(module->ldb, ldap_errstr(ildb->ldap, mem_ctx, status)); talloc_free(mem_ctx); if (NT_STATUS_IS_LDAP(status)) { @@ -141,47 +183,46 @@ static int ildb_map_error(struct ildb_private *ildb, NTSTATUS status) return LDB_ERR_OPERATIONS_ERROR; } -static void ildb_request_timeout(struct event_context *ev, - struct timed_event *te, +static void ildb_request_timeout(struct event_context *ev, struct timed_event *te, struct timeval t, void *private_data) { - struct ildb_context *ac; - struct ldb_handle *handle; - - ac = talloc_get_type(private_data, struct ildb_context); - handle = ac->handle; - - ac = talloc_get_type(private_data, struct ildb_context); + struct ildb_context *ac = talloc_get_type(private_data, struct ildb_context); - if (ac->req->state == LDAP_REQUEST_PENDING) { - DLIST_REMOVE(ac->req->conn->pending, ac->req); + if (ac->ireq->state == LDAP_REQUEST_PENDING) { + DLIST_REMOVE(ac->ireq->conn->pending, ac->ireq); } - handle->status = LDB_ERR_TIME_LIMIT_EXCEEDED; - - return; + ildb_request_done(ac, NULL, LDB_ERR_TIME_LIMIT_EXCEEDED); } static void ildb_callback(struct ldap_request *req) { struct ildb_context *ac; - struct ldb_handle *handle; - struct ildb_private *ildb; NTSTATUS status; + struct ldap_SearchResEntry *search; + struct ldap_message *msg; + struct ldb_control **controls; + struct ldb_message *ldbmsg; + char *referral; + bool callback_failed; + bool request_done; + int ret; int i; ac = talloc_get_type(req->async.private_data, struct ildb_context); - ildb = ac->ildb; - handle = ac->handle; - handle->status = LDB_SUCCESS; + callback_failed = false; + request_done = false; + controls = NULL; if (!NT_STATUS_IS_OK(req->status)) { - handle->status = ildb_map_error(ildb, req->status); + ret = ildb_map_error(ac->module, req->status); + ildb_request_done(ac, NULL, ret); return; } if (req->num_replies < 1) { - handle->status = LDB_ERR_OPERATIONS_ERROR; + ret = LDB_ERR_OPERATIONS_ERROR; + ildb_request_done(ac, NULL, ret); return; } @@ -189,140 +230,112 @@ static void ildb_callback(struct ldap_request *req) case LDAP_TAG_ModifyRequest: if (req->replies[0]->type != LDAP_TAG_ModifyResponse) { - handle->status = LDB_ERR_PROTOCOL_ERROR; - return; + ret = LDB_ERR_PROTOCOL_ERROR; + break; } - status = ldap_check_response(req->conn, &req->replies[0]->r.GeneralResult); - handle->status = ildb_map_error(ildb, status); - if (ac->callback && handle->status == LDB_SUCCESS) { - /* FIXME: build a corresponding ares to pass on */ - handle->status = ac->callback(ac->ildb->module->ldb, ac->context, NULL); - } - handle->state = LDB_ASYNC_DONE; + status = ldap_check_response(ac->ireq->conn, &req->replies[0]->r.GeneralResult); + ret = ildb_map_error(ac->module, status); + request_done = true; break; case LDAP_TAG_AddRequest: if (req->replies[0]->type != LDAP_TAG_AddResponse) { - handle->status = LDB_ERR_PROTOCOL_ERROR; + ret = LDB_ERR_PROTOCOL_ERROR; return; } - status = ldap_check_response(req->conn, &req->replies[0]->r.GeneralResult); - handle->status = ildb_map_error(ildb, status); - if (ac->callback && handle->status == LDB_SUCCESS) { - /* FIXME: build a corresponding ares to pass on */ - handle->status = ac->callback(ac->ildb->module->ldb, ac->context, NULL); - } - handle->state = LDB_ASYNC_DONE; + status = ldap_check_response(ac->ireq->conn, &req->replies[0]->r.GeneralResult); + ret = ildb_map_error(ac->module, status); + request_done = true; break; case LDAP_TAG_DelRequest: if (req->replies[0]->type != LDAP_TAG_DelResponse) { - handle->status = LDB_ERR_PROTOCOL_ERROR; + ret = LDB_ERR_PROTOCOL_ERROR; return; } - status = ldap_check_response(req->conn, &req->replies[0]->r.GeneralResult); - handle->status = ildb_map_error(ildb, status); - if (ac->callback && handle->status == LDB_SUCCESS) { - /* FIXME: build a corresponding ares to pass on */ - handle->status = ac->callback(ac->ildb->module->ldb, ac->context, NULL); - } - handle->state = LDB_ASYNC_DONE; + status = ldap_check_response(ac->ireq->conn, &req->replies[0]->r.GeneralResult); + ret = ildb_map_error(ac->module, status); + request_done = true; break; case LDAP_TAG_ModifyDNRequest: if (req->replies[0]->type != LDAP_TAG_ModifyDNResponse) { - handle->status = LDB_ERR_PROTOCOL_ERROR; + ret = LDB_ERR_PROTOCOL_ERROR; return; } - status = ldap_check_response(req->conn, &req->replies[0]->r.GeneralResult); - handle->status = ildb_map_error(ildb, status); - if (ac->callback && handle->status == LDB_SUCCESS) { - /* FIXME: build a corresponding ares to pass on */ - handle->status = ac->callback(ac->ildb->module->ldb, ac->context, NULL); - } - handle->state = LDB_ASYNC_DONE; + status = ldap_check_response(ac->ireq->conn, &req->replies[0]->r.GeneralResult); + ret = ildb_map_error(ac->module, status); + request_done = true; break; case LDAP_TAG_SearchRequest: /* loop over all messages */ for (i = 0; i < req->num_replies; i++) { - struct ldap_SearchResEntry *search; - struct ldb_reply *ares = NULL; - struct ldap_message *msg; - int ret; - - ares = talloc_zero(ac, struct ldb_reply); - if (!ares) { - handle->status = LDB_ERR_OPERATIONS_ERROR; - return; - } msg = req->replies[i]; switch (msg->type) { case LDAP_TAG_SearchResultDone: - status = ldap_check_response(req->conn, &msg->r.GeneralResult); + status = ldap_check_response(ac->ireq->conn, &msg->r.GeneralResult); if (!NT_STATUS_IS_OK(status)) { - handle->status = ildb_map_error(ildb, status); - return; + ret = ildb_map_error(ac->module, status); + break; } - ares->controls = talloc_move(ares, &msg->controls); + controls = talloc_steal(ac, msg->controls); if (msg->r.SearchResultDone.resultcode) { if (msg->r.SearchResultDone.errormessage) { - ldb_set_errstring(ac->ildb->module->ldb, msg->r.SearchResultDone.errormessage); + ldb_set_errstring(ac->module->ldb, msg->r.SearchResultDone.errormessage); } } - handle->status = msg->r.SearchResultDone.resultcode; - handle->state = LDB_ASYNC_DONE; - ares->type = LDB_REPLY_DONE; + ret = msg->r.SearchResultDone.resultcode; + request_done = true; break; case LDAP_TAG_SearchResultEntry: - - ares->message = ldb_msg_new(ares); - if (!ares->message) { - handle->status = LDB_ERR_OPERATIONS_ERROR; - return; + ldbmsg = ldb_msg_new(ac); + if (!ldbmsg) { + ret = LDB_ERR_OPERATIONS_ERROR; + break; } search = &(msg->r.SearchResultEntry); - ares->message->dn = ldb_dn_new(ares->message, ac->ildb->module->ldb, search->dn); - if ( ! ldb_dn_validate(ares->message->dn)) { - handle->status = LDB_ERR_OPERATIONS_ERROR; - return; + ldbmsg->dn = ldb_dn_new(ldbmsg, ac->module->ldb, search->dn); + if ( ! ldb_dn_validate(ldbmsg->dn)) { + ret = LDB_ERR_OPERATIONS_ERROR; + break; } - ares->message->num_elements = search->num_attributes; - ares->message->elements = talloc_move(ares->message, - &search->attributes); + ldbmsg->num_elements = search->num_attributes; + ldbmsg->elements = talloc_move(ldbmsg, &search->attributes); - handle->status = LDB_SUCCESS; - handle->state = LDB_ASYNC_PENDING; - ares->type = LDB_REPLY_ENTRY; + ret = ldb_module_send_entry(ac->req, ldbmsg); + if (ret != LDB_SUCCESS) { + callback_failed = true; + } break; case LDAP_TAG_SearchResultReference: - ares->referral = talloc_strdup(ares, msg->r.SearchResultReference.referral); + referral = talloc_strdup(ac, msg->r.SearchResultReference.referral); - handle->status = LDB_SUCCESS; - handle->state = LDB_ASYNC_PENDING; - ares->type = LDB_REPLY_REFERRAL; + ret = ldb_module_send_referral(ac->req, referral); + if (ret != LDB_SUCCESS) { + callback_failed = true; + } break; default: /* TAG not handled, fail ! */ - handle->status = LDB_ERR_PROTOCOL_ERROR; - return; + ret = LDB_ERR_PROTOCOL_ERROR; + break; } - ret = ac->callback(ac->ildb->module->ldb, ac->context, ares); - if (ret) { - handle->status = ret; + if (ret != LDB_SUCCESS) { + break; } } @@ -333,121 +346,81 @@ static void ildb_callback(struct ldap_request *req) break; default: - handle->status = LDB_ERR_PROTOCOL_ERROR; - return; + ret = LDB_ERR_PROTOCOL_ERROR; + break; } -} -static struct ildb_context *init_ildb_handle(struct ildb_private *ildb, - struct ldb_request *req) -{ - struct ildb_context *ildb_ac; - struct ldb_handle *h; + if (ret != LDB_SUCCESS) { - h = talloc_zero(req, struct ldb_handle); - if (h == NULL) { - ldb_set_errstring(ildb->module->ldb, "Out of Memory"); - return NULL; + /* if the callback failed the caller will have freed the + * request. Just return and don't try to use it */ + if ( ! callback_failed) { + request_done = true; + } } - h->module = ildb->module; - - ildb_ac = talloc(h, struct ildb_context); - if (ildb_ac == NULL) { - ldb_set_errstring(ildb->module->ldb, "Out of Memory"); - talloc_free(h); - return NULL; + if (request_done) { + ildb_request_done(ac, controls, ret); } - - h->private_data = ildb_ac; - - h->state = LDB_ASYNC_INIT; - h->status = LDB_SUCCESS; - - ildb_ac->ildb = ildb; - ildb_ac->handle = h; - ildb_ac->context = req->context; - ildb_ac->callback = req->callback; - - req->handle = h; - return ildb_ac; + return; } -static int ildb_request_send(struct ildb_private *ildb, struct ldap_message *msg, struct ldb_request *r) +static int ildb_request_send(struct ildb_context *ac, struct ldap_message *msg) { - struct ildb_context *ildb_ac = init_ildb_handle(ildb, r); struct ldap_request *req; - if (!ildb_ac) { + if (!ac) { return LDB_ERR_OPERATIONS_ERROR; } - req = ldap_request_send(ildb->ldap, msg); + req = ldap_request_send(ac->ildb->ldap, msg); if (req == NULL) { - ldb_set_errstring(ildb->module->ldb, "async send request failed"); + ldb_set_errstring(ac->module->ldb, "async send request failed"); return LDB_ERR_OPERATIONS_ERROR; } - ildb_ac->req = talloc_steal(ildb_ac, req); + ac->ireq = talloc_steal(ac, req); - if (!req->conn) { - ldb_set_errstring(ildb->module->ldb, "connection to remote LDAP server dropped?"); + if (!ac->ireq->conn) { + ldb_set_errstring(ac->module->ldb, "connection to remote LDAP server dropped?"); return LDB_ERR_OPERATIONS_ERROR; } talloc_free(req->time_event); req->time_event = NULL; - if (r->timeout) { - req->time_event = event_add_timed(req->conn->event.event_ctx, ildb_ac, - timeval_current_ofs(r->timeout, 0), - ildb_request_timeout, ildb_ac); + if (ac->req->timeout) { + req->time_event = event_add_timed(ac->ildb->event_ctx, ac, + timeval_current_ofs(ac->req->timeout, 0), + ildb_request_timeout, ac); } req->async.fn = ildb_callback; - req->async.private_data = ildb_ac; + req->async.private_data = ac; return LDB_SUCCESS; } -static int ildb_request_noop(struct ildb_private *ildb, struct ldb_request *req) -{ - struct ildb_context *ildb_ac = init_ildb_handle(ildb, req); - int ret = LDB_SUCCESS; - - if (!ildb_ac) { - return LDB_ERR_OPERATIONS_ERROR; - } - - if (ildb_ac->callback) { - ret = ildb_ac->callback(ildb->module->ldb, ildb_ac->context, NULL); - } - ildb_ac->handle->state = LDB_ASYNC_DONE; - return ret; -} - /* search for matching records using an asynchronous function */ -static int ildb_search(struct ldb_module *module, struct ldb_request *req) +static int ildb_search(struct ildb_context *ac) { - struct ildb_private *ildb = talloc_get_type(module->private_data, struct ildb_private); + struct ldb_request *req = ac->req; struct ldap_message *msg; int n; - req->handle = NULL; - if (!req->callback || !req->context) { - ldb_set_errstring(module->ldb, "Async interface called with NULL callback function or NULL context"); + ldb_set_errstring(ac->module->ldb, "Async interface called with NULL callback function or NULL context"); return LDB_ERR_OPERATIONS_ERROR; } if (req->op.search.tree == NULL) { - ldb_set_errstring(module->ldb, "Invalid expression parse tree"); + ldb_set_errstring(ac->module->ldb, "Invalid expression parse tree"); return LDB_ERR_OPERATIONS_ERROR; } msg = new_ldap_message(req); if (msg == NULL) { - ldb_set_errstring(module->ldb, "Out of Memory"); + ldb_set_errstring(ac->module->ldb, "Out of Memory"); return LDB_ERR_OPERATIONS_ERROR; } @@ -459,7 +432,7 @@ static int ildb_search(struct ldb_module *module, struct ldb_request *req) msg->r.SearchRequest.basedn = ldb_dn_alloc_linearized(msg, req->op.search.base); } if (msg->r.SearchRequest.basedn == NULL) { - ldb_set_errstring(module->ldb, "Unable to determine baseDN"); + ldb_set_errstring(ac->module->ldb, "Unable to determine baseDN"); talloc_free(msg); return LDB_ERR_OPERATIONS_ERROR; } @@ -481,26 +454,19 @@ static int ildb_search(struct ldb_module *module, struct ldb_request *req) msg->r.SearchRequest.attributes = discard_const(req->op.search.attrs); msg->controls = req->controls; - return ildb_request_send(ildb, msg, req); + return ildb_request_send(ac, msg); } /* add a record */ -static int ildb_add(struct ldb_module *module, struct ldb_request *req) +static int ildb_add(struct ildb_context *ac) { - struct ildb_private *ildb = talloc_get_type(module->private_data, struct ildb_private); + struct ldb_request *req = ac->req; struct ldap_message *msg; struct ldap_mod **mods; int i,n; - req->handle = NULL; - - /* ignore ltdb specials */ - if (ldb_dn_is_special(req->op.add.message->dn)) { - return ildb_request_noop(ildb, req); - } - msg = new_ldap_message(req); if (msg == NULL) { return LDB_ERR_OPERATIONS_ERROR; @@ -531,26 +497,19 @@ static int ildb_add(struct ldb_module *module, struct ldb_request *req) msg->r.AddRequest.attributes[i] = mods[i]->attrib; } - return ildb_request_send(ildb, msg, req); + return ildb_request_send(ac, msg); } /* modify a record */ -static int ildb_modify(struct ldb_module *module, struct ldb_request *req) +static int ildb_modify(struct ildb_context *ac) { - struct ildb_private *ildb = talloc_get_type(module->private_data, struct ildb_private); + struct ldb_request *req = ac->req; struct ldap_message *msg; struct ldap_mod **mods; int i,n; - req->handle = NULL; - - /* ignore ltdb specials */ - if (ldb_dn_is_special(req->op.mod.message->dn)) { - return ildb_request_noop(ildb, req); - } - msg = new_ldap_message(req); if (msg == NULL) { return LDB_ERR_OPERATIONS_ERROR; @@ -581,24 +540,17 @@ static int ildb_modify(struct ldb_module *module, struct ldb_request *req) msg->r.ModifyRequest.mods[i] = *mods[i]; } - return ildb_request_send(ildb, msg, req); + return ildb_request_send(ac, msg); } /* delete a record */ -static int ildb_delete(struct ldb_module *module, struct ldb_request *req) +static int ildb_delete(struct ildb_context *ac) { - struct ildb_private *ildb = talloc_get_type(module->private_data, struct ildb_private); + struct ldb_request *req = ac->req; struct ldap_message *msg; - req->handle = NULL; - - /* ignore ltdb specials */ - if (ldb_dn_is_special(req->op.del.dn)) { - return ildb_request_noop(ildb, req); - } - msg = new_ldap_message(req); if (msg == NULL) { return LDB_ERR_OPERATIONS_ERROR; @@ -612,24 +564,17 @@ static int ildb_delete(struct ldb_module *module, struct ldb_request *req) return LDB_ERR_INVALID_DN_SYNTAX; } - return ildb_request_send(ildb, msg, req); + return ildb_request_send(ac, msg); } /* rename a record */ -static int ildb_rename(struct ldb_module *module, struct ldb_request *req) +static int ildb_rename(struct ildb_context *ac) { - struct ildb_private *ildb = talloc_get_type(module->private_data, struct ildb_private); + struct ldb_request *req = ac->req; struct ldap_message *msg; - req->handle = NULL; - - /* ignore ltdb specials */ - if (ldb_dn_is_special(req->op.rename.olddn) || ldb_dn_is_special(req->op.rename.newdn)) { - return ildb_request_noop(ildb, req); - } - msg = new_ldap_message(req); if (msg == NULL) { return LDB_ERR_OPERATIONS_ERROR; @@ -660,7 +605,7 @@ static int ildb_rename(struct ldb_module *module, struct ldb_request *req) msg->r.ModifyDNRequest.deleteolddn = true; - return ildb_request_send(ildb, msg, req); + return ildb_request_send(ac, msg); } static int ildb_start_trans(struct ldb_module *module) @@ -684,57 +629,105 @@ static int ildb_del_trans(struct ldb_module *module) return LDB_SUCCESS; } -static int ildb_request(struct ldb_module *module, struct ldb_request *req) +static bool ildb_dn_is_special(struct ldb_request *req) { - return LDB_ERR_OPERATIONS_ERROR; + struct ldb_dn *dn = NULL; + + switch (req->operation) { + case LDB_ADD: + dn = req->op.add.message->dn; + break; + case LDB_MODIFY: + dn = req->op.mod.message->dn; + break; + case LDB_DELETE: + dn = req->op.del.dn; + break; + case LDB_RENAME: + dn = req->op.rename.olddn; + break; + default: + break; + } + + if (dn && ldb_dn_is_special(dn)) { + return true; + } + return false; } -static int ildb_wait(struct ldb_handle *handle, enum ldb_wait_type type) +static int ildb_handle_request(struct ldb_module *module, struct ldb_request *req) { - struct ildb_context *ac = talloc_get_type(handle->private_data, struct ildb_context); + struct ildb_private *ildb; + struct ildb_context *ac; + struct timed_event *te; + int ret; + + ildb = talloc_get_type(module->private_data, struct ildb_private); - if (handle->state == LDB_ASYNC_DONE) { - return handle->status; + if (req->starttime == 0 || req->timeout == 0) { + ldb_set_errstring(module->ldb, "Invalid timeout settings"); + return LDB_ERR_TIME_LIMIT_EXCEEDED; } - if (!ac) { + ac = talloc_zero(req, struct ildb_context); + if (ac == NULL) { + ldb_set_errstring(module->ldb, "Out of Memory"); return LDB_ERR_OPERATIONS_ERROR; } - handle->state = LDB_ASYNC_INIT; + ac->module = module; + ac->req = req; + ac->ildb = ildb; + + if (ildb_dn_is_special(req)) { - switch(type) { - case LDB_WAIT_NONE: - if (event_loop_once(ac->req->conn->event.event_ctx) != 0) { - return LDB_ERR_OTHER; + te = event_add_timed(ac->ildb->event_ctx, + ac, timeval_zero(), + ildb_auto_done_callback, ac); + if (NULL == te) { + return LDB_ERR_OPERATIONS_ERROR; } + + return LDB_SUCCESS; + } + + switch (ac->req->operation) { + case LDB_SEARCH: + ret = ildb_search(ac); break; - case LDB_WAIT_ALL: - while (handle->status == LDB_SUCCESS && handle->state != LDB_ASYNC_DONE) { - if (event_loop_once(ac->req->conn->event.event_ctx) != 0) { - return LDB_ERR_OTHER; - } - } + case LDB_ADD: + ret = ildb_add(ac); + break; + case LDB_MODIFY: + ret = ildb_modify(ac); + break; + case LDB_DELETE: + ret = ildb_delete(ac); + break; + case LDB_RENAME: + ret = ildb_rename(ac); break; default: - return LDB_ERR_OPERATIONS_ERROR; + /* no other op supported */ + ret = LDB_ERR_OPERATIONS_ERROR; + break; } - return handle->status; + return ret; } static const struct ldb_module_ops ildb_ops = { .name = "ldap", - .search = ildb_search, - .add = ildb_add, - .modify = ildb_modify, - .del = ildb_delete, - .rename = ildb_rename, - .request = ildb_request, + .search = ildb_handle_request, + .add = ildb_handle_request, + .modify = ildb_handle_request, + .del = ildb_handle_request, + .rename = ildb_handle_request, +/* .request = ildb_handle_request, */ .start_transaction = ildb_start_trans, .end_transaction = ildb_end_trans, .del_transaction = ildb_del_trans, - .wait = ildb_wait }; /* @@ -748,7 +741,6 @@ static int ildb_connect(struct ldb_context *ldb, const char *url, struct ildb_private *ildb; NTSTATUS status; struct cli_credentials *creds; - struct event_context *event_ctx; module = talloc(ldb, struct ldb_module); if (!module) { @@ -758,7 +750,6 @@ static int ildb_connect(struct ldb_context *ldb, const char *url, talloc_set_name_const(module, "ldb_ildap backend"); module->ldb = ldb; module->prev = module->next = NULL; - module->private_data = NULL; module->ops = &ildb_ops; ildb = talloc(module, struct ildb_private); @@ -767,12 +758,12 @@ static int ildb_connect(struct ldb_context *ldb, const char *url, goto failed; } module->private_data = ildb; - ildb->module = module; - event_ctx = ldb_get_event_context(ldb); + ildb->event_ctx = ldb_get_event_context(ldb); + ildb->ldap = ldap4_new_connection(ildb, ldb_get_opaque(ldb, "loadparm"), - event_ctx); + ildb->event_ctx); if (!ildb->ldap) { ldb_oom(ldb); goto failed; diff --git a/source4/lib/ldb/ldb_ldap/ldb_ldap.c b/source4/lib/ldb/ldb_ldap/ldb_ldap.c index a4534c549a..7caee10b47 100644 --- a/source4/lib/ldb/ldb_ldap/ldb_ldap.c +++ b/source4/lib/ldb/ldb_ldap/ldb_ldap.c @@ -45,17 +45,16 @@ struct lldb_private { LDAP *ldap; - struct ldb_module *module; }; struct lldb_context { + struct ldb_module *module; + struct ldb_request *req; + struct lldb_private *lldb; - struct ldb_handle *handle; + + struct ldb_control **controls; int msgid; - int timeout; - time_t starttime; - void *context; - int (*callback)(struct ldb_context *, void *, struct ldb_reply *); }; static int lldb_ldap_to_ldb(int err) { @@ -63,42 +62,6 @@ static int lldb_ldap_to_ldb(int err) { return err; } -static struct lldb_context *init_lldb_handle(struct lldb_private *lldb, struct ldb_request *req) -{ - struct lldb_context *ac; - struct ldb_handle *h; - - h = talloc_zero(req, struct ldb_handle); - if (h == NULL) { - ldb_set_errstring(lldb->module->ldb, "Out of Memory"); - return NULL; - } - - h->module = lldb->module; - - ac = talloc(h, struct lldb_context); - if (ac == NULL) { - ldb_set_errstring(lldb->module->ldb, "Out of Memory"); - talloc_free(h); - return NULL; - } - - h->private_data = ac; - - h->state = LDB_ASYNC_INIT; - h->status = LDB_SUCCESS; - - ac->lldb = lldb; - ac->handle = h; - ac->context = req->context; - ac->callback = req->callback; - ac->timeout = req->timeout; - ac->starttime = req->starttime; - ac->msgid = 0; - - req->handle = h; - return ac; -} /* convert a ldb_message structure to a list of LDAPMod structures ready for ldap_add() or ldap_modify() @@ -230,10 +193,11 @@ static int lldb_add_msg_attr(struct ldb_context *ldb, /* search for matching records */ -static int lldb_search(struct ldb_module *module, struct ldb_request *req) +static int lldb_search(struct lldb_context *lldb_ac) { - struct lldb_private *lldb = talloc_get_type(module->private_data, struct lldb_private); - struct lldb_context *lldb_ac; + struct lldb_private *lldb = lldb_ac->lldb; + struct ldb_module *module = lldb_ac->module; + struct ldb_request *req = lldb_ac->req; struct timeval tv; int ldap_scope; char *search_base; @@ -254,10 +218,7 @@ static int lldb_search(struct ldb_module *module, struct ldb_request *req) ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Controls are not yet supported by ldb_ldap backend!\n"); } - lldb_ac = init_lldb_handle(lldb, req); - if (lldb_ac == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } + req->handle->state = LDB_ASYNC_PENDING; search_base = ldb_dn_alloc_linearized(lldb_ac, req->op.search.base); if (req->op.search.base == NULL) { @@ -307,23 +268,16 @@ static int lldb_search(struct ldb_module *module, struct ldb_request *req) /* add a record */ -static int lldb_add(struct ldb_module *module, struct ldb_request *req) +static int lldb_add(struct lldb_context *lldb_ac) { - struct lldb_private *lldb = talloc_get_type(module->private_data, struct lldb_private); - struct lldb_context *lldb_ac; + struct lldb_private *lldb = lldb_ac->lldb; + struct ldb_module *module = lldb_ac->module; + struct ldb_request *req = lldb_ac->req; LDAPMod **mods; char *dn; int ret; - /* ltdb specials should not reach this point */ - if (ldb_dn_is_special(req->op.add.message->dn)) { - return LDB_ERR_INVALID_DN_SYNTAX; - } - - lldb_ac = init_lldb_handle(lldb, req); - if (lldb_ac == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } + req->handle->state = LDB_ASYNC_PENDING; mods = lldb_msg_to_mods(lldb_ac, req->op.add.message, 0); if (mods == NULL) { @@ -350,23 +304,16 @@ static int lldb_add(struct ldb_module *module, struct ldb_request *req) /* modify a record */ -static int lldb_modify(struct ldb_module *module, struct ldb_request *req) +static int lldb_modify(struct lldb_context *lldb_ac) { - struct lldb_private *lldb = talloc_get_type(module->private_data, struct lldb_private); - struct lldb_context *lldb_ac; + struct lldb_private *lldb = lldb_ac->lldb; + struct ldb_module *module = lldb_ac->module; + struct ldb_request *req = lldb_ac->req; LDAPMod **mods; char *dn; int ret; - /* ltdb specials should not reach this point */ - if (ldb_dn_is_special(req->op.mod.message->dn)) { - return LDB_ERR_INVALID_DN_SYNTAX; - } - - lldb_ac = init_lldb_handle(lldb, req); - if (req->handle == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } + req->handle->state = LDB_ASYNC_PENDING; mods = lldb_msg_to_mods(lldb_ac, req->op.mod.message, 1); if (mods == NULL) { @@ -393,22 +340,15 @@ static int lldb_modify(struct ldb_module *module, struct ldb_request *req) /* delete a record */ -static int lldb_delete(struct ldb_module *module, struct ldb_request *req) +static int lldb_delete(struct lldb_context *lldb_ac) { - struct lldb_private *lldb = talloc_get_type(module->private_data, struct lldb_private); - struct lldb_context *lldb_ac; + struct lldb_private *lldb = lldb_ac->lldb; + struct ldb_module *module = lldb_ac->module; + struct ldb_request *req = lldb_ac->req; char *dnstr; int ret; - - /* ltdb specials should not reach this point */ - if (ldb_dn_is_special(req->op.del.dn)) { - return LDB_ERR_INVALID_DN_SYNTAX; - } - lldb_ac = init_lldb_handle(lldb, req); - if (lldb_ac == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } + req->handle->state = LDB_ASYNC_PENDING; dnstr = ldb_dn_alloc_linearized(lldb_ac, req->op.del.dn); @@ -427,24 +367,17 @@ static int lldb_delete(struct ldb_module *module, struct ldb_request *req) /* rename a record */ -static int lldb_rename(struct ldb_module *module, struct ldb_request *req) +static int lldb_rename(struct lldb_context *lldb_ac) { - struct lldb_private *lldb = talloc_get_type(module->private_data, struct lldb_private); - struct lldb_context *lldb_ac; + struct lldb_private *lldb = lldb_ac->lldb; + struct ldb_module *module = lldb_ac->module; + struct ldb_request *req = lldb_ac->req; char *old_dn; char *newrdn; char *parentdn; int ret; - - /* ltdb specials should not reach this point */ - if (ldb_dn_is_special(req->op.rename.olddn) || ldb_dn_is_special(req->op.rename.newdn)) { - return LDB_ERR_INVALID_DN_SYNTAX; - } - lldb_ac = init_lldb_handle(lldb, req); - if (lldb_ac == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } + req->handle->state = LDB_ASYNC_PENDING; old_dn = ldb_dn_alloc_linearized(lldb_ac, req->op.rename.olddn); if (old_dn == NULL) { @@ -474,57 +407,99 @@ static int lldb_rename(struct ldb_module *module, struct ldb_request *req) return lldb_ldap_to_ldb(ret); } -static int lldb_parse_result(struct lldb_context *ac, LDAPMessage *result) +static int lldb_start_trans(struct ldb_module *module) +{ + /* TODO implement a local transaction mechanism here */ + + return LDB_SUCCESS; +} + +static int lldb_end_trans(struct ldb_module *module) +{ + /* TODO implement a local transaction mechanism here */ + + return LDB_SUCCESS; +} + +static int lldb_del_trans(struct ldb_module *module) +{ + /* TODO implement a local transaction mechanism here */ + + return LDB_SUCCESS; +} + +void lldb_request_done(struct ldb_request *req, + struct ldb_control **ctrls, 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; + } + ares->type = LDB_REPLY_DONE; + ares->controls = talloc_steal(ares, ctrls); + ares->error = error; + + req->callback(req, ares); +} + +/* return false if the request is still in progress + * return true if the request is completed + */ +static bool lldb_parse_result(struct lldb_context *ac, LDAPMessage *result) { - struct ldb_handle *handle = ac->handle; struct lldb_private *lldb = ac->lldb; - struct ldb_reply *ares = NULL; - LDAPMessage *msg; - int type; + LDAPControl **serverctrlsp = NULL; + char **referralsp = NULL; char *matcheddnp = NULL; char *errmsgp = NULL; - char **referralsp = NULL; - LDAPControl **serverctrlsp = NULL; - int ret = LDB_SUCCESS; - - type = ldap_msgtype(result); + LDAPMessage *msg; + int type; + struct ldb_message *ldbmsg; + char *referral; + bool callback_failed; + bool request_done; + bool lret; + int ret; + int i; - handle->status = 0; + type = ldap_msgtype(result); + callback_failed = false; + request_done = false; switch (type) { - case LDAP_RES_SEARCH_ENTRY: + msg = ldap_first_entry(lldb->ldap, result); if (msg != NULL) { BerElement *berptr = NULL; char *attr, *dn; - ares = talloc_zero(ac, struct ldb_reply); - if (!ares) { - ret = LDB_ERR_OPERATIONS_ERROR; - goto error; - } - - ares->message = ldb_msg_new(ares); - if (!ares->message) { + ldbmsg = ldb_msg_new(ac); + if (!ldbmsg) { ret = LDB_ERR_OPERATIONS_ERROR; - goto error; + break; } dn = ldap_get_dn(lldb->ldap, msg); if (!dn) { + talloc_free(ldbmsg); ret = LDB_ERR_OPERATIONS_ERROR; - goto error; + break; } - ares->message->dn = ldb_dn_new(ares->message, ac->lldb->module->ldb, dn); - if ( ! ldb_dn_validate(ares->message->dn)) { + ldbmsg->dn = ldb_dn_new(ldbmsg, ac->module->ldb, dn); + if ( ! ldb_dn_validate(ldbmsg->dn)) { + talloc_free(ldbmsg); ret = LDB_ERR_OPERATIONS_ERROR; - goto error; + break; } ldap_memfree(dn); - ares->message->num_elements = 0; - ares->message->elements = NULL; + ldbmsg->num_elements = 0; + ldbmsg->elements = NULL; /* loop over all attributes */ for (attr=ldap_first_attribute(lldb->ldap, msg, &berptr); @@ -534,97 +509,104 @@ static int lldb_parse_result(struct lldb_context *ac, LDAPMessage *result) bval = ldap_get_values_len(lldb->ldap, msg, attr); if (bval) { - lldb_add_msg_attr(ac->lldb->module->ldb, ares->message, attr, bval); + lldb_add_msg_attr(ac->module->ldb, ldbmsg, attr, bval); ldap_value_free_len(bval); - } + } } if (berptr) ber_free(berptr, 0); + ret = ldb_module_send_entry(ac->req, ldbmsg); + if (ret != LDB_SUCCESS) { - ares->type = LDB_REPLY_ENTRY; - ret = ac->callback(ac->lldb->module->ldb, ac->context, ares); + callback_failed = true; + } } else { - handle->status = LDB_ERR_PROTOCOL_ERROR; - handle->state = LDB_ASYNC_DONE; + ret = LDB_ERR_OPERATIONS_ERROR; } break; case LDAP_RES_SEARCH_REFERENCE: - if (ldap_parse_result(lldb->ldap, result, &handle->status, + + if (ldap_parse_result(lldb->ldap, result, &ret, &matcheddnp, &errmsgp, &referralsp, &serverctrlsp, 0) != LDAP_SUCCESS) { ret = LDB_ERR_OPERATIONS_ERROR; - goto error; } - if (referralsp == NULL) { - handle->status = LDB_ERR_PROTOCOL_ERROR; - goto error; + if (ret != LDB_SUCCESS) { + break; } - - ares = talloc_zero(ac, struct ldb_reply); - if (!ares) { - ret = LDB_ERR_OPERATIONS_ERROR; - goto error; + if (referralsp == NULL) { + ret = LDB_ERR_PROTOCOL_ERROR; + break; } - ares->referral = talloc_strdup(ares, *referralsp); - ares->type = LDB_REPLY_REFERRAL; - ret = ac->callback(ac->lldb->module->ldb, ac->context, ares); + for (i = 0; referralsp[i]; i++) { + referral = talloc_strdup(ac, referralsp[i]); + ret = ldb_module_send_referral(ac->req, referral); + if (ret != LDB_SUCCESS) { + callback_failed = true; + break; + } + } break; case LDAP_RES_SEARCH_RESULT: - if (ldap_parse_result(lldb->ldap, result, &handle->status, + case LDAP_RES_MODIFY: + case LDAP_RES_ADD: + case LDAP_RES_DELETE: + case LDAP_RES_MODDN: + + if (ldap_parse_result(lldb->ldap, result, &ret, &matcheddnp, &errmsgp, &referralsp, &serverctrlsp, 0) != LDAP_SUCCESS) { - handle->status = LDB_ERR_OPERATIONS_ERROR; - goto error; - } - - ares = talloc_zero(ac, struct ldb_reply); - if (!ares) { ret = LDB_ERR_OPERATIONS_ERROR; - goto error; + } + if (ret != LDB_SUCCESS) { + break; } if (serverctrlsp != NULL) { /* FIXME: transform the LDAPControl list into an ldb_control one */ - ares->controls = NULL; + ac->controls = NULL; } - - ares->type = LDB_REPLY_DONE; - handle->state = LDB_ASYNC_DONE; - ret = ac->callback(ac->lldb->module->ldb, ac->context, ares); - - break; - case LDAP_RES_MODIFY: - case LDAP_RES_ADD: - case LDAP_RES_DELETE: - case LDAP_RES_MODDN: - if (ldap_parse_result(lldb->ldap, result, &handle->status, - &matcheddnp, &errmsgp, - &referralsp, &serverctrlsp, 0) != LDAP_SUCCESS) { - handle->status = LDB_ERR_OPERATIONS_ERROR; - goto error; - } - if (ac->callback && handle->status == LDB_SUCCESS) { - ares = NULL; /* FIXME: build a corresponding ares to pass on */ - ret = ac->callback(ac->lldb->module->ldb, ac->context, ares); - } - handle->state = LDB_ASYNC_DONE; + request_done = true; break; default: ret = LDB_ERR_PROTOCOL_ERROR; - goto error; + break; } + if (ret != LDB_SUCCESS) { + + /* if the callback failed the caller will have freed the + * request. Just return and don't try to use it */ + if (callback_failed) { + + /* tell lldb_wait to remove the request from the + * queue */ + lret = true; + goto free_and_return; + } + + request_done = true; + } + + if (request_done) { + lldb_request_done(ac->req, ac->controls, ret); + lret = true; + goto free_and_return; + } + + lret = false; + +free_and_return: + if (matcheddnp) ldap_memfree(matcheddnp); if (errmsgp && *errmsgp) { - ldb_set_errstring(ac->lldb->module->ldb, errmsgp); - } else if (handle->status) { - ldb_set_errstring(ac->lldb->module->ldb, ldap_err2string(handle->status)); + ldb_set_errstring(ac->module->ldb, errmsgp); } if (errmsgp) { ldap_memfree(errmsgp); @@ -633,131 +615,203 @@ static int lldb_parse_result(struct lldb_context *ac, LDAPMessage *result) if (serverctrlsp) ldap_controls_free(serverctrlsp); ldap_msgfree(result); - return lldb_ldap_to_ldb(handle->status); -error: - handle->state = LDB_ASYNC_DONE; - ldap_msgfree(result); - return ret; + return lret; } -static int lldb_wait(struct ldb_handle *handle, enum ldb_wait_type type) +static void lldb_timeout(struct event_context *ev, + struct timed_event *te, + struct timeval t, + void *private_data) { - struct lldb_context *ac = talloc_get_type(handle->private_data, struct lldb_context); - struct lldb_private *lldb = ac->lldb; - struct timeval timeout; + struct lldb_context *ac; + ac = talloc_get_type(private_data, struct lldb_context); + + lldb_request_done(ac->req, NULL, LDB_ERR_TIME_LIMIT_EXCEEDED); +} + +static void lldb_callback(struct event_context *ev, + struct timed_event *te, + struct timeval t, + void *private_data) +{ + struct lldb_context *ac; + struct timed_event *lte; + struct timeval tv; LDAPMessage *result; - int ret, lret; + int lret; + + ac = talloc_get_type(private_data, struct lldb_context); - if (handle->state == LDB_ASYNC_DONE) { - return handle->status; + if (!ac->msgid) { + lldb_request_done(ac->req, NULL, LDB_ERR_OPERATIONS_ERROR); + return; } - if (!ac || !ac->msgid) { - return LDB_ERR_OPERATIONS_ERROR; + tv.tv_sec = 0; + tv.tv_usec = 0; + lret = ldap_result(ac->lldb->ldap, ac->msgid, 0, &tv, &result); + if (lret == 0) { + goto respin; + } + if (lret == -1) { + lldb_request_done(ac->req, NULL, LDB_ERR_OPERATIONS_ERROR); + return; } - handle->state = LDB_ASYNC_PENDING; - handle->status = LDB_SUCCESS; + if ( ! lldb_parse_result(ac, result)) { + goto respin; + } - switch(type) { - case LDB_WAIT_NONE: + return; - if ((ac->timeout != -1) && - ((ac->starttime + ac->timeout) > time(NULL))) { - return LDB_ERR_TIME_LIMIT_EXCEEDED; - } +respin: + tv.tv_sec = 0; + tv.tv_usec = 100; + lte = event_add_timed(ev, ac, tv, lldb_callback, ac); + if (NULL == lte) { + lldb_request_done(ac->req, NULL, LDB_ERR_OPERATIONS_ERROR); + } +} - timeout.tv_sec = 0; - timeout.tv_usec = 0; +static bool lldb_dn_is_special(struct ldb_request *req) +{ + struct ldb_dn *dn = NULL; - lret = ldap_result(lldb->ldap, ac->msgid, 0, &timeout, &result); - if (lret == -1) { - return LDB_ERR_OPERATIONS_ERROR; - } - if (lret == 0) { - ret = LDB_SUCCESS; - goto done; - } + switch (req->operation) { + case LDB_ADD: + dn = req->op.add.message->dn; + break; + case LDB_MODIFY: + dn = req->op.mod.message->dn; + break; + case LDB_DELETE: + dn = req->op.del.dn; + break; + case LDB_RENAME: + dn = req->op.rename.olddn; + break; + default: + break; + } - return lldb_parse_result(ac, result); + if (dn && ldb_dn_is_special(dn)) { + return true; + } + return false; +} - case LDB_WAIT_ALL: - timeout.tv_usec = 0; - ret = LDB_ERR_OPERATIONS_ERROR; +static void lldb_auto_done_callback(struct event_context *ev, + struct timed_event *te, + struct timeval t, + void *private_data) +{ + struct lldb_context *ac; - while (handle->status == LDB_SUCCESS && handle->state != LDB_ASYNC_DONE) { + ac = talloc_get_type(private_data, struct lldb_context); + lldb_request_done(ac->req, NULL, LDB_SUCCESS); +} - if (ac->timeout == -1) { - lret = ldap_result(lldb->ldap, ac->msgid, 0, NULL, &result); - } else { - timeout.tv_sec = ac->timeout - (time(NULL) - ac->starttime); - if (timeout.tv_sec <= 0) - return LDB_ERR_TIME_LIMIT_EXCEEDED; - lret = ldap_result(lldb->ldap, ac->msgid, 0, &timeout, &result); - } - if (lret == -1) { - return LDB_ERR_OPERATIONS_ERROR; - } - if (lret == 0) { - return LDB_ERR_TIME_LIMIT_EXCEEDED; - } +static int lldb_handle_request(struct ldb_module *module, struct ldb_request *req) +{ + struct lldb_private *lldb; + struct lldb_context *ac; + struct event_context *ev; + struct timed_event *te; + struct timeval tv; + int ret; - ret = lldb_parse_result(ac, result); - if (ret != LDB_SUCCESS) { - return ret; - } + lldb = talloc_get_type(module->private_data, struct lldb_private); + + if (req->starttime == 0 || req->timeout == 0) { + ldb_set_errstring(module->ldb, "Invalid timeout settings"); + return LDB_ERR_TIME_LIMIT_EXCEEDED; + } + + ev = ldb_get_event_context(module->ldb); + if (NULL == ev) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ac = talloc_zero(module->ldb, struct lldb_context); + if (ac == NULL) { + ldb_set_errstring(module->ldb, "Out of Memory"); + return LDB_ERR_OPERATIONS_ERROR; + } + + ac->module = module; + ac->req = req; + ac->lldb = lldb; + ac->msgid = 0; + + if (lldb_dn_is_special(req)) { + tv.tv_sec = 0; + tv.tv_usec = 0; + te = event_add_timed(ev, ac, tv, + lldb_auto_done_callback, ac); + if (NULL == te) { + return LDB_ERR_OPERATIONS_ERROR; } + return LDB_SUCCESS; + } + + switch (ac->req->operation) { + case LDB_SEARCH: + ret = lldb_search(ac); + break; + case LDB_ADD: + ret = lldb_add(ac); + break; + case LDB_MODIFY: + ret = lldb_modify(ac); + break; + case LDB_DELETE: + ret = lldb_delete(ac); + break; + case LDB_RENAME: + ret = lldb_rename(ac); break; - default: - handle->state = LDB_ASYNC_DONE; + /* no other op supported */ ret = LDB_ERR_OPERATIONS_ERROR; + break; } -done: - return ret; -} - -static int lldb_start_trans(struct ldb_module *module) -{ - /* TODO implement a local transaction mechanism here */ - - return LDB_SUCCESS; -} + if (ret != LDB_SUCCESS) { + lldb_request_done(req, NULL, ret); + return ret; + } -static int lldb_end_trans(struct ldb_module *module) -{ - /* TODO implement a local transaction mechanism here */ + tv.tv_sec = 0; + tv.tv_usec = 0; + te = event_add_timed(ev, ac, tv, lldb_callback, ac); + if (NULL == te) { + return LDB_ERR_OPERATIONS_ERROR; + } - return LDB_SUCCESS; -} -static int lldb_del_trans(struct ldb_module *module) -{ - /* TODO implement a local transaction mechanism here */ + tv.tv_sec = req->starttime + req->timeout; + tv.tv_usec = 0; + te = event_add_timed(ev, ac, tv, lldb_timeout, ac); + if (NULL == te) { + return LDB_ERR_OPERATIONS_ERROR; + } return LDB_SUCCESS; } -static int lldb_request(struct ldb_module *module, struct ldb_request *req) -{ - return LDB_ERR_OPERATIONS_ERROR; -} - static const struct ldb_module_ops lldb_ops = { .name = "ldap", - .search = lldb_search, - .add = lldb_add, - .modify = lldb_modify, - .del = lldb_delete, - .rename = lldb_rename, - .request = lldb_request, + .search = lldb_handle_request, + .add = lldb_handle_request, + .modify = lldb_handle_request, + .del = lldb_handle_request, + .rename = lldb_handle_request, + .request = lldb_handle_request, .start_transaction = lldb_start_trans, .end_transaction = lldb_end_trans, .del_transaction = lldb_del_trans, - .wait = lldb_wait }; @@ -771,8 +825,8 @@ static int lldb_destructor(struct lldb_private *lldb) connect to the database */ static int lldb_connect(struct ldb_context *ldb, - const char *url, - unsigned int flags, + const char *url, + unsigned int flags, const char *options[], struct ldb_module **_module) { @@ -790,7 +844,6 @@ static int lldb_connect(struct ldb_context *ldb, talloc_set_name_const(module, "ldb_ldap backend"); module->ldb = ldb; module->prev = module->next = NULL; - module->private_data = NULL; module->ops = &lldb_ops; lldb = talloc(module, struct lldb_private); @@ -799,7 +852,6 @@ static int lldb_connect(struct ldb_context *ldb, goto failed; } module->private_data = lldb; - lldb->module = module; lldb->ldap = NULL; ret = ldap_initialize(&lldb->ldap, url); diff --git a/source4/lib/ldb/ldb_map/ldb_map.c b/source4/lib/ldb/ldb_map/ldb_map.c index e9129c812b..fafbb63b0a 100644 --- a/source4/lib/ldb/ldb_map/ldb_map.c +++ b/source4/lib/ldb/ldb_map/ldb_map.c @@ -3,6 +3,7 @@ Copyright (C) Jelmer Vernooij 2005 Copyright (C) Martin Kuehl <mkhl@samba.org> 2006 + Copyright (C) Simo Sorce 2008 ** NOTE! The following LGPL license applies to the ldb ** library. This does NOT imply that all of Samba is released @@ -106,69 +107,23 @@ const struct ldb_map_context *map_get_context(struct ldb_module *module) } /* Create a generic request context. */ -static struct map_context *map_init_context(struct ldb_handle *h, struct ldb_request *req) +struct map_context *map_init_context(struct ldb_module *module, + struct ldb_request *req) { struct map_context *ac; - ac = talloc_zero(h, struct map_context); + ac = talloc_zero(req, struct map_context); if (ac == NULL) { - map_oom(h->module); + ldb_set_errstring(module->ldb, "Out of Memory"); return NULL; } - ac->module = h->module; - ac->orig_req = req; + ac->module = module; + ac->req = req; return ac; } -/* Create a search request context. */ -struct map_search_context *map_init_search_context(struct map_context *ac, struct ldb_reply *ares) -{ - struct map_search_context *sc; - - sc = talloc_zero(ac, struct map_search_context); - if (sc == NULL) { - map_oom(ac->module); - return NULL; - } - - sc->ac = ac; - sc->local_res = NULL; - sc->remote_res = ares; - - return sc; -} - -/* Create a request context and handle. */ -struct ldb_handle *map_init_handle(struct ldb_request *req, struct ldb_module *module) -{ - struct map_context *ac; - struct ldb_handle *h; - - h = talloc_zero(req, struct ldb_handle); - if (h == NULL) { - map_oom(module); - return NULL; - } - - h->module = module; - - ac = map_init_context(h, req); - if (ac == NULL) { - talloc_free(h); - return NULL; - } - - h->private_data = (void *)ac; - - h->state = LDB_ASYNC_INIT; - h->status = LDB_SUCCESS; - - return h; -} - - /* Dealing with DNs for different partitions * ========================================= */ @@ -888,113 +843,52 @@ static int map_objectclass_convert_operator(struct ldb_module *module, void *mem /* Auxiliary request construction * ============================== */ -/* Store the DN of a single search result in context. */ -static int map_search_self_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) -{ - struct map_context *ac; - - if (context == NULL || ares == NULL) { - ldb_set_errstring(ldb, talloc_asprintf(ldb, "NULL Context or Result in callback")); - return LDB_ERR_OPERATIONS_ERROR; - } - - ac = talloc_get_type(context, struct map_context); - - /* We are interested only in the single reply */ - if (ares->type != LDB_REPLY_ENTRY) { - talloc_free(ares); - return LDB_SUCCESS; - } - - /* We have already found a remote DN */ - if (ac->local_dn) { - ldb_set_errstring(ldb, talloc_asprintf(ldb, "Too many results to base search")); - talloc_free(ares); - return LDB_ERR_OPERATIONS_ERROR; - } - - /* Store local DN */ - ac->local_dn = ares->message->dn; - - return LDB_SUCCESS; -} - /* Build a request to search a record by its DN. */ -struct ldb_request *map_search_base_req(struct map_context *ac, struct ldb_dn *dn, const char * const *attrs, const struct ldb_parse_tree *tree, void *context, ldb_search_callback callback) +struct ldb_request *map_search_base_req(struct map_context *ac, struct ldb_dn *dn, const char * const *attrs, const struct ldb_parse_tree *tree, void *context, ldb_map_callback_t callback) { + const struct ldb_parse_tree *search_tree; struct ldb_request *req; - - req = talloc_zero(ac, struct ldb_request); - if (req == NULL) { - map_oom(ac->module); - return NULL; - } - - req->operation = LDB_SEARCH; - req->op.search.base = dn; - req->op.search.scope = LDB_SCOPE_BASE; - req->op.search.attrs = attrs; + int ret; if (tree) { - req->op.search.tree = tree; + search_tree = tree; } else { - req->op.search.tree = ldb_parse_tree(req, NULL); - if (req->op.search.tree == NULL) { - talloc_free(req); + search_tree = ldb_parse_tree(ac, NULL); + if (search_tree == NULL) { return NULL; } } - req->controls = NULL; - req->context = context; - req->callback = callback; - ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, req); - - return req; -} - -/* Build a request to search the local record by its DN. */ -struct ldb_request *map_search_self_req(struct map_context *ac, struct ldb_dn *dn) -{ - /* attrs[] is returned from this function in - * ac->search_req->op.search.attrs, so it must be static, as - * otherwise the compiler can put it on the stack */ - static const char * const attrs[] = { IS_MAPPED, NULL }; - struct ldb_parse_tree *tree; - - /* Limit search to records with 'IS_MAPPED' present */ - /* TODO: `tree = ldb_parse_tree(ac, IS_MAPPED);' won't do. */ - tree = talloc_zero(ac, struct ldb_parse_tree); - if (tree == NULL) { - map_oom(ac->module); + ret = ldb_build_search_req_ex(&req, ac->module->ldb, ac, + dn, LDB_SCOPE_BASE, + search_tree, attrs, + NULL, + context, callback, + ac->req); + if (ret != LDB_SUCCESS) { return NULL; } - tree->operation = LDB_OP_PRESENT; - tree->u.present.attr = talloc_strdup(tree, IS_MAPPED); - - return map_search_base_req(ac, dn, attrs, tree, ac, map_search_self_callback); + return req; } /* Build a request to update the 'IS_MAPPED' attribute */ -struct ldb_request *map_build_fixup_req(struct map_context *ac, struct ldb_dn *olddn, struct ldb_dn *newdn) +struct ldb_request *map_build_fixup_req(struct map_context *ac, + struct ldb_dn *olddn, + struct ldb_dn *newdn, + void *context, + ldb_map_callback_t callback) { struct ldb_request *req; struct ldb_message *msg; const char *dn; - - /* Prepare request */ - req = talloc_zero(ac, struct ldb_request); - if (req == NULL) { - map_oom(ac->module); - return NULL; - } + int ret; /* Prepare message */ - msg = ldb_msg_new(req); + msg = ldb_msg_new(ac); if (msg == NULL) { map_oom(ac->module); - goto failed; + return NULL; } /* Update local 'IS_MAPPED' to the new remote DN */ @@ -1010,193 +904,22 @@ struct ldb_request *map_build_fixup_req(struct map_context *ac, struct ldb_dn *o goto failed; } - req->operation = LDB_MODIFY; - req->op.mod.message = msg; - req->controls = NULL; - req->handle = NULL; - req->context = NULL; - req->callback = NULL; + /* Prepare request */ + ret = ldb_build_mod_req(&req, ac->module->ldb, + ac, msg, NULL, + context, callback, + ac->req); + if (ret != LDB_SUCCESS) { + goto failed; + } + talloc_steal(req, msg); return req; - failed: - talloc_free(req); + talloc_free(msg); return NULL; } - -/* Asynchronous call structure - * =========================== */ - -/* Figure out which request is currently pending. */ -static struct ldb_request *map_get_req(struct map_context *ac) -{ - switch (ac->step) { - case MAP_SEARCH_SELF_MODIFY: - case MAP_SEARCH_SELF_DELETE: - case MAP_SEARCH_SELF_RENAME: - return ac->search_req; - - case MAP_ADD_REMOTE: - case MAP_MODIFY_REMOTE: - case MAP_DELETE_REMOTE: - case MAP_RENAME_REMOTE: - return ac->remote_req; - - case MAP_RENAME_FIXUP: - return ac->down_req; - - case MAP_ADD_LOCAL: - case MAP_MODIFY_LOCAL: - case MAP_DELETE_LOCAL: - case MAP_RENAME_LOCAL: - return ac->local_req; - - case MAP_SEARCH_REMOTE: - /* Can't happen */ - break; - } - - return NULL; /* unreachable; silences a warning */ -} - -typedef int (*map_next_function)(struct ldb_handle *handle); - -/* Figure out the next request to run. */ -static map_next_function map_get_next(struct map_context *ac) -{ - switch (ac->step) { - case MAP_SEARCH_REMOTE: - return NULL; - - case MAP_ADD_LOCAL: - return map_add_do_remote; - case MAP_ADD_REMOTE: - return NULL; - - case MAP_SEARCH_SELF_MODIFY: - return map_modify_do_local; - case MAP_MODIFY_LOCAL: - return map_modify_do_remote; - case MAP_MODIFY_REMOTE: - return NULL; - - case MAP_SEARCH_SELF_DELETE: - return map_delete_do_local; - case MAP_DELETE_LOCAL: - return map_delete_do_remote; - case MAP_DELETE_REMOTE: - return NULL; - - case MAP_SEARCH_SELF_RENAME: - return map_rename_do_local; - case MAP_RENAME_LOCAL: - return map_rename_do_fixup; - case MAP_RENAME_FIXUP: - return map_rename_do_remote; - case MAP_RENAME_REMOTE: - return NULL; - } - - return NULL; /* unreachable; silences a warning */ -} - -/* Wait for the current pending request to finish and continue with the next. */ -static int map_wait_next(struct ldb_handle *handle) -{ - struct map_context *ac; - struct ldb_request *req; - map_next_function next; - int ret; - - if (handle == NULL || handle->private_data == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } - - if (handle->state == LDB_ASYNC_DONE) { - return handle->status; - } - - handle->state = LDB_ASYNC_PENDING; - handle->status = LDB_SUCCESS; - - ac = talloc_get_type(handle->private_data, struct map_context); - - if (ac->step == MAP_SEARCH_REMOTE) { - int i; - for (i = 0; i < ac->num_searches; i++) { - req = ac->search_reqs[i]; - ret = ldb_wait(req->handle, LDB_WAIT_NONE); - - if (ret != LDB_SUCCESS) { - handle->status = ret; - goto done; - } - if (req->handle->status != LDB_SUCCESS) { - handle->status = req->handle->status; - goto done; - } - if (req->handle->state != LDB_ASYNC_DONE) { - return LDB_SUCCESS; - } - } - } else { - - req = map_get_req(ac); - - ret = ldb_wait(req->handle, LDB_WAIT_NONE); - - if (ret != LDB_SUCCESS) { - handle->status = ret; - goto done; - } - if (req->handle->status != LDB_SUCCESS) { - handle->status = req->handle->status; - goto done; - } - if (req->handle->state != LDB_ASYNC_DONE) { - return LDB_SUCCESS; - } - - next = map_get_next(ac); - if (next) { - return next(handle); - } - } - - ret = LDB_SUCCESS; - -done: - handle->state = LDB_ASYNC_DONE; - return ret; -} - -/* Wait for all current pending requests to finish. */ -static int map_wait_all(struct ldb_handle *handle) -{ - int ret; - - while (handle->state != LDB_ASYNC_DONE) { - ret = map_wait_next(handle); - if (ret != LDB_SUCCESS) { - return ret; - } - } - - return handle->status; -} - -/* Wait for pending requests to finish. */ -int map_wait(struct ldb_handle *handle, enum ldb_wait_type type) -{ - if (type == LDB_WAIT_ALL) { - return map_wait_all(handle); - } else { - return map_wait_next(handle); - } -} - - /* Module initialization * ===================== */ diff --git a/source4/lib/ldb/ldb_map/ldb_map.h b/source4/lib/ldb/ldb_map/ldb_map.h index e40bb9cd7e..7f92c15b98 100644 --- a/source4/lib/ldb/ldb_map/ldb_map.h +++ b/source4/lib/ldb/ldb_map/ldb_map.h @@ -160,14 +160,12 @@ int map_search(struct ldb_module *module, struct ldb_request *req); int map_rename(struct ldb_module *module, struct ldb_request *req); int map_delete(struct ldb_module *module, struct ldb_request *req); int map_modify(struct ldb_module *module, struct ldb_request *req); -int map_wait(struct ldb_handle *handle, enum ldb_wait_type type); #define LDB_MAP_OPS \ .add = map_add, \ .modify = map_modify, \ .del = map_delete, \ .rename = map_rename, \ - .search = map_search, \ - .wait = map_wait, + .search = map_search, #endif /* __LDB_MAP_H__ */ diff --git a/source4/lib/ldb/ldb_map/ldb_map_inbound.c b/source4/lib/ldb/ldb_map/ldb_map_inbound.c index 7fc3ac4ed5..96605f23eb 100644 --- a/source4/lib/ldb/ldb_map/ldb_map_inbound.c +++ b/source4/lib/ldb/ldb_map/ldb_map_inbound.c @@ -3,6 +3,7 @@ Copyright (C) Jelmer Vernooij 2005 Copyright (C) Martin Kuehl <mkhl@samba.org> 2006 + Copyright (C) Simo Sorce <idra@samba.org> 2008 ** NOTE! The following LGPL license applies to the ldb ** library. This does NOT imply that all of Samba is released @@ -178,51 +179,181 @@ static int ldb_msg_partition(struct ldb_module *module, struct ldb_message *loca } -/* Inbound requests: add, modify, rename, delete - * ============================================= */ +static int map_add_do_local(struct map_context *ac); +static int map_modify_do_local(struct map_context *ac); +static int map_delete_do_local(struct map_context *ac); +static int map_rename_do_local(struct map_context *ac); +static int map_rename_do_fixup(struct map_context *ac); +static int map_rename_local_callback(struct ldb_request *req, + struct ldb_reply *ares); -/* Add the remote record. */ -int map_add_do_remote(struct ldb_handle *handle) + +/***************************************************************************** + * COMMON INBOUND functions +*****************************************************************************/ + +/* Store the DN of a single search result in context. */ +static int map_search_self_callback(struct ldb_request *req, struct ldb_reply *ares) { struct map_context *ac; + int ret; - ac = talloc_get_type(handle->private_data, struct map_context); + ac = talloc_get_type(req->context, struct map_context); - ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->remote_req); + if (!ares) { + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); + } + if (ares->error != LDB_SUCCESS) { + return ldb_module_done(ac->req, ares->controls, + ares->response, ares->error); + } - ac->step = MAP_ADD_REMOTE; + /* We are interested only in the single reply */ + switch(ares->type) { + case LDB_REPLY_ENTRY: + /* We have already found a remote DN */ + if (ac->local_dn) { + ldb_set_errstring(ac->module->ldb, + "Too many results!"); + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); + } - handle->state = LDB_ASYNC_INIT; - handle->status = LDB_SUCCESS; + /* Store local DN */ + ac->local_dn = talloc_steal(ac, ares->message->dn); + break; - return ldb_next_remote_request(ac->module, ac->remote_req); + case LDB_REPLY_DONE: + + switch (ac->req->operation) { + case LDB_MODIFY: + ret = map_modify_do_local(ac); + break; + case LDB_DELETE: + ret = map_delete_do_local(ac); + break; + case LDB_RENAME: + ret = map_rename_do_local(ac); + break; + default: + /* if we get here we have definitely a problem */ + ret = LDB_ERR_OPERATIONS_ERROR; + } + if (ret != LDB_SUCCESS) { + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); + } + + default: + /* ignore referrals */ + break; + } + + talloc_free(ares); + return LDB_SUCCESS; } -/* Add the local record. */ -int map_add_do_local(struct ldb_handle *handle) +/* Build a request to search the local record by its DN. */ +static int map_search_self_req(struct ldb_request **req, + struct map_context *ac, + struct ldb_dn *dn) +{ + /* attrs[] is returned from this function in + * ac->search_req->op.search.attrs, so it must be static, as + * otherwise the compiler can put it on the stack */ + static const char * const attrs[] = { IS_MAPPED, NULL }; + struct ldb_parse_tree *tree; + + /* Limit search to records with 'IS_MAPPED' present */ + tree = ldb_parse_tree(ac, "(" IS_MAPPED "=*)"); + if (tree == NULL) { + map_oom(ac->module); + return LDB_ERR_OPERATIONS_ERROR; + } + + *req = map_search_base_req(ac, dn, attrs, tree, + ac, map_search_self_callback); + if (*req == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + return LDB_SUCCESS; +} + +static int map_op_local_callback(struct ldb_request *req, + struct ldb_reply *ares) { struct map_context *ac; + int ret; - ac = talloc_get_type(handle->private_data, struct map_context); + ac = talloc_get_type(req->context, struct map_context); - ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req); + if (!ares) { + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); + } + if (ares->error != LDB_SUCCESS) { + return ldb_module_done(ac->req, ares->controls, + ares->response, ares->error); + } - ac->step = MAP_ADD_LOCAL; + if (ares->type != LDB_REPLY_DONE) { + ldb_set_errstring(req->handle->ldb, "Invalid reply type!"); + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); + } - handle->state = LDB_ASYNC_INIT; - handle->status = LDB_SUCCESS; + /* Do the remote request. */ + ret = ldb_next_remote_request(ac->module, ac->remote_req); + if (ret != LDB_SUCCESS) { + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); + } - return ldb_next_request(ac->module, ac->local_req); + return LDB_SUCCESS; } +static int map_op_remote_callback(struct ldb_request *req, + struct ldb_reply *ares) +{ + struct map_context *ac; + + ac = talloc_get_type(req->context, struct map_context); + + if (!ares) { + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); + } + if (ares->error != LDB_SUCCESS) { + return ldb_module_done(ac->req, ares->controls, + ares->response, ares->error); + } + + if (ares->type != LDB_REPLY_DONE) { + ldb_set_errstring(req->handle->ldb, "Invalid reply type!"); + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); + } + + return ldb_module_done(ac->req, ares->controls, + ares->response, ares->error); +} + + +/***************************************************************************** + * ADD operations +*****************************************************************************/ + + /* Add a record. */ int map_add(struct ldb_module *module, struct ldb_request *req) { const struct ldb_message *msg = req->op.add.message; - struct ldb_handle *h; struct map_context *ac; - struct ldb_message *local, *remote; + struct ldb_message *remote_msg; const char *dn; + int ret; /* Do not manipulate our control entries */ if (ldb_dn_is_special(msg->dn)) { @@ -240,141 +371,88 @@ int map_add(struct ldb_module *module, struct ldb_request *req) } /* Prepare context and handle */ - h = map_init_handle(req, module); - if (h == NULL) { + ac = map_init_context(module, req); + if (ac == NULL) { return LDB_ERR_OPERATIONS_ERROR; } - ac = talloc_get_type(h->private_data, struct map_context); - - /* Prepare the local operation */ - ac->local_req = talloc(ac, struct ldb_request); - if (ac->local_req == NULL) { - goto oom; - } - *(ac->local_req) = *req; /* copy the request */ - - ac->local_req->context = NULL; - ac->local_req->callback = NULL; - - /* Prepare the remote operation */ - ac->remote_req = talloc(ac, struct ldb_request); - if (ac->remote_req == NULL) { - goto oom; - } - - *(ac->remote_req) = *req; /* copy the request */ - - ac->remote_req->context = NULL; - ac->remote_req->callback = NULL; /* Prepare the local message */ - local = ldb_msg_new(ac->local_req); - if (local == NULL) { - goto oom; + ac->local_msg = ldb_msg_new(ac); + if (ac->local_msg == NULL) { + map_oom(module); + return LDB_ERR_OPERATIONS_ERROR; } - local->dn = msg->dn; + ac->local_msg->dn = msg->dn; /* Prepare the remote message */ - remote = ldb_msg_new(ac->remote_req); - if (remote == NULL) { - goto oom; + remote_msg = ldb_msg_new(ac); + if (remote_msg == NULL) { + map_oom(module); + return LDB_ERR_OPERATIONS_ERROR; } - remote->dn = ldb_dn_map_local(ac->module, remote, msg->dn); + remote_msg->dn = ldb_dn_map_local(ac->module, remote_msg, msg->dn); /* Split local from remote message */ - ldb_msg_partition(module, local, remote, msg); - ac->local_req->op.add.message = local; - ac->remote_req->op.add.message = remote; + ldb_msg_partition(module, ac->local_msg, remote_msg, msg); + + /* Prepare the remote operation */ + ret = ldb_build_add_req(&ac->remote_req, module->ldb, + ac, remote_msg, + req->controls, + ac, map_op_remote_callback, + req); + if (ret != LDB_SUCCESS) { + return LDB_ERR_OPERATIONS_ERROR; + } - if ((local->num_elements == 0) || (!map_check_local_db(ac->module))) { + if ((ac->local_msg->num_elements == 0) || + ( ! map_check_local_db(ac->module))) { /* No local data or db, just run the remote request */ - talloc_free(ac->local_req); - req->handle = h; /* return our own handle to deal with this call */ - return map_add_do_remote(h); + return ldb_next_remote_request(ac->module, ac->remote_req); } /* Store remote DN in 'IS_MAPPED' */ /* TODO: use GUIDs here instead */ - dn = ldb_dn_alloc_linearized(local, remote->dn); - if (ldb_msg_add_string(local, IS_MAPPED, dn) != 0) { - goto failed; + dn = ldb_dn_alloc_linearized(ac->local_msg, remote_msg->dn); + if (ldb_msg_add_string(ac->local_msg, IS_MAPPED, dn) != 0) { + return LDB_ERR_OPERATIONS_ERROR; } - req->handle = h; /* return our own handle to deal with this call */ - return map_add_do_local(h); - -oom: - map_oom(module); -failed: - talloc_free(h); - return LDB_ERR_OPERATIONS_ERROR; -} - -/* Modify the remote record. */ -int map_modify_do_remote(struct ldb_handle *handle) -{ - struct map_context *ac; - - ac = talloc_get_type(handle->private_data, struct map_context); - - ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->remote_req); - - ac->step = MAP_MODIFY_REMOTE; - - handle->state = LDB_ASYNC_INIT; - handle->status = LDB_SUCCESS; - - return ldb_next_remote_request(ac->module, ac->remote_req); + return map_add_do_local(ac); } -/* Modify the local record. */ -int map_modify_do_local(struct ldb_handle *handle) +/* Add the local record. */ +static int map_add_do_local(struct map_context *ac) { - struct map_context *ac; - struct ldb_message *msg; - char *dn; - - ac = talloc_get_type(handle->private_data, struct map_context); - - if (ac->local_dn == NULL) { - /* No local record present, add it instead */ - msg = discard_const_p(struct ldb_message, ac->local_req->op.mod.message); - - /* Add local 'IS_MAPPED' */ - /* TODO: use GUIDs here instead */ - if (ldb_msg_add_empty(msg, IS_MAPPED, LDB_FLAG_MOD_ADD, NULL) != 0) { - return LDB_ERR_OPERATIONS_ERROR; - } - dn = ldb_dn_alloc_linearized(msg, ac->remote_req->op.mod.message->dn); - if (ldb_msg_add_string(msg, IS_MAPPED, dn) != 0) { - return LDB_ERR_OPERATIONS_ERROR; - } + struct ldb_request *local_req; + int ret; - /* Turn request into 'add' */ - ac->local_req->operation = LDB_ADD; - ac->local_req->op.add.message = msg; - /* TODO: Could I just leave msg in there? I think so, - * but it looks clearer this way. */ + /* Prepare the local operation */ + ret = ldb_build_add_req(&local_req, ac->module->ldb, ac, + ac->local_msg, + ac->req->controls, + ac, + map_op_local_callback, + ac->req); + if (ret != LDB_SUCCESS) { + return LDB_ERR_OPERATIONS_ERROR; } - - ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req); - - ac->step = MAP_MODIFY_LOCAL; - - handle->state = LDB_ASYNC_INIT; - handle->status = LDB_SUCCESS; - - return ldb_next_request(ac->module, ac->local_req); + return ldb_next_request(ac->module, local_req); } +/***************************************************************************** + * MODIFY operations +*****************************************************************************/ + /* Modify a record. */ int map_modify(struct ldb_module *module, struct ldb_request *req) { const struct ldb_message *msg = req->op.mod.message; - struct ldb_handle *h; + struct ldb_request *search_req; + struct ldb_message *remote_msg; struct map_context *ac; - struct ldb_message *local, *remote; + int ret; /* Do not manipulate our control entries */ if (ldb_dn_is_special(msg->dn)) { @@ -395,257 +473,200 @@ int map_modify(struct ldb_module *module, struct ldb_request *req) } /* Prepare context and handle */ - h = map_init_handle(req, module); - if (h == NULL) { + ac = map_init_context(module, req); + if (ac == NULL) { return LDB_ERR_OPERATIONS_ERROR; } - ac = talloc_get_type(h->private_data, struct map_context); - - /* Prepare the local operation */ - ac->local_req = talloc(ac, struct ldb_request); - if (ac->local_req == NULL) { - goto oom; - } - - *(ac->local_req) = *req; /* copy the request */ - - ac->local_req->context = NULL; - ac->local_req->callback = NULL; - - /* Prepare the remote operation */ - ac->remote_req = talloc(ac, struct ldb_request); - if (ac->remote_req == NULL) { - goto oom; - } - - *(ac->remote_req) = *req; /* copy the request */ - - ac->remote_req->context = NULL; - ac->remote_req->callback = NULL; /* Prepare the local message */ - local = ldb_msg_new(ac->local_req); - if (local == NULL) { - goto oom; + ac->local_msg = ldb_msg_new(ac); + if (ac->local_msg == NULL) { + map_oom(module); + return LDB_ERR_OPERATIONS_ERROR; } - local->dn = msg->dn; + ac->local_msg->dn = msg->dn; /* Prepare the remote message */ - remote = ldb_msg_new(ac->remote_req); - if (remote == NULL) { - goto oom; + remote_msg = ldb_msg_new(ac->remote_req); + if (remote_msg == NULL) { + map_oom(module); + return LDB_ERR_OPERATIONS_ERROR; } - remote->dn = ldb_dn_map_local(ac->module, remote, msg->dn); + remote_msg->dn = ldb_dn_map_local(ac->module, remote_msg, msg->dn); /* Split local from remote message */ - ldb_msg_partition(module, local, remote, msg); - ac->local_req->op.mod.message = local; - ac->remote_req->op.mod.message = remote; + ldb_msg_partition(module, ac->local_msg, remote_msg, msg); + + /* Prepare the remote operation */ + ret = ldb_build_mod_req(&ac->remote_req, module->ldb, + ac, remote_msg, + req->controls, + ac, map_op_remote_callback, + req); + if (ret != LDB_SUCCESS) { + return LDB_ERR_OPERATIONS_ERROR; + } - if ((local->num_elements == 0) || (!map_check_local_db(ac->module))) { + if ((ac->local_msg->num_elements == 0) || + ( ! map_check_local_db(ac->module))) { /* No local data or db, just run the remote request */ - talloc_free(ac->local_req); - req->handle = h; /* return our own handle to deal with this call */ - return map_modify_do_remote(h); + return ldb_next_remote_request(ac->module, ac->remote_req); } /* prepare the search operation */ - ac->search_req = map_search_self_req(ac, msg->dn); - if (ac->search_req == NULL) { - goto failed; + ret = map_search_self_req(&search_req, ac, msg->dn); + if (ret != LDB_SUCCESS) { + return LDB_ERR_OPERATIONS_ERROR; } - ac->step = MAP_SEARCH_SELF_MODIFY; - - req->handle = h; /* return our own handle to deal with this call */ - return ldb_next_request(module, ac->search_req); - -oom: - map_oom(module); -failed: - talloc_free(h); - return LDB_ERR_OPERATIONS_ERROR; -} - -/* Delete the remote record. */ -int map_delete_do_remote(struct ldb_handle *handle) -{ - struct map_context *ac; - - ac = talloc_get_type(handle->private_data, struct map_context); - - ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->remote_req); - - ac->step = MAP_DELETE_REMOTE; - - handle->state = LDB_ASYNC_INIT; - handle->status = LDB_SUCCESS; - - return ldb_next_remote_request(ac->module, ac->remote_req); + return ldb_next_request(module, search_req); } -/* Delete the local record. */ -int map_delete_do_local(struct ldb_handle *handle) +/* Modify the local record. */ +static int map_modify_do_local(struct map_context *ac) { - struct map_context *ac; - - ac = talloc_get_type(handle->private_data, struct map_context); + struct ldb_request *local_req; + char *dn; + int ret; - /* No local record, continue remotely */ if (ac->local_dn == NULL) { - return map_delete_do_remote(handle); - } - - ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req); - - ac->step = MAP_DELETE_LOCAL; + /* No local record present, add it instead */ + /* Add local 'IS_MAPPED' */ + /* TODO: use GUIDs here instead */ + if (ldb_msg_add_empty(ac->local_msg, IS_MAPPED, + LDB_FLAG_MOD_ADD, NULL) != 0) { + return LDB_ERR_OPERATIONS_ERROR; + } + dn = ldb_dn_alloc_linearized(ac->local_msg, + ac->remote_req->op.mod.message->dn); + if (ldb_msg_add_string(ac->local_msg, IS_MAPPED, dn) != 0) { + return LDB_ERR_OPERATIONS_ERROR; + } - handle->state = LDB_ASYNC_INIT; - handle->status = LDB_SUCCESS; + /* Prepare the local operation */ + ret = ldb_build_add_req(&local_req, ac->module->ldb, ac, + ac->local_msg, + ac->req->controls, + ac, + map_op_local_callback, + ac->req); + if (ret != LDB_SUCCESS) { + return LDB_ERR_OPERATIONS_ERROR; + } + } else { + /* Prepare the local operation */ + ret = ldb_build_mod_req(&local_req, ac->module->ldb, ac, + ac->local_msg, + ac->req->controls, + ac, + map_op_local_callback, + ac->req); + if (ret != LDB_SUCCESS) { + return LDB_ERR_OPERATIONS_ERROR; + } + } - return ldb_next_request(ac->module, ac->local_req); + return ldb_next_request(ac->module, local_req); } +/***************************************************************************** + * DELETE operations +*****************************************************************************/ + /* Delete a record. */ int map_delete(struct ldb_module *module, struct ldb_request *req) { - struct ldb_handle *h; + struct ldb_request *search_req; struct map_context *ac; + int ret; /* Do not manipulate our control entries */ if (ldb_dn_is_special(req->op.del.dn)) { return ldb_next_request(module, req); } - /* No mapping requested (perhaps no DN mapping specified), skip to next module */ + /* No mapping requested (perhaps no DN mapping specified). + * Skip to next module */ if (!ldb_dn_check_local(module, req->op.del.dn)) { return ldb_next_request(module, req); } /* Prepare context and handle */ - h = map_init_handle(req, module); - if (h == NULL) { + ac = map_init_context(module, req); + if (ac == NULL) { return LDB_ERR_OPERATIONS_ERROR; } - ac = talloc_get_type(h->private_data, struct map_context); - - /* Prepare the local operation */ - ac->local_req = talloc(ac, struct ldb_request); - if (ac->local_req == NULL) { - goto oom; - } - - *(ac->local_req) = *req; /* copy the request */ - ac->local_req->op.del.dn = req->op.del.dn; - - ac->local_req->context = NULL; - ac->local_req->callback = NULL; /* Prepare the remote operation */ - ac->remote_req = talloc(ac, struct ldb_request); - if (ac->remote_req == NULL) { - goto oom; + ret = ldb_build_del_req(&ac->remote_req, module->ldb, ac, + ldb_dn_map_local(module, ac, req->op.del.dn), + req->controls, + ac, + map_op_remote_callback, + req); + if (ret != LDB_SUCCESS) { + return LDB_ERR_OPERATIONS_ERROR; } - *(ac->remote_req) = *req; /* copy the request */ - ac->remote_req->op.del.dn = ldb_dn_map_local(module, ac->remote_req, req->op.del.dn); - /* No local db, just run the remote request */ if (!map_check_local_db(ac->module)) { - req->handle = h; /* return our own handle to deal with this call */ - return map_delete_do_remote(h); + /* Do the remote request. */ + return ldb_next_remote_request(ac->module, ac->remote_req); } - ac->remote_req->context = NULL; - ac->remote_req->callback = NULL; - /* Prepare the search operation */ - ac->search_req = map_search_self_req(ac, req->op.del.dn); - if (ac->search_req == NULL) { - goto failed; + ret = map_search_self_req(&search_req, ac, req->op.del.dn); + if (ret != LDB_SUCCESS) { + map_oom(module); + return LDB_ERR_OPERATIONS_ERROR; } - req->handle = h; /* return our own handle to deal with this call */ - - ac->step = MAP_SEARCH_SELF_DELETE; - - return ldb_next_request(module, ac->search_req); - -oom: - map_oom(module); -failed: - talloc_free(h); - return LDB_ERR_OPERATIONS_ERROR; + return ldb_next_request(module, search_req); } -/* Rename the remote record. */ -int map_rename_do_remote(struct ldb_handle *handle) -{ - struct map_context *ac; - - ac = talloc_get_type(handle->private_data, struct map_context); - - ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->remote_req); - - ac->step = MAP_RENAME_REMOTE; - - handle->state = LDB_ASYNC_INIT; - handle->status = LDB_SUCCESS; - - return ldb_next_remote_request(ac->module, ac->remote_req); -} - -/* Update the local 'IS_MAPPED' attribute. */ -int map_rename_do_fixup(struct ldb_handle *handle) -{ - struct map_context *ac; - - ac = talloc_get_type(handle->private_data, struct map_context); - - ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->down_req); - - ac->step = MAP_RENAME_FIXUP; - - handle->state = LDB_ASYNC_INIT; - handle->status = LDB_SUCCESS; - - return ldb_next_request(ac->module, ac->down_req); -} - -/* Rename the local record. */ -int map_rename_do_local(struct ldb_handle *handle) +/* Delete the local record. */ +static int map_delete_do_local(struct map_context *ac) { - struct map_context *ac; - - ac = talloc_get_type(handle->private_data, struct map_context); + struct ldb_request *local_req; + int ret; /* No local record, continue remotely */ if (ac->local_dn == NULL) { - return map_rename_do_remote(handle); + /* Do the remote request. */ + return ldb_next_remote_request(ac->module, ac->remote_req); } - ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req); - - ac->step = MAP_RENAME_LOCAL; - - handle->state = LDB_ASYNC_INIT; - handle->status = LDB_SUCCESS; - - return ldb_next_request(ac->module, ac->local_req); + /* Prepare the local operation */ + ret = ldb_build_del_req(&local_req, ac->module->ldb, ac, + ac->req->op.del.dn, + ac->req->controls, + ac, + map_op_local_callback, + ac->req); + if (ret != LDB_SUCCESS) { + return LDB_ERR_OPERATIONS_ERROR; + } + return ldb_next_request(ac->module, local_req); } +/***************************************************************************** + * RENAME operations +*****************************************************************************/ + /* Rename a record. */ int map_rename(struct ldb_module *module, struct ldb_request *req) { - struct ldb_handle *h; + struct ldb_request *search_req; struct map_context *ac; + int ret; /* Do not manipulate our control entries */ if (ldb_dn_is_special(req->op.rename.olddn)) { return ldb_next_request(module, req); } - /* No mapping requested (perhaps no DN mapping specified), skip to next module */ + /* No mapping requested (perhaps no DN mapping specified). + * Skip to next module */ if ((!ldb_dn_check_local(module, req->op.rename.olddn)) && (!ldb_dn_check_local(module, req->op.rename.newdn))) { return ldb_next_request(module, req); @@ -658,66 +679,113 @@ int map_rename(struct ldb_module *module, struct ldb_request *req) } /* Prepare context and handle */ - h = map_init_handle(req, module); - if (h == NULL) { + ac = map_init_context(module, req); + if (ac == NULL) { return LDB_ERR_OPERATIONS_ERROR; } - ac = talloc_get_type(h->private_data, struct map_context); - /* Prepare the local operation */ - ac->local_req = talloc(ac, struct ldb_request); - if (ac->local_req == NULL) { - goto oom; + /* Prepare the remote operation */ + ret = ldb_build_rename_req(&ac->remote_req, module->ldb, ac, + ldb_dn_map_local(module, ac, req->op.rename.olddn), + ldb_dn_map_local(module, ac, req->op.rename.newdn), + req->controls, + ac, map_op_remote_callback, + req); + if (ret != LDB_SUCCESS) { + return LDB_ERR_OPERATIONS_ERROR; } - *(ac->local_req) = *req; /* copy the request */ - ac->local_req->op.rename.olddn = req->op.rename.olddn; - ac->local_req->op.rename.newdn = req->op.rename.newdn; + /* No local db, just run the remote request */ + if (!map_check_local_db(ac->module)) { + /* Do the remote request. */ + return ldb_next_remote_request(ac->module, ac->remote_req); + } - ac->local_req->context = NULL; - ac->local_req->callback = NULL; + /* Prepare the search operation */ + ret = map_search_self_req(&search_req, ac, req->op.rename.olddn); + if (ret != LDB_SUCCESS) { + map_oom(module); + return LDB_ERR_OPERATIONS_ERROR; + } - /* Prepare the remote operation */ - ac->remote_req = talloc(ac, struct ldb_request); - if (ac->remote_req == NULL) { - goto oom; + return ldb_next_request(module, search_req); +} + +/* Rename the local record. */ +static int map_rename_do_local(struct map_context *ac) +{ + struct ldb_request *local_req; + int ret; + + /* No local record, continue remotely */ + if (ac->local_dn == NULL) { + /* Do the remote request. */ + return ldb_next_remote_request(ac->module, ac->remote_req); } - *(ac->remote_req) = *req; /* copy the request */ - ac->remote_req->op.rename.olddn = ldb_dn_map_local(module, ac->remote_req, req->op.rename.olddn); - ac->remote_req->op.rename.newdn = ldb_dn_map_local(module, ac->remote_req, req->op.rename.newdn); + /* Prepare the local operation */ + ret = ldb_build_rename_req(&local_req, ac->module->ldb, ac, + ac->req->op.rename.olddn, + ac->req->op.rename.newdn, + ac->req->controls, + ac, + map_rename_local_callback, + ac->req); + if (ret != LDB_SUCCESS) { + return LDB_ERR_OPERATIONS_ERROR; + } - ac->remote_req->context = NULL; - ac->remote_req->callback = NULL; + return ldb_next_request(ac->module, local_req); +} - /* No local db, just run the remote request */ - if (!map_check_local_db(ac->module)) { - req->handle = h; /* return our own handle to deal with this call */ - return map_rename_do_remote(h); +static int map_rename_local_callback(struct ldb_request *req, + struct ldb_reply *ares) +{ + struct map_context *ac; + int ret; + + ac = talloc_get_type(req->context, struct map_context); + + if (!ares) { + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); + } + if (ares->error != LDB_SUCCESS) { + return ldb_module_done(ac->req, ares->controls, + ares->response, ares->error); } - /* Prepare the fixup operation */ - /* TODO: use GUIDs here instead -- or skip it when GUIDs are used. */ - ac->down_req = map_build_fixup_req(ac, req->op.rename.newdn, ac->remote_req->op.rename.newdn); - if (ac->down_req == NULL) { - goto failed; + if (ares->type != LDB_REPLY_DONE) { + ldb_set_errstring(req->handle->ldb, "Invalid reply type!"); + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); } - /* Prepare the search operation */ - ac->search_req = map_search_self_req(ac, req->op.rename.olddn); - if (ac->search_req == NULL) { - goto failed; + /* proceed with next step */ + ret = map_rename_do_fixup(ac); + if (ret != LDB_SUCCESS) { + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); } - req->handle = h; /* return our own handle to deal with this call */ + return LDB_SUCCESS; +} - ac->step = MAP_SEARCH_SELF_RENAME; +/* Update the local 'IS_MAPPED' attribute. */ +static int map_rename_do_fixup(struct map_context *ac) +{ + struct ldb_request *local_req; - return ldb_next_request(module, ac->search_req); + /* Prepare the fixup operation */ + /* TODO: use GUIDs here instead -- or skip it when GUIDs are used. */ + local_req = map_build_fixup_req(ac, + ac->req->op.rename.newdn, + ac->remote_req->op.rename.newdn, + ac, + map_op_local_callback); + if (local_req == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } -oom: - map_oom(module); -failed: - talloc_free(h); - return LDB_ERR_OPERATIONS_ERROR; + return ldb_next_request(ac->module, local_req); } diff --git a/source4/lib/ldb/ldb_map/ldb_map_outbound.c b/source4/lib/ldb/ldb_map/ldb_map_outbound.c index fbc097f313..5f524a8be3 100644 --- a/source4/lib/ldb/ldb_map/ldb_map_outbound.c +++ b/source4/lib/ldb/ldb_map/ldb_map_outbound.c @@ -4,6 +4,7 @@ Copyright (C) Jelmer Vernooij 2005 Copyright (C) Martin Kuehl <mkhl@samba.org> 2006 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006 + Copyright (C) Simo Sorce <idra@samba.org> 2008 ** NOTE! The following LGPL license applies to the ldb ** library. This does NOT imply that all of Samba is released @@ -905,7 +906,11 @@ static int map_subtree_collect_remote(struct ldb_module *module, void *mem_ctx, /* Split subtrees that query attributes in the local partition from * those that query the remote partition. */ -static int ldb_parse_tree_partition(struct ldb_module *module, void *local_ctx, void *remote_ctx, struct ldb_parse_tree **local_tree, struct ldb_parse_tree **remote_tree, const struct ldb_parse_tree *tree) +static int ldb_parse_tree_partition(struct ldb_module *module, + void *mem_ctx, + struct ldb_parse_tree **local_tree, + struct ldb_parse_tree **remote_tree, + const struct ldb_parse_tree *tree) { int ret; @@ -918,13 +923,13 @@ static int ldb_parse_tree_partition(struct ldb_module *module, void *local_ctx, } /* Generate local tree */ - ret = map_subtree_select_local(module, local_ctx, local_tree, tree); + ret = map_subtree_select_local(module, mem_ctx, local_tree, tree); if (ret) { return ret; } /* Generate remote tree */ - ret = map_subtree_collect_remote(module, remote_ctx, remote_tree, tree); + ret = map_subtree_collect_remote(module, mem_ctx, remote_tree, tree); if (ret) { talloc_free(*local_tree); return ret; @@ -1008,24 +1013,46 @@ oom: /* Outbound requests: search * ========================= */ -/* Pass a merged search result up the callback chain. */ -int map_up_callback(struct ldb_context *ldb, const struct ldb_request *req, struct ldb_reply *ares) +static int map_remote_search_callback(struct ldb_request *req, + struct ldb_reply *ares); +static int map_local_merge_callback(struct ldb_request *req, + struct ldb_reply *ares); +static int map_search_local(struct map_context *ac); + +static int map_save_entry(struct map_context *ac, struct ldb_reply *ares) { - int i; + struct map_reply *mr; - /* No callback registered, stop */ - if (req->callback == NULL) { - return LDB_SUCCESS; + mr = talloc_zero(ac, struct map_reply); + if (mr == NULL) { + map_oom(ac->module); + return LDB_ERR_OPERATIONS_ERROR; } - - /* Only records need special treatment */ - if (ares->type != LDB_REPLY_ENTRY) { - return req->callback(ldb, req->context, ares); + mr->remote = talloc_steal(mr, ares); + if (ac->r_current) { + ac->r_current->next = mr; + } else { + /* first entry */ + ac->r_list = mr; } + ac->r_current = mr; + + return LDB_SUCCESS; +} + +/* Pass a merged search result up the callback chain. */ +int map_return_entry(struct map_context *ac, struct ldb_reply *ares) +{ + struct ldb_message_element *el; + const char * const *attrs; + int i; /* Merged result doesn't match original query, skip */ - if (!ldb_match_msg(ldb, ares->message, req->op.search.tree, req->op.search.base, req->op.search.scope)) { - ldb_debug(ldb, LDB_DEBUG_TRACE, "ldb_map: " + if (!ldb_match_msg(ac->module->ldb, ares->message, + ac->req->op.search.tree, + ac->req->op.search.base, + ac->req->op.search.scope)) { + ldb_debug(ac->module->ldb, LDB_DEBUG_TRACE, "ldb_map: " "Skipping record '%s': " "doesn't match original search\n", ldb_dn_get_linearized(ares->message->dn)); @@ -1033,10 +1060,16 @@ int map_up_callback(struct ldb_context *ldb, const struct ldb_request *req, stru } /* Limit result to requested attrs */ - if ((req->op.search.attrs) && (!ldb_attr_in_list(req->op.search.attrs, "*"))) { - for (i = 0; i < ares->message->num_elements; ) { - struct ldb_message_element *el = &ares->message->elements[i]; - if (!ldb_attr_in_list(req->op.search.attrs, el->name)) { + if (ac->req->op.search.attrs && + (! ldb_attr_in_list(ac->req->op.search.attrs, "*"))) { + + attrs = ac->req->op.search.attrs; + i = 0; + + while (i < ares->message->num_elements) { + + el = &ares->message->elements[i]; + if ( ! ldb_attr_in_list(attrs, el->name)) { ldb_msg_remove_element(ares->message, el); } else { i++; @@ -1044,129 +1077,16 @@ int map_up_callback(struct ldb_context *ldb, const struct ldb_request *req, stru } } - return req->callback(ldb, req->context, ares); -} - -/* Merge the remote and local parts of a search result. */ -int map_local_merge_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) -{ - struct map_search_context *sc; - int ret; - - if (context == NULL || ares == NULL) { - ldb_set_errstring(ldb, talloc_asprintf(ldb, "ldb_map: " - "NULL Context or Result in `map_local_merge_callback`")); - return LDB_ERR_OPERATIONS_ERROR; - } - - sc = talloc_get_type(context, struct map_search_context); - - switch (ares->type) { - case LDB_REPLY_ENTRY: - /* We have already found a local record */ - if (sc->local_res) { - ldb_set_errstring(ldb, talloc_asprintf(ldb, "ldb_map: " - "Too many results to base search for local entry")); - talloc_free(ares); - return LDB_ERR_OPERATIONS_ERROR; - } - - /* Store local result */ - sc->local_res = ares; - - /* Merge remote into local message */ - ret = ldb_msg_merge_local(sc->ac->module, ares->message, sc->remote_res->message); - if (ret) { - talloc_free(ares); - return LDB_ERR_OPERATIONS_ERROR; - } - - return map_up_callback(ldb, sc->ac->orig_req, ares); - - case LDB_REPLY_DONE: - /* No local record found, continue with remote record */ - if (sc->local_res == NULL) { - return map_up_callback(ldb, sc->ac->orig_req, sc->remote_res); - } - return LDB_SUCCESS; - - default: - ldb_set_errstring(ldb, talloc_asprintf(ldb, "ldb_map: " - "Unexpected result type in base search for local entry")); - talloc_free(ares); - return LDB_ERR_OPERATIONS_ERROR; - } -} - -/* Search the local part of a remote search result. */ -int map_remote_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) -{ - struct map_context *ac; - struct map_search_context *sc; - struct ldb_request *req; - int ret; - - if (context == NULL || ares == NULL) { - ldb_set_errstring(ldb, talloc_asprintf(ldb, "ldb_map: " - "NULL Context or Result in `map_remote_search_callback`")); - return LDB_ERR_OPERATIONS_ERROR; - } - - ac = talloc_get_type(context, struct map_context); - - /* It's not a record, stop searching */ - if (ares->type != LDB_REPLY_ENTRY) { - return map_up_callback(ldb, ac->orig_req, ares); - } - - /* Map result record into a local message */ - ret = map_reply_remote(ac, ares); - if (ret) { - talloc_free(ares); - return LDB_ERR_OPERATIONS_ERROR; - } - - /* There is no local db, stop searching */ - if (!map_check_local_db(ac->module)) { - return map_up_callback(ldb, ac->orig_req, ares); - } - - /* Prepare local search context */ - sc = map_init_search_context(ac, ares); - if (sc == NULL) { - talloc_free(ares); - return LDB_ERR_OPERATIONS_ERROR; - } - - /* Prepare local search request */ - /* TODO: use GUIDs here instead? */ - - ac->search_reqs = talloc_realloc(ac, ac->search_reqs, struct ldb_request *, ac->num_searches + 2); - if (ac->search_reqs == NULL) { - talloc_free(ares); - return LDB_ERR_OPERATIONS_ERROR; - } - - ac->search_reqs[ac->num_searches] - = req = map_search_base_req(ac, ares->message->dn, - NULL, NULL, sc, map_local_merge_callback); - if (req == NULL) { - talloc_free(sc); - talloc_free(ares); - return LDB_ERR_OPERATIONS_ERROR; - } - ac->num_searches++; - ac->search_reqs[ac->num_searches] = NULL; - - return ldb_next_request(ac->module, req); + return ldb_module_send_entry(ac->req, ares->message); } /* Search a record. */ int map_search(struct ldb_module *module, struct ldb_request *req) { - struct ldb_handle *h; + struct ldb_parse_tree *remote_tree; + struct ldb_parse_tree *local_tree; + struct ldb_request *remote_req; struct map_context *ac; - struct ldb_parse_tree *local_tree, *remote_tree; int ret; const char *wildcard[] = { "*", NULL }; @@ -1176,8 +1096,9 @@ int map_search(struct ldb_module *module, struct ldb_request *req) return ldb_next_request(module, req); /* Do not manipulate our control entries */ - if (ldb_dn_is_special(req->op.search.base)) + if (ldb_dn_is_special(req->op.search.base)) { return ldb_next_request(module, req); + } /* No mapping requested, skip to next module */ if ((req->op.search.base) && (!ldb_dn_check_local(module, req->op.search.base))) { @@ -1188,32 +1109,10 @@ int map_search(struct ldb_module *module, struct ldb_request *req) * targetting when there is no search base? */ /* Prepare context and handle */ - h = map_init_handle(req, module); - if (h == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } - ac = talloc_get_type(h->private_data, struct map_context); - - ac->search_reqs = talloc_array(ac, struct ldb_request *, 2); - if (ac->search_reqs == NULL) { - talloc_free(h); + ac = map_init_context(module, req); + if (ac == NULL) { return LDB_ERR_OPERATIONS_ERROR; } - ac->num_searches = 1; - ac->search_reqs[1] = NULL; - - /* Prepare the remote operation */ - ac->search_reqs[0] = talloc(ac, struct ldb_request); - if (ac->search_reqs[0] == NULL) { - goto oom; - } - - *(ac->search_reqs[0]) = *req; /* copy the request */ - - ac->search_reqs[0]->handle = h; /* return our own handle to deal with this call */ - - ac->search_reqs[0]->context = ac; - ac->search_reqs[0]->callback = map_remote_search_callback; /* It is easier to deal with the two different ways of * expressing the wildcard in the same codepath */ @@ -1226,17 +1125,15 @@ int map_search(struct ldb_module *module, struct ldb_request *req) ret = map_attrs_collect_and_partition(module, ac, attrs, req->op.search.tree); if (ret) { - goto failed; + return LDB_ERR_OPERATIONS_ERROR; } - ac->search_reqs[0]->op.search.attrs = ac->remote_attrs; - /* Split local from remote tree */ - ret = ldb_parse_tree_partition(module, ac, ac->search_reqs[0], - &local_tree, &remote_tree, + ret = ldb_parse_tree_partition(module, ac, + &local_tree, &remote_tree, req->op.search.tree); if (ret) { - goto failed; + return LDB_ERR_OPERATIONS_ERROR; } if (((local_tree != NULL) && (remote_tree != NULL)) && @@ -1251,7 +1148,7 @@ int map_search(struct ldb_module *module, struct ldb_request *req) local_tree = talloc_zero(ac, struct ldb_parse_tree); if (local_tree == NULL) { map_oom(ac->module); - goto failed; + return LDB_ERR_OPERATIONS_ERROR; } local_tree->operation = LDB_OP_PRESENT; @@ -1259,31 +1156,209 @@ int map_search(struct ldb_module *module, struct ldb_request *req) } if (remote_tree == NULL) { /* Construct default remote parse tree */ - remote_tree = ldb_parse_tree(ac->search_reqs[0], NULL); + remote_tree = ldb_parse_tree(ac, NULL); if (remote_tree == NULL) { - goto failed; + return LDB_ERR_OPERATIONS_ERROR; } } ac->local_tree = local_tree; - ac->search_reqs[0]->op.search.tree = remote_tree; - ldb_set_timeout_from_prev_req(module->ldb, req, ac->search_reqs[0]); + /* Prepare the remote operation */ + ret = ldb_build_search_req_ex(&remote_req, module->ldb, ac, + req->op.search.base, + req->op.search.scope, + remote_tree, + ac->remote_attrs, + req->controls, + ac, map_remote_search_callback, + req); + if (ret != LDB_SUCCESS) { + return LDB_ERR_OPERATIONS_ERROR; + } - h->state = LDB_ASYNC_INIT; - h->status = LDB_SUCCESS; + return ldb_next_remote_request(module, remote_req); +} + +/* Now, search the local part of a remote search result. */ +static int map_remote_search_callback(struct ldb_request *req, + struct ldb_reply *ares) +{ + struct map_context *ac; + int ret; - ac->step = MAP_SEARCH_REMOTE; + ac = talloc_get_type(req->context, struct map_context); - ret = ldb_next_remote_request(module, ac->search_reqs[0]); - if (ret == LDB_SUCCESS) { - req->handle = h; + if (!ares) { + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); + } + if (ares->error != LDB_SUCCESS) { + return ldb_module_done(ac->req, ares->controls, + ares->response, ares->error); } - return ret; -oom: - map_oom(module); -failed: - talloc_free(h); - return LDB_ERR_OPERATIONS_ERROR; + switch (ares->type) { + case LDB_REPLY_REFERRAL: + + /* ignore referrals */ + talloc_free(ares); + return LDB_SUCCESS; + + case LDB_REPLY_ENTRY: + + /* Map result record into a local message */ + ret = map_reply_remote(ac, ares); + if (ret) { + talloc_free(ares); + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); + } + + /* if we have no local db, then we can just return the reply to + * the upper layer, otherwise we must save it and process it + * when all replies ahve been gathered */ + if ( ! map_check_local_db(ac->module)) { + ret = map_return_entry(ac, ares); + } else { + ret = map_save_entry(ac,ares); + } + + if (ret != LDB_SUCCESS) { + talloc_free(ares); + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); + } + break; + + case LDB_REPLY_DONE: + + if ( ! map_check_local_db(ac->module)) { + return ldb_module_done(ac->req, ares->controls, + ares->response, LDB_SUCCESS); + } + + talloc_free(ares); + + /* reset the pointer to the start of the list */ + ac->r_current = ac->r_list; + + /* no entry just return */ + if (ac->r_current == NULL) { + return ldb_module_done(ac->req, ares->controls, + ares->response, LDB_SUCCESS); + } + + ret = map_search_local(ac); + if (ret != LDB_SUCCESS) { + return ldb_module_done(ac->req, NULL, NULL, ret); + } + } + + return LDB_SUCCESS; +} + +static int map_search_local(struct map_context *ac) +{ + struct ldb_request *search_req; + + if (ac->r_current == NULL || ac->r_current->remote == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + /* Prepare local search request */ + /* TODO: use GUIDs here instead? */ + search_req = map_search_base_req(ac, + ac->r_current->remote->message->dn, + NULL, NULL, + ac, map_local_merge_callback); + if (search_req == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + return ldb_next_request(ac->module, search_req); +} + +/* Merge the remote and local parts of a search result. */ +int map_local_merge_callback(struct ldb_request *req, struct ldb_reply *ares) +{ + struct map_context *ac; + int ret; + + ac = talloc_get_type(req->context, struct map_context); + + if (!ares) { + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); + } + if (ares->error != LDB_SUCCESS) { + return ldb_module_done(ac->req, ares->controls, + ares->response, ares->error); + } + + switch (ares->type) { + case LDB_REPLY_ENTRY: + /* We have already found a local record */ + if (ac->r_current->local) { + talloc_free(ares); + ldb_set_errstring(ac->module->ldb, "ldb_map: Too many results!"); + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); + } + + /* Store local result */ + ac->r_current->local = talloc_steal(ac->r_current, ares); + + break; + + case LDB_REPLY_REFERRAL: + /* ignore referrals */ + talloc_free(ares); + break; + + case LDB_REPLY_DONE: + talloc_free(ares); + + /* No local record found, map and send remote record */ + if (ac->r_current->local != NULL) { + /* Merge remote into local message */ + ret = ldb_msg_merge_local(ac->module, + ac->r_current->local->message, + ac->r_current->remote->message); + if (ret == LDB_SUCCESS) { + ret = map_return_entry(ac, ac->r_current->local); + } + if (ret != LDB_SUCCESS) { + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); + } + } else { + ret = map_return_entry(ac, ac->r_current->remote); + if (ret != LDB_SUCCESS) { + return ldb_module_done(ac->req, + NULL, NULL, ret); + } + } + + if (ac->r_current->next != NULL) { + ac->r_current = ac->r_current->next; + if (ac->r_current->remote->type == LDB_REPLY_ENTRY) { + ret = map_search_local(ac); + if (ret != LDB_SUCCESS) { + return ldb_module_done(ac->req, + NULL, NULL, ret); + } + break; + } + } + + /* ok we are done with all search, finally it is time to + * finish operations for this module */ + return ldb_module_done(ac->req, + ac->r_current->remote->controls, + ac->r_current->remote->response, + ac->r_current->remote->error); + } + + return LDB_SUCCESS; } diff --git a/source4/lib/ldb/ldb_map/ldb_map_private.h b/source4/lib/ldb/ldb_map/ldb_map_private.h index 58a9f2704e..5522125344 100644 --- a/source4/lib/ldb/ldb_map/ldb_map_private.h +++ b/source4/lib/ldb/ldb_map/ldb_map_private.h @@ -3,7 +3,7 @@ #define map_oom(module) ldb_set_errstring(module->ldb, talloc_asprintf(module, "Out of Memory")); /* The type of search callback functions */ -typedef int (*ldb_search_callback)(struct ldb_context *, void *, struct ldb_reply *); +typedef int (*ldb_map_callback_t)(struct ldb_request *, struct ldb_reply *); /* The special DN from which the local and remote base DNs are fetched */ #define MAP_DN_NAME "@MAP" @@ -13,25 +13,17 @@ typedef int (*ldb_search_callback)(struct ldb_context *, void *, struct ldb_repl /* Private data structures * ======================= */ +struct map_reply { + struct map_reply *next; + struct ldb_reply *remote; + struct ldb_reply *local; +}; + /* Context data for mapped requests */ struct map_context { - enum map_step { - MAP_SEARCH_REMOTE, - MAP_ADD_REMOTE, - MAP_ADD_LOCAL, - MAP_SEARCH_SELF_MODIFY, - MAP_MODIFY_REMOTE, - MAP_MODIFY_LOCAL, - MAP_SEARCH_SELF_DELETE, - MAP_DELETE_REMOTE, - MAP_DELETE_LOCAL, - MAP_SEARCH_SELF_RENAME, - MAP_RENAME_REMOTE, - MAP_RENAME_FIXUP, - MAP_RENAME_LOCAL - } step; struct ldb_module *module; + struct ldb_request *req; struct ldb_dn *local_dn; const struct ldb_parse_tree *local_tree; @@ -39,32 +31,20 @@ struct map_context { const char * const *remote_attrs; const char * const *all_attrs; - struct ldb_request *orig_req; - struct ldb_request *local_req; + struct ldb_message *local_msg; struct ldb_request *remote_req; - struct ldb_request *down_req; - struct ldb_request *search_req; - - /* for search, we may have a lot of contexts */ - int num_searches; - struct ldb_request **search_reqs; -}; -/* Context data for mapped search requests */ -struct map_search_context { - struct map_context *ac; - struct ldb_reply *local_res; - struct ldb_reply *remote_res; + struct map_reply *r_list; + struct map_reply *r_current; }; - /* Common operations * ================= */ /* The following definitions come from lib/ldb/modules/ldb_map.c */ const struct ldb_map_context *map_get_context(struct ldb_module *module); -struct map_search_context *map_init_search_context(struct map_context *ac, struct ldb_reply *ares); -struct ldb_handle *map_init_handle(struct ldb_request *req, struct ldb_module *module); +struct map_context *map_init_context(struct ldb_module *module, + struct ldb_request *req); int ldb_next_remote_request(struct ldb_module *module, struct ldb_request *request); @@ -86,25 +66,23 @@ struct ldb_dn *ldb_dn_map_local(struct ldb_module *module, void *mem_ctx, struct struct ldb_dn *ldb_dn_map_remote(struct ldb_module *module, void *mem_ctx, struct ldb_dn *dn); struct ldb_dn *ldb_dn_map_rebase_remote(struct ldb_module *module, void *mem_ctx, struct ldb_dn *dn); -struct ldb_request *map_search_base_req(struct map_context *ac, struct ldb_dn *dn, const char * const *attrs, const struct ldb_parse_tree *tree, void *context, ldb_search_callback callback); -struct ldb_request *map_search_self_req(struct map_context *ac, struct ldb_dn *dn); -struct ldb_request *map_build_fixup_req(struct map_context *ac, struct ldb_dn *olddn, struct ldb_dn *newdn); - -int map_subtree_collect_remote_simple(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree, const struct ldb_map_attribute *map); - -/* LDB Requests - * ============ */ - -/* The following definitions come from lib/ldb/modules/ldb_map_inbound.c */ -int map_add_do_remote(struct ldb_handle *handle); -int map_add_do_local(struct ldb_handle *handle); - -int map_modify_do_remote(struct ldb_handle *handle); -int map_modify_do_local(struct ldb_handle *handle); - -int map_delete_do_remote(struct ldb_handle *handle); -int map_delete_do_local(struct ldb_handle *handle); - -int map_rename_do_remote(struct ldb_handle *handle); -int map_rename_do_fixup(struct ldb_handle *handle); -int map_rename_do_local(struct ldb_handle *handle); +struct ldb_request *map_search_base_req(struct map_context *ac, + struct ldb_dn *dn, + const char * const *attrs, + const struct ldb_parse_tree *tree, + void *context, + ldb_map_callback_t callback); +struct ldb_request *map_build_fixup_req(struct map_context *ac, + struct ldb_dn *olddn, + struct ldb_dn *newdn, + void *context, + ldb_map_callback_t callback); +int map_subtree_collect_remote_simple(struct ldb_module *module, void *mem_ctx, + struct ldb_parse_tree **new, + const struct ldb_parse_tree *tree, + const struct ldb_map_attribute *map); +int map_return_fatal_error(struct ldb_request *req, + struct ldb_reply *ares); +int map_return_normal_error(struct ldb_request *req, + struct ldb_reply *ares, + int error); diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index a0e63c8da1..be99c29d1e 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -44,51 +44,14 @@ struct lsqlite3_private { struct lsql_context { struct ldb_module *module; + struct ldb_request *req; /* search stuff */ long long current_eid; const char * const * attrs; struct ldb_reply *ares; - - /* async stuff */ - void *context; - int (*callback)(struct ldb_context *, void *, struct ldb_reply *); }; -static struct ldb_handle *init_handle(struct lsqlite3_private *lsqlite3, - struct ldb_module *module, - struct ldb_request *req) -{ - struct lsql_context *ac; - struct ldb_handle *h; - - h = talloc_zero(lsqlite3, struct ldb_handle); - if (h == NULL) { - ldb_set_errstring(module->ldb, "Out of Memory"); - return NULL; - } - - h->module = module; - - ac = talloc(h, struct lsql_context); - if (ac == NULL) { - ldb_set_errstring(module->ldb, "Out of Memory"); - talloc_free(h); - return NULL; - } - - h->private_data = (void *)ac; - - h->state = LDB_ASYNC_INIT; - h->status = LDB_SUCCESS; - - ac->module = module; - ac->context = req->context; - ac->callback = req->callback; - - return h; -} - /* * Macros used throughout */ @@ -835,11 +798,6 @@ int lsql_search(struct ldb_module *module, struct ldb_request *req) char *query = NULL; int ret; - req->handle = init_handle(lsqlite3, module, req); - if (req->handle == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } - lsql_ac = talloc_get_type(req->handle->private_data, struct lsql_context); if ((( ! ldb_dn_is_valid(req->op.search.base)) || ldb_dn_is_null(req->op.search.base)) && @@ -1013,10 +971,6 @@ static int lsql_add(struct ldb_module *module, struct ldb_request *req) int i; int ret = LDB_SUCCESS; - req->handle = init_handle(lsqlite3, module, req); - if (req->handle == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } lsql_ac = talloc_get_type(req->handle->private_data, struct lsql_context); req->handle->state = LDB_ASYNC_DONE; req->handle->status = LDB_SUCCESS; @@ -1143,10 +1097,6 @@ static int lsql_modify(struct ldb_module *module, struct ldb_request *req) int i; int ret = LDB_SUCCESS; - req->handle = init_handle(lsqlite3, module, req); - if (req->handle == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } lsql_ac = talloc_get_type(req->handle->private_data, struct lsql_context); req->handle->state = LDB_ASYNC_DONE; req->handle->status = LDB_SUCCESS; @@ -1329,10 +1279,6 @@ static int lsql_delete(struct ldb_module *module, struct ldb_request *req) int ret = LDB_SUCCESS; - req->handle = init_handle(lsqlite3, module, req); - if (req->handle == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } lsql_ac = talloc_get_type(req->handle->private_data, struct lsql_context); req->handle->state = LDB_ASYNC_DONE; req->handle->status = LDB_SUCCESS; @@ -1382,10 +1328,6 @@ static int lsql_rename(struct ldb_module *module, struct ldb_request *req) char *query; int ret = LDB_SUCCESS; - req->handle = init_handle(lsqlite3, module, req); - if (req->handle == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } lsql_ac = talloc_get_type(req->handle->private_data, struct lsql_context); req->handle->state = LDB_ASYNC_DONE; req->handle->status = LDB_SUCCESS; @@ -1501,9 +1443,61 @@ static int lsql_request(struct ldb_module *module, struct ldb_request *req) return LDB_ERR_OPERATIONS_ERROR; } -static int lsql_wait(struct ldb_handle *handle, enum ldb_wait_type type) +static int lsql_run_request(struct ldb_module *module, struct ldb_request *req) +{ + switch (req->operation) { + case LDB_SEARCH: + return lsql_search(module, req); + break; + case LDB_ADD: + return lsql_add(module, req); + break; + case LDB_MODIFY: + return lsql_modify(module, req); + break; + case LDB_DELETE: + return lsql_delete(module, req); + break; + case LDB_RENAME: + return lsql_rename(module, req); + break; +/* TODO: + case LDB_SEQUENCE_NUMBER: + return lsql_sequence_number(module, req); + break; + */ + default: + return lsql_request(module, req); + break; + } + + return LDB_ERR_OPERATIONS_ERROR; +} + +static int lsql_handle_request(struct ldb_module *module, struct ldb_request *req) { - return handle->status; + struct lsql_context *ac; + + if (check_critical_controls(req->controls)) { + return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION; + } + + ac = talloc_zero(req, struct lsql_context); + if (ac == NULL) { + ldb_set_errstring(module->ldb, "Out of Memory"); + return LDB_ERR_OPERATIONS_ERROR; + } + + ac->module = module; + ac->req = req; + + req->handle = ldb_handle_new(req, lsql_run_request, ac); + if (req->handle == NULL) { + talloc_free(ac); + return LDB_ERR_OPERATIONS_ERROR; + } + + return LDB_SUCCESS; } /* @@ -1511,16 +1505,16 @@ static int lsql_wait(struct ldb_handle *handle, enum ldb_wait_type type) */ static const struct ldb_module_ops lsqlite3_ops = { .name = "sqlite", - .search = lsql_search, - .add = lsql_add, - .modify = lsql_modify, - .del = lsql_delete, - .rename = lsql_rename, - .request = lsql_request, + .search = lsql_handle_request, + .add = lsql_handle_request, + .modify = lsql_handle_request, + .del = lsql_handle_request, + .rename = lsql_handle_request, + .request = lsql_handle_request, .start_transaction = lsql_start_trans, .end_transaction = lsql_end_trans, .del_transaction = lsql_del_trans, - .wait = lsql_wait, + /* TODO: .sequence_number = lsql_handle_request */ }; /* diff --git a/source4/lib/ldb/ldb_tdb/ldb_index.c b/source4/lib/ldb/ldb_tdb/ldb_index.c index 269305a468..65711d9f4b 100644 --- a/source4/lib/ldb/ldb_tdb/ldb_index.c +++ b/source4/lib/ldb/ldb_tdb/ldb_index.c @@ -667,74 +667,58 @@ static int ltdb_index_dn(struct ldb_module *module, extracting just the given attributes */ static int ltdb_index_filter(const struct dn_list *dn_list, - struct ldb_handle *handle) + struct ltdb_context *ac) { - struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_context); - struct ldb_reply *ares = NULL; + struct ldb_message *msg; unsigned int i; for (i = 0; i < dn_list->count; i++) { struct ldb_dn *dn; int ret; - ares = talloc_zero(ac, struct ldb_reply); - if (!ares) { - handle->status = LDB_ERR_OPERATIONS_ERROR; - handle->state = LDB_ASYNC_DONE; - return LDB_ERR_OPERATIONS_ERROR; - } - - ares->message = ldb_msg_new(ares); - if (!ares->message) { - handle->status = LDB_ERR_OPERATIONS_ERROR; - handle->state = LDB_ASYNC_DONE; - talloc_free(ares); + msg = ldb_msg_new(ac); + if (!msg) { return LDB_ERR_OPERATIONS_ERROR; } - - dn = ldb_dn_new(ares->message, ac->module->ldb, dn_list->dn[i]); + dn = ldb_dn_new(msg, ac->module->ldb, dn_list->dn[i]); if (dn == NULL) { - talloc_free(ares); + talloc_free(msg); return LDB_ERR_OPERATIONS_ERROR; } - ret = ltdb_search_dn1(ac->module, dn, ares->message); + ret = ltdb_search_dn1(ac->module, dn, msg); talloc_free(dn); if (ret == LDB_ERR_NO_SUCH_OBJECT) { /* the record has disappeared? yes, this can happen */ - talloc_free(ares); + talloc_free(msg); continue; } if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_OBJECT) { /* an internal error */ - talloc_free(ares); + talloc_free(msg); return LDB_ERR_OPERATIONS_ERROR; } - if (!ldb_match_msg(ac->module->ldb, ares->message, ac->tree, ac->base, ac->scope)) { - talloc_free(ares); + if (!ldb_match_msg(ac->module->ldb, msg, + ac->tree, ac->base, ac->scope)) { + talloc_free(msg); continue; } /* filter the attributes that the user wants */ - ret = ltdb_filter_attrs(ares->message, ac->attrs); + ret = ltdb_filter_attrs(msg, ac->attrs); if (ret == -1) { - handle->status = LDB_ERR_OPERATIONS_ERROR; - handle->state = LDB_ASYNC_DONE; - talloc_free(ares); + talloc_free(msg); return LDB_ERR_OPERATIONS_ERROR; } - ares->type = LDB_REPLY_ENTRY; - handle->state = LDB_ASYNC_PENDING; - handle->status = ac->callback(ac->module->ldb, ac->context, ares); - - if (handle->status != LDB_SUCCESS) { - handle->state = LDB_ASYNC_DONE; - return handle->status; + ret = ldb_module_send_entry(ac->req, msg); + if (ret != LDB_SUCCESS) { + ac->callback_failed = true; + return ret; } } @@ -746,9 +730,8 @@ static int ltdb_index_filter(const struct dn_list *dn_list, returns -1 if an indexed search is not possible, in which case the caller should call ltdb_search_full() */ -int ltdb_search_indexed(struct ldb_handle *handle) +int ltdb_search_indexed(struct ltdb_context *ac) { - struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_context); struct ltdb_private *ltdb = talloc_get_type(ac->module->private_data, struct ltdb_private); struct dn_list *dn_list; int ret, idxattr, idxone; @@ -773,7 +756,7 @@ int ltdb_search_indexed(struct ldb_handle *handle) ret = LDB_ERR_OPERATIONS_ERROR; - dn_list = talloc_zero(handle, struct dn_list); + dn_list = talloc_zero(ac, struct dn_list); if (dn_list == NULL) { return LDB_ERR_OPERATIONS_ERROR; } @@ -810,9 +793,7 @@ int ltdb_search_indexed(struct ldb_handle *handle) if (ret == LDB_SUCCESS) { /* we've got a candidate list - now filter by the full tree and extract the needed attributes */ - ret = ltdb_index_filter(dn_list, handle); - handle->status = ret; - handle->state = LDB_ASYNC_DONE; + ret = ltdb_index_filter(dn_list, ac); } talloc_free(dn_list); diff --git a/source4/lib/ldb/ldb_tdb/ldb_search.c b/source4/lib/ldb/ldb_tdb/ldb_search.c index da899c361e..a220b4a628 100644 --- a/source4/lib/ldb/ldb_tdb/ldb_search.c +++ b/source4/lib/ldb/ldb_tdb/ldb_search.c @@ -395,71 +395,57 @@ int ltdb_filter_attrs(struct ldb_message *msg, const char * const *attrs) */ static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state) { - struct ldb_handle *handle = talloc_get_type(state, struct ldb_handle); - struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_context); - struct ldb_reply *ares = NULL; + struct ltdb_context *ac; + struct ldb_message *msg; int ret; + ac = talloc_get_type(state, struct ltdb_context); + if (key.dsize < 4 || strncmp((char *)key.dptr, "DN=", 3) != 0) { return 0; } - ares = talloc_zero(ac, struct ldb_reply); - if (!ares) { - handle->status = LDB_ERR_OPERATIONS_ERROR; - handle->state = LDB_ASYNC_DONE; - return -1; - } - - ares->message = ldb_msg_new(ares); - if (!ares->message) { - handle->status = LDB_ERR_OPERATIONS_ERROR; - handle->state = LDB_ASYNC_DONE; - talloc_free(ares); + msg = ldb_msg_new(ac); + if (!msg) { return -1; } /* unpack the record */ - ret = ltdb_unpack_data(ac->module, &data, ares->message); + ret = ltdb_unpack_data(ac->module, &data, msg); if (ret == -1) { - talloc_free(ares); + talloc_free(msg); return -1; } - if (!ares->message->dn) { - ares->message->dn = ldb_dn_new(ares->message, ac->module->ldb, (char *)key.dptr + 3); - if (ares->message->dn == NULL) { - handle->status = LDB_ERR_OPERATIONS_ERROR; - handle->state = LDB_ASYNC_DONE; - talloc_free(ares); + if (!msg->dn) { + msg->dn = ldb_dn_new(msg, ac->module->ldb, + (char *)key.dptr + 3); + if (msg->dn == NULL) { + talloc_free(msg); return -1; } } /* see if it matches the given expression */ - if (!ldb_match_msg(ac->module->ldb, ares->message, ac->tree, - ac->base, ac->scope)) { - talloc_free(ares); + if (!ldb_match_msg(ac->module->ldb, msg, + ac->tree, ac->base, ac->scope)) { + talloc_free(msg); return 0; } /* filter the attributes that the user wants */ - ret = ltdb_filter_attrs(ares->message, ac->attrs); + ret = ltdb_filter_attrs(msg, ac->attrs); if (ret == -1) { - handle->status = LDB_ERR_OPERATIONS_ERROR; - handle->state = LDB_ASYNC_DONE; - talloc_free(ares); + talloc_free(msg); return -1; } - ares->type = LDB_REPLY_ENTRY; - handle->state = LDB_ASYNC_PENDING; - handle->status = ac->callback(ac->module->ldb, ac->context, ares); - - if (handle->status != LDB_SUCCESS) { - /* don't try to free ares here, the callback is in charge of that */ + ret = ldb_module_send_entry(ac->req, msg); + if (ret != LDB_SUCCESS) { + ac->callback_failed = true; + /* the callback failed, abort the operation */ return -1; } @@ -471,23 +457,21 @@ static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, voi search the database with a LDAP-like expression. this is the "full search" non-indexed variant */ -static int ltdb_search_full(struct ldb_handle *handle) +static int ltdb_search_full(struct ltdb_context *ctx) { - struct ltdb_context *ac = talloc_get_type(handle->private_data, struct ltdb_context); - struct ltdb_private *ltdb = talloc_get_type(ac->module->private_data, struct ltdb_private); + struct ltdb_private *ltdb = talloc_get_type(ctx->module->private_data, struct ltdb_private); int ret; if (ltdb->in_transaction != 0) { - ret = tdb_traverse(ltdb->tdb, search_func, handle); + ret = tdb_traverse(ltdb->tdb, search_func, ctx); } else { - ret = tdb_traverse_read(ltdb->tdb, search_func, handle); + ret = tdb_traverse_read(ltdb->tdb, search_func, ctx); } if (ret == -1) { - handle->status = LDB_ERR_OPERATIONS_ERROR; + return LDB_ERR_OPERATIONS_ERROR; } - handle->state = LDB_ASYNC_DONE; return LDB_SUCCESS; } @@ -495,13 +479,15 @@ static int ltdb_search_full(struct ldb_handle *handle) search the database with a LDAP-like expression. choses a search method */ -int ltdb_search(struct ldb_module *module, struct ldb_request *req) +int ltdb_search(struct ltdb_context *ctx) { + struct ldb_module *module = ctx->module; + struct ldb_request *req = ctx->req; struct ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private); - struct ltdb_context *ltdb_ac; - struct ldb_reply *ares; int ret; + req->handle->state = LDB_ASYNC_PENDING; + if (ltdb_lock_read(module) != 0) { return LDB_ERR_OPERATIONS_ERROR; } @@ -516,12 +502,6 @@ int ltdb_search(struct ldb_module *module, struct ldb_request *req) return LDB_ERR_OPERATIONS_ERROR; } - req->handle = init_ltdb_handle(ltdb, module, req); - if (req->handle == NULL) { - ltdb_unlock_read(module); - return LDB_ERR_OPERATIONS_ERROR; - } - if ((req->op.search.base == NULL) || (ldb_dn_is_null(req->op.search.base) == true)) { /* Check what we should do with a NULL dn */ @@ -564,53 +544,32 @@ int ltdb_search(struct ldb_module *module, struct ldb_request *req) ret = LDB_SUCCESS; } - ltdb_ac = talloc_get_type(req->handle->private_data, struct ltdb_context); - - ltdb_ac->tree = req->op.search.tree; - ltdb_ac->scope = req->op.search.scope; - ltdb_ac->base = req->op.search.base; - ltdb_ac->attrs = req->op.search.attrs; - + ctx->tree = req->op.search.tree; + ctx->scope = req->op.search.scope; + ctx->base = req->op.search.base; + ctx->attrs = req->op.search.attrs; if (ret == LDB_SUCCESS) { - ret = ltdb_search_indexed(req->handle); + ret = ltdb_search_indexed(ctx); if (ret == LDB_ERR_NO_SUCH_OBJECT) { /* Not in the index, therefore OK! */ ret = LDB_SUCCESS; - } else if (ret == LDB_ERR_OPERATIONS_ERROR) { + } + /* Check if we got just a normal error. + * In that case proceed to a full search unless we got a + * callback error */ + if ( ! ctx->callback_failed && ret != LDB_SUCCESS) { /* Not indexed, so we need to do a full scan */ - ret = ltdb_search_full(req->handle); + ret = ltdb_search_full(ctx); if (ret != LDB_SUCCESS) { ldb_set_errstring(module->ldb, "Indexed and full searches both failed!\n"); } } } - if (ret != LDB_SUCCESS) { - req->handle->state = LDB_ASYNC_DONE; - req->handle->status = ret; - } - - /* Finally send an LDB_REPLY_DONE packet when searching is finished */ - - ares = talloc_zero(req, struct ldb_reply); - if (!ares) { - ltdb_unlock_read(module); - return LDB_ERR_OPERATIONS_ERROR; - } - - req->handle->state = LDB_ASYNC_DONE; - - if (ret == LDB_SUCCESS) { - ares->type = LDB_REPLY_DONE; - - ret = req->callback(module->ldb, req->context, ares); - req->handle->status = ret; - } - ltdb_unlock_read(module); - return LDB_SUCCESS; + return ret; } diff --git a/source4/lib/ldb/ldb_tdb/ldb_tdb.c b/source4/lib/ldb/ldb_tdb/ldb_tdb.c index 01d570c89a..0087f6c44d 100644 --- a/source4/lib/ldb/ldb_tdb/ldb_tdb.c +++ b/source4/lib/ldb/ldb_tdb/ldb_tdb.c @@ -3,7 +3,7 @@ Copyright (C) Andrew Tridgell 2004 Copyright (C) Stefan Metzmacher 2004 - Copyright (C) Simo Sorce 2006 + Copyright (C) Simo Sorce 2006-2008 ** NOTE! The following LGPL license applies to the ldb @@ -39,6 +39,10 @@ * - description: make the module use asyncronous calls * date: Feb 2006 * Author: Simo Sorce + * + * - description: make it possible to use event contexts + * date: Jan 2008 + * Author: Simo Sorce */ #include "ldb_includes.h" @@ -76,40 +80,6 @@ static int ltdb_err_map(enum TDB_ERROR tdb_code) } -struct ldb_handle *init_ltdb_handle(struct ltdb_private *ltdb, - struct ldb_module *module, - struct ldb_request *req) -{ - struct ltdb_context *ac; - struct ldb_handle *h; - - h = talloc_zero(req, struct ldb_handle); - if (h == NULL) { - ldb_set_errstring(module->ldb, "Out of Memory"); - return NULL; - } - - h->module = module; - - ac = talloc_zero(h, struct ltdb_context); - if (ac == NULL) { - ldb_set_errstring(module->ldb, "Out of Memory"); - talloc_free(h); - return NULL; - } - - h->private_data = (void *)ac; - - h->state = LDB_ASYNC_INIT; - h->status = LDB_SUCCESS; - - ac->module = module; - ac->context = req->context; - ac->callback = req->callback; - - return h; -} - /* form a TDB_DATA for a record key caller frees @@ -296,36 +266,20 @@ static int ltdb_add_internal(struct ldb_module *module, /* add a record to the database */ -static int ltdb_add(struct ldb_module *module, struct ldb_request *req) +static int ltdb_add(struct ltdb_context *ctx) { - struct ltdb_private *ltdb; - struct ltdb_context *ltdb_ac; - int tret, ret = LDB_SUCCESS; - - ltdb = talloc_get_type(module->private_data, struct ltdb_private); - - if (check_critical_controls(req->controls)) { - return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION; - } + struct ldb_module *module = ctx->module; + struct ldb_request *req = ctx->req; + int tret; - req->handle = init_ltdb_handle(ltdb, module, req); - if (req->handle == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } - ltdb_ac = talloc_get_type(req->handle->private_data, struct ltdb_context); + req->handle->state = LDB_ASYNC_PENDING; tret = ltdb_add_internal(module, req->op.add.message); if (tret != LDB_SUCCESS) { - req->handle->status = tret; - goto done; + return tret; } - if (ltdb_ac->callback) { - ret = ltdb_ac->callback(module->ldb, ltdb_ac->context, NULL); - } -done: - req->handle->state = LDB_ASYNC_DONE; - return ret; + return LDB_SUCCESS; } /* @@ -402,42 +356,24 @@ done: /* delete a record from the database */ -static int ltdb_delete(struct ldb_module *module, struct ldb_request *req) +static int ltdb_delete(struct ltdb_context *ctx) { - struct ltdb_private *ltdb; - struct ltdb_context *ltdb_ac; - int tret, ret = LDB_SUCCESS; - - ltdb = talloc_get_type(module->private_data, struct ltdb_private); - - if (check_critical_controls(req->controls)) { - return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION; - } + struct ldb_module *module = ctx->module; + struct ldb_request *req = ctx->req; + int tret; - req->handle = NULL; + req->handle->state = LDB_ASYNC_PENDING; if (ltdb_cache_load(module) != 0) { return LDB_ERR_OPERATIONS_ERROR; } - req->handle = init_ltdb_handle(ltdb, module, req); - if (req->handle == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } - ltdb_ac = talloc_get_type(req->handle->private_data, struct ltdb_context); - tret = ltdb_delete_internal(module, req->op.del.dn); if (tret != LDB_SUCCESS) { - req->handle->status = tret; - goto done; + return tret; } - if (ltdb_ac->callback) { - ret = ltdb_ac->callback(module->ldb, ltdb_ac->context, NULL); - } -done: - req->handle->state = LDB_ASYNC_DONE; - return ret; + return LDB_SUCCESS; } /* @@ -784,83 +720,50 @@ failed: /* modify a record */ -static int ltdb_modify(struct ldb_module *module, struct ldb_request *req) +static int ltdb_modify(struct ltdb_context *ctx) { - struct ltdb_private *ltdb; - struct ltdb_context *ltdb_ac; - int tret, ret = LDB_SUCCESS; - - ltdb = talloc_get_type(module->private_data, struct ltdb_private); - - if (check_critical_controls(req->controls)) { - return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION; - } - - req->handle = NULL; + struct ldb_module *module = ctx->module; + struct ldb_request *req = ctx->req; + int tret; - req->handle = init_ltdb_handle(ltdb, module, req); - if (req->handle == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } - ltdb_ac = talloc_get_type(req->handle->private_data, struct ltdb_context); + req->handle->state = LDB_ASYNC_PENDING; tret = ltdb_check_special_dn(module, req->op.mod.message); if (tret != LDB_SUCCESS) { - req->handle->status = tret; - goto done; + return tret; } if (ltdb_cache_load(module) != 0) { - ret = LDB_ERR_OPERATIONS_ERROR; - goto done; + return LDB_ERR_OPERATIONS_ERROR; } tret = ltdb_modify_internal(module, req->op.mod.message); if (tret != LDB_SUCCESS) { - req->handle->status = tret; - goto done; + return tret; } - if (ltdb_ac->callback) { - ret = ltdb_ac->callback(module->ldb, ltdb_ac->context, NULL); - } -done: - req->handle->state = LDB_ASYNC_DONE; - return ret; + return LDB_SUCCESS; } /* rename a record */ -static int ltdb_rename(struct ldb_module *module, struct ldb_request *req) +static int ltdb_rename(struct ltdb_context *ctx) { - struct ltdb_private *ltdb; - struct ltdb_context *ltdb_ac; + struct ldb_module *module = ctx->module; + struct ldb_request *req = ctx->req; struct ldb_message *msg; - int tret, ret = LDB_SUCCESS; - - ltdb = talloc_get_type(module->private_data, struct ltdb_private); - - if (check_critical_controls(req->controls)) { - return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION; - } - - req->handle = NULL; + int tret; - if (ltdb_cache_load(module) != 0) { - return LDB_ERR_OPERATIONS_ERROR; - } + req->handle->state = LDB_ASYNC_PENDING; - req->handle = init_ltdb_handle(ltdb, module, req); - if (req->handle == NULL) { + if (ltdb_cache_load(ctx->module) != 0) { return LDB_ERR_OPERATIONS_ERROR; } - ltdb_ac = talloc_get_type(req->handle->private_data, struct ltdb_context); - msg = talloc(ltdb_ac, struct ldb_message); + msg = talloc(ctx, struct ldb_message); if (msg == NULL) { - ret = LDB_ERR_OPERATIONS_ERROR; - goto done; + return LDB_ERR_OPERATIONS_ERROR; } /* in case any attribute of the message was indexed, we need @@ -868,14 +771,12 @@ static int ltdb_rename(struct ldb_module *module, struct ldb_request *req) tret = ltdb_search_dn1(module, req->op.rename.olddn, msg); if (tret != LDB_SUCCESS) { /* not finding the old record is an error */ - req->handle->status = tret; - goto done; + return tret; } msg->dn = ldb_dn_copy(msg, req->op.rename.newdn); if (!msg->dn) { - ret = LDB_ERR_OPERATIONS_ERROR; - goto done; + return LDB_ERR_OPERATIONS_ERROR; } if (ldb_dn_compare(req->op.rename.olddn, req->op.rename.newdn) == 0) { @@ -886,38 +787,32 @@ static int ltdb_rename(struct ldb_module *module, struct ldb_request *req) The only drawback to this is that if the delete succeeds but the add fails, we rely on the transaction to roll this all back. */ - ret = ltdb_delete_internal(module, req->op.rename.olddn); - if (ret != LDB_SUCCESS) { - goto done; + tret = ltdb_delete_internal(module, req->op.rename.olddn); + if (tret != LDB_SUCCESS) { + return tret; } - ret = ltdb_add_internal(module, msg); - if (ret != LDB_SUCCESS) { - goto done; + tret = ltdb_add_internal(module, msg); + if (tret != LDB_SUCCESS) { + return tret; } } else { /* The rename operation is changing DNs. Try to add the new DN first to avoid clobbering another DN not related to this rename operation. */ - ret = ltdb_add_internal(module, msg); - if (ret != LDB_SUCCESS) { - goto done; + tret = ltdb_add_internal(module, msg); + if (tret != LDB_SUCCESS) { + return tret; } tret = ltdb_delete_internal(module, req->op.rename.olddn); if (tret != LDB_SUCCESS) { ltdb_delete_internal(module, req->op.rename.newdn); - ret = LDB_ERR_OPERATIONS_ERROR; - goto done; + return LDB_ERR_OPERATIONS_ERROR; } } - if (ltdb_ac->callback) { - ret = ltdb_ac->callback(module->ldb, ltdb_ac->context, NULL); - } -done: - req->handle->state = LDB_ASYNC_DONE; - return ret; + return LDB_SUCCESS; } static int ltdb_start_trans(struct ldb_module *module) @@ -962,24 +857,6 @@ static int ltdb_del_trans(struct ldb_module *module) return LDB_SUCCESS; } -static int ltdb_wait(struct ldb_handle *handle, enum ldb_wait_type type) -{ - return handle->status; -} - -static int ltdb_request(struct ldb_module *module, struct ldb_request *req) -{ - /* check for oustanding critical controls - * and return an error if found */ - if (check_critical_controls(req->controls)) { - return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION; - } - - /* search, add, modify, delete, rename are handled by their own, - * no other op supported */ - return LDB_ERR_OPERATIONS_ERROR; -} - /* return sequenceNumber from @BASEINFO */ @@ -1013,7 +890,7 @@ static int ltdb_sequence_number(struct ldb_module *module, talloc_free(tmp_ctx); /* zero is as good as anything when we don't know */ req->op.seq_num.seq_num = 0; - return LDB_SUCCESS; + return tret; } switch (req->op.seq_num.type) { @@ -1034,22 +911,136 @@ static int ltdb_sequence_number(struct ldb_module *module, } break; } + talloc_free(tmp_ctx); + + return LDB_SUCCESS; +} + +void ltdb_request_done(struct ldb_request *req, int error) +{ + struct ldb_reply *ares; + + /* if we already returned an error just return */ + if (req->handle->status != LDB_SUCCESS) { + return; + } + + ares = talloc_zero(req, struct ldb_reply); + if (!ares) { + ldb_oom(req->handle->ldb); + req->callback(req, NULL); + return; + } + ares->type = LDB_REPLY_DONE; + ares->error = error; + + req->callback(req, ares); +} + +static void ltdb_timeout(struct event_context *ev, + struct timed_event *te, + struct timeval t, + void *private_data) +{ + struct ltdb_context *ctx; + ctx = talloc_get_type(private_data, struct ltdb_context); + + ltdb_request_done(ctx->req, LDB_ERR_TIME_LIMIT_EXCEEDED); +} + +static void ltdb_callback(struct event_context *ev, + struct timed_event *te, + struct timeval t, + void *private_data) +{ + struct ltdb_context *ctx; + int ret; + + ctx = talloc_get_type(private_data, struct ltdb_context); + + switch (ctx->req->operation) { + case LDB_SEARCH: + ret = ltdb_search(ctx); + break; + case LDB_ADD: + ret = ltdb_add(ctx); + break; + case LDB_MODIFY: + ret = ltdb_modify(ctx); + break; + case LDB_DELETE: + ret = ltdb_delete(ctx); + break; + case LDB_RENAME: + ret = ltdb_rename(ctx); + break; + default: + /* no other op supported */ + ret = LDB_ERR_UNWILLING_TO_PERFORM; + } + + if (!ctx->callback_failed) { + ltdb_request_done(ctx->req, ret); + } +} + +static int ltdb_handle_request(struct ldb_module *module, + struct ldb_request *req) +{ + struct event_context *ev; + struct ltdb_context *ac; + struct timed_event *te; + struct timeval tv; + + if (check_critical_controls(req->controls)) { + return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION; + } + + if (req->starttime == 0 || req->timeout == 0) { + ldb_set_errstring(module->ldb, "Invalid timeout settings"); + return LDB_ERR_TIME_LIMIT_EXCEEDED; + } + + ev = ldb_get_event_context(module->ldb); + + ac = talloc_zero(req, struct ltdb_context); + if (ac == NULL) { + ldb_set_errstring(module->ldb, "Out of Memory"); + return LDB_ERR_OPERATIONS_ERROR; + } + + ac->module = module; + ac->req = req; + + tv.tv_sec = 0; + tv.tv_usec = 0; + te = event_add_timed(ev, ac, tv, ltdb_callback, ac); + if (NULL == te) { + return LDB_ERR_OPERATIONS_ERROR; + } + + + tv.tv_sec = req->starttime + req->timeout; + te = event_add_timed(ev, ac, tv, ltdb_timeout, ac); + if (NULL == te) { + return LDB_ERR_OPERATIONS_ERROR; + } + return LDB_SUCCESS; } static const struct ldb_module_ops ltdb_ops = { .name = "tdb", - .search = ltdb_search, - .add = ltdb_add, - .modify = ltdb_modify, - .del = ltdb_delete, - .rename = ltdb_rename, - .request = ltdb_request, + .search = ltdb_handle_request, + .add = ltdb_handle_request, + .modify = ltdb_handle_request, + .del = ltdb_handle_request, + .rename = ltdb_handle_request, +/* .request = ltdb_handle_request, */ .start_transaction = ltdb_start_trans, .end_transaction = ltdb_end_trans, .del_transaction = ltdb_del_trans, - .wait = ltdb_wait, .sequence_number = ltdb_sequence_number }; @@ -1114,7 +1105,7 @@ static int ltdb_connect(struct ldb_context *ldb, const char *url, ltdb->sequence_number = 0; *module = talloc(ldb, struct ldb_module); - if (!module) { + if ((*module) == NULL) { ldb_oom(ldb); talloc_free(ltdb); return -1; diff --git a/source4/lib/ldb/ldb_tdb/ldb_tdb.h b/source4/lib/ldb/ldb_tdb/ldb_tdb.h index 4beced30eb..223181ca0b 100644 --- a/source4/lib/ldb/ldb_tdb/ldb_tdb.h +++ b/source4/lib/ldb/ldb_tdb/ldb_tdb.h @@ -41,16 +41,15 @@ struct ltdb_private { */ struct ltdb_context { struct ldb_module *module; + struct ldb_request *req; + + bool callback_failed; /* search stuff */ const struct ldb_parse_tree *tree; struct ldb_dn *base; enum ldb_scope scope; const char * const *attrs; - - /* async stuff */ - void *context; - int (*callback)(struct ldb_context *, void *, struct ldb_reply *); }; /* special record types */ @@ -80,7 +79,7 @@ int ltdb_check_at_attributes_values(const struct ldb_val *value); struct ldb_parse_tree; -int ltdb_search_indexed(struct ldb_handle *handle); +int ltdb_search_indexed(struct ltdb_context *ctx); int ltdb_index_add(struct ldb_module *module, const struct ldb_message *msg); int ltdb_index_del(struct ldb_module *module, const struct ldb_message *msg); int ltdb_index_one(struct ldb_module *module, const struct ldb_message *msg, int add); @@ -110,11 +109,9 @@ int ltdb_add_attr_results(struct ldb_module *module, unsigned int *count, struct ldb_message ***res); int ltdb_filter_attrs(struct ldb_message *msg, const char * const *attrs); -int ltdb_search(struct ldb_module *module, struct ldb_request *req); +int ltdb_search(struct ltdb_context *ctx); /* The following definitions come from lib/ldb/ldb_tdb/ldb_tdb.c */ -struct ldb_handle *init_ltdb_handle(struct ltdb_private *ltdb, struct ldb_module *module, - struct ldb_request *req); struct TDB_DATA ltdb_key(struct ldb_module *module, struct ldb_dn *dn); int ltdb_store(struct ldb_module *module, const struct ldb_message *msg, int flgs); int ltdb_delete_noindex(struct ldb_module *module, struct ldb_dn *dn); @@ -127,4 +124,3 @@ struct tdb_context *ltdb_wrap_open(TALLOC_CTX *mem_ctx, const char *path, int hash_size, int tdb_flags, int open_flags, mode_t mode, struct ldb_context *ldb); - diff --git a/source4/lib/ldb/ldb_wrap.c b/source4/lib/ldb/ldb_wrap.c index c15fd2b9ae..cc8099f27f 100644 --- a/source4/lib/ldb/ldb_wrap.c +++ b/source4/lib/ldb/ldb_wrap.c @@ -3156,15 +3156,14 @@ SWIGINTERN ldb_error ldb_search_ex(ldb *self,TALLOC_CTX *mem_ctx,ldb_dn *base,en attrs, controls, res, - ldb_search_default_callback); + ldb_search_default_callback, + NULL); if (ret != 0) { talloc_free(res); return ret; } - ldb_set_timeout(self, req, 0); /* use default timeout */ - ret = ldb_request(self, req); if (ret == 0) { @@ -3506,22 +3505,6 @@ int py_module_del_transaction(struct ldb_module *mod) return LDB_SUCCESS; } -int py_module_wait(struct ldb_handle *mod, enum ldb_wait_type wait_type) -{ - PyObject *py_ldb = mod->private_data; - PyObject *py_result; - - py_result = PyObject_CallMethod(py_ldb, "wait", "i", wait_type); - - if (py_result == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } - - Py_DECREF(py_result); - - return LDB_SUCCESS; -} - int py_module_sequence_number(struct ldb_module *mod, struct ldb_request *req) { PyObject *py_ldb = mod->private_data; @@ -6665,7 +6648,6 @@ SWIGINTERN PyObject *_wrap_register_module(PyObject *SWIGUNUSEDPARM(self), PyObj arg1->start_transaction = py_module_start_transaction; arg1->end_transaction = py_module_end_transaction; arg1->del_transaction = py_module_del_transaction; - arg1->wait = py_module_wait; arg1->sequence_number = py_module_sequence_number; result = ldb_register_module((struct ldb_module_ops const *)arg1); if (result != 0) { diff --git a/source4/lib/ldb/libldb.m4 b/source4/lib/ldb/libldb.m4 index 77ebcc5ff4..5653794a88 100644 --- a/source4/lib/ldb/libldb.m4 +++ b/source4/lib/ldb/libldb.m4 @@ -2,6 +2,6 @@ # disable ldb_sqlite3 by default SMB_ENABLE(ldb_sqlite3, NO) -if test x"$with_sqlite3_support" = x"yes"; then - SMB_ENABLE(ldb_sqlite3, YES) -fi +#if test x"$with_sqlite3_support" = x"yes"; then +# SMB_ENABLE(ldb_sqlite3, YES) +#fi diff --git a/source4/lib/ldb/modules/asq.c b/source4/lib/ldb/modules/asq.c index eb27263b16..17896a006a 100644 --- a/source4/lib/ldb/modules/asq.c +++ b/source4/lib/ldb/modules/asq.c @@ -1,7 +1,7 @@ /* ldb database library - Copyright (C) Simo Sorce 2005 + 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 @@ -36,10 +36,10 @@ struct asq_context { - enum {ASQ_INIT, ASQ_SEARCH_BASE, ASQ_SEARCH_MULTI} step; + enum {ASQ_SEARCH_BASE, ASQ_SEARCH_MULTI} step; struct ldb_module *module; - struct ldb_request *orig_req; + struct ldb_request *req; struct ldb_asq_control *asq_ctrl; @@ -52,7 +52,6 @@ struct asq_context { ASQ_CTRL_AFFECTS_MULTIPLE_DSA = 71 } asq_ret; - struct ldb_request *base_req; struct ldb_reply *base_res; struct ldb_request **reqs; @@ -62,192 +61,200 @@ struct asq_context { struct ldb_control **controls; }; -static struct ldb_handle *init_handle(struct ldb_request *req, struct ldb_module *module) +static struct asq_context *asq_context_init(struct ldb_module *module, struct ldb_request *req) { struct asq_context *ac; - struct ldb_handle *h; - - h = talloc_zero(req, struct ldb_handle); - if (h == NULL) { - ldb_set_errstring(module->ldb, "Out of Memory"); - return NULL; - } - h->module = module; - - ac = talloc_zero(h, struct asq_context); + ac = talloc_zero(req, struct asq_context); if (ac == NULL) { - ldb_set_errstring(module->ldb, "Out of Memory"); - talloc_free(h); + ldb_oom(module->ldb); return NULL; } - h->private_data = (void *)ac; - - h->state = LDB_ASYNC_INIT; - h->status = LDB_SUCCESS; - - ac->step = ASQ_INIT; ac->module = module; - ac->orig_req = req; + ac->req = req; - return h; + return ac; } -static int asq_terminate(struct ldb_handle *handle) +static int asq_search_continue(struct asq_context *ac); + +static int asq_search_terminate(struct asq_context *ac) { - struct asq_context *ac; - struct ldb_reply *ares; struct ldb_asq_control *asq; int i; - ac = talloc_get_type(handle->private_data, struct asq_context); - if (ac == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } - - handle->status = LDB_SUCCESS; - handle->state = LDB_ASYNC_DONE; - - ares = talloc_zero(ac, struct ldb_reply); - if (ares == NULL) - return LDB_ERR_OPERATIONS_ERROR; - - ares->type = LDB_REPLY_DONE; - if (ac->controls) { - for (i = 0; ac->controls[i]; i++); - ares->controls = talloc_move(ares, &ac->controls); + for (i = 0; ac->controls[i]; i++) /* count em */ ; } else { i = 0; } - ares->controls = talloc_realloc(ares, ares->controls, struct ldb_control *, i + 2); - - if (ares->controls == NULL) + ac->controls = talloc_realloc(ac, ac->controls, struct ldb_control *, i + 2); + + if (ac->controls == NULL) { return LDB_ERR_OPERATIONS_ERROR; + } - ares->controls[i] = talloc(ares->controls, struct ldb_control); - if (ares->controls[i] == NULL) + ac->controls[i] = talloc(ac->controls, struct ldb_control); + if (ac->controls[i] == NULL) { return LDB_ERR_OPERATIONS_ERROR; + } - ares->controls[i]->oid = LDB_CONTROL_ASQ_OID; - ares->controls[i]->critical = 0; + ac->controls[i]->oid = LDB_CONTROL_ASQ_OID; + ac->controls[i]->critical = 0; - asq = talloc_zero(ares->controls[i], struct ldb_asq_control); + asq = talloc_zero(ac->controls[i], struct ldb_asq_control); if (asq == NULL) return LDB_ERR_OPERATIONS_ERROR; asq->result = ac->asq_ret; - - ares->controls[i]->data = asq; - ares->controls[i + 1] = NULL; + ac->controls[i]->data = asq; - ac->orig_req->callback(ac->module->ldb, ac->orig_req->context, ares); + ac->controls[i + 1] = NULL; - return LDB_SUCCESS; + return ldb_module_done(ac->req, ac->controls, NULL, LDB_SUCCESS); } -static int asq_base_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) +static int asq_base_callback(struct ldb_request *req, struct ldb_reply *ares) { struct asq_context *ac; + int ret; - if (!context || !ares) { - ldb_set_errstring(ldb, "NULL Context or Result in callback"); - goto error; - } + ac = talloc_get_type(req->context, struct asq_context); - ac = talloc_get_type(context, struct asq_context); - if (ac == NULL) { - goto error; + if (!ares) { + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); + } + if (ares->error != LDB_SUCCESS) { + return ldb_module_done(ac->req, ares->controls, + ares->response, ares->error); } - /* we are interested only in the single reply (base search) we receive here */ - if (ares->type == LDB_REPLY_ENTRY) { + switch (ares->type) { + case LDB_REPLY_ENTRY: ac->base_res = talloc_move(ac, &ares); - } else { + break; + + case LDB_REPLY_REFERRAL: + /* ignore referrals */ talloc_free(ares); - } + break; + case LDB_REPLY_DONE: + + talloc_free(ares); + + /* next step */ + ret = asq_search_continue(ac); + if (ret != LDB_SUCCESS) { + return ldb_module_done(ac->req, NULL, NULL, ret); + } + break; + + } return LDB_SUCCESS; -error: - talloc_free(ares); - return LDB_ERR_OPERATIONS_ERROR; } -static int asq_reqs_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) +static int asq_reqs_callback(struct ldb_request *req, struct ldb_reply *ares) { struct asq_context *ac; + int ret; - if (!context || !ares) { - ldb_set_errstring(ldb, "NULL Context or Result in callback"); - goto error; - } + ac = talloc_get_type(req->context, struct asq_context); - ac = talloc_get_type(context, struct asq_context); - if (ac == NULL) { - goto error; + if (!ares) { + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); + } + if (ares->error != LDB_SUCCESS) { + return ldb_module_done(ac->req, ares->controls, + ares->response, ares->error); } - /* we are interested only in the single reply (base search) we receive here */ - if (ares->type == LDB_REPLY_ENTRY) { - + switch (ares->type) { + case LDB_REPLY_ENTRY: /* pass the message up to the original callback as we * do not have to elaborate on it any further */ - return ac->orig_req->callback(ac->module->ldb, ac->orig_req->context, ares); - - } else { /* ignore any REFERRAL or DONE reply */ + ret = ldb_module_send_entry(ac->req, ares->message); + if (ret != LDB_SUCCESS) { + return ldb_module_done(ac->req, NULL, NULL, ret); + } + talloc_free(ares); + break; + + case LDB_REPLY_REFERRAL: + /* ignore referrals */ + talloc_free(ares); + break; + + case LDB_REPLY_DONE: + talloc_free(ares); + + ret = asq_search_continue(ac); + if (ret != LDB_SUCCESS) { + return ldb_module_done(ac->req, NULL, NULL, ret); + } + break; } return LDB_SUCCESS; -error: - talloc_free(ares); - return LDB_ERR_OPERATIONS_ERROR; } -static int asq_build_first_request(struct asq_context *ac) +static int asq_build_first_request(struct asq_context *ac, struct ldb_request **base_req) { - char **base_attrs; + const char **base_attrs; + int ret; - ac->base_req = talloc_zero(ac, struct ldb_request); - if (ac->base_req == NULL) return LDB_ERR_OPERATIONS_ERROR; + ac->req_attrs = ac->req->op.search.attrs; + ac->req_attribute = talloc_strdup(ac, ac->asq_ctrl->source_attribute); + if (ac->req_attribute == NULL) + return LDB_ERR_OPERATIONS_ERROR; - ac->base_req->operation = ac->orig_req->operation; - ac->base_req->op.search.base = ac->orig_req->op.search.base; - ac->base_req->op.search.scope = LDB_SCOPE_BASE; - ac->base_req->op.search.tree = ac->orig_req->op.search.tree; - base_attrs = talloc_array(ac->base_req, char *, 2); + base_attrs = talloc_array(ac, const char *, 2); if (base_attrs == NULL) return LDB_ERR_OPERATIONS_ERROR; base_attrs[0] = talloc_strdup(base_attrs, ac->asq_ctrl->source_attribute); if (base_attrs[0] == NULL) return LDB_ERR_OPERATIONS_ERROR; base_attrs[1] = NULL; - ac->base_req->op.search.attrs = (const char * const *)base_attrs; - ac->base_req->context = ac; - ac->base_req->callback = asq_base_callback; - ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->base_req); + ret = ldb_build_search_req_ex(base_req, ac->module->ldb, ac, + ac->req->op.search.base, + LDB_SCOPE_BASE, + ac->req->op.search.tree, + (const char * const *)base_attrs, + NULL, + ac, asq_base_callback, + ac->req); + if (ret != LDB_SUCCESS) { + return LDB_ERR_OPERATIONS_ERROR; + } return LDB_SUCCESS; } -static int asq_build_multiple_requests(struct asq_context *ac, struct ldb_handle *handle) +static int asq_build_multiple_requests(struct asq_context *ac, bool *terminated) { + struct ldb_control **saved_controls; + struct ldb_control *control; + struct ldb_dn *dn; struct ldb_message_element *el; - int i; + int ret, i; - /* look up the DNs */ if (ac->base_res == NULL) { return LDB_ERR_NO_SUCH_OBJECT; } + el = ldb_msg_find_element(ac->base_res->message, ac->req_attribute); /* no values found */ if (el == NULL) { ac->asq_ret = ASQ_CTRL_SUCCESS; - return asq_terminate(handle); + *terminated = true; + return asq_search_terminate(ac); } ac->num_reqs = el->num_values; @@ -259,144 +266,75 @@ static int asq_build_multiple_requests(struct asq_context *ac, struct ldb_handle for (i = 0; i < el->num_values; i++) { - ac->reqs[i] = talloc_zero(ac->reqs, struct ldb_request); - if (ac->reqs[i] == NULL) - return LDB_ERR_OPERATIONS_ERROR; - ac->reqs[i]->operation = LDB_SEARCH; - ac->reqs[i]->op.search.base = ldb_dn_new(ac->reqs[i], ac->module->ldb, (const char *)el->values[i].data); - if ( ! ldb_dn_validate(ac->reqs[i]->op.search.base)) { + dn = ldb_dn_new(ac, ac->module->ldb, + (const char *)el->values[i].data); + if ( ! ldb_dn_validate(dn)) { ac->asq_ret = ASQ_CTRL_INVALID_ATTRIBUTE_SYNTAX; - return asq_terminate(handle); + *terminated = true; + return asq_search_terminate(ac); + } + + ret = ldb_build_search_req_ex(&ac->reqs[i], + ac->module->ldb, ac, + dn, LDB_SCOPE_BASE, + ac->req->op.search.tree, + ac->req_attrs, + ac->req->controls, + ac, asq_reqs_callback, + ac->req); + if (ret != LDB_SUCCESS) { + return LDB_ERR_OPERATIONS_ERROR; } - ac->reqs[i]->op.search.scope = LDB_SCOPE_BASE; - ac->reqs[i]->op.search.tree = ac->base_req->op.search.tree; - ac->reqs[i]->op.search.attrs = ac->req_attrs; - ac->reqs[i]->context = ac; - ac->reqs[i]->callback = asq_reqs_callback; - ldb_set_timeout_from_prev_req(ac->module->ldb, ac->base_req, ac->reqs[i]); + /* remove the ASQ control itself */ + control = ldb_request_get_control(ac->req, LDB_CONTROL_ASQ_OID); + if (!save_controls(control, ac->reqs[i], &saved_controls)) { + return LDB_ERR_OPERATIONS_ERROR; + } } return LDB_SUCCESS; } -static int asq_search_continue(struct ldb_handle *handle) +static int asq_search_continue(struct asq_context *ac) { - struct asq_context *ac; + bool terminated = false; int ret; - - if (!handle || !handle->private_data) { - return LDB_ERR_OPERATIONS_ERROR; - } - - if (handle->state == LDB_ASYNC_DONE) { - return handle->status; - } - - ac = talloc_get_type(handle->private_data, struct asq_context); - if (ac == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } switch (ac->step) { - case ASQ_INIT: - /* check the search is well formed */ - if (ac->orig_req->op.search.scope != LDB_SCOPE_BASE) { - ac->asq_ret = ASQ_CTRL_UNWILLING_TO_PERFORM; - return asq_terminate(handle); - } - - ac->req_attrs = ac->orig_req->op.search.attrs; - ac->req_attribute = talloc_strdup(ac, ac->asq_ctrl->source_attribute); - if (ac->req_attribute == NULL) - return LDB_ERR_OPERATIONS_ERROR; - - /* get the object to retrieve the DNs to search */ - ret = asq_build_first_request(ac); - if (ret != LDB_SUCCESS) { - return ret; - } - - ac->step = ASQ_SEARCH_BASE; - - handle->state = LDB_ASYNC_PENDING; - handle->status = LDB_SUCCESS; - - return ldb_request(ac->module->ldb, ac->base_req); - case ASQ_SEARCH_BASE: - ret = ldb_wait(ac->base_req->handle, LDB_WAIT_NONE); - - if (ret != LDB_SUCCESS) { - handle->status = ret; - goto done; - } - - if (ac->base_req->handle->status != LDB_SUCCESS) { - handle->status = ac->base_req->handle->status; - goto done; + /* build up the requests call chain */ + ret = asq_build_multiple_requests(ac, &terminated); + if (ret != LDB_SUCCESS || terminated) { + return ret; } - if (ac->base_req->handle->state == LDB_ASYNC_DONE) { + ac->step = ASQ_SEARCH_MULTI; - /* build up the requests call chain */ - ret = asq_build_multiple_requests(ac, handle); - if (ret != LDB_SUCCESS) { - return ret; - } - if (handle->state == LDB_ASYNC_DONE) { - return LDB_SUCCESS; - } - - ac->step = ASQ_SEARCH_MULTI; - - return ldb_request(ac->module->ldb, ac->reqs[ac->cur_req]); - } - - /* request still pending, return to cycle again */ - return LDB_SUCCESS; + return ldb_request(ac->module->ldb, ac->reqs[ac->cur_req]); case ASQ_SEARCH_MULTI: - ret = ldb_wait(ac->reqs[ac->cur_req]->handle, LDB_WAIT_NONE); - - if (ret != LDB_SUCCESS) { - handle->status = ret; - goto done; - } - if (ac->reqs[ac->cur_req]->handle->status != LDB_SUCCESS) { - handle->status = ac->reqs[ac->cur_req]->handle->status; - } - - if (ac->reqs[ac->cur_req]->handle->state == LDB_ASYNC_DONE) { - ac->cur_req++; + ac->cur_req++; - if (ac->cur_req < ac->num_reqs) { - return ldb_request(ac->module->ldb, ac->reqs[ac->cur_req]); - } - - return asq_terminate(handle); + if (ac->cur_req == ac->num_reqs) { + /* done */ + return asq_search_terminate(ac); } - /* request still pending, return to cycle again */ - return LDB_SUCCESS; - - default: - ret = LDB_ERR_OPERATIONS_ERROR; - break; + return ldb_request(ac->module->ldb, ac->reqs[ac->cur_req]); } -done: - handle->state = LDB_ASYNC_DONE; - return ret; + return LDB_ERR_OPERATIONS_ERROR; } static int asq_search(struct ldb_module *module, struct ldb_request *req) { + struct ldb_request *base_req; struct ldb_control *control; struct asq_context *ac; - struct ldb_handle *h; + int ret; /* check if there's a paged request control */ control = ldb_request_get_control(req, LDB_CONTROL_ASQ_OID); @@ -405,67 +343,37 @@ static int asq_search(struct ldb_module *module, struct ldb_request *req) return ldb_next_request(module, req); } - req->handle = NULL; - - if (!req->callback || !req->context) { - ldb_set_errstring(module->ldb, - "Async interface called with NULL callback function or NULL context"); + ac = asq_context_init(module, req); + if (!ac) { return LDB_ERR_OPERATIONS_ERROR; } - h = init_handle(req, module); - if (!h) { - return LDB_ERR_OPERATIONS_ERROR; + /* check the search is well formed */ + if (req->op.search.scope != LDB_SCOPE_BASE) { + ac->asq_ret = ASQ_CTRL_UNWILLING_TO_PERFORM; + return asq_search_terminate(ac); } - ac = talloc_get_type(h->private_data, struct asq_context); ac->asq_ctrl = talloc_get_type(control->data, struct ldb_asq_control); if (!ac->asq_ctrl) { return LDB_ERR_PROTOCOL_ERROR; } - req->handle = h; - - return asq_search_continue(h); -} - -static int asq_wait(struct ldb_handle *handle, enum ldb_wait_type type) -{ - int ret; - - if (!handle || !handle->private_data) { - return LDB_ERR_OPERATIONS_ERROR; + ret = asq_build_first_request(ac, &base_req); + if (ret != LDB_SUCCESS) { + return ret; } - if (type == LDB_WAIT_ALL) { - while (handle->state != LDB_ASYNC_DONE) { - ret = asq_search_continue(handle); - if (ret != LDB_SUCCESS) { - return ret; - } - } - - return handle->status; - } + ac->step = ASQ_SEARCH_BASE; - return asq_search_continue(handle); + return ldb_request(module->ldb, base_req); } static int asq_init(struct ldb_module *module) { - struct ldb_request *req; int ret; - req = talloc_zero(module, struct ldb_request); - if (req == NULL) { - ldb_debug(module->ldb, LDB_DEBUG_ERROR, "asq: Out of memory!\n"); - return LDB_ERR_OPERATIONS_ERROR; - } - - req->operation = LDB_REQ_REGISTER_CONTROL; - req->op.reg_control.oid = LDB_CONTROL_ASQ_OID; - - ret = ldb_request(module->ldb, req); + ret = ldb_mod_register_control(module, LDB_CONTROL_ASQ_OID); if (ret != LDB_SUCCESS) { ldb_debug(module->ldb, LDB_DEBUG_WARNING, "asq: Unable to register control with rootdse!\n"); } @@ -476,6 +384,5 @@ static int asq_init(struct ldb_module *module) const struct ldb_module_ops ldb_asq_module_ops = { .name = "asq", .search = asq_search, - .wait = asq_wait, .init_context = asq_init }; diff --git a/source4/lib/ldb/modules/operational.c b/source4/lib/ldb/modules/operational.c index a59e81becd..abb1d4ca1a 100644 --- a/source4/lib/ldb/modules/operational.c +++ b/source4/lib/ldb/modules/operational.c @@ -2,7 +2,7 @@ ldb database library Copyright (C) Andrew Tridgell 2005 - Copyright (C) Simo Sorce 2006 + Copyright (C) Simo Sorce 2006-2008 ** NOTE! The following LGPL license applies to the ldb ** library. This does NOT imply that all of Samba is released @@ -173,38 +173,53 @@ failed: */ struct operational_context { - struct ldb_module *module; - void *up_context; - int (*up_callback)(struct ldb_context *, void *, struct ldb_reply *); + struct ldb_request *req; const char * const *attrs; }; -static int operational_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) +static int operational_callback(struct ldb_request *req, struct ldb_reply *ares) { struct operational_context *ac; + int ret; - if (!context || !ares) { - ldb_set_errstring(ldb, "NULL Context or Result in callback"); - goto error; - } + ac = talloc_get_type(req->context, struct operational_context); - ac = talloc_get_type(context, struct operational_context); + if (!ares) { + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); + } + if (ares->error != LDB_SUCCESS) { + return ldb_module_done(ac->req, ares->controls, + ares->response, ares->error); + } - if (ares->type == LDB_REPLY_ENTRY) { + switch (ares->type) { + case LDB_REPLY_ENTRY: /* for each record returned post-process to add any derived attributes that have been asked for */ - if (operational_search_post_process(ac->module, ares->message, ac->attrs) != 0) { - goto error; + ret = operational_search_post_process(ac->module, + ares->message, + ac->attrs); + if (ret != 0) { + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); } - } + return ldb_module_send_entry(ac->req, ares->message); - return ac->up_callback(ldb, ac->up_context, ares); + case LDB_REPLY_REFERRAL: + /* ignore referrals */ + break; + + case LDB_REPLY_DONE: + + return ldb_module_done(ac->req, ares->controls, + ares->response, LDB_SUCCESS); + } -error: talloc_free(ares); - return LDB_ERR_OPERATIONS_ERROR; + return LDB_SUCCESS; } static int operational_search(struct ldb_module *module, struct ldb_request *req) @@ -212,9 +227,8 @@ static int operational_search(struct ldb_module *module, struct ldb_request *req struct operational_context *ac; struct ldb_request *down_req; const char **search_attrs = NULL; - int i, a, ret; - - req->handle = NULL; + int i, a; + int ret; ac = talloc(req, struct operational_context); if (ac == NULL) { @@ -222,21 +236,10 @@ static int operational_search(struct ldb_module *module, struct ldb_request *req } ac->module = module; - ac->up_context = req->context; - ac->up_callback = req->callback; + ac->req = req; ac->attrs = req->op.search.attrs; - down_req = talloc_zero(req, struct ldb_request); - if (down_req == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } - - down_req->operation = req->operation; - down_req->op.search.base = req->op.search.base; - down_req->op.search.scope = req->op.search.scope; - down_req->op.search.tree = req->op.search.tree; - - /* FIXME: I hink we should copy the tree and keep the original + /* FIXME: We must copy the tree and keep the original * unmodified. SSS */ /* replace any attributes in the parse tree that are searchable, but are stored using a different name in the @@ -264,27 +267,26 @@ static int operational_search(struct ldb_module *module, struct ldb_request *req } } } - - /* use new set of attrs if any */ - if (search_attrs) down_req->op.search.attrs = search_attrs; - else down_req->op.search.attrs = req->op.search.attrs; - - down_req->controls = req->controls; - - down_req->context = ac; - down_req->callback = operational_callback; - ldb_set_timeout_from_prev_req(module->ldb, req, down_req); - /* perform the search */ - ret = ldb_next_request(module, down_req); + /* use new set of attrs if any */ + if (search_attrs == NULL) { + search_attrs = req->op.search.attrs; + } - /* do not free down_req as the call results may be linked to it, - * it will be freed when the upper level request get freed */ - if (ret == LDB_SUCCESS) { - req->handle = down_req->handle; + ret = ldb_build_search_req_ex(&down_req, module->ldb, ac, + req->op.search.base, + req->op.search.scope, + req->op.search.tree, + (const char * const *)search_attrs, + req->controls, + ac, operational_callback, + req); + if (ret != LDB_SUCCESS) { + return LDB_ERR_OPERATIONS_ERROR; } - return ret; + /* perform the search */ + return ldb_next_request(module, down_req); } static int operational_init(struct ldb_module *ctx) diff --git a/source4/lib/ldb/modules/paged_results.c b/source4/lib/ldb/modules/paged_results.c index b62b1f92cb..d3bb83bbcd 100644 --- a/source4/lib/ldb/modules/paged_results.c +++ b/source4/lib/ldb/modules/paged_results.c @@ -1,7 +1,7 @@ /* ldb database library - 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 @@ -51,9 +51,8 @@ struct results_store { char *cookie; time_t timestamp; - struct results_store *prev; struct results_store *next; - + struct message_store *first; struct message_store *last; int num_entries; @@ -62,8 +61,6 @@ struct results_store { struct message_store *last_ref; struct ldb_control **controls; - - struct ldb_request *req; }; struct private_data { @@ -73,20 +70,25 @@ struct private_data { }; -int store_destructor(struct results_store *store) +int store_destructor(struct results_store *del) { - if (store->prev) { - store->prev->next = store->next; - } - if (store->next) { - store->next->prev = store->prev; + struct private_data *priv = del->priv; + struct results_store *loop; + + if (priv->store == del) { + priv->store = del->next; + return 0; } - if (store == store->priv->store) { - store->priv->store = NULL; + for (loop = priv->store; loop; loop = loop->next) { + if (loop->next == del) { + loop->next = del->next; + return 0; + } } - return 0; + /* is not in list ? */ + return -1; } static struct results_store *new_store(struct private_data *priv) @@ -116,10 +118,7 @@ static struct results_store *new_store(struct private_data *priv) newr->first_ref = NULL; newr->controls = NULL; - /* put this entry as first */ - newr->prev = NULL; newr->next = priv->store; - if (priv->store != NULL) priv->store->prev = newr; priv->store = newr; talloc_set_destructor(newr, store_destructor); @@ -129,101 +128,164 @@ static struct results_store *new_store(struct private_data *priv) struct paged_context { struct ldb_module *module; - void *up_context; - int (*up_callback)(struct ldb_context *, void *, struct ldb_reply *); - - int size; + struct ldb_request *req; struct results_store *store; + int size; + struct ldb_control **controls; }; -static struct ldb_handle *init_handle(void *mem_ctx, struct ldb_module *module, - void *context, - int (*callback)(struct ldb_context *, void *, struct ldb_reply *)) +static int paged_results(struct paged_context *ac) { - struct paged_context *ac; - struct ldb_handle *h; + struct ldb_paged_control *paged; + struct message_store *msg; + int i, num_ctrls, ret; - h = talloc_zero(mem_ctx, struct ldb_handle); - if (h == NULL) { - ldb_set_errstring(module->ldb, "Out of Memory"); - return NULL; + if (ac->store == NULL) { + return LDB_ERR_OPERATIONS_ERROR; } - h->module = module; + while (ac->store->num_entries > 0 && ac->size > 0) { + msg = ac->store->first; + ret = ldb_module_send_entry(ac->req, msg->r->message); + if (ret != LDB_SUCCESS) { + return ret; + } - ac = talloc_zero(h, struct paged_context); - if (ac == NULL) { - ldb_set_errstring(module->ldb, "Out of Memory"); - talloc_free(h); - return NULL; + ac->store->first = msg->next; + talloc_free(msg); + ac->store->num_entries--; + ac->size--; } - h->private_data = (void *)ac; + while (ac->store->first_ref != NULL) { + msg = ac->store->first_ref; + ret = ldb_module_send_referral(ac->req, msg->r->referral); + if (ret != LDB_SUCCESS) { + return ret; + } - h->state = LDB_ASYNC_INIT; - h->status = LDB_SUCCESS; + ac->store->first_ref = msg->next; + talloc_free(msg); + } - ac->module = module; - ac->up_context = context; - ac->up_callback = callback; + /* return result done */ + num_ctrls = 1; + i = 0; + + if (ac->store->controls != NULL) { + while (ac->store->controls[i]) i++; /* counting */ + + num_ctrls += i; + } + + ac->controls = talloc_array(ac, struct ldb_control *, num_ctrls +1); + if (ac->controls == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + ac->controls[num_ctrls] = NULL; + + for (i = 0; i < (num_ctrls -1); i++) { + ac->controls[i] = talloc_reference(ac->controls, ac->store->controls[i]); + } + + ac->controls[i] = talloc(ac->controls, struct ldb_control); + if (ac->controls[i] == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } - return h; + ac->controls[i]->oid = talloc_strdup(ac->controls[i], + LDB_CONTROL_PAGED_RESULTS_OID); + if (ac->controls[i]->oid == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ac->controls[i]->critical = 0; + + paged = talloc(ac->controls[i], struct ldb_paged_control); + if (paged == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ac->controls[i]->data = paged; + + if (ac->size > 0) { + paged->size = 0; + paged->cookie = NULL; + paged->cookie_len = 0; + } else { + paged->size = ac->store->num_entries; + paged->cookie = talloc_strdup(paged, ac->store->cookie); + paged->cookie_len = strlen(paged->cookie) + 1; + } + + return LDB_SUCCESS; } -static int paged_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) +static int paged_search_callback(struct ldb_request *req, struct ldb_reply *ares) { - struct paged_context *ac = NULL; + struct paged_context *ac ; + struct message_store *msg_store; + int ret; - if (!context || !ares) { - ldb_set_errstring(ldb, "NULL Context or Result in callback"); - goto error; + ac = talloc_get_type(req->context, struct paged_context); + + if (!ares) { + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); + } + if (ares->error != LDB_SUCCESS) { + return ldb_module_done(ac->req, ares->controls, + ares->response, ares->error); } - ac = talloc_get_type(context, struct paged_context); + switch (ares->type) { + case LDB_REPLY_ENTRY: + msg_store = talloc(ac->store, struct message_store); + if (msg_store == NULL) { + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); + } + msg_store->next = NULL; + msg_store->r = talloc_steal(msg_store, ares); - if (ares->type == LDB_REPLY_ENTRY) { if (ac->store->first == NULL) { - ac->store->first = ac->store->last = talloc(ac->store, struct message_store); + ac->store->first = msg_store; } else { - ac->store->last->next = talloc(ac->store, struct message_store); - ac->store->last = ac->store->last->next; - } - if (ac->store->last == NULL) { - goto error; + ac->store->last->next = msg_store; } + ac->store->last = msg_store; ac->store->num_entries++; - ac->store->last->r = talloc_steal(ac->store->last, ares); - ac->store->last->next = NULL; - } + break; + + case LDB_REPLY_REFERRAL: + msg_store = talloc(ac->store, struct message_store); + if (msg_store == NULL) { + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); + } + msg_store->next = NULL; + msg_store->r = talloc_steal(msg_store, ares); - if (ares->type == LDB_REPLY_REFERRAL) { if (ac->store->first_ref == NULL) { - ac->store->first_ref = ac->store->last_ref = talloc(ac->store, struct message_store); + ac->store->first_ref = msg_store; } else { - ac->store->last_ref->next = talloc(ac->store, struct message_store); - ac->store->last_ref = ac->store->last_ref->next; - } - if (ac->store->last_ref == NULL) { - goto error; + ac->store->last_ref->next = msg_store; } + ac->store->last_ref = msg_store; - ac->store->last_ref->r = talloc_steal(ac->store->last, ares); - ac->store->last_ref->next = NULL; - } + break; - if (ares->type == LDB_REPLY_DONE) { + case LDB_REPLY_DONE: ac->store->controls = talloc_move(ac->store, &ares->controls); - talloc_free(ares); + ret = paged_results(ac); + return ldb_module_done(ac->req, ac->controls, + ares->response, ret); } return LDB_SUCCESS; - -error: - talloc_free(ares); - return LDB_ERR_OPERATIONS_ERROR; } static int paged_search(struct ldb_module *module, struct ldb_request *req) @@ -232,8 +294,8 @@ static int paged_search(struct ldb_module *module, struct ldb_request *req) struct private_data *private_data; struct ldb_paged_control *paged_ctrl; struct ldb_control **saved_controls; + struct ldb_request *search_req; struct paged_context *ac; - struct ldb_handle *h; int ret; /* check if there's a paged request control */ @@ -243,65 +305,57 @@ static int paged_search(struct ldb_module *module, struct ldb_request *req) return ldb_next_request(module, req); } - private_data = talloc_get_type(module->private_data, struct private_data); - - req->handle = NULL; - - if (!req->callback || !req->context) { - ldb_set_errstring(module->ldb, - "Async interface called with NULL callback function or NULL context"); - return LDB_ERR_OPERATIONS_ERROR; - } - paged_ctrl = talloc_get_type(control->data, struct ldb_paged_control); if (!paged_ctrl) { return LDB_ERR_PROTOCOL_ERROR; } - h = init_handle(req, module, req->context, req->callback); - if (!h) { + private_data = talloc_get_type(module->private_data, struct private_data); + + ac = talloc_zero(req, struct paged_context); + if (ac == NULL) { + ldb_set_errstring(module->ldb, "Out of Memory"); return LDB_ERR_OPERATIONS_ERROR; } - ac = talloc_get_type(h->private_data, struct paged_context); + ac->module = module; + ac->req = req; ac->size = paged_ctrl->size; /* check if it is a continuation search the store */ if (paged_ctrl->cookie_len == 0) { - - ac->store = new_store(private_data); - if (ac->store == NULL) { - talloc_free(h); - return LDB_ERR_UNWILLING_TO_PERFORM; + if (paged_ctrl->size == 0) { + return LDB_ERR_OPERATIONS_ERROR; } - ac->store->req = talloc(ac->store, struct ldb_request); - if (!ac->store->req) + ac->store = new_store(private_data); + if (ac->store == NULL) { return LDB_ERR_OPERATIONS_ERROR; + } - ac->store->req->operation = req->operation; - ac->store->req->op.search.base = req->op.search.base; - ac->store->req->op.search.scope = req->op.search.scope; - ac->store->req->op.search.tree = req->op.search.tree; - ac->store->req->op.search.attrs = req->op.search.attrs; - ac->store->req->controls = req->controls; + ret = ldb_build_search_req_ex(&search_req, module->ldb, ac, + req->op.search.base, + req->op.search.scope, + req->op.search.tree, + req->op.search.attrs, + req->controls, + ac, + paged_search_callback, + req); /* save it locally and remove it from the list */ /* we do not need to replace them later as we * are keeping the original req intact */ - if (!save_controls(control, ac->store->req, &saved_controls)) { + if (!save_controls(control, search_req, &saved_controls)) { return LDB_ERR_OPERATIONS_ERROR; } - ac->store->req->context = ac; - ac->store->req->callback = paged_search_callback; - ldb_set_timeout_from_prev_req(module->ldb, req, ac->store->req); - - ret = ldb_next_request(module, ac->store->req); + return ldb_next_request(module, search_req); } else { struct results_store *current = NULL; + /* TODO: age out old outstanding requests */ for (current = private_data->store; current; current = current->next) { if (strcmp(current->cookie, paged_ctrl->cookie) == 0) { current->timestamp = time(NULL); @@ -309,249 +363,52 @@ static int paged_search(struct ldb_module *module, struct ldb_request *req) } } if (current == NULL) { - talloc_free(h); return LDB_ERR_UNWILLING_TO_PERFORM; } ac->store = current; - ret = LDB_SUCCESS; - } - - req->handle = h; - - /* check if it is an abandon */ - if (ac->size == 0) { - talloc_free(ac->store); - h->status = LDB_SUCCESS; - h->state = LDB_ASYNC_DONE; - return LDB_SUCCESS; - } - - /* TODO: age out old outstanding requests */ - - return ret; - -} - -static int paged_results(struct ldb_handle *handle) -{ - struct paged_context *ac; - struct ldb_paged_control *paged; - struct ldb_reply *ares; - struct message_store *msg; - int i, num_ctrls, ret; - - ac = talloc_get_type(handle->private_data, struct paged_context); - - if (ac->store == NULL) - return LDB_ERR_OPERATIONS_ERROR; - while (ac->store->num_entries > 0 && ac->size > 0) { - msg = ac->store->first; - ret = ac->up_callback(ac->module->ldb, ac->up_context, msg->r); - if (ret != LDB_SUCCESS) { - handle->status = ret; - handle->state = LDB_ASYNC_DONE; - return ret; + /* check if it is an abandon */ + if (ac->size == 0) { + return ldb_module_done(req, NULL, NULL, + LDB_SUCCESS); } - ac->store->first = msg->next; - talloc_free(msg); - ac->store->num_entries--; - ac->size--; - } - - handle->state = LDB_ASYNC_DONE; - - while (ac->store->first_ref != NULL) { - msg = ac->store->first_ref; - ret = ac->up_callback(ac->module->ldb, ac->up_context, msg->r); + ret = paged_results(ac); if (ret != LDB_SUCCESS) { - handle->status = ret; - handle->state = LDB_ASYNC_DONE; - return ret; + return ldb_module_done(req, NULL, NULL, ret); } - - ac->store->first_ref = msg->next; - talloc_free(msg); - } - - ares = talloc_zero(ac->store, struct ldb_reply); - if (ares == NULL) { - handle->status = LDB_ERR_OPERATIONS_ERROR; - return handle->status; - } - num_ctrls = 2; - i = 0; - - if (ac->store->controls != NULL) { - ares->controls = ac->store->controls; - while (ares->controls[i]) i++; /* counting */ - - ares->controls = talloc_move(ares, &ac->store->controls); - num_ctrls += i; - } - - ares->controls = talloc_realloc(ares, ares->controls, struct ldb_control *, num_ctrls); - if (ares->controls == NULL) { - handle->status = LDB_ERR_OPERATIONS_ERROR; - return handle->status; + return ldb_module_done(req, ac->controls, NULL, + LDB_SUCCESS); } - - ares->controls[i] = talloc(ares->controls, struct ldb_control); - if (ares->controls[i] == NULL) { - handle->status = LDB_ERR_OPERATIONS_ERROR; - return handle->status; - } - - ares->controls[i]->oid = talloc_strdup(ares->controls[i], LDB_CONTROL_PAGED_RESULTS_OID); - if (ares->controls[i]->oid == NULL) { - handle->status = LDB_ERR_OPERATIONS_ERROR; - return handle->status; - } - - ares->controls[i]->critical = 0; - ares->controls[i + 1] = NULL; - - paged = talloc(ares->controls[i], struct ldb_paged_control); - if (paged == NULL) { - handle->status = LDB_ERR_OPERATIONS_ERROR; - return handle->status; - } - - ares->controls[i]->data = paged; - - if (ac->size > 0) { - paged->size = 0; - paged->cookie = NULL; - paged->cookie_len = 0; - } else { - paged->size = ac->store->num_entries; - paged->cookie = talloc_strdup(paged, ac->store->cookie); - paged->cookie_len = strlen(paged->cookie) + 1; - } - - ares->type = LDB_REPLY_DONE; - - ret = ac->up_callback(ac->module->ldb, ac->up_context, ares); - - handle->status = ret; - - return ret; -} - -static int paged_wait_once(struct ldb_handle *handle) { - struct paged_context *ac; - int ret; - - if (!handle || !handle->private_data) { - return LDB_ERR_OPERATIONS_ERROR; - } - - if (handle->state == LDB_ASYNC_DONE) { - return handle->status; - } - - handle->state = LDB_ASYNC_PENDING; - - ac = talloc_get_type(handle->private_data, struct paged_context); - - if (ac->store->req->handle->state == LDB_ASYNC_DONE) { - /* if lower level is finished we do not need to call it anymore */ - /* return all we have until size == 0 or we empty storage */ - ret = paged_results(handle); - - /* we are done, if num_entries is zero free the storage - * as that mean we delivered the last batch */ - if (ac->store->num_entries == 0) { - talloc_free(ac->store); - } - - return ret; - } - - ret = ldb_wait(ac->store->req->handle, LDB_WAIT_NONE); - if (ret != LDB_SUCCESS) { - handle->state = LDB_ASYNC_DONE; - handle->status = ret; - return ret; - } - - handle->status = ret; - - if (ac->store->num_entries >= ac->size || - ac->store->req->handle->state == LDB_ASYNC_DONE) { - - ret = paged_results(handle); - - /* we are done, if num_entries is zero free the storage - * as that mean we delivered the last batch */ - if (ac->store->num_entries == 0) { - talloc_free(ac->store); - } - } - - return ret; -} - -static int paged_wait(struct ldb_handle *handle, enum ldb_wait_type type) -{ - int ret; - - if (!handle || !handle->private_data) { - return LDB_ERR_OPERATIONS_ERROR; - } - - if (type == LDB_WAIT_ALL) { - while (handle->state != LDB_ASYNC_DONE) { - ret = paged_wait_once(handle); - if (ret != LDB_SUCCESS) { - return ret; - } - } - - return handle->status; - } - - return paged_wait_once(handle); } static int paged_request_init(struct ldb_module *module) { struct private_data *data; - struct ldb_request *req; int ret; data = talloc(module, struct private_data); if (data == NULL) { return LDB_ERR_OTHER; } - + data->next_free_id = 1; data->store = NULL; module->private_data = data; - req = talloc(module, struct ldb_request); - if (req == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } - - req->operation = LDB_REQ_REGISTER_CONTROL; - req->op.reg_control.oid = LDB_CONTROL_PAGED_RESULTS_OID; - req->controls = NULL; - - ret = ldb_request(module->ldb, req); + ret = ldb_mod_register_control(module, LDB_CONTROL_PAGED_RESULTS_OID); if (ret != LDB_SUCCESS) { - ldb_debug(module->ldb, LDB_DEBUG_WARNING, "paged_request: Unable to register control with rootdse!\n"); + ldb_debug(module->ldb, LDB_DEBUG_WARNING, + "paged_request:" + "Unable to register control with rootdse!\n"); } - talloc_free(req); return ldb_next_init(module); } const struct ldb_module_ops ldb_paged_results_module_ops = { .name = "paged_results", .search = paged_search, - .wait = paged_wait, .init_context = paged_request_init }; diff --git a/source4/lib/ldb/modules/paged_searches.c b/source4/lib/ldb/modules/paged_searches.c index 40e87f70d6..7a728e3bb0 100644 --- a/source4/lib/ldb/modules/paged_searches.c +++ b/source4/lib/ldb/modules/paged_searches.c @@ -1,7 +1,7 @@ /* ldb database library - 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 @@ -46,12 +46,7 @@ struct private_data { struct ps_context { struct ldb_module *module; - void *up_context; - int (*up_callback)(struct ldb_context *, void *, struct ldb_reply *); - - struct ldb_request *orig_req; - - struct ldb_request *new_req; + struct ldb_request *req; bool pending; @@ -59,51 +54,13 @@ struct ps_context { int num_referrals; }; -static struct ldb_handle *init_handle(void *mem_ctx, struct ldb_module *module, - void *context, - int (*callback)(struct ldb_context *, void *, struct ldb_reply *)) +static int check_ps_continuation(struct ldb_request *req, struct ldb_reply *ares) { struct ps_context *ac; - struct ldb_handle *h; - - h = talloc_zero(mem_ctx, struct ldb_handle); - if (h == NULL) { - ldb_set_errstring(module->ldb, "Out of Memory"); - return NULL; - } - - h->module = module; - - ac = talloc_zero(h, struct ps_context); - if (ac == NULL) { - ldb_set_errstring(module->ldb, "Out of Memory"); - talloc_free(h); - return NULL; - } - - h->private_data = (void *)ac; - - h->state = LDB_ASYNC_INIT; - h->status = LDB_SUCCESS; - - ac->module = module; - ac->up_context = context; - ac->up_callback = callback; - - ac->pending = false; - - - - ac->saved_referrals = NULL; - ac->num_referrals = 0; - - return h; -} - -static int check_ps_continuation(struct ldb_reply *ares, struct ps_context *ac) -{ struct ldb_paged_control *rep_control, *req_control; + ac = talloc_get_type(req->context, struct ps_context); + /* look up our paged control */ if (!ares->controls || strcmp(LDB_CONTROL_PAGED_RESULTS_OID, ares->controls[0]->oid) != 0) { /* something wrong here */ @@ -122,12 +79,12 @@ static int check_ps_continuation(struct ldb_reply *ares, struct ps_context *ac) /* if there's a reply control we must find a request * control matching it */ - if (strcmp(LDB_CONTROL_PAGED_RESULTS_OID, ac->new_req->controls[0]->oid) != 0) { + if (strcmp(LDB_CONTROL_PAGED_RESULTS_OID, req->controls[0]->oid) != 0) { /* something wrong here */ return LDB_ERR_OPERATIONS_ERROR; } - req_control = talloc_get_type(ac->new_req->controls[0]->data, struct ldb_paged_control); + req_control = talloc_get_type(req->controls[0]->data, struct ldb_paged_control); if (req_control->cookie) { talloc_free(req_control->cookie); @@ -142,7 +99,7 @@ static int check_ps_continuation(struct ldb_reply *ares, struct ps_context *ac) return LDB_SUCCESS; } -static int store_referral(char *referral, struct ps_context *ac) +static int store_referral(struct ps_context *ac, char *referral) { ac->saved_referrals = talloc_realloc(ac, ac->saved_referrals, char *, ac->num_referrals + 2); if (!ac->saved_referrals) { @@ -160,13 +117,14 @@ static int store_referral(char *referral, struct ps_context *ac) return LDB_SUCCESS; } -static int send_referrals(struct ldb_context *ldb, struct ps_context *ac) +static int send_referrals(struct ps_context *ac) { struct ldb_reply *ares; + int ret; int i; for (i = 0; i < ac->num_referrals; i++) { - ares = talloc_zero(ac, struct ldb_reply); + ares = talloc_zero(ac->req, struct ldb_reply); if (!ares) { return LDB_ERR_OPERATIONS_ERROR; } @@ -174,69 +132,87 @@ static int send_referrals(struct ldb_context *ldb, struct ps_context *ac) ares->type = LDB_REPLY_REFERRAL; ares->referral = ac->saved_referrals[i]; - ac->up_callback(ldb, ac->up_context, ares); + ret = ldb_module_send_referral(ac->req, ares->referral); + if (ret != LDB_SUCCESS) { + return ret; + } } return LDB_SUCCESS; } -static int ps_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) +static int ps_next_request(struct ps_context *ac); + +static int ps_callback(struct ldb_request *req, struct ldb_reply *ares) { - struct ps_context *ac = NULL; - int ret = LDB_ERR_OPERATIONS_ERROR; + struct ps_context *ac; + int ret; - if (!context || !ares) { - ldb_set_errstring(ldb, "NULL Context or Result in callback"); - goto error; - } + ac = talloc_get_type(req->context, struct ps_context); - ac = talloc_get_type(context, struct ps_context); + if (!ares) { + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); + } + if (ares->error != LDB_SUCCESS) { + return ldb_module_done(ac->req, ares->controls, + ares->response, ares->error); + } switch (ares->type) { case LDB_REPLY_ENTRY: - ac->up_callback(ldb, ac->up_context, ares); + ret = ldb_module_send_entry(ac->req, ares->message); + if (ret != LDB_SUCCESS) { + return ldb_module_done(ac->req, NULL, NULL, ret); + } break; case LDB_REPLY_REFERRAL: - ret = store_referral(ares->referral, ac); + ret = store_referral(ac, ares->referral); if (ret != LDB_SUCCESS) { - goto error; + return ldb_module_done(ac->req, NULL, NULL, ret); } break; case LDB_REPLY_DONE: - ret = check_ps_continuation(ares, ac); + + ret = check_ps_continuation(req, ares); if (ret != LDB_SUCCESS) { - goto error; + return ldb_module_done(ac->req, NULL, NULL, ret); } - if (!ac->pending) { + + if (ac->pending) { + + ret = ps_next_request(ac); + if (ret != LDB_SUCCESS) { + return ldb_module_done(ac->req, + NULL, NULL, ret); + } + + } else { + /* send referrals */ - ret = send_referrals(ldb, ac); + ret = send_referrals(ac); if (ret != LDB_SUCCESS) { - goto error; + return ldb_module_done(ac->req, + NULL, NULL, ret); } /* send REPLY_DONE */ - ac->up_callback(ldb, ac->up_context, ares); + return ldb_module_done(ac->req, ares->controls, + ares->response, LDB_SUCCESS); } break; - default: - goto error; } - return LDB_SUCCESS; - -error: talloc_free(ares); - return ret; + return LDB_SUCCESS; } static int ps_search(struct ldb_module *module, struct ldb_request *req) { struct private_data *private_data; - struct ldb_paged_control *control; struct ps_context *ac; - struct ldb_handle *h; private_data = talloc_get_type(module->private_data, struct private_data); @@ -248,216 +224,151 @@ static int ps_search(struct ldb_module *module, struct ldb_request *req) return ldb_next_request(module, req); } - if (!req->callback || !req->context) { - ldb_set_errstring(module->ldb, - "Async interface called with NULL callback function or NULL context"); - return LDB_ERR_OPERATIONS_ERROR; - } - - h = init_handle(req, module, req->context, req->callback); - if (!h) { + ac = talloc_zero(req, struct ps_context); + if (ac == NULL) { + ldb_oom(module->ldb); return LDB_ERR_OPERATIONS_ERROR; } - ac = talloc_get_type(h->private_data, struct ps_context); - - ac->new_req = talloc(ac, struct ldb_request); - if (!ac->new_req) return LDB_ERR_OPERATIONS_ERROR; - - ac->new_req->controls = talloc_array(ac->new_req, struct ldb_control *, 2); - if (!ac->new_req->controls) return LDB_ERR_OPERATIONS_ERROR; - - ac->new_req->controls[0] = talloc(ac->new_req->controls, struct ldb_control); - if (!ac->new_req->controls[0]) return LDB_ERR_OPERATIONS_ERROR; - - control = talloc(ac->new_req->controls[0], struct ldb_paged_control); - if (!control) return LDB_ERR_OPERATIONS_ERROR; - - control->size = PS_DEFAULT_PAGE_SIZE; - control->cookie = NULL; - control->cookie_len = 0; - - ac->new_req->controls[0]->oid = LDB_CONTROL_PAGED_RESULTS_OID; - ac->new_req->controls[0]->critical = 1; - ac->new_req->controls[0]->data = control; - - ac->new_req->controls[1] = NULL; - ac->new_req->operation = req->operation; - ac->new_req->op.search.base = req->op.search.base; - ac->new_req->op.search.scope = req->op.search.scope; - ac->new_req->op.search.tree = req->op.search.tree; - ac->new_req->op.search.attrs = req->op.search.attrs; - ac->new_req->context = ac; - ac->new_req->callback = ps_callback; - ldb_set_timeout_from_prev_req(module->ldb, req, ac->new_req); - - req->handle = h; + ac->module = module; + ac->req = req; + ac->pending = false; + ac->saved_referrals = NULL; + ac->num_referrals = 0; - return ldb_next_request(module, ac->new_req); + return ps_next_request(ac); } -static int ps_continuation(struct ldb_handle *handle) -{ - struct ps_context *ac; +static int ps_next_request(struct ps_context *ac) { - if (!handle || !handle->private_data) { + struct ldb_paged_control *control; + struct ldb_control **controls; + struct ldb_request *new_req; + int ret; + + controls = talloc_array(ac, struct ldb_control *, 2); + if (!controls) { return LDB_ERR_OPERATIONS_ERROR; } - ac = talloc_get_type(handle->private_data, struct ps_context); - - /* reset the requests handle */ - ac->new_req->handle = NULL; - - return ldb_next_request(handle->module, ac->new_req); -} - -static int ps_wait_once(struct ldb_handle *handle) -{ - struct ps_context *ac; - int ret; - - if (!handle || !handle->private_data) { + controls[0] = talloc(controls, struct ldb_control); + if (!controls[0]) { return LDB_ERR_OPERATIONS_ERROR; } - if (handle->state == LDB_ASYNC_DONE) { - return handle->status; + control = talloc(controls[0], struct ldb_paged_control); + if (!control) { + return LDB_ERR_OPERATIONS_ERROR; } - handle->state = LDB_ASYNC_PENDING; - handle->status = LDB_SUCCESS; - - ac = talloc_get_type(handle->private_data, struct ps_context); - - ret = ldb_wait(ac->new_req->handle, LDB_WAIT_NONE); + control->size = PS_DEFAULT_PAGE_SIZE; + control->cookie = NULL; + control->cookie_len = 0; + controls[0]->oid = LDB_CONTROL_PAGED_RESULTS_OID; + controls[0]->critical = 1; + controls[0]->data = control; + controls[1] = NULL; + + ret = ldb_build_search_req_ex(&new_req, ac->module->ldb, ac, + ac->req->op.search.base, + ac->req->op.search.scope, + ac->req->op.search.tree, + ac->req->op.search.attrs, + controls, + ac, + ps_callback, + ac->req); if (ret != LDB_SUCCESS) { - handle->status = ret; - goto done; - } - - if (ac->new_req->handle->status != LDB_SUCCESS) { - handle->status = ac->new_req->handle->status; - goto done; - } - - if (ac->new_req->handle->state != LDB_ASYNC_DONE) { - return LDB_SUCCESS; - } - - /* see if we need to send another request for the next batch */ - if (ac->pending) { - ret = ps_continuation(handle); - if (ret != LDB_SUCCESS) { - handle->status = ret; - goto done; - } - - /* continue the search with the next request */ - return LDB_SUCCESS; + return ret; } + talloc_steal(new_req, controls); - ret = LDB_SUCCESS; - -done: - handle->state = LDB_ASYNC_DONE; - return ret; + return ldb_next_request(ac->module, new_req); } -static int ps_wait(struct ldb_handle *handle, enum ldb_wait_type type) +static int check_supported_paged(struct ldb_request *req, + struct ldb_reply *ares) { - int ret; - - if (!handle || !handle->private_data) { - return LDB_ERR_OPERATIONS_ERROR; - } + struct private_data *data; - if (type == LDB_WAIT_ALL) { - while (handle->state != LDB_ASYNC_DONE) { - ret = ps_wait_once(handle); - if (ret != LDB_SUCCESS) { - return ret; - } - } + data = talloc_get_type(req->context, struct private_data); - return handle->status; + if (!ares) { + return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR); + } + if (ares->error != LDB_SUCCESS) { + return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR); } - return ps_wait_once(handle); -} -static int check_supported_paged(struct ldb_context *ldb, void *context, - struct ldb_reply *ares) -{ - struct private_data *data; - data = talloc_get_type(context, - struct private_data); - if (ares->type == LDB_REPLY_ENTRY) { + switch (ares->type) { + case LDB_REPLY_ENTRY: if (ldb_msg_check_string_attribute(ares->message, "supportedControl", LDB_CONTROL_PAGED_RESULTS_OID)) { data->paged_supported = true; } + break; + + case LDB_REPLY_REFERRAL: + /* ignore */ + break; + + case LDB_REPLY_DONE: + return ldb_request_done(req, LDB_SUCCESS); } + + talloc_free(ares); return LDB_SUCCESS; } - static int ps_init(struct ldb_module *module) { static const char *attrs[] = { "supportedControl", NULL }; struct private_data *data; + struct ldb_dn *base; int ret; struct ldb_request *req; data = talloc(module, struct private_data); if (data == NULL) { - ldb_set_errstring(module->ldb, "Out of Memory"); - return LDB_ERR_OTHER; + ldb_oom(module->ldb); + return LDB_ERR_OPERATIONS_ERROR; } module->private_data = data; data->paged_supported = false; - req = talloc(module, struct ldb_request); - if (req == NULL) { - ldb_set_errstring(module->ldb, "Out of Memory"); + base = ldb_dn_new(module, module->ldb, ""); + if (base == NULL) { + ldb_oom(module->ldb); return LDB_ERR_OPERATIONS_ERROR; } - - req->operation = LDB_SEARCH; - req->op.search.base = ldb_dn_new(req, module->ldb, ""); - req->op.search.scope = LDB_SCOPE_BASE; - - req->op.search.tree = ldb_parse_tree(req, "objectClass=*"); - if (req->op.search.tree == NULL) { - ldb_set_errstring(module->ldb, "Unable to parse search expression"); - talloc_free(req); - return LDB_ERR_OPERATIONS_ERROR; + ret = ldb_build_search_req(&req, module->ldb, module, + base, LDB_SCOPE_BASE, + "(objectClass=*)", + attrs, NULL, + data, check_supported_paged, + NULL); + if (ret != LDB_SUCCESS) { + return ret; } - req->op.search.attrs = attrs; - req->controls = NULL; - req->context = data; - req->callback = check_supported_paged; - ldb_set_timeout(module->ldb, req, 0); /* use default timeout */ - ret = ldb_next_request(module, req); - if (ret == LDB_SUCCESS) { ret = ldb_wait(req->handle, LDB_WAIT_ALL); } - - talloc_free(req); if (ret != LDB_SUCCESS) { return ret; } + talloc_free(base); + talloc_free(req); + return ldb_next_init(module); } _PUBLIC_ const struct ldb_module_ops ldb_paged_searches_module_ops = { .name = "paged_searches", .search = ps_search, - .wait = ps_wait, .init_context = ps_init }; diff --git a/source4/lib/ldb/modules/rdn_name.c b/source4/lib/ldb/modules/rdn_name.c index 65c044c0f4..62b8ce5112 100644 --- a/source4/lib/ldb/modules/rdn_name.c +++ b/source4/lib/ldb/modules/rdn_name.c @@ -2,7 +2,7 @@ ldb database library Copyright (C) Andrew Bartlet 2005 - Copyright (C) Simo Sorce 2006 + Copyright (C) Simo Sorce 2006-2008 ** NOTE! The following LGPL license applies to the ldb ** library. This does NOT imply that all of Samba is released @@ -38,6 +38,14 @@ #include "ldb_includes.h" +struct rename_context { + + struct ldb_module *module; + struct ldb_request *req; + + struct ldb_reply *ares; +}; + static struct ldb_message_element *rdn_name_find_attribute(const struct ldb_message *msg, const char *name) { int i; @@ -51,11 +59,38 @@ static struct ldb_message_element *rdn_name_find_attribute(const struct ldb_mess return NULL; } +static int rdn_name_add_callback(struct ldb_request *req, + struct ldb_reply *ares) +{ + struct rename_context *ac; + + ac = talloc_get_type(req->context, struct rename_context); + + if (!ares) { + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); + } + if (ares->error != LDB_SUCCESS) { + return ldb_module_done(ac->req, ares->controls, + ares->response, ares->error); + } + + if (ares->type != LDB_REPLY_DONE) { + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); + } + + return ldb_module_done(ac->req, ares->controls, + ares->response, LDB_SUCCESS); +} + static int rdn_name_add(struct ldb_module *module, struct ldb_request *req) { struct ldb_request *down_req; + struct rename_context *ac; struct ldb_message *msg; struct ldb_message_element *attribute; + const struct ldb_schema_attribute *a; const char *rdn_name; struct ldb_val rdn_val; int i, ret; @@ -67,21 +102,22 @@ static int rdn_name_add(struct ldb_module *module, struct ldb_request *req) return ldb_next_request(module, req); } - down_req = talloc(req, struct ldb_request); - if (down_req == NULL) { + ac = talloc_zero(req, struct rename_context); + if (ac == NULL) { return LDB_ERR_OPERATIONS_ERROR; } - *down_req = *req; + ac->module = module; + ac->req = req; - down_req->op.add.message = msg = ldb_msg_copy_shallow(down_req, req->op.add.message); + msg = ldb_msg_copy_shallow(req, req->op.add.message); if (msg == NULL) { return LDB_ERR_OPERATIONS_ERROR; } rdn_name = ldb_dn_get_rdn_name(msg->dn); if (rdn_name == NULL) { - talloc_free(down_req); + talloc_free(ac); return LDB_ERR_OPERATIONS_ERROR; } @@ -93,7 +129,7 @@ static int rdn_name_add(struct ldb_module *module, struct ldb_request *req) } if (ldb_msg_add_value(msg, "name", &rdn_val, NULL) != 0) { - talloc_free(down_req); + talloc_free(ac); return LDB_ERR_OPERATIONS_ERROR; } @@ -101,14 +137,16 @@ static int rdn_name_add(struct ldb_module *module, struct ldb_request *req) if (!attribute) { if (ldb_msg_add_value(msg, rdn_name, &rdn_val, NULL) != 0) { - talloc_free(down_req); + talloc_free(ac); return LDB_ERR_OPERATIONS_ERROR; } } else { - const struct ldb_schema_attribute *a = ldb_schema_attribute_by_name(module->ldb, rdn_name); + a = ldb_schema_attribute_by_name(module->ldb, rdn_name); for (i = 0; i < attribute->num_values; i++) { - if (a->syntax->comparison_fn(module->ldb, msg, &rdn_val, &attribute->values[i]) == 0) { + ret = a->syntax->comparison_fn(module->ldb, msg, + &rdn_val, &attribute->values[i]); + if (ret == 0) { /* overwrite so it matches in case */ attribute->values[i] = rdn_val; break; @@ -118,218 +156,166 @@ static int rdn_name_add(struct ldb_module *module, struct ldb_request *req) ldb_debug_set(module->ldb, LDB_DEBUG_FATAL, "RDN mismatch on %s: %s (%s)", ldb_dn_get_linearized(msg->dn), rdn_name, rdn_val.data); - talloc_free(down_req); + talloc_free(ac); /* Match AD's error here */ return LDB_ERR_INVALID_DN_SYNTAX; } } - /* go on with the call chain */ - ret = ldb_next_request(module, down_req); - - /* do not free down_req as the call results may be linked to it, - * it will be freed when the upper level request get freed */ - if (ret == LDB_SUCCESS) { - req->handle = down_req->handle; + ret = ldb_build_add_req(&down_req, module->ldb, req, + msg, + req->controls, + ac, rdn_name_add_callback, + req); + if (ret != LDB_SUCCESS) { + return ret; } - return ret; -} - -struct rename_context { + talloc_steal(down_req, msg); - enum {RENAME_RENAME, RENAME_MODIFY} step; - struct ldb_request *orig_req; - struct ldb_request *down_req; - struct ldb_request *mod_req; -}; + /* go on with the call chain */ + return ldb_next_request(module, down_req); +} -static int rdn_name_rename(struct ldb_module *module, struct ldb_request *req) +static int rdn_modify_callback(struct ldb_request *req, struct ldb_reply *ares) { - struct ldb_handle *h; struct rename_context *ac; - ldb_debug(module->ldb, LDB_DEBUG_TRACE, "rdn_name_rename\n"); + ac = talloc_get_type(req->context, struct rename_context); - /* do not manipulate our control entries */ - if (ldb_dn_is_special(req->op.rename.newdn)) { - return ldb_next_request(module, req); + if (!ares) { + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); } - - h = talloc_zero(req, struct ldb_handle); - if (h == NULL) { - return LDB_ERR_OPERATIONS_ERROR; + if (ares->error != LDB_SUCCESS) { + return ldb_module_done(ac->req, ares->controls, + ares->response, ares->error); } - h->module = module; - - ac = talloc_zero(h, struct rename_context); - if (ac == NULL) { - return LDB_ERR_OPERATIONS_ERROR; + /* the only supported reply right now is a LDB_REPLY_DONE */ + if (ares->type != LDB_REPLY_DONE) { + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); } - h->private_data = (void *)ac; - - h->state = LDB_ASYNC_INIT; - h->status = LDB_SUCCESS; - - ac->orig_req = req; - ac->down_req = talloc(req, struct ldb_request); - if (ac->down_req == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } - - *(ac->down_req) = *req; - - ac->step = RENAME_RENAME; - - req->handle = h; - - /* rename first, modify "name" if rename is ok */ - return ldb_next_request(module, ac->down_req); + /* send saved controls eventually */ + return ldb_module_done(ac->req, ac->ares->controls, + ac->ares->response, LDB_SUCCESS); } -static int rdn_name_rename_do_mod(struct ldb_handle *h) { - +static int rdn_rename_callback(struct ldb_request *req, struct ldb_reply *ares) +{ struct rename_context *ac; + struct ldb_request *mod_req; const char *rdn_name; struct ldb_val rdn_val; struct ldb_message *msg; + int ret; - ac = talloc_get_type(h->private_data, struct rename_context); + ac = talloc_get_type(req->context, struct rename_context); - ac->mod_req = talloc_zero(ac, struct ldb_request); + if (!ares) { + goto error; + } + if (ares->error != LDB_SUCCESS) { + return ldb_module_done(ac->req, ares->controls, + ares->response, ares->error); + } - ac->mod_req->operation = LDB_MODIFY; - ac->mod_req->op.mod.message = msg = ldb_msg_new(ac->mod_req); - if (msg == NULL) { - return LDB_ERR_OPERATIONS_ERROR; + /* the only supported reply right now is a LDB_REPLY_DONE */ + if (ares->type != LDB_REPLY_DONE) { + goto error; } - msg->dn = ldb_dn_copy(msg, ac->orig_req->op.rename.newdn); + /* save reply for caller */ + ac->ares = talloc_steal(ac, ares); + + msg = ldb_msg_new(ac); + if (msg == NULL) { + goto error; + } + msg->dn = ldb_dn_copy(msg, ac->req->op.rename.newdn); if (msg->dn == NULL) { - return LDB_ERR_OPERATIONS_ERROR; + goto error; } - - rdn_name = ldb_dn_get_rdn_name(ac->orig_req->op.rename.newdn); + rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn); if (rdn_name == NULL) { - return LDB_ERR_OPERATIONS_ERROR; + goto error; } - rdn_val = ldb_val_dup(msg, ldb_dn_get_rdn_val(ac->orig_req->op.rename.newdn)); + rdn_val = ldb_val_dup(msg, ldb_dn_get_rdn_val(ac->req->op.rename.newdn)); if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) { - return LDB_ERR_OPERATIONS_ERROR; + goto error; } if (ldb_msg_add_value(msg, rdn_name, &rdn_val, NULL) != 0) { - return LDB_ERR_OPERATIONS_ERROR; + goto error; } if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) { - return LDB_ERR_OPERATIONS_ERROR; + goto error; } if (ldb_msg_add_value(msg, "name", &rdn_val, NULL) != 0) { - return LDB_ERR_OPERATIONS_ERROR; + goto error; } - ldb_set_timeout_from_prev_req(h->module->ldb, ac->orig_req, ac->mod_req); - - ac->step = RENAME_MODIFY; + ret = ldb_build_mod_req(&mod_req, ac->module->ldb, + ac, msg, NULL, + ac, rdn_modify_callback, + req); + if (ret != LDB_SUCCESS) { + return ldb_module_done(ac->req, NULL, NULL, ret); + } + talloc_steal(mod_req, msg); /* do the mod call */ - return ldb_request(h->module->ldb, ac->mod_req); + return ldb_request(ac->module->ldb, mod_req); + +error: + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); } -static int rdn_name_wait_once(struct ldb_handle *handle) +static int rdn_name_rename(struct ldb_module *module, struct ldb_request *req) { struct rename_context *ac; + struct ldb_request *down_req; int ret; - - if (!handle || !handle->private_data) { - return LDB_ERR_OPERATIONS_ERROR; - } - - if (handle->state == LDB_ASYNC_DONE) { - return handle->status; - } - handle->state = LDB_ASYNC_PENDING; - handle->status = LDB_SUCCESS; - - ac = talloc_get_type(handle->private_data, struct rename_context); - - switch(ac->step) { - case RENAME_RENAME: - ret = ldb_wait(ac->down_req->handle, LDB_WAIT_NONE); - if (ret != LDB_SUCCESS) { - handle->status = ret; - goto done; - } - if (ac->down_req->handle->status != LDB_SUCCESS) { - handle->status = ac->down_req->handle->status; - goto done; - } - - if (ac->down_req->handle->state != LDB_ASYNC_DONE) { - return LDB_SUCCESS; - } - - /* rename operation done */ - return rdn_name_rename_do_mod(handle); - - case RENAME_MODIFY: - ret = ldb_wait(ac->mod_req->handle, LDB_WAIT_NONE); - if (ret != LDB_SUCCESS) { - handle->status = ret; - goto done; - } - if (ac->mod_req->handle->status != LDB_SUCCESS) { - handle->status = ac->mod_req->handle->status; - goto done; - } - - if (ac->mod_req->handle->state != LDB_ASYNC_DONE) { - return LDB_SUCCESS; - } - - break; + ldb_debug(module->ldb, LDB_DEBUG_TRACE, "rdn_name_rename\n"); - default: - ret = LDB_ERR_OPERATIONS_ERROR; - goto done; + /* do not manipulate our control entries */ + if (ldb_dn_is_special(req->op.rename.newdn)) { + return ldb_next_request(module, req); } - ret = LDB_SUCCESS; - -done: - handle->state = LDB_ASYNC_DONE; - return ret; -} - -static int rdn_name_wait(struct ldb_handle *handle, enum ldb_wait_type type) -{ - int ret; - - if (!handle || !handle->private_data) { + ac = talloc_zero(req, struct rename_context); + if (ac == NULL) { return LDB_ERR_OPERATIONS_ERROR; } - if (type == LDB_WAIT_ALL) { - while (handle->state != LDB_ASYNC_DONE) { - ret = rdn_name_wait_once(handle); - if (ret != LDB_SUCCESS) { - return ret; - } - } + ac->module = module; + ac->req = req; - return handle->status; + ret = ldb_build_rename_req(&down_req, + module->ldb, + ac, + req->op.rename.olddn, + req->op.rename.newdn, + req->controls, + ac, + rdn_rename_callback, + req); + + if (ret != LDB_SUCCESS) { + return LDB_ERR_OPERATIONS_ERROR; } - return rdn_name_wait_once(handle); + /* rename first, modify "name" if rename is ok */ + return ldb_next_request(module, down_req); } const struct ldb_module_ops ldb_rdn_name_module_ops = { .name = "rdn_name", .add = rdn_name_add, .rename = rdn_name_rename, - .wait = rdn_name_wait }; diff --git a/source4/lib/ldb/modules/sort.c b/source4/lib/ldb/modules/sort.c index 746befa559..64d60f370c 100644 --- a/source4/lib/ldb/modules/sort.c +++ b/source4/lib/ldb/modules/sort.c @@ -1,7 +1,7 @@ /* ldb database library - Copyright (C) Simo Sorce 2005 + 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 @@ -43,8 +43,6 @@ struct opaque { struct sort_context { struct ldb_module *module; - void *up_context; - int (*up_callback)(struct ldb_context *, void *, struct ldb_reply *); char *attributeName; char *orderingRule; @@ -53,7 +51,6 @@ struct sort_context { struct ldb_request *req; struct ldb_message **msgs; char **referrals; - struct ldb_control **controls; int num_msgs; int num_refs; @@ -61,40 +58,6 @@ struct sort_context { int sort_result; }; -static struct ldb_handle *init_handle(void *mem_ctx, struct ldb_module *module, - void *context, - int (*callback)(struct ldb_context *, void *, struct ldb_reply *)) -{ - struct sort_context *ac; - struct ldb_handle *h; - - h = talloc_zero(mem_ctx, struct ldb_handle); - if (h == NULL) { - ldb_set_errstring(module->ldb, "Out of Memory"); - return NULL; - } - - h->module = module; - - ac = talloc_zero(h, struct sort_context); - if (ac == NULL) { - ldb_set_errstring(module->ldb, "Out of Memory"); - talloc_free(h); - return NULL; - } - - h->private_data = (void *)ac; - - h->state = LDB_ASYNC_INIT; - h->status = LDB_SUCCESS; - - ac->module = module; - ac->up_context = context; - ac->up_callback = callback; - - return h; -} - static int build_response(void *mem_ctx, struct ldb_control ***ctrls, int result, const char *desc) { struct ldb_control **controls; @@ -142,7 +105,7 @@ static int sort_compare(struct ldb_message **msg1, struct ldb_message **msg2, vo struct sort_context *ac = talloc_get_type(opaque, struct sort_context); struct ldb_message_element *el1, *el2; - if (ac->sort_result != 0) { + if (!ac || ac->sort_result != 0) { /* an error occurred previously, * let's exit the sorting by returning always 0 */ return 0; @@ -154,7 +117,7 @@ static int sort_compare(struct ldb_message **msg1, struct ldb_message **msg2, vo if (!el1 || !el2) { /* the attribute was not found return and * set an error */ - ac->sort_result = 53; + ac->sort_result = LDB_ERR_UNWILLING_TO_PERFORM; return 0; } @@ -164,51 +127,111 @@ static int sort_compare(struct ldb_message **msg1, struct ldb_message **msg2, vo return ac->a->syntax->comparison_fn(ac->module->ldb, ac, &el1->values[0], &el2->values[0]); } -static int server_sort_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) +static int server_sort_results(struct sort_context *ac) { - struct sort_context *ac = NULL; - - if (!context || !ares) { - ldb_set_errstring(ldb, "NULL Context or Result in callback"); - goto error; - } + struct ldb_reply *ares; + int i, ret; + + ac->a = ldb_schema_attribute_by_name(ac->module->ldb, ac->attributeName); + ac->sort_result = 0; + + ldb_qsort(ac->msgs, ac->num_msgs, + sizeof(struct ldb_message *), + ac, (ldb_qsort_cmp_fn_t)sort_compare); + + if (ac->sort_result != LDB_SUCCESS) { + return ac->sort_result; + } + + for (i = 0; i < ac->num_msgs; i++) { + ares = talloc_zero(ac, struct ldb_reply); + if (!ares) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ares->type = LDB_REPLY_ENTRY; + ares->message = talloc_move(ares, &ac->msgs[i]); + + ret = ldb_module_send_entry(ac->req, ares->message); + if (ret != LDB_SUCCESS) { + return ret; + } + } + + for (i = 0; i < ac->num_refs; i++) { + ares = talloc_zero(ac, struct ldb_reply); + if (!ares) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ares->type = LDB_REPLY_REFERRAL; + ares->referral = talloc_move(ares, &ac->referrals[i]); + + ret = ldb_module_send_referral(ac->req, ares->referral); + if (ret != LDB_SUCCESS) { + return ret; + } + } + + return LDB_SUCCESS; +} + +static int server_sort_search_callback(struct ldb_request *req, struct ldb_reply *ares) +{ + struct sort_context *ac; + int ret; - ac = talloc_get_type(context, struct sort_context); + ac = talloc_get_type(req->context, struct sort_context); - if (ares->type == LDB_REPLY_ENTRY) { + if (!ares) { + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); + } + if (ares->error != LDB_SUCCESS) { + return ldb_module_done(ac->req, ares->controls, + ares->response, ares->error); + } + + switch (ares->type) { + case LDB_REPLY_ENTRY: ac->msgs = talloc_realloc(ac, ac->msgs, struct ldb_message *, ac->num_msgs + 2); if (! ac->msgs) { - goto error; + talloc_free(ares); + ldb_oom(ac->module->ldb); + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); } - ac->msgs[ac->num_msgs + 1] = NULL; - - ac->msgs[ac->num_msgs] = talloc_move(ac->msgs, &ares->message); + ac->msgs[ac->num_msgs] = talloc_steal(ac->msgs, ares->message); ac->num_msgs++; - } + ac->msgs[ac->num_msgs] = NULL; - if (ares->type == LDB_REPLY_REFERRAL) { + break; + + case LDB_REPLY_REFERRAL: ac->referrals = talloc_realloc(ac, ac->referrals, char *, ac->num_refs + 2); if (! ac->referrals) { - goto error; + talloc_free(ares); + ldb_oom(ac->module->ldb); + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); } - ac->referrals[ac->num_refs + 1] = NULL; - ac->referrals[ac->num_refs] = talloc_move(ac->referrals, &ares->referral); - + ac->referrals[ac->num_refs] = talloc_steal(ac->referrals, ares->referral); ac->num_refs++; - } + ac->referrals[ac->num_refs] = NULL; - if (ares->type == LDB_REPLY_DONE) { - ac->controls = talloc_move(ac, &ares->controls); + break; + + case LDB_REPLY_DONE: + + ret = server_sort_results(ac); + return ldb_module_done(ac->req, ares->controls, + ares->response, ret); } talloc_free(ares); return LDB_SUCCESS; - -error: - talloc_free(ares); - return LDB_ERR_OPERATIONS_ERROR; } static int server_sort_search(struct ldb_module *module, struct ldb_request *req) @@ -216,8 +239,9 @@ static int server_sort_search(struct ldb_module *module, struct ldb_request *req struct ldb_control *control; struct ldb_server_sort_control **sort_ctrls; struct ldb_control **saved_controls; + struct ldb_control **controls; + struct ldb_request *down_req; struct sort_context *ac; - struct ldb_handle *h; int ret; /* check if there's a paged request control */ @@ -227,19 +251,14 @@ static int server_sort_search(struct ldb_module *module, struct ldb_request *req return ldb_next_request(module, req); } - req->handle = NULL; - - if (!req->callback || !req->context) { - ldb_set_errstring(module->ldb, - "Async interface called with NULL callback function or NULL context"); - return LDB_ERR_OPERATIONS_ERROR; - } - - h = init_handle(req, module, req->context, req->callback); - if (!h) { + ac = talloc_zero(req, struct sort_context); + if (ac == NULL) { + ldb_oom(module->ldb); return LDB_ERR_OPERATIONS_ERROR; } - ac = talloc_get_type(h->private_data, struct sort_context); + + ac->module = module; + ac->req = req; sort_ctrls = talloc_get_type(control->data, struct ldb_server_sort_control *); if (!sort_ctrls) { @@ -251,26 +270,20 @@ static int server_sort_search(struct ldb_module *module, struct ldb_request *req if (sort_ctrls[1] != NULL) { if (control->critical) { - struct ldb_reply *ares; - - ares = talloc_zero(req, struct ldb_reply); - if (!ares) - return LDB_ERR_OPERATIONS_ERROR; - /* 53 = unwilling to perform */ - ares->type = LDB_REPLY_DONE; - if ((ret = build_response(ares, &ares->controls, 53, "sort control is not complete yet")) != LDB_SUCCESS) { - return ret; + /* callback immediately */ + ret = build_response(req, &controls, + LDB_ERR_UNWILLING_TO_PERFORM, + "sort control is not complete yet"); + if (ret != LDB_SUCCESS) { + return ldb_module_done(req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); } - h->status = LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION; - h->state = LDB_ASYNC_DONE; - ret = ac->up_callback(module->ldb, ac->up_context, ares); - - return ret; + return ldb_module_done(req, controls, NULL, ret); } else { /* just pass the call down and don't do any sorting */ - ldb_next_request(module, req); + return ldb_next_request(module, req); } } @@ -278,181 +291,45 @@ static int server_sort_search(struct ldb_module *module, struct ldb_request *req ac->orderingRule = sort_ctrls[0]->orderingRule; ac->reverse = sort_ctrls[0]->reverse; - ac->req = talloc(req, struct ldb_request); - if (!ac->req) + ret = ldb_build_search_req_ex(&down_req, module->ldb, ac, + req->op.search.base, + req->op.search.scope, + req->op.search.tree, + req->op.search.attrs, + req->controls, + ac, + server_sort_search_callback, + req); + if (ret != LDB_SUCCESS) { return LDB_ERR_OPERATIONS_ERROR; - - ac->req->operation = req->operation; - ac->req->op.search.base = req->op.search.base; - ac->req->op.search.scope = req->op.search.scope; - ac->req->op.search.tree = req->op.search.tree; - ac->req->op.search.attrs = req->op.search.attrs; - ac->req->controls = req->controls; + } /* save it locally and remove it from the list */ /* we do not need to replace them later as we * are keeping the original req intact */ - if (!save_controls(control, ac->req, &saved_controls)) { + if (!save_controls(control, down_req, &saved_controls)) { return LDB_ERR_OPERATIONS_ERROR; } - ac->req->context = ac; - ac->req->callback = server_sort_search_callback; - ldb_set_timeout_from_prev_req(module->ldb, req, ac->req); - - req->handle = h; - - return ldb_next_request(module, ac->req); -} - -static int server_sort_results(struct ldb_handle *handle) -{ - struct sort_context *ac; - struct ldb_reply *ares; - int i, ret; - - ac = talloc_get_type(handle->private_data, struct sort_context); - - ac->a = ldb_schema_attribute_by_name(ac->module->ldb, ac->attributeName); - ac->sort_result = 0; - - ldb_qsort(ac->msgs, ac->num_msgs, - sizeof(struct ldb_message *), - ac, (ldb_qsort_cmp_fn_t)sort_compare); - - for (i = 0; i < ac->num_msgs; i++) { - ares = talloc_zero(ac, struct ldb_reply); - if (!ares) { - handle->status = LDB_ERR_OPERATIONS_ERROR; - return handle->status; - } - - ares->type = LDB_REPLY_ENTRY; - ares->message = talloc_move(ares, &ac->msgs[i]); - - handle->status = ac->up_callback(ac->module->ldb, ac->up_context, ares); - if (handle->status != LDB_SUCCESS) { - return handle->status; - } - } - - for (i = 0; i < ac->num_refs; i++) { - ares = talloc_zero(ac, struct ldb_reply); - if (!ares) { - handle->status = LDB_ERR_OPERATIONS_ERROR; - return handle->status; - } - - ares->type = LDB_REPLY_REFERRAL; - ares->referral = talloc_move(ares, &ac->referrals[i]); - - handle->status = ac->up_callback(ac->module->ldb, ac->up_context, ares); - if (handle->status != LDB_SUCCESS) { - return handle->status; - } - } - - ares = talloc_zero(ac, struct ldb_reply); - if (!ares) { - handle->status = LDB_ERR_OPERATIONS_ERROR; - return handle->status; - } - - ares->type = LDB_REPLY_DONE; - ares->controls = talloc_move(ares, &ac->controls); - - handle->status = ac->up_callback(ac->module->ldb, ac->up_context, ares); - if (handle->status != LDB_SUCCESS) { - return handle->status; - } - - if ((ret = build_response(ac, &ac->controls, ac->sort_result, "sort control is not complete yet")) != LDB_SUCCESS) { - return ret; - } - - return LDB_SUCCESS; -} - -static int server_sort_wait_once(struct ldb_handle *handle) -{ - struct sort_context *ac; - int ret; - - if (!handle || !handle->private_data) { - return LDB_ERR_OPERATIONS_ERROR; - } - - ac = talloc_get_type(handle->private_data, struct sort_context); - - ret = ldb_wait(ac->req->handle, LDB_WAIT_NONE); - - if (ret != LDB_SUCCESS) { - handle->status = ret; - return ret; - } - - handle->state = ac->req->handle->state; - handle->status = ac->req->handle->status; - - if (handle->status != LDB_SUCCESS) { - return handle->status; - } - - if (handle->state == LDB_ASYNC_DONE) { - ret = server_sort_results(handle); - } - - return ret; -} - -static int server_sort_wait(struct ldb_handle *handle, enum ldb_wait_type type) -{ - int ret; - - if (!handle || !handle->private_data) { - return LDB_ERR_OPERATIONS_ERROR; - } - - if (type == LDB_WAIT_ALL) { - while (handle->state != LDB_ASYNC_DONE) { - ret = server_sort_wait_once(handle); - if (ret != LDB_SUCCESS) { - return ret; - } - } - - return handle->status; - } - - return server_sort_wait_once(handle); + return ldb_next_request(module, down_req); } static int server_sort_init(struct ldb_module *module) { - struct ldb_request *req; int ret; - req = talloc(module, struct ldb_request); - if (req == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } - - req->operation = LDB_REQ_REGISTER_CONTROL; - req->op.reg_control.oid = LDB_CONTROL_SERVER_SORT_OID; - req->controls = NULL; - - ret = ldb_request(module->ldb, req); + ret = ldb_mod_register_control(module, LDB_CONTROL_SERVER_SORT_OID); if (ret != LDB_SUCCESS) { - ldb_debug(module->ldb, LDB_DEBUG_WARNING, "server_sort: Unable to register control with rootdse!\n"); + ldb_debug(module->ldb, LDB_DEBUG_WARNING, + "server_sort:" + "Unable to register control with rootdse!\n"); } - talloc_free(req); return ldb_next_init(module); } const struct ldb_module_ops ldb_server_sort_module_ops = { .name = "server_sort", .search = server_sort_search, - .wait = server_sort_wait, .init_context = server_sort_init }; diff --git a/source4/lib/ldb/tests/python/ldap.py b/source4/lib/ldb/tests/python/ldap.py index 6c910b63f1..e2cc658521 100755 --- a/source4/lib/ldb/tests/python/ldap.py +++ b/source4/lib/ldb/tests/python/ldap.py @@ -8,6 +8,7 @@ import sys import time sys.path.append("bin/python") +sys.path.append("../lib/subunit/python") import samba.getopt as options diff --git a/source4/lib/ldb/tools/ldbsearch.c b/source4/lib/ldb/tools/ldbsearch.c index b3d1f934a6..ceabd5cd78 100644 --- a/source4/lib/ldb/tools/ldbsearch.c +++ b/source4/lib/ldb/tools/ldbsearch.c @@ -56,6 +56,7 @@ static int do_compare_msg(struct ldb_message **el1, } struct search_context { + struct ldb_context *ldb; struct ldb_control **req_ctrls; int sort; @@ -101,7 +102,7 @@ static int store_referral(char *referral, struct search_context *sctx) { return 0; } -static int display_message(struct ldb_context *ldb, struct ldb_message *msg, struct search_context *sctx) { +static int display_message(struct ldb_message *msg, struct search_context *sctx) { struct ldb_ldif ldif; sctx->entries++; @@ -119,7 +120,7 @@ static int display_message(struct ldb_context *ldb, struct ldb_message *msg, str ldb_msg_sort_elements(ldif.msg); } - ldb_ldif_write_file(ldb, stdout, &ldif); + ldb_ldif_write_file(sctx->ldb, stdout, &ldif); return 0; } @@ -133,18 +134,26 @@ static int display_referral(char *referral, struct search_context *sctx) return 0; } -static int search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) +static int search_callback(struct ldb_request *req, struct ldb_reply *ares) { - struct search_context *sctx = talloc_get_type(context, struct search_context); + struct search_context *sctx; int ret; + + sctx = talloc_get_type(req->context, struct search_context); + + 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: if (sctx->sort) { ret = store_message(ares->message, sctx); } else { - ret = display_message(ldb, ares->message, sctx); + ret = display_message(ares->message, sctx); } break; @@ -154,6 +163,9 @@ static int search_callback(struct ldb_context *ldb, void *context, struct ldb_re } else { ret = display_referral(ares->referral, sctx); } + if (ret) { + return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR); + } break; case LDB_REPLY_DONE: @@ -161,22 +173,13 @@ static int search_callback(struct ldb_context *ldb, void *context, struct ldb_re if (handle_controls_reply(ares->controls, sctx->req_ctrls) == 1) sctx->pending = 1; } - ret = 0; - break; - - default: - fprintf(stderr, "unknown Reply Type\n"); - return LDB_ERR_OTHER; - } - - if (talloc_free(ares) == -1) { - fprintf(stderr, "talloc_free failed\n"); - sctx->pending = 0; - return LDB_ERR_OPERATIONS_ERROR; + talloc_free(ares); + return ldb_request_done(req, LDB_SUCCESS); } + talloc_free(ares); if (ret) { - return LDB_ERR_OPERATIONS_ERROR; + return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR); } return LDB_SUCCESS; @@ -192,12 +195,12 @@ static int do_search(struct ldb_context *ldb, struct search_context *sctx; int ret; - req = talloc(ldb, struct ldb_request); - if (!req) return -1; + req = NULL; - sctx = talloc(req, struct search_context); + sctx = talloc(ldb, struct search_context); if (!sctx) return -1; + sctx->ldb = ldb; sctx->sort = options->sorted; sctx->num_stored = 0; sctx->refs_stored = 0; @@ -214,18 +217,22 @@ static int do_search(struct ldb_context *ldb, basedn = ldb_get_default_basedn(ldb); } - req->operation = LDB_SEARCH; - req->op.search.base = basedn; - req->op.search.scope = options->scope; - req->op.search.tree = ldb_parse_tree(req, expression); - if (req->op.search.tree == NULL) return -1; - req->op.search.attrs = attrs; - req->controls = sctx->req_ctrls; - req->context = sctx; - req->callback = &search_callback; - ldb_set_timeout(ldb, req, 0); /* TODO: make this settable by command line */ - again: + /* free any previous requests */ + if (req) talloc_free(req); + + ret = ldb_build_search_req(&req, ldb, ldb, + basedn, options->scope, + expression, attrs, + sctx->req_ctrls, + sctx, search_callback, + NULL); + if (ret != LDB_SUCCESS) { + talloc_free(sctx); + printf("allocating request failed: %s\n", ldb_errstring(ldb)); + return -1; + } + sctx->pending = 0; ret = ldb_request(ldb, req); @@ -251,7 +258,7 @@ again: ldb, (ldb_qsort_cmp_fn_t)do_compare_msg); } for (i = 0; i < sctx->num_stored; i++) { - display_message(ldb, sctx->store[i], sctx); + display_message(sctx->store[i], sctx); } for (i = 0; i < sctx->refs_stored; i++) { @@ -262,6 +269,7 @@ again: printf("# returned %d records\n# %d entries\n# %d referrals\n", sctx->entries + sctx->refs, sctx->entries, sctx->refs); + talloc_free(sctx); talloc_free(req); return 0; |