mirror of
https://github.com/sudo-project/sudo.git
synced 2025-08-28 21:07:55 +00:00
Add support for logging stdin when it is not a tty.
There is still a bug where "cat | sudo cat" has problems because both cat and sudo are trying to read from the tty.
This commit is contained in:
parent
782f494003
commit
b4d16ae1af
93
src/script.c
93
src/script.c
@ -432,7 +432,7 @@ script_execve(struct command_details *details, char *argv[], char *envp[],
|
|||||||
sigaction_t sa;
|
sigaction_t sa;
|
||||||
struct io_buffer *iob, *iobufs = NULL;
|
struct io_buffer *iob, *iobufs = NULL;
|
||||||
int n, nready;
|
int n, nready;
|
||||||
int pv[2], sv[2];
|
int io_pipe[3][2], sv[2];
|
||||||
fd_set *fdsr, *fdsw;
|
fd_set *fdsr, *fdsw;
|
||||||
int rbac_enabled = 0;
|
int rbac_enabled = 0;
|
||||||
int log_io, maxfd;
|
int log_io, maxfd;
|
||||||
@ -501,12 +501,7 @@ script_execve(struct command_details *details, char *argv[], char *envp[],
|
|||||||
/*
|
/*
|
||||||
* Setup stdin/stdout/stderr for child, to be duped after forking.
|
* Setup stdin/stdout/stderr for child, to be duped after forking.
|
||||||
*/
|
*/
|
||||||
#ifdef notyet
|
|
||||||
script_fds[SFD_STDIN] = script_fds[SFD_SLAVE];
|
script_fds[SFD_STDIN] = script_fds[SFD_SLAVE];
|
||||||
#else
|
|
||||||
script_fds[SFD_STDIN] = isatty(STDIN_FILENO) ?
|
|
||||||
script_fds[SFD_SLAVE] : STDIN_FILENO;
|
|
||||||
#endif
|
|
||||||
script_fds[SFD_STDOUT] = script_fds[SFD_SLAVE];
|
script_fds[SFD_STDOUT] = script_fds[SFD_SLAVE];
|
||||||
script_fds[SFD_STDERR] = script_fds[SFD_SLAVE];
|
script_fds[SFD_STDERR] = script_fds[SFD_SLAVE];
|
||||||
|
|
||||||
@ -522,26 +517,28 @@ script_execve(struct command_details *details, char *argv[], char *envp[],
|
|||||||
* If either stdin, stdout or stderr is not a tty we use a pipe
|
* If either stdin, stdout or stderr is not a tty we use a pipe
|
||||||
* to interpose ourselves instead of duping the pty fd.
|
* to interpose ourselves instead of duping the pty fd.
|
||||||
*/
|
*/
|
||||||
#ifdef notyet
|
memset(io_pipe, 0, sizeof(io_pipe));
|
||||||
if (!isatty(STDIN_FILENO)) {
|
if (!isatty(STDIN_FILENO)) {
|
||||||
if (pipe(pv) != 0)
|
if (pipe(io_pipe[STDIN_FILENO]) != 0)
|
||||||
error(1, "unable to create pipe");
|
error(1, "unable to create pipe");
|
||||||
iobufs = io_buf_new(STDIN_FILENO, pv[1], log_stdin, iobufs);
|
iobufs = io_buf_new(STDIN_FILENO, io_pipe[STDIN_FILENO][1],
|
||||||
script_fds[SFD_STDIN] = pv[0];
|
log_stdin, iobufs);
|
||||||
|
script_fds[SFD_STDIN] = io_pipe[STDIN_FILENO][0];
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
if (!isatty(STDOUT_FILENO)) {
|
if (!isatty(STDOUT_FILENO)) {
|
||||||
ttyout = FALSE;
|
ttyout = FALSE;
|
||||||
if (pipe(pv) != 0)
|
if (pipe(io_pipe[STDOUT_FILENO]) != 0)
|
||||||
error(1, "unable to create pipe");
|
error(1, "unable to create pipe");
|
||||||
iobufs = io_buf_new(pv[0], STDOUT_FILENO, log_stdout, iobufs);
|
iobufs = io_buf_new(io_pipe[STDOUT_FILENO][0], STDOUT_FILENO,
|
||||||
script_fds[SFD_STDOUT] = pv[1];
|
log_stdout, iobufs);
|
||||||
|
script_fds[SFD_STDOUT] = io_pipe[STDOUT_FILENO][1];
|
||||||
}
|
}
|
||||||
if (!isatty(STDERR_FILENO)) {
|
if (!isatty(STDERR_FILENO)) {
|
||||||
if (pipe(pv) != 0)
|
if (pipe(io_pipe[STDERR_FILENO]) != 0)
|
||||||
error(1, "unable to create pipe");
|
error(1, "unable to create pipe");
|
||||||
iobufs = io_buf_new(pv[0], STDERR_FILENO, log_stderr, iobufs);
|
iobufs = io_buf_new(io_pipe[STDERR_FILENO][0], STDERR_FILENO,
|
||||||
script_fds[SFD_STDERR] = pv[1];
|
log_stderr, iobufs);
|
||||||
|
script_fds[SFD_STDERR] = io_pipe[STDERR_FILENO][1];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Job control signals to relay from parent to child. */
|
/* Job control signals to relay from parent to child. */
|
||||||
@ -586,9 +583,16 @@ script_execve(struct command_details *details, char *argv[], char *envp[],
|
|||||||
fcntl(sv[1], F_SETFD, FD_CLOEXEC);
|
fcntl(sv[1], F_SETFD, FD_CLOEXEC);
|
||||||
if (exec_setup(details) == 0) {
|
if (exec_setup(details) == 0) {
|
||||||
/* headed for execve() */
|
/* headed for execve() */
|
||||||
if (log_io)
|
if (log_io) {
|
||||||
|
/* Close the other end of the stdin/stdout/stderr pipes. */
|
||||||
|
if (io_pipe[STDIN_FILENO][1])
|
||||||
|
close(io_pipe[STDIN_FILENO][1]);
|
||||||
|
if (io_pipe[STDOUT_FILENO][0])
|
||||||
|
close(io_pipe[STDOUT_FILENO][0]);
|
||||||
|
if (io_pipe[STDERR_FILENO][0])
|
||||||
|
close(io_pipe[STDERR_FILENO][0]);
|
||||||
script_child(details->command, argv, envp, sv[1], rbac_enabled);
|
script_child(details->command, argv, envp, sv[1], rbac_enabled);
|
||||||
else {
|
} else {
|
||||||
#ifdef HAVE_SELINUX
|
#ifdef HAVE_SELINUX
|
||||||
if (rbac_enabled)
|
if (rbac_enabled)
|
||||||
selinux_execve(details->command, argv, envp);
|
selinux_execve(details->command, argv, envp);
|
||||||
@ -612,11 +616,13 @@ script_execve(struct command_details *details, char *argv[], char *envp[],
|
|||||||
maxfd = sv[0];
|
maxfd = sv[0];
|
||||||
|
|
||||||
if (log_io) {
|
if (log_io) {
|
||||||
/* Close the writer end of the stdout/stderr pipes. */
|
/* Close the other end of the stdin/stdout/stderr pipes. */
|
||||||
if (script_fds[SFD_STDOUT] != script_fds[SFD_SLAVE])
|
if (io_pipe[STDIN_FILENO][0])
|
||||||
close(script_fds[SFD_STDOUT]);
|
close(io_pipe[STDIN_FILENO][0]);
|
||||||
if (script_fds[SFD_STDERR] != script_fds[SFD_SLAVE])
|
if (io_pipe[STDOUT_FILENO][1])
|
||||||
close(script_fds[SFD_STDERR]);
|
close(io_pipe[STDOUT_FILENO][1]);
|
||||||
|
if (io_pipe[STDERR_FILENO][1])
|
||||||
|
close(io_pipe[STDERR_FILENO][1]);
|
||||||
|
|
||||||
for (iob = iobufs; iob; iob = iob->next) {
|
for (iob = iobufs; iob; iob = iob->next) {
|
||||||
/* Determine maxfd */
|
/* Determine maxfd */
|
||||||
@ -668,14 +674,14 @@ script_execve(struct command_details *details, char *argv[], char *envp[],
|
|||||||
|
|
||||||
FD_SET(sv[0], fdsr);
|
FD_SET(sv[0], fdsr);
|
||||||
for (iob = iobufs; iob; iob = iob->next) {
|
for (iob = iobufs; iob; iob = iob->next) {
|
||||||
if (iob->off == iob->len)
|
|
||||||
iob->off = iob->len = 0;
|
|
||||||
/* Don't read/write /dev/tty if we are not in the foreground. */
|
/* Don't read/write /dev/tty if we are not in the foreground. */
|
||||||
if (ttymode == TERM_RAW || iob->rfd != script_fds[SFD_USERTTY]) {
|
if (iob->rfd != -1 &&
|
||||||
|
(ttymode == TERM_RAW || iob->rfd != script_fds[SFD_USERTTY])) {
|
||||||
if (iob->len != sizeof(iob->buf))
|
if (iob->len != sizeof(iob->buf))
|
||||||
FD_SET(iob->rfd, fdsr);
|
FD_SET(iob->rfd, fdsr);
|
||||||
}
|
}
|
||||||
if (ttymode == TERM_RAW || iob->wfd != script_fds[SFD_USERTTY]) {
|
if (iob->wfd != -1 &&
|
||||||
|
(ttymode == TERM_RAW || iob->wfd != script_fds[SFD_USERTTY])) {
|
||||||
if (iob->len > iob->off)
|
if (iob->len > iob->off)
|
||||||
FD_SET(iob->wfd, fdsw);
|
FD_SET(iob->wfd, fdsw);
|
||||||
}
|
}
|
||||||
@ -751,7 +757,7 @@ script_execve(struct command_details *details, char *argv[], char *envp[],
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (iob = iobufs; iob; iob = iob->next) {
|
for (iob = iobufs; iob; iob = iob->next) {
|
||||||
if (FD_ISSET(iob->rfd, fdsr)) {
|
if (iob->rfd != -1 && FD_ISSET(iob->rfd, fdsr)) {
|
||||||
n = read(iob->rfd, iob->buf + iob->len,
|
n = read(iob->rfd, iob->buf + iob->len,
|
||||||
sizeof(iob->buf) - iob->len);
|
sizeof(iob->buf) - iob->len);
|
||||||
if (n == -1) {
|
if (n == -1) {
|
||||||
@ -759,15 +765,17 @@ script_execve(struct command_details *details, char *argv[], char *envp[],
|
|||||||
goto retry;
|
goto retry;
|
||||||
if (errno != EAGAIN)
|
if (errno != EAGAIN)
|
||||||
goto io_error;
|
goto io_error;
|
||||||
|
} else if (n == 0) {
|
||||||
|
/* got EOF */
|
||||||
|
close(iob->rfd);
|
||||||
|
iob->rfd = -1;
|
||||||
} else {
|
} else {
|
||||||
if (n == 0)
|
|
||||||
break; /* got EOF */
|
|
||||||
if (!iob->action(iob->buf + iob->len, n))
|
if (!iob->action(iob->buf + iob->len, n))
|
||||||
terminate_child(child, TRUE);
|
terminate_child(child, TRUE);
|
||||||
iob->len += n;
|
iob->len += n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (FD_ISSET(iob->wfd, fdsw)) {
|
if (iob->wfd != -1 && FD_ISSET(iob->wfd, fdsw)) {
|
||||||
n = write(iob->wfd, iob->buf + iob->off,
|
n = write(iob->wfd, iob->buf + iob->off,
|
||||||
iob->len - iob->off);
|
iob->len - iob->off);
|
||||||
if (n == -1) {
|
if (n == -1) {
|
||||||
@ -778,6 +786,14 @@ script_execve(struct command_details *details, char *argv[], char *envp[],
|
|||||||
} else {
|
} else {
|
||||||
iob->off += n;
|
iob->off += n;
|
||||||
}
|
}
|
||||||
|
if (iob->off == iob->len) {
|
||||||
|
iob->off = iob->len = 0;
|
||||||
|
/* Forward the EOF from reader to writer. */
|
||||||
|
if (iob->rfd == -1) {
|
||||||
|
close(iob->wfd);
|
||||||
|
iob->wfd = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -973,15 +989,14 @@ script_child(const char *path, char *argv[], char *envp[], int backchannel, int
|
|||||||
}
|
}
|
||||||
close(errpipe[1]);
|
close(errpipe[1]);
|
||||||
|
|
||||||
#ifdef notyet
|
|
||||||
/* If any of stdin/stdout/stderr are pipes, close them in parent. */
|
/* If any of stdin/stdout/stderr are pipes, close them in parent. */
|
||||||
|
/* XXX - close other end too */
|
||||||
if (script_fds[SFD_STDIN] != script_fds[SFD_SLAVE])
|
if (script_fds[SFD_STDIN] != script_fds[SFD_SLAVE])
|
||||||
close(script_fds[SFD_STDIN]);
|
close(script_fds[SFD_STDIN]);
|
||||||
if (script_fds[SFD_STDOUT] != script_fds[SFD_SLAVE])
|
if (script_fds[SFD_STDOUT] != script_fds[SFD_SLAVE])
|
||||||
close(script_fds[SFD_STDOUT]);
|
close(script_fds[SFD_STDOUT]);
|
||||||
if (script_fds[SFD_STDERR] != script_fds[SFD_SLAVE])
|
if (script_fds[SFD_STDERR] != script_fds[SFD_SLAVE])
|
||||||
close(script_fds[SFD_STDERR]);
|
close(script_fds[SFD_STDERR]);
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Put child in its own process group. If we are starting the command
|
* Put child in its own process group. If we are starting the command
|
||||||
@ -1094,6 +1109,7 @@ bad:
|
|||||||
return errno;
|
return errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* XXX - should use select in poll mode to flush things */
|
||||||
static void
|
static void
|
||||||
flush_output(struct io_buffer *iobufs)
|
flush_output(struct io_buffer *iobufs)
|
||||||
{
|
{
|
||||||
@ -1102,19 +1118,24 @@ flush_output(struct io_buffer *iobufs)
|
|||||||
|
|
||||||
/* Drain output buffers. */
|
/* Drain output buffers. */
|
||||||
for (iob = iobufs; iob; iob = iob->next) {
|
for (iob = iobufs; iob; iob = iob->next) {
|
||||||
/* XXX - check wfd against slave instead? */
|
if (iob->wfd == -1 && iob->wfd == script_fds[SFD_SLAVE])
|
||||||
if (iob->rfd == script_fds[SFD_USERTTY])
|
|
||||||
continue;
|
continue;
|
||||||
while (iob->len > iob->off) {
|
while (iob->len > iob->off) {
|
||||||
n = write(iob->wfd, iob->buf + iob->off, iob->len - iob->off);
|
n = write(iob->wfd, iob->buf + iob->off, iob->len - iob->off);
|
||||||
if (n <= 0)
|
if (n <= 0)
|
||||||
break;
|
break;
|
||||||
iob->off += n;
|
iob->off += n;
|
||||||
|
if (iob->rfd == -1) {
|
||||||
|
close(iob->wfd);
|
||||||
|
iob->wfd = -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure there is no output remaining on the master pty or in pipes. */
|
/* Make sure there is no output remaining on the master pty or in pipes. */
|
||||||
for (iob = iobufs; iob; iob = iob->next) {
|
for (iob = iobufs; iob; iob = iob->next) {
|
||||||
|
if (iob->rfd == -1 || iob->wfd == -1) /* XXX */
|
||||||
|
continue;
|
||||||
if (iob->rfd == script_fds[SFD_USERTTY])
|
if (iob->rfd == script_fds[SFD_USERTTY])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user