diff options
author | Jakub Hrozek <jhrozek@redhat.com> | 2014-10-20 23:16:40 +0200 |
---|---|---|
committer | Jakub Hrozek <jhrozek@redhat.com> | 2014-11-05 19:55:09 +0100 |
commit | f3a25949de81f80c136bb073e4a8f504b080c20c (patch) | |
tree | 69523a939b65b371d7a95e16d1f69e237c77f048 /src | |
parent | 77b13371c87702aee3f858f6b2b73826cf5a01bd (diff) | |
download | sssd-f3a25949de81f80c136bb073e4a8f504b080c20c.tar.gz sssd-f3a25949de81f80c136bb073e4a8f504b080c20c.tar.xz sssd-f3a25949de81f80c136bb073e4a8f504b080c20c.zip |
IPA: Move setting the SELinux context to a child process
In order for the sssd_be process to run as unprivileged user, we need to
move the semanage processing to a process that runs as the root user
using setuid privileges.
Reviewed-by: Michal Židek <mzidek@redhat.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/providers/ipa/ipa_selinux.c | 409 | ||||
-rw-r--r-- | src/providers/ipa/selinux_child.c | 272 | ||||
-rw-r--r-- | src/util/util_errors.c | 1 | ||||
-rw-r--r-- | src/util/util_errors.h | 1 |
4 files changed, 663 insertions, 20 deletions
diff --git a/src/providers/ipa/ipa_selinux.c b/src/providers/ipa/ipa_selinux.c index 7db1c6ed2..b392d82a6 100644 --- a/src/providers/ipa/ipa_selinux.c +++ b/src/providers/ipa/ipa_selinux.c @@ -24,6 +24,7 @@ #include <security/pam_modules.h> #include "db/sysdb_selinux.h" +#include "util/child_common.h" #include "util/sss_selinux.h" #include "providers/ldap/sdap_async.h" #include "providers/ipa/ipa_common.h" @@ -37,8 +38,23 @@ #include "providers/ipa/ipa_subdomains.h" #if defined HAVE_SELINUX && defined HAVE_SELINUX_LOGIN_DIR + +#ifndef SELINUX_CHILD_DIR +#ifndef SSSD_LIBEXEC_PATH +#error "SSSD_LIBEXEC_PATH not defined" +#endif /* SSSD_LIBEXEC_PATH */ + +#define SELINUX_CHILD_DIR SSSD_LIBEXEC_PATH +#endif /* SELINUX_CHILD_DIR */ + +#define SELINUX_CHILD SELINUX_CHILD_DIR"/selinux_child" +#define SELINUX_CHILD_LOG_FILE "selinux_child" + #include <selinux/selinux.h> +/* fd used by the selinux_child process for logging */ +int selinux_child_debug_fd = -1; + static struct tevent_req * ipa_get_selinux_send(TALLOC_CTX *mem_ctx, struct be_ctx *be_ctx, @@ -274,12 +290,27 @@ struct map_order_ctx { static errno_t init_map_order_ctx(TALLOC_CTX *mem_ctx, const char *map_order, struct map_order_ctx **_mo_ctx); -static errno_t choose_best_seuser(struct sysdb_attrs **usermaps, + +struct selinux_child_input { + const char *seuser; + const char *mls_range; + const char *username; +}; + +static errno_t choose_best_seuser(TALLOC_CTX *mem_ctx, + struct sysdb_attrs **usermaps, struct pam_data *pd, struct sss_domain_info *user_domain, struct map_order_ctx *mo_ctx, - const char *default_user); + const char *default_user, + struct selinux_child_input **_sci); + +static struct tevent_req *selinux_child_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct selinux_child_input *sci); +static errno_t selinux_child_recv(struct tevent_req *req); +static void ipa_selinux_child_done(struct tevent_req *child_req); static void ipa_selinux_handler_done(struct tevent_req *req) { @@ -299,6 +330,8 @@ static void ipa_selinux_handler_done(struct tevent_req *req) struct sysdb_attrs **hbac_rules = 0; struct sysdb_attrs **best_match_maps; struct map_order_ctx *map_order_ctx; + struct selinux_child_input *sci; + struct tevent_req *child_req; ret = ipa_get_selinux_recv(req, breq, &map_count, &maps, &hbac_count, &hbac_rules, @@ -360,21 +393,25 @@ static void ipa_selinux_handler_done(struct tevent_req *req) goto fail; } - ret = choose_best_seuser(best_match_maps, pd, op_ctx->user_domain, - map_order_ctx, default_user); + ret = choose_best_seuser(breq, + best_match_maps, pd, op_ctx->user_domain, + map_order_ctx, default_user, &sci); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to evaluate ordered SELinux users array.\n"); goto fail; } - /* If we got here in online mode, set last_update to current time */ - if (!be_is_offline(be_ctx)) { - op_ctx->selinux_ctx->last_update = time(NULL); + /* Update the SELinux context in a privileged child as the back end is + * running unprivileged + */ + child_req = selinux_child_send(breq, be_ctx->ev, sci); + if (child_req == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "selinux_child_send() failed\n"); + ret = ENOMEM; + goto fail; } - - pd->pam_status = PAM_SUCCESS; - be_req_terminate(breq, DP_ERR_OK, EOK, "Success"); + tevent_req_set_callback(child_req, ipa_selinux_child_done, op_ctx); return; fail: @@ -391,6 +428,35 @@ fail: } } +static void ipa_selinux_child_done(struct tevent_req *child_req) +{ + errno_t ret; + struct ipa_selinux_op_ctx *op_ctx; + struct be_req *breq; + struct pam_data *pd; + struct be_ctx *be_ctx; + + op_ctx = tevent_req_callback_data(child_req, struct ipa_selinux_op_ctx); + breq = op_ctx->be_req; + pd = talloc_get_type(be_req_get_data(breq), struct pam_data); + be_ctx = be_req_get_be_ctx(breq); + + ret = selinux_child_recv(child_req); + talloc_free(child_req); + if (ret != EOK) { + be_req_terminate(breq, DP_ERR_FATAL, ret, NULL); + return; + } + + /* If we got here in online mode, set last_update to current time */ + if (!be_is_offline(be_ctx)) { + op_ctx->selinux_ctx->last_update = time(NULL); + } + + pd->pam_status = PAM_SUCCESS; + be_req_terminate(breq, DP_ERR_OK, EOK, "Success"); +} + static errno_t ipa_selinux_process_seealso_maps(struct sysdb_attrs *user, struct sysdb_attrs *host, @@ -652,24 +718,28 @@ done: return ret; } -static errno_t -set_seuser_helper(const char *orig_name, struct sss_domain_info *dom, - const char *seuser_mls_string); - +static errno_t selinux_child_setup(TALLOC_CTX *mem_ctx, + const char *orig_name, + struct sss_domain_info *dom, + const char *seuser_mls_string, + struct selinux_child_input **_sci); /* Choose best selinux user based on given order and write * the user to selinux login file. */ -static errno_t choose_best_seuser(struct sysdb_attrs **usermaps, +static errno_t choose_best_seuser(TALLOC_CTX *mem_ctx, + struct sysdb_attrs **usermaps, struct pam_data *pd, struct sss_domain_info *user_domain, struct map_order_ctx *mo_ctx, - const char *default_user) + const char *default_user, + struct selinux_child_input **_sci) { TALLOC_CTX *tmp_ctx; char *seuser_mls_str = NULL; const char *tmp_str; errno_t ret; int i, j; + struct selinux_child_input *sci; tmp_ctx = talloc_new(NULL); if (tmp_ctx == NULL) { @@ -716,15 +786,25 @@ static errno_t choose_best_seuser(struct sysdb_attrs **usermaps, } } - ret = set_seuser_helper(pd->user, user_domain, seuser_mls_str); + ret = selinux_child_setup(tmp_ctx, pd->user, user_domain, seuser_mls_str, &sci); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Cannot set up child input buffer"); + goto done; + } + + *_sci = talloc_steal(mem_ctx, sci); + ret = EOK; done: talloc_free(tmp_ctx); return ret; } static errno_t -set_seuser_helper(const char *orig_name, struct sss_domain_info *dom, - const char *seuser_mls_string) +selinux_child_setup(TALLOC_CTX *mem_ctx, + const char *orig_name, + struct sss_domain_info *dom, + const char *seuser_mls_string, + struct selinux_child_input **_sci) { errno_t ret; char *seuser; @@ -733,6 +813,7 @@ set_seuser_helper(const char *orig_name, struct sss_domain_info *dom, char *username; char *username_final; TALLOC_CTX *tmp_ctx; + struct selinux_child_input *sci; tmp_ctx = talloc_new(NULL); if (tmp_ctx == NULL) { @@ -778,12 +859,300 @@ set_seuser_helper(const char *orig_name, struct sss_domain_info *dom, username_final = username; } - ret = set_seuser(username_final, seuser, mls_range); + sci = talloc(tmp_ctx, struct selinux_child_input); + if (sci == NULL) { + ret = ENOMEM; + goto done; + } + + sci->seuser = talloc_strdup(sci, seuser); + sci->mls_range = talloc_strdup(sci, mls_range); + sci->username = talloc_strdup(sci, username); + if (sci->seuser == NULL || sci->mls_range == NULL + || sci->username == NULL) { + ret = ENOMEM; + goto done; + } + + *_sci = talloc_steal(mem_ctx, sci); + ret = EOK; done: talloc_free(tmp_ctx); return ret; } +struct selinux_child_state { + struct selinux_child_input *sci; + struct tevent_context *ev; + struct io_buffer *buf; + struct child_io_fds *io; +}; + +static errno_t selinux_child_init(void); +static errno_t selinux_child_create_buffer(struct selinux_child_state *state); +static errno_t selinux_fork_child(struct selinux_child_state *state); +static void selinux_child_step(struct tevent_req *subreq); +static void selinux_child_done(struct tevent_req *subreq); +static errno_t selinux_child_parse_response(uint8_t *buf, ssize_t len, + uint32_t *_child_result); + +static struct tevent_req *selinux_child_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct selinux_child_input *sci) +{ + struct tevent_req *req; + struct tevent_req *subreq; + struct selinux_child_state *state; + errno_t ret; + + req = tevent_req_create(mem_ctx, &state, struct selinux_child_state); + if (req == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); + return NULL; + } + + state->sci = sci; + state->ev = ev; + state->io = talloc(state, struct child_io_fds); + state->buf = talloc(state, struct io_buffer); + if (state->io == NULL || state->buf == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc failed.\n"); + ret = ENOMEM; + goto immediately; + } + + state->io->write_to_child_fd = -1; + state->io->read_from_child_fd = -1; + talloc_set_destructor((void *) state->io, child_io_destructor); + + ret = selinux_child_init(); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Failed to init the child\n"); + goto immediately; + } + + ret = selinux_child_create_buffer(state); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Failed to create the send buffer\n"); + ret = ENOMEM; + goto immediately; + } + + ret = selinux_fork_child(state); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Failed to fork the child\n"); + goto immediately; + } + + subreq = write_pipe_send(state, ev, state->buf->data, state->buf->size, + state->io->write_to_child_fd); + if (subreq == NULL) { + ret = ENOMEM; + goto immediately; + } + tevent_req_set_callback(subreq, selinux_child_step, req); + + ret = EOK; +immediately: + if (ret != EOK) { + tevent_req_error(req, ret); + tevent_req_post(req, ev); + } + return req; +} + +static errno_t selinux_child_init(void) +{ + return child_debug_init(SELINUX_CHILD_LOG_FILE, &selinux_child_debug_fd); +} + +static errno_t selinux_child_create_buffer(struct selinux_child_state *state) +{ + size_t rp; + size_t seuser_len; + size_t mls_range_len; + size_t username_len; + + seuser_len = strlen(state->sci->seuser); + mls_range_len = strlen(state->sci->mls_range); + username_len = strlen(state->sci->username); + + state->buf->size = 3 * sizeof(uint32_t); + state->buf->size += seuser_len + mls_range_len + username_len; + + DEBUG(SSSDBG_TRACE_ALL, "buffer size: %zu\n", state->buf->size); + + state->buf->data = talloc_size(state->buf, state->buf->size); + if (state->buf->data == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc_size failed.\n"); + return ENOMEM; + } + + rp = 0; + + /* seuser */ + SAFEALIGN_SET_UINT32(&state->buf->data[rp], seuser_len, &rp); + safealign_memcpy(&state->buf->data[rp], state->sci->seuser, + seuser_len, &rp); + + /* mls_range */ + SAFEALIGN_SET_UINT32(&state->buf->data[rp], mls_range_len, &rp); + safealign_memcpy(&state->buf->data[rp], state->sci->mls_range, + mls_range_len, &rp); + + /* username */ + SAFEALIGN_SET_UINT32(&state->buf->data[rp], username_len, &rp); + safealign_memcpy(&state->buf->data[rp], state->sci->username, + username_len, &rp); + + return EOK; +} + +static errno_t selinux_fork_child(struct selinux_child_state *state) +{ + int pipefd_to_child[2]; + int pipefd_from_child[2]; + pid_t pid; + errno_t ret; + + ret = pipe(pipefd_from_child); + if (ret == -1) { + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, + "pipe failed [%d][%s].\n", errno, sss_strerror(errno)); + return ret; + } + + ret = pipe(pipefd_to_child); + if (ret == -1) { + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, + "pipe failed [%d][%s].\n", errno, sss_strerror(errno)); + return ret; + } + + pid = fork(); + + if (pid == 0) { /* child */ + ret = exec_child(state, + pipefd_to_child, pipefd_from_child, + SELINUX_CHILD, selinux_child_debug_fd); + DEBUG(SSSDBG_CRIT_FAILURE, "Could not exec selinux_child: [%d][%s].\n", + ret, sss_strerror(ret)); + return ret; + } else if (pid > 0) { /* parent */ + state->io->read_from_child_fd = pipefd_from_child[0]; + close(pipefd_from_child[1]); + state->io->write_to_child_fd = pipefd_to_child[1]; + close(pipefd_to_child[0]); + fd_nonblocking(state->io->read_from_child_fd); + fd_nonblocking(state->io->write_to_child_fd); + + ret = child_handler_setup(state->ev, pid, NULL, NULL, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Could not set up child signal handler\n"); + return ret; + } + } else { /* error */ + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, + "fork failed [%d][%s].\n", errno, sss_strerror(errno)); + return ret; + } + + return EOK; +} + +static void selinux_child_step(struct tevent_req *subreq) +{ + struct tevent_req *req; + errno_t ret; + struct selinux_child_state *state; + + + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct selinux_child_state); + + ret = write_pipe_recv(subreq); + talloc_zfree(subreq); + if (ret != EOK) { + tevent_req_error(req, ret); + return; + } + + close(state->io->write_to_child_fd); + state->io->write_to_child_fd = -1; + + subreq = read_pipe_send(state, state->ev, state->io->read_from_child_fd); + if (subreq == NULL) { + tevent_req_error(req, ENOMEM); + return; + } + tevent_req_set_callback(subreq, selinux_child_done, req); +} + +static void selinux_child_done(struct tevent_req *subreq) +{ + struct tevent_req *req; + struct selinux_child_state *state; + uint32_t child_result; + errno_t ret; + ssize_t len; + uint8_t *buf; + + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct selinux_child_state); + + ret = read_pipe_recv(subreq, state, &buf, &len); + talloc_zfree(subreq); + if (ret != EOK) { + tevent_req_error(req, ret); + return; + } + + close(state->io->read_from_child_fd); + state->io->read_from_child_fd = -1; + + ret = selinux_child_parse_response(buf, len, &child_result); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "selinux_child_parse_response failed: [%d][%s]\n", + ret, strerror(ret)); + tevent_req_error(req, ret); + return; + } else if (child_result != 0){ + DEBUG(SSSDBG_CRIT_FAILURE, + "Error in selinux_child: [%d][%s]\n", + child_result, strerror(child_result)); + tevent_req_error(req, ERR_SELINUX_CONTEXT); + return; + } + + tevent_req_done(req); + return; +} + +static errno_t selinux_child_parse_response(uint8_t *buf, + ssize_t len, + uint32_t *_child_result) +{ + size_t p = 0; + uint32_t child_result; + + /* semanage retval */ + SAFEALIGN_COPY_UINT32_CHECK(&child_result, buf + p, len, &p); + + *_child_result = child_result; + return EOK; +} + +static errno_t selinux_child_recv(struct tevent_req *req) +{ + TEVENT_REQ_RETURN_ON_ERROR(req); + return EOK; +} + /* A more generic request to gather all SELinux and HBAC rules. Updates * cache if necessary */ diff --git a/src/providers/ipa/selinux_child.c b/src/providers/ipa/selinux_child.c new file mode 100644 index 000000000..a624cfd30 --- /dev/null +++ b/src/providers/ipa/selinux_child.c @@ -0,0 +1,272 @@ +/* + SSSD + + IPA back end -- set SELinux context in a child module + + Authors: + Jakub Hrozek <jhrozek@redhat.com> + + Copyright (C) 2014 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 <http://www.gnu.org/licenses/>. +*/ + + +#include <sys/types.h> +#include <unistd.h> +#include <sys/stat.h> +#include <popt.h> + +#include "util/util.h" +#include "util/child_common.h" +#include "providers/dp_backend.h" + +struct input_buffer { + const char *seuser; + const char *mls_range; + const char *username; +}; + +static errno_t unpack_buffer(uint8_t *buf, + size_t size, + struct input_buffer *ibuf) +{ + size_t p = 0; + uint32_t len; + + /* seuser */ + SAFEALIGN_COPY_UINT32_CHECK(&len, buf + p, size, &p); + DEBUG(SSSDBG_TRACE_INTERNAL, "seuser length: %d\n", len); + if (len == 0) { + return EINVAL; + } else { + if ((p + len ) > size) return EINVAL; + ibuf->seuser = talloc_strndup(ibuf, (char *)(buf + p), len); + if (ibuf->seuser == NULL) return ENOMEM; + DEBUG(SSSDBG_TRACE_INTERNAL, "seuser: %s\n", ibuf->seuser); + p += len; + } + + /* MLS range */ + SAFEALIGN_COPY_UINT32_CHECK(&len, buf + p, size, &p); + DEBUG(SSSDBG_TRACE_INTERNAL, "mls_range length: %d\n", len); + if (len == 0) { + return EINVAL; + } else { + if ((p + len ) > size) return EINVAL; + ibuf->mls_range = talloc_strndup(ibuf, (char *)(buf + p), len); + if (ibuf->mls_range == NULL) return ENOMEM; + DEBUG(SSSDBG_TRACE_INTERNAL, "mls_range: %s\n", ibuf->mls_range); + p += len; + } + + /* username */ + SAFEALIGN_COPY_UINT32_CHECK(&len, buf + p, size, &p); + DEBUG(SSSDBG_TRACE_INTERNAL, "username length: %d\n", len); + if (len == 0) { + return EINVAL; + } else { + if ((p + len ) > size) return EINVAL; + ibuf->username = talloc_strndup(ibuf, (char *)(buf + p), len); + if (ibuf->username == NULL) return ENOMEM; + DEBUG(SSSDBG_TRACE_INTERNAL, "username: %s\n", ibuf->username); + p += len; + } + + return EOK; +} + +static errno_t pack_buffer(struct response *r, int result) +{ + size_t p = 0; + + /* A buffer with the following structure must be created: + * uint32_t status of the request (required) + */ + r->size = sizeof(uint32_t); + + r->buf = talloc_array(r, uint8_t, r->size); + if(r->buf == NULL) { + return ENOMEM; + } + + DEBUG(SSSDBG_TRACE_FUNC, "result [%d]\n", result); + + /* result */ + SAFEALIGN_SET_UINT32(&r->buf[p], result, &p); + + return EOK; +} + +static errno_t prepare_response(TALLOC_CTX *mem_ctx, + int result, + struct response **rsp) +{ + int ret; + struct response *r = NULL; + + r = talloc_zero(mem_ctx, struct response); + if (r == NULL) { + return ENOMEM; + } + + r->buf = NULL; + r->size = 0; + + ret = pack_buffer(r, result); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "pack_buffer failed\n"); + return ret; + } + + *rsp = r; + DEBUG(SSSDBG_TRACE_ALL, "r->size: %zu\n", r->size); + return EOK; +} + +int main(int argc, const char *argv[]) +{ + int opt; + poptContext pc; + int debug_fd = -1; + errno_t ret; + TALLOC_CTX *main_ctx = NULL; + uint8_t *buf = NULL; + ssize_t len = 0; + struct input_buffer *ibuf = NULL; + struct response *resp = NULL; + size_t written; + + struct poptOption long_options[] = { + POPT_AUTOHELP + {"debug-level", 'd', POPT_ARG_INT, &debug_level, 0, + _("Debug level"), NULL}, + {"debug-timestamps", 0, POPT_ARG_INT, &debug_timestamps, 0, + _("Add debug timestamps"), NULL}, + {"debug-microseconds", 0, POPT_ARG_INT, &debug_microseconds, 0, + _("Show timestamps with microseconds"), NULL}, + {"debug-fd", 0, POPT_ARG_INT, &debug_fd, 0, + _("An open file descriptor for the debug logs"), NULL}, + {"debug-to-stderr", 0, POPT_ARG_NONE | POPT_ARGFLAG_DOC_HIDDEN, + &debug_to_stderr, 0, + _("Send the debug output to stderr directly."), NULL }, + POPT_TABLEEND + }; + + /* Set debug level to invalid value so we can decide if -d 0 was used. */ + debug_level = SSSDBG_INVALID; + + pc = poptGetContext(argv[0], argc, argv, long_options, 0); + while((opt = poptGetNextOpt(pc)) != -1) { + switch(opt) { + default: + fprintf(stderr, "\nInvalid option %s: %s\n\n", + poptBadOption(pc, 0), poptStrerror(opt)); + poptPrintUsage(pc, stderr, 0); + _exit(-1); + } + } + + poptFreeContext(pc); + + DEBUG_INIT(debug_level); + + debug_prg_name = talloc_asprintf(NULL, "[sssd[selinux_child[%d]]]", getpid()); + if (debug_prg_name == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed.\n"); + goto fail; + } + + if (debug_fd != -1) { + ret = set_debug_file_from_fd(debug_fd); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "set_debug_file_from_fd failed.\n"); + } + } + + DEBUG(SSSDBG_TRACE_FUNC, "selinux_child started.\n"); + DEBUG(SSSDBG_TRACE_INTERNAL, + "Running as [%"SPRIuid"][%"SPRIgid"].\n", geteuid(), getegid()); + + main_ctx = talloc_new(NULL); + if (main_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new failed.\n"); + talloc_free(discard_const(debug_prg_name)); + goto fail; + } + talloc_steal(main_ctx, debug_prg_name); + + buf = talloc_size(main_ctx, sizeof(uint8_t)*IN_BUF_SIZE); + if (buf == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc_size failed.\n"); + goto fail; + } + + ibuf = talloc_zero(main_ctx, struct input_buffer); + if (ibuf == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n"); + goto fail; + } + + DEBUG(SSSDBG_TRACE_FUNC, "context initialized\n"); + + errno = 0; + len = sss_atomic_read_s(STDIN_FILENO, buf, IN_BUF_SIZE); + if (len == -1) { + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, "read failed [%d][%s].\n", ret, strerror(ret)); + goto fail; + } + + close(STDIN_FILENO); + + ret = unpack_buffer(buf, len, ibuf); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "unpack_buffer failed.[%d][%s].\n", ret, strerror(ret)); + goto fail; + } + + DEBUG(SSSDBG_TRACE_FUNC, "performing selinux operations\n"); + + ret = set_seuser(ibuf->username, ibuf->seuser, ibuf->mls_range); + + ret = prepare_response(main_ctx, ret, &resp); + + errno = 0; + + written = sss_atomic_write_s(STDOUT_FILENO, resp->buf, resp->size); + if (written == -1) { + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, "write failed [%d][%s].\n", ret, + strerror(ret)); + goto fail; + } + + if (written != resp->size) { + DEBUG(SSSDBG_CRIT_FAILURE, "Expected to write %zu bytes, wrote %zu\n", + resp->size, written); + goto fail; + } + + DEBUG(SSSDBG_TRACE_FUNC, "selinux_child completed successfully\n"); + close(STDOUT_FILENO); + talloc_free(main_ctx); + return EXIT_SUCCESS; +fail: + DEBUG(SSSDBG_CRIT_FAILURE, "selinux_child failed!\n"); + close(STDOUT_FILENO); + talloc_free(main_ctx); + return EXIT_FAILURE; +} diff --git a/src/util/util_errors.c b/src/util/util_errors.c index 5b36780ff..d5da64622 100644 --- a/src/util/util_errors.c +++ b/src/util/util_errors.c @@ -62,6 +62,7 @@ struct err_string error_to_str[] = { { "Bus method not supported" }, /* ERR_SBUS_NOSUP */ { "Cannot connect to system bus" }, /* ERR_NO_SYSBUS */ { "LDAP search returned a referral" }, /* ERR_REFERRAL */ + { "Error setting SELinux user context" }, /* ERR_SELINUX_CONTEXT */ }; diff --git a/src/util/util_errors.h b/src/util/util_errors.h index e040ba903..2bc576605 100644 --- a/src/util/util_errors.h +++ b/src/util/util_errors.h @@ -84,6 +84,7 @@ enum sssd_errors { ERR_SBUS_NOSUP, ERR_NO_SYSBUS, ERR_REFERRAL, + ERR_SELINUX_CONTEXT, ERR_LAST /* ALWAYS LAST */ }; |