diff options
author | Simo Sorce <ssorce@redhat.com> | 2009-06-24 16:40:56 -0400 |
---|---|---|
committer | Simo Sorce <ssorce@redhat.com> | 2009-07-03 11:07:36 -0400 |
commit | 94ec51d8b53f636d41a879ed1d0d39127168cb21 (patch) | |
tree | e6984ad304bf81781de2b118dac189db4bb0a582 /server/db | |
parent | 6aca93fb4d5d39a100b900a8c297d08629407960 (diff) | |
download | sssd-94ec51d8b53f636d41a879ed1d0d39127168cb21.tar.gz sssd-94ec51d8b53f636d41a879ed1d0d39127168cb21.tar.bz2 sssd-94ec51d8b53f636d41a879ed1d0d39127168cb21.zip |
Rework transaction code to use tevent_req
This is part of a set of patches to rewrite sysdb to a hopefully better
API, that will also let use use tevent_req async style calls to manipulate
our cache.
Diffstat (limited to 'server/db')
-rw-r--r-- | server/db/sysdb.c | 364 | ||||
-rw-r--r-- | server/db/sysdb.h | 371 | ||||
-rw-r--r-- | server/db/sysdb_ops.c | 3633 | ||||
-rw-r--r-- | server/db/sysdb_private.h | 25 | ||||
-rw-r--r-- | server/db/sysdb_req.c | 252 | ||||
-rw-r--r-- | server/db/sysdb_search.c | 122 |
6 files changed, 3137 insertions, 1630 deletions
diff --git a/server/db/sysdb.c b/server/db/sysdb.c index a86a966b..bb39c064 100644 --- a/server/db/sysdb.c +++ b/server/db/sysdb.c @@ -140,6 +140,46 @@ int sysdb_attrs_add_long(struct sysdb_attrs *attrs, return ret; } +int sysdb_attrs_add_uint32(struct sysdb_attrs *attrs, + const char *name, uint32_t value) +{ + unsigned long val = value; + struct ldb_val v; + char *str; + int ret; + + str = talloc_asprintf(attrs, "%lu", val); + if (!str) return ENOMEM; + + v.data = (uint8_t *)str; + v.length = strlen(str); + + ret = sysdb_attrs_add_val(attrs, name, &v); + talloc_free(str); + + return ret; +} + +int sysdb_attrs_add_time_t(struct sysdb_attrs *attrs, + const char *name, time_t value) +{ + long long val = value; + struct ldb_val v; + char *str; + int ret; + + str = talloc_asprintf(attrs, "%lld", val); + if (!str) return ENOMEM; + + v.data = (uint8_t *)str; + v.length = strlen(str); + + ret = sysdb_attrs_add_val(attrs, name, &v); + talloc_free(str); + + return ret; +} + /* TODO: make a more complete and precise mapping */ int sysdb_error_to_errno(int ldberr) { @@ -159,9 +199,327 @@ int sysdb_error_to_errno(int ldberr) } } -/************************************************ - * Initialiazation stuff - */ +/* =Internal-Operations-Queue============================================= */ + +static void sysdb_run_operation(struct tevent_context *ev, + struct tevent_timer *te, + struct timeval tv, void *pvt) +{ + struct sysdb_handle *handle = talloc_get_type(pvt, struct sysdb_handle); + + tevent_req_done(handle->subreq); +} + +static void sysdb_schedule_operation(struct sysdb_handle *handle) +{ + struct timeval tv = { 0, 0 }; + struct tevent_timer *te; + + te = tevent_add_timer(handle->ctx->ev, handle, tv, + sysdb_run_operation, handle); + if (!te) { + DEBUG(1, ("Failed to add critical timer to run next handle!\n")); + } +} + +static int sysdb_handle_destructor(void *mem) +{ + struct sysdb_handle *handle = talloc_get_type(mem, struct sysdb_handle); + bool start_next = false; + int ret; + + /* if this was the current op start next */ + if (handle->ctx->queue == handle) { + start_next = true; + } + + DLIST_REMOVE(handle->ctx->queue, handle); + + if (start_next && handle->ctx->queue) { + /* run next */ + sysdb_schedule_operation(handle->ctx->queue); + } + + if (handle->transaction_active) { + ret = ldb_transaction_cancel(handle->ctx->ldb); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Failed to cancel ldb transaction! (%d)\n", ret)); + } + /* FIXME: abort() ? */ + handle->transaction_active = false; + } + + return 0; +} + +struct sysdb_get_handle_state { + struct tevent_context *ev; + struct sysdb_ctx *ctx; + + struct sysdb_handle *handle; +}; + +struct tevent_req *sysdb_get_handle_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_ctx *ctx) +{ + struct tevent_req *req; + struct sysdb_get_handle_state *state; + struct sysdb_handle *handle; + + req = tevent_req_create(mem_ctx, &state, struct sysdb_get_handle_state); + if (!req) return NULL; + + state->ev = ev; + state->ctx = ctx; + + handle = talloc_zero(state, struct sysdb_handle); + if (!handle) { + talloc_zfree(req); + return NULL; + } + + handle->ctx = ctx; + handle->subreq = req; + + talloc_set_destructor((TALLOC_CTX *)handle, sysdb_handle_destructor); + + DLIST_ADD_END(ctx->queue, handle, struct sysdb_handle *); + + if (ctx->queue == handle) { + /* this is the first in the queue, schedule an immediate run */ + sysdb_schedule_operation(handle); + } + + state->handle = handle; + + return req; +} + +static int sysdb_get_handle_recv(struct tevent_req *req, TALLOC_CTX *memctx, + struct sysdb_handle **handle) +{ + struct sysdb_get_handle_state *state = tevent_req_data(req, + struct sysdb_get_handle_state); + enum tevent_req_state tstate; + uint64_t err; + + if (tevent_req_is_error(req, &tstate, &err)) { + return err; + } + + *handle = talloc_steal(memctx, state->handle); + if (!*handle) return ENOMEM; + + return EOK; +} + +/* =Transactions========================================================== */ + +struct sysdb_transaction_state { + struct tevent_context *ev; + struct sysdb_ctx *ctx; + + struct sysdb_handle *handle; +}; + +static void sysdb_transaction_done(struct tevent_req *subreq); + +struct tevent_req *sysdb_transaction_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_ctx *ctx) +{ + struct tevent_req *req, *subreq; + struct sysdb_transaction_state *state; + + req = tevent_req_create(mem_ctx, &state, struct sysdb_transaction_state); + if (!req) return NULL; + + state->ev = ev; + state->ctx = ctx; + + subreq = sysdb_get_handle_send(state, ev, ctx); + if (!subreq) { + talloc_zfree(req); + return NULL; + } + + tevent_req_set_callback(subreq, sysdb_transaction_done, req); + + return req; +} + +static void sysdb_transaction_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_transaction_state *state = tevent_req_data(req, + struct sysdb_transaction_state); + int ret; + + ret = sysdb_get_handle_recv(subreq, state, &state->handle); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } + + ret = ldb_transaction_start(state->ctx->ldb); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Failed to start ldb transaction! (%d)\n", ret)); + tevent_req_error(req, sysdb_error_to_errno(ret)); + return; + } + state->handle->transaction_active = true; + + tevent_req_done(req); +} + +int sysdb_transaction_recv(struct tevent_req *req, TALLOC_CTX *memctx, + struct sysdb_handle **handle) +{ + struct sysdb_transaction_state *state = tevent_req_data(req, + struct sysdb_transaction_state); + enum tevent_req_state tstate; + uint64_t err; + + if (tevent_req_is_error(req, &tstate, &err)) { + return err; + } + + *handle = talloc_steal(memctx, state->handle); + if (!*handle) return ENOMEM; + + return EOK; +} + +struct tevent_req *sysdb_transaction_commit_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle) +{ + struct tevent_req *req; + struct sysdb_transaction_state *state; + int ret; + + req = tevent_req_create(mem_ctx, &state, struct sysdb_transaction_state); + if (!req) return NULL; + + state->ev = ev; + state->ctx = handle->ctx; + state->handle = handle; + + ret = ldb_transaction_commit(handle->ctx->ldb); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Failed to commit ldb transaction! (%d)\n", ret)); + tevent_req_error(req, sysdb_error_to_errno(ret)); + } + handle->transaction_active = false; + + /* the following may seem weird but it is actually fine. + * _done() will not actually call the callback as it will not be set + * until we return. But it will mark the request as done. + * _post() will trigger the callback as it schedules after we returned + * and actually set the callback */ + tevent_req_done(req); + tevent_req_post(req, ev); + return req; +} + +int sysdb_transaction_commit_recv(struct tevent_req *req) +{ + struct sysdb_transaction_state *state = tevent_req_data(req, + struct sysdb_transaction_state); + enum tevent_req_state tstate; + uint64_t err; + + /* finally free handle + * this will also trigger the next transaction in the queue if any */ + talloc_free(state->handle); + + if (tevent_req_is_error(req, &tstate, &err)) { + return err; + } + + return EOK; +} + +/* =Operations============================================================ */ + +struct sysdb_operation_state { + struct tevent_context *ev; + struct sysdb_ctx *ctx; + + struct sysdb_handle *handle; +}; + +static void sysdb_operation_process(struct tevent_req *subreq); + +struct tevent_req *sysdb_operation_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_ctx *ctx) +{ + struct tevent_req *req, *subreq; + struct sysdb_operation_state *state; + + req = tevent_req_create(mem_ctx, &state, struct sysdb_operation_state); + if (!req) return NULL; + + state->ev = ev; + state->ctx = ctx; + + subreq = sysdb_get_handle_send(state, ev, ctx); + if (!subreq) { + talloc_zfree(req); + return NULL; + } + + tevent_req_set_callback(subreq, sysdb_operation_process, req); + + return req; +} + +static void sysdb_operation_process(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_operation_state *state = tevent_req_data(req, + struct sysdb_operation_state); + int ret; + + ret = sysdb_get_handle_recv(subreq, state, &state->handle); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } + + tevent_req_done(req); +} + +int sysdb_operation_recv(struct tevent_req *req, TALLOC_CTX *memctx, + struct sysdb_handle **handle) +{ + struct sysdb_operation_state *state = tevent_req_data(req, + struct sysdb_operation_state); + enum tevent_req_state tstate; + uint64_t err; + + if (tevent_req_is_error(req, &tstate, &err)) { + return err; + } + + *handle = talloc_steal(memctx, state->handle); + if (!*handle) return ENOMEM; + + return EOK; +} + +void sysdb_operation_done(struct sysdb_handle *handle) +{ + talloc_free(handle); +} + +/* =Initialization======================================================== */ static int sysdb_read_var(TALLOC_CTX *mem_ctx, struct confdb_ctx *cdb, diff --git a/server/db/sysdb.h b/server/db/sysdb.h index 6da83318..2696dfaf 100644 --- a/server/db/sysdb.h +++ b/server/db/sysdb.h @@ -23,6 +23,7 @@ #define __SYS_DB_H__ #include "confdb/confdb.h" +#include <tevent.h> #define SYSDB_CONF_SECTION "config/sysdb" #define SYSDB_FILE "sssd.ldb" @@ -88,8 +89,6 @@ #define SYSDB_GETCACHED_FILTER "(&"SYSDB_UC")("SYSDB_LAST_LOGIN">=%lu))" -#define SYSDB_CHECK_FILTER "(&(|("SYSDB_UC")("SYSDB_GC"))("SYSDB_NAME"=%s))" - #define SYSDB_PW_ATTRS {SYSDB_NAME, SYSDB_UIDNUM, \ SYSDB_GIDNUM, SYSDB_GECOS, \ SYSDB_HOMEDIR, SYSDB_SHELL, \ @@ -125,6 +124,10 @@ #define SYSDB_TMPL_USER SYSDB_NAME"=%s,"SYSDB_TMPL_USER_BASE #define SYSDB_TMPL_GROUP SYSDB_NAME"=%s,"SYSDB_TMPL_GROUP_BASE +#define SYSDB_MOD_ADD LDB_FLAG_MOD_ADD +#define SYSDB_MOD_DEL LDB_FLAG_MOD_DELETE +#define SYSDB_MOD_REP LDB_FLAG_MOD_REPLACE + struct confdb_ctx; struct sysdb_ctx; struct sysdb_handle; @@ -142,40 +145,15 @@ int sysdb_attrs_add_string(struct sysdb_attrs *attrs, const char *name, const char *str); int sysdb_attrs_add_long(struct sysdb_attrs *attrs, const char *name, long value); +int sysdb_attrs_add_uint32(struct sysdb_attrs *attrs, + const char *name, uint32_t value); +int sysdb_attrs_add_time_t(struct sysdb_attrs *attrs, + const char *name, time_t value); /* convert an ldb error into an errno error */ int sysdb_error_to_errno(int ldberr); -/* callbacks */ -typedef void (*sysdb_callback_t)(void *, int, struct ldb_result *); -typedef void (*sysdb_fn_t)(struct sysdb_handle *, void *pvt); - -/* service functions */ -struct ldb_context *sysdb_ctx_get_ldb(struct sysdb_ctx *ctx); -struct sysdb_ctx *sysdb_handle_get_ctx(struct sysdb_handle *req); - -/* function to start and finish a transaction - * After sysdb_transaction() is successfully called, - * it *MUST* be closed with a call to sysdb_transaction_done() - * if error is == 0 the transaction is committed otherwise it - * is canceled and all modifications to the db are thrown away - * - * Transactions are serialized, no other transaction or operation can be - * performed while a transaction is active. - */ -int sysdb_transaction(TALLOC_CTX *mem_ctx, - struct sysdb_ctx *ctx, - sysdb_fn_t fn, void *pvt); -void sysdb_transaction_done(struct sysdb_handle *req, int error); - -/* An operation blocks the transaction queue as well, but does not - * start a transaction, normally useful only for search type calls. - * Cannot be called within a transaction */ -int sysdb_operation(TALLOC_CTX *mem_ctx, - struct sysdb_ctx *ctx, - sysdb_fn_t fn, void *pvt); -void sysdb_operation_done(struct sysdb_handle *req); - +/* DNs related helper functions */ struct ldb_dn *sysdb_user_dn(struct sysdb_ctx *ctx, void *memctx, const char *domain, const char *name); struct ldb_dn *sysdb_group_dn(struct sysdb_ctx *ctx, void *memctx, @@ -183,12 +161,44 @@ struct ldb_dn *sysdb_group_dn(struct sysdb_ctx *ctx, void *memctx, struct ldb_dn *sysdb_domain_dn(struct sysdb_ctx *ctx, void *memctx, const char *domain); +/* function to start and finish a transaction + * sysdb_transaction_send() will queue a request for a transaction + * when it is done it will call the tevent_req callback, which must + * retrieve the transaction handle using sysdb_transaction_recv() + * + * A transaction must be completed either by sending a commit: + * sysdb_transaction_commit_send()/sysdb_transaction_commit_recv() + * or by freeing the transaction handle (this will implicitly cause + * a transaction cancelation). + * + * Transactions are serialized, no other transaction or operation can be + * performed while a transaction is active. Multiple transaction request + * are queued internally and served in order. + */ + +struct tevent_req *sysdb_transaction_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_ctx *ctx); +int sysdb_transaction_recv(struct tevent_req *req, TALLOC_CTX *memctx, + struct sysdb_handle **handle); + +struct tevent_req *sysdb_transaction_commit_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle); +int sysdb_transaction_commit_recv(struct tevent_req *req); + +/* Sysdb initialization. + * call this function *only* once to initialize the database and get + * the sysdb ctx */ int sysdb_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct confdb_ctx *cdb, const char *alt_db_path, struct sysdb_ctx **dbctx); +/* FIXME: REMOVE */ +typedef void (*sysdb_callback_t)(void *, int, struct ldb_result *); + /* functions to retrieve information from sysdb * These functions automatically starts an operation * therefore they cannot be called within a transaction */ @@ -243,84 +253,233 @@ int sysdb_get_user_attr(TALLOC_CTX *mem_ctx, /* functions that modify the databse * they have to be called within a transaction - * See sysdb_transaction() */ -int sysdb_add_group_member(struct sysdb_handle *handle, - struct ldb_dn *member_dn, - struct ldb_dn *group_dn, - sysdb_callback_t fn, void *pvt); - -int sysdb_remove_group_member(struct sysdb_handle *handle, - struct ldb_dn *member_dn, - struct ldb_dn *group_dn, - sysdb_callback_t fn, void *pvt); - -int sysdb_delete_entry(struct sysdb_handle *handle, - struct ldb_dn *dn, - sysdb_callback_t fn, void *pvt); - -int sysdb_delete_user_by_uid(struct sysdb_handle *handle, - struct sss_domain_info *domain, - uid_t uid, - sysdb_callback_t fn, void *pvt); - -int sysdb_delete_group_by_gid(struct sysdb_handle *handle, - struct sss_domain_info *domain, - gid_t gid, - sysdb_callback_t fn, void *pvt); - -int sysdb_set_user_attr(struct sysdb_handle *handle, - struct sss_domain_info *domain, - const char *name, - struct sysdb_attrs *attributes, - sysdb_callback_t fn, void *ptr); - -int sysdb_add_user(struct sysdb_handle *handle, - struct sss_domain_info *domain, - const char *name, - uid_t uid, gid_t gid, const char *fullname, - const char *homedir, const char *shell, - sysdb_callback_t fn, void *pvt); - -int sysdb_add_group(struct sysdb_handle *handle, - struct sss_domain_info *domain, - const char *name, gid_t gid, - sysdb_callback_t fn, void *pvt); + * See sysdb_transaction_send()/_recv() */ + +/* Delete Entry */ +struct tevent_req *sysdb_delete_entry_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct ldb_dn *dn); +int sysdb_delete_entry_recv(struct tevent_req *req); + +/* Search Entry */ +struct tevent_req *sysdb_search_entry_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct ldb_dn *base_dn, + const char *filter, + const char **attrs); +int sysdb_search_entry_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + struct ldb_message **msg); + +/* Search User (by uid or name) */ +struct tevent_req *sysdb_search_user_by_name_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name); +struct tevent_req *sysdb_search_user_by_uid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + uid_t uid); +int sysdb_search_user_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + struct ldb_message **msg); + +/* Delete User by uid */ +struct tevent_req *sysdb_delete_user_by_uid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + uid_t uid); +int sysdb_delete_user_by_uid_recv(struct tevent_req *req); + +/* Search Group (gy gid or name) */ +struct tevent_req *sysdb_search_group_by_name_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name); +struct tevent_req *sysdb_search_group_by_gid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + gid_t gid); +int sysdb_search_group_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + struct ldb_message **msg); + +/* Delete group by gid */ +struct tevent_req *sysdb_delete_group_by_gid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + gid_t gid); +int sysdb_delete_group_by_gid_recv(struct tevent_req *req); + +/* Replace entry attrs */ +struct tevent_req *sysdb_set_entry_attr_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct ldb_dn *entry_dn, + struct sysdb_attrs *attrs, + int mod_op); +int sysdb_set_entry_attr_recv(struct tevent_req *req); + +/* Replace user attrs */ +struct tevent_req *sysdb_set_user_attr_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name, + struct sysdb_attrs *attrs, + int mod_op); +int sysdb_set_user_attr_recv(struct tevent_req *req); + +/* Replace group attrs */ +struct tevent_req *sysdb_set_group_attr_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name, + struct sysdb_attrs *attrs, + int mod_op); +int sysdb_set_group_attr_recv(struct tevent_req *req); + +/* Allocate a new id */ +struct tevent_req *sysdb_get_new_id_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain); +int sysdb_get_new_id_recv(struct tevent_req *req, uint32_t *id); + +/* Add user (only basic attrs and w/o checks) */ +struct tevent_req *sysdb_add_basic_user_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name, + uid_t uid, gid_t gid, + const char *gecos, + const char *homedir, + const char *shell); +int sysdb_add_basic_user_recv(struct tevent_req *req); + +/* Add user (all checks) */ +struct tevent_req *sysdb_add_user_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name, + uid_t uid, gid_t gid, + const char *gecos, + const char *homedir, + const char *shell, + struct sysdb_attrs *attrs); +int sysdb_add_user_recv(struct tevent_req *req); + +/* Add group (only basic attrs and w/o checks) */ +struct tevent_req *sysdb_add_basic_group_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name, gid_t gid); +int sysdb_add_basic_group_recv(struct tevent_req *req); + +/* Add group (all checks) */ +struct tevent_req *sysdb_add_group_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name, gid_t gid, + struct sysdb_attrs *attrs); +int sysdb_add_group_recv(struct tevent_req *req); + +/* mod_op must be either LDB_FLAG_MOD_ADD or LDB_FLAG_MOD_DELETE */ +struct tevent_req *sysdb_mod_group_member_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct ldb_dn *member_dn, + struct ldb_dn *group_dn, + int mod_op); +int sysdb_mod_group_member_recv(struct tevent_req *req); int sysdb_set_group_gid(struct sysdb_handle *handle, struct sss_domain_info *domain, const char *name, gid_t gid, sysdb_callback_t fn, void *pvt); -/* legacy functions for proxy providers */ - -int sysdb_legacy_store_user(struct sysdb_handle *handle, - struct sss_domain_info *domain, - const char *name, const char *pwd, - uid_t uid, gid_t gid, const char *gecos, - const char *homedir, const char *shell, - sysdb_callback_t fn, void *pvt); - -int sysdb_legacy_store_group(struct sysdb_handle *handle, - struct sss_domain_info *domain, - const char *name, gid_t gid, - const char **members, - sysdb_callback_t fn, void *pvt); - -int sysdb_legacy_add_group_member(struct sysdb_handle *handle, - struct sss_domain_info *domain, - const char *group, - const char *member, - sysdb_callback_t fn, void *pvt); - -int sysdb_legacy_remove_group_member(struct sysdb_handle *handle, - struct sss_domain_info *domain, - const char *group, - const char *member, - sysdb_callback_t fn, void *pvt); - -int sysdb_set_cached_password(struct sysdb_handle *handle, - struct sss_domain_info *domain, - const char *user, - const char *password, - sysdb_callback_t fn, void *pvt); +struct tevent_req *sysdb_store_user_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name, + const char *pwd, + uid_t uid, gid_t gid, + const char *gecos, + const char *homedir, + const char *shell); +int sysdb_store_user_recv(struct tevent_req *req); + +struct tevent_req *sysdb_store_group_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name, + gid_t gid, + const char **members); +int sysdb_store_group_recv(struct tevent_req *req); + +struct tevent_req *sysdb_add_group_member_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *group, + const char *member); +int sysdb_add_group_member_recv(struct tevent_req *req); + +struct tevent_req *sysdb_remove_group_member_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *group, + const char *member); +int sysdb_remove_group_member_recv(struct tevent_req *req); + +struct tevent_req *sysdb_set_cached_password_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *user, + const char *password); +int sysdb_set_cached_password_recv(struct tevent_req *req); + +/* TODO: remove later + * These functions are available in the latest tevent and are the ones that + * should be used as tevent_req is rightfully opaque there */ +#ifndef tevent_req_data +#define tevent_req_data(req, type) ((type *)req->private_state) +#endif + +#ifndef tevent_req_set_callback +#define tevent_req_set_callback(req, func, data) \ + do { req->async.fn = func; req->async.private_data = data; } while(0) +#endif + +#ifndef tevent_req_callback_data +#define tevent_req_callback_data(req, type) ((type *)req->async.private_data) +#endif + +#ifndef tevent_req_notify_callback +#define tevent_req_notify_callback(req) \ + do { \ + if (req->async.fn != NULL) { \ + req->async.fn(req); \ + } \ + } while(0) +#endif + + #endif /* __SYS_DB_H__ */ diff --git a/server/db/sysdb_ops.c b/server/db/sysdb_ops.c index 9b3f2828..785ce15e 100644 --- a/server/db/sysdb_ops.c +++ b/server/db/sysdb_ops.c @@ -24,25 +24,6 @@ #include "util/nss_sha512crypt.h" #include <time.h> -struct sysdb_cb_ctx { - sysdb_callback_t fn; - void *pvt; - - bool ignore_not_found; -}; - -static int sysdb_ret_error(struct sysdb_cb_ctx *ctx, int ret, int lret) -{ - ctx->fn(ctx->pvt, ret, NULL); - return lret; -}; - -static int sysdb_ret_done(struct sysdb_cb_ctx *ctx) -{ - ctx->fn(ctx->pvt, EOK, NULL); - return LDB_SUCCESS; -}; - static int add_string(struct ldb_message *msg, int flags, const char *attr, const char *value) { @@ -51,8 +32,9 @@ static int add_string(struct ldb_message *msg, int flags, ret = ldb_msg_add_empty(msg, attr, flags, NULL); if (ret == LDB_SUCCESS) { ret = ldb_msg_add_string(msg, attr, value); + if (ret == LDB_SUCCESS) return EOK; } - return ret; + return ENOMEM; } static int add_ulong(struct ldb_message *msg, int flags, @@ -63,8 +45,9 @@ static int add_ulong(struct ldb_message *msg, int flags, ret = ldb_msg_add_empty(msg, attr, flags, NULL); if (ret == LDB_SUCCESS) { ret = ldb_msg_add_fmt(msg, attr, "%lu", value); + if (ret == LDB_SUCCESS) return EOK; } - return ret; + return ENOMEM; } static uint32_t get_attr_as_uint32(struct ldb_message *msg, const char *attr) @@ -89,1798 +72,2948 @@ static uint32_t get_attr_as_uint32(struct ldb_message *msg, const char *attr) return l; } -static int sysdb_op_callback(struct ldb_request *req, struct ldb_reply *rep) +#define ERROR_OUT(v, r, l) do { v = r; goto l; } while(0); + +/* =LDB-Request-(tevent_req-style)======================================== */ + +struct sldb_request_state { + struct tevent_context *ev; + struct ldb_context *ldbctx; + struct ldb_request *ldbreq; + struct ldb_reply *ldbreply; +}; + +static void sldb_request_wakeup(struct tevent_req *subreq); +static int sldb_request_callback(struct ldb_request *ldbreq, + struct ldb_reply *ldbreply); + +static struct tevent_req *sldb_request_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct ldb_context *ldbctx, + struct ldb_request *ldbreq) { - struct sysdb_cb_ctx *cbctx; - int err; + struct tevent_req *req, *subreq; + struct sldb_request_state *state; + struct timeval tv = { 0, 0 }; - cbctx = talloc_get_type(req->context, struct sysdb_cb_ctx); + req = tevent_req_create(mem_ctx, &state, struct sldb_request_state); + if (!req) return NULL; - if (!rep) { - return sysdb_ret_error(cbctx, EIO, LDB_ERR_OPERATIONS_ERROR); - } - if (rep->error != LDB_SUCCESS) { - if (! (cbctx->ignore_not_found && - rep->error == LDB_ERR_NO_SUCH_OBJECT)) { - err = sysdb_error_to_errno(rep->error); - return sysdb_ret_error(cbctx, err, rep->error); - } - } + state->ev = ev; + state->ldbctx = ldbctx; + state->ldbreq = ldbreq; + state->ldbreply = NULL; - if (rep->type != LDB_REPLY_DONE) { - sysdb_ret_error(cbctx, EINVAL, LDB_ERR_OPERATIONS_ERROR); + subreq = tevent_wakeup_send(state, ev, tv); + if (!subreq) { + DEBUG(1, ("Failed to add critical timer to run next ldb operation!\n")); + talloc_zfree(req); + return NULL; } + tevent_req_set_callback(subreq, sldb_request_wakeup, req); - return sysdb_ret_done(cbctx); + return req; } -int sysdb_add_group_member(struct sysdb_handle *handle, - struct ldb_dn *member_dn, - struct ldb_dn *group_dn, - sysdb_callback_t fn, void *pvt) +static void sldb_request_wakeup(struct tevent_req *subreq) { - struct sysdb_ctx *ctx; - struct sysdb_cb_ctx *cbctx; - struct ldb_request *req; - struct ldb_message *msg; - const char *dn; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sldb_request_state *state = tevent_req_data(req, + struct sldb_request_state); int ret; - if (!sysdb_handle_check_running(handle)) { - DEBUG(2, ("Invalid request! Not running at this time.\n")); - return EINVAL; - } - - ctx = sysdb_handle_get_ctx(handle); + if (!tevent_wakeup_recv(subreq)) return; + talloc_zfree(subreq); - cbctx = talloc_zero(handle, struct sysdb_cb_ctx); - if (!cbctx) return ENOMEM; + state->ldbreq->callback = sldb_request_callback; + state->ldbreq->context = req; - cbctx->fn = fn; - cbctx->pvt = pvt; + ret = ldb_request(state->ldbctx, state->ldbreq); + if (ret != LDB_SUCCESS) { + tevent_req_error(req, sysdb_error_to_errno(ret)); + } +} - /* Add the member_dn as a member of the group */ - msg = ldb_msg_new(cbctx); - if(msg == NULL) return ENOMEM; +static int sldb_request_callback(struct ldb_request *ldbreq, + struct ldb_reply *ldbreply) +{ + struct tevent_req *req = talloc_get_type(ldbreq->context, + struct tevent_req); + struct sldb_request_state *state = tevent_req_data(req, + struct sldb_request_state); + int err; - msg->dn = group_dn; - ret = ldb_msg_add_empty(msg, SYSDB_MEMBER, - LDB_FLAG_MOD_ADD, NULL); - if (ret != LDB_SUCCESS) return ENOMEM; + if (!ldbreply) { + ERROR_OUT(err, EIO, fail); + } - dn = ldb_dn_get_linearized(member_dn); - if (!dn) return EINVAL; + state->ldbreply = talloc_steal(state, ldbreply); - ret = ldb_msg_add_fmt(msg, SYSDB_MEMBER, "%s", dn); - if (ret != LDB_SUCCESS) return EINVAL; + if (ldbreply->error != LDB_SUCCESS) { + ERROR_OUT(err, sysdb_error_to_errno(ldbreply->error), fail); + } - ret = ldb_build_mod_req(&req, ctx->ldb, cbctx, msg, - NULL, cbctx, sysdb_op_callback, NULL); - if (ret != LDB_SUCCESS) { - DEBUG(1, ("Failed to build modify request: %s(%d)[%s]\n", - ldb_strerror(ret), ret, ldb_errstring(ctx->ldb))); - return sysdb_error_to_errno(ret); + if (ldbreply->type == LDB_REPLY_DONE) { + tevent_req_done(req); + return EOK; } - ret = ldb_request(ctx->ldb, req); - if (ret != LDB_SUCCESS) return sysdb_error_to_errno(ret); + tevent_req_notify_callback(req); + return EOK; +fail: + tevent_req_error(req, err); return EOK; } -int sysdb_remove_group_member(struct sysdb_handle *handle, - struct ldb_dn *member_dn, - struct ldb_dn *group_dn, - sysdb_callback_t fn, void *pvt) +static int sldb_request_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + struct ldb_reply **ldbreply) { - struct sysdb_ctx *ctx; - struct sysdb_cb_ctx *cbctx; - struct ldb_request *req; - struct ldb_message *msg; - const char *dn; - int ret; + struct sldb_request_state *state = tevent_req_data(req, + struct sldb_request_state); + enum tevent_req_state tstate; + uint64_t err = 0; - if (!sysdb_handle_check_running(handle)) { - DEBUG(2, ("Invalid request! Not running at this time.\n")); - return EINVAL; + if (state->ldbreply) { + *ldbreply = talloc_move(mem_ctx, &state->ldbreply); } - ctx = sysdb_handle_get_ctx(handle); + if (tevent_req_is_error(req, &tstate, &err)) { + if (err != 0) return err; + if (tstate == TEVENT_REQ_IN_PROGRESS) return EOK; + return EIO; + } - cbctx = talloc_zero(handle, struct sysdb_cb_ctx); - if (!cbctx) return ENOMEM; + return EOK; +} - cbctx->fn = fn; - cbctx->pvt = pvt; +/* =Standard-Sysdb-Operations-utility-functions=========================== */ - /* Add the member_dn as a member of the group */ - msg = ldb_msg_new(cbctx); - if(msg == NULL) return ENOMEM; +struct sysdb_op_state { + struct tevent_context *ev; + struct sysdb_handle *handle; - msg->dn = group_dn; - ret = ldb_msg_add_empty(msg, SYSDB_MEMBER, - LDB_FLAG_MOD_DELETE, NULL); - if (ret != LDB_SUCCESS) return ENOMEM; + bool ignore_not_found; - dn = ldb_dn_get_linearized(member_dn); - if (!dn) return EINVAL; + struct ldb_reply *ldbreply; +}; - ret = ldb_msg_add_fmt(msg, SYSDB_MEMBER, "%s", dn); - if (ret != LDB_SUCCESS) return EINVAL; +static void sysdb_op_default_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_op_state *state = tevent_req_data(req, + struct sysdb_op_state); + int ret; - ret = ldb_build_mod_req(&req, ctx->ldb, cbctx, msg, - NULL, cbctx, sysdb_op_callback, NULL); - if (ret != LDB_SUCCESS) { - DEBUG(1, ("Failed to build modify request: %s(%d)[%s]\n", - ldb_strerror(ret), ret, ldb_errstring(ctx->ldb))); - return sysdb_error_to_errno(ret); + ret = sldb_request_recv(subreq, state, &state->ldbreply); + talloc_zfree(subreq); + if (ret) { + if (state->ignore_not_found && ret == ENOENT) { + goto done; + } + tevent_req_error(req, ret); + return; } - ret = ldb_request(ctx->ldb, req); - if (ret != LDB_SUCCESS) return sysdb_error_to_errno(ret); + if (state->ldbreply->type != LDB_REPLY_DONE) { + tevent_req_error(req, EIO); + return; + } - return EOK; +done: + tevent_req_done(req); } -int sysdb_delete_entry(struct sysdb_handle *handle, - struct ldb_dn *dn, - sysdb_callback_t fn, void *pvt) +static int sysdb_op_default_recv(struct tevent_req *req) { - struct sysdb_ctx *ctx; - struct sysdb_cb_ctx *cbctx; - struct ldb_request *req; - int ret; + enum tevent_req_state tstate; + uint64_t err; - if (!sysdb_handle_check_running(handle)) { - DEBUG(2, ("Invalid request! Not running at this time.\n")); - return EINVAL; + if (tevent_req_is_error(req, &tstate, &err)) { + return err; } - ctx = sysdb_handle_get_ctx(handle); + return EOK; +} + - cbctx = talloc_zero(handle, struct sysdb_cb_ctx); - if (!cbctx) return ENOMEM; +/* =Remove-Entry-From-Sysdb=============================================== */ - cbctx->fn = fn; - cbctx->pvt = pvt; - cbctx->ignore_not_found = true; +struct tevent_req *sysdb_delete_entry_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct ldb_dn *dn) +{ + struct tevent_req *req, *subreq; + struct sysdb_op_state *state; + struct ldb_request *ldbreq; + int ret; + + req = tevent_req_create(mem_ctx, &state, struct sysdb_op_state); + if (!req) return NULL; + + state->ev = ev; + state->handle = handle; + state->ignore_not_found = true; + state->ldbreply = NULL; - ret = ldb_build_del_req(&req, ctx->ldb, cbctx, dn, NULL, - cbctx, sysdb_op_callback, NULL); + ret = ldb_build_del_req(&ldbreq, handle->ctx->ldb, state, dn, + NULL, NULL, NULL, NULL); if (ret != LDB_SUCCESS) { DEBUG(1, ("LDB Error: %s(%d)\nError Message: [%s]\n", - ldb_strerror(ret), ret, ldb_errstring(ctx->ldb))); - return sysdb_error_to_errno(ret); + ldb_strerror(ret), ret, ldb_errstring(handle->ctx->ldb))); + ERROR_OUT(ret, sysdb_error_to_errno(ret), fail); } - ret = ldb_request(ctx->ldb, req); - if (ret != LDB_SUCCESS) return sysdb_error_to_errno(ret); + subreq = sldb_request_send(state, ev, handle->ctx->ldb, ldbreq); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); + } + tevent_req_set_callback(subreq, sysdb_op_default_done, req); - return EOK; + return req; + +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; } -struct delete_ctx { - struct sysdb_handle *handle; - struct sysdb_cb_ctx *cbctx; +int sysdb_delete_entry_recv(struct tevent_req *req) +{ + return sysdb_op_default_recv(req); +} - struct ldb_result *res; -}; -static int delete_callback(struct ldb_request *req, struct ldb_reply *rep) +/* =Search-Entry========================================================== */ + +static void sysdb_search_entry_done(struct tevent_req *subreq); + +struct tevent_req *sysdb_search_entry_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct ldb_dn *base_dn, + const char *filter, + const char **attrs) { - struct delete_ctx *del_ctx; - struct sysdb_cb_ctx *cbctx; - struct sysdb_ctx *ctx; - struct ldb_request *delreq; - struct ldb_result *res; - struct ldb_dn *dn; - int ret, err; + struct tevent_req *req, *subreq; + struct sysdb_op_state *state; + struct ldb_request *ldbreq; + int ret; + + req = tevent_req_create(mem_ctx, &state, struct sysdb_op_state); + if (!req) return NULL; + + state->ev = ev; + state->handle = handle; + state->ignore_not_found = false; + state->ldbreply = NULL; - del_ctx = talloc_get_type(req->context, struct delete_ctx); - ctx = sysdb_handle_get_ctx(del_ctx->handle); - cbctx = del_ctx->cbctx; - res = del_ctx->res; + ret = ldb_build_search_req(&ldbreq, handle->ctx->ldb, state, + base_dn, LDB_SCOPE_SUBTREE, + filter, attrs, NULL, NULL, NULL, NULL); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Failed to build search request: %s(%d)[%s]\n", + ldb_strerror(ret), ret, ldb_errstring(handle->ctx->ldb))); + ERROR_OUT(ret, sysdb_error_to_errno(ret), fail); + } - if (!rep) { - return sysdb_ret_error(cbctx, EIO, LDB_ERR_OPERATIONS_ERROR); + subreq = sldb_request_send(state, ev, handle->ctx->ldb, ldbreq); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); } - if (rep->error != LDB_SUCCESS) { - err = sysdb_error_to_errno(rep->error); - return sysdb_ret_error(cbctx, err, rep->error); + tevent_req_set_callback(subreq, sysdb_search_entry_done, req); + + return req; + +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; +} + +static void sysdb_search_entry_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_op_state *state = tevent_req_data(req, + struct sysdb_op_state); + struct ldb_reply *ldbreply; + int ret; + + ret = sldb_request_recv(subreq, state, &ldbreply); + if (ret) { + tevent_req_error(req, ret); + return; } - switch (rep->type) { + switch (ldbreply->type) { case LDB_REPLY_ENTRY: - if (res->msgs != NULL) { + if (state->ldbreply) { DEBUG(1, ("More than one reply for a base search ?! " "DB seems corrupted, aborting.")); - return sysdb_ret_error(cbctx, EFAULT, LDB_ERR_OPERATIONS_ERROR); - } - res->msgs = talloc_realloc(res, res->msgs, struct ldb_message *, 2); - if (!res->msgs) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); + tevent_req_error(req, EFAULT); + return; } - res->msgs[0] = talloc_steal(res->msgs, rep->message); - res->msgs[1] = NULL; - res->count = 1; + /* save the entry so that it can be retrieved by the caller */ + state->ldbreply = ldbreply; - break; + /* just return, wait for a LDB_REPLY_DONE entry */ + return; case LDB_REPLY_DONE: - - if (res->count == 0) { - DEBUG(7, ("Base search returned no results\n")); - return sysdb_ret_done(cbctx); + if (!state->ldbreply) { + talloc_zfree(ldbreply); + tevent_req_error(req, ENOENT); + return; } + talloc_zfree(ldbreply); + return tevent_req_done(req); - dn = ldb_dn_copy(del_ctx, res->msgs[0]->dn); - if (!dn) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); - } - - talloc_free(res); - del_ctx->res = res = NULL; + default: + /* unexpected stuff */ + talloc_zfree(ldbreply); + tevent_req_error(req, EIO); + return; + } +} - ret = ldb_build_del_req(&delreq, ctx->ldb, cbctx, dn, NULL, - cbctx, sysdb_op_callback, NULL); - if (ret == LDB_SUCCESS) { - ret = ldb_request(ctx->ldb, delreq); - } - if (ret != LDB_SUCCESS) { - err = sysdb_error_to_errno(ret); - return sysdb_ret_error(cbctx, err, ret); - } - break; +int sysdb_search_entry_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + struct ldb_message **msg) +{ + struct sysdb_op_state *state = tevent_req_data(req, + struct sysdb_op_state); + enum tevent_req_state tstate; + uint64_t err; - default: - return sysdb_ret_error(cbctx, EINVAL, LDB_ERR_OPERATIONS_ERROR); + if (tevent_req_is_error(req, &tstate, &err)) { + return err; } - talloc_free(rep); - return LDB_SUCCESS; + *msg = talloc_move(mem_ctx, &state->ldbreply->message); + + return EOK; } -int sysdb_delete_user_by_uid(struct sysdb_handle *handle, - struct sss_domain_info *domain, - uid_t uid, - sysdb_callback_t fn, void *pvt) + +/* =Search-User-by-[UID/NAME]============================================= */ + +struct sysdb_search_user_state { + struct tevent_context *ev; + struct sysdb_handle *handle; + + struct ldb_message *msg; +}; + +static void sysdb_search_user_done(struct tevent_req *subreq); + +struct tevent_req *sysdb_search_user_by_name_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name) { + struct tevent_req *req, *subreq; + struct sysdb_search_user_state *state; static const char *attrs[] = { SYSDB_NAME, SYSDB_UIDNUM, NULL }; - struct delete_ctx *del_ctx; - struct sysdb_ctx *ctx; struct ldb_dn *base_dn; - struct ldb_request *req; char *filter; int ret; - if (!sysdb_handle_check_running(handle)) { - DEBUG(2, ("Invalid request! Not running at this time.\n")); - return EINVAL; + req = tevent_req_create(mem_ctx, &state, struct sysdb_search_user_state); + if (!req) return NULL; + + state->ev = ev; + state->handle = handle; + state->msg = NULL; + + base_dn = ldb_dn_new_fmt(state, handle->ctx->ldb, + SYSDB_TMPL_USER_BASE, domain->name); + if (!base_dn) + ERROR_OUT(ret, ENOMEM, fail); + + filter = talloc_asprintf(state, SYSDB_PWNAM_FILTER, name); + if (!filter) + ERROR_OUT(ret, ENOMEM, fail); + + subreq = sysdb_search_entry_send(state, ev, handle, + base_dn, filter, attrs); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); } + tevent_req_set_callback(subreq, sysdb_search_user_done, req); - ctx = sysdb_handle_get_ctx(handle); + return req; - del_ctx = talloc_zero(handle, struct delete_ctx); - if (!del_ctx) return ENOMEM; +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; +} - del_ctx->cbctx = talloc_zero(del_ctx, struct sysdb_cb_ctx); - if (!del_ctx->cbctx) return ENOMEM; +struct tevent_req *sysdb_search_user_by_uid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + uid_t uid) +{ + struct tevent_req *req, *subreq; + struct sysdb_search_user_state *state; + static const char *attrs[] = { SYSDB_NAME, SYSDB_UIDNUM, NULL }; + struct ldb_dn *base_dn; + char *filter; + int ret; - del_ctx->handle = handle; - del_ctx->cbctx->fn = fn; - del_ctx->cbctx->pvt = pvt; - del_ctx->cbctx->ignore_not_found = true; + req = tevent_req_create(mem_ctx, &state, struct sysdb_search_user_state); + if (!req) return NULL; - del_ctx->res = talloc_zero(del_ctx, struct ldb_result); - if (!del_ctx->res) return ENOMEM; + state->ev = ev; + state->handle = handle; + state->msg = NULL; - base_dn = ldb_dn_new_fmt(del_ctx, ctx->ldb, + base_dn = ldb_dn_new_fmt(state, handle->ctx->ldb, SYSDB_TMPL_USER_BASE, domain->name); - if (!base_dn) return ENOMEM; + if (!base_dn) + ERROR_OUT(ret, ENOMEM, fail); - filter = talloc_asprintf(del_ctx, SYSDB_PWUID_FILTER, (unsigned long)uid); - if (!filter) return ENOMEM; + filter = talloc_asprintf(state, SYSDB_PWUID_FILTER, (unsigned long)uid); + if (!filter) + ERROR_OUT(ret, ENOMEM, fail); - ret = ldb_build_search_req(&req, ctx->ldb, del_ctx, - base_dn, LDB_SCOPE_ONELEVEL, - filter, attrs, NULL, - del_ctx, delete_callback, NULL); - if (ret != LDB_SUCCESS) { - DEBUG(1, ("Failed to build search request: %s(%d)[%s]\n", - ldb_strerror(ret), ret, ldb_errstring(ctx->ldb))); - return sysdb_error_to_errno(ret); + subreq = sysdb_search_entry_send(state, ev, handle, + base_dn, filter, attrs); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); + } + tevent_req_set_callback(subreq, sysdb_search_user_done, req); + + return req; + +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; +} + +static void sysdb_search_user_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_search_user_state *state = tevent_req_data(req, + struct sysdb_search_user_state); + int ret; + + ret = sysdb_search_entry_recv(subreq, state, &state->msg); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } + + tevent_req_done(req); +} + +int sysdb_search_user_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + struct ldb_message **msg) +{ + struct sysdb_search_user_state *state = tevent_req_data(req, + struct sysdb_search_user_state); + enum tevent_req_state tstate; + uint64_t err; + + if (tevent_req_is_error(req, &tstate, &err)) { + return err; } - ret = ldb_request(ctx->ldb, req); - if (ret != LDB_SUCCESS) return sysdb_error_to_errno(ret); + *msg = talloc_move(mem_ctx, &state->msg); return EOK; } -int sysdb_delete_group_by_gid(struct sysdb_handle *handle, - struct sss_domain_info *domain, - gid_t gid, - sysdb_callback_t fn, void *pvt) + +/* =Delete-User-by-UID==================================================== */ + +static void sysdb_delete_user_by_uid_found(struct tevent_req *subreq); +static void sysdb_delete_user_by_uid_done(struct tevent_req *subreq); + +struct tevent_req *sysdb_delete_user_by_uid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + uid_t uid) +{ + struct tevent_req *req, *subreq; + struct sysdb_op_state *state; + + req = tevent_req_create(mem_ctx, &state, struct sysdb_op_state); + if (!req) return NULL; + + state->ev = ev; + state->handle = handle; + state->ignore_not_found = true; + state->ldbreply = NULL; + + subreq = sysdb_search_user_by_uid_send(state, ev, handle, domain, uid); + if (!subreq) { + talloc_zfree(req); + return NULL; + } + tevent_req_set_callback(subreq, sysdb_delete_user_by_uid_found, req); + + return req; +} + +static void sysdb_delete_user_by_uid_found(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_op_state *state = tevent_req_data(req, + struct sysdb_op_state); + struct ldb_message *msg; + int ret; + + ret = sysdb_search_user_recv(subreq, state, &msg); + talloc_zfree(subreq); + if (ret) { + if (state->ignore_not_found && ret == ENOENT) { + return tevent_req_done(req); + } + tevent_req_error(req, ret); + return; + } + + subreq = sysdb_delete_entry_send(state, state->ev, state->handle, msg->dn); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_delete_user_by_uid_done, req); +} + +static void sysdb_delete_user_by_uid_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + int ret; + + ret = sysdb_delete_entry_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } + + tevent_req_done(req); +} + +int sysdb_delete_user_by_uid_recv(struct tevent_req *req) +{ + return sysdb_op_default_recv(req); +} + + +/* =Search-Group-by-[GID/NAME]============================================ */ + +struct sysdb_search_group_state { + struct tevent_context *ev; + struct sysdb_handle *handle; + + struct ldb_message *msg; +}; + +static void sysdb_search_group_done(struct tevent_req *subreq); + +struct tevent_req *sysdb_search_group_by_name_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name) { + struct tevent_req *req, *subreq; + struct sysdb_search_group_state *state; static const char *attrs[] = { SYSDB_NAME, SYSDB_GIDNUM, NULL }; - struct delete_ctx *del_ctx; - struct sysdb_ctx *ctx; struct ldb_dn *base_dn; - struct ldb_request *req; char *filter; int ret; - if (!sysdb_handle_check_running(handle)) { - DEBUG(2, ("Invalid request! Not running at this time.\n")); - return EINVAL; + req = tevent_req_create(mem_ctx, &state, struct sysdb_search_group_state); + if (!req) return NULL; + + state->ev = ev; + state->handle = handle; + state->msg = NULL; + + base_dn = ldb_dn_new_fmt(state, handle->ctx->ldb, + SYSDB_TMPL_GROUP_BASE, domain->name); + if (!base_dn) + ERROR_OUT(ret, ENOMEM, fail); + + filter = talloc_asprintf(state, SYSDB_GRNAM_FILTER, name); + if (!filter) + ERROR_OUT(ret, ENOMEM, fail); + + subreq = sysdb_search_entry_send(state, ev, handle, + base_dn, filter, attrs); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); } + tevent_req_set_callback(subreq, sysdb_search_group_done, req); - ctx = sysdb_handle_get_ctx(handle); + return req; - del_ctx = talloc_zero(handle, struct delete_ctx); - if (!del_ctx) return ENOMEM; +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; +} - del_ctx->cbctx = talloc_zero(del_ctx, struct sysdb_cb_ctx); - if (!del_ctx->cbctx) return ENOMEM; +struct tevent_req *sysdb_search_group_by_gid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + gid_t gid) +{ + struct tevent_req *req, *subreq; + struct sysdb_search_group_state *state; + static const char *attrs[] = { SYSDB_NAME, SYSDB_GIDNUM, NULL }; + struct ldb_dn *base_dn; + char *filter; + int ret; - del_ctx->handle = handle; - del_ctx->cbctx->fn = fn; - del_ctx->cbctx->pvt = pvt; - del_ctx->cbctx->ignore_not_found = true; + req = tevent_req_create(mem_ctx, &state, struct sysdb_search_group_state); + if (!req) return NULL; - del_ctx->res = talloc_zero(del_ctx, struct ldb_result); - if (!del_ctx->res) return ENOMEM; + state->ev = ev; + state->handle = handle; + state->msg = NULL; - base_dn = ldb_dn_new_fmt(del_ctx, ctx->ldb, + base_dn = ldb_dn_new_fmt(state, handle->ctx->ldb, SYSDB_TMPL_GROUP_BASE, domain->name); - if (!base_dn) return ENOMEM; + if (!base_dn) + ERROR_OUT(ret, ENOMEM, fail); - filter = talloc_asprintf(del_ctx, SYSDB_GRGID_FILTER, (unsigned long)gid); - if (!filter) return ENOMEM; + filter = talloc_asprintf(state, SYSDB_GRGID_FILTER, (unsigned long)gid); + if (!filter) + ERROR_OUT(ret, ENOMEM, fail); - ret = ldb_build_search_req(&req, ctx->ldb, del_ctx, - base_dn, LDB_SCOPE_ONELEVEL, - filter, attrs, NULL, - del_ctx, delete_callback, NULL); - if (ret != LDB_SUCCESS) { - DEBUG(1, ("Failed to build search request: %s(%d)[%s]\n", - ldb_strerror(ret), ret, ldb_errstring(ctx->ldb))); - return sysdb_error_to_errno(ret); + subreq = sysdb_search_entry_send(state, ev, handle, + base_dn, filter, attrs); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); + } + tevent_req_set_callback(subreq, sysdb_search_group_done, req); + + return req; + +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; +} + +static void sysdb_search_group_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_search_group_state *state = tevent_req_data(req, + struct sysdb_search_group_state); + int ret; + + ret = sysdb_search_entry_recv(subreq, state, &state->msg); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } + + tevent_req_done(req); +} + +int sysdb_search_group_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + struct ldb_message **msg) +{ + struct sysdb_search_group_state *state = tevent_req_data(req, + struct sysdb_search_group_state); + enum tevent_req_state tstate; + uint64_t err; + + if (tevent_req_is_error(req, &tstate, &err)) { + return err; } - ret = ldb_request(ctx->ldb, req); - if (ret != LDB_SUCCESS) return sysdb_error_to_errno(ret); + *msg = talloc_move(mem_ctx, &state->msg); return EOK; } -int sysdb_set_user_attr(struct sysdb_handle *handle, - struct sss_domain_info *domain, - const char *name, - struct sysdb_attrs *attrs, - sysdb_callback_t fn, void *pvt) + +/* =Delete-Group-by-GID=================================================== */ + +static void sysdb_delete_group_by_gid_found(struct tevent_req *subreq); +static void sysdb_delete_group_by_gid_done(struct tevent_req *subreq); + +struct tevent_req *sysdb_delete_group_by_gid_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + gid_t gid) +{ + struct tevent_req *req, *subreq; + struct sysdb_op_state *state; + + req = tevent_req_create(mem_ctx, &state, struct sysdb_op_state); + if (!req) return NULL; + + state->ev = ev; + state->handle = handle; + state->ignore_not_found = true; + state->ldbreply = NULL; + + subreq = sysdb_search_group_by_gid_send(state, ev, handle, domain, gid); + if (!subreq) { + talloc_zfree(req); + return NULL; + } + tevent_req_set_callback(subreq, sysdb_delete_group_by_gid_found, req); + + return req; +} + +static void sysdb_delete_group_by_gid_found(struct tevent_req *subreq) { - struct sysdb_ctx *ctx; - struct sysdb_cb_ctx *cbctx; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_op_state *state = tevent_req_data(req, + struct sysdb_op_state); struct ldb_message *msg; - struct ldb_request *req; - int i, ret; + int ret; - if (!sysdb_handle_check_running(handle)) { - DEBUG(2, ("Invalid request! Not running at this time.\n")); - return EINVAL; + ret = sysdb_search_group_recv(subreq, state, &msg); + talloc_zfree(subreq); + if (ret) { + if (state->ignore_not_found && ret == ENOENT) { + return tevent_req_done(req); + } + tevent_req_error(req, ret); + return; } - if (attrs->num == 0) return EINVAL; + subreq = sysdb_delete_entry_send(state, state->ev, state->handle, msg->dn); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_delete_group_by_gid_done, req); +} - ctx = sysdb_handle_get_ctx(handle); +static void sysdb_delete_group_by_gid_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + int ret; - cbctx = talloc_zero(handle, struct sysdb_cb_ctx); - if (!cbctx) return ENOMEM; + ret = sysdb_delete_entry_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } - cbctx->fn = fn; - cbctx->pvt = pvt; + tevent_req_done(req); +} - msg = ldb_msg_new(cbctx); - if (!msg) return ENOMEM; +int sysdb_delete_group_by_gid_recv(struct tevent_req *req) +{ + return sysdb_op_default_recv(req); +} + + +/* =Replace-Attributes-On-Entry=========================================== */ + +struct tevent_req *sysdb_set_entry_attr_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct ldb_dn *entry_dn, + struct sysdb_attrs *attrs, + int mod_op) +{ + struct tevent_req *req, *subreq; + struct sysdb_op_state *state; + struct ldb_request *ldbreq; + struct ldb_message *msg; + int i, ret; - msg->dn = sysdb_user_dn(ctx, msg, domain->name, name); - if (!msg->dn) return ENOMEM; + req = tevent_req_create(mem_ctx, &state, struct sysdb_op_state); + if (!req) return NULL; + + state->ev = ev; + state->handle = handle; + state->ignore_not_found = false; + state->ldbreply = NULL; + + if (!entry_dn) { + ERROR_OUT(ret, EINVAL, fail); + } + + if (attrs->num == 0) { + ERROR_OUT(ret, EINVAL, fail); + } + + msg = ldb_msg_new(state); + if (!msg) { + ERROR_OUT(ret, ENOMEM, fail); + } + + msg->dn = entry_dn; msg->elements = talloc_array(msg, struct ldb_message_element, attrs->num); - if (!msg->elements) return ENOMEM; + if (!msg->elements) { + ERROR_OUT(ret, ENOMEM, fail); + } for (i = 0; i < attrs->num; i++) { msg->elements[i] = attrs->a[i]; - msg->elements[i].flags = LDB_FLAG_MOD_REPLACE; + msg->elements[i].flags = mod_op; } msg->num_elements = attrs->num; - ret = ldb_build_mod_req(&req, ctx->ldb, cbctx, msg, NULL, - cbctx, sysdb_op_callback, NULL); - if (ret == LDB_SUCCESS) { - ret = ldb_request(ctx->ldb, req); - } + ret = ldb_build_mod_req(&ldbreq, handle->ctx->ldb, state, msg, + NULL, NULL, NULL, NULL); if (ret != LDB_SUCCESS) { - return sysdb_error_to_errno(ret); + DEBUG(1, ("Failed to build modify request: %s(%d)[%s]\n", + ldb_strerror(ret), ret, ldb_errstring(handle->ctx->ldb))); + ERROR_OUT(ret, sysdb_error_to_errno(ret), fail); } - return EOK; + subreq = sldb_request_send(state, ev, handle->ctx->ldb, ldbreq); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); + } + tevent_req_set_callback(subreq, sysdb_op_default_done, req); + + return req; + +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; } -struct next_id { - uint32_t id; -}; +int sysdb_set_entry_attr_recv(struct tevent_req *req) +{ + return sysdb_op_default_recv(req); +} -struct next_id_ctx { - struct sysdb_handle *handle; - struct sss_domain_info *domain; - struct sysdb_cb_ctx *cbctx; - struct ldb_dn *base_dn; - struct ldb_result *res; - uint32_t tmp_id; +/* =Replace-Attributes-On-User============================================ */ - enum next_step { NEXTID_SEARCH=0, NEXTID_VERIFY, NEXTID_STORE } step; +static void sysdb_set_user_attr_done(struct tevent_req *subreq); - struct next_id *result; -}; +struct tevent_req *sysdb_set_user_attr_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name, + struct sysdb_attrs *attrs, + int mod_op) +{ + struct tevent_req *req, *subreq; + struct sysdb_op_state *state; + struct ldb_dn *dn; + int ret; -static int nextid_callback(struct ldb_request *req, struct ldb_reply *rep); + req = tevent_req_create(mem_ctx, &state, struct sysdb_op_state); + if (!req) return NULL; -static int sysdb_get_next_available_id(struct sysdb_handle *handle, - struct sss_domain_info *domain, - struct next_id *result, - sysdb_callback_t fn, void *pvt) + state->ev = ev; + state->handle = handle; + state->ignore_not_found = false; + state->ldbreply = NULL; + + dn = sysdb_user_dn(handle->ctx, state, domain->name, name); + if (!dn) { + ERROR_OUT(ret, ENOMEM, fail); + } + + subreq = sysdb_set_entry_attr_send(state, ev, handle, dn, attrs, mod_op); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); + } + tevent_req_set_callback(subreq, sysdb_set_user_attr_done, req); + + return req; + +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; +} + +static void sysdb_set_user_attr_done(struct tevent_req *subreq) { - static const char *attrs[] = { SYSDB_NEXTID, NULL }; - struct sysdb_ctx *ctx; - struct next_id_ctx *idctx; - struct ldb_request *req; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + int ret; + + ret = sysdb_set_entry_attr_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } + + tevent_req_done(req); +} + +int sysdb_set_user_attr_recv(struct tevent_req *req) +{ + return sysdb_op_default_recv(req); +} + + +/* =Replace-Attributes-On-Group=========================================== */ + +static void sysdb_set_group_attr_done(struct tevent_req *subreq); + +struct tevent_req *sysdb_set_group_attr_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name, + struct sysdb_attrs *attrs, + int mod_op) +{ + struct tevent_req *req, *subreq; + struct sysdb_op_state *state; + struct ldb_dn *dn; int ret; - if (!sysdb_handle_check_running(handle)) { - DEBUG(2, ("Invalid request! Not running at this time.\n")); - return EINVAL; + req = tevent_req_create(mem_ctx, &state, struct sysdb_op_state); + if (!req) return NULL; + + state->ev = ev; + state->handle = handle; + state->ignore_not_found = false; + state->ldbreply = NULL; + + dn = sysdb_group_dn(handle->ctx, state, domain->name, name); + if (!dn) { + ERROR_OUT(ret, ENOMEM, fail); } - ctx = sysdb_handle_get_ctx(handle); + subreq = sysdb_set_entry_attr_send(state, ev, handle, dn, attrs, mod_op); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); + } + tevent_req_set_callback(subreq, sysdb_set_group_attr_done, req); - idctx = talloc_zero(handle, struct next_id_ctx); - if (!idctx) return ENOMEM; + return req; - idctx->handle = handle; - idctx->domain = domain; - idctx->result = result; +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; +} - idctx->cbctx = talloc_zero(handle, struct sysdb_cb_ctx); - if (!idctx->cbctx) return ENOMEM; +static void sysdb_set_group_attr_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + int ret; - idctx->cbctx->fn = fn; - idctx->cbctx->pvt = pvt; + ret = sysdb_set_entry_attr_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } - idctx->base_dn = sysdb_domain_dn(ctx, idctx, domain->name); - if (!idctx->base_dn) return ENOMEM; + tevent_req_done(req); +} - idctx->res = talloc_zero(idctx, struct ldb_result); - if (!idctx->res) return ENOMEM; +int sysdb_set_group_attr_recv(struct tevent_req *req) +{ + return sysdb_op_default_recv(req); +} - ret = ldb_build_search_req(&req, ctx->ldb, idctx, - idctx->base_dn, LDB_SCOPE_BASE, - SYSDB_NEXTID_FILTER, attrs, NULL, - idctx, nextid_callback, NULL); + +/* =Get-New-ID============================================================ */ + +struct sysdb_get_new_id_state { + struct tevent_context *ev; + struct sysdb_handle *handle; + struct sss_domain_info *domain; + + struct ldb_dn *base_dn; + struct ldb_message *base; + + struct ldb_message **v_msgs; + int v_count; + + uint32_t new_id; +}; + +static void sysdb_get_new_id_base(struct tevent_req *subreq); +static void sysdb_get_new_id_verify(struct tevent_req *subreq); +static void sysdb_get_new_id_done(struct tevent_req *subreq); + +struct tevent_req *sysdb_get_new_id_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain) +{ + struct tevent_req *req, *subreq; + struct sysdb_get_new_id_state *state; + static const char *attrs[] = { SYSDB_NEXTID, NULL }; + struct ldb_request *ldbreq; + int ret; + + req = tevent_req_create(mem_ctx, &state, struct sysdb_get_new_id_state); + if (!req) return NULL; + + state->ev = ev; + state->handle = handle; + state->domain = domain; + state->base = NULL; + state->v_msgs = NULL; + state->v_count = 0; + state->new_id = 0; + + state->base_dn = sysdb_domain_dn(handle->ctx, state, domain->name); + if (!state->base_dn) { + ERROR_OUT(ret, ENOMEM, fail); + } + + ret = ldb_build_search_req(&ldbreq, handle->ctx->ldb, state, + state->base_dn, LDB_SCOPE_BASE, + SYSDB_NEXTID_FILTER, attrs, + NULL, NULL, NULL, NULL); if (ret != LDB_SUCCESS) { DEBUG(1, ("Failed to build search request: %s(%d)[%s]\n", - ldb_strerror(ret), ret, ldb_errstring(ctx->ldb))); - return sysdb_error_to_errno(ret); + ldb_strerror(ret), ret, ldb_errstring(handle->ctx->ldb))); + ERROR_OUT(ret, sysdb_error_to_errno(ret), fail); } - ret = ldb_request(ctx->ldb, req); - if (ret != LDB_SUCCESS) return sysdb_error_to_errno(ret); + subreq = sldb_request_send(state, ev, handle->ctx->ldb, ldbreq); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); + } + tevent_req_set_callback(subreq, sysdb_get_new_id_base, req); - return EOK; + return req; + +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; } -static int nextid_callback(struct ldb_request *req, struct ldb_reply *rep) +static void sysdb_get_new_id_base(struct tevent_req *subreq) { + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_get_new_id_state *state = tevent_req_data(req, + struct sysdb_get_new_id_state); static const char *attrs[] = { SYSDB_UIDNUM, SYSDB_GIDNUM, NULL }; - struct next_id_ctx *idctx; - struct sysdb_cb_ctx *cbctx; - struct sysdb_ctx *ctx; - struct ldb_request *nreq; - struct ldb_message *msg; - struct ldb_result *res; + struct ldb_reply *ldbreply; + struct ldb_request *ldbreq; char *filter; - int ret, err; - - idctx = talloc_get_type(req->context, struct next_id_ctx); - ctx = sysdb_handle_get_ctx(idctx->handle); - cbctx = idctx->cbctx; - res = idctx->res; + int ret; - if (!rep) { - return sysdb_ret_error(cbctx, EIO, LDB_ERR_OPERATIONS_ERROR); - } - if (rep->error != LDB_SUCCESS) { - err = sysdb_error_to_errno(rep->error); - return sysdb_ret_error(cbctx, err, rep->error); + ret = sldb_request_recv(subreq, state, &ldbreply); + if (ret) { + talloc_zfree(subreq); + tevent_req_error(req, ret); + return; } - switch (rep->type) { + switch (ldbreply->type) { case LDB_REPLY_ENTRY: - - if (idctx->step == NEXTID_VERIFY) { - res->count++; - break; - } - - /* NEXTID_SEARCH */ - if (res->msgs != NULL) { + if (state->base) { DEBUG(1, ("More than one reply for a base search ?! " "DB seems corrupted, aborting.")); - return sysdb_ret_error(cbctx, EFAULT, LDB_ERR_OPERATIONS_ERROR); + tevent_req_error(req, EFAULT); + return; } - res->msgs = talloc_realloc(res, res->msgs, struct ldb_message *, 2); - if (!res->msgs) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); + state->base = talloc_move(state, &ldbreply->message); + if (!state->base) { + tevent_req_error(req, ENOMEM); + return; } - res->msgs[0] = talloc_steal(res->msgs, rep->message); - res->msgs[1] = NULL; - res->count = 1; + /* just return, wait for a LDB_REPLY_DONE entry */ + talloc_zfree(ldbreply); + return; + case LDB_REPLY_DONE: break; - case LDB_REPLY_DONE: + default: + /* unexpected stuff */ + tevent_req_error(req, EIO); + talloc_zfree(ldbreply); + return; + } - switch (idctx->step) { - case NEXTID_SEARCH: - if (res->count != 0) { - idctx->tmp_id = get_attr_as_uint32(res->msgs[0], SYSDB_NEXTID); - if (idctx->tmp_id == (uint32_t)(-1)) { - DEBUG(1, ("Invalid Next ID in domain %s\n", - idctx->domain->name)); - return sysdb_ret_error(cbctx, ERANGE, LDB_ERR_OPERATIONS_ERROR); - } - } else { - DEBUG(4, ("Base search returned no results, adding min id!\n")); - } + talloc_zfree(subreq); - if (idctx->tmp_id < idctx->domain->id_min) { - DEBUG(2, ("Initializing domain next id to id min %u\n", - idctx->domain->id_min)); - idctx->tmp_id = idctx->domain->id_min; - } - if ((idctx->domain->id_max != 0) && - (idctx->tmp_id > idctx->domain->id_max)) { - DEBUG(0, ("Failed to allocate new id, out of range (%u/%u)\n", - idctx->tmp_id, idctx->domain->id_max)); - return sysdb_ret_error(cbctx, ERANGE, LDB_ERR_OPERATIONS_ERROR); - } + if (state->base) { + state->new_id = get_attr_as_uint32(state->base, SYSDB_NEXTID); + if (state->new_id == (uint32_t)(-1)) { + DEBUG(1, ("Invalid Next ID in domain %s\n", state->domain->name)); + tevent_req_error(req, ERANGE); + return; + } - talloc_free(res->msgs); - res->msgs = NULL; - res->count = 0; + if (state->new_id < state->domain->id_min) { + state->new_id = state->domain->id_min; + } - idctx->step = NEXTID_VERIFY; - break; + if ((state->domain->id_max != 0) && + (state->new_id > state->domain->id_max)) { + DEBUG(0, ("Failed to allocate new id, out of range (%u/%u)\n", + state->new_id, state->domain->id_max)); + tevent_req_error(req, ERANGE); + return; + } - case NEXTID_VERIFY: - if (res->count) { - /* actually something's using the id, try next */ - idctx->tmp_id++; - } else { - /* ok store new next_id */ - idctx->result->id = idctx->tmp_id; - idctx->tmp_id++; - idctx->step = NEXTID_STORE; - } - break; + } else { + /* looks like the domain is not initialized yet, use min_id */ + state->new_id = state->domain->id_min; + } + + /* verify the id is actually really free. + * search all entries with id >= new_id and < max_id */ + filter = talloc_asprintf(state, + "(|(&(%s>=%u)(%s<=%u))(&(%s>=%u)(%s<=%u)))", + SYSDB_UIDNUM, state->new_id, + SYSDB_UIDNUM, state->domain->id_max, + SYSDB_GIDNUM, state->new_id, + SYSDB_GIDNUM, state->domain->id_max); + if (!filter) { + tevent_req_error(req, ENOMEM); + return; + } - default: - DEBUG(1, ("Invalid step, aborting.\n")); - return sysdb_ret_error(cbctx, EFAULT, LDB_ERR_OPERATIONS_ERROR); - } + ret = ldb_build_search_req(&ldbreq, state->handle->ctx->ldb, state, + state->base_dn, LDB_SCOPE_SUBTREE, + filter, attrs, + NULL, NULL, NULL, NULL); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Failed to build search request: %s(%d)[%s]\n", + ldb_strerror(ret), ret, + ldb_errstring(state->handle->ctx->ldb))); + tevent_req_error(req, sysdb_error_to_errno(ret)); + return; + } - switch (idctx->step) { - case NEXTID_VERIFY: - filter = talloc_asprintf(idctx, "(|(%s=%u)(%s=%u))", - SYSDB_UIDNUM, idctx->tmp_id, - SYSDB_GIDNUM, idctx->tmp_id); - if (!filter) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); - } - ret = ldb_build_search_req(&nreq, ctx->ldb, idctx, - idctx->base_dn, LDB_SCOPE_SUBTREE, - filter, attrs, NULL, - idctx, nextid_callback, NULL); - break; - - case NEXTID_STORE: - msg = ldb_msg_new(idctx); - if (!msg) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); - } + subreq = sldb_request_send(state, state->ev, + state->handle->ctx->ldb, ldbreq); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_get_new_id_verify, req); - msg->dn = idctx->base_dn; + return; +} - ret = add_ulong(msg, LDB_FLAG_MOD_REPLACE, - SYSDB_NEXTID, idctx->tmp_id); - if (ret != LDB_SUCCESS) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); - } +static void sysdb_get_new_id_verify(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_get_new_id_state *state = tevent_req_data(req, + struct sysdb_get_new_id_state); + struct ldb_reply *ldbreply; + struct ldb_request *ldbreq; + struct ldb_message *msg; + int ret, i; - ret = ldb_build_mod_req(&nreq, ctx->ldb, idctx, msg, NULL, - cbctx, sysdb_op_callback, NULL); - break; + ret = sldb_request_recv(subreq, state, &ldbreply); + if (ret) { + talloc_zfree(subreq); + tevent_req_error(req, ret); + return; + } - default: - DEBUG(1, ("Invalid step, aborting.\n")); - return sysdb_ret_error(cbctx, EFAULT, LDB_ERR_OPERATIONS_ERROR); + switch (ldbreply->type) { + case LDB_REPLY_ENTRY: + state->v_msgs = talloc_realloc(state, state->v_msgs, + struct ldb_message *, + state->v_count + 2); + if (!state->v_msgs) { + tevent_req_error(req, ENOMEM); + return; } - if (ret != LDB_SUCCESS) { - DEBUG(1, ("Failed to build search request: %s(%d)[%s]\n", - ldb_strerror(ret), ret, ldb_errstring(ctx->ldb))); - err = sysdb_error_to_errno(ret); - return sysdb_ret_error(cbctx, err, ret); + state->v_msgs[state->v_count] = talloc_move(state, &ldbreply->message); + if (!state->v_msgs[state->v_count]) { + tevent_req_error(req, ENOMEM); + return; } + state->v_count++; - ret = ldb_request(ctx->ldb, nreq); - if (ret != LDB_SUCCESS) { - err = sysdb_error_to_errno(ret); - return sysdb_ret_error(cbctx, err, ret); - } + /* just return, wait for a LDB_REPLY_DONE entry */ + talloc_zfree(ldbreply); + return; + case LDB_REPLY_DONE: break; default: - return sysdb_ret_error(cbctx, EINVAL, LDB_ERR_OPERATIONS_ERROR); + /* unexpected stuff */ + tevent_req_error(req, EIO); + talloc_zfree(ldbreply); + return; } - talloc_free(rep); - return LDB_SUCCESS; -} + talloc_zfree(subreq); -static int check_name_callback(struct ldb_request *req, struct ldb_reply *rep); + /* if anything was found, find the maximum and increment past it */ + if (state->v_count) { + uint32_t id; -int sysdb_check_name_unique(struct sysdb_handle *handle, - struct sss_domain_info *domain, - TALLOC_CTX *mem_ctx, const char *name, - sysdb_callback_t fn, void *pvt) -{ - static const char *attrs[] = { SYSDB_NAME, NULL }; - struct sysdb_cb_ctx *cbctx; - struct sysdb_ctx *ctx; - struct ldb_dn *base_dn; - struct ldb_request *req; - char *filter; - int ret; + for (i = 0; i < state->v_count; i++) { + id = get_attr_as_uint32(state->v_msgs[i], SYSDB_UIDNUM); + if (id != (uint32_t)(-1)) { + if (id > state->new_id) state->new_id = id; + } + id = get_attr_as_uint32(state->v_msgs[i], SYSDB_GIDNUM); + if (id != (uint32_t)(-1)) { + if (id > state->new_id) state->new_id = id; + } + } + + state->new_id++; + + /* check again we are not falling out of range */ + if ((state->domain->id_max != 0) && + (state->new_id > state->domain->id_max)) { + DEBUG(0, ("Failed to allocate new id, out of range (%u/%u)\n", + state->new_id, state->domain->id_max)); + tevent_req_error(req, ERANGE); + return; + } + + talloc_zfree(state->v_msgs); + state->v_count = 0; + } + + /* finally store the new next id */ + msg = ldb_msg_new(state); + if (!msg) { + tevent_req_error(req, ENOMEM); + return; + } + msg->dn = state->base->dn; + + ret = add_ulong(msg, LDB_FLAG_MOD_REPLACE, + SYSDB_NEXTID, state->new_id + 1); + if (ret) { + tevent_req_error(req, ret); + return; + } - if (!sysdb_handle_check_running(handle)) { - DEBUG(2, ("Invalid request! Not running at this time.\n")); - return EINVAL; + ret = ldb_build_mod_req(&ldbreq, state->handle->ctx->ldb, state, msg, + NULL, NULL, NULL, NULL); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Failed to build modify request: %s(%d)[%s]\n", + ldb_strerror(ret), ret, + ldb_errstring(state->handle->ctx->ldb))); + tevent_req_error(req, ret); + return; } - ctx = sysdb_handle_get_ctx(handle); + subreq = sldb_request_send(state, state->ev, + state->handle->ctx->ldb, ldbreq); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_get_new_id_done, req); +} - cbctx = talloc_zero(mem_ctx, struct sysdb_cb_ctx); - if (!cbctx) return ENOMEM; +static void sysdb_get_new_id_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_get_new_id_state *state = tevent_req_data(req, + struct sysdb_get_new_id_state); + struct ldb_reply *ldbreply; + int ret; - cbctx->fn = fn; - cbctx->pvt = pvt; + ret = sldb_request_recv(subreq, state, &ldbreply); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } - base_dn = sysdb_domain_dn(ctx, cbctx, domain->name); - if (!base_dn) return ENOMEM; + if (ldbreply->type != LDB_REPLY_DONE) { + tevent_req_error(req, EIO); + return; + } - filter = talloc_asprintf(cbctx, SYSDB_CHECK_FILTER, name); - if (!filter) return ENOMEM; + tevent_req_done(req); +} - ret = ldb_build_search_req(&req, ctx->ldb, mem_ctx, - base_dn, LDB_SCOPE_SUBTREE, - filter, attrs, NULL, - cbctx, check_name_callback, NULL); - if (ret != LDB_SUCCESS) { - DEBUG(1, ("Failed to build search request: %s(%d)[%s]\n", - ldb_strerror(ret), ret, ldb_errstring(ctx->ldb))); - return sysdb_error_to_errno(ret); +int sysdb_get_new_id_recv(struct tevent_req *req, uint32_t *id) +{ + struct sysdb_get_new_id_state *state = tevent_req_data(req, + struct sysdb_get_new_id_state); + enum tevent_req_state tstate; + uint64_t err; + + if (tevent_req_is_error(req, &tstate, &err)) { + return err; } - ret = ldb_request(ctx->ldb, req); - if (ret != LDB_SUCCESS) return sysdb_error_to_errno(ret); + *id = state->new_id; return EOK; } -static int check_name_callback(struct ldb_request *req, struct ldb_reply *rep) + +/* =Add-Basic-User-NO-CHECKS============================================== */ + +struct tevent_req *sysdb_add_basic_user_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name, + uid_t uid, gid_t gid, + const char *gecos, + const char *homedir, + const char *shell) { - struct sysdb_cb_ctx *cbctx; - int err; + struct tevent_req *req, *subreq; + struct sysdb_op_state *state; + struct ldb_request *ldbreq; + struct ldb_message *msg; + int ret; + + req = tevent_req_create(mem_ctx, &state, struct sysdb_op_state); + if (!req) return NULL; + + state->ev = ev; + state->handle = handle; + state->ignore_not_found = false; + state->ldbreply = NULL; - cbctx = talloc_get_type(req->context, struct sysdb_cb_ctx); + msg = ldb_msg_new(state); + if (!msg) { + ERROR_OUT(ret, ENOMEM, fail); + } - if (!rep) { - return sysdb_ret_error(cbctx, EIO, LDB_ERR_OPERATIONS_ERROR); + /* user dn */ + msg->dn = sysdb_user_dn(handle->ctx, msg, domain->name, name); + if (!msg->dn) { + ERROR_OUT(ret, ENOMEM, fail); } - if (rep->error != LDB_SUCCESS) { - err = sysdb_error_to_errno(rep->error); - return sysdb_ret_error(cbctx, err, rep->error); + + ret = add_string(msg, LDB_FLAG_MOD_ADD, "objectClass", SYSDB_USER_CLASS); + if (ret) goto fail; + + ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_NAME, name); + if (ret) goto fail; + + ret = add_ulong(msg, LDB_FLAG_MOD_ADD, SYSDB_UIDNUM, (unsigned long)uid); + if (ret) goto fail; + + ret = add_ulong(msg, LDB_FLAG_MOD_ADD, SYSDB_GIDNUM, (unsigned long)gid); + if (ret) goto fail; + + /* We set gecos to be the same as fullname on user creation, + * But we will not enforce coherency after that, it's up to + * admins to decide if they want to keep it in sync if they change + * one of the 2 */ + if (gecos && *gecos) { + ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_FULLNAME, gecos); + if (ret) goto fail; + ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_GECOS, gecos); + if (ret) goto fail; } - switch (rep->type) { - case LDB_REPLY_ENTRY: + if (homedir && *homedir) { + ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_HOMEDIR, homedir); + if (ret) goto fail; + } - /* one found, that means name is not available */ - /* return EEXIST */ - return sysdb_ret_error(cbctx, EEXIST, LDB_ERR_ENTRY_ALREADY_EXISTS); + if (shell && *shell) { + ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_SHELL, shell); + if (ret) goto fail; + } - case LDB_REPLY_DONE: + /* creation time */ + ret = add_ulong(msg, LDB_FLAG_MOD_ADD, SYSDB_CREATE_TIME, + (unsigned long)time(NULL)); + if (ret) goto fail; - return sysdb_ret_done(cbctx); - default: - return sysdb_ret_error(cbctx, EINVAL, LDB_ERR_OPERATIONS_ERROR); + ret = ldb_build_add_req(&ldbreq, handle->ctx->ldb, state, msg, + NULL, NULL, NULL, NULL); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Failed to build modify request: %s(%d)[%s]\n", + ldb_strerror(ret), ret, ldb_errstring(handle->ctx->ldb))); + ERROR_OUT(ret, sysdb_error_to_errno(ret), fail); } - return LDB_SUCCESS; + subreq = sldb_request_send(state, ev, handle->ctx->ldb, ldbreq); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); + } + tevent_req_set_callback(subreq, sysdb_op_default_done, req); + + return req; + +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; } +int sysdb_add_basic_user_recv(struct tevent_req *req) +{ + return sysdb_op_default_recv(req); +} + + +/* =Add-User-Function===================================================== */ -struct user_add_ctx { +struct sysdb_add_user_state { + struct tevent_context *ev; struct sysdb_handle *handle; - struct sysdb_cb_ctx *cbctx; struct sss_domain_info *domain; const char *name; uid_t uid; gid_t gid; - const char *fullname; + const char *gecos; const char *homedir; const char *shell; - - struct next_id id; + struct sysdb_attrs *attrs; }; -static void user_check_callback(void *pvt, int error, struct ldb_result *res); -static int user_add_id(struct user_add_ctx *user_ctx); -static void user_add_id_callback(void *pvt, int error, struct ldb_result *res); -static int user_add_call(struct user_add_ctx *user_ctx); +static void sysdb_add_user_group_check(struct tevent_req *subreq); +static void sysdb_add_user_uid_check(struct tevent_req *subreq); +static void sysdb_add_user_basic_done(struct tevent_req *subreq); +static void sysdb_add_user_get_id_done(struct tevent_req *subreq); +static void sysdb_add_user_set_id_done(struct tevent_req *subreq); +static void sysdb_add_user_set_attrs_done(struct tevent_req *subreq); -int sysdb_add_user(struct sysdb_handle *handle, - struct sss_domain_info *domain, - const char *name, - uid_t uid, gid_t gid, const char *fullname, - const char *homedir, const char *shell, - sysdb_callback_t fn, void *pvt) +struct tevent_req *sysdb_add_user_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name, + uid_t uid, gid_t gid, + const char *gecos, + const char *homedir, + const char *shell, + struct sysdb_attrs *attrs) { - struct user_add_ctx *user_ctx; + struct tevent_req *req, *subreq; + struct sysdb_add_user_state *state; + int ret; + + req = tevent_req_create(mem_ctx, &state, struct sysdb_add_user_state); + if (!req) return NULL; + + state->ev = ev; + state->handle = handle; + state->domain = domain; + state->name = name; + state->uid = uid; + state->gid = gid; + state->gecos = gecos; + state->homedir = homedir; + state->shell = shell; + state->attrs = attrs; - if (!sysdb_handle_check_running(handle)) { - DEBUG(2, ("Invalid request! Not running at this time.\n")); - return EINVAL; + if (domain->mpg) { + if (gid != 0) { + DEBUG(0, ("Cannot add user with arbitrary GID in MPG domain!\n")); + ERROR_OUT(ret, EINVAL, fail); + } + state->gid = state->uid; } if (domain->id_max != 0 && uid != 0 && (uid < domain->id_min || uid > domain->id_max)) { DEBUG(2, ("Supplied uid [%d] is not in the allowed range [%d-%d].\n", uid, domain->id_min, domain->id_max)); - return EINVAL; + ERROR_OUT(ret, EINVAL, fail); } if (domain->id_max != 0 && gid != 0 && (gid < domain->id_min || gid > domain->id_max)) { DEBUG(2, ("Supplied gid [%d] is not in the allowed range [%d-%d].\n", gid, domain->id_min, domain->id_max)); - return EINVAL; + ERROR_OUT(ret, EINVAL, fail); } + if (domain->mpg) { + /* In MPG domains you can't have groups with the same name as users, + * search if a group with the same name exists. + * Don't worry about users, if we try to add a user with the same + * name the operation will fail */ + + subreq = sysdb_search_group_by_name_send(state, ev, handle, + domain, name); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); + } + tevent_req_set_callback(subreq, sysdb_add_user_group_check, req); + return req; + } - user_ctx = talloc(handle, struct user_add_ctx); - if (!user_ctx) return ENOMEM; + /* check no other user with the same uid exist */ + if (state->uid != 0) { + subreq = sysdb_search_user_by_uid_send(state, ev, handle, domain, uid); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); + } + tevent_req_set_callback(subreq, sysdb_add_user_uid_check, req); + return req; + } - user_ctx->cbctx = talloc_zero(user_ctx, struct sysdb_cb_ctx); - if (!user_ctx->cbctx) return ENOMEM; + /* try to add the user */ + subreq = sysdb_add_basic_user_send(state, ev, handle, + domain, name, uid, gid, + gecos, homedir, shell); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); + } + tevent_req_set_callback(subreq, sysdb_add_user_basic_done, req); + return req; - user_ctx->handle = handle; - user_ctx->domain = domain; - user_ctx->cbctx->fn = fn; - user_ctx->cbctx->pvt = pvt; - user_ctx->name = name; - user_ctx->uid = uid; - user_ctx->gid = gid; - user_ctx->fullname = fullname; - user_ctx->homedir = homedir; - user_ctx->shell = shell; +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; +} - if (domain->mpg) { - /* if the domain is mpg we need to check we do not have there are no - * name conflicts */ +static void sysdb_add_user_group_check(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_add_user_state *state = tevent_req_data(req, + struct sysdb_add_user_state); + struct ldb_message *msg; + int ret; - return sysdb_check_name_unique(handle, domain, user_ctx, name, - user_check_callback, user_ctx); + /* We can succeed only if we get an ENOENT error, which means no groups + * with the same name exist. + * If any other error is returned fail as well. */ + ret = sysdb_search_group_recv(subreq, state, &msg); + talloc_zfree(subreq); + if (ret != ENOENT) { + if (ret == EOK) ret = EEXIST; + tevent_req_error(req, ret); + return; } - return user_add_id(user_ctx); + /* check no other user with the same uid exist */ + if (state->uid != 0) { + subreq = sysdb_search_user_by_uid_send(state, + state->ev, state->handle, + state->domain, state->uid); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_add_user_uid_check, req); + return; + } + + /* try to add the user */ + subreq = sysdb_add_basic_user_send(state, state->ev, state->handle, + state->domain, state->name, + state->uid, state->gid, + state->gecos, + state->homedir, + state->shell); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_add_user_basic_done, req); } -static void user_check_callback(void *pvt, int error, struct ldb_result *res) +static void sysdb_add_user_uid_check(struct tevent_req *subreq) { - struct user_add_ctx *user_ctx; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_add_user_state *state = tevent_req_data(req, + struct sysdb_add_user_state); + struct ldb_message *msg; int ret; - user_ctx = talloc_get_type(pvt, struct user_add_ctx); - if (error != EOK) { - sysdb_ret_error(user_ctx->cbctx, error, LDB_ERR_OPERATIONS_ERROR); + /* We can succeed only if we get an ENOENT error, which means no user + * with the same uid exist. + * If any other error is returned fail as well. */ + ret = sysdb_search_user_recv(subreq, state, &msg); + talloc_zfree(subreq); + if (ret != ENOENT) { + if (ret == EOK) ret = EEXIST; + tevent_req_error(req, ret); return; } - ret = user_add_id(user_ctx); - if (ret != EOK) { - sysdb_ret_error(user_ctx->cbctx, ret, LDB_ERR_OPERATIONS_ERROR); + /* try to add the user */ + subreq = sysdb_add_basic_user_send(state, state->ev, state->handle, + state->domain, state->name, + state->uid, state->gid, + state->gecos, + state->homedir, + state->shell); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; } + tevent_req_set_callback(subreq, sysdb_add_user_basic_done, req); } -static int user_add_id(struct user_add_ctx *user_ctx) +static void sysdb_add_user_basic_done(struct tevent_req *subreq) { - if (user_ctx->uid != 0 && user_ctx->gid == 0) { - if(user_ctx->domain->mpg) { - user_ctx->gid = user_ctx->uid; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_add_user_state *state = tevent_req_data(req, + struct sysdb_add_user_state); + int ret; + + ret = sysdb_add_basic_user_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } + + if (state->uid == 0) { + subreq = sysdb_get_new_id_send(state, + state->ev, state->handle, + state->domain); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; } + tevent_req_set_callback(subreq, sysdb_add_user_get_id_done, req); + return; } - if (user_ctx->uid == 0 || user_ctx->gid == 0) { - /* Must generate uid/gid pair */ - return sysdb_get_next_available_id(user_ctx->handle, - user_ctx->domain, - &(user_ctx->id), - user_add_id_callback, user_ctx); + if (state->attrs) { + subreq = sysdb_set_user_attr_send(state, state->ev, state->handle, + state->domain, state->name, + state->attrs, SYSDB_MOD_ADD); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_add_user_set_attrs_done, req); + return; } - return user_add_call(user_ctx); + tevent_req_done(req); } -static void user_add_id_callback(void *pvt, int error, struct ldb_result *res) +static void sysdb_add_user_get_id_done(struct tevent_req *subreq) { - struct user_add_ctx *user_ctx; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_add_user_state *state = tevent_req_data(req, + struct sysdb_add_user_state); + struct sysdb_attrs *id_attrs; + uint32_t id; int ret; - user_ctx = talloc_get_type(pvt, struct user_add_ctx); - if (error != EOK) { - sysdb_ret_error(user_ctx->cbctx, error, LDB_ERR_OPERATIONS_ERROR); + ret = sysdb_get_new_id_recv(subreq, &id); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); return; } - /* ok id has been allocated, fill in uid and gid fields if not - * already set */ - if (user_ctx->uid == 0) { - user_ctx->uid = user_ctx->id.id; + if (state->uid == 0) { + id_attrs = sysdb_new_attrs(state); + if (!id_attrs) { + tevent_req_error(req, ENOMEM); + return; + } + ret = sysdb_attrs_add_uint32(id_attrs, SYSDB_UIDNUM, id); + if (ret) { + tevent_req_error(req, ret); + return; + } + if (state->domain->mpg) { + ret = sysdb_attrs_add_uint32(id_attrs, SYSDB_GIDNUM, id); + if (ret) { + tevent_req_error(req, ret); + return; + } + } + + subreq = sysdb_set_user_attr_send(state, state->ev, state->handle, + state->domain, state->name, + id_attrs, SYSDB_MOD_REP); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_add_user_set_id_done, req); + return; + } + + if (state->attrs) { + subreq = sysdb_set_user_attr_send(state, state->ev, + state->handle, state->domain, + state->name, state->attrs, + SYSDB_MOD_REP); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_add_user_set_attrs_done, req); + return; } - if (user_ctx->gid == 0) { - user_ctx->gid = user_ctx->id.id; + + tevent_req_done(req); +} + +static void sysdb_add_user_set_id_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_add_user_state *state = tevent_req_data(req, + struct sysdb_add_user_state); + int ret; + + ret = sysdb_set_user_attr_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; } - ret = user_add_call(user_ctx); - if (ret != EOK) { - sysdb_ret_error(user_ctx->cbctx, ret, LDB_ERR_OPERATIONS_ERROR); + if (state->attrs) { + subreq = sysdb_set_user_attr_send(state, state->ev, + state->handle, state->domain, + state->name, state->attrs, + SYSDB_MOD_REP); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_add_user_set_attrs_done, req); + return; } + + tevent_req_done(req); } -static int user_add_call(struct user_add_ctx *user_ctx) +static void sysdb_add_user_set_attrs_done(struct tevent_req *subreq) { - struct sysdb_ctx *ctx; - struct ldb_message *msg; - struct ldb_request *req; - int flags = LDB_FLAG_MOD_ADD; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); int ret; - ctx = sysdb_handle_get_ctx(user_ctx->handle); + ret = sysdb_set_user_attr_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } - msg = ldb_msg_new(user_ctx); - if (!msg) return ENOMEM; + tevent_req_done(req); +} - msg->dn = sysdb_user_dn(ctx, msg, user_ctx->domain->name, user_ctx->name); - if (!msg->dn) return ENOMEM; +int sysdb_add_user_recv(struct tevent_req *req) +{ + return sysdb_op_default_recv(req); +} - ret = add_string(msg, flags, "objectClass", SYSDB_USER_CLASS); - if (ret != LDB_SUCCESS) return ENOMEM; - ret = add_string(msg, flags, SYSDB_NAME, user_ctx->name); - if (ret != LDB_SUCCESS) return ENOMEM; +/* =Add-Basic-Group-NO-CHECKS============================================= */ - if (user_ctx->uid) { - ret = add_ulong(msg, flags, SYSDB_UIDNUM, - (unsigned long)(user_ctx->uid)); - if (ret != LDB_SUCCESS) return ENOMEM; - } else { - DEBUG(0, ("Cached users can't have UID == 0\n")); - return EINVAL; - } +struct tevent_req *sysdb_add_basic_group_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name, gid_t gid) +{ + struct tevent_req *req, *subreq; + struct sysdb_op_state *state; + struct ldb_request *ldbreq; + struct ldb_message *msg; + int ret; - if (user_ctx->gid) { - ret = add_ulong(msg, flags, SYSDB_GIDNUM, - (unsigned long)(user_ctx->gid)); - if (ret != LDB_SUCCESS) return ENOMEM; - } else { - DEBUG(0, ("Cached users can't have GID == 0\n")); - return EINVAL; - } + req = tevent_req_create(mem_ctx, &state, struct sysdb_op_state); + if (!req) return NULL; - /* We set gecos to be the same as fullname on user creation, - * But we will not enforce coherency after that, it's up to - * admins to decide if they want to keep it in sync if they change - * one of the 2 */ - if (user_ctx->fullname && *user_ctx->fullname) { - ret = add_string(msg, flags, SYSDB_FULLNAME, user_ctx->fullname); - if (ret != LDB_SUCCESS) return ENOMEM; - ret = add_string(msg, flags, SYSDB_GECOS, user_ctx->fullname); - if (ret != LDB_SUCCESS) return ENOMEM; - } + state->ev = ev; + state->handle = handle; + state->ignore_not_found = false; + state->ldbreply = NULL; - if (user_ctx->homedir && *user_ctx->homedir) { - ret = add_string(msg, flags, SYSDB_HOMEDIR, user_ctx->homedir); - if (ret != LDB_SUCCESS) return ENOMEM; + msg = ldb_msg_new(state); + if (!msg) { + ERROR_OUT(ret, ENOMEM, fail); } - if (user_ctx->shell && *user_ctx->shell) { - ret = add_string(msg, flags, SYSDB_SHELL, user_ctx->shell); - if (ret != LDB_SUCCESS) return ENOMEM; + /* user dn */ + msg->dn = sysdb_group_dn(handle->ctx, msg, domain->name, name); + if (!msg->dn) { + ERROR_OUT(ret, ENOMEM, fail); } + ret = add_string(msg, LDB_FLAG_MOD_ADD, "objectClass", SYSDB_GROUP_CLASS); + if (ret) goto fail; + + ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_NAME, name); + if (ret) goto fail; + + ret = add_ulong(msg, LDB_FLAG_MOD_ADD, SYSDB_GIDNUM, (unsigned long)gid); + if (ret) goto fail; + /* creation time */ - ret = add_ulong(msg, flags, SYSDB_CREATE_TIME, (unsigned long)time(NULL)); - if (ret != LDB_SUCCESS) return ENOMEM; + ret = add_ulong(msg, LDB_FLAG_MOD_ADD, SYSDB_CREATE_TIME, + (unsigned long)time(NULL)); + if (ret) goto fail; - ret = ldb_build_add_req(&req, ctx->ldb, user_ctx, msg, NULL, - user_ctx->cbctx, sysdb_op_callback, NULL); - if (ret == LDB_SUCCESS) { - ret = ldb_request(ctx->ldb, req); - } + + ret = ldb_build_add_req(&ldbreq, handle->ctx->ldb, state, msg, + NULL, NULL, NULL, NULL); if (ret != LDB_SUCCESS) { - return sysdb_error_to_errno(ret); + DEBUG(1, ("Failed to build modify request: %s(%d)[%s]\n", + ldb_strerror(ret), ret, ldb_errstring(handle->ctx->ldb))); + ERROR_OUT(ret, sysdb_error_to_errno(ret), fail); } - return EOK; + subreq = sldb_request_send(state, ev, handle->ctx->ldb, ldbreq); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); + } + tevent_req_set_callback(subreq, sysdb_op_default_done, req); + + return req; + +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; +} + +int sysdb_add_basic_group_recv(struct tevent_req *req) +{ + return sysdb_op_default_recv(req); } -struct group_add_ctx { + +/* =Add-Group-Function==================================================== */ + +struct sysdb_add_group_state { + struct tevent_context *ev; struct sysdb_handle *handle; - struct sysdb_cb_ctx *cbctx; struct sss_domain_info *domain; const char *name; gid_t gid; - - struct next_id id; + struct sysdb_attrs *attrs; }; -static void group_check_callback(void *pvt, int error, struct ldb_result *res); -static int group_add_id(struct group_add_ctx *group_ctx); -static void group_add_id_callback(void *pvt, int error, struct ldb_result *res); -static int group_add_call(struct group_add_ctx *group_ctx); - -int sysdb_add_group(struct sysdb_handle *handle, - struct sss_domain_info *domain, - const char *name, gid_t gid, - sysdb_callback_t fn, void *pvt) +static void sysdb_add_group_user_check(struct tevent_req *subreq); +static void sysdb_add_group_gid_check(struct tevent_req *subreq); +static void sysdb_add_group_basic_done(struct tevent_req *subreq); +static void sysdb_add_group_get_id_done(struct tevent_req *subreq); +static void sysdb_add_group_set_id_done(struct tevent_req *subreq); +static void sysdb_add_group_set_attrs_done(struct tevent_req *subreq); + +struct tevent_req *sysdb_add_group_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name, gid_t gid, + struct sysdb_attrs *attrs) { - struct group_add_ctx *group_ctx; + struct tevent_req *req, *subreq; + struct sysdb_add_group_state *state; + int ret; - if (!sysdb_handle_check_running(handle)) { - DEBUG(2, ("Invalid request! Not running at this time.\n")); - return EINVAL; - } + req = tevent_req_create(mem_ctx, &state, struct sysdb_add_group_state); + if (!req) return NULL; + + state->ev = ev; + state->handle = handle; + state->domain = domain; + state->name = name; + state->gid = gid; + state->attrs = attrs; if (domain->id_max != 0 && gid != 0 && (gid < domain->id_min || gid > domain->id_max)) { DEBUG(2, ("Supplied gid [%d] is not in the allowed range [%d-%d].\n", gid, domain->id_min, domain->id_max)); - return EINVAL; + ERROR_OUT(ret, EINVAL, fail); } - group_ctx = talloc(handle, struct group_add_ctx); - if (!group_ctx) return ENOMEM; - - group_ctx->cbctx = talloc_zero(group_ctx, struct sysdb_cb_ctx); - if (!group_ctx->cbctx) return ENOMEM; - - group_ctx->handle = handle; - group_ctx->domain = domain; - group_ctx->cbctx->fn = fn; - group_ctx->cbctx->pvt = pvt; - group_ctx->name = name; - group_ctx->gid = gid; - if (domain->mpg) { - /* if the domain is mpg we need to check we do not have there are no - * name conflicts */ + /* In MPG domains you can't have groups with the same name as users, + * search if a group with the same name exists. + * Don't worry about users, if we try to add a user with the same + * name the operation will fail */ + + subreq = sysdb_search_user_by_name_send(state, ev, handle, + domain, name); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); + } + tevent_req_set_callback(subreq, sysdb_add_group_user_check, req); + return req; + } + + /* check no other groups with the same gid exist */ + if (state->gid != 0) { + subreq = sysdb_search_group_by_gid_send(state, ev, handle, + domain, gid); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); + } + tevent_req_set_callback(subreq, sysdb_add_group_gid_check, req); + return req; + } - return sysdb_check_name_unique(handle, domain, group_ctx, name, - group_check_callback, group_ctx); + /* try to add the group */ + subreq = sysdb_add_basic_group_send(state, ev, handle, + domain, name, gid); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); } + tevent_req_set_callback(subreq, sysdb_add_group_basic_done, req); + return req; - return group_add_id(group_ctx); +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; } -static void group_check_callback(void *pvt, int error, struct ldb_result *res) +static void sysdb_add_group_user_check(struct tevent_req *subreq) { - struct group_add_ctx *group_ctx; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_add_group_state *state = tevent_req_data(req, + struct sysdb_add_group_state); + struct ldb_message *msg; int ret; - group_ctx = talloc_get_type(pvt, struct group_add_ctx); - if (error != EOK) { - sysdb_ret_error(group_ctx->cbctx, error, LDB_ERR_OPERATIONS_ERROR); + /* We can succeed only if we get an ENOENT error, which means no users + * with the same name exist. + * If any other error is returned fail as well. */ + ret = sysdb_search_user_recv(subreq, state, &msg); + talloc_zfree(subreq); + if (ret != ENOENT) { + if (ret == EOK) ret = EEXIST; + tevent_req_error(req, ret); return; } - ret = group_add_id(group_ctx); - if (ret != EOK) { - sysdb_ret_error(group_ctx->cbctx, ret, LDB_ERR_OPERATIONS_ERROR); + /* check no other group with the same gid exist */ + if (state->gid != 0) { + subreq = sysdb_search_group_by_gid_send(state, + state->ev, state->handle, + state->domain, state->gid); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_add_group_gid_check, req); + return; } + + /* try to add the group */ + subreq = sysdb_add_basic_group_send(state, state->ev, + state->handle, state->domain, + state->name, state->gid); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_add_group_basic_done, req); } -static int group_add_id(struct group_add_ctx *group_ctx) +static void sysdb_add_group_gid_check(struct tevent_req *subreq) { - if (group_ctx->gid == 0) { - /* Must generate uid/gid pair */ - return sysdb_get_next_available_id(group_ctx->handle, - group_ctx->domain, - &(group_ctx->id), - group_add_id_callback, group_ctx); + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_add_group_state *state = tevent_req_data(req, + struct sysdb_add_group_state); + struct ldb_message *msg; + int ret; + + /* We can succeed only if we get an ENOENT error, which means no group + * with the same gid exist. + * If any other error is returned fail as well. */ + ret = sysdb_search_group_recv(subreq, state, &msg); + talloc_zfree(subreq); + if (ret != ENOENT) { + if (ret == EOK) ret = EEXIST; + tevent_req_error(req, ret); + return; } - return group_add_call(group_ctx); + /* try to add the group */ + subreq = sysdb_add_basic_group_send(state, state->ev, + state->handle, state->domain, + state->name, state->gid); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_add_group_basic_done, req); } -static void group_add_id_callback(void *pvt, int error, struct ldb_result *res) +static void sysdb_add_group_basic_done(struct tevent_req *subreq) { - struct group_add_ctx *group_ctx; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_add_group_state *state = tevent_req_data(req, + struct sysdb_add_group_state); int ret; - group_ctx = talloc_get_type(pvt, struct group_add_ctx); - if (error != EOK) { - sysdb_ret_error(group_ctx->cbctx, error, LDB_ERR_OPERATIONS_ERROR); + ret = sysdb_add_basic_group_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); return; } - /* ok id has been allocated, fill in uid and gid fields */ - group_ctx->gid = group_ctx->id.id; + if (state->gid == 0) { + subreq = sysdb_get_new_id_send(state, + state->ev, state->handle, + state->domain); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_add_group_get_id_done, req); + return; + } - ret = group_add_call(group_ctx); - if (ret != EOK) { - sysdb_ret_error(group_ctx->cbctx, ret, LDB_ERR_OPERATIONS_ERROR); + if (state->attrs) { + subreq = sysdb_set_group_attr_send(state, state->ev, + state->handle, state->domain, + state->name, state->attrs, + SYSDB_MOD_ADD); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_add_group_set_attrs_done, req); + return; } + + tevent_req_done(req); } -static int group_add_call(struct group_add_ctx *group_ctx) +static void sysdb_add_group_get_id_done(struct tevent_req *subreq) { - struct sysdb_ctx *ctx; - struct ldb_message *msg; - struct ldb_request *req; - int flags = LDB_FLAG_MOD_ADD; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_add_group_state *state = tevent_req_data(req, + struct sysdb_add_group_state); + struct sysdb_attrs *id_attrs; + uint32_t id; int ret; - ctx = sysdb_handle_get_ctx(group_ctx->handle); - - msg = ldb_msg_new(group_ctx); - if (!msg) return ENOMEM; - - msg->dn = sysdb_group_dn(ctx, msg, group_ctx->domain->name, group_ctx->name); - if (!msg->dn) return ENOMEM; + ret = sysdb_get_new_id_recv(subreq, &id); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } - ret = add_string(msg, flags, "objectClass", SYSDB_GROUP_CLASS); - if (ret != LDB_SUCCESS) return ENOMEM; + if (state->gid == 0) { + id_attrs = sysdb_new_attrs(state); + if (!id_attrs) { + tevent_req_error(req, ENOMEM); + return; + } + ret = sysdb_attrs_add_uint32(id_attrs, SYSDB_GIDNUM, id); + if (ret) { + tevent_req_error(req, ret); + return; + } - ret = add_string(msg, flags, SYSDB_NAME, group_ctx->name); - if (ret != LDB_SUCCESS) return ENOMEM; + subreq = sysdb_set_group_attr_send(state, state->ev, state->handle, + state->domain, state->name, + id_attrs, SYSDB_MOD_REP); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_add_group_set_id_done, req); + return; + } - if (group_ctx->gid) { - ret = add_ulong(msg, flags, SYSDB_GIDNUM, - (unsigned long)(group_ctx->gid)); - if (ret != LDB_SUCCESS) return ENOMEM; - } else { - DEBUG(0, ("Cached groups can't have GID == 0\n")); - return EINVAL; + if (state->attrs) { + subreq = sysdb_set_group_attr_send(state, state->ev, + state->handle, state->domain, + state->name, state->attrs, + SYSDB_MOD_ADD); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_add_group_set_attrs_done, req); + return; } - /* creation time */ - ret = add_ulong(msg, flags, SYSDB_CREATE_TIME, (unsigned long)time(NULL)); - if (ret != LDB_SUCCESS) return ENOMEM; + tevent_req_done(req); +} - ret = ldb_build_add_req(&req, ctx->ldb, group_ctx, msg, NULL, - group_ctx->cbctx, sysdb_op_callback, NULL); - if (ret == LDB_SUCCESS) { - ret = ldb_request(ctx->ldb, req); +static void sysdb_add_group_set_id_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_add_group_state *state = tevent_req_data(req, + struct sysdb_add_group_state); + int ret; + + ret = sysdb_set_group_attr_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; } - if (ret != LDB_SUCCESS) { - return sysdb_error_to_errno(ret); + + if (state->attrs) { + subreq = sysdb_set_group_attr_send(state, state->ev, + state->handle, state->domain, + state->name, state->attrs, + SYSDB_MOD_ADD); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_add_group_set_attrs_done, req); + return; } - return EOK; + tevent_req_done(req); } -/* This function is not safe, but is included for completeness - * It is much better to allow SSSD to internally manage the - * group GID values. sysdb_set_group_gid() will perform no - * validation that the new GID is unused. The only check it - * will perform is whether the requested GID is in the range - * of IDs allocated for the domain. - */ -int sysdb_set_group_gid(struct sysdb_handle *handle, - struct sss_domain_info *domain, - const char *name, gid_t gid, - sysdb_callback_t fn, void *pvt) -{ - struct group_add_ctx *group_ctx; - struct sysdb_ctx *sysdb; - struct ldb_message *msg; - struct ldb_request *req; - int flags = LDB_FLAG_MOD_REPLACE; +static void sysdb_add_group_set_attrs_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); int ret; - if (!sysdb_handle_check_running(handle)) { - DEBUG(2, ("Invalid request! Not running at this time.\n")); - return EINVAL; + ret = sysdb_set_group_attr_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; } - /* Validate that the target GID is within the domain range */ - if((gid < domain->id_min) || - (domain->id_max && (gid > domain->id_max))) { - DEBUG(2, ("Invalid request. Domain ID out of range")); - return EDOM; - } + tevent_req_done(req); +} + +int sysdb_add_group_recv(struct tevent_req *req) +{ + return sysdb_op_default_recv(req); +} - group_ctx = talloc(handle, struct group_add_ctx); - if (!group_ctx) return ENOMEM; - group_ctx->cbctx = talloc_zero(group_ctx, struct sysdb_cb_ctx); - if (!group_ctx->cbctx) return ENOMEM; +/* =Add-Or-Remove-Group-Memeber=========================================== */ - group_ctx->handle = handle; - group_ctx->domain = domain; - group_ctx->cbctx->fn = fn; - group_ctx->cbctx->pvt = pvt; - group_ctx->name = name; - group_ctx->gid = gid; +/* mod_op must be either SYSDB_MOD_ADD or SYSDB_MOD_DEL */ +struct tevent_req *sysdb_mod_group_member_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct ldb_dn *member_dn, + struct ldb_dn *group_dn, + int mod_op) +{ + struct tevent_req *req, *subreq; + struct sysdb_op_state *state; + struct ldb_request *ldbreq; + struct ldb_message *msg; + const char *dn; + int ret; - sysdb = sysdb_handle_get_ctx(group_ctx->handle); + req = tevent_req_create(mem_ctx, &state, struct sysdb_op_state); + if (!req) return NULL; - msg = ldb_msg_new(group_ctx); - if (!msg) return ENOMEM; + state->ev = ev; + state->handle = handle; + state->ignore_not_found = false; + state->ldbreply = NULL; - msg->dn = sysdb_group_dn(sysdb, msg, - group_ctx->domain->name, - group_ctx->name); - if (!msg->dn) return ENOMEM; + msg = ldb_msg_new(state); + if (!msg) { + ERROR_OUT(ret, ENOMEM, fail); + } - ret = add_ulong(msg, flags, SYSDB_GIDNUM, - (unsigned long)(group_ctx->gid)); + msg->dn = group_dn; + ret = ldb_msg_add_empty(msg, SYSDB_MEMBER, mod_op, NULL); + if (ret != LDB_SUCCESS) { + ERROR_OUT(ret, ENOMEM, fail); + } - ret = ldb_build_mod_req(&req, sysdb->ldb, group_ctx, msg, NULL, - group_ctx->cbctx, sysdb_op_callback, NULL); - if (ret == LDB_SUCCESS) { - ret = ldb_request(sysdb->ldb, req); + dn = ldb_dn_get_linearized(member_dn); + if (!dn) { + ERROR_OUT(ret, EINVAL, fail); } + + ret = ldb_msg_add_fmt(msg, SYSDB_MEMBER, "%s", dn); if (ret != LDB_SUCCESS) { - return sysdb_error_to_errno(ret); + ERROR_OUT(ret, EINVAL, fail); } - return EOK; + ret = ldb_build_mod_req(&ldbreq, handle->ctx->ldb, state, msg, + NULL, NULL, NULL, NULL); + if (ret != LDB_SUCCESS) { + DEBUG(1, ("Failed to build modify request: %s(%d)[%s]\n", + ldb_strerror(ret), ret, ldb_errstring(handle->ctx->ldb))); + ERROR_OUT(ret, sysdb_error_to_errno(ret), fail); + } + + subreq = sldb_request_send(state, ev, handle->ctx->ldb, ldbreq); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); + } + tevent_req_set_callback(subreq, sysdb_op_default_done, req); + + return req; + +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; +} + +int sysdb_mod_group_member_recv(struct tevent_req *req) +{ + return sysdb_op_default_recv(req); } -/* "sysdb_legacy_" functions - * the set of functions named sysdb_legacy_* are used by modules - * that only have access to strictly posix like databases where - * user and groups names are retrieved as strings, groups can't - * be nested and can't reference foreign sources */ -struct legacy_user_ctx { +/* =Store-Users-(Native/Legacy)-(replaces-existing-data)================== */ + +/* if one of the basic attributes is empty ("") as opposed to NULL, + * this will just remove it */ + +struct sysdb_store_user_state { + struct tevent_context *ev; struct sysdb_handle *handle; - struct sysdb_cb_ctx *cbctx; struct sss_domain_info *domain; - struct ldb_dn *dn; - const char *name; - const char *pwd; uid_t uid; gid_t gid; const char *gecos; const char *homedir; const char *shell; - - struct ldb_result *res; + struct sysdb_attrs *attrs; }; -static int legacy_user_callback(struct ldb_request *req, - struct ldb_reply *rep); - -int sysdb_legacy_store_user(struct sysdb_handle *handle, - struct sss_domain_info *domain, - const char *name, const char *pwd, - uid_t uid, gid_t gid, const char *gecos, - const char *homedir, const char *shell, - sysdb_callback_t fn, void *pvt) +static void sysdb_store_user_check(struct tevent_req *subreq); +static void sysdb_store_user_add_done(struct tevent_req *subreq); +static void sysdb_store_user_attr_done(struct tevent_req *subreq); + +struct tevent_req *sysdb_store_user_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name, + const char *pwd, + uid_t uid, gid_t gid, + const char *gecos, + const char *homedir, + const char *shell) { - static const char *attrs[] = { SYSDB_NAME, NULL }; - struct legacy_user_ctx *user_ctx; - struct sysdb_ctx *ctx; - struct ldb_request *req; + struct tevent_req *req, *subreq; + struct sysdb_store_user_state *state; int ret; - if (!sysdb_handle_check_running(handle)) { - DEBUG(2, ("Invalid request! Not running at this time.\n")); - return EINVAL; - } - - ctx = sysdb_handle_get_ctx(handle); + req = tevent_req_create(mem_ctx, &state, struct sysdb_store_user_state); + if (!req) return NULL; - user_ctx = talloc(handle, struct legacy_user_ctx); - if (!user_ctx) return ENOMEM; + state->ev = ev; + state->handle = handle; + state->domain = domain; + state->name = name; + state->uid = uid; + state->gid = gid; + state->gecos = gecos; + state->homedir = homedir; + state->shell = shell; + state->attrs = NULL; - user_ctx->cbctx = talloc_zero(user_ctx, struct sysdb_cb_ctx); - if (!user_ctx->cbctx) return ENOMEM; - - user_ctx->dn = sysdb_user_dn(ctx, user_ctx, domain->name, name); - if (!user_ctx->dn) return ENOMEM; - - user_ctx->handle = handle; - user_ctx->cbctx->fn = fn; - user_ctx->cbctx->pvt = pvt; - user_ctx->domain = domain; - user_ctx->name = name; - user_ctx->pwd = pwd; - user_ctx->uid = uid; - user_ctx->gid = gid; - user_ctx->gecos = gecos; - user_ctx->homedir = homedir; - user_ctx->shell = shell; - - user_ctx->res = talloc_zero(user_ctx, struct ldb_result); - if (!user_ctx->res) return ENOMEM; + if (pwd && (domain->legacy_passwords || !*pwd)) { + ret = sysdb_attrs_add_string(state->attrs, SYSDB_PWD, pwd); + if (ret) goto fail; + } - ret = ldb_build_search_req(&req, ctx->ldb, user_ctx, - user_ctx->dn, LDB_SCOPE_BASE, - SYSDB_PWENT_FILTER, attrs, NULL, - user_ctx, legacy_user_callback, NULL); - if (ret != LDB_SUCCESS) { - DEBUG(1, ("Failed to build search request: %s(%d)[%s]\n", - ldb_strerror(ret), ret, ldb_errstring(ctx->ldb))); - return sysdb_error_to_errno(ret); + subreq = sysdb_search_user_by_name_send(state, ev, handle, domain, name); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); } + tevent_req_set_callback(subreq, sysdb_store_user_check, req); - ret = ldb_request(ctx->ldb, req); - if (ret != LDB_SUCCESS) return sysdb_error_to_errno(ret); + return req; - return EOK; +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; } -static int legacy_user_callback(struct ldb_request *req, - struct ldb_reply *rep) +static void sysdb_store_user_check(struct tevent_req *subreq) { - struct legacy_user_ctx *user_ctx; - struct sysdb_cb_ctx *cbctx; - struct sysdb_ctx *ctx; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_store_user_state *state = tevent_req_data(req, + struct sysdb_store_user_state); struct ldb_message *msg; - struct ldb_request *ureq; - struct ldb_result *res; - int flags; - int ret, err; - - user_ctx = talloc_get_type(req->context, struct legacy_user_ctx); - ctx = sysdb_handle_get_ctx(user_ctx->handle); - cbctx = user_ctx->cbctx; - res = user_ctx->res; + int ret; - if (!rep) { - return sysdb_ret_error(cbctx, EIO, LDB_ERR_OPERATIONS_ERROR); - } - if (rep->error != LDB_SUCCESS) { - err = sysdb_error_to_errno(rep->error); - return sysdb_ret_error(cbctx, err, rep->error); + ret = sysdb_search_user_recv(subreq, state, &msg); + talloc_zfree(subreq); + if (ret && ret != ENOENT) { + tevent_req_error(req, ret); + return; } - switch (rep->type) { - case LDB_REPLY_ENTRY: - res->msgs = talloc_realloc(res, res->msgs, - struct ldb_message *, - res->count + 2); - if (!res->msgs) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); + if (ret == ENOENT) { + /* users doesn't exist, turn into adding a user */ + subreq = sysdb_add_user_send(state, state->ev, state->handle, + state->domain, state->name, + state->uid, state->gid, + state->gecos, state->homedir, + state->shell, state->attrs); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; } + tevent_req_set_callback(subreq, sysdb_store_user_add_done, req); + return; + } - res->msgs[res->count + 1] = NULL; - - res->msgs[res->count] = talloc_steal(res->msgs, rep->message); - res->count++; - - break; - - case LDB_REPLY_DONE: - - msg = ldb_msg_new(cbctx); - if (!msg) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); - } - msg->dn = user_ctx->dn; - - switch (res->count) { - case 0: - flags = LDB_FLAG_MOD_ADD; - break; - case 1: - flags = LDB_FLAG_MOD_REPLACE; - break; - default: - DEBUG(0, ("Cache DB corrupted, base search returned %d results\n", - res->count)); - - return sysdb_ret_error(cbctx, EFAULT, LDB_ERR_OPERATIONS_ERROR); + /* the user exists, let's just replace attributes when set */ + if (!state->attrs) { + state->attrs = sysdb_new_attrs(state); + if (!state->attrs) { + tevent_req_error(req, ENOMEM); + return; } + } - talloc_free(res); - user_ctx->res = res = NULL; - - if (flags == LDB_FLAG_MOD_ADD) { - ret = add_string(msg, flags, "objectClass", SYSDB_USER_CLASS); - if (ret != LDB_SUCCESS) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); - } - - ret = add_string(msg, flags, SYSDB_NAME, user_ctx->name); - if (ret != LDB_SUCCESS) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); - } + if (state->uid) { + ret = sysdb_attrs_add_uint32(state->attrs, SYSDB_UIDNUM, state->uid); + if (ret) { + tevent_req_error(req, ret); + return; } + } - if (user_ctx->domain->legacy_passwords && - user_ctx->pwd && *user_ctx->pwd) { - ret = add_string(msg, flags, SYSDB_PWD, user_ctx->pwd); - } else { - ret = ldb_msg_add_empty(msg, SYSDB_PWD, - LDB_FLAG_MOD_DELETE, NULL); - } - if (ret != LDB_SUCCESS) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); + if (state->gid) { + ret = sysdb_attrs_add_uint32(state->attrs, SYSDB_GIDNUM, state->gid); + if (ret) { + tevent_req_error(req, ret); + return; } + } - if (user_ctx->uid) { - ret = add_ulong(msg, flags, SYSDB_UIDNUM, - (unsigned long)(user_ctx->uid)); - if (ret != LDB_SUCCESS) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); - } - } else { - DEBUG(0, ("Cached users can't have UID == 0\n")); - return sysdb_ret_error(cbctx, EINVAL, LDB_ERR_OPERATIONS_ERROR); + if (state->uid && !state->gid && state->domain->mpg) { + ret = sysdb_attrs_add_uint32(state->attrs, SYSDB_GIDNUM, state->uid); + if (ret) { + tevent_req_error(req, ret); + return; } + } - if (user_ctx->gid) { - ret = add_ulong(msg, flags, SYSDB_GIDNUM, - (unsigned long)(user_ctx->gid)); - if (ret != LDB_SUCCESS) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); - } - } else { - DEBUG(0, ("Cached users can't have GID == 0\n")); - return sysdb_ret_error(cbctx, EINVAL, LDB_ERR_OPERATIONS_ERROR); + if (state->gecos) { + ret = sysdb_attrs_add_string(state->attrs, SYSDB_GECOS, state->gecos); + if (ret) { + tevent_req_error(req, ret); + return; } + } - if (user_ctx->gecos && *user_ctx->gecos) { - ret = add_string(msg, flags, SYSDB_GECOS, user_ctx->gecos); - } else { - ret = ldb_msg_add_empty(msg, SYSDB_GECOS, - LDB_FLAG_MOD_DELETE, NULL); - } - if (ret != LDB_SUCCESS) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); + if (state->homedir) { + ret = sysdb_attrs_add_string(state->attrs, + SYSDB_HOMEDIR, state->homedir); + if (ret) { + tevent_req_error(req, ret); + return; } + } - if (user_ctx->homedir && *user_ctx->homedir) { - ret = add_string(msg, flags, SYSDB_HOMEDIR, user_ctx->homedir); - } else { - ret = ldb_msg_add_empty(msg, SYSDB_HOMEDIR, - LDB_FLAG_MOD_DELETE, NULL); - } - if (ret != LDB_SUCCESS) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); + if (state->shell) { + ret = sysdb_attrs_add_string(state->attrs, SYSDB_SHELL, state->shell); + if (ret) { + tevent_req_error(req, ret); + return; } + } - if (user_ctx->shell && *user_ctx->shell) { - ret = add_string(msg, flags, SYSDB_SHELL, user_ctx->shell); - } else { - ret = ldb_msg_add_empty(msg, SYSDB_SHELL, - LDB_FLAG_MOD_DELETE, NULL); - } - if (ret != LDB_SUCCESS) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); - } + ret = sysdb_attrs_add_time_t(state->attrs, SYSDB_LAST_UPDATE, time(NULL)); + if (ret) { + tevent_req_error(req, ret); + return; + } - /* modification time */ - ret = add_ulong(msg, flags, SYSDB_LAST_UPDATE, - (unsigned long)time(NULL)); - if (ret != LDB_SUCCESS) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); - } + subreq = sysdb_set_user_attr_send(state, state->ev, + state->handle, state->domain, + state->name, state->attrs, + SYSDB_MOD_REP); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_store_user_attr_done, req); +} - if (flags == LDB_FLAG_MOD_ADD) { - ret = ldb_build_add_req(&ureq, ctx->ldb, cbctx, msg, NULL, - cbctx, sysdb_op_callback, NULL); - } else { - ret = ldb_build_mod_req(&ureq, ctx->ldb, cbctx, msg, NULL, - cbctx, sysdb_op_callback, NULL); - } - if (ret == LDB_SUCCESS) { - ret = ldb_request(ctx->ldb, ureq); - } - if (ret != LDB_SUCCESS) { - err = sysdb_error_to_errno(ret); - return sysdb_ret_error(cbctx, err, ret); - } - break; +static void sysdb_store_user_add_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + int ret; - default: - return sysdb_ret_error(cbctx, EINVAL, LDB_ERR_OPERATIONS_ERROR); + ret = sysdb_add_user_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; } - talloc_free(rep); - return LDB_SUCCESS; + tevent_req_done(req); } +static void sysdb_store_user_attr_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + int ret; + ret = sysdb_set_user_attr_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } + + tevent_req_done(req); +} + +int sysdb_store_user_recv(struct tevent_req *req) +{ + return sysdb_op_default_recv(req); +} + + +/* =Store-Group-(Native/Legacy)-(replaces-existing-data)================== */ /* this function does not check that all user members are actually present */ -struct legacy_group_ctx { +struct sysdb_store_group_state { + struct tevent_context *ev; struct sysdb_handle *handle; - struct sysdb_cb_ctx *cbctx; struct sss_domain_info *domain; - struct ldb_dn *dn; - const char *name; gid_t gid; const char **members; - struct ldb_result *res; + struct sysdb_attrs *attrs; }; -static int legacy_group_callback(struct ldb_request *req, - struct ldb_reply *rep); - -int sysdb_legacy_store_group(struct sysdb_handle *handle, - struct sss_domain_info *domain, - const char *name, gid_t gid, - const char **members, - sysdb_callback_t fn, void *pvt) +static void sysdb_store_group_check(struct tevent_req *subreq); +static void sysdb_store_group_add_done(struct tevent_req *subreq); +static void sysdb_store_group_attr_done(struct tevent_req *subreq); + +struct tevent_req *sysdb_store_group_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *name, + gid_t gid, + const char **members) { - static const char *attrs[] = { SYSDB_NAME, NULL }; - struct legacy_group_ctx *group_ctx; - struct sysdb_ctx *ctx; - struct ldb_request *req; - int ret; + struct tevent_req *req, *subreq; + struct sysdb_store_group_state *state; + int ret, i; + + req = tevent_req_create(mem_ctx, &state, struct sysdb_store_group_state); + if (!req) return NULL; + + state->ev = ev; + state->handle = handle; + state->domain = domain; + state->name = name; + state->gid = gid; + state->members = members; + state->attrs = NULL; + + if (state->members) { + state->attrs = sysdb_new_attrs(state); + if (!state->attrs) { + ERROR_OUT(ret, ENOMEM, fail); + } + + for (i = 0; state->members[i]; i++) { + if (domain->legacy) { +/* + const char *member; - if (!sysdb_handle_check_running(handle)) { - DEBUG(2, ("Invalid request! Not running at this time.\n")); - return EINVAL; + member = talloc_asprintf(state, SYSDB_TMPL_USER, + domain->name, state->members[i]); + if (!member) { + ERROR_OUT(ret, ENOMEM, fail); + } +*/ + ret = sysdb_attrs_add_string(state->attrs, SYSDB_LEGACY_MEMBER, + state->members[i]); + if (ret) goto fail; + } else { + ret = sysdb_attrs_add_string(state->attrs, SYSDB_MEMBER, + state->members[i]); + if (ret) goto fail; + } + } + + state->members = NULL; } - ctx = sysdb_handle_get_ctx(handle); + subreq = sysdb_search_group_by_name_send(state, ev, handle, domain, name); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); + } + tevent_req_set_callback(subreq, sysdb_store_group_check, req); - group_ctx = talloc(handle, struct legacy_group_ctx); - if (!group_ctx) return ENOMEM; + return req; - group_ctx->cbctx = talloc_zero(group_ctx, struct sysdb_cb_ctx); - if (!group_ctx->cbctx) return ENOMEM; +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; +} - group_ctx->dn = sysdb_group_dn(ctx, group_ctx, domain->name, name); - if (!group_ctx->dn) return ENOMEM; +static void sysdb_store_group_check(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct sysdb_store_group_state *state = tevent_req_data(req, + struct sysdb_store_group_state); + struct ldb_message *msg; + int ret; - group_ctx->handle = handle; - group_ctx->cbctx->fn = fn; - group_ctx->cbctx->pvt = pvt; - group_ctx->domain = domain; - group_ctx->name = name; - group_ctx->gid = gid; - group_ctx->members = members; + ret = sysdb_search_group_recv(subreq, state, &msg); + talloc_zfree(subreq); + if (ret && ret != ENOENT) { + tevent_req_error(req, ret); + return; + } - group_ctx->res = talloc_zero(group_ctx, struct ldb_result); - if (!group_ctx->res) return ENOMEM; + if (ret == ENOENT) { + /* groups doesn't exist, turn into adding a group */ + subreq = sysdb_add_group_send(state, state->ev, state->handle, + state->domain, state->name, + state->gid, state->attrs); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_store_group_add_done, req); + return; + } - ret = ldb_build_search_req(&req, ctx->ldb, group_ctx, - group_ctx->dn, LDB_SCOPE_BASE, - SYSDB_GRENT_FILTER, attrs, NULL, - group_ctx, legacy_group_callback, NULL); - if (ret != LDB_SUCCESS) { - DEBUG(1, ("Failed to build search request: %s(%d)[%s]\n", - ldb_strerror(ret), ret, ldb_errstring(ctx->ldb))); - return sysdb_error_to_errno(ret); + /* the group exists, let's just replace attributes when set */ + if (!state->attrs) { + state->attrs = sysdb_new_attrs(state); + if (!state->attrs) { + tevent_req_error(req, ENOMEM); + return; + } } - ret = ldb_request(ctx->ldb, req); - if (ret != LDB_SUCCESS) return sysdb_error_to_errno(ret); + if (state->gid) { + ret = sysdb_attrs_add_uint32(state->attrs, SYSDB_GIDNUM, state->gid); + if (ret) { + tevent_req_error(req, ret); + return; + } + } - return EOK; + /* FIXME: handle non legacy groups */ + + ret = sysdb_attrs_add_time_t(state->attrs, SYSDB_LAST_UPDATE, time(NULL)); + if (ret) { + tevent_req_error(req, ret); + return; + } + + subreq = sysdb_set_group_attr_send(state, state->ev, + state->handle, state->domain, + state->name, state->attrs, + SYSDB_MOD_REP); + if (!subreq) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, sysdb_store_group_attr_done, req); } -static int legacy_group_callback(struct ldb_request *req, - struct ldb_reply *rep) +static void sysdb_store_group_add_done(struct tevent_req *subreq) { - struct legacy_group_ctx *group_ctx; - struct sysdb_cb_ctx *cbctx; - struct sysdb_ctx *ctx; - struct ldb_message *msg; - struct ldb_request *greq; - struct ldb_result *res; - int flags; - int i, ret, err; - - group_ctx = talloc_get_type(req->context, struct legacy_group_ctx); - ctx = sysdb_handle_get_ctx(group_ctx->handle); - cbctx = group_ctx->cbctx; - res = group_ctx->res; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + int ret; - if (!rep) { - return sysdb_ret_error(cbctx, EIO, LDB_ERR_OPERATIONS_ERROR); + ret = sysdb_add_group_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; } - if (rep->error != LDB_SUCCESS) { - err = sysdb_error_to_errno(rep->error); - return sysdb_ret_error(cbctx, err, rep->error); + + tevent_req_done(req); +} + +static void sysdb_store_group_attr_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + int ret; + + ret = sysdb_set_group_attr_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; } - switch (rep->type) { - case LDB_REPLY_ENTRY: - res->msgs = talloc_realloc(res, res->msgs, - struct ldb_message *, - res->count + 2); - if (!res->msgs) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); - } + tevent_req_done(req); +} - res->msgs[res->count + 1] = NULL; +int sysdb_store_group_recv(struct tevent_req *req) +{ + return sysdb_op_default_recv(req); +} - res->msgs[res->count] = talloc_steal(res->msgs, rep->message); - res->count++; - break; +/* =Add-User-to-Group(Native/Legacy)====================================== */ - case LDB_REPLY_DONE: +static void sysdb_add_group_member_done(struct tevent_req *subreq); +static void sysdb_add_group_member_l_done(struct tevent_req *subreq); - msg = ldb_msg_new(cbctx); - if (!msg) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); - } - msg->dn = group_ctx->dn; - - switch (res->count) { - case 0: - flags = LDB_FLAG_MOD_ADD; - break; - case 1: - flags = LDB_FLAG_MOD_REPLACE; - break; - default: - DEBUG(0, ("Cache DB corrupted, base search returned %d results\n", - res->count)); - - return sysdb_ret_error(cbctx, EFAULT, LDB_ERR_OPERATIONS_ERROR); - } +struct tevent_req *sysdb_add_group_member_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *group, + const char *user) +{ + struct tevent_req *req, *subreq; + struct sysdb_op_state *state; + struct ldb_dn *group_dn, *user_dn; + struct sysdb_attrs *attrs; + int ret; - talloc_free(res); - group_ctx->res = res = NULL; + req = tevent_req_create(mem_ctx, &state, struct sysdb_op_state); + if (!req) return NULL; - if (flags == LDB_FLAG_MOD_ADD) { - ret = add_string(msg, flags, "objectClass", SYSDB_GROUP_CLASS); - if (ret != LDB_SUCCESS) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); - } + state->ev = ev; + state->handle = handle; + state->ignore_not_found = false; + state->ldbreply = NULL; - ret = add_string(msg, flags, SYSDB_NAME, group_ctx->name); - if (ret != LDB_SUCCESS) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); - } + if (domain->legacy) { + attrs = sysdb_new_attrs(state); + if (!attrs) { + ERROR_OUT(ret, ENOMEM, fail); } - if (group_ctx->gid) { - ret = add_ulong(msg, flags, SYSDB_GIDNUM, - (unsigned long)(group_ctx->gid)); - if (ret != LDB_SUCCESS) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); - } - } else { - DEBUG(0, ("Cached groups can't have GID == 0\n")); - return sysdb_ret_error(cbctx, EINVAL, LDB_ERR_OPERATIONS_ERROR); - } + ret = sysdb_attrs_add_string(attrs, SYSDB_LEGACY_MEMBER, user); + if (ret) goto fail; - /* members */ - if (group_ctx->members && group_ctx->members[0]) { - ret = ldb_msg_add_empty(msg, SYSDB_LEGACY_MEMBER, flags, NULL); - if (ret != LDB_SUCCESS) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); - } - for (i = 0; group_ctx->members[i]; i++) { - ret = ldb_msg_add_string(msg, SYSDB_LEGACY_MEMBER, - group_ctx->members[i]); - if (ret != LDB_SUCCESS) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); - } - } + subreq = sysdb_set_group_attr_send(state, ev, handle, + domain, group, attrs, + SYSDB_MOD_ADD); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); } + tevent_req_set_callback(subreq, sysdb_add_group_member_l_done, req); - /* modification time */ - ret = add_ulong(msg, flags, SYSDB_LAST_UPDATE, - (unsigned long)time(NULL)); - if (ret != LDB_SUCCESS) { - return sysdb_ret_error(cbctx, ENOMEM, LDB_ERR_OPERATIONS_ERROR); + } else { + group_dn = sysdb_group_dn(handle->ctx, state, domain->name, group); + if (!group_dn) { + ERROR_OUT(ret, ENOMEM, fail); } - if (flags == LDB_FLAG_MOD_ADD) { - ret = ldb_build_add_req(&greq, ctx->ldb, cbctx, msg, NULL, - cbctx, sysdb_op_callback, NULL); - } else { - ret = ldb_build_mod_req(&greq, ctx->ldb, cbctx, msg, NULL, - cbctx, sysdb_op_callback, NULL); - } - if (ret == LDB_SUCCESS) { - ret = ldb_request(ctx->ldb, greq); + user_dn = sysdb_user_dn(handle->ctx, state, domain->name, user); + if (!user_dn) { + ERROR_OUT(ret, ENOMEM, fail); } - if (ret != LDB_SUCCESS) { - err = sysdb_error_to_errno(ret); - return sysdb_ret_error(cbctx, err, ret); + + subreq = sysdb_mod_group_member_send(state, ev, handle, + user_dn, group_dn, + SYSDB_MOD_ADD); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); } - break; + tevent_req_set_callback(subreq, sysdb_add_group_member_done, req); + } - default: - return sysdb_ret_error(cbctx, EINVAL, LDB_ERR_OPERATIONS_ERROR); + return req; + +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; +} + +static void sysdb_add_group_member_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + int ret; + + ret = sysdb_mod_group_member_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; } - talloc_free(rep); - return LDB_SUCCESS; + tevent_req_done(req); } -int sysdb_legacy_add_group_member(struct sysdb_handle *handle, - struct sss_domain_info *domain, - const char *group, - const char *member, - sysdb_callback_t fn, void *pvt) +static void sysdb_add_group_member_l_done(struct tevent_req *subreq) { - struct sysdb_ctx *ctx; - struct sysdb_cb_ctx *cbctx; - struct ldb_request *req; - struct ldb_message *msg; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); int ret; - if (!sysdb_handle_check_running(handle)) { - DEBUG(2, ("Invalid request! Not running at this time.\n")); - return EINVAL; + ret = sysdb_set_group_attr_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; } - ctx = sysdb_handle_get_ctx(handle); + tevent_req_done(req); +} + +int sysdb_add_group_member_recv(struct tevent_req *req) +{ + return sysdb_op_default_recv(req); +} + - cbctx = talloc_zero(handle, struct sysdb_cb_ctx); - if (!cbctx) return ENOMEM; +/* =Remove-member-from-Group(Native/Legacy)=============================== */ - cbctx->fn = fn; - cbctx->pvt = pvt; +static void sysdb_remove_group_member_done(struct tevent_req *subreq); +static void sysdb_remove_group_member_l_done(struct tevent_req *subreq); - /* Add the member_dn as a member of the group */ - msg = ldb_msg_new(cbctx); - if(msg == NULL) return ENOMEM; +struct tevent_req *sysdb_remove_group_member_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *group, + const char *user) +{ + struct tevent_req *req, *subreq; + struct sysdb_op_state *state; + struct ldb_dn *group_dn, *user_dn; + struct sysdb_attrs *attrs; + int ret; - msg->dn = sysdb_group_dn(ctx, cbctx, domain->name, group); - if (!msg->dn) return ENOMEM; + req = tevent_req_create(mem_ctx, &state, struct sysdb_op_state); + if (!req) return NULL; - ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_LEGACY_MEMBER, member); - if (ret != LDB_SUCCESS) return ENOMEM; + state->ev = ev; + state->handle = handle; + state->ignore_not_found = false; + state->ldbreply = NULL; - ret = ldb_build_mod_req(&req, ctx->ldb, cbctx, msg, - NULL, cbctx, sysdb_op_callback, NULL); - if (ret != LDB_SUCCESS) { - DEBUG(1, ("Failed to build modify request: %s(%d)[%s]\n", - ldb_strerror(ret), ret, ldb_errstring(ctx->ldb))); - return sysdb_error_to_errno(ret); + if (domain->legacy) { + attrs = sysdb_new_attrs(state); + if (!attrs) { + ERROR_OUT(ret, ENOMEM, fail); + } + + ret = sysdb_attrs_add_string(attrs, SYSDB_LEGACY_MEMBER, user); + if (ret) goto fail; + + subreq = sysdb_set_group_attr_send(state, ev, handle, + domain, group, attrs, + SYSDB_MOD_DEL); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); + } + tevent_req_set_callback(subreq, sysdb_remove_group_member_l_done, req); + + } else { + group_dn = sysdb_group_dn(handle->ctx, state, domain->name, group); + if (!group_dn) { + ERROR_OUT(ret, ENOMEM, fail); + } + + user_dn = sysdb_user_dn(handle->ctx, state, domain->name, user); + if (!user_dn) { + ERROR_OUT(ret, ENOMEM, fail); + } + + subreq = sysdb_mod_group_member_send(state, ev, handle, + user_dn, group_dn, + SYSDB_MOD_DEL); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); + } + tevent_req_set_callback(subreq, sysdb_remove_group_member_done, req); } - ret = ldb_request(ctx->ldb, req); - if (ret != LDB_SUCCESS) return sysdb_error_to_errno(ret); + return req; - return EOK; +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; } -int sysdb_legacy_remove_group_member(struct sysdb_handle *handle, - struct sss_domain_info *domain, - const char *group, - const char *member, - sysdb_callback_t fn, void *pvt) +static void sysdb_remove_group_member_done(struct tevent_req *subreq) { - struct sysdb_ctx *ctx; - struct sysdb_cb_ctx *cbctx; - struct ldb_request *req; - struct ldb_message *msg; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); int ret; - if (!sysdb_handle_check_running(handle)) { - DEBUG(2, ("Invalid request! Not running at this time.\n")); - return EINVAL; + ret = sysdb_mod_group_member_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; } - ctx = sysdb_handle_get_ctx(handle); - - cbctx = talloc_zero(handle, struct sysdb_cb_ctx); - if (!cbctx) return ENOMEM; + tevent_req_done(req); +} - cbctx->fn = fn; - cbctx->pvt = pvt; +static void sysdb_remove_group_member_l_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + int ret; - /* Add the member_dn as a member of the group */ - msg = ldb_msg_new(cbctx); - if(msg == NULL) return ENOMEM; + ret = sysdb_set_group_attr_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } - msg->dn = sysdb_group_dn(ctx, cbctx, domain->name, group); - if (!msg->dn) return ENOMEM; + tevent_req_done(req); +} - ret = add_string(msg, LDB_FLAG_MOD_DELETE, SYSDB_LEGACY_MEMBER, member); - if (ret != LDB_SUCCESS) return ENOMEM; +int sysdb_remove_group_member_recv(struct tevent_req *req) +{ + return sysdb_op_default_recv(req); +} - ret = ldb_build_mod_req(&req, ctx->ldb, cbctx, msg, - NULL, cbctx, sysdb_op_callback, NULL); - if (ret != LDB_SUCCESS) { - DEBUG(1, ("Failed to build modify request: %s(%d)[%s]\n", - ldb_strerror(ret), ret, ldb_errstring(ctx->ldb))); - return sysdb_error_to_errno(ret); - } - ret = ldb_request(ctx->ldb, req); - if (ret != LDB_SUCCESS) return sysdb_error_to_errno(ret); +/* ======================================================================= */ - return EOK; -} +static void sysdb_set_cached_password_done(struct tevent_req *subreq); -int sysdb_set_cached_password(struct sysdb_handle *handle, - struct sss_domain_info *domain, - const char *user, - const char *password, - sysdb_callback_t fn, void *pvt) +struct tevent_req *sysdb_set_cached_password_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_handle *handle, + struct sss_domain_info *domain, + const char *user, + const char *password) { - struct sysdb_ctx *ctx; + struct tevent_req *req, *subreq; + struct sysdb_op_state *state; struct sysdb_attrs *attrs; char *hash = NULL; char *salt; int ret; - ctx = sysdb_handle_get_ctx(handle); - if (!ctx) return EFAULT; + req = tevent_req_create(mem_ctx, &state, struct sysdb_op_state); + if (!req) return NULL; + + state->ev = ev; + state->handle = handle; + state->ignore_not_found = false; + state->ldbreply = NULL; - ret = s3crypt_gen_salt(handle, &salt); + ret = s3crypt_gen_salt(state, &salt); if (ret) { DEBUG(4, ("Failed to generate random salt.\n")); - return ret; + goto fail; } - ret = s3crypt_sha512(handle, password, salt, &hash); + ret = s3crypt_sha512(state, password, salt, &hash); if (ret) { DEBUG(4, ("Failed to create password hash.\n")); - return ret; + goto fail; } - attrs = sysdb_new_attrs(handle); + attrs = sysdb_new_attrs(state); if (!attrs) { - return ENOMEM; + ERROR_OUT(ret, ENOMEM, fail); } ret = sysdb_attrs_add_string(attrs, SYSDB_CACHEDPWD, hash); - if (ret) return ret; + if (ret) goto fail; /* FIXME: should we use a different attribute for chache passwords ?? */ ret = sysdb_attrs_add_long(attrs, "lastCachedPasswordChange", (long)time(NULL)); - if (ret) return ret; + if (ret) goto fail; - ret = sysdb_set_user_attr(handle, domain, user, attrs, fn, pvt); - if (ret) return ret; + subreq = sysdb_set_user_attr_send(state, ev, handle, domain, + user, attrs, SYSDB_MOD_REP); + if (!subreq) { + ERROR_OUT(ret, ENOMEM, fail); + } + tevent_req_set_callback(subreq, sysdb_set_cached_password_done, req); - return EOK; + return req; + +fail: + tevent_req_error(req, ret); + tevent_req_post(req, ev); + return req; } + +static void sysdb_set_cached_password_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + int ret; + + ret = sysdb_set_user_attr_recv(subreq); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } + + tevent_req_done(req); +} + +int sysdb_set_cached_password_recv(struct tevent_req *req) +{ + return sysdb_op_default_recv(req); +} + diff --git a/server/db/sysdb_private.h b/server/db/sysdb_private.h index 8c10d951..d15ec370 100644 --- a/server/db/sysdb_private.h +++ b/server/db/sysdb_private.h @@ -68,15 +68,36 @@ #include "db/sysdb.h" -struct sysdb_handle; +struct sysdb_handle { + struct sysdb_handle *prev; + struct sysdb_handle *next; + + struct sysdb_ctx *ctx; + struct tevent_req *subreq; + + bool transaction_active; +}; struct sysdb_ctx { struct tevent_context *ev; struct ldb_context *ldb; char *ldb_file; + struct sysdb_handle *queue; }; -bool sysdb_handle_check_running(struct sysdb_handle *handle); +/* An operation blocks the transaction queue as well, but does not + * start a transaction, normally useful only for search type calls. + * do *NOT* call within a transaction you'll deadlock sysdb. + * Also make sure to free the handle as soon as the operation is + * finished to avoid stalling or potentially deadlocking sysdb */ + +struct tevent_req *sysdb_operation_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sysdb_ctx *ctx); +int sysdb_operation_recv(struct tevent_req *req, TALLOC_CTX *memctx, + struct sysdb_handle **handle); + +void sysdb_operation_done(struct sysdb_handle *handle); #endif /* __INT_SYS_DB_H__ */ diff --git a/server/db/sysdb_req.c b/server/db/sysdb_req.c deleted file mode 100644 index a768fefb..00000000 --- a/server/db/sysdb_req.c +++ /dev/null @@ -1,252 +0,0 @@ -/* - SSSD - - System Database - - Copyright (C) Simo Sorce <ssorce@redhat.com> 2009 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include <time.h> -#include "util/util.h" -#include "util/dlinklist.h" -#include "db/sysdb_private.h" -#include "ldb.h" - -struct sysdb_handle { - struct sysdb_handle *next, *prev; - struct sysdb_ctx *ctx; - sysdb_fn_t fn; - void *pvt; - int status; - bool transaction_active; -}; - -bool sysdb_handle_check_running(struct sysdb_handle *handle) -{ - if (handle->ctx->queue == handle) return true; - return false; -} - -struct sysdb_ctx *sysdb_handle_get_ctx(struct sysdb_handle *handle) -{ - return handle->ctx; -} - -static void sysdb_queue_run(struct tevent_context *ev, - struct tevent_timer *te, - struct timeval tv, void *ptr) -{ - struct sysdb_handle *handle = talloc_get_type(ptr, struct sysdb_handle); - - if (handle != handle->ctx->queue) abort(); - - handle->fn(handle, handle->pvt); -} - -static int sysdb_queue_schedule(struct sysdb_handle *handle) -{ - struct tevent_timer *te = NULL; - struct timeval tv; - - /* call it asap */ - tv.tv_sec = 0; - tv.tv_usec = 0; - - te = tevent_add_timer(handle->ctx->ev, handle, tv, sysdb_queue_run, handle); - if (te == NULL) { - return EIO; - } - - return EOK; -} - -static int sysdb_enqueue(struct sysdb_handle *handle) -{ - int ret = EOK; - - DLIST_ADD_END(handle->ctx->queue, handle, struct sysdb_handle *); - - if (handle->ctx->queue == handle) { - ret = sysdb_queue_schedule(handle); - } - - return ret; -} - -static void sysdb_transaction_end(struct sysdb_handle *handle); - -static int sysdb_handle_destructor(void *ptr) -{ - struct sysdb_handle *handle; - int ret; - - handle = talloc_get_type(ptr, struct sysdb_handle); - - if (handle->ctx->queue != handle) { - DLIST_REMOVE(handle->ctx->queue, handle); - return 0; - } - - /* handle is the currently running operation or - * scheduled to run operation */ - - if (handle->transaction_active) { - /* freeing before the transaction is complete */ - handle->status = ETIMEDOUT; - sysdb_transaction_end(handle); - } - - DLIST_REMOVE(handle->ctx->queue, handle); - - /* make sure we schedule the next in line if any */ - if (handle->ctx->queue) { - ret = sysdb_queue_schedule(handle->ctx->queue); - if (ret != EOK) abort(); - } - - return 0; -} - -static struct sysdb_handle *sysdb_new_req(TALLOC_CTX *memctx, - struct sysdb_ctx *ctx, - sysdb_fn_t fn, void *pvt) -{ - struct sysdb_handle *handle; - - handle = talloc_zero(memctx, struct sysdb_handle); - if (!handle) return NULL; - - handle->ctx = ctx; - handle->fn = fn; - handle->pvt = pvt; - - talloc_set_destructor((TALLOC_CTX *)handle, sysdb_handle_destructor); - - return handle; -} - -static void sysdb_transaction_int(struct sysdb_handle *ihandle, void *pvt) -{ - struct sysdb_handle *handle = talloc_get_type(pvt, struct sysdb_handle); - int ret; - - /* first of all swap this internal handle with the real one on the queue - * otherwise request_done() will later abort */ - DLIST_REMOVE(handle->ctx->queue, ihandle); - DLIST_ADD(handle->ctx->queue, handle); - - if (ihandle->status != EOK) { - handle->status = ihandle->status; - handle->fn(handle, handle->pvt); - return; - } - - ret = ldb_transaction_start(handle->ctx->ldb); - if (ret != LDB_SUCCESS) { - DEBUG(1, ("Failed to start ldb transaction! (%d)\n", ret)); - handle->status = sysdb_error_to_errno(ret); - } - handle->transaction_active = true; - - handle->fn(handle, handle->pvt); -} - -static void sysdb_transaction_end(struct sysdb_handle *handle) -{ - int ret; - - if (handle->status == EOK) { - ret = ldb_transaction_commit(handle->ctx->ldb); - if (ret != LDB_SUCCESS) { - DEBUG(1, ("Failed to commit ldb transaction! (%d)\n", ret)); - } - } else { - DEBUG(4, ("Canceling transaction (%d[%s])\n", - handle->status, strerror(handle->status))); - ret = ldb_transaction_cancel(handle->ctx->ldb); - if (ret != LDB_SUCCESS) { - DEBUG(1, ("Failed to cancel ldb transaction! (%d)\n", ret)); - /* FIXME: abort() ? */ - } - } - handle->transaction_active = false; -} - -int sysdb_transaction(TALLOC_CTX *memctx, struct sysdb_ctx *ctx, - sysdb_fn_t fn, void *pvt) -{ - struct sysdb_handle *handle, *ihandle; - - handle = sysdb_new_req(memctx, ctx, fn, pvt); - if (!handle) return ENOMEM; - - ihandle = sysdb_new_req(handle, ctx, sysdb_transaction_int, handle); - if (!ihandle) { - talloc_free(ihandle); - return ENOMEM; - } - - return sysdb_enqueue(ihandle); -} - -void sysdb_transaction_done(struct sysdb_handle *handle, int status) -{ - int ret; - - if (handle->ctx->queue != handle) abort(); - if (!handle->transaction_active) abort(); - - handle->status = status; - - sysdb_transaction_end(handle); - - DLIST_REMOVE(handle->ctx->queue, handle); - - if (handle->ctx->queue) { - ret = sysdb_queue_schedule(handle->ctx->queue); - if (ret != EOK) abort(); - } - - talloc_free(handle); -} - -int sysdb_operation(TALLOC_CTX *memctx, struct sysdb_ctx *ctx, - sysdb_fn_t fn, void *pvt) -{ - struct sysdb_handle *handle; - - handle = sysdb_new_req(memctx, ctx, fn, pvt); - if (!handle) return ENOMEM; - - return sysdb_enqueue(handle); -} - -void sysdb_operation_done(struct sysdb_handle *handle) -{ - int ret; - - if (handle->ctx->queue != handle) abort(); - - DLIST_REMOVE(handle->ctx->queue, handle); - - if (handle->ctx->queue) { - ret = sysdb_queue_schedule(handle->ctx->queue); - if (ret != EOK) abort(); - } - - talloc_free(handle); -} - diff --git a/server/db/sysdb_search.c b/server/db/sysdb_search.c index 7e0aed8f..5ee9f8c0 100644 --- a/server/db/sysdb_search.c +++ b/server/db/sysdb_search.c @@ -29,6 +29,7 @@ struct sysdb_search_ctx; typedef void (*gen_callback)(struct sysdb_search_ctx *); struct sysdb_search_ctx { + struct tevent_context *ev; struct sysdb_ctx *ctx; struct sysdb_handle *handle; @@ -46,6 +47,8 @@ struct sysdb_search_ctx { struct ldb_result *res; const char **attrs; + + int error; }; static struct sysdb_search_ctx *init_src_ctx(TALLOC_CTX *mem_ctx, @@ -61,6 +64,7 @@ static struct sysdb_search_ctx *init_src_ctx(TALLOC_CTX *mem_ctx, return NULL; } sctx->ctx = ctx; + sctx->ev = ctx->ev; sctx->callback = fn; sctx->ptr = ptr; sctx->res = talloc_zero(sctx, struct ldb_result); @@ -162,15 +166,19 @@ static int get_gen_callback(struct ldb_request *req, /* users */ -static void user_search(struct sysdb_handle *handle, void *ptr) +static void user_search(struct tevent_req *treq) { struct sysdb_search_ctx *sctx; struct ldb_request *req; struct ldb_dn *base_dn; int ret; - sctx = talloc_get_type(ptr, struct sysdb_search_ctx); - sctx->handle = handle; + sctx = tevent_req_callback_data(treq, struct sysdb_search_ctx); + + ret = sysdb_operation_recv(treq, sctx, &sctx->handle); + if (ret) { + return request_error(sctx, ret); + } base_dn = ldb_dn_new_fmt(sctx, sctx->ctx->ldb, SYSDB_TMPL_USER_BASE, sctx->domain->name); @@ -201,6 +209,7 @@ int sysdb_getpwnam(TALLOC_CTX *mem_ctx, { static const char *attrs[] = SYSDB_PW_ATTRS; struct sysdb_search_ctx *sctx; + struct tevent_req *req; if (!domain) { return EINVAL; @@ -219,7 +228,15 @@ int sysdb_getpwnam(TALLOC_CTX *mem_ctx, sctx->attrs = attrs; - return sysdb_operation(mem_ctx, ctx, user_search, sctx); + req = sysdb_operation_send(mem_ctx, ctx->ev, ctx); + if (!req) { + talloc_free(sctx); + return ENOMEM; + } + + tevent_req_set_callback(req, user_search, sctx); + + return EOK; } int sysdb_getpwuid(TALLOC_CTX *mem_ctx, @@ -231,6 +248,7 @@ int sysdb_getpwuid(TALLOC_CTX *mem_ctx, static const char *attrs[] = SYSDB_PW_ATTRS; struct sysdb_search_ctx *sctx; unsigned long int filter_uid = uid; + struct tevent_req *req; if (!domain) { return EINVAL; @@ -249,7 +267,15 @@ int sysdb_getpwuid(TALLOC_CTX *mem_ctx, sctx->attrs = attrs; - return sysdb_operation(mem_ctx, ctx, user_search, sctx); + req = sysdb_operation_send(mem_ctx, ctx->ev, ctx); + if (!req) { + talloc_free(sctx); + return ENOMEM; + } + + tevent_req_set_callback(req, user_search, sctx); + + return EOK; } int sysdb_enumpwent(TALLOC_CTX *mem_ctx, @@ -260,6 +286,7 @@ int sysdb_enumpwent(TALLOC_CTX *mem_ctx, { static const char *attrs[] = SYSDB_PW_ATTRS; struct sysdb_search_ctx *sctx; + struct tevent_req *req; if (!domain) { return EINVAL; @@ -277,7 +304,15 @@ int sysdb_enumpwent(TALLOC_CTX *mem_ctx, sctx->attrs = attrs; - return sysdb_operation(mem_ctx, ctx, user_search, sctx); + req = sysdb_operation_send(mem_ctx, ctx->ev, ctx); + if (!req) { + talloc_free(sctx); + return ENOMEM; + } + + tevent_req_set_callback(req, user_search, sctx); + + return EOK; } /* groups */ @@ -478,7 +513,7 @@ static int get_grp_callback(struct ldb_request *req, return LDB_SUCCESS; } -static void grp_search(struct sysdb_handle *handle, void *ptr) +static void grp_search(struct tevent_req *treq) { struct sysdb_search_ctx *sctx; static const char *attrs[] = SYSDB_GRSRC_ATTRS; @@ -486,8 +521,12 @@ static void grp_search(struct sysdb_handle *handle, void *ptr) struct ldb_dn *base_dn; int ret; - sctx = talloc_get_type(ptr, struct sysdb_search_ctx); - sctx->handle = handle; + sctx = tevent_req_callback_data(treq, struct sysdb_search_ctx); + + ret = sysdb_operation_recv(treq, sctx, &sctx->handle); + if (ret) { + return request_error(sctx, ret); + } if (sctx->domain->mpg) { base_dn = ldb_dn_new_fmt(sctx, sctx->ctx->ldb, @@ -522,6 +561,7 @@ int sysdb_getgrnam(TALLOC_CTX *mem_ctx, sysdb_callback_t fn, void *ptr) { struct sysdb_search_ctx *sctx; + struct tevent_req *req; if (!domain) { return EINVAL; @@ -542,7 +582,15 @@ int sysdb_getgrnam(TALLOC_CTX *mem_ctx, return ENOMEM; } - return sysdb_operation(mem_ctx, ctx, grp_search, sctx); + req = sysdb_operation_send(mem_ctx, ctx->ev, ctx); + if (!req) { + talloc_free(sctx); + return ENOMEM; + } + + tevent_req_set_callback(req, grp_search, sctx); + + return EOK; } int sysdb_getgrgid(TALLOC_CTX *mem_ctx, @@ -552,6 +600,7 @@ int sysdb_getgrgid(TALLOC_CTX *mem_ctx, sysdb_callback_t fn, void *ptr) { struct sysdb_search_ctx *sctx; + struct tevent_req *req; if (!domain) { return EINVAL; @@ -576,7 +625,15 @@ int sysdb_getgrgid(TALLOC_CTX *mem_ctx, return ENOMEM; } - return sysdb_operation(mem_ctx, ctx, grp_search, sctx); + req = sysdb_operation_send(mem_ctx, ctx->ev, ctx); + if (!req) { + talloc_free(sctx); + return ENOMEM; + } + + tevent_req_set_callback(req, grp_search, sctx); + + return EOK; } int sysdb_enumgrent(TALLOC_CTX *mem_ctx, @@ -585,6 +642,7 @@ int sysdb_enumgrent(TALLOC_CTX *mem_ctx, sysdb_callback_t fn, void *ptr) { struct sysdb_search_ctx *sctx; + struct tevent_req *req; if (!domain) { return EINVAL; @@ -601,7 +659,15 @@ int sysdb_enumgrent(TALLOC_CTX *mem_ctx, sctx->expression = SYSDB_GRENT_FILTER; } - return sysdb_operation(mem_ctx, ctx, grp_search, sctx); + req = sysdb_operation_send(mem_ctx, ctx->ev, ctx); + if (!req) { + talloc_free(sctx); + return ENOMEM; + } + + tevent_req_set_callback(req, grp_search, sctx); + + return EOK; } static void initgr_mem_legacy(struct sysdb_search_ctx *sctx) @@ -720,7 +786,7 @@ static void initgr_mem_search(struct sysdb_search_ctx *sctx) } } -static void initgr_search(struct sysdb_handle *handle, void *ptr) +static void initgr_search(struct tevent_req *treq) { struct sysdb_search_ctx *sctx; static const char *attrs[] = SYSDB_PW_ATTRS; @@ -728,8 +794,12 @@ static void initgr_search(struct sysdb_handle *handle, void *ptr) struct ldb_dn *base_dn; int ret; - sctx = talloc_get_type(ptr, struct sysdb_search_ctx); - sctx->handle = handle; + sctx = tevent_req_callback_data(treq, struct sysdb_search_ctx); + + ret = sysdb_operation_recv(treq, sctx, &sctx->handle); + if (ret) { + return request_error(sctx, ret); + } if (sctx->domain->legacy) { sctx->gen_aux_fn = initgr_mem_legacy; @@ -765,6 +835,7 @@ int sysdb_initgroups(TALLOC_CTX *mem_ctx, sysdb_callback_t fn, void *ptr) { struct sysdb_search_ctx *sctx; + struct tevent_req *req; if (!domain) { return EINVAL; @@ -781,7 +852,15 @@ int sysdb_initgroups(TALLOC_CTX *mem_ctx, return ENOMEM; } - return sysdb_operation(mem_ctx, ctx, initgr_search, sctx); + req = sysdb_operation_send(mem_ctx, ctx->ev, ctx); + if (!req) { + talloc_free(sctx); + return ENOMEM; + } + + tevent_req_set_callback(req, initgr_search, sctx); + + return EOK; } int sysdb_get_user_attr(TALLOC_CTX *mem_ctx, @@ -792,6 +871,7 @@ int sysdb_get_user_attr(TALLOC_CTX *mem_ctx, sysdb_callback_t fn, void *ptr) { struct sysdb_search_ctx *sctx; + struct tevent_req *req; if (!domain) { return EINVAL; @@ -810,5 +890,13 @@ int sysdb_get_user_attr(TALLOC_CTX *mem_ctx, sctx->attrs = attributes; - return sysdb_operation(mem_ctx, ctx, user_search, sctx); + req = sysdb_operation_send(mem_ctx, ctx->ev, ctx); + if (!req) { + talloc_free(sctx); + return ENOMEM; + } + + tevent_req_set_callback(req, user_search, sctx); + + return EOK; } |