diff options
Diffstat (limited to 'server/db/sysdb.c')
-rw-r--r-- | server/db/sysdb.c | 1125 |
1 files changed, 1125 insertions, 0 deletions
diff --git a/server/db/sysdb.c b/server/db/sysdb.c new file mode 100644 index 00000000..aedf7ef2 --- /dev/null +++ b/server/db/sysdb.c @@ -0,0 +1,1125 @@ +/* + SSSD + + System Database + + Copyright (C) Simo Sorce <ssorce@redhat.com> 2008 + + 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 "util/util.h" +#include "db/sysdb.h" +#include "confdb/confdb.h" +#include <time.h> + +struct sysdb_search_ctx { + struct sysdb_ctx *dbctx; + const char *base_dn; + sysdb_callback_t callback; + void *ptr; + struct ldb_result *res; +}; + +static int sysdb_error_to_errno(int lerr) +{ + /* fake it up for now, requires a mapping table */ + return EIO; +} + +static void request_error(struct sysdb_search_ctx *sctx, int ldb_error) +{ + sctx->callback(sctx->ptr, sysdb_error_to_errno(ldb_error), sctx->res); +} + +static void request_done(struct sysdb_search_ctx *sctx) +{ + sctx->callback(sctx->ptr, EOK, sctx->res); +} + +static int get_gen_callback(struct ldb_request *req, + struct ldb_reply *ares) +{ + struct sysdb_search_ctx *sctx; + struct ldb_result *res; + int n; + + sctx = talloc_get_type(req->context, struct sysdb_search_ctx); + res = sctx->res; + + if (!ares) { + request_error(sctx, LDB_ERR_OPERATIONS_ERROR); + return LDB_ERR_OPERATIONS_ERROR; + } + if (ares->error != LDB_SUCCESS) { + request_error(sctx, ares->error); + return ares->error; + } + + switch (ares->type) { + case LDB_REPLY_ENTRY: + res->msgs = talloc_realloc(res, res->msgs, + struct ldb_message *, + res->count + 2); + if (!res->msgs) { + request_error(sctx, LDB_ERR_OPERATIONS_ERROR); + return LDB_ERR_OPERATIONS_ERROR; + } + + res->msgs[res->count + 1] = NULL; + + res->msgs[res->count] = talloc_steal(res->msgs, ares->message); + res->count++; + break; + + case LDB_REPLY_REFERRAL: + if (res->refs) { + for (n = 0; res->refs[n]; n++) /*noop*/ ; + } else { + n = 0; + } + + res->refs = talloc_realloc(res, res->refs, char *, n + 2); + if (! res->refs) { + request_error(sctx, LDB_ERR_OPERATIONS_ERROR); + return LDB_ERR_OPERATIONS_ERROR; + } + + res->refs[n] = talloc_steal(res->refs, ares->referral); + res->refs[n + 1] = NULL; + break; + + case LDB_REPLY_DONE: + res->controls = talloc_steal(res, ares->controls); + + /* this is the last message, and means the request is done */ + request_done(sctx); + return LDB_SUCCESS; + } + + talloc_free(ares); + return LDB_SUCCESS; +} + +static struct sysdb_search_ctx *init_src_ctx(TALLOC_CTX *mem_ctx, + const char *base_dn, + struct sysdb_ctx *ctx, + sysdb_callback_t fn, + void *ptr) +{ + struct sysdb_search_ctx *sctx; + + sctx = talloc(mem_ctx, struct sysdb_search_ctx); + if (!sctx) { + return NULL; + } + sctx->dbctx = ctx; + sctx->base_dn = base_dn; + sctx->callback = fn; + sctx->ptr = ptr; + sctx->res = talloc_zero(sctx, struct ldb_result); + if (!sctx->res) { + talloc_free(sctx); + return NULL; + } + + return sctx; +} + +/* users */ + +static int pwd_search(struct sysdb_search_ctx *sctx, + struct sysdb_ctx *ctx, + const char *expression) +{ + static const char *attrs[] = SYSDB_PW_ATTRS; + struct ldb_request *req; + int ret; + + ret = ldb_build_search_req(&req, ctx->ldb, sctx, + ldb_dn_new(sctx, ctx->ldb, sctx->base_dn), + LDB_SCOPE_SUBTREE, + expression, attrs, NULL, + sctx, get_gen_callback, + NULL); + if (ret != LDB_SUCCESS) { + return sysdb_error_to_errno(ret); + } + + ret = ldb_request(ctx->ldb, req); + if (ret != LDB_SUCCESS) { + return sysdb_error_to_errno(ret); + } + + return EOK; +} + +int sysdb_getpwnam(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct sysdb_ctx *ctx, + const char *domain, + const char *name, + sysdb_callback_t fn, void *ptr) +{ + struct sysdb_search_ctx *sctx; + const char *base_dn; + char *expression; + + if (domain) { + base_dn = talloc_asprintf(mem_ctx, SYSDB_TMPL_USER_BASE, domain); + } else { + base_dn = SYSDB_BASE; + } + if (!base_dn) { + return ENOMEM; + } + + sctx = init_src_ctx(mem_ctx, base_dn, ctx, fn, ptr); + if (!sctx) { + return ENOMEM; + } + + expression = talloc_asprintf(sctx, SYSDB_PWNAM_FILTER, name); + if (!expression) { + talloc_free(sctx); + return ENOMEM; + } + + return pwd_search(sctx, ctx, expression); +} + +int sysdb_getpwuid(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct sysdb_ctx *ctx, + const char *domain, + uint64_t uid, + sysdb_callback_t fn, void *ptr) +{ + struct sysdb_search_ctx *sctx; + unsigned long int filter_uid = uid; + const char *base_dn; + char *expression; + + if (domain) { + base_dn = talloc_asprintf(mem_ctx, SYSDB_TMPL_USER_BASE, domain); + } else { + base_dn = SYSDB_BASE; + } + if (!base_dn) { + return ENOMEM; + } + + sctx = init_src_ctx(mem_ctx, base_dn, ctx, fn, ptr); + if (!sctx) { + return ENOMEM; + } + + expression = talloc_asprintf(sctx, SYSDB_PWUID_FILTER, filter_uid); + if (!expression) { + talloc_free(sctx); + return ENOMEM; + } + + return pwd_search(sctx, ctx, expression); +} + +int sysdb_enumpwent(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct sysdb_ctx *ctx, + sysdb_callback_t fn, void *ptr) +{ + struct sysdb_search_ctx *sctx; + + sctx = init_src_ctx(mem_ctx, SYSDB_BASE, ctx, fn, ptr); + if (!sctx) { + return ENOMEM; + } + + return pwd_search(sctx, ctx, SYSDB_PWENT_FILTER); +} + +/* groups */ + +struct get_mem_ctx { + struct sysdb_search_ctx *ret_sctx; + struct ldb_message **grps; + int num_grps; +}; + +static void get_members(void *ptr, int status, struct ldb_result *res) +{ + struct sysdb_ctx *ctx; + struct sysdb_search_ctx *sctx; + struct get_mem_ctx *gmctx; + struct sysdb_search_ctx *mem_sctx; + struct ldb_request *req; + struct ldb_message *msg; + struct ldb_result *ret_res; + static const char *attrs[] = SYSDB_GRPW_ATTRS; + const char *expression; + int ret, i; + + sctx = talloc_get_type(ptr, struct sysdb_search_ctx); + gmctx = talloc_get_type(sctx->ptr, struct get_mem_ctx); + ctx = sctx->dbctx; + + if (status != LDB_SUCCESS) { + return request_error(gmctx->ret_sctx, status); + } + + ret_res = gmctx->ret_sctx->res; + + /* append previous search results to final (if any) */ + if (res && res->count != 0) { + ret_res->msgs = talloc_realloc(ret_res, ret_res->msgs, + struct ldb_message *, + ret_res->count + res->count + 1); + for(i = 0; i < res->count; i++) { + ret_res->msgs[ret_res->count] = talloc_steal(ret_res, res->msgs[i]); + ret_res->count++; + } + ret_res->msgs[ret_res->count] = NULL; + } + + if (gmctx->grps[0] == NULL) { + return request_done(gmctx->ret_sctx); + } + + mem_sctx = init_src_ctx(gmctx, SYSDB_BASE, ctx, get_members, sctx); + if (!mem_sctx) { + return request_error(gmctx->ret_sctx, LDB_ERR_OPERATIONS_ERROR); + } + + /* fetch next group to search for members */ + gmctx->num_grps--; + msg = gmctx->grps[gmctx->num_grps]; + gmctx->grps[gmctx->num_grps] = NULL; + + /* queue the group entry on the final result structure */ + ret_res->msgs = talloc_realloc(ret_res, ret_res->msgs, + struct ldb_message *, + ret_res->count + 2); + if (!ret_res->msgs) { + return request_error(gmctx->ret_sctx, LDB_ERR_OPERATIONS_ERROR); + } + ret_res->msgs[ret_res->count + 1] = NULL; + ret_res->msgs[ret_res->count] = talloc_steal(ret_res->msgs, msg); + ret_res->count++; + + /* search for this group members */ + expression = talloc_asprintf(mem_sctx, SYSDB_GRNA2_FILTER, + ldb_dn_get_linearized(msg->dn)); + if (!expression) { + return request_error(gmctx->ret_sctx, LDB_ERR_OPERATIONS_ERROR); + } + + ret = ldb_build_search_req(&req, ctx->ldb, mem_sctx, + ldb_dn_new(mem_sctx, ctx->ldb, sctx->base_dn), + LDB_SCOPE_SUBTREE, + expression, attrs, NULL, + mem_sctx, get_gen_callback, + NULL); + if (ret != LDB_SUCCESS) { + return request_error(gmctx->ret_sctx, ret); + } + + ret = ldb_request(ctx->ldb, req); + if (ret != LDB_SUCCESS) { + return request_error(gmctx->ret_sctx, ret); + } +} + +static int get_grp_callback(struct ldb_request *req, + struct ldb_reply *ares) +{ + struct sysdb_search_ctx *sctx; + struct sysdb_ctx *ctx; + struct ldb_result *res; + int n; + + sctx = talloc_get_type(req->context, struct sysdb_search_ctx); + ctx = sctx->dbctx; + res = sctx->res; + + if (!ares) { + request_error(sctx, LDB_ERR_OPERATIONS_ERROR); + return LDB_ERR_OPERATIONS_ERROR; + } + if (ares->error != LDB_SUCCESS) { + request_error(sctx, ares->error); + return ares->error; + } + + switch (ares->type) { + case LDB_REPLY_ENTRY: + res->msgs = talloc_realloc(res, res->msgs, + struct ldb_message *, + res->count + 2); + if (!res->msgs) { + request_error(sctx, LDB_ERR_OPERATIONS_ERROR); + return LDB_ERR_OPERATIONS_ERROR; + } + + res->msgs[res->count + 1] = NULL; + + res->msgs[res->count] = talloc_steal(res->msgs, ares->message); + res->count++; + break; + + case LDB_REPLY_REFERRAL: + if (res->refs) { + for (n = 0; res->refs[n]; n++) /*noop*/ ; + } else { + n = 0; + } + + res->refs = talloc_realloc(res, res->refs, char *, n + 2); + if (! res->refs) { + request_error(sctx, LDB_ERR_OPERATIONS_ERROR); + return LDB_ERR_OPERATIONS_ERROR; + } + + res->refs[n] = talloc_steal(res->refs, ares->referral); + res->refs[n + 1] = NULL; + break; + + case LDB_REPLY_DONE: + res->controls = talloc_steal(res, ares->controls); + + /* no results, return */ + if (res->count == 0) { + request_done(sctx); + return LDB_SUCCESS; + } + if (res->count > 0) { + struct get_mem_ctx *gmctx; + + gmctx = talloc_zero(req, struct get_mem_ctx); + if (!gmctx) { + request_error(sctx, LDB_ERR_OPERATIONS_ERROR); + return LDB_ERR_OPERATIONS_ERROR; + } + gmctx->ret_sctx = sctx; + gmctx->grps = talloc_steal(gmctx, res->msgs); + gmctx->num_grps = res->count; + res->msgs = NULL; + res->count = 0; + + /* re-use sctx to create a fake handler for the first call to + * get_members() */ + sctx = init_src_ctx(gmctx, SYSDB_BASE, ctx, get_members, gmctx); + + get_members(sctx, LDB_SUCCESS, NULL); + return LDB_SUCCESS; + } + + /* anything else is an error */ + request_error(sctx, LDB_ERR_OPERATIONS_ERROR); + return LDB_ERR_OPERATIONS_ERROR; + } + + talloc_free(ares); + return LDB_SUCCESS; +} + +static int grp_search(struct sysdb_search_ctx *sctx, + struct sysdb_ctx *ctx, + const char *expression) +{ + static const char *attrs[] = SYSDB_GRNAM_ATTRS; + struct ldb_request *req; + int ret; + + ret = ldb_build_search_req(&req, ctx->ldb, sctx, + ldb_dn_new(sctx, ctx->ldb, sctx->base_dn), + LDB_SCOPE_SUBTREE, + expression, attrs, NULL, + sctx, get_grp_callback, + NULL); + if (ret != LDB_SUCCESS) { + return sysdb_error_to_errno(ret); + } + + ret = ldb_request(ctx->ldb, req); + if (ret != LDB_SUCCESS) { + return sysdb_error_to_errno(ret); + } + + return EOK; +} + +int sysdb_getgrnam(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct sysdb_ctx *ctx, + const char *domain, + const char *name, + sysdb_callback_t fn, void *ptr) +{ + struct sysdb_search_ctx *sctx; + const char *base_dn; + char *expression; + + if (domain) { + base_dn = talloc_asprintf(mem_ctx, SYSDB_TMPL_GROUP_BASE, domain); + } else { + base_dn = SYSDB_BASE; + } + if (!base_dn) { + return ENOMEM; + } + + sctx = init_src_ctx(mem_ctx, base_dn, ctx, fn, ptr); + if (!sctx) { + return ENOMEM; + } + + expression = talloc_asprintf(sctx, SYSDB_GRNAM_FILTER, name); + if (!expression) { + talloc_free(sctx); + return ENOMEM; + } + + return grp_search(sctx, ctx, expression); +} + +int sysdb_getgrgid(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct sysdb_ctx *ctx, + const char *domain, + uint64_t gid, + sysdb_callback_t fn, void *ptr) +{ + struct sysdb_search_ctx *sctx; + unsigned long int filter_gid = gid; + const char *base_dn; + char *expression; + + if (domain) { + base_dn = talloc_asprintf(mem_ctx, SYSDB_TMPL_GROUP_BASE, domain); + } else { + base_dn = SYSDB_BASE; + } + if (!base_dn) { + return ENOMEM; + } + + sctx = init_src_ctx(mem_ctx, base_dn, ctx, fn, ptr); + if (!sctx) { + return ENOMEM; + } + + expression = talloc_asprintf(sctx, SYSDB_GRGID_FILTER, filter_gid); + if (!expression) { + talloc_free(sctx); + return ENOMEM; + } + + return grp_search(sctx, ctx, expression); +} + +int sysdb_enumgrent(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct sysdb_ctx *ctx, + sysdb_callback_t fn, void *ptr) +{ + struct sysdb_search_ctx *sctx; + + sctx = init_src_ctx(mem_ctx, SYSDB_BASE, ctx, fn, ptr); + if (!sctx) { + return ENOMEM; + } + + return grp_search(sctx, ctx, SYSDB_GRENT_FILTER); +} + +static void sysdb_initgr_search(void *ptr, int status, + struct ldb_result *res) +{ + struct sysdb_ctx *ctx; + struct sysdb_search_ctx *sctx; + char *expression; + struct ldb_request *req; + struct ldb_control **ctrl; + struct ldb_asq_control *control; + static const char *attrs[] = SYSDB_INITGR_ATTRS; + int ret; + + sctx = talloc_get_type(ptr, struct sysdb_search_ctx); + ctx = sctx->dbctx; + + if (res->count == 0) { + return request_done(sctx); + } + if (res->count > 1) { + return request_error(sctx, LDB_ERR_OPERATIONS_ERROR); + } + + expression = talloc_asprintf(sctx, SYSDB_INITGR_FILTER); + if (!expression) { + return request_error(sctx, LDB_ERR_OPERATIONS_ERROR); + } + + ctrl = talloc_array(sctx, struct ldb_control *, 2); + if (!ctrl) { + return request_error(sctx, LDB_ERR_OPERATIONS_ERROR); + } + ctrl[1] = NULL; + ctrl[0] = talloc(ctrl, struct ldb_control); + if (!ctrl[0]) { + return request_error(sctx, LDB_ERR_OPERATIONS_ERROR); + } + ctrl[0]->oid = LDB_CONTROL_ASQ_OID; + ctrl[0]->critical = 1; + control = talloc(ctrl[0], struct ldb_asq_control); + if (!control) { + return request_error(sctx, LDB_ERR_OPERATIONS_ERROR); + } + control->request = 1; + control->source_attribute = talloc_strdup(control, SYSDB_INITGR_ATTR); + if (!control->source_attribute) { + return request_error(sctx, LDB_ERR_OPERATIONS_ERROR); + } + control->src_attr_len = strlen(control->source_attribute); + ctrl[0]->data = control; + + ret = ldb_build_search_req(&req, ctx->ldb, sctx, + res->msgs[0]->dn, + LDB_SCOPE_BASE, + expression, attrs, ctrl, + sctx, get_gen_callback, + NULL); + if (ret != LDB_SUCCESS) { + return request_error(sctx, ret); + } + + ret = ldb_request(ctx->ldb, req); + if (ret != LDB_SUCCESS) { + return request_error(sctx, ret); + } +} + +int sysdb_initgroups(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct sysdb_ctx *ctx, + const char *domain, + const char *name, + sysdb_callback_t fn, void *ptr) +{ + static const char *attrs[] = SYSDB_PW_ATTRS; + struct sysdb_search_ctx *ret_sctx; + struct sysdb_search_ctx *sctx; + const char *base_dn; + char *expression; + struct ldb_request *req; + int ret; + + if (domain) { + base_dn = talloc_asprintf(mem_ctx, SYSDB_TMPL_USER_BASE, domain); + } else { + base_dn = SYSDB_BASE; + } + if (!base_dn) { + return ENOMEM; + } + + ret_sctx = init_src_ctx(mem_ctx, SYSDB_BASE, ctx, fn, ptr); + if (!ret_sctx) { + return ENOMEM; + } + sctx = init_src_ctx(ret_sctx, base_dn, ctx, sysdb_initgr_search, ret_sctx); + if (!sctx) { + talloc_free(sctx); + return ENOMEM; + } + + expression = talloc_asprintf(sctx, SYSDB_PWNAM_FILTER, name); + if (!expression) { + talloc_free(sctx); + return ENOMEM; + } + + ret = ldb_build_search_req(&req, ctx->ldb, sctx, + ldb_dn_new(sctx, ctx->ldb, sctx->base_dn), + LDB_SCOPE_SUBTREE, + expression, attrs, NULL, + sctx, get_gen_callback, + NULL); + if (ret != LDB_SUCCESS) { + return sysdb_error_to_errno(ret); + } + + ret = ldb_request(ctx->ldb, req); + if (ret != LDB_SUCCESS) { + return sysdb_error_to_errno(ret); + } + + return LDB_SUCCESS; +} + +static int sysdb_read_var(TALLOC_CTX *tmp_ctx, + struct confdb_ctx *cdb, + struct sysdb_ctx *ctx, + const char *name, + const char *def_value, + const char **target) +{ + int ret; + char *t; + char **values; + + ret = confdb_get_param(cdb, tmp_ctx, + SYSDB_CONF_SECTION, + name, &values); + if (ret != EOK) + return ret; + + if (values[0]) + t = talloc_steal(ctx, values[0]); + else + t = talloc_strdup(ctx, def_value); + + *target = t; + return EOK; +} + +static int sysdb_read_conf(TALLOC_CTX *mem_ctx, + struct confdb_ctx *cdb, + struct sysdb_ctx **dbctx) +{ + struct sysdb_ctx *ctx; + TALLOC_CTX *tmp_ctx; + char *default_ldb_path; + int ret; + + tmp_ctx = talloc_new(mem_ctx); + if (!tmp_ctx) + return ENOMEM; + + ctx = talloc(mem_ctx, struct sysdb_ctx); + if (!ctx) { + ret = ENOMEM; + goto done; + } + + default_ldb_path = talloc_asprintf(tmp_ctx, "%s/%s", DB_PATH, SYSDB_FILE); + if (default_ldb_path == NULL) { + ret = ENOMEM; + goto done; + } + + sysdb_read_var(tmp_ctx, cdb, ctx, "ldbFile", + default_ldb_path, &ctx->ldb_file); + DEBUG(3, ("NSS LDB Cache Path: %s\n", ctx->ldb_file)); + + *dbctx = ctx; + ret = EOK; + +done: + talloc_free(tmp_ctx); + return ret; +} + +int sysdb_store_account_posix(TALLOC_CTX *memctx, + struct sysdb_ctx *sysdb, + const char *domain, + char *name, char *pwd, + uint64_t uid, uint64_t gid, + char *gecos, char *homedir, char *shell) +{ + TALLOC_CTX *tmp_ctx; + const char *attrs[] = { SYSDB_PW_NAME, NULL }; + struct ldb_dn *account_dn; + struct ldb_message *msg; + struct ldb_request *req; + struct ldb_result *res; + int lret, ret; + int flags; + + tmp_ctx = talloc_new(memctx); + if (!tmp_ctx) { + return ENOMEM; + } + + account_dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, + "uid=%s,"SYSDB_TMPL_USER_BASE, + name, domain); + if (!account_dn) { + talloc_free(tmp_ctx); + return ENOMEM; + } + + lret = ldb_transaction_start(sysdb->ldb); + if (lret != LDB_SUCCESS) { + DEBUG(1, ("Failed ldb transaction start !? (%d)\n", lret)); + ret = EIO; + goto done; + } + + lret = ldb_search(sysdb->ldb, tmp_ctx, &res, account_dn, + LDB_SCOPE_BASE, attrs, SYSDB_PWENT_FILTER); + if (lret != LDB_SUCCESS) { + DEBUG(1, ("Failed to make search request: %s(%d)[%s]\n", + ldb_strerror(lret), lret, ldb_errstring(sysdb->ldb))); + ret = EIO; + goto done; + } + + req = NULL; + + msg = ldb_msg_new(tmp_ctx); + if (!msg) { + ret = ENOMEM; + goto done; + } + msg->dn = account_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)); + ret = EIO; + goto done; + } + + talloc_free(res); + res = NULL; + + if (flags == LDB_FLAG_MOD_ADD) { + /* TODO: retrieve user objectclass list from configuration */ + lret = ldb_msg_add_empty(msg, "objectClass", flags, NULL); + if (lret == LDB_SUCCESS) { + lret = ldb_msg_add_string(msg, "objectClass", "user"); + } + if (lret != LDB_SUCCESS) { + ret = errno; + goto done; + } + + /* TODO: retrieve user name attribute from configuration */ + lret = ldb_msg_add_empty(msg, SYSDB_PW_NAME, flags, NULL); + if (lret == LDB_SUCCESS) { + lret = ldb_msg_add_string(msg, SYSDB_PW_NAME, name); + } + if (lret != LDB_SUCCESS) { + ret = errno; + goto done; + } + } + + /* TODO: retrieve attribute name mappings from configuration */ + + /* pwd */ + if (pwd && *pwd) { + lret = ldb_msg_add_empty(msg, SYSDB_PW_PWD, flags, NULL); + if (lret == LDB_SUCCESS) { + lret = ldb_msg_add_string(msg, SYSDB_PW_PWD, pwd); + } + } else { + lret = ldb_msg_add_empty(msg, SYSDB_PW_PWD, + LDB_FLAG_MOD_DELETE, NULL); + } + if (lret != LDB_SUCCESS) { + ret = errno; + goto done; + } + + /* uid */ + if (uid) { + lret = ldb_msg_add_empty(msg, SYSDB_PW_UIDNUM, flags, NULL); + if (lret == LDB_SUCCESS) { + lret = ldb_msg_add_fmt(msg, SYSDB_PW_UIDNUM, + "%lu", (unsigned long)uid); + } + if (lret != LDB_SUCCESS) { + ret = errno; + goto done; + } + } else { + DEBUG(0, ("Cached users can't have UID == 0\n")); + ret = EINVAL; + goto done; + } + + /* gid */ + if (gid) { + lret = ldb_msg_add_empty(msg, SYSDB_PW_GIDNUM, flags, NULL); + if (lret == LDB_SUCCESS) { + lret = ldb_msg_add_fmt(msg, SYSDB_PW_GIDNUM, + "%lu", (unsigned long)gid); + } + if (lret != LDB_SUCCESS) { + ret = errno; + goto done; + } + } else { + DEBUG(0, ("Cached users can't have GID == 0\n")); + ret = EINVAL; + goto done; + } + + /* gecos */ + if (gecos && *gecos) { + lret = ldb_msg_add_empty(msg, SYSDB_PW_FULLNAME, flags, NULL); + if (lret == LDB_SUCCESS) { + lret = ldb_msg_add_string(msg, SYSDB_PW_FULLNAME, gecos); + } + } else { + lret = ldb_msg_add_empty(msg, SYSDB_PW_FULLNAME, + LDB_FLAG_MOD_DELETE, NULL); + } + if (lret != LDB_SUCCESS) { + ret = errno; + goto done; + } + + /* homedir */ + if (homedir && *homedir) { + lret = ldb_msg_add_empty(msg, SYSDB_PW_HOMEDIR, flags, NULL); + if (lret == LDB_SUCCESS) { + lret = ldb_msg_add_string(msg, SYSDB_PW_HOMEDIR, homedir); + } + } else { + lret = ldb_msg_add_empty(msg, SYSDB_PW_HOMEDIR, + LDB_FLAG_MOD_DELETE, NULL); + } + if (lret != LDB_SUCCESS) { + ret = errno; + goto done; + } + + /* shell */ + if (shell && *shell) { + lret = ldb_msg_add_empty(msg, SYSDB_PW_SHELL, flags, NULL); + if (lret == LDB_SUCCESS) { + lret = ldb_msg_add_string(msg, SYSDB_PW_SHELL, shell); + } + } else { + lret = ldb_msg_add_empty(msg, SYSDB_PW_SHELL, + LDB_FLAG_MOD_DELETE, NULL); + } + if (lret != LDB_SUCCESS) { + ret = errno; + goto done; + } + + /* modification time */ + lret = ldb_msg_add_empty(msg, SYSDB_LAST_UPDATE, flags, NULL); + if (lret == LDB_SUCCESS) { + lret = ldb_msg_add_fmt(msg, SYSDB_LAST_UPDATE, + "%ld", (long int)time(NULL)); + } + if (lret != LDB_SUCCESS) { + ret = errno; + goto done; + } + + if (flags == LDB_FLAG_MOD_ADD) { + lret = ldb_build_add_req(&req, sysdb->ldb, tmp_ctx, msg, NULL, + NULL, ldb_op_default_callback, NULL); + } else { + lret = ldb_build_mod_req(&req, sysdb->ldb, tmp_ctx, msg, NULL, + NULL, ldb_op_default_callback, NULL); + } + if (lret == LDB_SUCCESS) { + lret = ldb_request(sysdb->ldb, req); + if (lret == LDB_SUCCESS) { + lret = ldb_wait(req->handle, LDB_WAIT_ALL); + } + } + if (lret != LDB_SUCCESS) { + DEBUG(1, ("Failed to make modify request: %s(%d)[%s]\n", + ldb_strerror(lret), lret, ldb_errstring(sysdb->ldb))); + ret = EIO; + goto done; + } + + lret = ldb_transaction_commit(sysdb->ldb); + if (lret != LDB_SUCCESS) { + DEBUG(1, ("Failed ldb transaction start !? (%d)\n", lret)); + ret = EIO; + goto done; + } + + ret = EOK; + +done: + if (ret != EOK) { + lret = ldb_transaction_cancel(sysdb->ldb); + if (lret != LDB_SUCCESS) { + DEBUG(1, ("Failed to cancel ldb transaction (%d)\n", lret)); + } + } + + talloc_free(tmp_ctx); + return ret; +} + +int sysdb_remove_account_posix(TALLOC_CTX *memctx, + struct sysdb_ctx *sysdb, + const char *domain, const char *name) +{ + TALLOC_CTX *tmp_ctx; + struct ldb_dn *account_dn; + int ret; + + tmp_ctx = talloc_new(memctx); + if (!tmp_ctx) { + return ENOMEM; + } + + account_dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, + "uid=%s,"SYSDB_TMPL_USER_BASE, + name, domain); + if (!account_dn) { + talloc_free(tmp_ctx); + return ENOMEM; + } + + ret = ldb_delete(sysdb->ldb, account_dn); + + if (ret != LDB_SUCCESS) { + DEBUG(2, ("LDB Error: %s(%d)\nError Message: [%s]\n", + ldb_strerror(ret), ret, ldb_errstring(sysdb->ldb))); + ret = EIO; + } + + talloc_free(tmp_ctx); + return ret; +} + +int sysdb_remove_account_posix_by_uid(TALLOC_CTX *memctx, + struct sysdb_ctx *sysdb, + const char *domain, uid_t uid) +{ + TALLOC_CTX *tmp_ctx; + const char *attrs[] = { SYSDB_PW_NAME, SYSDB_PW_UIDNUM, NULL }; + struct ldb_dn *base_dn; + struct ldb_dn *account_dn; + struct ldb_result *res; + int lret, ret; + + tmp_ctx = talloc_new(memctx); + if (!tmp_ctx) { + return ENOMEM; + } + + base_dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, + SYSDB_TMPL_USER_BASE, domain); + if (!base_dn) { + talloc_free(tmp_ctx); + return ENOMEM; + } + + lret = ldb_transaction_start(sysdb->ldb); + if (lret != LDB_SUCCESS) { + DEBUG(1, ("Failed ldb transaction start !? (%d)\n", lret)); + ret = EIO; + goto done; + } + + lret = ldb_search(sysdb->ldb, tmp_ctx, &res, base_dn, + LDB_SCOPE_BASE, attrs, + SYSDB_PWUID_FILTER, + (unsigned long)uid); + if (lret != LDB_SUCCESS) { + DEBUG(1, ("Failed to make search request: %s(%d)[%s]\n", + ldb_strerror(lret), lret, ldb_errstring(sysdb->ldb))); + ret = EIO; + goto done; + } + + if (res->count == 0) { + ret = EOK; + goto done; + } + if (res->count > 1) { + DEBUG(0, ("Cache DB corrupted, base search returned %d results\n", + res->count)); + ret = EOK; + goto done; + } + + account_dn = ldb_dn_copy(tmp_ctx, res->msgs[0]->dn); + if (!account_dn) { + ret = ENOMEM; + goto done; + } + + talloc_free(res); + res = NULL; + + ret = ldb_delete(sysdb->ldb, account_dn); + + if (ret != LDB_SUCCESS) { + DEBUG(2, ("LDB Error: %s(%d)\nError Message: [%s]\n", + ldb_strerror(ret), ret, ldb_errstring(sysdb->ldb))); + ret = EIO; + goto done; + } + + lret = ldb_transaction_commit(sysdb->ldb); + if (lret != LDB_SUCCESS) { + DEBUG(1, ("Failed ldb transaction commit !! (%d)\n", lret)); + ret = EIO; + goto done; + } + + ret = EOK; + +done: + if (ret != EOK) { + lret = ldb_transaction_cancel(sysdb->ldb); + if (lret != LDB_SUCCESS) { + DEBUG(1, ("Failed to cancel ldb transaction (%d)\n", lret)); + } + } + + talloc_free(tmp_ctx); + return ret; +} + +int sysdb_init(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct confdb_ctx *cdb, + struct sysdb_ctx **dbctx) +{ + struct sysdb_ctx *ctx; + int ret; + + ret = sysdb_read_conf(mem_ctx, cdb, &ctx); + if (ret != EOK) + return ret; + + ctx->ldb = ldb_init(mem_ctx, ev); + if (!ctx->ldb) { + talloc_free(ctx); + return EIO; + } + + ret = ldb_connect(ctx->ldb, ctx->ldb_file, 0, NULL); + if (ret != LDB_SUCCESS) { + talloc_free(ctx); + return EIO; + } + + *dbctx = ctx; + + return EOK; +} |