version 1.1, 2012/02/21 16:23:02
|
version 1.1.1.5, 2014/06/15 16:12:55
|
Line 1
|
Line 1
|
/* |
/* |
* Copyright (c) 2009-2010 Todd C. Miller <Todd.Miller@courtesan.com> | * Copyright (c) 2009-2013 Todd C. Miller <Todd.Miller@courtesan.com> |
* Copyright (c) 2008 Dan Walsh <dwalsh@redhat.com> |
* Copyright (c) 2008 Dan Walsh <dwalsh@redhat.com> |
* |
* |
* Borrowed heavily from newrole source code |
* Borrowed heavily from newrole source code |
Line 48
|
Line 48
|
#endif |
#endif |
|
|
#include "sudo.h" |
#include "sudo.h" |
|
#include "sudo_exec.h" |
|
|
static struct selinux_state { |
static struct selinux_state { |
security_context_t old_context; |
security_context_t old_context; |
Line 64 static int
|
Line 65 static int
|
audit_role_change(const security_context_t old_context, |
audit_role_change(const security_context_t old_context, |
const security_context_t new_context, const char *ttyn) |
const security_context_t new_context, const char *ttyn) |
{ |
{ |
int au_fd, rc; | int au_fd, rc = -1; |
char *message; |
char *message; |
|
debug_decl(audit_role_change, SUDO_DEBUG_SELINUX) |
|
|
au_fd = audit_open(); |
au_fd = audit_open(); |
if (au_fd == -1) { |
if (au_fd == -1) { |
/* Kernel may not have audit support. */ |
/* Kernel may not have audit support. */ |
if (errno != EINVAL && errno != EPROTONOSUPPORT && errno != EAFNOSUPPORT |
if (errno != EINVAL && errno != EPROTONOSUPPORT && errno != EAFNOSUPPORT |
) |
) |
error(1, _("unable to open audit system")); | fatal(U_("unable to open audit system")); |
return -1; | } else { |
| /* audit role change using the same format as newrole(1) */ |
| easprintf(&message, "newrole: old-context=%s new-context=%s", |
| old_context, new_context); |
| rc = audit_log_user_message(au_fd, AUDIT_USER_ROLE_CHANGE, |
| message, NULL, NULL, ttyn, 1); |
| if (rc <= 0) |
| warning(U_("unable to send audit message")); |
| efree(message); |
| close(au_fd); |
} |
} |
|
|
/* audit role change using the same format as newrole(1) */ | debug_return_int(rc); |
easprintf(&message, "newrole: old-context=%s new-context=%s", | |
old_context, new_context); | |
rc = audit_log_user_message(au_fd, AUDIT_USER_ROLE_CHANGE, | |
message, NULL, NULL, ttyn, 1); | |
if (rc <= 0) | |
warning(_("unable to send audit message")); | |
| |
efree(message); | |
close(au_fd); | |
| |
return rc; | |
} |
} |
#endif |
#endif |
|
|
Line 103 selinux_restore_tty(void)
|
Line 103 selinux_restore_tty(void)
|
{ |
{ |
int retval = 0; |
int retval = 0; |
security_context_t chk_tty_context = NULL; |
security_context_t chk_tty_context = NULL; |
|
debug_decl(selinux_restore_tty, SUDO_DEBUG_SELINUX) |
|
|
if (se_state.ttyfd == -1 || se_state.new_tty_context == NULL) |
if (se_state.ttyfd == -1 || se_state.new_tty_context == NULL) |
goto skip_relabel; |
goto skip_relabel; |
|
|
/* Verify that the tty still has the context set by sudo. */ |
/* Verify that the tty still has the context set by sudo. */ |
if ((retval = fgetfilecon(se_state.ttyfd, &chk_tty_context)) < 0) { |
if ((retval = fgetfilecon(se_state.ttyfd, &chk_tty_context)) < 0) { |
warning(_("unable to fgetfilecon %s"), se_state.ttyn); | warning(U_("unable to fgetfilecon %s"), se_state.ttyn); |
goto skip_relabel; |
goto skip_relabel; |
} |
} |
|
|
if ((retval = strcmp(chk_tty_context, se_state.new_tty_context))) { |
if ((retval = strcmp(chk_tty_context, se_state.new_tty_context))) { |
warningx(_("%s changed labels"), se_state.ttyn); | warningx(U_("%s changed labels"), se_state.ttyn); |
goto skip_relabel; |
goto skip_relabel; |
} |
} |
|
|
if ((retval = fsetfilecon(se_state.ttyfd, se_state.tty_context)) < 0) |
if ((retval = fsetfilecon(se_state.ttyfd, se_state.tty_context)) < 0) |
warning(_("unable to restore context for %s"), se_state.ttyn); | warning(U_("unable to restore context for %s"), se_state.ttyn); |
|
|
skip_relabel: |
skip_relabel: |
if (se_state.ttyfd != -1) { |
if (se_state.ttyfd != -1) { |
Line 130 skip_relabel:
|
Line 131 skip_relabel:
|
freecon(chk_tty_context); |
freecon(chk_tty_context); |
chk_tty_context = NULL; |
chk_tty_context = NULL; |
} |
} |
return retval; | debug_return_int(retval); |
} |
} |
|
|
/* |
/* |
Line 147 relabel_tty(const char *ttyn, int ptyfd)
|
Line 148 relabel_tty(const char *ttyn, int ptyfd)
|
security_context_t tty_con = NULL; |
security_context_t tty_con = NULL; |
security_context_t new_tty_con = NULL; |
security_context_t new_tty_con = NULL; |
int fd; |
int fd; |
|
debug_decl(relabel_tty, SUDO_DEBUG_SELINUX) |
|
|
se_state.ttyfd = ptyfd; |
se_state.ttyfd = ptyfd; |
|
|
/* It is perfectly legal to have no tty. */ |
/* It is perfectly legal to have no tty. */ |
if (ptyfd == -1 && ttyn == NULL) |
if (ptyfd == -1 && ttyn == NULL) |
return 0; | debug_return_int(0); |
|
|
/* If sudo is not allocating a pty for the command, open current tty. */ |
/* If sudo is not allocating a pty for the command, open current tty. */ |
if (ptyfd == -1) { |
if (ptyfd == -1) { |
se_state.ttyfd = open(ttyn, O_RDWR|O_NONBLOCK); |
se_state.ttyfd = open(ttyn, O_RDWR|O_NONBLOCK); |
if (se_state.ttyfd == -1) { |
if (se_state.ttyfd == -1) { |
warning(_("unable to open %s, not relabeling tty"), ttyn); | warning(U_("unable to open %s, not relabeling tty"), ttyn); |
if (se_state.enforcing) |
if (se_state.enforcing) |
goto bad; |
goto bad; |
} |
} |
Line 167 relabel_tty(const char *ttyn, int ptyfd)
|
Line 169 relabel_tty(const char *ttyn, int ptyfd)
|
} |
} |
|
|
if (fgetfilecon(se_state.ttyfd, &tty_con) < 0) { |
if (fgetfilecon(se_state.ttyfd, &tty_con) < 0) { |
warning(_("unable to get current tty context, not relabeling tty")); | warning(U_("unable to get current tty context, not relabeling tty")); |
if (se_state.enforcing) |
if (se_state.enforcing) |
goto bad; |
goto bad; |
} |
} |
|
|
if (tty_con && (security_compute_relabel(se_state.new_context, tty_con, |
if (tty_con && (security_compute_relabel(se_state.new_context, tty_con, |
SECCLASS_CHR_FILE, &new_tty_con) < 0)) { |
SECCLASS_CHR_FILE, &new_tty_con) < 0)) { |
warning(_("unable to get new tty context, not relabeling tty")); | warning(U_("unable to get new tty context, not relabeling tty")); |
if (se_state.enforcing) |
if (se_state.enforcing) |
goto bad; |
goto bad; |
} |
} |
|
|
if (new_tty_con != NULL) { |
if (new_tty_con != NULL) { |
if (fsetfilecon(se_state.ttyfd, new_tty_con) < 0) { |
if (fsetfilecon(se_state.ttyfd, new_tty_con) < 0) { |
warning(_("unable to set new tty context")); | warning(U_("unable to set new tty context")); |
if (se_state.enforcing) |
if (se_state.enforcing) |
goto bad; |
goto bad; |
} |
} |
Line 191 relabel_tty(const char *ttyn, int ptyfd)
|
Line 193 relabel_tty(const char *ttyn, int ptyfd)
|
/* Reopen pty that was relabeled, std{in,out,err} are reset later. */ |
/* Reopen pty that was relabeled, std{in,out,err} are reset later. */ |
se_state.ttyfd = open(ttyn, O_RDWR|O_NOCTTY, 0); |
se_state.ttyfd = open(ttyn, O_RDWR|O_NOCTTY, 0); |
if (se_state.ttyfd == -1) { |
if (se_state.ttyfd == -1) { |
warning(_("unable to open %s"), ttyn); | warning(U_("unable to open %s"), ttyn); |
if (se_state.enforcing) |
if (se_state.enforcing) |
goto bad; |
goto bad; |
} |
} |
Line 204 relabel_tty(const char *ttyn, int ptyfd)
|
Line 206 relabel_tty(const char *ttyn, int ptyfd)
|
close(se_state.ttyfd); |
close(se_state.ttyfd); |
se_state.ttyfd = open(ttyn, O_RDWR|O_NONBLOCK); |
se_state.ttyfd = open(ttyn, O_RDWR|O_NONBLOCK); |
if (se_state.ttyfd == -1) { |
if (se_state.ttyfd == -1) { |
warning(_("unable to open %s"), ttyn); | warning(U_("unable to open %s"), ttyn); |
goto bad; |
goto bad; |
} |
} |
(void)fcntl(se_state.ttyfd, F_SETFL, |
(void)fcntl(se_state.ttyfd, F_SETFL, |
Line 222 relabel_tty(const char *ttyn, int ptyfd)
|
Line 224 relabel_tty(const char *ttyn, int ptyfd)
|
se_state.ttyn = ttyn; |
se_state.ttyn = ttyn; |
se_state.tty_context = tty_con; |
se_state.tty_context = tty_con; |
se_state.new_tty_context = new_tty_con; |
se_state.new_tty_context = new_tty_con; |
return 0; | debug_return_int(0); |
|
|
bad: |
bad: |
if (se_state.ttyfd != -1 && se_state.ttyfd != ptyfd) { |
if (se_state.ttyfd != -1 && se_state.ttyfd != ptyfd) { |
Line 230 bad:
|
Line 232 bad:
|
se_state.ttyfd = -1; |
se_state.ttyfd = -1; |
} |
} |
freecon(tty_con); |
freecon(tty_con); |
return -1; | debug_return_int(-1); |
} |
} |
|
|
/* |
/* |
Line 243 get_exec_context(security_context_t old_context, const
|
Line 245 get_exec_context(security_context_t old_context, const
|
security_context_t new_context = NULL; |
security_context_t new_context = NULL; |
context_t context = NULL; |
context_t context = NULL; |
char *typebuf = NULL; |
char *typebuf = NULL; |
|
debug_decl(get_exec_context, SUDO_DEBUG_SELINUX) |
|
|
/* We must have a role, the type is optional (we can use the default). */ |
/* We must have a role, the type is optional (we can use the default). */ |
if (!role) { |
if (!role) { |
warningx(_("you must specify a role for type %s"), type); | warningx(U_("you must specify a role for type %s"), type); |
errno = EINVAL; |
errno = EINVAL; |
return NULL; | goto bad; |
} |
} |
if (!type) { |
if (!type) { |
if (get_default_type(role, &typebuf)) { |
if (get_default_type(role, &typebuf)) { |
warningx(_("unable to get default type for role %s"), role); | warningx(U_("unable to get default type for role %s"), role); |
errno = EINVAL; |
errno = EINVAL; |
return NULL; | goto bad; |
} |
} |
type = typebuf; |
type = typebuf; |
} |
} |
Line 270 get_exec_context(security_context_t old_context, const
|
Line 273 get_exec_context(security_context_t old_context, const
|
* type we will be running the command as. |
* type we will be running the command as. |
*/ |
*/ |
if (context_role_set(context, role)) { |
if (context_role_set(context, role)) { |
warning(_("failed to set new role %s"), role); | warning(U_("failed to set new role %s"), role); |
goto bad; |
goto bad; |
} |
} |
if (context_type_set(context, type)) { |
if (context_type_set(context, type)) { |
warning(_("failed to set new type %s"), type); | warning(U_("failed to set new type %s"), type); |
goto bad; |
goto bad; |
} |
} |
|
|
Line 283 get_exec_context(security_context_t old_context, const
|
Line 286 get_exec_context(security_context_t old_context, const
|
*/ |
*/ |
new_context = estrdup(context_str(context)); |
new_context = estrdup(context_str(context)); |
if (security_check_context(new_context) < 0) { |
if (security_check_context(new_context) < 0) { |
warningx(_("%s is not a valid context"), new_context); | warningx(U_("%s is not a valid context"), new_context); |
errno = EINVAL; |
errno = EINVAL; |
goto bad; |
goto bad; |
} |
} |
Line 293 get_exec_context(security_context_t old_context, const
|
Line 296 get_exec_context(security_context_t old_context, const
|
#endif |
#endif |
|
|
context_free(context); |
context_free(context); |
return new_context; | debug_return_ptr(new_context); |
|
|
bad: |
bad: |
free(typebuf); | efree(typebuf); |
context_free(context); |
context_free(context); |
freecon(new_context); |
freecon(new_context); |
return NULL; | debug_return_ptr(NULL); |
} |
} |
|
|
/* |
/* |
Line 314 selinux_setup(const char *role, const char *type, cons
|
Line 317 selinux_setup(const char *role, const char *type, cons
|
int ptyfd) |
int ptyfd) |
{ |
{ |
int rval = -1; |
int rval = -1; |
|
debug_decl(selinux_setup, SUDO_DEBUG_SELINUX) |
|
|
/* Store the caller's SID in old_context. */ |
/* Store the caller's SID in old_context. */ |
if (getprevcon(&se_state.old_context)) { |
if (getprevcon(&se_state.old_context)) { |
warning(_("failed to get old_context")); | warning(U_("failed to get old_context")); |
goto done; |
goto done; |
} |
} |
|
|
se_state.enforcing = security_getenforce(); |
se_state.enforcing = security_getenforce(); |
if (se_state.enforcing < 0) { |
if (se_state.enforcing < 0) { |
warning(_("unable to determine enforcing mode.")); | warning(U_("unable to determine enforcing mode.")); |
goto done; |
goto done; |
} |
} |
|
|
Line 335 selinux_setup(const char *role, const char *type, cons
|
Line 339 selinux_setup(const char *role, const char *type, cons
|
goto done; |
goto done; |
|
|
if (relabel_tty(ttyn, ptyfd) < 0) { |
if (relabel_tty(ttyn, ptyfd) < 0) { |
warning(_("unable to setup tty context for %s"), se_state.new_context); | warning(U_("unable to set tty context to %s"), se_state.new_context); |
goto done; |
goto done; |
} |
} |
|
|
Line 354 selinux_setup(const char *role, const char *type, cons
|
Line 358 selinux_setup(const char *role, const char *type, cons
|
rval = 0; |
rval = 0; |
|
|
done: |
done: |
return rval; | debug_return_int(rval); |
} |
} |
|
|
void |
void |
selinux_execve(const char *path, char *argv[], char *envp[]) | selinux_execve(const char *path, char *const argv[], char *const envp[], |
| int noexec) |
{ |
{ |
char **nargv; |
char **nargv; |
|
const char *sesh; |
int argc, serrno; |
int argc, serrno; |
|
debug_decl(selinux_execve, SUDO_DEBUG_SELINUX) |
|
|
|
sesh = sudo_conf_sesh_path(); |
|
if (sesh == NULL) { |
|
warningx("internal error: sesh path not set"); |
|
errno = EINVAL; |
|
debug_return; |
|
} |
|
|
if (setexeccon(se_state.new_context)) { |
if (setexeccon(se_state.new_context)) { |
warning(_("unable to set exec context to %s"), se_state.new_context); | warning(U_("unable to set exec context to %s"), se_state.new_context); |
if (se_state.enforcing) |
if (se_state.enforcing) |
return; | debug_return; |
} |
} |
|
|
#ifdef HAVE_SETKEYCREATECON |
#ifdef HAVE_SETKEYCREATECON |
if (setkeycreatecon(se_state.new_context)) { |
if (setkeycreatecon(se_state.new_context)) { |
warning(_("unable to set key creation context to %s"), se_state.new_context); | warning(U_("unable to set key creation context to %s"), se_state.new_context); |
if (se_state.enforcing) |
if (se_state.enforcing) |
return; | debug_return; |
} |
} |
#endif /* HAVE_SETKEYCREATECON */ |
#endif /* HAVE_SETKEYCREATECON */ |
|
|
|
/* |
|
* Build new argv with sesh as argv[0]. |
|
* If argv[0] ends in -noexec, sesh will disable execute |
|
* for the command it runs. |
|
*/ |
for (argc = 0; argv[argc] != NULL; argc++) |
for (argc = 0; argv[argc] != NULL; argc++) |
continue; |
continue; |
|
|
/* Build new argv with sesh as argv[0]. */ |
|
nargv = emalloc2(argc + 2, sizeof(char *)); |
nargv = emalloc2(argc + 2, sizeof(char *)); |
nargv[0] = *argv[0] == '-' ? "-sesh" : "sesh"; | if (noexec) |
| nargv[0] = *argv[0] == '-' ? "-sesh-noexec" : "sesh-noexec"; |
| else |
| nargv[0] = *argv[0] == '-' ? "-sesh" : "sesh"; |
nargv[1] = (char *)path; |
nargv[1] = (char *)path; |
memcpy(&nargv[2], &argv[1], argc * sizeof(char *)); /* copies NULL */ |
memcpy(&nargv[2], &argv[1], argc * sizeof(char *)); /* copies NULL */ |
|
|
execve(_PATH_SUDO_SESH, nargv, envp); | /* sesh will handle noexec for us. */ |
| sudo_execve(sesh, nargv, envp, false); |
serrno = errno; |
serrno = errno; |
free(nargv); |
free(nargv); |
errno = serrno; |
errno = serrno; |
|
debug_return; |
} |
} |