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
#endif
#include "sudoers.h"
+#include "iolog.h"
struct script_buf {
int len; /* buffer length (how much read in) */
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;
#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);
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[],
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.
--- /dev/null
+/*
+ * Copyright (c) 2013 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * 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 */
#include "fatal.h"
#include "gettext.h"
#include "logging.h"
+#include "iolog.h"
#include "sudo_plugin.h"
#include "sudo_conf.h"
#include "sudo_debug.h"
# 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
*/
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' },
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);
{
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;
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);
}
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)) {
/* 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. */
* 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';
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. */
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;
}
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);
}
/*