From: Todd C. Miller Date: Tue, 3 Sep 2013 15:22:44 +0000 (-0600) Subject: Repair writing of the I/O log file indices broken in sudo 1.8.7. X-Git-Tag: SUDO_1_8_8^2~18 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=422115d728ae97eda932e980fd4ad0fa179811a0;p=sudo Repair writing of the I/O log file indices broken in sudo 1.8.7. --- diff --git a/MANIFEST b/MANIFEST index 0a7c4b0ae..fb2d90f62 100644 --- a/MANIFEST +++ b/MANIFEST @@ -219,6 +219,7 @@ plugins/sudoers/insults.h plugins/sudoers/interfaces.c plugins/sudoers/interfaces.h plugins/sudoers/iolog.c +plugins/sudoers/iolog.h plugins/sudoers/iolog_path.c plugins/sudoers/ldap.c plugins/sudoers/linux_audit.c diff --git a/plugins/sudoers/iolog.c b/plugins/sudoers/iolog.c index af7fcac84..57b2026b4 100644 --- a/plugins/sudoers/iolog.c +++ b/plugins/sudoers/iolog.c @@ -50,6 +50,7 @@ #endif #include "sudoers.h" +#include "iolog.h" struct script_buf { int len; /* buffer length (how much read in) */ @@ -73,39 +74,6 @@ struct iolog_details { int cols; }; -union io_fd { - FILE *f; -#ifdef HAVE_ZLIB_H - gzFile g; -#endif - void *v; -}; - -static struct io_log_file { - bool enabled; - const char *suffix; - union io_fd fd; -} io_log_files[] = { -#define IOFD_LOG 0 - { true, "/log" }, -#define IOFD_TIMING 1 - { true, "/timing" }, -#define IOFD_STDIN 2 - { false, "/stdin" }, -#define IOFD_STDOUT 3 - { false, "/stdout" }, -#define IOFD_STDERR 4 - { false, "/stderr" }, -#define IOFD_TTYIN 5 - { false, "/ttyin" }, -#define IOFD_TTYOUT 6 - { false, "/ttyout" }, -#define IOFD_MAX 7 - { false, NULL } -}; - -#define SESSID_MAX 2176782336U - static int iolog_compress; static struct timeval last_time; static unsigned int sessid_max = SESSID_MAX; @@ -330,11 +298,8 @@ open_io_fd(char *pathbuf, size_t len, struct io_log_file *iol, bool docompress) #endif iol->fd.f = fdopen(fd, "w"); } - if (fd == -1 || iol->fd.v == NULL) { + if (fd == -1 || iol->fd.v == NULL) log_fatal(USE_ERRNO, N_("unable to create %s"), pathbuf); - if (fd != -1) - close(fd); - } } else { /* Remove old log file if we recycled sequence numbers. */ unlink(pathbuf); @@ -508,6 +473,37 @@ iolog_deserialize_info(struct iolog_details *details, char * const user_info[], io_log_files[IOFD_TTYOUT].enabled); } +/* + * Write the "/log" file that contains the user and command info. + */ +void +write_info_log(char *pathbuf, size_t len, struct iolog_details *details, + char * const argv[], struct timeval *now) +{ + char * const *av; + FILE *fp; + int fd; + + pathbuf[len] = '\0'; + strlcat(pathbuf, "/log", PATH_MAX); + fd = open(pathbuf, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR); + if (fd != -1 || (fp = fdopen(fd, "w")) == NULL) + log_fatal(USE_ERRNO, N_("unable to create %s"), pathbuf); + + fprintf(fp, "%lld:%s:%s:%s:%s:%d:%d\n%s\n%s", (long long)now->tv_sec, + details->user ? details->user : "unknown", details->runas_pw->pw_name, + details->runas_gr ? details->runas_gr->gr_name : "", + details->tty ? details->tty : "unknown", details->lines, details->cols, + details->cwd ? details->cwd : "unknown", + details->command ? details->command : "unknown"); + for (av = argv + 1; *av != NULL; av++) { + fputc(' ', fp); + fputs(*av, fp); + } + fputc('\n', fp); + fclose(fp); +} + static int sudoers_io_open(unsigned int version, sudo_conv_t conversation, sudo_printf_t plugin_printf, char * const settings[], @@ -581,28 +577,13 @@ sudoers_io_open(unsigned int version, sudo_conv_t conversation, if (len >= sizeof(pathbuf)) goto done; - /* - * We create 7 files: a log file, a timing file and 5 for input/output. - */ - for (i = 0; i < IOFD_MAX; i++) { - open_io_fd(pathbuf, len, &io_log_files[i], i ? iolog_compress : false); - } - + /* Write log file with user and command details. */ gettimeofday(&last_time, NULL); - fprintf(io_log_files[IOFD_LOG].fd.f, "%lld:%s:%s:%s:%s:%d:%d\n%s\n%s", - (long long)last_time.tv_sec, - details.user ? details.user : "unknown", details.runas_pw->pw_name, - details.runas_gr ? details.runas_gr->gr_name : "", - details.tty ? details.tty : "unknown", details.lines, details.cols, - details.cwd ? details.cwd : "unknown", - details.command ? details.command : "unknown"); - for (cur = &argv[1]; *cur != NULL; cur++) { - fputc(' ', io_log_files[IOFD_LOG].fd.f); - fputs(*cur, io_log_files[IOFD_LOG].fd.f); - } - fputc('\n', io_log_files[IOFD_LOG].fd.f); - fclose(io_log_files[IOFD_LOG].fd.f); - io_log_files[IOFD_LOG].fd.f = NULL; + write_info_log(pathbuf, len, &details, argv, &last_time); + + /* Create the timing I/O log files. */ + for (i = 0; i < IOFD_MAX; i++) + open_io_fd(pathbuf, len, &io_log_files[i], iolog_compress); /* * Clear I/O log function pointers for disabled log functions. diff --git a/plugins/sudoers/iolog.h b/plugins/sudoers/iolog.h new file mode 100644 index 000000000..54d9955d8 --- /dev/null +++ b/plugins/sudoers/iolog.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2013 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _SUDOERS_IOLOG_H +#define _SUDOERS_IOLOG_H + +/* + * I/O log fd numbers as stored in the timing file. + * Changing these will result in incompatible I/O log files! + */ +#define IOFD_STDIN 0 +#define IOFD_STDOUT 1 +#define IOFD_STDERR 2 +#define IOFD_TTYIN 3 +#define IOFD_TTYOUT 4 +#define IOFD_TIMING 5 +#define IOFD_MAX 6 + +/* Default maximum session ID */ +#define SESSID_MAX 2176782336U + +union io_fd { + FILE *f; +#ifdef HAVE_ZLIB_H + gzFile g; +#endif + void *v; +}; + +struct io_log_file { + bool enabled; + const char *suffix; + union io_fd fd; +}; + +static struct io_log_file io_log_files[] = { + { false, "/stdin" }, /* IOFD_STDIN */ + { false, "/stdout" }, /* IOFD_STDOUT */ + { false, "/stderr" }, /* IOFD_STDERR */ + { false, "/ttyin" }, /* IOFD_TTYIN */ + { false, "/ttyout" }, /* IOFD_TTYOUT */ + { true, "/timing" }, /* IOFD_TIMING */ + { false, NULL } /* IOFD_MAX */ +}; + +#endif /* _SUDOERS_IOLOG_H */ diff --git a/plugins/sudoers/sudoreplay.c b/plugins/sudoers/sudoreplay.c index 5a9bbc253..8cefbbd8b 100644 --- a/plugins/sudoers/sudoreplay.c +++ b/plugins/sudoers/sudoreplay.c @@ -100,6 +100,7 @@ #include "fatal.h" #include "gettext.h" #include "logging.h" +#include "iolog.h" #include "sudo_plugin.h" #include "sudo_conf.h" #include "sudo_debug.h" @@ -108,27 +109,6 @@ # define LINE_MAX 2048 #endif -/* Must match the defines in iolog.c */ -#define IOFD_STDIN 0 -#define IOFD_STDOUT 1 -#define IOFD_STDERR 2 -#define IOFD_TTYIN 3 -#define IOFD_TTYOUT 4 -#define IOFD_TIMING 5 -#define IOFD_MAX 6 - -/* Bitmap of iofds to be replayed */ -unsigned int replay_filter = (1 << IOFD_STDOUT) | (1 << IOFD_STDERR) | - (1 << IOFD_TTYOUT); - -union io_fd { - FILE *f; -#ifdef HAVE_ZLIB_H - gzFile g; -#endif - void *v; -}; - /* * Info present in the I/O log file */ @@ -185,16 +165,6 @@ static int stack_top; static const char *session_dir = _PATH_SUDO_IO_LOGDIR; -static union io_fd io_fds[IOFD_MAX]; -static const char *io_fnames[IOFD_MAX] = { - "/stdin", - "/stdout", - "/stderr", - "/ttyin", - "/ttyout", - "/timing" -}; - static const char short_opts[] = "d:f:hlm:s:V"; static struct option long_opts[] = { { "directory", required_argument, NULL, 'd' }, @@ -219,7 +189,7 @@ static void check_input(int, double *); static void delay(double); static void help(void) __attribute__((__noreturn__)); static void usage(int); -static int open_io_fd(char *pathbuf, int len, const char *suffix, union io_fd *fdp); +static int open_io_fd(char *path, int len, struct io_log_file *iol); static int parse_timing(const char *buf, const char *decimal, int *idx, double *seconds, size_t *nbytes); static struct log_info *parse_logfile(char *logfile); static void free_log_info(struct log_info *li); @@ -254,6 +224,7 @@ main(int argc, char *argv[]) { int ch, idx, plen, exitcode = 0, rows = 0, cols = 0; bool interactive = false, listonly = false, need_nlcr = false; + bool def_filter = true; const char *decimal, *id, *user = NULL, *pattern = NULL, *tty = NULL; char path[PATH_MAX], buf[LINE_MAX], *cp, *ep; double seconds, to_wait, speed = 1.0, max_wait = 0; @@ -293,14 +264,14 @@ main(int argc, char *argv[]) break; case 'f': /* Set the replay filter. */ - replay_filter = 0; + def_filter = false; for (cp = strtok(optarg, ","); cp; cp = strtok(NULL, ",")) { if (strcmp(cp, "stdout") == 0) - SET(replay_filter, 1 << IOFD_STDOUT); + io_log_files[IOFD_STDOUT].enabled = true; else if (strcmp(cp, "stderr") == 0) - SET(replay_filter, 1 << IOFD_STDERR); + io_log_files[IOFD_STDERR].enabled = true; else if (strcmp(cp, "ttyout") == 0) - SET(replay_filter, 1 << IOFD_TTYOUT); + io_log_files[IOFD_TTYOUT].enabled = true; else fatalx(_("invalid filter option: %s"), optarg); } @@ -343,6 +314,13 @@ main(int argc, char *argv[]) if (argc != 1) usage(1); + /* By default we replay stdout, stderr and ttyout. */ + if (def_filter) { + io_log_files[IOFD_STDOUT].enabled = true; + io_log_files[IOFD_STDERR].enabled = true; + io_log_files[IOFD_TTYOUT].enabled = true; + } + /* 6 digit ID in base 36, e.g. 01G712AB or free-form name */ id = argv[0]; if (VALID_ID(id)) { @@ -362,10 +340,8 @@ main(int argc, char *argv[]) /* Open files for replay, applying replay filter for the -f flag. */ for (idx = 0; idx < IOFD_MAX; idx++) { - if (ISSET(replay_filter, 1 << idx) || idx == IOFD_TIMING) { - if (open_io_fd(path, plen, io_fnames[idx], &io_fds[idx]) == -1) - fatal(_("unable to open %s"), path); - } + if (open_io_fd(path, plen, &io_log_files[idx]) == -1) + fatal(_("unable to open %s"), path); } /* Parse log file. */ @@ -419,9 +395,9 @@ main(int argc, char *argv[]) * Timing file consists of line of the format: "%f %d\n" */ #ifdef HAVE_ZLIB_H - while (gzgets(io_fds[IOFD_TIMING].g, buf, sizeof(buf)) != NULL) { + while (gzgets(io_log_files[IOFD_TIMING].fd.g, buf, sizeof(buf)) != NULL) { #else - while (fgets(buf, sizeof(buf), io_fds[IOFD_TIMING].f) != NULL) { + while (fgets(buf, sizeof(buf), io_log_files[IOFD_TIMING].fd.f) != NULL) { #endif char last_char = '\0'; @@ -437,8 +413,8 @@ main(int argc, char *argv[]) to_wait = max_wait; delay(to_wait); - /* Even if we are not relaying, we still have to delay. */ - if (io_fds[idx].v == NULL) + /* Even if we are not replaying, we still have to delay. */ + if (io_log_files[idx].fd.v == NULL) continue; /* Check whether we need to convert newline to CR LF pairs. */ @@ -452,9 +428,9 @@ main(int argc, char *argv[]) else len = nbytes; #ifdef HAVE_ZLIB_H - nread = gzread(io_fds[idx].g, buf, len); + nread = gzread(io_log_files[idx].fd.g, buf, len); #else - nread = fread(buf, 1, len, io_fds[idx].f); + nread = fread(buf, 1, len, io_log_files[idx].fd.f); #endif nbytes -= nread; @@ -544,19 +520,21 @@ delay(double secs) } static int -open_io_fd(char *path, int len, const char *suffix, union io_fd *fdp) +open_io_fd(char *path, int len, struct io_log_file *iol) { debug_decl(open_io_fd, SUDO_DEBUG_UTIL) - path[len] = '\0'; - strlcat(path, suffix, PATH_MAX); + if (!iol->enabled) + debug_return_int(0); + path[len] = '\0'; + strlcat(path, iol->suffix, PATH_MAX); #ifdef HAVE_ZLIB_H - fdp->g = gzopen(path, "r"); + iol->fd.g = gzopen(path, "r"); #else - fdp->f = fopen(path, "r"); + iol->fd.f = fopen(path, "r"); #endif - debug_return_int(fdp->v ? 0 : -1); + debug_return_int(iol->fd.v ? 0 : -1); } /*