version 1.1.1.4, 2013/07/22 10:46:12
|
version 1.1.1.5, 2013/10/14 07:56:35
|
Line 87
|
Line 87
|
#else |
#else |
# include "compat/stdbool.h" |
# include "compat/stdbool.h" |
#endif /* HAVE_STDBOOL_H */ |
#endif /* HAVE_STDBOOL_H */ |
|
#ifdef HAVE_GETOPT_LONG |
|
# include <getopt.h> |
|
# else |
|
# include "compat/getopt.h" |
|
#endif /* HAVE_GETOPT_LONG */ |
|
|
#include <pathnames.h> |
#include <pathnames.h> |
|
|
#include "missing.h" |
#include "missing.h" |
#include "alloc.h" |
#include "alloc.h" |
#include "error.h" | #include "fatal.h" |
#include "gettext.h" |
#include "gettext.h" |
#include "logging.h" |
#include "logging.h" |
|
#include "iolog.h" |
#include "sudo_plugin.h" |
#include "sudo_plugin.h" |
#include "sudo_conf.h" |
#include "sudo_conf.h" |
#include "sudo_debug.h" |
#include "sudo_debug.h" |
Line 103
|
Line 109
|
# define LINE_MAX 2048 |
# define LINE_MAX 2048 |
#endif |
#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); |
|
|
|
/* For getopt(3) */ |
|
extern char *optarg; |
|
extern int optind; |
|
|
|
union io_fd { |
|
FILE *f; |
|
#ifdef HAVE_ZLIB_H |
|
gzFile g; |
|
#endif |
|
void *v; |
|
}; |
|
|
|
/* |
/* |
* Info present in the I/O log file |
* Info present in the I/O log file |
*/ |
*/ |
Line 147 struct log_info {
|
Line 128 struct log_info {
|
* Handle expressions like: |
* Handle expressions like: |
* ( user millert or user root ) and tty console and command /bin/sh |
* ( user millert or user root ) and tty console and command /bin/sh |
*/ |
*/ |
struct search_node { | static struct search_node { |
struct search_node *next; |
struct search_node *next; |
#define ST_EXPR 1 |
#define ST_EXPR 1 |
#define ST_TTY 2 |
#define ST_TTY 2 |
Line 182 struct search_node {
|
Line 163 struct search_node {
|
static struct search_node *node_stack[32]; |
static struct search_node *node_stack[32]; |
static int stack_top; |
static int stack_top; |
|
|
|
static int timing_idx_adj = 0; |
|
|
static const char *session_dir = _PATH_SUDO_IO_LOGDIR; |
static const char *session_dir = _PATH_SUDO_IO_LOGDIR; |
|
|
static union io_fd io_fds[IOFD_MAX]; | static const char short_opts[] = "d:f:hlm:s:V"; |
static const char *io_fnames[IOFD_MAX] = { | static struct option long_opts[] = { |
"/stdin", | { "directory", required_argument, NULL, 'd' }, |
"/stdout", | { "filter", required_argument, NULL, 'f' }, |
"/stderr", | { "help", no_argument, NULL, 'h' }, |
"/ttyin", | { "list", no_argument, NULL, 'l' }, |
"/ttyout", | { "max-wait", required_argument, NULL, 'm' }, |
"/timing" | { "speed", required_argument, NULL, 's' }, |
| { "version", no_argument, NULL, 'V' }, |
| { NULL, no_argument, NULL, '\0' }, |
}; |
}; |
|
|
extern time_t get_date(char *); |
extern time_t get_date(char *); |
Line 206 static void check_input(int, double *);
|
Line 191 static void check_input(int, double *);
|
static void delay(double); |
static void delay(double); |
static void help(void) __attribute__((__noreturn__)); |
static void help(void) __attribute__((__noreturn__)); |
static void usage(int); |
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 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 struct log_info *parse_logfile(char *logfile); |
static void free_log_info(struct log_info *li); |
static void free_log_info(struct log_info *li); |
Line 241 main(int argc, char *argv[])
|
Line 226 main(int argc, char *argv[])
|
{ |
{ |
int ch, idx, plen, exitcode = 0, rows = 0, cols = 0; |
int ch, idx, plen, exitcode = 0, rows = 0, cols = 0; |
bool interactive = false, listonly = false, need_nlcr = false; |
bool interactive = false, listonly = false, need_nlcr = false; |
|
bool def_filter = true; |
const char *decimal, *id, *user = NULL, *pattern = NULL, *tty = NULL; |
const char *decimal, *id, *user = NULL, *pattern = NULL, *tty = NULL; |
char path[PATH_MAX], buf[LINE_MAX], *cp, *ep; |
char path[PATH_MAX], buf[LINE_MAX], *cp, *ep; |
double seconds, to_wait, speed = 1.0, max_wait = 0; |
double seconds, to_wait, speed = 1.0, max_wait = 0; |
Line 273 main(int argc, char *argv[])
|
Line 259 main(int argc, char *argv[])
|
/* Read sudo.conf. */ |
/* Read sudo.conf. */ |
sudo_conf_read(NULL); |
sudo_conf_read(NULL); |
|
|
while ((ch = getopt(argc, argv, "d:f:hlm:s:V")) != -1) { | while ((ch = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) { |
switch(ch) { | switch (ch) { |
case 'd': |
case 'd': |
session_dir = optarg; |
session_dir = optarg; |
break; |
break; |
case 'f': |
case 'f': |
/* Set the replay filter. */ |
/* Set the replay filter. */ |
replay_filter = 0; | def_filter = false; |
for (cp = strtok(optarg, ","); cp; cp = strtok(NULL, ",")) { |
for (cp = strtok(optarg, ","); cp; cp = strtok(NULL, ",")) { |
if (strcmp(cp, "stdout") == 0) |
if (strcmp(cp, "stdout") == 0) |
SET(replay_filter, 1 << IOFD_STDOUT); | io_log_files[IOFD_STDOUT].enabled = true; |
else if (strcmp(cp, "stderr") == 0) |
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) |
else if (strcmp(cp, "ttyout") == 0) |
SET(replay_filter, 1 << IOFD_TTYOUT); | io_log_files[IOFD_TTYOUT].enabled = true; |
else |
else |
fatalx(_("invalid filter option: %s"), optarg); |
fatalx(_("invalid filter option: %s"), optarg); |
} |
} |
Line 330 main(int argc, char *argv[])
|
Line 316 main(int argc, char *argv[])
|
if (argc != 1) |
if (argc != 1) |
usage(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 */ |
/* 6 digit ID in base 36, e.g. 01G712AB or free-form name */ |
id = argv[0]; |
id = argv[0]; |
if (VALID_ID(id)) { |
if (VALID_ID(id)) { |
Line 349 main(int argc, char *argv[])
|
Line 342 main(int argc, char *argv[])
|
|
|
/* Open files for replay, applying replay filter for the -f flag. */ |
/* Open files for replay, applying replay filter for the -f flag. */ |
for (idx = 0; idx < IOFD_MAX; idx++) { |
for (idx = 0; idx < IOFD_MAX; idx++) { |
if (ISSET(replay_filter, 1 << idx) || idx == IOFD_TIMING) { | if (open_io_fd(path, plen, &io_log_files[idx]) == -1) |
if (open_io_fd(path, plen, io_fnames[idx], &io_fds[idx]) == -1) | fatal(_("unable to open %s"), path); |
fatal(_("unable to open %s"), path); | |
} | |
} |
} |
|
|
/* Parse log file. */ |
/* Parse log file. */ |
Line 406 main(int argc, char *argv[])
|
Line 397 main(int argc, char *argv[])
|
* Timing file consists of line of the format: "%f %d\n" |
* Timing file consists of line of the format: "%f %d\n" |
*/ |
*/ |
#ifdef HAVE_ZLIB_H |
#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 |
#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 |
#endif |
char last_char = '\0'; |
char last_char = '\0'; |
|
|
Line 424 main(int argc, char *argv[])
|
Line 415 main(int argc, char *argv[])
|
to_wait = max_wait; |
to_wait = max_wait; |
delay(to_wait); |
delay(to_wait); |
|
|
/* Even if we are not relaying, we still have to delay. */ | /* Even if we are not replaying, we still have to delay. */ |
if (io_fds[idx].v == NULL) | if (io_log_files[idx].fd.v == NULL) |
continue; |
continue; |
|
|
/* Check whether we need to convert newline to CR LF pairs. */ |
/* Check whether we need to convert newline to CR LF pairs. */ |
Line 439 main(int argc, char *argv[])
|
Line 430 main(int argc, char *argv[])
|
else |
else |
len = nbytes; |
len = nbytes; |
#ifdef HAVE_ZLIB_H |
#ifdef HAVE_ZLIB_H |
nread = gzread(io_fds[idx].g, buf, len); | nread = gzread(io_log_files[idx].fd.g, buf, len); |
#else |
#else |
nread = fread(buf, 1, len, io_fds[idx].f); | nread = fread(buf, 1, len, io_log_files[idx].fd.f); |
#endif |
#endif |
nbytes -= nread; |
nbytes -= nread; |
|
|
Line 531 delay(double secs)
|
Line 522 delay(double secs)
|
} |
} |
|
|
static int |
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) |
debug_decl(open_io_fd, SUDO_DEBUG_UTIL) |
|
|
path[len] = '\0'; | if (!iol->enabled) |
strlcat(path, suffix, PATH_MAX); | debug_return_int(0); |
|
|
|
path[len] = '\0'; |
|
strlcat(path, iol->suffix, PATH_MAX); |
#ifdef HAVE_ZLIB_H |
#ifdef HAVE_ZLIB_H |
fdp->g = gzopen(path, "r"); | iol->fd.g = gzopen(path, "r"); |
#else |
#else |
fdp->f = fopen(path, "r"); | iol->fd.f = fopen(path, "r"); |
#endif |
#endif |
debug_return_int(fdp->v ? 0 : -1); | debug_return_int(iol->fd.v ? 0 : -1); |
} |
} |
|
|
/* |
/* |
Line 1133 parse_timing(buf, decimal, idx, seconds, nbytes)
|
Line 1126 parse_timing(buf, decimal, idx, seconds, nbytes)
|
|
|
/* Parse index */ |
/* Parse index */ |
ul = strtoul(buf, &ep, 10); |
ul = strtoul(buf, &ep, 10); |
if (ul > IOFD_MAX) | if (ul >= IOFD_TIMING) { |
goto bad; | if (ul != 6) |
*idx = (int)ul; | goto bad; |
| /* work around a bug in timing files generated by sudo 1.8.7 */ |
| timing_idx_adj = 2; |
| } |
| *idx = (int)ul - timing_idx_adj; |
for (cp = ep + 1; isspace((unsigned char) *cp); cp++) |
for (cp = ep + 1; isspace((unsigned char) *cp); cp++) |
continue; |
continue; |
|
|
Line 1179 static void
|
Line 1176 static void
|
usage(int fatal) |
usage(int fatal) |
{ |
{ |
fprintf(fatal ? stderr : stdout, |
fprintf(fatal ? stderr : stdout, |
_("usage: %s [-h] [-d directory] [-m max_wait] [-s speed_factor] ID\n"), | _("usage: %s [-h] [-d dir] [-m num] [-s num] ID\n"), |
getprogname()); |
getprogname()); |
fprintf(fatal ? stderr : stdout, |
fprintf(fatal ? stderr : stdout, |
_("usage: %s [-h] [-d directory] -l [search expression]\n"), | _("usage: %s [-h] [-d dir] -l [search expression]\n"), |
getprogname()); |
getprogname()); |
if (fatal) |
if (fatal) |
exit(1); |
exit(1); |
Line 1194 help(void)
|
Line 1191 help(void)
|
(void) printf(_("%s - replay sudo session logs\n\n"), getprogname()); |
(void) printf(_("%s - replay sudo session logs\n\n"), getprogname()); |
usage(0); |
usage(0); |
(void) puts(_("\nOptions:\n" |
(void) puts(_("\nOptions:\n" |
" -d directory specify directory for session logs\n" | " -d, --directory=dir specify directory for session logs\n" |
" -f filter specify which I/O type to display\n" | " -f, --filter=filter specify which I/O type(s) to display\n" |
" -h display help message and exit\n" | " -h, --help display help message and exit\n" |
" -l [expression] list available session IDs that match expression\n" | " -l, --list list available session IDs, with optional expression\n" |
" -m max_wait max number of seconds to wait between events\n" | " -m, --max-wait=num max number of seconds to wait between events\n" |
" -s speed_factor speed up or slow down output\n" | " -s, --speed=num speed up or slow down output\n" |
" -V display version information and exit")); | " -V, --version display version information and exit")); |
exit(0); |
exit(0); |
} |
} |
|
|