Add separate I/O logging functions for tty in/out and stdin/stdout/stderr.
NOTE: stdin logging does not currently work and is disabled for now.
This commit is contained in:
@@ -80,8 +80,11 @@ struct io_plugin {
|
|||||||
char * const user_info[], char * const user_env[]);
|
char * const user_info[], char * const user_env[]);
|
||||||
void (*close)(int exit_status, int error); /* wait status or error */
|
void (*close)(int exit_status, int error); /* wait status or error */
|
||||||
int (*show_version)(int verbose);
|
int (*show_version)(int verbose);
|
||||||
int (*log_input)(const char *buf, unsigned int len);
|
int (*log_ttyin)(const char *buf, unsigned int len);
|
||||||
int (*log_output)(const char *buf, unsigned int len);
|
int (*log_ttyout)(const char *buf, unsigned int len);
|
||||||
|
int (*log_stdin)(const char *buf, unsigned int len);
|
||||||
|
int (*log_stdout)(const char *buf, unsigned int len);
|
||||||
|
int (*log_stderr)(const char *buf, unsigned int len);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Internal use only */
|
/* Internal use only */
|
||||||
|
@@ -349,12 +349,19 @@ struct policy_plugin sample_policy = {
|
|||||||
NULL /* invalidate */
|
NULL /* invalidate */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note: This plugin does not differentiate between tty and pipe I/O.
|
||||||
|
* It all gets logged to the same file.
|
||||||
|
*/
|
||||||
struct io_plugin sample_io = {
|
struct io_plugin sample_io = {
|
||||||
SUDO_IO_PLUGIN,
|
SUDO_IO_PLUGIN,
|
||||||
SUDO_API_VERSION,
|
SUDO_API_VERSION,
|
||||||
io_open,
|
io_open,
|
||||||
io_close,
|
io_close,
|
||||||
io_version,
|
io_version,
|
||||||
io_log_input,
|
io_log_input, /* tty input */
|
||||||
io_log_output
|
io_log_output, /* tty output */
|
||||||
|
io_log_input, /* command stdin if not tty */
|
||||||
|
io_log_output, /* command stdout if not tty */
|
||||||
|
io_log_output /* command stderr if not tty */
|
||||||
};
|
};
|
||||||
|
@@ -1313,6 +1313,9 @@ struct io_plugin sudoers_io = {
|
|||||||
sudoers_io_open,
|
sudoers_io_open,
|
||||||
sudoers_io_close,
|
sudoers_io_close,
|
||||||
sudoers_io_version,
|
sudoers_io_version,
|
||||||
NULL,
|
NULL, /* log_ttyin */
|
||||||
sudoers_io_log_output
|
sudoers_io_log_output, /* log_ttyout */
|
||||||
|
NULL, /* log_stdin */
|
||||||
|
sudoers_io_log_output, /* log_stdout */
|
||||||
|
sudoers_io_log_output /* log_stderr */
|
||||||
};
|
};
|
||||||
|
130
src/script.c
130
src/script.c
@@ -146,9 +146,9 @@ script_setup(uid_t uid)
|
|||||||
error(1, "Can't get pty");
|
error(1, "Can't get pty");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Call I/O plugin input method. */
|
/* Call I/O plugin tty input log method. */
|
||||||
static int
|
static int
|
||||||
log_input(char *buf, unsigned int n)
|
log_ttyin(char *buf, unsigned int n)
|
||||||
{
|
{
|
||||||
struct plugin_container *plugin;
|
struct plugin_container *plugin;
|
||||||
sigset_t omask;
|
sigset_t omask;
|
||||||
@@ -157,8 +157,8 @@ log_input(char *buf, unsigned int n)
|
|||||||
sigprocmask(SIG_BLOCK, &ttyblock, &omask);
|
sigprocmask(SIG_BLOCK, &ttyblock, &omask);
|
||||||
|
|
||||||
tq_foreach_fwd(&io_plugins, plugin) {
|
tq_foreach_fwd(&io_plugins, plugin) {
|
||||||
if (plugin->u.io->log_input) {
|
if (plugin->u.io->log_ttyin) {
|
||||||
if (!plugin->u.io->log_input(buf, n)) {
|
if (!plugin->u.io->log_ttyin(buf, n)) {
|
||||||
rval = FALSE;
|
rval = FALSE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -169,9 +169,9 @@ log_input(char *buf, unsigned int n)
|
|||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Call I/O plugin output method. */
|
/* Call I/O plugin stdin log method. */
|
||||||
static int
|
static int
|
||||||
log_output(char *buf, unsigned int n)
|
log_stdin(char *buf, unsigned int n)
|
||||||
{
|
{
|
||||||
struct plugin_container *plugin;
|
struct plugin_container *plugin;
|
||||||
sigset_t omask;
|
sigset_t omask;
|
||||||
@@ -180,8 +180,77 @@ log_output(char *buf, unsigned int n)
|
|||||||
sigprocmask(SIG_BLOCK, &ttyblock, &omask);
|
sigprocmask(SIG_BLOCK, &ttyblock, &omask);
|
||||||
|
|
||||||
tq_foreach_fwd(&io_plugins, plugin) {
|
tq_foreach_fwd(&io_plugins, plugin) {
|
||||||
if (plugin->u.io->log_output) {
|
if (plugin->u.io->log_stdin) {
|
||||||
if (!plugin->u.io->log_output(buf, n)) {
|
if (!plugin->u.io->log_stdin(buf, n)) {
|
||||||
|
rval = FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sigprocmask(SIG_SETMASK, &omask, NULL);
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Call I/O plugin tty output log method. */
|
||||||
|
static int
|
||||||
|
log_ttyout(char *buf, unsigned int n)
|
||||||
|
{
|
||||||
|
struct plugin_container *plugin;
|
||||||
|
sigset_t omask;
|
||||||
|
int rval = TRUE;
|
||||||
|
|
||||||
|
sigprocmask(SIG_BLOCK, &ttyblock, &omask);
|
||||||
|
|
||||||
|
tq_foreach_fwd(&io_plugins, plugin) {
|
||||||
|
if (plugin->u.io->log_ttyout) {
|
||||||
|
if (!plugin->u.io->log_ttyout(buf, n)) {
|
||||||
|
rval = FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sigprocmask(SIG_SETMASK, &omask, NULL);
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Call I/O plugin stdout log method. */
|
||||||
|
static int
|
||||||
|
log_stdout(char *buf, unsigned int n)
|
||||||
|
{
|
||||||
|
struct plugin_container *plugin;
|
||||||
|
sigset_t omask;
|
||||||
|
int rval = TRUE;
|
||||||
|
|
||||||
|
sigprocmask(SIG_BLOCK, &ttyblock, &omask);
|
||||||
|
|
||||||
|
tq_foreach_fwd(&io_plugins, plugin) {
|
||||||
|
if (plugin->u.io->log_stdout) {
|
||||||
|
if (!plugin->u.io->log_stdout(buf, n)) {
|
||||||
|
rval = FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sigprocmask(SIG_SETMASK, &omask, NULL);
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Call I/O plugin stderr log method. */
|
||||||
|
static int
|
||||||
|
log_stderr(char *buf, unsigned int n)
|
||||||
|
{
|
||||||
|
struct plugin_container *plugin;
|
||||||
|
sigset_t omask;
|
||||||
|
int rval = TRUE;
|
||||||
|
|
||||||
|
sigprocmask(SIG_BLOCK, &ttyblock, &omask);
|
||||||
|
|
||||||
|
tq_foreach_fwd(&io_plugins, plugin) {
|
||||||
|
if (plugin->u.io->log_stderr) {
|
||||||
|
if (!plugin->u.io->log_stderr(buf, n)) {
|
||||||
rval = FALSE;
|
rval = FALSE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -432,36 +501,46 @@ 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.
|
||||||
*/
|
*/
|
||||||
/* XXX - use a pipe for stdin if not a tty? */
|
#ifdef notyet
|
||||||
|
script_fds[SFD_STDIN] = script_fds[SFD_SLAVE];
|
||||||
|
#else
|
||||||
script_fds[SFD_STDIN] = isatty(STDIN_FILENO) ?
|
script_fds[SFD_STDIN] = isatty(STDIN_FILENO) ?
|
||||||
script_fds[SFD_SLAVE] : 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];
|
||||||
|
|
||||||
/* Copy /dev/tty -> pty master */
|
/* Copy /dev/tty -> pty master */
|
||||||
iobufs = io_buf_new(script_fds[SFD_USERTTY], script_fds[SFD_MASTER],
|
iobufs = io_buf_new(script_fds[SFD_USERTTY], script_fds[SFD_MASTER],
|
||||||
log_input, iobufs);
|
log_ttyin, iobufs);
|
||||||
|
|
||||||
/* Copy pty master -> /dev/tty */
|
/* Copy pty master -> /dev/tty */
|
||||||
iobufs = io_buf_new(script_fds[SFD_MASTER], script_fds[SFD_USERTTY],
|
iobufs = io_buf_new(script_fds[SFD_MASTER], script_fds[SFD_USERTTY],
|
||||||
log_output, iobufs);
|
log_ttyout, iobufs);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If either 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.
|
||||||
* NOTE: we don't currently log tty/stdout/stderr separately.
|
|
||||||
*/
|
*/
|
||||||
|
#ifdef notyet
|
||||||
|
if (!isatty(STDIN_FILENO)) {
|
||||||
|
if (pipe(pv) != 0)
|
||||||
|
error(1, "unable to create pipe");
|
||||||
|
iobufs = io_buf_new(STDIN_FILENO, pv[1], log_stdin, iobufs);
|
||||||
|
script_fds[SFD_STDIN] = pv[0];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (!isatty(STDOUT_FILENO)) {
|
if (!isatty(STDOUT_FILENO)) {
|
||||||
ttyout = FALSE;
|
ttyout = FALSE;
|
||||||
if (pipe(pv) != 0)
|
if (pipe(pv) != 0)
|
||||||
error(1, "unable to create pipe");
|
error(1, "unable to create pipe");
|
||||||
iobufs = io_buf_new(pv[0], STDOUT_FILENO, log_output, iobufs);
|
iobufs = io_buf_new(pv[0], STDOUT_FILENO, log_stdout, iobufs);
|
||||||
script_fds[SFD_STDOUT] = pv[1];
|
script_fds[SFD_STDOUT] = pv[1];
|
||||||
}
|
}
|
||||||
if (!isatty(STDERR_FILENO)) {
|
if (!isatty(STDERR_FILENO)) {
|
||||||
if (pipe(pv) != 0)
|
if (pipe(pv) != 0)
|
||||||
error(1, "unable to create pipe");
|
error(1, "unable to create pipe");
|
||||||
iobufs = io_buf_new(pv[0], STDERR_FILENO, log_output, iobufs);
|
iobufs = io_buf_new(pv[0], STDERR_FILENO, log_stderr, iobufs);
|
||||||
script_fds[SFD_STDERR] = pv[1];
|
script_fds[SFD_STDERR] = pv[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -617,6 +696,7 @@ script_execve(struct command_details *details, char *argv[], char *envp[],
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
retry:
|
||||||
nready = select(maxfd + 1, fdsr, fdsw, NULL, NULL);
|
nready = select(maxfd + 1, fdsr, fdsw, NULL, NULL);
|
||||||
if (nready == -1) {
|
if (nready == -1) {
|
||||||
if (errno == EINTR)
|
if (errno == EINTR)
|
||||||
@@ -676,9 +756,9 @@ script_execve(struct command_details *details, char *argv[], char *envp[],
|
|||||||
sizeof(iob->buf) - iob->len);
|
sizeof(iob->buf) - iob->len);
|
||||||
if (n == -1) {
|
if (n == -1) {
|
||||||
if (errno == EINTR)
|
if (errno == EINTR)
|
||||||
continue;
|
goto retry;
|
||||||
if (errno != EAGAIN)
|
if (errno != EAGAIN)
|
||||||
break;
|
goto io_error;
|
||||||
} else {
|
} else {
|
||||||
if (n == 0)
|
if (n == 0)
|
||||||
break; /* got EOF */
|
break; /* got EOF */
|
||||||
@@ -692,9 +772,9 @@ script_execve(struct command_details *details, char *argv[], char *envp[],
|
|||||||
iob->len - iob->off);
|
iob->len - iob->off);
|
||||||
if (n == -1) {
|
if (n == -1) {
|
||||||
if (errno == EINTR)
|
if (errno == EINTR)
|
||||||
continue;
|
goto retry;
|
||||||
if (errno != EAGAIN)
|
if (errno != EAGAIN)
|
||||||
break;
|
goto io_error;
|
||||||
} else {
|
} else {
|
||||||
iob->off += n;
|
iob->off += n;
|
||||||
}
|
}
|
||||||
@@ -702,6 +782,7 @@ script_execve(struct command_details *details, char *argv[], char *envp[],
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
io_error:
|
||||||
if (log_io) {
|
if (log_io) {
|
||||||
/* Flush any remaining output (the plugin already got it) */
|
/* Flush any remaining output (the plugin already got it) */
|
||||||
n = fcntl(script_fds[SFD_USERTTY], F_GETFL, 0);
|
n = fcntl(script_fds[SFD_USERTTY], F_GETFL, 0);
|
||||||
@@ -892,6 +973,16 @@ 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 (script_fds[SFD_STDIN] != script_fds[SFD_SLAVE])
|
||||||
|
close(script_fds[SFD_STDIN]);
|
||||||
|
if (script_fds[SFD_STDOUT] != script_fds[SFD_SLAVE])
|
||||||
|
close(script_fds[SFD_STDOUT]);
|
||||||
|
if (script_fds[SFD_STDERR] != script_fds[SFD_SLAVE])
|
||||||
|
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
|
||||||
* in the foreground, assign its pgrp to the tty.
|
* in the foreground, assign its pgrp to the tty.
|
||||||
@@ -1011,6 +1102,7 @@ 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->rfd == script_fds[SFD_USERTTY])
|
if (iob->rfd == script_fds[SFD_USERTTY])
|
||||||
continue;
|
continue;
|
||||||
while (iob->len > iob->off) {
|
while (iob->len > iob->off) {
|
||||||
|
Reference in New Issue
Block a user