Make transcript mode work as long as we can figure out our tty, even if
it is not stdin. We'd like to use /dev/tty but that won't be valid after the setsid().
This commit is contained in:
57
script.c
57
script.c
@@ -67,6 +67,7 @@ __unused static const char rcsid[] = "$Sudo$";
|
|||||||
#define SFD_LOG 2
|
#define SFD_LOG 2
|
||||||
#define SFD_OUTPUT 3
|
#define SFD_OUTPUT 3
|
||||||
#define SFD_TIMING 4
|
#define SFD_TIMING 4
|
||||||
|
#define SFD_USERTTY 5
|
||||||
|
|
||||||
struct script_buf {
|
struct script_buf {
|
||||||
int len; /* buffer length (how much read in) */
|
int len; /* buffer length (how much read in) */
|
||||||
@@ -74,7 +75,7 @@ struct script_buf {
|
|||||||
char buf[16 * 1024];
|
char buf[16 * 1024];
|
||||||
};
|
};
|
||||||
|
|
||||||
static int script_fds[5];
|
static int script_fds[6];
|
||||||
|
|
||||||
static sig_atomic_t alive = 1;
|
static sig_atomic_t alive = 1;
|
||||||
static sig_atomic_t suspended = 0;
|
static sig_atomic_t suspended = 0;
|
||||||
@@ -222,19 +223,21 @@ script_setup()
|
|||||||
char pathbuf[PATH_MAX];
|
char pathbuf[PATH_MAX];
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
if (!isatty(STDIN_FILENO))
|
/* XXX - can't use _PATH_TTY here since it won't be valid in new session */
|
||||||
log_error(0, "Standard input is not a tty");
|
if (!user_ttypath ||
|
||||||
|
(script_fds[SFD_USERTTY] = open(user_ttypath, O_RDWR|O_NOCTTY, 0) == -1))
|
||||||
|
log_error(0, "tty required for transcript support"); /* XXX */
|
||||||
|
|
||||||
if (!get_pty(&script_fds[SFD_MASTER], &script_fds[SFD_SLAVE],
|
if (!get_pty(&script_fds[SFD_MASTER], &script_fds[SFD_SLAVE],
|
||||||
slavename, sizeof(slavename)))
|
slavename, sizeof(slavename)))
|
||||||
log_error(USE_ERRNO, "Can't get pty");
|
log_error(USE_ERRNO, "Can't get pty");
|
||||||
|
|
||||||
/* Copy terminal attrs from stdin -> pty slave. */
|
/* Copy terminal attrs from user tty -> pty slave. */
|
||||||
if (!term_copy(STDIN_FILENO, script_fds[SFD_SLAVE], 0))
|
if (!term_copy(script_fds[SFD_USERTTY], script_fds[SFD_SLAVE], 0))
|
||||||
log_error(USE_ERRNO, "Can't copy terminal attributes");
|
log_error(USE_ERRNO, "Can't copy terminal attributes");
|
||||||
sync_winsize(STDIN_FILENO, script_fds[SFD_SLAVE]);
|
sync_winsize(script_fds[SFD_USERTTY], script_fds[SFD_SLAVE]);
|
||||||
|
|
||||||
if (!term_raw(STDIN_FILENO, 1))
|
if (!term_raw(script_fds[SFD_USERTTY], 1))
|
||||||
log_error(USE_ERRNO, "Can't set terminal to raw mode");
|
log_error(USE_ERRNO, "Can't set terminal to raw mode");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -268,15 +271,15 @@ int
|
|||||||
script_duplow(fd)
|
script_duplow(fd)
|
||||||
int fd;
|
int fd;
|
||||||
{
|
{
|
||||||
int i, j, indices[5];
|
int i, j, indices[6];
|
||||||
|
|
||||||
/* sort fds so we can dup them safely */
|
/* sort fds so we can dup them safely */
|
||||||
for (i = 0; i < 5; i++)
|
for (i = 0; i < 6; i++)
|
||||||
indices[i] = i;
|
indices[i] = i;
|
||||||
qsort(indices, 5, sizeof(int), fdcompar);
|
qsort(indices, 6, sizeof(int), fdcompar);
|
||||||
|
|
||||||
/* Move pty master/slave and session fds to low numbered fds. */
|
/* Move pty master/slave and session fds to low numbered fds. */
|
||||||
for (i = 0; i < 5; i++) {
|
for (i = 0; i < 6; i++) {
|
||||||
j = indices[i];
|
j = indices[i];
|
||||||
if (script_fds[j] != fd) {
|
if (script_fds[j] != fd) {
|
||||||
#ifdef HAVE_DUP2
|
#ifdef HAVE_DUP2
|
||||||
@@ -395,7 +398,7 @@ script_execv(path, argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Restore old tty settings and signal handler. */
|
/* Restore old tty settings and signal handler. */
|
||||||
term_restore(STDIN_FILENO);
|
term_restore(script_fds[SFD_USERTTY]);
|
||||||
check_sig:
|
check_sig:
|
||||||
switch (signo) {
|
switch (signo) {
|
||||||
case SIGINT:
|
case SIGINT:
|
||||||
@@ -426,12 +429,12 @@ script_execv(path, argv)
|
|||||||
kill(parent, signo); /* re-send signal with handler disabled */
|
kill(parent, signo); /* re-send signal with handler disabled */
|
||||||
/* Reinstall signal handler, reset raw mode and continue child */
|
/* Reinstall signal handler, reset raw mode and continue child */
|
||||||
(void) sigaction(signo, &sa, NULL);
|
(void) sigaction(signo, &sa, NULL);
|
||||||
if (!term_raw(STDIN_FILENO, 1) && errno == EINTR)
|
if (!term_raw(script_fds[SFD_USERTTY], 1) && errno == EINTR)
|
||||||
goto check_sig;
|
goto check_sig;
|
||||||
kill(child, SIGCONT);
|
kill(child, SIGCONT);
|
||||||
}
|
}
|
||||||
|
|
||||||
term_restore(STDIN_FILENO);
|
term_restore(script_fds[SFD_USERTTY]);
|
||||||
|
|
||||||
exit(exitcode);
|
exit(exitcode);
|
||||||
}
|
}
|
||||||
@@ -534,10 +537,10 @@ script_child(path, argv)
|
|||||||
n |= O_NONBLOCK;
|
n |= O_NONBLOCK;
|
||||||
(void) fcntl(script_fds[SFD_MASTER], F_SETFL, n);
|
(void) fcntl(script_fds[SFD_MASTER], F_SETFL, n);
|
||||||
}
|
}
|
||||||
n = fcntl(STDIN_FILENO, F_GETFL, 0);
|
n = fcntl(script_fds[SFD_USERTTY], F_GETFL, 0);
|
||||||
if (n != -1) {
|
if (n != -1) {
|
||||||
n |= O_NONBLOCK;
|
n |= O_NONBLOCK;
|
||||||
(void) fcntl(STDIN_FILENO, F_SETFL, n);
|
(void) fcntl(script_fds[SFD_USERTTY], F_SETFL, n);
|
||||||
}
|
}
|
||||||
n = fcntl(STDOUT_FILENO, F_GETFL, 0);
|
n = fcntl(STDOUT_FILENO, F_GETFL, 0);
|
||||||
if (n != -1) {
|
if (n != -1) {
|
||||||
@@ -546,10 +549,9 @@ script_child(path, argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In the event loop we pass input from stdin to master
|
* In the event loop we pass input from user tty to master
|
||||||
* and pass output from master to stdout and ofile.
|
* and pass output from master to stdout and ofile. Note that
|
||||||
* Note that we've set things up such that master is above
|
* we've set things up such that master is > 3 (see sudo.c).
|
||||||
* stdin and stdout (see sudo.c).
|
|
||||||
*/
|
*/
|
||||||
fdsr = (fd_set *)emalloc2(howmany(script_fds[SFD_MASTER] + 1, NFDBITS),
|
fdsr = (fd_set *)emalloc2(howmany(script_fds[SFD_MASTER] + 1, NFDBITS),
|
||||||
sizeof(fd_mask));
|
sizeof(fd_mask));
|
||||||
@@ -566,7 +568,7 @@ script_child(path, argv)
|
|||||||
zero_bytes(fdsw, howmany(script_fds[SFD_MASTER] + 1, NFDBITS) * sizeof(fd_mask));
|
zero_bytes(fdsw, howmany(script_fds[SFD_MASTER] + 1, NFDBITS) * sizeof(fd_mask));
|
||||||
zero_bytes(fdsr, howmany(script_fds[SFD_MASTER] + 1, NFDBITS) * sizeof(fd_mask));
|
zero_bytes(fdsr, howmany(script_fds[SFD_MASTER] + 1, NFDBITS) * sizeof(fd_mask));
|
||||||
if (input.len != sizeof(input.buf))
|
if (input.len != sizeof(input.buf))
|
||||||
FD_SET(STDIN_FILENO, fdsr);
|
FD_SET(script_fds[SFD_USERTTY], fdsr);
|
||||||
if (output.len != sizeof(output.buf))
|
if (output.len != sizeof(output.buf))
|
||||||
FD_SET(script_fds[SFD_MASTER], fdsr);
|
FD_SET(script_fds[SFD_MASTER], fdsr);
|
||||||
if (output.len > output.off)
|
if (output.len > output.off)
|
||||||
@@ -590,8 +592,8 @@ script_child(path, argv)
|
|||||||
continue;
|
continue;
|
||||||
log_error(USE_ERRNO, "select failed");
|
log_error(USE_ERRNO, "select failed");
|
||||||
}
|
}
|
||||||
if (FD_ISSET(STDIN_FILENO, fdsr)) {
|
if (FD_ISSET(script_fds[SFD_USERTTY], fdsr)) {
|
||||||
n = read(STDIN_FILENO, input.buf + input.len,
|
n = read(script_fds[SFD_USERTTY], input.buf + input.len,
|
||||||
sizeof(input.buf) - input.len);
|
sizeof(input.buf) - input.len);
|
||||||
if (n == -1) {
|
if (n == -1) {
|
||||||
if (errno == EINTR)
|
if (errno == EINTR)
|
||||||
@@ -717,6 +719,10 @@ script_grandchild(path, argv, rbac_enabled)
|
|||||||
{
|
{
|
||||||
pid_t self = getpid();
|
pid_t self = getpid();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We have guaranteed that the slave fd > 3
|
||||||
|
*/
|
||||||
|
if (isatty(STDIN_FILENO))
|
||||||
dup2(script_fds[SFD_SLAVE], STDIN_FILENO);
|
dup2(script_fds[SFD_SLAVE], STDIN_FILENO);
|
||||||
dup2(script_fds[SFD_SLAVE], STDOUT_FILENO);
|
dup2(script_fds[SFD_SLAVE], STDOUT_FILENO);
|
||||||
dup2(script_fds[SFD_SLAVE], STDERR_FILENO);
|
dup2(script_fds[SFD_SLAVE], STDERR_FILENO);
|
||||||
@@ -729,9 +735,10 @@ script_grandchild(path, argv, rbac_enabled)
|
|||||||
close(script_fds[SFD_LOG]);
|
close(script_fds[SFD_LOG]);
|
||||||
close(script_fds[SFD_OUTPUT]);
|
close(script_fds[SFD_OUTPUT]);
|
||||||
close(script_fds[SFD_TIMING]);
|
close(script_fds[SFD_TIMING]);
|
||||||
|
close(script_fds[SFD_USERTTY]);
|
||||||
|
|
||||||
/* Spin until parent grants us the controlling pty */
|
/* Spin until parent grants us the controlling pty */
|
||||||
while (tcgetpgrp(STDIN_FILENO) != self)
|
while (tcgetpgrp(STDOUT_FILENO) != self)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
#ifdef HAVE_SELINUX
|
#ifdef HAVE_SELINUX
|
||||||
@@ -808,6 +815,6 @@ sigwinch(s)
|
|||||||
{
|
{
|
||||||
int serrno = errno;
|
int serrno = errno;
|
||||||
|
|
||||||
sync_winsize(STDIN_FILENO, script_fds[SFD_SLAVE]);
|
sync_winsize(script_fds[SFD_USERTTY], script_fds[SFD_SLAVE]);
|
||||||
errno = serrno;
|
errno = serrno;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user