diff --git a/src/exec_pty.c b/src/exec_pty.c index 7403506..56b2899 100644 --- a/src/exec_pty.c +++ b/src/exec_pty.c @@ -711,8 +711,10 @@ io_buf_new(int rfd, int wfd, int fork_pty(struct command_details *details, int sv[], sigset_t *omask) { + struct plugin_container *plugin; struct command_status cstat; - int io_pipe[3][2]; + int io_pipe[3][2] = { { -1, -1 }, { -1, -1 }, { -1, -1 } }; + bool interpose[3] = { false, false, false }; sigaction_t sa; sigset_t mask; pid_t child; @@ -738,6 +740,16 @@ fork_pty(struct command_details *details, int sv[], sigset_t *omask) sigaddset(&ttyblock, SIGTTIN); sigaddset(&ttyblock, SIGTTOU); + /* Determine whether any of std{in,out,err} should be logged. */ + TAILQ_FOREACH(plugin, &io_plugins, entries) { + if (plugin->u.io->log_stdin) + interpose[STDIN_FILENO] = true; + if (plugin->u.io->log_stdout) + interpose[STDOUT_FILENO] = true; + if (plugin->u.io->log_stderr) + interpose[STDERR_FILENO] = true; + } + /* * Setup stdin/stdout/stderr for child, to be duped after forking. * In background mode there is no stdin. @@ -763,35 +775,64 @@ fork_pty(struct command_details *details, int sv[], sigset_t *omask) } /* - * If either stdin, stdout or stderr is not a tty we use a pipe - * to interpose ourselves instead of duping the pty fd. + * If stdin, stdout or stderr is not a tty and logging is enabled, + * use a pipe to interpose ourselves instead of using the pty fd. */ - memset(io_pipe, 0, sizeof(io_pipe)); if (io_fds[SFD_STDIN] == -1 || !isatty(STDIN_FILENO)) { - sudo_debug_printf(SUDO_DEBUG_INFO, "stdin not a tty, creating a pipe"); - pipeline = true; - if (pipe(io_pipe[STDIN_FILENO]) != 0) - sudo_fatal(U_("unable to create pipe")); - io_buf_new(STDIN_FILENO, io_pipe[STDIN_FILENO][1], - log_stdin, &iobufs); - io_fds[SFD_STDIN] = io_pipe[STDIN_FILENO][0]; - } - if (io_fds[SFD_STDOUT] == -1 || !isatty(STDOUT_FILENO)) { - sudo_debug_printf(SUDO_DEBUG_INFO, "stdout not a tty, creating a pipe"); - pipeline = true; - if (pipe(io_pipe[STDOUT_FILENO]) != 0) - sudo_fatal(U_("unable to create pipe")); - io_buf_new(io_pipe[STDOUT_FILENO][0], STDOUT_FILENO, - log_stdout, &iobufs); - io_fds[SFD_STDOUT] = io_pipe[STDOUT_FILENO][1]; - } - if (io_fds[SFD_STDERR] == -1 || !isatty(STDERR_FILENO)) { - sudo_debug_printf(SUDO_DEBUG_INFO, "stderr not a tty, creating a pipe"); - if (pipe(io_pipe[STDERR_FILENO]) != 0) - sudo_fatal(U_("unable to create pipe")); - io_buf_new(io_pipe[STDERR_FILENO][0], STDERR_FILENO, - log_stderr, &iobufs); - io_fds[SFD_STDERR] = io_pipe[STDERR_FILENO][1]; + if (!interpose[STDIN_FILENO]) { + /* Not logging stdin, do not interpose. */ + sudo_debug_printf(SUDO_DEBUG_INFO, + "stdin not a tty, not logging"); + io_fds[SFD_STDIN] = dup(STDIN_FILENO); + if (io_fds[SFD_STDIN] == -1) + sudo_fatal("dup"); + } else { + sudo_debug_printf(SUDO_DEBUG_INFO, + "stdin not a tty, creating a pipe"); + pipeline = true; + if (pipe(io_pipe[STDIN_FILENO]) != 0) + sudo_fatal(U_("unable to create pipe")); + io_buf_new(STDIN_FILENO, io_pipe[STDIN_FILENO][1], + log_stdin, &iobufs); + io_fds[SFD_STDIN] = io_pipe[STDIN_FILENO][0]; + } + } + if (io_fds[SFD_STDOUT] == -1 || !isatty(STDOUT_FILENO)) { + if (!interpose[STDOUT_FILENO]) { + /* Not logging stdout, do not interpose. */ + sudo_debug_printf(SUDO_DEBUG_INFO, + "stdout not a tty, not logging"); + io_fds[SFD_STDOUT] = dup(STDOUT_FILENO); + if (io_fds[SFD_STDOUT] == -1) + sudo_fatal("dup"); + } else { + sudo_debug_printf(SUDO_DEBUG_INFO, + "stdout not a tty, creating a pipe"); + pipeline = true; + if (pipe(io_pipe[STDOUT_FILENO]) != 0) + sudo_fatal(U_("unable to create pipe")); + io_buf_new(io_pipe[STDOUT_FILENO][0], STDOUT_FILENO, + log_stdout, &iobufs); + io_fds[SFD_STDOUT] = io_pipe[STDOUT_FILENO][1]; + } + } + if (io_fds[SFD_STDERR] == -1 || !isatty(STDERR_FILENO)) { + if (!interpose[STDERR_FILENO]) { + /* Not logging stderr, do not interpose. */ + sudo_debug_printf(SUDO_DEBUG_INFO, + "stderr not a tty, not logging"); + io_fds[SFD_STDERR] = dup(STDERR_FILENO); + if (io_fds[SFD_STDERR] == -1) + sudo_fatal("dup"); + } else { + sudo_debug_printf(SUDO_DEBUG_INFO, + "stderr not a tty, creating a pipe"); + if (pipe(io_pipe[STDERR_FILENO]) != 0) + sudo_fatal(U_("unable to create pipe")); + io_buf_new(io_pipe[STDERR_FILENO][0], STDERR_FILENO, + log_stderr, &iobufs); + io_fds[SFD_STDERR] = io_pipe[STDERR_FILENO][1]; + } } /* We don't want to receive SIGTTIN/SIGTTOU, getting EIO is preferable. */ @@ -1549,10 +1590,24 @@ exec_pty(struct command_details *details, setpgid(0, self); /* Wire up standard fds, note that stdout/stderr may be pipes. */ - if (dup2(io_fds[SFD_STDIN], STDIN_FILENO) == -1 || - dup2(io_fds[SFD_STDOUT], STDOUT_FILENO) == -1 || - dup2(io_fds[SFD_STDERR], STDERR_FILENO) == -1) - sudo_fatal("dup2"); + if (io_fds[SFD_STDIN] != STDIN_FILENO) { + if (dup2(io_fds[SFD_STDIN], STDIN_FILENO) == -1) + sudo_fatal("dup2"); + if (io_fds[SFD_STDIN] != io_fds[SFD_SLAVE]) + close(io_fds[SFD_STDIN]); + } + if (io_fds[SFD_STDOUT] != STDOUT_FILENO) { + if (dup2(io_fds[SFD_STDOUT], STDOUT_FILENO) == -1) + sudo_fatal("dup2"); + if (io_fds[SFD_STDOUT] != io_fds[SFD_SLAVE]) + close(io_fds[SFD_STDOUT]); + } + if (io_fds[SFD_STDERR] != STDERR_FILENO) { + if (dup2(io_fds[SFD_STDERR], STDERR_FILENO) == -1) + sudo_fatal("dup2"); + if (io_fds[SFD_STDERR] != io_fds[SFD_SLAVE]) + close(io_fds[SFD_STDERR]); + } /* Wait for parent to grant us the tty if we are foreground. */ if (foreground && !ISSET(details->flags, CD_EXEC_BG)) { @@ -1561,15 +1616,9 @@ exec_pty(struct command_details *details, nanosleep(&ts, NULL); } - /* We have guaranteed that the slave fd is > 2 */ + /* Done with the pty slave, don't leak it. */ if (io_fds[SFD_SLAVE] != -1) close(io_fds[SFD_SLAVE]); - if (io_fds[SFD_STDIN] != io_fds[SFD_SLAVE]) - close(io_fds[SFD_STDIN]); - if (io_fds[SFD_STDOUT] != io_fds[SFD_SLAVE]) - close(io_fds[SFD_STDOUT]); - if (io_fds[SFD_STDERR] != io_fds[SFD_SLAVE]) - close(io_fds[SFD_STDERR]); /* Execute command; only returns on error. */ exec_cmnd(details, cstat, errfd);