2
0
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:
Todd C. Miller
2009-08-23 13:33:26 +00:00
parent 30cfb7160e
commit 9efd18b1bb

View File

@@ -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);
} }