static pid_t child;
static int child_status;
-static void script_child __P((const char *path, char *const argv[]));
+#if defined(HAVE_OPENPTY) || defined(HAVE_GRANTPT)
+static char slavename[PATH_MAX];
+#else
+static char slavename[] = "/dev/ptyXX";
+#endif
+
+static void script_child __P((char *path, char *argv[], int));
static void sync_winsize __P((int src, int dst));
static void sigchild __P((int signo));
static void sigwinch __P((int signo));
int
script_execv(path, argv)
- const char *path;
- char *const argv[];
+ char *path;
+ char *argv[];
{
int n, nready;
fd_set *fdsr, *fdsw;
struct timeval now, then;
sigaction_t sa;
FILE *idfile, *ofile, *tfile;
+ int rbac_enabled = 0;
if ((idfile = fdopen(script_fds[SFD_LOG], "w")) == NULL)
log_error(USE_ERRNO, "fdopen");
if ((tfile = fdopen(script_fds[SFD_TIMING], "w")) == NULL)
log_error(USE_ERRNO, "fdopen");
+#ifdef HAVE_SELINUX
+ rbac_enabled = is_selinux_enabled() > 0 && user_role != NULL;
+ if (rbac_enabled) {
+ selinux_prefork(user_role, user_type, script_fds[SFD_SLAVE]);
+ /* Re-open slave fd after it has been relabeled */
+ close(script_fds[SFD_SLAVE]);
+ script_fds[SFD_SLAVE] = open(slavename, O_RDWR, 0);
+ if (script_fds[SFD_SLAVE] == -1)
+ log_error(USE_ERRNO, "cannot open %s", slavename);
+ }
+#endif
+
child = fork();
if (child == -1)
log_error(USE_ERRNO, "Can't fork");
if (child == 0) {
/* fork child, setup tty and exec command */
- script_child(path, argv);
- return(-1); /* execv failure */
+ script_child(path, argv, rbac_enabled);
+ warning("unable to execute %s", path);
+ _exit(127);
}
/* Setup signal handlers for child exit and window size changes. */
}
static void
-script_child(path, argv)
- const char *path;
- char *const argv[];
+script_child(path, argv, rbac_enabled)
+ char *path;
+ char *argv[];
+ int rbac_enabled;
{
/*
* Create new session, make slave controlling terminal and
close(script_fds[SFD_LOG]);
close(script_fds[SFD_OUTPUT]);
close(script_fds[SFD_TIMING]);
+#ifdef HAVE_SELINUX
+ if (rbac_enabled)
+ selinux_execv(path, argv);
+ else
+#endif
execv(path, argv);
}
int *master;
int *slave;
{
- char line[PATH_MAX];
struct group *gr;
gid_t ttygid = -1;
if ((gr = sudo_getgrnam("tty")) != NULL)
ttygid = gr->gr_gid;
- if (openpty(master, slave, line, NULL, NULL) != 0)
+ if (openpty(master, slave, slavename, NULL, NULL) != 0)
return(0);
- (void) chown(line, runas_pw->pw_uid, ttygid);
+ (void) chown(slavename, runas_pw->pw_uid, ttygid);
return(1);
}
#else
# ifdef HAVE_GRANTPT
-
# ifndef HAVE_POSIX_OPENPT
static int
posix_openpt(oflag)
close(*master);
return(0);
}
- *slave = open(line, O_RDWR, 0);
+ strlcpy(slavename, line, sizeof(slavename));
+ *slave = open(slavename, O_RDWR, 0);
if (*slave == -1) {
close(*master);
return(0);
}
- (void) chown(line, runas_pw->pw_uid, -1);
+ (void) chown(slavename, runas_pw->pw_uid, -1);
return(1);
}
# else /* !HAVE_GRANTPT */
-static char line[] = "/dev/ptyXX";
static int
get_pty(master, slave)
int *master;
ttygid = gr->gr_gid;
for (bank = "pqrs"; *bank != '\0'; bank++) {
- line[sizeof("/dev/ptyX") - 2] = *bank;
+ slavename[sizeof("/dev/ptyX") - 2] = *bank;
for (cp = "0123456789abcdef"; *cp != '\0'; cp++) {
- line[sizeof("/dev/ptyXX") - 2] = *cp;
- *master = open(line, O_RDWR, 0);
+ slavename[sizeof("/dev/ptyXX") - 2] = *cp;
+ *master = open(slavename, O_RDWR, 0);
if (*master == -1) {
if (errno == ENOENT)
return(0); /* out of ptys */
continue; /* already in use */
}
- line[sizeof("/dev/p") - 2] = 't';
- (void) chown(line, runas_pw->pw_uid, ttygid);
- (void) chmod(line, S_IRUSR|S_IWUSR|S_IWGRP);
+ slavename[sizeof("/dev/p") - 2] = 't';
+ (void) chown(slavename, runas_pw->pw_uid, ttygid);
+ (void) chmod(slavename, S_IRUSR|S_IWUSR|S_IWGRP);
# ifdef HAVE_REVOKE
- (void) revoke(line);
+ (void) revoke(slavename);
# endif
- *slave = open(line, O_RDWR, 0);
+ *slave = open(slavename, O_RDWR, 0);
if (*slave != -1)
return(1); /* success */
(void) close(*master);
__unused static const char rcsid[] = "$Sudo$";
#endif /* lint */
+static security_context_t old_context;
+static security_context_t new_context;
+static security_context_t tty_context;
+static security_context_t new_tty_context;
+static int enforcing;
+
/*
* This function attempts to revert the relabeling done to the tty.
* fd - referencing the opened ttyn
/*
* This function attempts to relabel the tty. If this function fails, then
- * the fd is closed, the contexts are free'd and -1 is returned. On success,
- * a valid fd is returned and tty_context and new_tty_context are set.
+ * the contexts are free'd and -1 is returned. On success, 0 is returned
+ * and tty_context and new_tty_context are set.
*
* This function will not fail if it can not relabel the tty when selinux is
* in permissive mode.
*/
static int
-relabel_tty(const char *ttyn, security_context_t new_context,
- security_context_t * tty_context, security_context_t * new_tty_context,
+relabel_tty(int ttyfd, security_context_t new_context,
+ security_context_t *tty_context, security_context_t *new_tty_context,
int enforcing)
{
- int fd;
security_context_t tty_con = NULL;
security_context_t new_tty_con = NULL;
- if (!ttyn)
- return(0);
-
- /* Re-open TTY descriptor */
- fd = open(ttyn, O_RDWR | O_NONBLOCK);
- if (fd == -1) {
- warning("unable to open %s", ttyn);
- return(-1);
- }
- (void)fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK);
-
- if (fgetfilecon(fd, &tty_con) < 0) {
- warning("unable to get current context for %s, not relabeling tty",
- ttyn);
+ if (fgetfilecon(ttyfd, &tty_con) < 0) {
+ warning("unable to get current tty context, not relabeling tty");
if (enforcing)
goto error;
}
if (tty_con && (security_compute_relabel(new_context, tty_con,
SECCLASS_CHR_FILE, &new_tty_con) < 0)) {
- warning("unable to get new context for %s, not relabeling tty", ttyn);
+ warning("unable to get new tty context, not relabeling tty");
if (enforcing)
goto error;
}
if (new_tty_con != NULL) {
- if (fsetfilecon(fd, new_tty_con) < 0) {
- warning("unable to set new context for %s", ttyn);
+ if (fsetfilecon(ttyfd, new_tty_con) < 0) {
+ warning("unable to set new tty context");
if (enforcing)
goto error;
}
*tty_context = tty_con;
*new_tty_context = new_tty_con;
- return(fd);
+ return(0);
error:
freecon(tty_con);
- close(fd);
return(-1);
}
}
/*
- * If the program is being run with a different security context we
- * need to go through an intermediary process for the transition to
- * be allowed by the policy. We use the "sesh" shell for this, which
- * will simply execute the command pass to it on the command line.
+ * Set the tty context in preparation for fork/exec.
*/
void
-selinux_exec(char *role, char *type, char **argv, int login_shell)
+selinux_prefork(char *role, char *type, int ttyfd)
{
- security_context_t old_context = NULL;
- security_context_t new_context = NULL;
- security_context_t tty_context = NULL;
- security_context_t new_tty_context = NULL;
- pid_t childPid;
- int enforcing, ttyfd;
-
- /* Must have a tty. */
- if (user_ttypath == NULL || *user_ttypath == '\0')
- error(EXIT_FAILURE, "unable to determine tty");
-
/* Store the caller's SID in old_context. */
if (getprevcon(&old_context))
error(EXIT_FAILURE, "failed to get old_context");
if (enforcing < 0)
error(EXIT_FAILURE, "unable to determine enforcing mode.");
-
#ifdef DEBUG
warningx("your old context was %s", old_context);
#endif
new_context = get_exec_context(old_context, role, type);
if (!new_context)
- exit(EXIT_FAILURE);
+ error(EXIT_FAILURE, "unable to get exec context");
- ttyfd = relabel_tty(user_ttypath, new_context, &tty_context,
+ ttyfd = relabel_tty(ttyfd, new_context, &tty_context,
&new_tty_context, enforcing);
if (ttyfd < 0)
error(EXIT_FAILURE, "unable to setup tty context for %s", new_context);
warningx("your old tty context is %s", tty_context);
warningx("your new tty context is %s", new_tty_context);
#endif
+}
+
+void
+selinux_execv(char *path, char **argv)
+{
+ if (setexeccon(new_context)) {
+ warning("unable to set exec context to %s", new_context);
+ if (enforcing)
+ return;
+ }
+
+ if (setkeycreatecon(new_context)) {
+ warning("unable to set key creation context to %s", new_context);
+ if (enforcing)
+ return;
+ }
+
+#ifdef WITH_AUDIT
+ if (send_audit_message(1, old_context, new_context, user_ttypath))
+ return;
+#endif
+
+ /* We use the "spare" slot in argv to store sesh. */
+ --argv;
+ argv[0] = *argv[1] == '-' ? "-sesh" : "sesh";
+ argv[1] = path;
+
+ execv(_PATH_SUDO_SESH, argv);
+ warning("%s", path);
+}
+
+/*
+ * If the program is being run with a different security context we
+ * need to go through an intermediary process for the transition to
+ * be allowed by the policy. We use the "sesh" shell for this, which
+ * will simply execute the command pass to it on the command line.
+ */
+void
+selinux_exec(char *role, char *type, char **argv)
+{
+ pid_t childPid;
+ int enforcing, ttyfd;
+
+ /* Must have a tty. */
+ if (user_ttypath == NULL || *user_ttypath == '\0')
+ error(EXIT_FAILURE, "unable to determine tty");
+
+ /* Re-open TTY descriptor */
+ ttyfd = open(user_ttypath, O_RDWR | O_NONBLOCK);
+ if (ttyfd == -1)
+ error(EXIT_FAILURE, "unable to open %s", user_ttypath);
+ (void)fcntl(ttyfd, F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NONBLOCK);
+
+ /*
+ * Get the old and new security and tty contexts, sets the new
+ * tty context on ttyfd.
+ */
+ selinux_prefork(role, type, ttyfd);
childPid = fork();
if (childPid < 0) {
if (ttyfd != STDERR_FILENO)
goto error;
- if (setexeccon(new_context)) {
- warning("unable to set exec context to %s", new_context);
- if (enforcing)
- goto error;
- }
-
- if (setkeycreatecon(new_context)) {
- warning("unable to set key creation context to %s", new_context);
- if (enforcing)
- goto error;
- }
-
-#ifdef WITH_AUDIT
- if (send_audit_message(1, old_context, new_context, user_ttypath))
- goto error;
-#endif
-
- /* We use the "spare" slot in argv to store sesh. */
- --argv;
- argv[0] = login_shell ? "-sesh" : "sesh";
- argv[1] = safe_cmnd;
-
- execv(_PATH_SUDO_SESH, argv);
- warning("%s", safe_cmnd);
+ selinux_execv(safe_cmnd, argv);
error:
_exit(EXIT_FAILURE);