]> granicus.if.org Git - sudo/commitdiff
Implement search expressions in sudoreplay similar in concept to
authorTodd C. Miller <Todd.Miller@courtesan.com>
Sun, 13 Sep 2009 22:02:07 +0000 (22:02 +0000)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Sun, 13 Sep 2009 22:02:07 +0000 (22:02 +0000)
what find or tcpdump uses.  TODO: date ranges

Makefile.in
sudoreplay.c
sudoreplay.cat
sudoreplay.man.in
sudoreplay.pod

index 30c3b54ea2443b4159eaf75ad6665c6e9d33eb14..870b0b2362d9d94edbfb3135cf85bfa074327035 100644 (file)
@@ -137,7 +137,7 @@ SUDO_OBJS = $(COMMON_OBJS) $(AUTH_OBJS) @SUDO_OBJS@ audit.o check.o env.o \
 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
 
@@ -154,8 +154,8 @@ DISTFILES = $(SRCS) $(HDRS) ChangeLog HISTORY INSTALL INSTALL.configure \
            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 \
index 3d997e2cfc5723261b824e0f751d013018f4c98e..09492cd6744b0d41900c2c478bb6a51f5f3c6452 100644 (file)
@@ -94,9 +94,58 @@ int Argc;
 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
@@ -136,7 +185,7 @@ main(argc, argv)
     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;
@@ -150,21 +199,12 @@ main(argc, argv)
            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);
@@ -177,9 +217,8 @@ main(argc, argv)
     argc -= optind;
     argv += optind;
 
-    if (listonly) {
+    if (listonly)
        exit(list_sessions(argc, argv, pattern, user, tty));
-    }
 
     if (argc != 1)
        usage();
@@ -279,7 +318,7 @@ nanosleep(ts, rts)
 }
 #endif
 
-void
+static void
 delay(secs)
     double secs;
 {
@@ -303,14 +342,149 @@ delay(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)
@@ -385,28 +559,9 @@ 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];
@@ -417,13 +572,13 @@ list_session_dir(pathbuf, re, user, tty)
        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;
@@ -437,6 +592,9 @@ list_sessions(argc, argv, pattern, user, tty)
     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);
@@ -488,14 +646,14 @@ list_sessions(argc, argv, pattern, user, tty)
     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);
 }
index 7ebd8f30b7081a4e9a39c663938c2956260bc052..fcee651ca97648d9029419a0846bd0611a58aca2 100644 (file)
@@ -10,7 +10,7 @@ N\bNA\bAM\bME\bE
 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
@@ -31,8 +31,56 @@ O\bOP\bPT\bTI\bIO\bON\bNS\bS
                    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
@@ -43,12 +91,6 @@ O\bOP\bPT\bTI\bIO\bON\bNS\bS
                    _\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.
@@ -57,26 +99,6 @@ O\bOP\bPT\bTI\bIO\bON\bNS\bS
                    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.
 
@@ -102,6 +124,18 @@ B\bBU\bUG\bGS\bS
        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
@@ -127,6 +161,38 @@ D\bDI\bIS\bSC\bCL\bLA\bAI\bIM\bME\bER\bR
 
 
 
-1.7.2                    August 30, 2009                        2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1.7.2                   September 13, 2009                      3
 
 
index 9b2c7e3b3652f650fd3c76cca1766e23dc465b21..158764e810d0ceba6c67c77260050d11e7f8234e 100644 (file)
 .\" ========================================================================
 .\"
 .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
@@ -159,7 +159,7 @@ sudoreplay \- replay sudo session logs
 .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
@@ -182,8 +182,42 @@ Use \fIdirectory\fR to for the session logs instead of the default,
 .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
@@ -193,12 +227,6 @@ can be tedious when the session includes long pauses.  When the
 \&\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
@@ -206,14 +234,6 @@ it will wait between key presses or program output.  This can be
 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
index 5e3d8daec809a77bc9cdcc559bbf5761c2192bbb..aebbcd952748ea76d6d6d63e32bf09c64e2c9ea8 100644 (file)
@@ -24,7 +24,7 @@ sudoreplay - replay sudo session logs
 
 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
 
@@ -53,8 +53,47 @@ F</var/log/sudo-sessions>.
 =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>
 
@@ -66,13 +105,6 @@ I<-m> option is specified, B<sudoreplay> will limit these pauses
 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
@@ -81,16 +113,6 @@ used to slow down or speed up the display.  For example, a
 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