mirror of
https://github.com/sudo-project/sudo.git
synced 2025-08-31 06:15:37 +00:00
Add support for selecting by pattern and tty when listing.
This commit is contained in:
180
sudoreplay.c
180
sudoreplay.c
@@ -73,6 +73,9 @@
|
|||||||
# include <ndir.h>
|
# include <ndir.h>
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_REGCOMP
|
||||||
|
# include <regex.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <pathnames.h>
|
#include <pathnames.h>
|
||||||
|
|
||||||
@@ -93,11 +96,24 @@ const char *session_dir = _PATH_SUDO_SESSDIR;
|
|||||||
|
|
||||||
void usage __P((void));
|
void usage __P((void));
|
||||||
void delay __P((double));
|
void delay __P((double));
|
||||||
int list_sessions __P((int, char **));
|
int list_sessions __P((int, char **, const char *, const char *));
|
||||||
|
|
||||||
|
#ifdef HAVE_REGCOMP
|
||||||
|
# define REGEX_T regex_t
|
||||||
|
#else
|
||||||
|
# define REGEX_T char
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TODO: expand ability to scan for session files:
|
* Things to think about:
|
||||||
* scan by command (regex?), user, tty, provide summary
|
* use a unique, inrementing id but break things up into lots of
|
||||||
|
* sub dirs like squid? Means keeping a seq file to track the next id.
|
||||||
|
* Just use a random uuid with multiple dirs?
|
||||||
|
* 550e8400-e29b-41d4-a716-446655440000
|
||||||
|
* Being able to select by user without opening all files is handy.
|
||||||
|
* Selecting by time could also be useful so an id that consists of a
|
||||||
|
* timestamp + random bits + username might be good.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -109,7 +125,7 @@ main(argc, argv)
|
|||||||
int listonly = 0;
|
int listonly = 0;
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
char buf[BUFSIZ];
|
char buf[BUFSIZ];
|
||||||
const char *user, *id, *tty = NULL;
|
const char *user, *id, *pattern = NULL, *tty = NULL;
|
||||||
char *cp, *ep;
|
char *cp, *ep;
|
||||||
FILE *tfile, *sfile, *lfile;
|
FILE *tfile, *sfile, *lfile;
|
||||||
double seconds;
|
double seconds;
|
||||||
@@ -120,7 +136,8 @@ main(argc, argv)
|
|||||||
Argc = argc;
|
Argc = argc;
|
||||||
Argv = argv;
|
Argv = argv;
|
||||||
|
|
||||||
while ((ch = getopt(argc, argv, "d:ls:t:")) != -1) {
|
/* XXX - timestamp option? (begin,end) */
|
||||||
|
while ((ch = getopt(argc, argv, "d:lp:s:t:")) != -1) {
|
||||||
switch(ch) {
|
switch(ch) {
|
||||||
case 'd':
|
case 'd':
|
||||||
session_dir = optarg;
|
session_dir = optarg;
|
||||||
@@ -128,6 +145,9 @@ main(argc, argv)
|
|||||||
case 'l':
|
case 'l':
|
||||||
listonly = 1;
|
listonly = 1;
|
||||||
break;
|
break;
|
||||||
|
case 'p':
|
||||||
|
pattern = optarg;
|
||||||
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
errno = 0;
|
errno = 0;
|
||||||
speed = strtod(optarg, &ep);
|
speed = strtod(optarg, &ep);
|
||||||
@@ -147,7 +167,7 @@ main(argc, argv)
|
|||||||
argv += optind;
|
argv += optind;
|
||||||
|
|
||||||
if (listonly) {
|
if (listonly) {
|
||||||
exit(list_sessions(argc, argv));
|
exit(list_sessions(argc, argv, pattern, tty));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argc != 2 && argc != 3)
|
if (argc != 2 && argc != 3)
|
||||||
@@ -177,9 +197,9 @@ main(argc, argv)
|
|||||||
if (lfile == NULL)
|
if (lfile == NULL)
|
||||||
error(1, "unable to open %s", path);
|
error(1, "unable to open %s", path);
|
||||||
|
|
||||||
/* XXX - better */
|
if (!fgets(buf, sizeof(buf), lfile) || !fgets(buf, sizeof(buf), lfile))
|
||||||
fgets(buf, sizeof(buf), lfile); /* XXX - ignore first line */
|
errorx(1, "incomplete log file: %s", path);
|
||||||
fgets(buf, sizeof(buf), lfile);
|
fclose(lfile);
|
||||||
printf("Replaying sudo session: %s", buf);
|
printf("Replaying sudo session: %s", buf);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -264,50 +284,124 @@ delay(secs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
list_sessions(argc, argv)
|
list_user_sessions(user, re, tty)
|
||||||
int argc;
|
const char *user;
|
||||||
char **argv;
|
REGEX_T *re;
|
||||||
|
const char *tty;
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
DIR *sess_d, *user_d;
|
DIR *user_d;
|
||||||
struct dirent *dp;
|
struct dirent *dp;
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX], buf[BUFSIZ], cmd[BUFSIZ];
|
||||||
char buf[BUFSIZ];
|
char *cmd_tty;
|
||||||
|
time_t tstamp;
|
||||||
int len, plen;
|
int len, plen;
|
||||||
|
|
||||||
|
plen = snprintf(path, sizeof(path), "%s/%s/", session_dir, user);
|
||||||
|
if (plen <= 0 || plen >= sizeof(path)) {
|
||||||
|
warning("%s/%s/: %s", session_dir, user, strerror(ENAMETOOLONG));
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
path[--plen] = '\0'; /* chop off the '/' for now */
|
||||||
|
user_d = opendir(path);
|
||||||
|
if (user_d == NULL && errno != ENOTDIR) {
|
||||||
|
warning("cannot opendir %s", path);
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
while ((dp = readdir(user_d)) != NULL) {
|
||||||
|
/* base session (log) file name is 10 characters */
|
||||||
|
len = NAMLEN(dp);
|
||||||
|
if (len != 10)
|
||||||
|
continue;
|
||||||
|
/* open log file, print id and command */
|
||||||
|
path[plen] = '/'; /* restore dir separator */
|
||||||
|
strlcpy(path + plen + 1, dp->d_name, sizeof(path) - plen - 1); /* XXX - check */
|
||||||
|
fp = fopen(path, "r");
|
||||||
|
if (fp == NULL) {
|
||||||
|
warning("unable to open %s", path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* ID file has two lines:
|
||||||
|
* timestamp tty
|
||||||
|
* command
|
||||||
|
*/
|
||||||
|
/* XXX - BUFSIZ might not be enough, implement getline? */
|
||||||
|
if (!fgets(buf, sizeof(buf), fp) || !fgets(cmd, sizeof(cmd), fp)) {
|
||||||
|
fclose(fp);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
buf[strcspn(buf, "\n")] = '\0';
|
||||||
|
cmd[strcspn(cmd, "\n")] = '\0';
|
||||||
|
tstamp = atoi(buf);
|
||||||
|
cmd_tty = strchr(buf, ' ');
|
||||||
|
if (tstamp == 0 || cmd_tty == NULL)
|
||||||
|
continue;
|
||||||
|
cmd_tty++;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Select based on tty and/or regex if applicable.
|
||||||
|
*/
|
||||||
|
if (tty && strcmp(tty, cmd_tty) == 0)
|
||||||
|
continue;
|
||||||
|
if (re) {
|
||||||
|
#ifdef HAVE_REGCOMP
|
||||||
|
int rc = regexec(re, cmd, 0, NULL, 0);
|
||||||
|
if (rc) {
|
||||||
|
if (rc == REG_NOMATCH)
|
||||||
|
continue;
|
||||||
|
regerror(rc, re, buf, sizeof(buf));
|
||||||
|
errorx(1, "%s", buf);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (strstr(cmd, re) == NULL)
|
||||||
|
continue;
|
||||||
|
#endif /* HAVE_REGCOMP */
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%s: %s\n", dp->d_name, cmd);
|
||||||
|
}
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
list_sessions(argc, argv, pattern, tty)
|
||||||
|
int argc;
|
||||||
|
char **argv;
|
||||||
|
const char *pattern;
|
||||||
|
const char *tty;
|
||||||
|
{
|
||||||
|
DIR *sess_d;
|
||||||
|
struct dirent *dp;
|
||||||
|
REGEX_T rebuf, *re = NULL;
|
||||||
|
const char *user = NULL;
|
||||||
|
|
||||||
sess_d = opendir(session_dir);
|
sess_d = opendir(session_dir);
|
||||||
if (sess_d == NULL)
|
if (sess_d == NULL)
|
||||||
error(1, "unable to open %s", session_dir);
|
error(1, "unable to open %s", session_dir);
|
||||||
|
|
||||||
/* XXX - ignores optional user and tty for now */
|
#ifdef HAVE_REGCOMP
|
||||||
|
/* optional regex */
|
||||||
|
if (pattern) {
|
||||||
|
re = &rebuf;
|
||||||
|
if (regcomp(re, pattern, REG_EXTENDED|REG_NOSUB) != 0)
|
||||||
|
errorx(1, "invalid regex: %s", pattern);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
re = (char *) pattern;
|
||||||
|
#endif /* HAVE_REGCOMP */
|
||||||
|
|
||||||
|
/* optional user */
|
||||||
|
if (argc == 1) {
|
||||||
|
user = argv[0];
|
||||||
|
return(list_user_sessions(user, re, tty));
|
||||||
|
}
|
||||||
|
|
||||||
while ((dp = readdir(sess_d)) != NULL) {
|
while ((dp = readdir(sess_d)) != NULL) {
|
||||||
if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
|
if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
|
||||||
continue;
|
continue;
|
||||||
plen = snprintf(path, sizeof(path), "%s/%s/", session_dir, dp->d_name);
|
list_user_sessions(dp->d_name, re, tty);
|
||||||
if (plen <= 0 || plen >= sizeof(path)) {
|
|
||||||
/* XXX - warn */
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
path[--plen] = '\0'; /* chop off the '/' for now */
|
|
||||||
user_d = opendir(path);
|
|
||||||
if (user_d == NULL && errno != ENOTDIR) {
|
|
||||||
warning("cannot opendir %s", path);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
while ((dp = readdir(user_d)) != NULL) {
|
|
||||||
/* base session (log) file name is 10 characters */
|
|
||||||
len = NAMLEN(dp);
|
|
||||||
if (len != 10)
|
|
||||||
continue;
|
|
||||||
/* open log file, print id and command */
|
|
||||||
path[plen] = '/'; /* restore dir separator */
|
|
||||||
strlcpy(path + plen + 1, dp->d_name, sizeof(path) - plen - 1); /* XXX - check */
|
|
||||||
fp = fopen(path, "r");
|
|
||||||
fgets(buf, sizeof(buf), fp); /* XXX - ignore first line */
|
|
||||||
fgets(buf, sizeof(buf), fp);
|
|
||||||
printf("%s: %s", dp->d_name, buf);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
closedir(sess_d);
|
closedir(sess_d);
|
||||||
return(0);
|
return(0);
|
||||||
@@ -316,7 +410,11 @@ list_sessions(argc, argv)
|
|||||||
void
|
void
|
||||||
usage()
|
usage()
|
||||||
{
|
{
|
||||||
fprintf(stderr, "usage: %s [-d directory] username ID [speed_factor]\n",
|
fprintf(stderr,
|
||||||
|
"usage: %s [-d directory] [-s speed_factor] username ID\n",
|
||||||
|
getprogname());
|
||||||
|
fprintf(stderr,
|
||||||
|
"usage: %s [-d directory] [-l] [-p pattern] [-t tty] [username]\n",
|
||||||
getprogname());
|
getprogname());
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user