]> granicus.if.org Git - sudo/commitdiff
Add support for replaying sessions from sudo 1.8 when iolog_file
authorTodd C. Miller <Todd.Miller@courtesan.com>
Wed, 23 May 2012 14:28:58 +0000 (10:28 -0400)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Wed, 23 May 2012 14:28:58 +0000 (10:28 -0400)
is set to something other than %{seq}.

--HG--
branch : 1.7

sudoreplay.c

index 56a27cb0fe4468b78cf4a7b03a8015b335d319bb..1f377227aec1990d5d022d5ca787c8f48111277a 100644 (file)
@@ -214,6 +214,15 @@ static int parse_timing __P((const char *buf, const char *decimal, int *idx, dou
     isalnum((unsigned char)(s)[3]) && isalnum((unsigned char)(s)[4]) && \
     isalnum((unsigned char)(s)[5]) && (s)[6] == '\0')
 
+#define IS_IDLOG(s) ( \
+    isalnum((unsigned char)(s)[0]) && isalnum((unsigned char)(s)[1]) && \
+    (s)[2] == '/' && \
+    isalnum((unsigned char)(s)[3]) && isalnum((unsigned char)(s)[4]) && \
+    (s)[5] == '/' && \
+    isalnum((unsigned char)(s)[6]) && isalnum((unsigned char)(s)[7]) && \
+    (s)[8] == '/' && (s)[9] == 'l' && (s)[10] == 'o' && (s)[11] == 'g' && \
+    (s)[9] == '\0')
+
 int
 main(argc, argv)
     int argc;
@@ -292,16 +301,21 @@ main(argc, argv)
     if (argc != 1)
        usage(1);
 
-    /* 6 digit ID in base 36, e.g. 01G712AB */
+    /* 6 digit ID in base 36, e.g. 01G712AB or free-form name */
     id = argv[0];
-    if (!VALID_ID(id))
-       errorx(1, "invalid ID %s", id);
-
-    plen = snprintf(path, sizeof(path), "%s/%.2s/%.2s/%.2s/timing",
-       session_dir, id, &id[2], &id[4]);
-    if (plen <= 0 || plen >= sizeof(path))
-       errorx(1, "%s/%.2s/%.2s/%.2s/timing: %s", session_dir,
-           id, &id[2], &id[4], strerror(ENAMETOOLONG));
+    if (VALID_ID(id)) {
+       plen = snprintf(path, sizeof(path), "%s/%.2s/%.2s/%.2s/timing",
+           session_dir, id, &id[2], &id[4]);
+       if (plen <= 0 || plen >= sizeof(path))
+           errorx(1, "%s/%.2s/%.2s/%.2s/timing: %s", session_dir,
+               id, &id[2], &id[4], strerror(ENAMETOOLONG));
+    } else {
+       plen = snprintf(path, sizeof(path), "%s/%s/timing",
+           session_dir, id);
+       if (plen <= 0 || plen >= sizeof(path))
+           errorx(1, "%s/%s/timing: %s", session_dir,
+               id, strerror(ENAMETOOLONG));
+    }
     plen -= 7;
 
     /* Open files for replay, applying replay filter for the -f flag. */
@@ -654,108 +668,151 @@ match_expr(head, log)
 }
 
 static int
-list_session_dir(pathbuf, re, user, tty)
-    char *pathbuf;
+list_session(logfile, re, user, tty)
+    char *logfile;
     REGEX_T *re;
     const char *user;
     const char *tty;
 {
     FILE *fp;
-    DIR *d;
-    struct dirent *dp;
-    char *buf = NULL, *cmd = NULL, *cwd = NULL, idstr[7], *cp;
+    char *buf = NULL, *cmd = NULL, *cwd = NULL, idbuf[7], *idstr, *cp;
     struct log_info li;
-    size_t bufsize = 0, cwdsize = 0, cmdsize = 0, plen;
+    size_t bufsize = 0, cwdsize = 0, cmdsize = 0;
+    int rval = -1;
 
-    plen = strlen(pathbuf);
-    d = opendir(pathbuf);
-    if (d == NULL && errno != ENOTDIR) {
-       warning("cannot opendir %s", pathbuf);
-       return -1;
+    fp = fopen(logfile, "r");
+    if (fp == NULL) {
+       warning("unable to open %s", logfile);
+       goto done;
     }
-    while ((dp = readdir(d)) != NULL) {
-       if (NAMLEN(dp) != 2 || !isalnum((unsigned char)dp->d_name[0]) ||
-           !isalnum((unsigned char)dp->d_name[1]))
-           continue;
 
-       /* open log file, print id and command */
-       pathbuf[plen + 0] = '/';
-       pathbuf[plen + 1] = dp->d_name[0];
-       pathbuf[plen + 2] = dp->d_name[1];
-       pathbuf[plen + 3] = '/';
-       pathbuf[plen + 4] = 'l';
-       pathbuf[plen + 5] = 'o';
-       pathbuf[plen + 6] = 'g';
-       pathbuf[plen + 7] = '\0';
-       fp = fopen(pathbuf, "r");
-       if (fp == NULL) {
-           warning("unable to open %s", pathbuf);
-           continue;
-       }
+    /*
+     * ID file has three lines:
+     *  1) a log info line
+     *  2) cwd
+     *  3) command with args
+     */
+    if (getline(&buf, &bufsize, fp) == -1 ||
+       getline(&cwd, &cwdsize, fp) == -1 ||
+       getline(&cmd, &cmdsize, fp) == -1) {
+       goto done;
+    }
 
-       /*
-        * ID file has three lines:
-        *  1) a log info line
-        *  2) cwd
-        *  3) command with args
-        */
-       if (getline(&buf, &bufsize, fp) == -1 ||
-           getline(&cwd, &cwdsize, fp) == -1 ||
-           getline(&cmd, &cmdsize, fp) == -1) {
-           fclose(fp);
-           continue;
-       }
-       fclose(fp);
+    /* crack the log line: timestamp:user:runas_user:runas_group:tty */
+    buf[strcspn(buf, "\n")] = '\0';
+    if ((li.tstamp = atoi(buf)) == 0)
+       goto done;
+
+    if ((cp = strchr(buf, ':')) == NULL)
+       goto done;
+    *cp++ = '\0';
+    li.user = cp;
+
+    if ((cp = strchr(cp, ':')) == NULL)
+       goto done;
+    *cp++ = '\0';
+    li.runas_user = cp;
+
+    if ((cp = strchr(cp, ':')) == NULL)
+       goto done;
+    *cp++ = '\0';
+    li.runas_group = cp;
+
+    if ((cp = strchr(cp, ':')) == NULL)
+       goto done;
+    *cp++ = '\0';
+    li.tty = cp;
+
+    cwd[strcspn(cwd, "\n")] = '\0';
+    li.cwd = cwd;
+
+    cmd[strcspn(cmd, "\n")] = '\0';
+    li.cmd = cmd;
+
+    /* Match on search expression if there is one. */
+    if (search_expr && !match_expr(search_expr, &li))
+       goto done;
+
+    /* Convert from /var/log/sudo-sessions/00/00/01/log to 000001 */
+    cp = logfile + strlen(session_dir) + 1;
+    if (IS_IDLOG(cp)) {
+       idbuf[0] = cp[7];
+       idbuf[1] = cp[6];
+       idbuf[2] = cp[4];
+       idbuf[3] = cp[3];
+       idbuf[4] = cp[1];
+       idbuf[5] = cp[0];
+       idbuf[6] = '\0';
+       idstr = idbuf;
+    } else {
+       /* Not an id, just use the iolog_file portion. */
+       cp[strlen(cp) - 4] = '\0';
+       idstr = cp;
+    }
+    printf("%s : %s : TTY=%s ; CWD=%s ; USER=%s ; ",
+       get_timestr(li.tstamp, 1), li.user, li.tty, li.cwd, li.runas_user);
+    if (*li.runas_group)
+       printf("GROUP=%s ; ", li.runas_group);
+    printf("TSID=%s ; COMMAND=%s\n", idstr, li.cmd);
 
-       /* crack the log line: timestamp:user:runas_user:runas_group:tty */
-       buf[strcspn(buf, "\n")] = '\0';
-       if ((li.tstamp = atoi(buf)) == 0)
-           continue;
+    rval = 0;
 
-       if ((cp = strchr(buf, ':')) == NULL)
-           continue;
-       *cp++ = '\0';
-       li.user = cp;
+done:
+    fclose(fp);
+    return rval;
+}
 
-       if ((cp = strchr(cp, ':')) == NULL)
-           continue;
-       *cp++ = '\0';
-       li.runas_user = cp;
+static int
+find_sessions(dir, re, user, tty)
+    const char *dir;
+    REGEX_T *re;
+    const char *user;
+    const char *tty;
+{
+    DIR *d;
+    struct dirent *dp;
+    struct stat sb;
+    size_t sdlen;
+    int len;
+    char pathbuf[PATH_MAX];
 
-       if ((cp = strchr(cp, ':')) == NULL)
-           continue;
-       *cp++ = '\0';
-       li.runas_group = cp;
+    d = opendir(dir);
+    if (d == NULL)
+       error(1, "unable to open %s", dir);
 
-       if ((cp = strchr(cp, ':')) == NULL)
+    /* XXX - would be faster to chdir and use relative names */
+    sdlen = strlcpy(pathbuf, dir, sizeof(pathbuf));
+    if (sdlen + 1 >= sizeof(pathbuf)) {
+       errno = ENAMETOOLONG;
+       error(1, "%s/", dir);
+    }
+    pathbuf[sdlen++] = '/';
+    pathbuf[sdlen] = '\0';
+    while ((dp = readdir(d)) != NULL) {
+       /* Skip "." and ".." */
+       if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' ||
+           (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
            continue;
-       *cp++ = '\0';
-       li.tty = cp;
 
-       cwd[strcspn(cwd, "\n")] = '\0';
-       li.cwd = cwd;
-
-       cmd[strcspn(cmd, "\n")] = '\0';
-       li.cmd = cmd;
-
-       /* Match on search expression if there is one. */
-       if (search_expr && !match_expr(search_expr, &li))
-           continue;
+       len = snprintf(&pathbuf[sdlen], sizeof(pathbuf) - sdlen,
+           "%s/log", dp->d_name);
+       if (len <= 0 || len >= sizeof(pathbuf) - sdlen) {
+           errno = ENAMETOOLONG;
+           error(1, "%s/%s/log", dir, dp->d_name);
+       }
 
-       /* Convert from /var/log/sudo-sessions/00/00/01 to 000001 */
-       idstr[0] = pathbuf[plen - 5];
-       idstr[1] = pathbuf[plen - 4];
-       idstr[2] = pathbuf[plen - 2];
-       idstr[3] = pathbuf[plen - 1];
-       idstr[4] = pathbuf[plen + 1];
-       idstr[5] = pathbuf[plen + 2];
-       idstr[6] = '\0';
-       printf("%s : %s : TTY=%s ; CWD=%s ; USER=%s ; ",
-           get_timestr(li.tstamp, 1), li.user, li.tty, li.cwd, li.runas_user);
-       if (*li.runas_group)
-           printf("GROUP=%s ; ", li.runas_group);
-       printf("TSID=%s ; COMMAND=%s\n", idstr, li.cmd);
+       /* Check for dir with a log file. */
+       if (lstat(pathbuf, &sb) == 0 && S_ISREG(sb.st_mode)) {
+           list_session(pathbuf, re, user, tty);
+       } else {
+           /* Strip off "/log" and recurse if a dir. */
+           pathbuf[sdlen + len - 4] = '\0';
+           if (lstat(pathbuf, &sb) == 0 && S_ISDIR(sb.st_mode))
+               find_sessions(pathbuf, re, user, tty);
+       }
     }
+    closedir(d);
+
     return 0;
 }
 
@@ -767,19 +824,11 @@ list_sessions(argc, argv, pattern, user, tty)
     const char *user;
     const char *tty;
 {
-    DIR *d1, *d2;
-    struct dirent *dp1, *dp2;
     REGEX_T rebuf, *re = NULL;
-    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);
-
 #ifdef HAVE_REGCOMP
     /* optional regex */
     if (pattern) {
@@ -791,44 +840,7 @@ list_sessions(argc, argv, pattern, user, tty)
     re = (char *) pattern;
 #endif /* HAVE_REGCOMP */
 
-    sdlen = strlcpy(pathbuf, session_dir, sizeof(pathbuf));
-    if (sdlen + sizeof("/00/00/00/log") >= sizeof(pathbuf)) {
-       errno = ENAMETOOLONG;
-       error(1, "%s/00/00/00/log", session_dir);
-    }
-
-    /*
-     * Three levels of directory, e.g. 00/00/00 .. ZZ/ZZ/ZZ
-     * We do a depth-first traversal.
-     */
-    while ((dp1 = readdir(d1)) != NULL) {
-       if (NAMLEN(dp1) != 2 || !isalnum((unsigned char)dp1->d_name[0]) ||
-           !isalnum((unsigned char)dp1->d_name[1]))
-           continue;
-
-       pathbuf[sdlen + 0] = '/';
-       pathbuf[sdlen + 1] = dp1->d_name[0];
-       pathbuf[sdlen + 2] = dp1->d_name[1];
-       pathbuf[sdlen + 3] = '\0';
-       d2 = opendir(pathbuf);
-       if (d2 == NULL)
-           continue;
-
-       while ((dp2 = readdir(d2)) != NULL) {
-           if (NAMLEN(dp2) != 2 || !isalnum((unsigned char)dp2->d_name[0]) ||
-               !isalnum((unsigned char)dp2->d_name[1]))
-               continue;
-
-           pathbuf[sdlen + 3] = '/';
-           pathbuf[sdlen + 4] = dp2->d_name[0];
-           pathbuf[sdlen + 5] = dp2->d_name[1];
-           pathbuf[sdlen + 6] = '\0';
-           list_session_dir(pathbuf, re, user, tty);
-       }
-       closedir(d2);
-    }
-    closedir(d1);
-    return 0;
+    return find_sessions(session_dir, re, user, tty);
 }
 
 /*