VISUDO_OBJS = $(COMMON_OBJS) visudo.o fileops.o gettime.o goodpath.o \
find_path.o pwutil.o
-REPLAY_OBJS = sudoreplay.o error.o
+REPLAY_OBJS = sudoreplay.o error.o alloc.o
TEST_OBJS = $(COMMON_OBJS) interfaces.o testsudoers.o tsgetgrpw.o tspwutil.o
schema.ActiveDirectory schema.OpenLDAP schema.iPlanet sudo.cat \
sudo.man.in sudo.pod sudo.psf sudo_usage.h.in sudoers sudoers.cat \
sudoers.man.in sudoers.pod sudoers.ldap.cat sudoers.ldap.man.in \
- sudoers.ldap.pod sudoers2ldif sudoreplay.cat sudoreplay.man.in \
- sudoreplay.pod visudo.cat visudo.man.in visudo.pod auth/API
+ sudoers.ldap.pod sudoers2ldif sudoreplay.cat sudoreplay.man.in \
+ sudoreplay.pod visudo.cat visudo.man.in visudo.pod auth/API
BINFILES= ChangeLog HISTORY LICENSE README TROUBLESHOOTING \
UPGRADE install-sh mkinstalldirs sample.syslog.conf sample.sudoers \
char **Argv;
const char *session_dir = _PATH_SUDO_SESSDIR;
-void usage __P((void));
-void delay __P((double));
-int list_sessions __P((int, char **, const char *, const char *, const char *));
+/*
+ * Info present in the transcript log file
+ */
+struct log_info {
+ char *user;
+ char *runas_user;
+ char *runas_group;
+ char *tty;
+ char *cmd;
+ time_t tstamp;
+};
+
+/*
+ * Handle expressions like:
+ * ( user millert or user root ) and tty console and command /bin/sh
+ * XXX - also time-based
+ */
+struct search_node {
+ struct search_node *next;
+#define ST_EXPR 1
+#define ST_TTY 2
+#define ST_USER 3
+#define ST_PATTERN 4
+#define ST_RUNASUSER 5
+#define ST_RUNASGROUP 6
+ char type;
+ char negated;
+ char or;
+ char pad;
+ union {
+#ifdef HAVE_REGCOMP
+ regex_t cmdre;
+#endif
+ char *tty;
+ char *user;
+ char *pattern;
+ char *runas_group;
+ char *runas_user;
+ struct search_node *expr;
+ void *ptr;
+ } u;
+} *search_expr;
+
+#define STACK_NODE_SIZE 32
+static struct search_node *node_stack[32];
+static int stack_top;
+
+extern void *emalloc __P((size_t));
+static int list_sessions __P((int, char **, const char *, const char *, const char *));
+static int parse_expr __P((struct search_node **, char **));
+static void delay __P((double));
+static void usage __P((void));
#ifdef HAVE_REGCOMP
# define REGEX_T regex_t
Argv = argv;
/* XXX - timestamp option? (begin,end) */
- while ((ch = getopt(argc, argv, "d:lm:p:s:t:u:V")) != -1) {
+ while ((ch = getopt(argc, argv, "d:lm:s:V")) != -1) {
switch(ch) {
case 'd':
session_dir = optarg;
if (*ep != '\0' || errno != 0)
error(1, "invalid max wait: %s", optarg);
break;
- case 'p':
- pattern = optarg;
- break;
case 's':
errno = 0;
speed = strtod(optarg, &ep);
if (*ep != '\0' || errno != 0)
error(1, "invalid speed factor: %s", optarg);
break;
- case 't':
- tty = optarg;
- break;
- case 'u':
- user = optarg;
- break;
case 'V':
(void) printf("%s version %s\n", getprogname(), PACKAGE_VERSION);
exit(0);
argc -= optind;
argv += optind;
- if (listonly) {
+ if (listonly)
exit(list_sessions(argc, argv, pattern, user, tty));
- }
if (argc != 1)
usage();
}
#endif
-void
+static void
delay(secs)
double secs;
{
error(1, "nanosleep: tv_sec %ld, tv_nsec %ld", ts.tv_sec, ts.tv_nsec);
}
-struct log_info {
- char *user;
- char *runas_user;
- char *runas_group;
- char *tty;
- char *cmd;
- time_t tstamp;
-};
+/*
+ * Build expression list from search args
+ * XXX - add additional search terms
+ */
+static int
+parse_expr(headp, argv)
+ struct search_node **headp;
+ char **argv;
+{
+ struct search_node *sn, *newsn;
+ char or = 0, not = 0, type;
+ char **av;
+
+ sn = *headp;
+ for (av = argv; *av; av++) {
+ switch (*av[0]) {
+ case 'a': /* and (ignore) */
+ continue;
+ case 'o': /* or */
+ or = 1;
+ continue;
+ case '!': /* negate */
+ not = 1;
+ continue;
+ case 'c': /* command */
+ type = ST_PATTERN;
+ break;
+ case 'g': /* runas group */
+ type = ST_RUNASGROUP;
+ break;
+ case 'r': /* runas user */
+ type = ST_RUNASUSER;
+ break;
+ case 't': /* tty */
+ type = ST_TTY;
+ break;
+ case 'u': /* user */
+ type = ST_USER;
+ break;
+ case '(': /* start sub-expression */
+ if (stack_top + 1 == STACK_NODE_SIZE) {
+ errorx(1, "too many parenthesized expressions, max %d",
+ STACK_NODE_SIZE);
+ }
+ node_stack[stack_top++] = sn;
+ type = ST_EXPR;
+ break;
+ case ')': /* end sub-expression */
+ /* pop */
+ if (--stack_top < 0)
+ errorx(1, "unmatched ')' in expression");
+ if (node_stack[stack_top])
+ sn->next = node_stack[stack_top]->next;
+ return(av - argv + 1);
+ default:
+ errorx(1, "unknown search term \"%s\"", *av);
+ /* NOTREACHED */
+ }
+
+ /* Allocate new search node */
+ newsn = emalloc(sizeof(*newsn));
+ newsn->next = NULL;
+ newsn->type = type;
+ newsn->or = or;
+ newsn->negated = not;
+ if (type == ST_EXPR) {
+ av += parse_expr(&newsn->u.expr, av + 1);
+ } else {
+ if (*(++av) == NULL)
+ errorx(1, "%s requires an argument", av[-1]);
+#ifdef HAVE_REGCOMP
+ if (type == ST_PATTERN) {
+ if (regcomp(&newsn->u.cmdre, *av, REG_EXTENDED|REG_NOSUB) != 0)
+ errorx(1, "invalid regex: %s", *av);
+ } else
+#endif
+ newsn->u.ptr = *av;
+ }
+ not = or = 0; /* reset state */
+ if (sn)
+ sn->next = newsn;
+ else
+ *headp = newsn;
+ sn = newsn;
+ }
+ if (stack_top)
+ errorx(1, "unmatched '(' in expression");
+ if (or)
+ errorx(1, "illegal trailing \"or\"");
+ if (not)
+ errorx(1, "illegal trailing \"!\"");
+
+ return(av - argv);
+}
+
+static int
+match_expr(head, log)
+ struct search_node *head;
+ struct log_info *log;
+{
+ struct search_node *sn;
+ int matched = 1, rc;
+
+ for (sn = head; sn; sn = sn->next) {
+ /* If we have no match, skip up to the next OR entry. */
+ if (!matched && !sn->or)
+ continue;
+
+ switch (sn->type) {
+ case ST_EXPR:
+ matched = match_expr(sn->u.expr, log);
+ break;
+ case ST_TTY:
+ matched = strcmp(sn->u.tty, log->tty) == 0;
+ break;
+ case ST_RUNASGROUP:
+ matched = strcmp(sn->u.runas_group, log->runas_group) == 0;
+ break;
+ case ST_RUNASUSER:
+ matched = strcmp(sn->u.runas_user, log->runas_user) == 0;
+ break;
+ case ST_USER:
+ matched = strcmp(sn->u.user, log->user) == 0;
+ break;
+ case ST_PATTERN:
+#ifdef HAVE_REGCOMP
+ rc = regexec(&sn->u.cmdre, log->cmd, 0, NULL, 0);
+ if (rc && rc != REG_NOMATCH) {
+ char buf[BUFSIZ];
+ regerror(rc, &sn->u.cmdre, buf, sizeof(buf));
+ errorx(1, "%s", buf);
+ }
+ matched = rc == REG_NOMATCH ? 0 : 1;
+#else
+ matched = strstr(log.cmd, sn->u.pattern) != NULL;
+#endif
+ break;
+ }
+ if (sn->negated)
+ matched = !matched;
+ }
+ return(matched);
+}
static int
list_session_dir(pathbuf, re, user, tty)
cmdbuf[strcspn(cmdbuf, "\n")] = '\0';
li.cmd = cmdbuf;
- /*
- * Select based on user/tty/regex if applicable.
- * XXX - select on time and/or runas bits too?
- */
- if (user && strcmp(user, li.user) != 0)
+ /* Match on search expression if there is one. */
+ if (search_expr && !match_expr(search_expr, &li))
continue;
- if (tty && strcmp(tty, li.tty) != 0)
- continue;
- if (re) {
-#ifdef HAVE_REGCOMP
- int rc = regexec(re, li.cmd, 0, NULL, 0);
- if (rc) {
- if (rc == REG_NOMATCH)
- continue;
- regerror(rc, re, buf, sizeof(buf));
- errorx(1, "%s", buf);
- }
-#else
- if (strstr(li.cmd, re) == NULL)
- continue;
-#endif /* HAVE_REGCOMP */
- }
/* Convert from /var/log/sudo-sessions/00/00/01 to 000001 */
idstr[0] = pathbuf[plen - 5];
idstr[5] = pathbuf[plen + 2];
idstr[6] = '\0';
/* XXX - better format (timestamp?) */
- printf("%s: %s %d (%s:%s) %s\n", idstr, li.user, li.tstamp,
+ printf("%s: %s %ld (%s:%s) %s\n", idstr, li.user, (long)li.tstamp,
li.runas_user, li.runas_group, li.cmd);
}
return(0);
}
-int
+static int
list_sessions(argc, argv, pattern, user, tty)
int argc;
char **argv;
size_t sdlen;
char pathbuf[PATH_MAX];
+ /* Parse search expression if present */
+ parse_expr(&search_expr, argv);
+
d1 = opendir(session_dir);
if (d1 == NULL)
error(1, "unable to open %s", session_dir);
return(0);
}
-void
+static void
usage()
{
fprintf(stderr,
"usage: %s [-d directory] [-m max_wait] [-s speed_factor] ID\n",
getprogname());
fprintf(stderr,
- "usage: %s [-d directory] [-p pattern] [-t tty] [-u username] -l\n",
+ "usage: %s [-d directory] -l [search expression]\n",
getprogname());
exit(1);
}
S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS
s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by [-\b-d\bd _\bd_\bi_\br_\be_\bc_\bt_\bo_\br_\by] [-\b-m\bm _\bm_\ba_\bx_\b__\bw_\ba_\bi_\bt] [-\b-s\bs _\bs_\bp_\be_\be_\bd_\b__\bf_\ba_\bc_\bt_\bo_\br] ID
- s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by [-\b-d\bd _\bd_\bi_\br_\be_\bc_\bt_\bo_\br_\by] [-\b-p\bp _\bp_\ba_\bt_\bt_\be_\br_\bn] [-\b-t\bt _\bt_\bt_\by] [-\b-u\bu _\bu_\bs_\be_\br] -l
+ s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by [-\b-d\bd _\bd_\bi_\br_\be_\bc_\bt_\bo_\br_\by] -l [search expression]
D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by plays back or lists the session logs created by s\bsu\bud\bdo\bo. When
default, _\b/_\bv_\ba_\br_\b/_\bl_\bo_\bg_\b/_\bs_\bu_\bd_\bo_\b-_\bs_\be_\bs_\bs_\bi_\bo_\bn_\bs.
-l Enable "list mode". In this mode, s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by will list
- available session IDs. The -p, <-t> and <-u> options can
- be used to restrict the IDs that are displayed.
+ available session IDs. If a _\bs_\be_\ba_\br_\bc_\bh _\be_\bx_\bp_\br_\be_\bs_\bs_\bi_\bo_\bn is
+ specified, it will be used to restrict the IDs that are
+ displayed. An expression is composed of the following
+ predicates:
+
+ user _\bu_\bs_\be_\br_\bn_\ba_\bm_\be
+ Evaluates to true if the ID matches a command run
+ by _\bu_\bs_\be_\br_\bn_\ba_\bm_\be.
+
+ command _\bc_\bo_\bm_\bm_\ba_\bn_\bd _\bp_\ba_\bt_\bt_\be_\br_\bn
+ Evaluates to true if the command run matches
+ _\bc_\bo_\bm_\bm_\ba_\bn_\bd _\bp_\ba_\bt_\bt_\be_\br_\bn. On systems with POSIX regular
+ expression support, the pattern may be an extended
+ regular expression. On systems without POSIX
+ regular expression support, a simple substring
+ match is performed instead.
+
+ tty _\bt_\bt_\by Evaluates to true if the command was run on the
+ specified terminal device. The _\bt_\bt_\by should be
+ specified without the _\b/_\bd_\be_\bv_\b/ prefix, e.g. _\bt_\bt_\by_\b0_\b1
+ instead of _\b/_\bd_\be_\bv_\b/_\bt_\bt_\by_\b0_\b1.
+
+ runas _\br_\bu_\bn_\ba_\bs_\b__\bu_\bs_\be_\br
+ Evaluates to true if the command was run as the
+ specified _\br_\bu_\bn_\ba_\bs_\b__\bu_\bs_\be_\br. Note that s\bsu\bud\bdo\bo runs commands
+ as user _\br_\bo_\bo_\bt by default.
+
+
+
+
+1.7.2 September 13, 2009 1
+
+
+
+
+
+SUDOREPLAY(1m) MAINTENANCE COMMANDS SUDOREPLAY(1m)
+
+
+ runas _\br_\bu_\bn_\ba_\bs_\b__\bg_\br_\bo_\bu_\bp
+ Evaluates to true if the command was run with the
+ specified _\br_\bu_\bn_\ba_\bs_\b__\bg_\br_\bo_\bu_\bp. Note that unless a
+ _\br_\bu_\bn_\ba_\bs_\b__\bg_\br_\bo_\bu_\bp was explicitly specified when s\bsu\bud\bdo\bo was
+ run this field will be empty in the log.
+
+ Predicates may be combined using _\ba_\bn_\bd, _\bo_\br and _\b! operators as
+ well as '(' and ')' for grouping (note that parentheses
+ must generally be escaped from the shell). The _\ba_\bn_\bd
+ operator is optional, adjacent predicates have an implied
+ _\ba_\bn_\bd unless separated by an _\bo_\br.
-m _\bm_\ba_\bx_\b__\bw_\ba_\bi_\bt Specify an upper bound on how long to wait between key
presses or output data. By default, s\bsu\bud\bdo\bo_\b_r\bre\bep\bpl\bla\bay\by will
_\bm_\ba_\bx_\b__\bw_\ba_\bi_\bt seconds. The value may be specified as a floating
point number, .e.g. _\b2_\b._\b5.
- -p _\bp_\ba_\bt_\bt_\be_\br_\bn Restrict list output to sessions where the command matches
- _\bp_\ba_\bt_\bt_\be_\br_\bn. On systems with POSIX regular expression support,
- the pattern may be an extended regular expression. On
- systems without POSIX regular expression support, a simple
- substring match is performed instead.
-
-s _\bs_\bp_\be_\be_\bd_\b__\bf_\ba_\bc_\bt_\bo_\br
This option causes s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by to adjust the number of
seconds it will wait between key presses or program output.
fast whereas a _\bs_\bp_\be_\be_\bd_\b__\bf_\ba_\bc_\bt_\bo_\br of <.5> would make the output
twice as slow.
- -t _\bt_\bt_\by Restrict list output to sessions where the command was run
-
-
-
-1.7.2 August 30, 2009 1
-
-
-
-
-
-SUDOREPLAY(1m) MAINTENANCE COMMANDS SUDOREPLAY(1m)
-
-
- on the specified terming device. The _\bt_\bt_\by should be
- specified without the _\b/_\bd_\be_\bv_\b/ prefix, e.g. _\bt_\bt_\by_\b0_\b1 instead of
- _\b/_\bd_\be_\bv_\b/_\bt_\bt_\by_\b0_\b1.
-
- -u _\bu_\bs_\be_\br Restrict list output to sessions where the command was run
- by _\bu_\bs_\be_\br.
-
-V The -\b-V\bV (version) option causes s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by to print its
version number and exit.
If you feel you have found a bug in s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by, please submit a bug
report at http://www.sudo.ws/sudo/bugs/
+
+
+
+1.7.2 September 13, 2009 2
+
+
+
+
+
+SUDOREPLAY(1m) MAINTENANCE COMMANDS SUDOREPLAY(1m)
+
+
S\bSU\bUP\bPP\bPO\bOR\bRT\bT
Limited free support is available via the sudo-users mailing list, see
http://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or search
-1.7.2 August 30, 2009 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1.7.2 September 13, 2009 3
.\" ========================================================================
.\"
.IX Title "SUDOREPLAY @mansectsu@"
-.TH SUDOREPLAY @mansectsu@ "August 30, 2009" "1.7.2" "MAINTENANCE COMMANDS"
+.TH SUDOREPLAY @mansectsu@ "September 13, 2009" "1.7.2" "MAINTENANCE COMMANDS"
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.if n .ad l
.IX Header "SYNOPSIS"
\&\fBsudoreplay\fR [\fB\-d\fR \fIdirectory\fR] [\fB\-m\fR \fImax_wait\fR] [\fB\-s\fR \fIspeed_factor\fR] \s-1ID\s0
.PP
-\&\fBsudoreplay\fR [\fB\-d\fR \fIdirectory\fR] [\fB\-p\fR \fIpattern\fR] [\fB\-t\fR \fItty\fR] [\fB\-u\fR \fIuser\fR] \-l
+\&\fBsudoreplay\fR [\fB\-d\fR \fIdirectory\fR] \-l [search expression]
.SH "DESCRIPTION"
.IX Header "DESCRIPTION"
\&\fBsudoreplay\fR plays back or lists the session logs created by
.IP "\-l" 12
.IX Item "-l"
Enable \*(L"list mode\*(R". In this mode, \fBsudoreplay\fR will list available
-session IDs. The \f(CW\*(C`\-p\*(C'\fR, <\-t> and <\-u> options can be used to
-restrict the IDs that are displayed.
+session IDs. If a \fIsearch expression\fR is specified, it will be
+used to restrict the IDs that are displayed. An expression is
+composed of the following predicates:
+.RS 12
+.IP "user \fIusername\fR" 8
+.IX Item "user username"
+Evaluates to true if the \s-1ID\s0 matches a command run by \fIusername\fR.
+.IP "command \fIcommand pattern\fR" 8
+.IX Item "command command pattern"
+Evaluates to true if the command run matches \fIcommand pattern\fR.
+On systems with \s-1POSIX\s0 regular expression support, the pattern may
+be an extended regular expression. On systems without \s-1POSIX\s0 regular
+expression support, a simple substring match is performed instead.
+.IP "tty \fItty\fR" 8
+.IX Item "tty tty"
+Evaluates to true if the command was run on the specified terminal
+device. The \fItty\fR should be specified without the \fI/dev/\fR prefix,
+e.g. \fItty01\fR instead of \fI/dev/tty01\fR.
+.IP "runas \fIrunas_user\fR" 8
+.IX Item "runas runas_user"
+Evaluates to true if the command was run as the specified \fIrunas_user\fR.
+Note that \fBsudo\fR runs commands as user \fIroot\fR by default.
+.IP "runas \fIrunas_group\fR" 8
+.IX Item "runas runas_group"
+Evaluates to true if the command was run with the specified
+\&\fIrunas_group\fR. Note that unless a \fIrunas_group\fR was explicitly
+specified when \fBsudo\fR was run this field will be empty in the log.
+.RE
+.RS 12
+.Sp
+Predicates may be combined using \fIand\fR, \fIor\fR and \fI!\fR operators
+as well as \f(CW\*(Aq(\*(Aq\fR and \f(CW\*(Aq)\*(Aq\fR for grouping (note that parentheses
+must generally be escaped from the shell). The \fIand\fR operator is
+optional, adjacent predicates have an implied \fIand\fR unless separated
+by an \fIor\fR.
+.RE
.IP "\-m \fImax_wait\fR" 12
.IX Item "-m max_wait"
Specify an upper bound on how long to wait between key presses or
\&\fI\-m\fR option is specified, \fBsudoreplay\fR will limit these pauses
to at most \fImax_wait\fR seconds. The value may be specified as a
floating point number, .e.g. \fI2.5\fR.
-.IP "\-p \fIpattern\fR" 12
-.IX Item "-p pattern"
-Restrict list output to sessions where the command matches \fIpattern\fR.
-On systems with \s-1POSIX\s0 regular expression support, the pattern may
-be an extended regular expression. On systems without \s-1POSIX\s0 regular
-expression support, a simple substring match is performed instead.
.IP "\-s \fIspeed_factor\fR" 12
.IX Item "-s speed_factor"
This option causes \fBsudoreplay\fR to adjust the number of seconds
used to slow down or speed up the display. For example, a
\&\fIspeed_factor\fR of \fI2\fR would make the output twice as fast whereas
a \fIspeed_factor\fR of <.5> would make the output twice as slow.
-.IP "\-t \fItty\fR" 12
-.IX Item "-t tty"
-Restrict list output to sessions where the command was run on the
-specified terming device. The \fItty\fR should be specified without the
-\&\fI/dev/\fR prefix, e.g. \fItty01\fR instead of \fI/dev/tty01\fR.
-.IP "\-u \fIuser\fR" 12
-.IX Item "-u user"
-Restrict list output to sessions where the command was run by \fIuser\fR.
.IP "\-V" 12
.IX Item "-V"
The \fB\-V\fR (version) option causes \fBsudoreplay\fR to print its version number
B<sudoreplay> [B<-d> I<directory>] [B<-m> I<max_wait>] [B<-s> I<speed_factor>] ID
-B<sudoreplay> [B<-d> I<directory>] [B<-p> I<pattern>] [B<-t> I<tty>] [B<-u> I<user>] -l
+B<sudoreplay> [B<-d> I<directory>] -l [search expression]
=head1 DESCRIPTION
=item -l
Enable "list mode". In this mode, B<sudoreplay> will list available
-session IDs. The C<-p>, <-t> and <-u> options can be used to
-restrict the IDs that are displayed.
+session IDs. If a I<search expression> is specified, it will be
+used to restrict the IDs that are displayed. An expression is
+composed of the following predicates:
+
+=over 8
+
+=item user I<username>
+
+Evaluates to true if the ID matches a command run by I<username>.
+
+=item command I<command pattern>
+
+Evaluates to true if the command run matches I<command pattern>.
+On systems with POSIX regular expression support, the pattern may
+be an extended regular expression. On systems without POSIX regular
+expression support, a simple substring match is performed instead.
+
+=item tty I<tty>
+
+Evaluates to true if the command was run on the specified terminal
+device. The I<tty> should be specified without the F</dev/> prefix,
+e.g. F<tty01> instead of F</dev/tty01>.
+
+=item runas I<runas_user>
+
+Evaluates to true if the command was run as the specified I<runas_user>.
+Note that B<sudo> runs commands as user I<root> by default.
+
+=item runas I<runas_group>
+
+Evaluates to true if the command was run with the specified
+I<runas_group>. Note that unless a I<runas_group> was explicitly
+specified when B<sudo> was run this field will be empty in the log.
+
+=back
+
+Predicates may be combined using I<and>, I<or> and I<!> operators
+as well as C<'('> and C<')'> for grouping (note that parentheses
+must generally be escaped from the shell). The I<and> operator is
+optional, adjacent predicates have an implied I<and> unless separated
+by an I<or>.
=item -m I<max_wait>
to at most I<max_wait> seconds. The value may be specified as a
floating point number, .e.g. I<2.5>.
-=item -p I<pattern>
-
-Restrict list output to sessions where the command matches I<pattern>.
-On systems with POSIX regular expression support, the pattern may
-be an extended regular expression. On systems without POSIX regular
-expression support, a simple substring match is performed instead.
-
=item -s I<speed_factor>
This option causes B<sudoreplay> to adjust the number of seconds
I<speed_factor> of I<2> would make the output twice as fast whereas
a I<speed_factor> of <.5> would make the output twice as slow.
-=item -t I<tty>
-
-Restrict list output to sessions where the command was run on the
-specified terming device. The I<tty> should be specified without the
-F</dev/> prefix, e.g. F<tty01> instead of F</dev/tty01>.
-
-=item -u I<user>
-
-Restrict list output to sessions where the command was run by I<user>.
-
=item -V
The B<-V> (version) option causes B<sudoreplay> to print its version number