From 0ca19d792b717456f334abdf35279acddf6d71c2 Mon Sep 17 00:00:00 2001 From: Pavel Březina Date: Mon, 23 Apr 2012 13:15:21 +0200 Subject: sudo ldap provider: move async routines to sdap_async_sudo.c --- Makefile.am | 1 + src/providers/ldap/sdap_async_sudo.c | 710 +++++++++++++++++++++++++++++++++++ src/providers/ldap/sdap_sudo.c | 675 --------------------------------- 3 files changed, 711 insertions(+), 675 deletions(-) create mode 100644 src/providers/ldap/sdap_async_sudo.c diff --git a/Makefile.am b/Makefile.am index 2bc47f76..d716755a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1186,6 +1186,7 @@ if BUILD_SUDO libsss_ldap_common_la_SOURCES += \ src/providers/ldap/sdap_sudo_cache.c \ src/providers/ldap/sdap_sudo_timer.c \ + src/providers/ldap/sdap_async_sudo.c \ src/providers/ldap/sdap_sudo.c endif diff --git a/src/providers/ldap/sdap_async_sudo.c b/src/providers/ldap/sdap_async_sudo.c new file mode 100644 index 00000000..d24420a2 --- /dev/null +++ b/src/providers/ldap/sdap_async_sudo.c @@ -0,0 +1,710 @@ +/* + SSSD + + Async LDAP Helper routines for sudo + + Authors: + Pavel Březina + + Copyright (C) 2012 Red Hat + + 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 . +*/ + +#include +#include +#include + +#include "providers/dp_backend.h" +#include "providers/ldap/ldap_common.h" +#include "providers/ldap/sdap.h" +#include "providers/ldap/sdap_async.h" +#include "providers/ldap/sdap_sudo.h" +#include "providers/ldap/sdap_sudo_cache.h" +#include "db/sysdb_sudo.h" + +struct sdap_sudo_load_sudoers_state { + struct tevent_context *ev; + struct sdap_sudo_ctx *sudo_ctx; + struct sdap_options *opts; + struct sdap_handle *sh; + struct sysdb_attrs **ldap_rules; /* search result will be stored here */ + size_t ldap_rules_count; /* search result will be stored here */ + + const char **attrs; + const char *filter; + size_t base_iter; + struct sdap_search_base **search_bases; + int timeout; +}; + +struct sdap_sudo_refresh_state { + struct be_ctx *be_ctx; + struct be_sudo_req *sudo_req; + struct sdap_options *opts; + struct sdap_id_op *sdap_op; + struct sdap_id_conn_cache *sdap_conn_cache; + + int dp_error; + int error; +}; + +static int sdap_sudo_connect(struct tevent_req *req); + +static void sdap_sudo_connect_done(struct tevent_req *subreq); + +static struct tevent_req * sdap_sudo_load_sudoers_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct be_sudo_req *sudo_req, + struct sdap_options *opts, + struct sdap_handle *sh); + +static errno_t sdap_sudo_load_sudoers_next_base(struct tevent_req *req); + +static void sdap_sudo_load_sudoers_process(struct tevent_req *subreq); + +static int sdap_sudo_load_sudoers_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + size_t *rules_count, + struct sysdb_attrs ***rules); + +static void sdap_sudo_load_sudoers_done(struct tevent_req *req); + +static int sdap_sudo_purge_sudoers(struct sysdb_ctx *sysdb_ctx, + struct sss_domain_info *domain, + struct be_sudo_req *sudo_req); + +static int sdap_sudo_store_sudoers(struct sysdb_ctx *sysdb_ctx, + struct sdap_options *opts, + size_t rules_count, + struct sysdb_attrs **rules); + +static const char *sdap_sudo_build_filter(TALLOC_CTX *mem_ctx, + struct sdap_attr_map *map, + struct be_sudo_req *sudo_req); + +static const char *sdap_sudo_build_user_filter(TALLOC_CTX *mem_ctx, + struct sdap_attr_map *map, + const char *username, + uid_t uid, + char **groups); + +struct tevent_req *sdap_sudo_refresh_send(TALLOC_CTX *mem_ctx, + struct be_ctx *be_ctx, + struct be_sudo_req *sudo_req, + struct sdap_options *opts, + struct sdap_id_conn_cache *conn_cache) +{ + struct tevent_req *req = NULL; + struct sdap_sudo_refresh_state *state = NULL; + int ret; + + req = tevent_req_create(mem_ctx, &state, struct sdap_sudo_refresh_state); + if (!req) { + return NULL; + } + + state->be_ctx = be_ctx; + state->sudo_req = sudo_req; + state->opts = opts; + state->sdap_op = NULL; + state->sdap_conn_cache = conn_cache; + state->dp_error = DP_ERR_OK; + state->error = EOK; + + switch (sudo_req->type) { + case BE_REQ_SUDO_ALL: + DEBUG(SSSDBG_TRACE_FUNC, ("Requested refresh for: \n")); + break; + case BE_REQ_SUDO_DEFAULTS: + DEBUG(SSSDBG_TRACE_FUNC, ("Requested refresh of cn=defaults\n")); + break; + case BE_REQ_SUDO_USER: + DEBUG(SSSDBG_TRACE_FUNC, ("Requested refresh for: %s\n", + sudo_req->username)); + break; + default: + DEBUG(SSSDBG_CRIT_FAILURE, ("Invalid request type %d\n", sudo_req->type)); + ret = EINVAL; + goto immediately; + } + + ret = sdap_sudo_connect(req); + if (ret == EAGAIN) { + /* asynchronous processing */ + return req; + } + +immediately: + if (ret == EOK) { + tevent_req_done(req); + } else { + tevent_req_error(req, ret); + } + tevent_req_post(req, be_ctx->ev); + + return req; +} + +int sdap_sudo_refresh_recv(struct tevent_req *req, + int *dp_error, + int *error) +{ + struct sdap_sudo_refresh_state *state = NULL; + + state = tevent_req_data(req, struct sdap_sudo_refresh_state); + + TEVENT_REQ_RETURN_ON_ERROR(req); + + *dp_error = state->dp_error; + *error = state->error; + + return EOK; +} + +int sdap_sudo_connect(struct tevent_req *req) +{ + struct tevent_req *subreq = NULL; + struct sdap_sudo_refresh_state *state = NULL; + int ret; + + state = tevent_req_data(req, struct sdap_sudo_refresh_state); + + if (be_is_offline(state->be_ctx)) { + state->dp_error = DP_ERR_OFFLINE; + state->error = EAGAIN; + return EOK; + } + + if (state->sdap_op == NULL) { + state->sdap_op = sdap_id_op_create(state, state->sdap_conn_cache); + if (state->sdap_op == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("sdap_id_op_create() failed\n")); + state->dp_error = DP_ERR_FATAL; + state->error = EIO; + return EIO; + } + } + + subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret); + if (subreq == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, + ("sdap_id_op_connect_send() failed: %d(%s)\n", ret, strerror(ret))); + talloc_zfree(state->sdap_op); + state->dp_error = DP_ERR_FATAL; + state->error = ret; + return ret; + } + + tevent_req_set_callback(subreq, sdap_sudo_connect_done, req); + + return EAGAIN; +} + +void sdap_sudo_connect_done(struct tevent_req *subreq) +{ + struct tevent_req *req = NULL; /* req from sdap_sudo_refresh_send() */ + struct sdap_sudo_refresh_state *state = NULL; + int dp_error; + int ret; + + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct sdap_sudo_refresh_state); + + ret = sdap_id_op_connect_recv(subreq, &dp_error); + talloc_zfree(subreq); + + if (dp_error == DP_ERR_OFFLINE) { + talloc_zfree(state->sdap_op); + state->dp_error = DP_ERR_OFFLINE; + state->error = EAGAIN; + tevent_req_done(req); + return; + } else if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + ("SUDO LDAP connection failed - %s\n", strerror(ret))); + goto fail; + } + + DEBUG(SSSDBG_TRACE_FUNC, ("SUDO LDAP connection successful\n")); + + subreq = sdap_sudo_load_sudoers_send(state, state->be_ctx->ev, + state->sudo_req, state->opts, + sdap_id_op_handle(state->sdap_op)); + if (subreq == NULL) { + ret = EFAULT; + goto fail; + } + + tevent_req_set_callback(subreq, sdap_sudo_load_sudoers_done, req); + + return; + +fail: + state->dp_error = DP_ERR_FATAL; + state->error = ret; + tevent_req_error(req, ret); +} + +struct tevent_req * sdap_sudo_load_sudoers_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct be_sudo_req *sudo_req, + struct sdap_options *opts, + struct sdap_handle *sh) + + + +{ + struct tevent_req *req = NULL; + struct sdap_sudo_load_sudoers_state *state = NULL; + int ret; + + req = tevent_req_create(mem_ctx, &state, struct sdap_sudo_load_sudoers_state); + if (!req) { + return NULL; + } + + state->ev = ev; + state->opts = opts; + state->sh = sh; + state->base_iter = 0; + state->search_bases = opts->sudo_search_bases; + state->timeout = dp_opt_get_int(opts->basic, SDAP_SEARCH_TIMEOUT); + state->ldap_rules = NULL; + state->ldap_rules_count = 0; + + if (!state->search_bases) { + DEBUG(SSSDBG_CRIT_FAILURE, + ("SUDOERS lookup request without a search base\n")); + ret = EINVAL; + goto done; + } + + /* create filter */ + state->filter = sdap_sudo_build_filter(state, opts->sudorule_map, sudo_req); + if (state->filter == NULL) { + goto fail; + } + + /* create attrs from map */ + ret = build_attrs_from_map(state, opts->sudorule_map, SDAP_OPTS_SUDO, + NULL, &state->attrs, NULL); + if (ret != EOK) { + goto fail; + } + + /* begin search */ + ret = sdap_sudo_load_sudoers_next_base(req); + +done: + if (ret != EOK) { + tevent_req_error(req, ret); + tevent_req_post(req, ev); + } + + return req; + +fail: + talloc_zfree(req); + return NULL; +} + +static errno_t sdap_sudo_load_sudoers_next_base(struct tevent_req *req) +{ + struct tevent_req *subreq = NULL; + struct sdap_sudo_load_sudoers_state *state = NULL; + struct sdap_search_base *search_base = NULL; + char *filter = NULL; + + state = tevent_req_data(req, struct sdap_sudo_load_sudoers_state); + search_base = state->search_bases[state->base_iter]; + if (search_base == NULL) { + /* should not happen */ + DEBUG(SSSDBG_CRIT_FAILURE, ("search_base is null\n")); + return EFAULT; + } + + /* create filter */ + filter = sdap_get_id_specific_filter(state, state->filter, + search_base->filter); + if (filter == NULL) { + return ENOMEM; + } + + /* send request */ + DEBUG(SSSDBG_TRACE_FUNC, + ("Searching for sudo rules with base [%s]\n", + search_base->basedn)); + + subreq = sdap_get_generic_send(state, + state->ev, + state->opts, + state->sh, + search_base->basedn, + search_base->scope, + filter, + state->attrs, + state->opts->sudorule_map, + SDAP_OPTS_SUDO, + state->timeout, + true); + if (subreq == NULL) { + return ENOMEM; + } + + tevent_req_set_callback(subreq, sdap_sudo_load_sudoers_process, req); + + return EOK; +} + +static void sdap_sudo_load_sudoers_process(struct tevent_req *subreq) +{ + struct tevent_req *req = NULL; + struct sdap_sudo_load_sudoers_state *state = NULL; + struct sdap_search_base *search_base = NULL; + struct sysdb_attrs **attrs = NULL; + size_t count; + int ret; + int i; + + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct sdap_sudo_load_sudoers_state); + search_base = state->search_bases[state->base_iter]; + + DEBUG(SSSDBG_TRACE_FUNC, + ("Receiving sudo rules with base [%s]\n", + search_base->basedn)); + + ret = sdap_get_generic_recv(subreq, state, &count, &attrs); + talloc_zfree(subreq); + if (ret) { + tevent_req_error(req, ret); + return; + } + + /* add rules to result */ + if (count > 0) { + state->ldap_rules = talloc_realloc(state, state->ldap_rules, + struct sysdb_attrs *, + state->ldap_rules_count + count); + if (state->ldap_rules == NULL) { + tevent_req_error(req, ENOMEM); + return; + } + + for (i = 0; i < count; i++) { + state->ldap_rules[state->ldap_rules_count + i] = talloc_steal( + state->ldap_rules, attrs[i]); + } + + state->ldap_rules_count += count; + } + + /* go to next base */ + state->base_iter++; + if (state->search_bases[state->base_iter]) { + ret = sdap_sudo_load_sudoers_next_base(req); + if (ret != EOK) { + tevent_req_error(req, ret); + } + + return; + } + + /* we are done */ + tevent_req_done(req); +} + +int sdap_sudo_load_sudoers_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + size_t *rules_count, + struct sysdb_attrs ***rules) +{ + struct sdap_sudo_load_sudoers_state *state = NULL; + + state = tevent_req_data(req, struct sdap_sudo_load_sudoers_state); + + TEVENT_REQ_RETURN_ON_ERROR(req); + + *rules_count = state->ldap_rules_count; + *rules = talloc_steal(mem_ctx, state->ldap_rules); + + return EOK; +} + +void sdap_sudo_load_sudoers_done(struct tevent_req *subreq) +{ + struct tevent_req *req = NULL; /* req from sdap_sudo_refresh_send() */ + struct sdap_sudo_refresh_state *state = NULL; + struct sysdb_attrs **rules = NULL; + size_t rules_count; + int ret; + + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct sdap_sudo_refresh_state); + + ret = sdap_sudo_load_sudoers_recv(subreq, state, &rules_count, &rules); + talloc_zfree(subreq); + if (ret != EOK) { + goto done; + } + + DEBUG(SSSDBG_TRACE_FUNC, ("Received %d rules\n", rules_count)); + + /* purge cache */ + ret = sdap_sudo_purge_sudoers(state->be_ctx->sysdb, state->be_ctx->domain, + state->sudo_req); + if (ret != EOK) { + goto done; + } + + /* store rules */ + ret = sdap_sudo_store_sudoers(state->be_ctx->sysdb, state->opts, + rules_count, rules); + if (ret != EOK) { + goto done; + } + + DEBUG(SSSDBG_TRACE_FUNC, ("Sudoers is successfuly stored in cache\n")); + + ret = EOK; + +done: + state->error = ret; + if (ret == EOK) { + state->dp_error = DP_ERR_OK; + tevent_req_done(req); + } else { + state->dp_error = DP_ERR_FATAL; + tevent_req_error(req, ret); + } +} + +int sdap_sudo_purge_sudoers(struct sysdb_ctx *sysdb_ctx, + struct sss_domain_info *domain, + struct be_sudo_req *sudo_req) +{ + TALLOC_CTX *tmp_ctx; + char *filter = NULL; + char **sudouser = NULL; + int ret = EOK; + errno_t sret; + bool in_transaction = false; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n")); + return ENOMEM; + } + + ret = sysdb_transaction_start(sysdb_ctx); + if (ret != EOK) { + goto done; + } + in_transaction = true; + + switch (sudo_req->type) { + case BE_REQ_SUDO_ALL: + DEBUG(SSSDBG_TRACE_FUNC, ("Purging SUDOers cache of all rules\n")); + ret = sysdb_sudo_purge_all(sysdb_ctx); + break; + case BE_REQ_SUDO_DEFAULTS: + DEBUG(SSSDBG_TRACE_FUNC, ("Purging SUDOers cache of default options\n")); + ret = sysdb_sudo_purge_byname(sysdb_ctx, SDAP_SUDO_DEFAULTS); + break; + case BE_REQ_SUDO_USER: + DEBUG(SSSDBG_TRACE_FUNC, ("Purging SUDOers cache of user's [%s] rules\n", + sudo_req->username)); + + /* netgroups */ + ret = sysdb_get_sudo_filter(tmp_ctx, NULL, 0, NULL, + SYSDB_SUDO_FILTER_NGRS, &filter); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to create filter to purge " + "SUDOers cache [%d]: %s\n", ret, strerror(ret))); + goto done; + } + + ret = sysdb_sudo_purge_byfilter(sysdb_ctx, filter); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to purge SUDOers cache " + "(netgroups) [%d]: %s\n", ret, strerror(ret))); + goto done; + } + + /* user, uid, groups */ + sudouser = sysdb_sudo_build_sudouser(tmp_ctx, sudo_req->username, + sudo_req->uid, sudo_req->groups, + true); + if (sudouser == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to create sudoUser to purge " + "SUDOers cache [%d]: %s\n", ret, strerror(ret))); + goto done; + } + + ret = sysdb_sudo_purge_bysudouser(sysdb_ctx, sudouser); + break; + default: + DEBUG(SSSDBG_CRIT_FAILURE, ("Invalid request type %d\n", sudo_req->type)); + return EINVAL; + } + + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to purge SUDOers cache [%d]: %s\n", + ret, strerror(ret))); + goto done; + } + + ret = sysdb_transaction_commit(sysdb_ctx); + if (ret == EOK) { + in_transaction = false; + } + +done: + if (in_transaction) { + sret = sysdb_transaction_cancel(sysdb_ctx); + if (sret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("Could not cancel transaction\n")); + } + } + + talloc_free(tmp_ctx); + return ret; +} + +int sdap_sudo_store_sudoers(struct sysdb_ctx *sysdb_ctx, + struct sdap_options *opts, + size_t rules_count, + struct sysdb_attrs **rules) +{ + errno_t ret; + + /* Empty sudoers? Done. */ + if (rules_count == 0 || rules == NULL) { + return EOK; + } + + ret = sdap_save_native_sudorule_list(sysdb_ctx, opts->sudorule_map, + rules, rules_count); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("failed to save sudo rules [%d]: %s\n", + ret, strerror(ret))); + return ret; + } + + return EOK; +} + +const char *sdap_sudo_build_filter(TALLOC_CTX *mem_ctx, + struct sdap_attr_map *map, + struct be_sudo_req *sudo_req) +{ + switch (sudo_req->type) { + case BE_REQ_SUDO_ALL: + return talloc_asprintf(mem_ctx, SDAP_SUDO_FILTER_ALL, + map[SDAP_OC_SUDORULE].name); + break; + case BE_REQ_SUDO_DEFAULTS: + return talloc_asprintf(mem_ctx, SDAP_SUDO_FILTER_DEFAULTS, + map[SDAP_OC_SUDORULE].name, + map[SDAP_AT_SUDO_NAME].name, + SDAP_SUDO_DEFAULTS); /* FIXME: add option for this */ + break; + case BE_REQ_SUDO_USER: + return sdap_sudo_build_user_filter(mem_ctx, map, sudo_req->username, + sudo_req->uid, sudo_req->groups); + + break; + default: + DEBUG(SSSDBG_CRIT_FAILURE, ("Invalid request type %d\n", sudo_req->type)); + return NULL; + } +} + +/* alway update cn=defaults and sudoUser=ALL */ +const char *sdap_sudo_build_user_filter(TALLOC_CTX *mem_ctx, + struct sdap_attr_map *map, + const char *username, + uid_t uid, + char **groups) +{ + char *filter = NULL; + char *output = NULL; + char *sanitized = NULL; + char **group = NULL; + int ret; + + /* user name */ + ret = sss_filter_sanitize(filter, username, &sanitized); + if (ret != EOK) { + goto fail; + } + filter = talloc_asprintf_append(filter, SDAP_SUDO_FILTER_USERNAME, + map[SDAP_AT_SUDO_USER].name, + sanitized); + if (filter == NULL) { + goto fail; + } + + /* user uid */ + filter = talloc_asprintf_append(filter, SDAP_SUDO_FILTER_UID, + map[SDAP_AT_SUDO_USER].name, + uid); + if (filter == NULL) { + goto fail; + } + + /* groups */ + if (groups != NULL) { + for (group = groups; *group != NULL; group++) { + ret = sss_filter_sanitize(filter, *group, &sanitized); + if (ret != EOK) { + goto fail; + } + filter = talloc_asprintf_append(filter, SDAP_SUDO_FILTER_GROUP, + map[SDAP_AT_SUDO_USER].name, + sanitized); + if (filter == NULL) { + goto fail; + } + } + } + + /* netgroups */ + /* + * FIXME: load only netgroups user is member of + * FIXME: add option to disable this filter + */ + filter = talloc_asprintf_append(filter, SDAP_SUDO_FILTER_NETGROUP, + map[SDAP_AT_SUDO_USER].name, + "*"); + if (filter == NULL) { + goto fail; + } + + + output = talloc_asprintf(mem_ctx, SDAP_SUDO_FILTER_USER, + map[SDAP_OC_SUDORULE].name, + map[SDAP_AT_SUDO_NAME].name, + SDAP_SUDO_DEFAULTS, /* FIXME: add option for this */ + map[SDAP_AT_SUDO_USER].name, + filter); + + talloc_free(filter); + return output; + +fail: + talloc_free(filter); + return NULL; +} diff --git a/src/providers/ldap/sdap_sudo.c b/src/providers/ldap/sdap_sudo.c index 75d30430..3bef454a 100644 --- a/src/providers/ldap/sdap_sudo.c +++ b/src/providers/ldap/sdap_sudo.c @@ -131,72 +131,6 @@ int sdap_sudo_setup_tasks(struct sdap_id_ctx *id_ctx) return EOK; } -struct sdap_sudo_load_sudoers_state { - struct tevent_context *ev; - struct sdap_sudo_ctx *sudo_ctx; - struct sdap_options *opts; - struct sdap_handle *sh; - struct sysdb_attrs **ldap_rules; /* search result will be stored here */ - size_t ldap_rules_count; /* search result will be stored here */ - - const char **attrs; - const char *filter; - size_t base_iter; - struct sdap_search_base **search_bases; - int timeout; -}; - -struct sdap_sudo_refresh_state { - struct be_ctx *be_ctx; - struct be_sudo_req *sudo_req; - struct sdap_options *opts; - struct sdap_id_op *sdap_op; - struct sdap_id_conn_cache *sdap_conn_cache; - - int dp_error; - int error; -}; - -static int sdap_sudo_connect(struct tevent_req *req); - -static void sdap_sudo_connect_done(struct tevent_req *subreq); - -static struct tevent_req * sdap_sudo_load_sudoers_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct be_sudo_req *sudo_req, - struct sdap_options *opts, - struct sdap_handle *sh); - -static errno_t sdap_sudo_load_sudoers_next_base(struct tevent_req *req); - -static void sdap_sudo_load_sudoers_process(struct tevent_req *subreq); - -static int sdap_sudo_load_sudoers_recv(struct tevent_req *req, - TALLOC_CTX *mem_ctx, - size_t *rules_count, - struct sysdb_attrs ***rules); - -static void sdap_sudo_load_sudoers_done(struct tevent_req *req); - -static int sdap_sudo_purge_sudoers(struct sysdb_ctx *sysdb_ctx, - struct sss_domain_info *domain, - struct be_sudo_req *sudo_req); - -static int sdap_sudo_store_sudoers(struct sysdb_ctx *sysdb_ctx, - struct sdap_options *opts, - size_t rules_count, - struct sysdb_attrs **rules); - -static const char *sdap_sudo_build_filter(TALLOC_CTX *mem_ctx, - struct sdap_attr_map *map, - struct be_sudo_req *sudo_req); - -static const char *sdap_sudo_build_user_filter(TALLOC_CTX *mem_ctx, - struct sdap_attr_map *map, - const char *username, - uid_t uid, - char **groups); - static void sdap_sudo_reply(struct tevent_req *req) { struct be_req *be_req = NULL; @@ -256,612 +190,3 @@ void sdap_sudo_handler(struct be_req *be_req) fail: sdap_handler_done(be_req, DP_ERR_FATAL, ret, NULL); } - -struct tevent_req *sdap_sudo_refresh_send(TALLOC_CTX *mem_ctx, - struct be_ctx *be_ctx, - struct be_sudo_req *sudo_req, - struct sdap_options *opts, - struct sdap_id_conn_cache *conn_cache) -{ - struct tevent_req *req = NULL; - struct sdap_sudo_refresh_state *state = NULL; - int ret; - - req = tevent_req_create(mem_ctx, &state, struct sdap_sudo_refresh_state); - if (!req) { - return NULL; - } - - state->be_ctx = be_ctx; - state->sudo_req = sudo_req; - state->opts = opts; - state->sdap_op = NULL; - state->sdap_conn_cache = conn_cache; - state->dp_error = DP_ERR_OK; - state->error = EOK; - - switch (sudo_req->type) { - case BE_REQ_SUDO_ALL: - DEBUG(SSSDBG_TRACE_FUNC, ("Requested refresh for: \n")); - break; - case BE_REQ_SUDO_DEFAULTS: - DEBUG(SSSDBG_TRACE_FUNC, ("Requested refresh of cn=defaults\n")); - break; - case BE_REQ_SUDO_USER: - DEBUG(SSSDBG_TRACE_FUNC, ("Requested refresh for: %s\n", - sudo_req->username)); - break; - default: - DEBUG(SSSDBG_CRIT_FAILURE, ("Invalid request type %d\n", sudo_req->type)); - ret = EINVAL; - goto immediately; - } - - ret = sdap_sudo_connect(req); - if (ret == EAGAIN) { - /* asynchronous processing */ - return req; - } - -immediately: - if (ret == EOK) { - tevent_req_done(req); - } else { - tevent_req_error(req, ret); - } - tevent_req_post(req, be_ctx->ev); - - return req; -} - -int sdap_sudo_refresh_recv(struct tevent_req *req, - int *dp_error, - int *error) -{ - struct sdap_sudo_refresh_state *state = NULL; - - state = tevent_req_data(req, struct sdap_sudo_refresh_state); - - TEVENT_REQ_RETURN_ON_ERROR(req); - - *dp_error = state->dp_error; - *error = state->error; - - return EOK; -} - -int sdap_sudo_connect(struct tevent_req *req) -{ - struct tevent_req *subreq = NULL; - struct sdap_sudo_refresh_state *state = NULL; - int ret; - - state = tevent_req_data(req, struct sdap_sudo_refresh_state); - - if (be_is_offline(state->be_ctx)) { - state->dp_error = DP_ERR_OFFLINE; - state->error = EAGAIN; - return EOK; - } - - if (state->sdap_op == NULL) { - state->sdap_op = sdap_id_op_create(state, state->sdap_conn_cache); - if (state->sdap_op == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, ("sdap_id_op_create() failed\n")); - state->dp_error = DP_ERR_FATAL; - state->error = EIO; - return EIO; - } - } - - subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret); - if (subreq == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, - ("sdap_id_op_connect_send() failed: %d(%s)\n", ret, strerror(ret))); - talloc_zfree(state->sdap_op); - state->dp_error = DP_ERR_FATAL; - state->error = ret; - return ret; - } - - tevent_req_set_callback(subreq, sdap_sudo_connect_done, req); - - return EAGAIN; -} - -void sdap_sudo_connect_done(struct tevent_req *subreq) -{ - struct tevent_req *req = NULL; /* req from sdap_sudo_refresh_send() */ - struct sdap_sudo_refresh_state *state = NULL; - int dp_error; - int ret; - - req = tevent_req_callback_data(subreq, struct tevent_req); - state = tevent_req_data(req, struct sdap_sudo_refresh_state); - - ret = sdap_id_op_connect_recv(subreq, &dp_error); - talloc_zfree(subreq); - - if (dp_error == DP_ERR_OFFLINE) { - talloc_zfree(state->sdap_op); - state->dp_error = DP_ERR_OFFLINE; - state->error = EAGAIN; - tevent_req_done(req); - return; - } else if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, - ("SUDO LDAP connection failed - %s\n", strerror(ret))); - goto fail; - } - - DEBUG(SSSDBG_TRACE_FUNC, ("SUDO LDAP connection successful\n")); - - subreq = sdap_sudo_load_sudoers_send(state, state->be_ctx->ev, - state->sudo_req, state->opts, - sdap_id_op_handle(state->sdap_op)); - if (subreq == NULL) { - ret = EFAULT; - goto fail; - } - - tevent_req_set_callback(subreq, sdap_sudo_load_sudoers_done, req); - - return; - -fail: - state->dp_error = DP_ERR_FATAL; - state->error = ret; - tevent_req_error(req, ret); -} - -struct tevent_req * sdap_sudo_load_sudoers_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct be_sudo_req *sudo_req, - struct sdap_options *opts, - struct sdap_handle *sh) - - - -{ - struct tevent_req *req = NULL; - struct sdap_sudo_load_sudoers_state *state = NULL; - int ret; - - req = tevent_req_create(mem_ctx, &state, struct sdap_sudo_load_sudoers_state); - if (!req) { - return NULL; - } - - state->ev = ev; - state->opts = opts; - state->sh = sh; - state->base_iter = 0; - state->search_bases = opts->sudo_search_bases; - state->timeout = dp_opt_get_int(opts->basic, SDAP_SEARCH_TIMEOUT); - state->ldap_rules = NULL; - state->ldap_rules_count = 0; - - if (!state->search_bases) { - DEBUG(SSSDBG_CRIT_FAILURE, - ("SUDOERS lookup request without a search base\n")); - ret = EINVAL; - goto done; - } - - /* create filter */ - state->filter = sdap_sudo_build_filter(state, opts->sudorule_map, sudo_req); - if (state->filter == NULL) { - goto fail; - } - - /* create attrs from map */ - ret = build_attrs_from_map(state, opts->sudorule_map, SDAP_OPTS_SUDO, - NULL, &state->attrs, NULL); - if (ret != EOK) { - goto fail; - } - - /* begin search */ - ret = sdap_sudo_load_sudoers_next_base(req); - -done: - if (ret != EOK) { - tevent_req_error(req, ret); - tevent_req_post(req, ev); - } - - return req; - -fail: - talloc_zfree(req); - return NULL; -} - -static errno_t sdap_sudo_load_sudoers_next_base(struct tevent_req *req) -{ - struct tevent_req *subreq = NULL; - struct sdap_sudo_load_sudoers_state *state = NULL; - struct sdap_search_base *search_base = NULL; - char *filter = NULL; - - state = tevent_req_data(req, struct sdap_sudo_load_sudoers_state); - search_base = state->search_bases[state->base_iter]; - if (search_base == NULL) { - /* should not happen */ - DEBUG(SSSDBG_CRIT_FAILURE, ("search_base is null\n")); - return EFAULT; - } - - /* create filter */ - filter = sdap_get_id_specific_filter(state, state->filter, - search_base->filter); - if (filter == NULL) { - return ENOMEM; - } - - /* send request */ - DEBUG(SSSDBG_TRACE_FUNC, - ("Searching for sudo rules with base [%s]\n", - search_base->basedn)); - - subreq = sdap_get_generic_send(state, - state->ev, - state->opts, - state->sh, - search_base->basedn, - search_base->scope, - filter, - state->attrs, - state->opts->sudorule_map, - SDAP_OPTS_SUDO, - state->timeout, - true); - if (subreq == NULL) { - return ENOMEM; - } - - tevent_req_set_callback(subreq, sdap_sudo_load_sudoers_process, req); - - return EOK; -} - -static void sdap_sudo_load_sudoers_process(struct tevent_req *subreq) -{ - struct tevent_req *req = NULL; - struct sdap_sudo_load_sudoers_state *state = NULL; - struct sdap_search_base *search_base = NULL; - struct sysdb_attrs **attrs = NULL; - size_t count; - int ret; - int i; - - req = tevent_req_callback_data(subreq, struct tevent_req); - state = tevent_req_data(req, struct sdap_sudo_load_sudoers_state); - search_base = state->search_bases[state->base_iter]; - - DEBUG(SSSDBG_TRACE_FUNC, - ("Receiving sudo rules with base [%s]\n", - search_base->basedn)); - - ret = sdap_get_generic_recv(subreq, state, &count, &attrs); - talloc_zfree(subreq); - if (ret) { - tevent_req_error(req, ret); - return; - } - - /* add rules to result */ - if (count > 0) { - state->ldap_rules = talloc_realloc(state, state->ldap_rules, - struct sysdb_attrs *, - state->ldap_rules_count + count); - if (state->ldap_rules == NULL) { - tevent_req_error(req, ENOMEM); - return; - } - - for (i = 0; i < count; i++) { - state->ldap_rules[state->ldap_rules_count + i] = talloc_steal( - state->ldap_rules, attrs[i]); - } - - state->ldap_rules_count += count; - } - - /* go to next base */ - state->base_iter++; - if (state->search_bases[state->base_iter]) { - ret = sdap_sudo_load_sudoers_next_base(req); - if (ret != EOK) { - tevent_req_error(req, ret); - } - - return; - } - - /* we are done */ - tevent_req_done(req); -} - -int sdap_sudo_load_sudoers_recv(struct tevent_req *req, - TALLOC_CTX *mem_ctx, - size_t *rules_count, - struct sysdb_attrs ***rules) -{ - struct sdap_sudo_load_sudoers_state *state = NULL; - - state = tevent_req_data(req, struct sdap_sudo_load_sudoers_state); - - TEVENT_REQ_RETURN_ON_ERROR(req); - - *rules_count = state->ldap_rules_count; - *rules = talloc_steal(mem_ctx, state->ldap_rules); - - return EOK; -} - -void sdap_sudo_load_sudoers_done(struct tevent_req *subreq) -{ - struct tevent_req *req = NULL; /* req from sdap_sudo_refresh_send() */ - struct sdap_sudo_refresh_state *state = NULL; - struct sysdb_attrs **rules = NULL; - size_t rules_count; - int ret; - - req = tevent_req_callback_data(subreq, struct tevent_req); - state = tevent_req_data(req, struct sdap_sudo_refresh_state); - - ret = sdap_sudo_load_sudoers_recv(subreq, state, &rules_count, &rules); - talloc_zfree(subreq); - if (ret != EOK) { - goto done; - } - - DEBUG(SSSDBG_TRACE_FUNC, ("Received %d rules\n", rules_count)); - - /* purge cache */ - ret = sdap_sudo_purge_sudoers(state->be_ctx->sysdb, state->be_ctx->domain, - state->sudo_req); - if (ret != EOK) { - goto done; - } - - /* store rules */ - ret = sdap_sudo_store_sudoers(state->be_ctx->sysdb, state->opts, - rules_count, rules); - if (ret != EOK) { - goto done; - } - - DEBUG(SSSDBG_TRACE_FUNC, ("Sudoers is successfuly stored in cache\n")); - - ret = EOK; - -done: - state->error = ret; - if (ret == EOK) { - state->dp_error = DP_ERR_OK; - tevent_req_done(req); - } else { - state->dp_error = DP_ERR_FATAL; - tevent_req_error(req, ret); - } -} - -int sdap_sudo_purge_sudoers(struct sysdb_ctx *sysdb_ctx, - struct sss_domain_info *domain, - struct be_sudo_req *sudo_req) -{ - TALLOC_CTX *tmp_ctx; - char *filter = NULL; - char **sudouser = NULL; - int ret = EOK; - errno_t sret; - bool in_transaction = false; - - tmp_ctx = talloc_new(NULL); - if (tmp_ctx == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n")); - return ENOMEM; - } - - ret = sysdb_transaction_start(sysdb_ctx); - if (ret != EOK) { - goto done; - } - in_transaction = true; - - switch (sudo_req->type) { - case BE_REQ_SUDO_ALL: - DEBUG(SSSDBG_TRACE_FUNC, ("Purging SUDOers cache of all rules\n")); - ret = sysdb_sudo_purge_all(sysdb_ctx); - break; - case BE_REQ_SUDO_DEFAULTS: - DEBUG(SSSDBG_TRACE_FUNC, ("Purging SUDOers cache of default options\n")); - ret = sysdb_sudo_purge_byname(sysdb_ctx, SDAP_SUDO_DEFAULTS); - break; - case BE_REQ_SUDO_USER: - DEBUG(SSSDBG_TRACE_FUNC, ("Purging SUDOers cache of user's [%s] rules\n", - sudo_req->username)); - - /* netgroups */ - ret = sysdb_get_sudo_filter(tmp_ctx, NULL, 0, NULL, - SYSDB_SUDO_FILTER_NGRS, &filter); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to create filter to purge " - "SUDOers cache [%d]: %s\n", ret, strerror(ret))); - goto done; - } - - ret = sysdb_sudo_purge_byfilter(sysdb_ctx, filter); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to purge SUDOers cache " - "(netgroups) [%d]: %s\n", ret, strerror(ret))); - goto done; - } - - /* user, uid, groups */ - sudouser = sysdb_sudo_build_sudouser(tmp_ctx, sudo_req->username, - sudo_req->uid, sudo_req->groups, - true); - if (sudouser == NULL) { - DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to create sudoUser to purge " - "SUDOers cache [%d]: %s\n", ret, strerror(ret))); - goto done; - } - - ret = sysdb_sudo_purge_bysudouser(sysdb_ctx, sudouser); - break; - default: - DEBUG(SSSDBG_CRIT_FAILURE, ("Invalid request type %d\n", sudo_req->type)); - return EINVAL; - } - - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to purge SUDOers cache [%d]: %s\n", - ret, strerror(ret))); - goto done; - } - - ret = sysdb_transaction_commit(sysdb_ctx); - if (ret == EOK) { - in_transaction = false; - } - -done: - if (in_transaction) { - sret = sysdb_transaction_cancel(sysdb_ctx); - if (sret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, ("Could not cancel transaction\n")); - } - } - - talloc_free(tmp_ctx); - return ret; -} - -int sdap_sudo_store_sudoers(struct sysdb_ctx *sysdb_ctx, - struct sdap_options *opts, - size_t rules_count, - struct sysdb_attrs **rules) -{ - errno_t ret; - - /* Empty sudoers? Done. */ - if (rules_count == 0 || rules == NULL) { - return EOK; - } - - ret = sdap_save_native_sudorule_list(sysdb_ctx, opts->sudorule_map, - rules, rules_count); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, ("failed to save sudo rules [%d]: %s\n", - ret, strerror(ret))); - return ret; - } - - return EOK; -} - -const char *sdap_sudo_build_filter(TALLOC_CTX *mem_ctx, - struct sdap_attr_map *map, - struct be_sudo_req *sudo_req) -{ - switch (sudo_req->type) { - case BE_REQ_SUDO_ALL: - return talloc_asprintf(mem_ctx, SDAP_SUDO_FILTER_ALL, - map[SDAP_OC_SUDORULE].name); - break; - case BE_REQ_SUDO_DEFAULTS: - return talloc_asprintf(mem_ctx, SDAP_SUDO_FILTER_DEFAULTS, - map[SDAP_OC_SUDORULE].name, - map[SDAP_AT_SUDO_NAME].name, - SDAP_SUDO_DEFAULTS); /* FIXME: add option for this */ - break; - case BE_REQ_SUDO_USER: - return sdap_sudo_build_user_filter(mem_ctx, map, sudo_req->username, - sudo_req->uid, sudo_req->groups); - - break; - default: - DEBUG(SSSDBG_CRIT_FAILURE, ("Invalid request type %d\n", sudo_req->type)); - return NULL; - } -} - -/* alway update cn=defaults and sudoUser=ALL */ -const char *sdap_sudo_build_user_filter(TALLOC_CTX *mem_ctx, - struct sdap_attr_map *map, - const char *username, - uid_t uid, - char **groups) -{ - char *filter = NULL; - char *output = NULL; - char *sanitized = NULL; - char **group = NULL; - int ret; - - /* user name */ - ret = sss_filter_sanitize(filter, username, &sanitized); - if (ret != EOK) { - goto fail; - } - filter = talloc_asprintf_append(filter, SDAP_SUDO_FILTER_USERNAME, - map[SDAP_AT_SUDO_USER].name, - sanitized); - if (filter == NULL) { - goto fail; - } - - /* user uid */ - filter = talloc_asprintf_append(filter, SDAP_SUDO_FILTER_UID, - map[SDAP_AT_SUDO_USER].name, - uid); - if (filter == NULL) { - goto fail; - } - - /* groups */ - if (groups != NULL) { - for (group = groups; *group != NULL; group++) { - ret = sss_filter_sanitize(filter, *group, &sanitized); - if (ret != EOK) { - goto fail; - } - filter = talloc_asprintf_append(filter, SDAP_SUDO_FILTER_GROUP, - map[SDAP_AT_SUDO_USER].name, - sanitized); - if (filter == NULL) { - goto fail; - } - } - } - - /* netgroups */ - /* - * FIXME: load only netgroups user is member of - * FIXME: add option to disable this filter - */ - filter = talloc_asprintf_append(filter, SDAP_SUDO_FILTER_NETGROUP, - map[SDAP_AT_SUDO_USER].name, - "*"); - if (filter == NULL) { - goto fail; - } - - - output = talloc_asprintf(mem_ctx, SDAP_SUDO_FILTER_USER, - map[SDAP_OC_SUDORULE].name, - map[SDAP_AT_SUDO_NAME].name, - SDAP_SUDO_DEFAULTS, /* FIXME: add option for this */ - map[SDAP_AT_SUDO_USER].name, - filter); - - talloc_free(filter); - return output; - -fail: - talloc_free(filter); - return NULL; -} -- cgit