Add support for replaying sessions when iolog_file is set to something

other than %{seq}.
This commit is contained in:
Todd C. Miller
2011-03-04 20:10:44 -05:00
parent f5e356ed40
commit 85e8e584ae

View File

@@ -212,6 +212,15 @@ static int parse_timing(const char *buf, const char *decimal, int *idx, double *
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(int argc, char *argv[])
{
@@ -289,16 +298,21 @@ main(int argc, char *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/%.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/%.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. */
@@ -642,104 +656,143 @@ match_expr(struct search_node *head, struct log_info *log)
}
static int
list_session_dir(char *pathbuf, REGEX_T *re, const char *user, const char *tty)
list_session(char *logfile, REGEX_T *re, const char *user, const char *tty)
{
FILE *fp;
char *buf = NULL, *cmd = NULL, *cwd = NULL, idbuf[7], *idstr, *cp;
struct log_info li;
size_t bufsize = 0, cwdsize = 0, cmdsize = 0;
int rval = -1;
fp = fopen(logfile, "r");
if (fp == NULL) {
warning("unable to open %s", logfile);
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) {
goto done;
}
/* 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);
rval = 0;
done:
fclose(fp);
return rval;
}
static int
find_sessions(const char *dir, REGEX_T *re, const char *user, const char *tty)
{
DIR *d;
struct dirent *dp;
char *buf = NULL, *cmd = NULL, *cwd = NULL, idstr[7], *cp;
struct log_info li;
size_t bufsize = 0, cwdsize = 0, cmdsize = 0, plen;
struct stat sb;
size_t sdlen;
int len;
char pathbuf[PATH_MAX];
plen = strlen(pathbuf);
d = opendir(pathbuf);
if (d == NULL && errno != ENOTDIR) {
warning("cannot opendir %s", pathbuf);
return -1;
d = opendir(dir);
if (d == NULL)
error(1, "unable to open %s", dir);
/* 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) {
if (NAMLEN(dp) != 2 || !isalnum((unsigned char)dp->d_name[0]) ||
!isalnum((unsigned char)dp->d_name[1]))
/* Skip "." and ".." */
if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' ||
(dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
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;
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);
}
/*
* 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;
/* 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);
}
fclose(fp);
/* crack the log line: timestamp:user:runas_user:runas_group:tty */
buf[strcspn(buf, "\n")] = '\0';
if ((li.tstamp = atoi(buf)) == 0)
continue;
if ((cp = strchr(buf, ':')) == NULL)
continue;
*cp++ = '\0';
li.user = cp;
if ((cp = strchr(cp, ':')) == NULL)
continue;
*cp++ = '\0';
li.runas_user = cp;
if ((cp = strchr(cp, ':')) == NULL)
continue;
*cp++ = '\0';
li.runas_group = cp;
if ((cp = strchr(cp, ':')) == NULL)
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;
/* 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);
}
closedir(d);
return 0;
}
@@ -747,19 +800,11 @@ static int
list_sessions(int argc, char **argv, const char *pattern, 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) {
@@ -771,44 +816,7 @@ list_sessions(int argc, char **argv, const char *pattern, const char *user,
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);
}
/*