From 38e2ec1c757955ab557fd95807afa58042d09482 Mon Sep 17 00:00:00 2001 From: Jan Zeleny Date: Tue, 24 Jul 2012 12:31:19 -0400 Subject: Renamed session provider to selinux provider --- src/providers/data_provider_be.c | 14 +- src/providers/dp_backend.h | 2 +- src/providers/ipa/ipa_autofs.c | 2 +- src/providers/ipa/ipa_init.c | 30 +- src/providers/ipa/ipa_selinux.c | 625 +++++++++++++++++++++++++++++++++++++++ src/providers/ipa/ipa_selinux.h | 40 +++ src/providers/ipa/ipa_session.c | 625 --------------------------------------- src/providers/ipa/ipa_session.h | 40 --- 8 files changed, 688 insertions(+), 690 deletions(-) create mode 100644 src/providers/ipa/ipa_selinux.c create mode 100644 src/providers/ipa/ipa_selinux.h delete mode 100644 src/providers/ipa/ipa_session.c delete mode 100644 src/providers/ipa/ipa_session.h (limited to 'src/providers') diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c index 3b901097..114fde52 100644 --- a/src/providers/data_provider_be.c +++ b/src/providers/data_provider_be.c @@ -113,7 +113,7 @@ static struct bet_data bet_data[] = { {BET_CHPASS, CONFDB_DOMAIN_CHPASS_PROVIDER, "sssm_%s_chpass_init"}, {BET_SUDO, CONFDB_DOMAIN_SUDO_PROVIDER, "sssm_%s_sudo_init"}, {BET_AUTOFS, CONFDB_DOMAIN_AUTOFS_PROVIDER, "sssm_%s_autofs_init"}, - {BET_SESSION, CONFDB_DOMAIN_SESSION_PROVIDER, "sssm_%s_session_init"}, + {BET_SELINUX, CONFDB_DOMAIN_SELINUX_PROVIDER, "sssm_%s_selinux_init"}, {BET_HOSTID, CONFDB_DOMAIN_HOSTID_PROVIDER, "sssm_%s_hostid_init"}, {BET_SUBDOMAINS, CONFDB_DOMAIN_SUBDOMAINS_PROVIDER, "sssm_%s_subdomains_init"}, {BET_MAX, NULL, NULL} @@ -858,8 +858,6 @@ static int be_pam_handler(DBusMessage *message, struct sbus_connection *conn) target = BET_CHPASS; break; case SSS_PAM_OPEN_SESSION: - target = BET_SESSION; - break; case SSS_PAM_SETCRED: case SSS_PAM_CLOSE_SESSION: pd->pam_status = PAM_SUCCESS; @@ -2170,19 +2168,19 @@ int be_process_init(TALLOC_CTX *mem_ctx, "from provider [%s].\n", ctx->bet_info[BET_AUTOFS].mod_name)); } - ret = load_backend_module(ctx, BET_SESSION, - &ctx->bet_info[BET_SESSION], + ret = load_backend_module(ctx, BET_SELINUX, + &ctx->bet_info[BET_SELINUX], ctx->bet_info[BET_ID].mod_name); if (ret != EOK) { if (ret != ENOENT) { DEBUG(SSSDBG_FATAL_FAILURE, ("fatal error initializing data providers\n")); return ret; } - DEBUG(SSSDBG_CRIT_FAILURE, ("No Session module provided for [%s] !!\n", + DEBUG(SSSDBG_CRIT_FAILURE, ("No selinux module provided for [%s] !!\n", be_domain)); } else { - DEBUG(SSSDBG_TRACE_ALL, ("Session backend target successfully loaded " - "from provider [%s].\n", ctx->bet_info[BET_SESSION].mod_name)); + DEBUG(SSSDBG_TRACE_ALL, ("selinux backend target successfully loaded " + "from provider [%s].\n", ctx->bet_info[BET_SELINUX].mod_name)); } ret = load_backend_module(ctx, BET_HOSTID, diff --git a/src/providers/dp_backend.h b/src/providers/dp_backend.h index 6e5c6e1a..4c703326 100644 --- a/src/providers/dp_backend.h +++ b/src/providers/dp_backend.h @@ -51,7 +51,7 @@ enum bet_type { BET_CHPASS, BET_SUDO, BET_AUTOFS, - BET_SESSION, + BET_SELINUX, BET_HOSTID, BET_SUBDOMAINS, BET_MAX diff --git a/src/providers/ipa/ipa_autofs.c b/src/providers/ipa/ipa_autofs.c index a050f070..de343212 100644 --- a/src/providers/ipa/ipa_autofs.c +++ b/src/providers/ipa/ipa_autofs.c @@ -29,7 +29,7 @@ #include "providers/ipa/ipa_auth.h" #include "providers/ipa/ipa_access.h" #include "providers/ipa/ipa_dyndns.h" -#include "providers/ipa/ipa_session.h" +#include "providers/ipa/ipa_selinux.h" struct bet_ops ipa_autofs_ops = { .handler = sdap_autofs_handler, diff --git a/src/providers/ipa/ipa_init.c b/src/providers/ipa/ipa_init.c index 4fb662c2..670e00fa 100644 --- a/src/providers/ipa/ipa_init.c +++ b/src/providers/ipa/ipa_init.c @@ -36,7 +36,7 @@ #include "providers/ipa/ipa_access.h" #include "providers/ipa/ipa_hostid.h" #include "providers/ipa/ipa_dyndns.h" -#include "providers/ipa/ipa_session.h" +#include "providers/ipa/ipa_selinux.h" #include "providers/ldap/sdap_access.h" #include "providers/ipa/ipa_subdomains.h" @@ -64,8 +64,8 @@ struct bet_ops ipa_access_ops = { .finalize = NULL }; -struct bet_ops ipa_session_ops = { - .handler = ipa_session_handler, +struct bet_ops ipa_selinux_ops = { + .handler = ipa_selinux_handler, .finalize = NULL }; @@ -386,38 +386,38 @@ done: return ret; } -int sssm_ipa_session_init(struct be_ctx *bectx, +int sssm_ipa_selinux_init(struct be_ctx *bectx, struct bet_ops **ops, void **pvt_data) { int ret; - struct ipa_session_ctx *session_ctx; + struct ipa_selinux_ctx *selinux_ctx; struct ipa_options *opts; - session_ctx = talloc_zero(bectx, struct ipa_session_ctx); - if (session_ctx == NULL) { + selinux_ctx = talloc_zero(bectx, struct ipa_selinux_ctx); + if (selinux_ctx == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_zero failed.\n")); return ENOMEM; } - ret = sssm_ipa_id_init(bectx, ops, (void **) &session_ctx->id_ctx); + ret = sssm_ipa_id_init(bectx, ops, (void **) &selinux_ctx->id_ctx); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("sssm_ipa_id_init failed.\n")); goto done; } - opts = session_ctx->id_ctx->ipa_options; + opts = selinux_ctx->id_ctx->ipa_options; - session_ctx->hbac_search_bases = opts->hbac_search_bases; - session_ctx->host_search_bases = opts->host_search_bases; - session_ctx->selinux_search_bases = opts->selinux_search_bases; + selinux_ctx->hbac_search_bases = opts->hbac_search_bases; + selinux_ctx->host_search_bases = opts->host_search_bases; + selinux_ctx->selinux_search_bases = opts->selinux_search_bases; - *ops = &ipa_session_ops; - *pvt_data = session_ctx; + *ops = &ipa_selinux_ops; + *pvt_data = selinux_ctx; done: if (ret != EOK) { - talloc_free(session_ctx); + talloc_free(selinux_ctx); } return ret; } diff --git a/src/providers/ipa/ipa_selinux.c b/src/providers/ipa/ipa_selinux.c new file mode 100644 index 00000000..03b7eb45 --- /dev/null +++ b/src/providers/ipa/ipa_selinux.c @@ -0,0 +1,625 @@ +/* + SSSD + + IPA Backend Module -- selinux loading + + Authors: + Jan Zeleny + + 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 "db/sysdb_selinux.h" +#include "util/sss_selinux.h" +#include "providers/ldap/sdap_async.h" +#include "providers/ipa/ipa_common.h" +#include "providers/ipa/ipa_config.h" +#include "providers/ipa/ipa_selinux.h" +#include "providers/ipa/ipa_hosts.h" +#include "providers/ipa/ipa_hbac_rules.h" +#include "providers/ipa/ipa_hbac_private.h" +#include "providers/ipa/ipa_selinux_common.h" +#include "providers/ipa/ipa_selinux_maps.h" + +struct ipa_get_selinux_state { + struct be_req *be_req; + struct pam_data *pd; + struct ipa_selinux_ctx *selinux_ctx; + struct sdap_id_op *op; + + const char *hostname; + struct sysdb_attrs *host; + struct sysdb_attrs *user; + + struct sysdb_attrs *defaults; + struct sysdb_attrs **selinuxmaps; + size_t nmaps; + + struct sysdb_attrs **possible_match; + size_t possible_matches; +}; + +static struct +tevent_req *ipa_get_selinux_send(struct be_req *breq, + struct pam_data *pd, + struct ipa_selinux_ctx *selinux_ctx); +static void ipa_selinux_handler_done(struct tevent_req *subreq); +static errno_t ipa_get_selinux_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + size_t *count, + struct sysdb_attrs ***maps, + char **default_user, + char **map_order); + +static void ipa_get_selinux_connect_done(struct tevent_req *subreq); +static void ipa_get_selinux_hosts_done(struct tevent_req *subreq); +static void ipa_get_config_step(struct tevent_req *req); +static void ipa_get_selinux_config_done(struct tevent_req *subreq); +static void ipa_get_selinux_maps_done(struct tevent_req *subreq); +static void ipa_get_selinux_hbac_done(struct tevent_req *subreq); + +void ipa_selinux_handler(struct be_req *be_req) +{ + struct ipa_selinux_ctx *selinux_ctx; + struct tevent_req *req; + struct pam_data *pd; + + pd = talloc_get_type(be_req->req_data, struct pam_data); + + selinux_ctx = talloc_get_type( + be_req->be_ctx->bet_info[BET_SELINUX].pvt_bet_data, + struct ipa_selinux_ctx); + + + req = ipa_get_selinux_send(be_req, pd, selinux_ctx); + if (req == NULL) { + goto fail; + } + + tevent_req_set_callback(req, ipa_selinux_handler_done, be_req); + + return; + +fail: + be_req->fn(be_req, DP_ERR_FATAL, PAM_SYSTEM_ERR, NULL); +} + +static void ipa_selinux_handler_done(struct tevent_req *req) +{ + struct be_req *breq = tevent_req_callback_data(req, struct be_req); + struct sysdb_ctx *sysdb = breq->be_ctx->sysdb; + errno_t ret, sret; + size_t map_count = 0; + struct sysdb_attrs **maps = NULL; + bool in_transaction = false; + char *default_user = NULL; + struct pam_data *pd = talloc_get_type(breq->req_data, struct pam_data); + char *map_order = NULL; + + ret = ipa_get_selinux_recv(req, breq, &map_count, &maps, + &default_user, &map_order); + if (ret != EOK) { + goto fail; + } + + ret = sysdb_transaction_start(sysdb); + if (ret != EOK) goto fail; + in_transaction = true; + + ret = sysdb_delete_usermaps(breq->sysdb); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + ("Cannot delete existing maps from sysdb\n")); + goto fail; + } + + if (default_user != NULL && map_order != NULL) { + ret = sysdb_store_selinux_config(sysdb, default_user, map_order); + if (ret != EOK) { + goto fail; + } + } + + if (map_count > 0 && maps != NULL) { + ret = ipa_save_user_maps(sysdb, map_count, maps); + if (ret != EOK) { + goto fail; + } + } + + ret = sysdb_transaction_commit(sysdb); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("Could not commit transaction\n")); + goto fail; + } + + /* Just in case more code will follow after this place in the future */ + in_transaction = false; + + + pd->pam_status = PAM_SUCCESS; + breq->fn(breq, DP_ERR_OK, EOK, "Success"); + return; + +fail: + if (in_transaction) { + sret = sysdb_transaction_cancel(sysdb); + if (sret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("Could not cancel transaction\n")); + } + } + if (ret == EAGAIN) { + breq->fn(breq, DP_ERR_OFFLINE, EAGAIN, "Offline"); + } else { + breq->fn(breq, DP_ERR_FATAL, ret, NULL); + } +} + +static struct tevent_req *ipa_get_selinux_send(struct be_req *breq, + struct pam_data *pd, + struct ipa_selinux_ctx *selinux_ctx) +{ + struct tevent_req *req; + struct tevent_req *subreq; + struct be_ctx *bctx = breq->be_ctx; + struct ipa_get_selinux_state *state; + bool offline; + int ret = EOK; + + DEBUG(SSSDBG_TRACE_FUNC, ("Retrieving SELinux user mapping\n")); + req = tevent_req_create(breq, &state, struct ipa_get_selinux_state); + if (req == NULL) { + return NULL; + } + + state->be_req = breq; + state->pd = pd; + state->selinux_ctx = selinux_ctx; + + offline = be_is_offline(bctx); + DEBUG(SSSDBG_TRACE_INTERNAL, ("Connection status is [%s].\n", + offline ? "offline" : "online")); + + if (!offline) { + state->op = sdap_id_op_create(state, selinux_ctx->id_ctx->sdap_id_ctx->conn_cache); + if (!state->op) { + DEBUG(SSSDBG_OP_FAILURE, ("sdap_id_op_create failed\n")); + ret = ENOMEM; + goto immediate; + } + + subreq = sdap_id_op_connect_send(state->op, state, &ret); + if (!subreq) { + DEBUG(SSSDBG_CRIT_FAILURE, ("sdap_id_op_connect_send failed: " + "%d(%s).\n", ret, strerror(ret))); + talloc_zfree(state->op); + goto immediate; + } + + tevent_req_set_callback(subreq, ipa_get_selinux_connect_done, req); + } else { + ret = EAGAIN; + goto immediate; + } + + return req; + +immediate: + if (ret == EOK) { + tevent_req_done(req); + } else { + tevent_req_error(req, ret); + } + tevent_req_post(req, bctx->ev); + return req; +} + +static void ipa_get_selinux_connect_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct ipa_get_selinux_state *state = tevent_req_data(req, + struct ipa_get_selinux_state); + int dp_error = DP_ERR_FATAL; + int ret; + struct ipa_id_ctx *id_ctx = state->selinux_ctx->id_ctx; + struct be_ctx *bctx = state->be_req->be_ctx; + + ret = sdap_id_op_connect_recv(subreq, &dp_error); + talloc_zfree(subreq); + + if (dp_error == DP_ERR_OFFLINE) { + talloc_zfree(state->op); + ret = EAGAIN; + } + + if (ret != EOK) { + goto fail; + } + + state->hostname = dp_opt_get_string(state->selinux_ctx->id_ctx->ipa_options->basic, + IPA_HOSTNAME); + + /* FIXME: detect if HBAC is configured + * - if yes, we can skip host retrieval and get it directly from sysdb + * and shortcut to ipa_get_config_step() + */ + subreq = ipa_host_info_send(state, bctx->ev, bctx->sysdb, + sdap_id_op_handle(state->op), + id_ctx->sdap_id_ctx->opts, + state->hostname, + id_ctx->ipa_options->host_map, + NULL, + state->selinux_ctx->host_search_bases); + if (subreq == NULL) { + ret = ENOMEM; + goto fail; + } + + tevent_req_set_callback(subreq, ipa_get_selinux_hosts_done, req); + + return; + +fail: + tevent_req_error(req, ret); +} + +static void ipa_get_selinux_hosts_done(struct tevent_req *subreq) +{ + errno_t ret; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct ipa_get_selinux_state *state = tevent_req_data(req, + struct ipa_get_selinux_state); + struct be_ctx *bctx = state->be_req->be_ctx; + size_t host_count, hostgroup_count; + struct sysdb_attrs **hostgroups; + struct sysdb_attrs **host; + + ret = ipa_host_info_recv(subreq, state, &host_count, &host, + &hostgroup_count, &hostgroups); + talloc_free(subreq); + if (ret != EOK) { + goto done; + } + state->host = host[0]; + + ret = sss_selinux_extract_user(state, bctx->sysdb, + state->pd->user, &state->user); + if (ret != EOK) { + goto done; + } + + return ipa_get_config_step(req); + +done: + if (ret != EOK) { + tevent_req_error(req, ret); + } +} + +static void ipa_get_config_step(struct tevent_req *req) +{ + const char *domain; + struct tevent_req *subreq; + struct ipa_get_selinux_state *state = tevent_req_data(req, + struct ipa_get_selinux_state); + struct be_ctx *bctx = state->be_req->be_ctx; + struct ipa_id_ctx *id_ctx = state->selinux_ctx->id_ctx; + + domain = dp_opt_get_string(state->selinux_ctx->id_ctx->ipa_options->basic, + IPA_KRB5_REALM); + subreq = ipa_get_config_send(state, bctx->ev, + sdap_id_op_handle(state->op), + id_ctx->sdap_id_ctx->opts, + domain, NULL); + if (subreq == NULL) { + tevent_req_error(req, ENOMEM); + } + tevent_req_set_callback(subreq, ipa_get_selinux_config_done, req); +} + +static void ipa_get_selinux_config_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct ipa_get_selinux_state *state = tevent_req_data(req, + struct ipa_get_selinux_state); + struct be_ctx *bctx = state->be_req->be_ctx; + struct sdap_id_ctx *id_ctx = state->selinux_ctx->id_ctx->sdap_id_ctx; + errno_t ret; + + ret = ipa_get_config_recv(subreq, state, &state->defaults); + talloc_free(subreq); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("Could not get IPA config\n")); + goto done; + } + + subreq = ipa_selinux_get_maps_send(state, bctx->ev, bctx->sysdb, + sdap_id_op_handle(state->op), + id_ctx->opts, + state->selinux_ctx->id_ctx->ipa_options, + state->selinux_ctx->selinux_search_bases); + if (!subreq) { + ret = ENOMEM; + goto done; + } + tevent_req_set_callback(subreq, ipa_get_selinux_maps_done, req); + return; + +done: + if (ret != EOK) { + tevent_req_error(req, ret); + } else { + tevent_req_done(req); + } +} + +static void ipa_get_selinux_maps_done(struct tevent_req *subreq) +{ + struct tevent_req *req; + struct ipa_get_selinux_state *state; + + struct be_ctx *bctx; + struct ipa_id_ctx *id_ctx; + + const char *tmp_str; + uint32_t priority = 0; + errno_t ret; + int i; + + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct ipa_get_selinux_state); + bctx = state->be_req->be_ctx; + id_ctx = state->selinux_ctx->id_ctx; + + ret = ipa_selinux_get_maps_recv(subreq, state, + &state->nmaps, &state->selinuxmaps); + talloc_free(subreq); + if (ret != EOK) { + if (ret == ENOENT) { + /* This is returned if no SELinux mapping + * rules were found. In that case no error + * occurred, but we don't want any more processing.*/ + ret = EOK; + } + goto done; + } + + DEBUG(SSSDBG_TRACE_FUNC, + ("Found %d SELinux user maps\n", state->nmaps)); + state->possible_match = talloc_zero_array(state, struct sysdb_attrs *, + state->nmaps + 1); + if (state->possible_match == NULL) { + ret = ENOMEM; + goto done; + } + + for (i = 0; i < state->nmaps; i++) { + if (sss_selinux_match(state->selinuxmaps[i], state->user, + state->host, &priority)) { + priority &= ~(SELINUX_PRIORITY_USER_NAME | + SELINUX_PRIORITY_USER_GROUP | + SELINUX_PRIORITY_USER_CAT); + ret = sysdb_attrs_add_uint32(state->selinuxmaps[i], + SYSDB_SELINUX_HOST_PRIORITY, + priority); + if (ret != EOK) { + goto done; + } + continue; + } + + ret = sysdb_attrs_get_string(state->selinuxmaps[i], + SYSDB_SELINUX_SEEALSO, &tmp_str); + if (ret == ENOENT) { + continue; + } + + state->possible_match[state->possible_matches] = state->selinuxmaps[i]; + state->possible_matches++; + } + + if (state->possible_matches) { + /* FIXME: detect if HBAC is configured + * - if yes, we can skip HBAC retrieval and get it directly from sysdb + */ + DEBUG(SSSDBG_TRACE_FUNC, ("%d SELinux maps referenced an HBAC rule. " + "Need to refresh HBAC rules\n", state->possible_matches)); + subreq = ipa_hbac_rule_info_send(state, false, bctx->ev, + sdap_id_op_handle(state->op), + id_ctx->sdap_id_ctx->opts, + state->selinux_ctx->hbac_search_bases, + state->host); + if (subreq == NULL) { + ret = ENOMEM; + goto done; + } + + tevent_req_set_callback(subreq, ipa_get_selinux_hbac_done, req); + return; + } + + ret = EOK; +done: + if (ret == EOK) { + tevent_req_done(req); + } else { + tevent_req_error(req, ret); + } +} + +static void ipa_get_selinux_hbac_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct ipa_get_selinux_state *state = tevent_req_data(req, + struct ipa_get_selinux_state); + struct sysdb_attrs **rules; + struct sysdb_attrs *usermap; + struct ldb_message_element *el; + const char *hbac_dn; + const char *seealso_dn; + size_t rule_count; + uint32_t priority = 0; + errno_t ret; + int i, j; + + ret = ipa_hbac_rule_info_recv(subreq, state, &rule_count, + &rules); + DEBUG(SSSDBG_TRACE_INTERNAL, + ("Received %d HBAC rules\n", rule_count)); + talloc_free(subreq); + if (ret != EOK) { + goto done; + } + + for (i = 0; i < rule_count; i++) { + ret = sysdb_attrs_get_string(rules[i], SYSDB_ORIG_DN, &hbac_dn); + if (ret != EOK) { + goto done; + } + + /* We need to do this translation for further processing. We have to + * do it manually because no map was used to retrieve HBAC rules. + */ + ret = sysdb_attrs_get_el(rules[i], IPA_MEMBER_HOST, &el); + if (ret != EOK) goto done; + el->name = SYSDB_ORIG_MEMBER_HOST; + + ret = sysdb_attrs_get_el(rules[i], IPA_MEMBER_USER, &el); + if (ret != EOK) goto done; + el->name = SYSDB_ORIG_MEMBER_USER; + + DEBUG(SSSDBG_TRACE_ALL, + ("Matching HBAC rule %s with SELinux mappings\n", hbac_dn)); + + if (!sss_selinux_match(rules[i], state->user, state->host, &priority)) { + DEBUG(SSSDBG_TRACE_ALL, ("Rule did not match\n")); + continue; + } + + + /* HBAC rule matched, find if it is in the "possible" list */ + for (j = 0; j < state->possible_matches; j++) { + usermap = state->possible_match[j]; + if (usermap == NULL) { + continue; + } + + ret = sysdb_attrs_get_string(usermap, SYSDB_SELINUX_SEEALSO, &seealso_dn); + if (ret != EOK) { + goto done; + } + + if (strcasecmp(hbac_dn, seealso_dn) == 0) { + DEBUG(SSSDBG_TRACE_FUNC, ("HBAC rule [%s] matched, copying its" + "attributes to SELinux user map [%s]\n", + hbac_dn, seealso_dn)); + priority &= ~(SELINUX_PRIORITY_USER_NAME | + SELINUX_PRIORITY_USER_GROUP | + SELINUX_PRIORITY_USER_CAT); + ret = sysdb_attrs_add_uint32(usermap, + SYSDB_SELINUX_HOST_PRIORITY, + priority); + if (ret != EOK) { + goto done; + } + + ret = sysdb_attrs_copy_values(rules[i], usermap, SYSDB_ORIG_MEMBER_USER); + if (ret != EOK) { + goto done; + } + + ret = sysdb_attrs_copy_values(rules[i], usermap, SYSDB_USER_CATEGORY); + if (ret != EOK) { + goto done; + } + + /* Just to boost the following lookup */ + state->possible_match[j] = NULL; + } + } + } + + /* Now we can dispose all possible rules, since they aren't possible any more */ + talloc_zfree(state->possible_match); + + ret = EOK; +done: + if (ret != EOK) { + tevent_req_error(req, ret); + } else { + tevent_req_done(req); + } +} + +static errno_t +ipa_get_selinux_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + size_t *count, + struct sysdb_attrs ***maps, + char **default_user, + char **map_order) +{ + struct ipa_get_selinux_state *state = + tevent_req_data(req, struct ipa_get_selinux_state); + const char *tmp_str; + errno_t ret; + + TEVENT_REQ_RETURN_ON_ERROR(req); + + if (state->defaults != NULL) { + ret = sysdb_attrs_get_string(state->defaults, IPA_CONFIG_SELINUX_DEFAULT_MAP, + &tmp_str); + if (ret != EOK) { + return ret; + } + + *default_user = talloc_strdup(mem_ctx, tmp_str); + if (*default_user == NULL) { + return ENOMEM; + } + + ret = sysdb_attrs_get_string(state->defaults, IPA_CONFIG_SELINUX_MAP_ORDER, + &tmp_str); + if (ret != EOK) { + return ret; + } + + *map_order = talloc_strdup(mem_ctx, tmp_str); + if (*map_order == NULL) { + talloc_zfree(*default_user); + return ENOMEM; + } + } else { + *map_order = NULL; + *default_user = NULL; + } + + if (state->selinuxmaps != NULL) { + *count = state->nmaps; + *maps = talloc_steal(mem_ctx, state->selinuxmaps); + } else { + *count = 0; + *maps = NULL; + } + + return EOK; +} diff --git a/src/providers/ipa/ipa_selinux.h b/src/providers/ipa/ipa_selinux.h new file mode 100644 index 00000000..60c22110 --- /dev/null +++ b/src/providers/ipa/ipa_selinux.h @@ -0,0 +1,40 @@ +/* + SSSD + + IPA Backend Module -- selinux loading + + Authors: + Jan Zeleny + + Copyright (C) 2011 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 . +*/ + +#ifndef _IPA_SELINUX_H_ +#define _IPA_SELINUX_H_ + +#include "providers/ldap/ldap_common.h" + +struct ipa_selinux_ctx { + struct ipa_id_ctx *id_ctx; + + struct sdap_search_base **selinux_search_bases; + struct sdap_search_base **host_search_bases; + struct sdap_search_base **hbac_search_bases; +}; + +void ipa_selinux_handler(struct be_req *be_req); + +#endif diff --git a/src/providers/ipa/ipa_session.c b/src/providers/ipa/ipa_session.c deleted file mode 100644 index 9032a8d1..00000000 --- a/src/providers/ipa/ipa_session.c +++ /dev/null @@ -1,625 +0,0 @@ -/* - SSSD - - IPA Backend Module -- session loading - - Authors: - Jan Zeleny - - 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 "db/sysdb_selinux.h" -#include "util/sss_selinux.h" -#include "providers/ldap/sdap_async.h" -#include "providers/ipa/ipa_common.h" -#include "providers/ipa/ipa_config.h" -#include "providers/ipa/ipa_session.h" -#include "providers/ipa/ipa_hosts.h" -#include "providers/ipa/ipa_hbac_rules.h" -#include "providers/ipa/ipa_hbac_private.h" -#include "providers/ipa/ipa_selinux_common.h" -#include "providers/ipa/ipa_selinux_maps.h" - -struct ipa_get_selinux_state { - struct be_req *be_req; - struct pam_data *pd; - struct ipa_session_ctx *session_ctx; - struct sdap_id_op *op; - - const char *hostname; - struct sysdb_attrs *host; - struct sysdb_attrs *user; - - struct sysdb_attrs *defaults; - struct sysdb_attrs **selinuxmaps; - size_t nmaps; - - struct sysdb_attrs **possible_match; - size_t possible_matches; -}; - -static struct -tevent_req *ipa_get_selinux_send(struct be_req *breq, - struct pam_data *pd, - struct ipa_session_ctx *session_ctx); -static void ipa_session_handler_done(struct tevent_req *subreq); -static errno_t ipa_get_selinux_recv(struct tevent_req *req, - TALLOC_CTX *mem_ctx, - size_t *count, - struct sysdb_attrs ***maps, - char **default_user, - char **map_order); - -static void ipa_get_selinux_connect_done(struct tevent_req *subreq); -static void ipa_get_selinux_hosts_done(struct tevent_req *subreq); -static void ipa_get_config_step(struct tevent_req *req); -static void ipa_get_selinux_config_done(struct tevent_req *subreq); -static void ipa_get_selinux_maps_done(struct tevent_req *subreq); -static void ipa_get_selinux_hbac_done(struct tevent_req *subreq); - -void ipa_session_handler(struct be_req *be_req) -{ - struct ipa_session_ctx *session_ctx; - struct tevent_req *req; - struct pam_data *pd; - - pd = talloc_get_type(be_req->req_data, struct pam_data); - - session_ctx = talloc_get_type( - be_req->be_ctx->bet_info[BET_SESSION].pvt_bet_data, - struct ipa_session_ctx); - - - req = ipa_get_selinux_send(be_req, pd, session_ctx); - if (req == NULL) { - goto fail; - } - - tevent_req_set_callback(req, ipa_session_handler_done, be_req); - - return; - -fail: - be_req->fn(be_req, DP_ERR_FATAL, PAM_SYSTEM_ERR, NULL); -} - -static void ipa_session_handler_done(struct tevent_req *req) -{ - struct be_req *breq = tevent_req_callback_data(req, struct be_req); - struct sysdb_ctx *sysdb = breq->be_ctx->sysdb; - errno_t ret, sret; - size_t map_count = 0; - struct sysdb_attrs **maps = NULL; - bool in_transaction = false; - char *default_user = NULL; - struct pam_data *pd = talloc_get_type(breq->req_data, struct pam_data); - char *map_order = NULL; - - ret = ipa_get_selinux_recv(req, breq, &map_count, &maps, - &default_user, &map_order); - if (ret != EOK) { - goto fail; - } - - ret = sysdb_transaction_start(sysdb); - if (ret != EOK) goto fail; - in_transaction = true; - - ret = sysdb_delete_usermaps(breq->sysdb); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, - ("Cannot delete existing maps from sysdb\n")); - goto fail; - } - - if (default_user != NULL && map_order != NULL) { - ret = sysdb_store_selinux_config(sysdb, default_user, map_order); - if (ret != EOK) { - goto fail; - } - } - - if (map_count > 0 && maps != NULL) { - ret = ipa_save_user_maps(sysdb, map_count, maps); - if (ret != EOK) { - goto fail; - } - } - - ret = sysdb_transaction_commit(sysdb); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, ("Could not commit transaction\n")); - goto fail; - } - - /* Just in case more code will follow after this place in the future */ - in_transaction = false; - - - pd->pam_status = PAM_SUCCESS; - breq->fn(breq, DP_ERR_OK, EOK, "Success"); - return; - -fail: - if (in_transaction) { - sret = sysdb_transaction_cancel(sysdb); - if (sret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, ("Could not cancel transaction\n")); - } - } - if (ret == EAGAIN) { - breq->fn(breq, DP_ERR_OFFLINE, EAGAIN, "Offline"); - } else { - breq->fn(breq, DP_ERR_FATAL, ret, NULL); - } -} - -static struct tevent_req *ipa_get_selinux_send(struct be_req *breq, - struct pam_data *pd, - struct ipa_session_ctx *session_ctx) -{ - struct tevent_req *req; - struct tevent_req *subreq; - struct be_ctx *bctx = breq->be_ctx; - struct ipa_get_selinux_state *state; - bool offline; - int ret = EOK; - - DEBUG(SSSDBG_TRACE_FUNC, ("Retrieving SELinux user mapping\n")); - req = tevent_req_create(breq, &state, struct ipa_get_selinux_state); - if (req == NULL) { - return NULL; - } - - state->be_req = breq; - state->pd = pd; - state->session_ctx = session_ctx; - - offline = be_is_offline(bctx); - DEBUG(SSSDBG_TRACE_INTERNAL, ("Connection status is [%s].\n", - offline ? "offline" : "online")); - - if (!offline) { - state->op = sdap_id_op_create(state, session_ctx->id_ctx->sdap_id_ctx->conn_cache); - if (!state->op) { - DEBUG(SSSDBG_OP_FAILURE, ("sdap_id_op_create failed\n")); - ret = ENOMEM; - goto immediate; - } - - subreq = sdap_id_op_connect_send(state->op, state, &ret); - if (!subreq) { - DEBUG(SSSDBG_CRIT_FAILURE, ("sdap_id_op_connect_send failed: " - "%d(%s).\n", ret, strerror(ret))); - talloc_zfree(state->op); - goto immediate; - } - - tevent_req_set_callback(subreq, ipa_get_selinux_connect_done, req); - } else { - ret = EAGAIN; - goto immediate; - } - - return req; - -immediate: - if (ret == EOK) { - tevent_req_done(req); - } else { - tevent_req_error(req, ret); - } - tevent_req_post(req, bctx->ev); - return req; -} - -static void ipa_get_selinux_connect_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct ipa_get_selinux_state *state = tevent_req_data(req, - struct ipa_get_selinux_state); - int dp_error = DP_ERR_FATAL; - int ret; - struct ipa_id_ctx *id_ctx = state->session_ctx->id_ctx; - struct be_ctx *bctx = state->be_req->be_ctx; - - ret = sdap_id_op_connect_recv(subreq, &dp_error); - talloc_zfree(subreq); - - if (dp_error == DP_ERR_OFFLINE) { - talloc_zfree(state->op); - ret = EAGAIN; - } - - if (ret != EOK) { - goto fail; - } - - state->hostname = dp_opt_get_string(state->session_ctx->id_ctx->ipa_options->basic, - IPA_HOSTNAME); - - /* FIXME: detect if HBAC is configured - * - if yes, we can skip host retrieval and get it directly from sysdb - * and shortcut to ipa_get_config_step() - */ - subreq = ipa_host_info_send(state, bctx->ev, bctx->sysdb, - sdap_id_op_handle(state->op), - id_ctx->sdap_id_ctx->opts, - state->hostname, - id_ctx->ipa_options->host_map, - NULL, - state->session_ctx->host_search_bases); - if (subreq == NULL) { - ret = ENOMEM; - goto fail; - } - - tevent_req_set_callback(subreq, ipa_get_selinux_hosts_done, req); - - return; - -fail: - tevent_req_error(req, ret); -} - -static void ipa_get_selinux_hosts_done(struct tevent_req *subreq) -{ - errno_t ret; - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct ipa_get_selinux_state *state = tevent_req_data(req, - struct ipa_get_selinux_state); - struct be_ctx *bctx = state->be_req->be_ctx; - size_t host_count, hostgroup_count; - struct sysdb_attrs **hostgroups; - struct sysdb_attrs **host; - - ret = ipa_host_info_recv(subreq, state, &host_count, &host, - &hostgroup_count, &hostgroups); - talloc_free(subreq); - if (ret != EOK) { - goto done; - } - state->host = host[0]; - - ret = sss_selinux_extract_user(state, bctx->sysdb, - state->pd->user, &state->user); - if (ret != EOK) { - goto done; - } - - return ipa_get_config_step(req); - -done: - if (ret != EOK) { - tevent_req_error(req, ret); - } -} - -static void ipa_get_config_step(struct tevent_req *req) -{ - const char *domain; - struct tevent_req *subreq; - struct ipa_get_selinux_state *state = tevent_req_data(req, - struct ipa_get_selinux_state); - struct be_ctx *bctx = state->be_req->be_ctx; - struct ipa_id_ctx *id_ctx = state->session_ctx->id_ctx; - - domain = dp_opt_get_string(state->session_ctx->id_ctx->ipa_options->basic, - IPA_KRB5_REALM); - subreq = ipa_get_config_send(state, bctx->ev, - sdap_id_op_handle(state->op), - id_ctx->sdap_id_ctx->opts, - domain, NULL); - if (subreq == NULL) { - tevent_req_error(req, ENOMEM); - } - tevent_req_set_callback(subreq, ipa_get_selinux_config_done, req); -} - -static void ipa_get_selinux_config_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct ipa_get_selinux_state *state = tevent_req_data(req, - struct ipa_get_selinux_state); - struct be_ctx *bctx = state->be_req->be_ctx; - struct sdap_id_ctx *id_ctx = state->session_ctx->id_ctx->sdap_id_ctx; - errno_t ret; - - ret = ipa_get_config_recv(subreq, state, &state->defaults); - talloc_free(subreq); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, ("Could not get IPA config\n")); - goto done; - } - - subreq = ipa_selinux_get_maps_send(state, bctx->ev, bctx->sysdb, - sdap_id_op_handle(state->op), - id_ctx->opts, - state->session_ctx->id_ctx->ipa_options, - state->session_ctx->selinux_search_bases); - if (!subreq) { - ret = ENOMEM; - goto done; - } - tevent_req_set_callback(subreq, ipa_get_selinux_maps_done, req); - return; - -done: - if (ret != EOK) { - tevent_req_error(req, ret); - } else { - tevent_req_done(req); - } -} - -static void ipa_get_selinux_maps_done(struct tevent_req *subreq) -{ - struct tevent_req *req; - struct ipa_get_selinux_state *state; - - struct be_ctx *bctx; - struct ipa_id_ctx *id_ctx; - - const char *tmp_str; - uint32_t priority = 0; - errno_t ret; - int i; - - req = tevent_req_callback_data(subreq, struct tevent_req); - state = tevent_req_data(req, struct ipa_get_selinux_state); - bctx = state->be_req->be_ctx; - id_ctx = state->session_ctx->id_ctx; - - ret = ipa_selinux_get_maps_recv(subreq, state, - &state->nmaps, &state->selinuxmaps); - talloc_free(subreq); - if (ret != EOK) { - if (ret == ENOENT) { - /* This is returned if no SELinux mapping - * rules were found. In that case no error - * occurred, but we don't want any more processing.*/ - ret = EOK; - } - goto done; - } - - DEBUG(SSSDBG_TRACE_FUNC, - ("Found %d SELinux user maps\n", state->nmaps)); - state->possible_match = talloc_zero_array(state, struct sysdb_attrs *, - state->nmaps + 1); - if (state->possible_match == NULL) { - ret = ENOMEM; - goto done; - } - - for (i = 0; i < state->nmaps; i++) { - if (sss_selinux_match(state->selinuxmaps[i], state->user, - state->host, &priority)) { - priority &= ~(SELINUX_PRIORITY_USER_NAME | - SELINUX_PRIORITY_USER_GROUP | - SELINUX_PRIORITY_USER_CAT); - ret = sysdb_attrs_add_uint32(state->selinuxmaps[i], - SYSDB_SELINUX_HOST_PRIORITY, - priority); - if (ret != EOK) { - goto done; - } - continue; - } - - ret = sysdb_attrs_get_string(state->selinuxmaps[i], - SYSDB_SELINUX_SEEALSO, &tmp_str); - if (ret == ENOENT) { - continue; - } - - state->possible_match[state->possible_matches] = state->selinuxmaps[i]; - state->possible_matches++; - } - - if (state->possible_matches) { - /* FIXME: detect if HBAC is configured - * - if yes, we can skip HBAC retrieval and get it directly from sysdb - */ - DEBUG(SSSDBG_TRACE_FUNC, ("%d SELinux maps referenced an HBAC rule. " - "Need to refresh HBAC rules\n", state->possible_matches)); - subreq = ipa_hbac_rule_info_send(state, false, bctx->ev, - sdap_id_op_handle(state->op), - id_ctx->sdap_id_ctx->opts, - state->session_ctx->hbac_search_bases, - state->host); - if (subreq == NULL) { - ret = ENOMEM; - goto done; - } - - tevent_req_set_callback(subreq, ipa_get_selinux_hbac_done, req); - return; - } - - ret = EOK; -done: - if (ret == EOK) { - tevent_req_done(req); - } else { - tevent_req_error(req, ret); - } -} - -static void ipa_get_selinux_hbac_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct ipa_get_selinux_state *state = tevent_req_data(req, - struct ipa_get_selinux_state); - struct sysdb_attrs **rules; - struct sysdb_attrs *usermap; - struct ldb_message_element *el; - const char *hbac_dn; - const char *seealso_dn; - size_t rule_count; - uint32_t priority = 0; - errno_t ret; - int i, j; - - ret = ipa_hbac_rule_info_recv(subreq, state, &rule_count, - &rules); - DEBUG(SSSDBG_TRACE_INTERNAL, - ("Received %d HBAC rules\n", rule_count)); - talloc_free(subreq); - if (ret != EOK) { - goto done; - } - - for (i = 0; i < rule_count; i++) { - ret = sysdb_attrs_get_string(rules[i], SYSDB_ORIG_DN, &hbac_dn); - if (ret != EOK) { - goto done; - } - - /* We need to do this translation for further processing. We have to - * do it manually because no map was used to retrieve HBAC rules. - */ - ret = sysdb_attrs_get_el(rules[i], IPA_MEMBER_HOST, &el); - if (ret != EOK) goto done; - el->name = SYSDB_ORIG_MEMBER_HOST; - - ret = sysdb_attrs_get_el(rules[i], IPA_MEMBER_USER, &el); - if (ret != EOK) goto done; - el->name = SYSDB_ORIG_MEMBER_USER; - - DEBUG(SSSDBG_TRACE_ALL, - ("Matching HBAC rule %s with SELinux mappings\n", hbac_dn)); - - if (!sss_selinux_match(rules[i], state->user, state->host, &priority)) { - DEBUG(SSSDBG_TRACE_ALL, ("Rule did not match\n")); - continue; - } - - - /* HBAC rule matched, find if it is in the "possible" list */ - for (j = 0; j < state->possible_matches; j++) { - usermap = state->possible_match[j]; - if (usermap == NULL) { - continue; - } - - ret = sysdb_attrs_get_string(usermap, SYSDB_SELINUX_SEEALSO, &seealso_dn); - if (ret != EOK) { - goto done; - } - - if (strcasecmp(hbac_dn, seealso_dn) == 0) { - DEBUG(SSSDBG_TRACE_FUNC, ("HBAC rule [%s] matched, copying its" - "attributes to SELinux user map [%s]\n", - hbac_dn, seealso_dn)); - priority &= ~(SELINUX_PRIORITY_USER_NAME | - SELINUX_PRIORITY_USER_GROUP | - SELINUX_PRIORITY_USER_CAT); - ret = sysdb_attrs_add_uint32(usermap, - SYSDB_SELINUX_HOST_PRIORITY, - priority); - if (ret != EOK) { - goto done; - } - - ret = sysdb_attrs_copy_values(rules[i], usermap, SYSDB_ORIG_MEMBER_USER); - if (ret != EOK) { - goto done; - } - - ret = sysdb_attrs_copy_values(rules[i], usermap, SYSDB_USER_CATEGORY); - if (ret != EOK) { - goto done; - } - - /* Just to boost the following lookup */ - state->possible_match[j] = NULL; - } - } - } - - /* Now we can dispose all possible rules, since they aren't possible any more */ - talloc_zfree(state->possible_match); - - ret = EOK; -done: - if (ret != EOK) { - tevent_req_error(req, ret); - } else { - tevent_req_done(req); - } -} - -static errno_t -ipa_get_selinux_recv(struct tevent_req *req, - TALLOC_CTX *mem_ctx, - size_t *count, - struct sysdb_attrs ***maps, - char **default_user, - char **map_order) -{ - struct ipa_get_selinux_state *state = - tevent_req_data(req, struct ipa_get_selinux_state); - const char *tmp_str; - errno_t ret; - - TEVENT_REQ_RETURN_ON_ERROR(req); - - if (state->defaults != NULL) { - ret = sysdb_attrs_get_string(state->defaults, IPA_CONFIG_SELINUX_DEFAULT_MAP, - &tmp_str); - if (ret != EOK) { - return ret; - } - - *default_user = talloc_strdup(mem_ctx, tmp_str); - if (*default_user == NULL) { - return ENOMEM; - } - - ret = sysdb_attrs_get_string(state->defaults, IPA_CONFIG_SELINUX_MAP_ORDER, - &tmp_str); - if (ret != EOK) { - return ret; - } - - *map_order = talloc_strdup(mem_ctx, tmp_str); - if (*map_order == NULL) { - talloc_zfree(*default_user); - return ENOMEM; - } - } else { - *map_order = NULL; - *default_user = NULL; - } - - if (state->selinuxmaps != NULL) { - *count = state->nmaps; - *maps = talloc_steal(mem_ctx, state->selinuxmaps); - } else { - *count = 0; - *maps = NULL; - } - - return EOK; -} diff --git a/src/providers/ipa/ipa_session.h b/src/providers/ipa/ipa_session.h deleted file mode 100644 index e185799f..00000000 --- a/src/providers/ipa/ipa_session.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - SSSD - - IPA Backend Module -- session loading - - Authors: - Jan Zeleny - - Copyright (C) 2011 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 . -*/ - -#ifndef _IPA_SESSION_H_ -#define _IPA_SESSION_H_ - -#include "providers/ldap/ldap_common.h" - -struct ipa_session_ctx { - struct ipa_id_ctx *id_ctx; - - struct sdap_search_base **selinux_search_bases; - struct sdap_search_base **host_search_bases; - struct sdap_search_base **hbac_search_bases; -}; - -void ipa_session_handler(struct be_req *be_req); - -#endif -- cgit