version 1.1.1.1, 2012/02/21 16:23:02
|
version 1.1.1.2, 2012/05/29 12:26:49
|
Line 1
|
Line 1
|
/* |
/* |
* Copyright (c) 2009-2011 Todd C. Miller <Todd.Miller@courtesan.com> | * Copyright (c) 2009-2012 Todd C. Miller <Todd.Miller@courtesan.com> |
* |
* |
* Permission to use, copy, modify, and distribute this software for any |
* Permission to use, copy, modify, and distribute this software for any |
* purpose with or without fee is hereby granted, provided that the above |
* purpose with or without fee is hereby granted, provided that the above |
Line 52
|
Line 52
|
#if TIME_WITH_SYS_TIME |
#if TIME_WITH_SYS_TIME |
# include <time.h> |
# include <time.h> |
#endif |
#endif |
#ifndef HAVE_TIMESPEC | #ifndef HAVE_STRUCT_TIMESPEC |
# include "compat/timespec.h" |
# include "compat/timespec.h" |
#endif |
#endif |
#include <ctype.h> |
#include <ctype.h> |
Line 85
|
Line 85
|
# include <locale.h> |
# include <locale.h> |
#endif |
#endif |
#include <signal.h> |
#include <signal.h> |
|
#ifdef HAVE_STDBOOL_H |
|
# include <stdbool.h> |
|
#else |
|
# include "compat/stdbool.h" |
|
#endif /* HAVE_STDBOOL_H */ |
|
|
#include <pathnames.h> |
#include <pathnames.h> |
|
|
Line 92
|
Line 97
|
#include "alloc.h" |
#include "alloc.h" |
#include "error.h" |
#include "error.h" |
#include "gettext.h" |
#include "gettext.h" |
|
#include "sudo_plugin.h" |
|
#include "sudo_conf.h" |
|
#include "sudo_debug.h" |
|
|
#ifndef LINE_MAX |
#ifndef LINE_MAX |
# define LINE_MAX 2048 |
# define LINE_MAX 2048 |
Line 133 struct log_info {
|
Line 141 struct log_info {
|
char *tty; |
char *tty; |
char *cmd; |
char *cmd; |
time_t tstamp; |
time_t tstamp; |
|
int rows; |
|
int cols; |
}; |
}; |
|
|
/* |
/* |
Line 170 struct search_node {
|
Line 180 struct search_node {
|
} u; |
} u; |
} *search_expr; |
} *search_expr; |
|
|
|
sudo_conv_t sudo_conv; /* NULL in non-plugin */ |
|
|
#define STACK_NODE_SIZE 32 |
#define STACK_NODE_SIZE 32 |
static struct search_node *node_stack[32]; |
static struct search_node *node_stack[32]; |
static int stack_top; |
static int stack_top; |
Line 190 extern time_t get_date(char *);
|
Line 202 extern time_t get_date(char *);
|
extern char *get_timestr(time_t, int); |
extern char *get_timestr(time_t, int); |
extern int term_raw(int, int); |
extern int term_raw(int, int); |
extern int term_restore(int, int); |
extern int term_restore(int, int); |
extern void zero_bytes(volatile void *, size_t); | extern void get_ttysize(int *rowp, int *colp); |
void cleanup(int); |
void cleanup(int); |
|
|
static int list_sessions(int, char **, const char *, const char *, const char *); |
static int list_sessions(int, char **, const char *, const char *, const char *); |
Line 201 static void help(void) __attribute__((__noreturn__));
|
Line 213 static void help(void) __attribute__((__noreturn__));
|
static void usage(int); |
static void usage(int); |
static int open_io_fd(char *pathbuf, int len, const char *suffix, union io_fd *fdp); |
static int open_io_fd(char *pathbuf, int len, const char *suffix, union io_fd *fdp); |
static int parse_timing(const char *buf, const char *decimal, int *idx, double *seconds, size_t *nbytes); |
static int parse_timing(const char *buf, const char *decimal, int *idx, double *seconds, size_t *nbytes); |
|
static struct log_info *parse_logfile(char *logfile); |
|
static void free_log_info(struct log_info *li); |
|
|
#ifdef HAVE_REGCOMP |
#ifdef HAVE_REGCOMP |
# define REGEX_T regex_t |
# define REGEX_T regex_t |
Line 220 static int parse_timing(const char *buf, const char *d
|
Line 234 static int parse_timing(const char *buf, const char *d
|
(s)[5] == '/' && \ |
(s)[5] == '/' && \ |
isalnum((unsigned char)(s)[6]) && isalnum((unsigned char)(s)[7]) && \ |
isalnum((unsigned char)(s)[6]) && isalnum((unsigned char)(s)[7]) && \ |
(s)[8] == '/' && (s)[9] == 'l' && (s)[10] == 'o' && (s)[11] == 'g' && \ |
(s)[8] == '/' && (s)[9] == 'l' && (s)[10] == 'o' && (s)[11] == 'g' && \ |
(s)[9] == '\0') | (s)[12] == '\0') |
|
|
int |
int |
main(int argc, char *argv[]) |
main(int argc, char *argv[]) |
{ |
{ |
int ch, idx, plen, nready, interactive = 0, listonly = 0; | int ch, idx, plen, nready, exitcode = 0, rows = 0, cols = 0; |
| bool interactive = false, listonly = false; |
const char *id, *user = NULL, *pattern = NULL, *tty = NULL, *decimal = "."; |
const char *id, *user = NULL, *pattern = NULL, *tty = NULL, *decimal = "."; |
char path[PATH_MAX], buf[LINE_MAX], *cp, *ep; |
char path[PATH_MAX], buf[LINE_MAX], *cp, *ep; |
double seconds, to_wait, speed = 1.0, max_wait = 0; |
double seconds, to_wait, speed = 1.0, max_wait = 0; |
FILE *lfile; |
|
fd_set *fdsw; |
fd_set *fdsw; |
sigaction_t sa; |
sigaction_t sa; |
size_t len, nbytes, nread, off; |
size_t len, nbytes, nread, off; |
ssize_t nwritten; |
ssize_t nwritten; |
|
struct log_info *li; |
|
debug_decl(main, SUDO_DEBUG_MAIN) |
|
|
|
#if defined(SUDO_DEVEL) && defined(__OpenBSD__) |
|
{ |
|
extern char *malloc_options; |
|
malloc_options = "AFGJPR"; |
|
} |
|
#endif |
|
|
#if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME) |
#if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME) |
setprogname(argc > 0 ? argv[0] : "sudoreplay"); |
setprogname(argc > 0 ? argv[0] : "sudoreplay"); |
#endif |
#endif |
Line 246 main(int argc, char *argv[])
|
Line 269 main(int argc, char *argv[])
|
bindtextdomain("sudoers", LOCALEDIR); /* XXX - should have sudoreplay domain */ |
bindtextdomain("sudoers", LOCALEDIR); /* XXX - should have sudoreplay domain */ |
textdomain("sudoers"); |
textdomain("sudoers"); |
|
|
|
/* Read sudo.conf. */ |
|
sudo_conf_read(); |
|
|
while ((ch = getopt(argc, argv, "d:f:hlm:s:V")) != -1) { |
while ((ch = getopt(argc, argv, "d:f:hlm:s:V")) != -1) { |
switch(ch) { |
switch(ch) { |
case 'd': |
case 'd': |
Line 269 main(int argc, char *argv[])
|
Line 295 main(int argc, char *argv[])
|
help(); |
help(); |
/* NOTREACHED */ |
/* NOTREACHED */ |
case 'l': |
case 'l': |
listonly = 1; | listonly = true; |
break; |
break; |
case 'm': |
case 'm': |
errno = 0; |
errno = 0; |
Line 285 main(int argc, char *argv[])
|
Line 311 main(int argc, char *argv[])
|
break; |
break; |
case 'V': |
case 'V': |
(void) printf(_("%s version %s\n"), getprogname(), PACKAGE_VERSION); |
(void) printf(_("%s version %s\n"), getprogname(), PACKAGE_VERSION); |
exit(0); | goto done; |
default: |
default: |
usage(1); |
usage(1); |
/* NOTREACHED */ |
/* NOTREACHED */ |
Line 295 main(int argc, char *argv[])
|
Line 321 main(int argc, char *argv[])
|
argc -= optind; |
argc -= optind; |
argv += optind; |
argv += optind; |
|
|
if (listonly) | if (listonly) { |
exit(list_sessions(argc, argv, pattern, user, tty)); | exitcode = list_sessions(argc, argv, pattern, user, tty); |
| goto done; |
| } |
|
|
if (argc != 1) |
if (argc != 1) |
usage(1); |
usage(1); |
Line 326 main(int argc, char *argv[])
|
Line 354 main(int argc, char *argv[])
|
} |
} |
} |
} |
|
|
/* Read log file. */ | /* Parse log file. */ |
path[plen] = '\0'; |
path[plen] = '\0'; |
strlcat(path, "/log", sizeof(path)); |
strlcat(path, "/log", sizeof(path)); |
lfile = fopen(path, "r"); | if ((li = parse_logfile(path)) == NULL) |
if (lfile == NULL) | exit(1); |
error(1, _("unable to open %s"), path); | printf(_("Replaying sudo session: %s\n"), li->cmd); |
cp = NULL; | |
len = 0; | /* Make sure the terminal is large enough. */ |
/* Pull out command (third line). */ | get_ttysize(&rows, &cols); |
if (getline(&cp, &len, lfile) == -1 || | if (li->rows != 0 && li->cols != 0) { |
getline(&cp, &len, lfile) == -1 || | if (li->rows > rows) { |
getline(&cp, &len, lfile) == -1) { | printf(_("Warning: your terminal is too small to properly replay the log.\n")); |
errorx(1, _("invalid log file %s"), path); | printf(_("Log geometry is %d x %d, your terminal's geometry is %d x %d."), li->rows, li->cols, rows, cols); |
| } |
} |
} |
printf(_("Replaying sudo session: %s"), cp); |
|
free(cp); |
|
fclose(lfile); |
|
|
|
|
/* Done with parsed log file. */ |
|
free_log_info(li); |
|
li = NULL; |
|
|
fflush(stdout); |
fflush(stdout); |
zero_bytes(&sa, sizeof(sa)); | memset(&sa, 0, sizeof(sa)); |
sigemptyset(&sa.sa_mask); |
sigemptyset(&sa.sa_mask); |
sa.sa_flags = SA_RESETHAND; |
sa.sa_flags = SA_RESETHAND; |
sa.sa_handler = cleanup; |
sa.sa_handler = cleanup; |
Line 368 main(int argc, char *argv[])
|
Line 398 main(int argc, char *argv[])
|
if (!term_raw(STDIN_FILENO, 1)) |
if (!term_raw(STDIN_FILENO, 1)) |
error(1, _("unable to set tty to raw mode")); |
error(1, _("unable to set tty to raw mode")); |
} |
} |
fdsw = (fd_set *)emalloc2(howmany(STDOUT_FILENO + 1, NFDBITS), | fdsw = ecalloc(howmany(STDOUT_FILENO + 1, NFDBITS), sizeof(fd_mask)); |
sizeof(fd_mask)); | |
|
|
/* |
/* |
* Timing file consists of line of the format: "%f %d\n" |
* Timing file consists of line of the format: "%f %d\n" |
Line 429 main(int argc, char *argv[])
|
Line 458 main(int argc, char *argv[])
|
} |
} |
} |
} |
term_restore(STDIN_FILENO, 1); |
term_restore(STDIN_FILENO, 1); |
exit(0); | done: |
| sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys, exitcode); |
| exit(exitcode); |
} |
} |
|
|
static void |
static void |
Line 452 delay(double secs)
|
Line 483 delay(double secs)
|
rval = nanosleep(&ts, &rts); |
rval = nanosleep(&ts, &rts); |
} while (rval == -1 && errno == EINTR); |
} while (rval == -1 && errno == EINTR); |
if (rval == -1) { |
if (rval == -1) { |
error(1, _("nanosleep: tv_sec %ld, tv_nsec %ld"), | error2(1, _("nanosleep: tv_sec %ld, tv_nsec %ld"), |
(long)ts.tv_sec, (long)ts.tv_nsec); |
(long)ts.tv_sec, (long)ts.tv_nsec); |
} |
} |
} |
} |
Line 462 open_io_fd(char *path, int len, const char *suffix, un
|
Line 493 open_io_fd(char *path, int len, const char *suffix, un
|
{ |
{ |
path[len] = '\0'; |
path[len] = '\0'; |
strlcat(path, suffix, PATH_MAX); |
strlcat(path, suffix, PATH_MAX); |
|
debug_decl(open_io_fd, SUDO_DEBUG_UTIL) |
|
|
#ifdef HAVE_ZLIB_H |
#ifdef HAVE_ZLIB_H |
fdp->g = gzopen(path, "r"); |
fdp->g = gzopen(path, "r"); |
return fdp->g ? 0 : -1; |
|
#else |
#else |
fdp->f = fopen(path, "r"); |
fdp->f = fopen(path, "r"); |
return fdp->f ? 0 : -1; |
|
#endif |
#endif |
|
debug_return_int(fdp->v ? 0 : -1); |
} |
} |
|
|
/* |
/* |
Line 480 parse_expr(struct search_node **headp, char *argv[])
|
Line 511 parse_expr(struct search_node **headp, char *argv[])
|
{ |
{ |
struct search_node *sn, *newsn; |
struct search_node *sn, *newsn; |
char or = 0, not = 0, type, **av; |
char or = 0, not = 0, type, **av; |
|
debug_decl(parse_expr, SUDO_DEBUG_UTIL) |
|
|
sn = *headp; |
sn = *headp; |
for (av = argv; *av; av++) { |
for (av = argv; *av; av++) { |
Line 556 parse_expr(struct search_node **headp, char *argv[])
|
Line 588 parse_expr(struct search_node **headp, char *argv[])
|
errorx(1, _("unmatched ')' in expression")); |
errorx(1, _("unmatched ')' in expression")); |
if (node_stack[stack_top]) |
if (node_stack[stack_top]) |
sn->next = node_stack[stack_top]->next; |
sn->next = node_stack[stack_top]->next; |
return av - argv + 1; | debug_return_int(av - argv + 1); |
bad: |
bad: |
default: |
default: |
errorx(1, _("unknown search term \"%s\""), *av); |
errorx(1, _("unknown search term \"%s\""), *av); |
Line 564 parse_expr(struct search_node **headp, char *argv[])
|
Line 596 parse_expr(struct search_node **headp, char *argv[])
|
} |
} |
|
|
/* Allocate new search node */ |
/* Allocate new search node */ |
newsn = emalloc(sizeof(*newsn)); | newsn = ecalloc(1, sizeof(*newsn)); |
newsn->next = NULL; | |
newsn->type = type; |
newsn->type = type; |
newsn->or = or; |
newsn->or = or; |
newsn->negated = not; |
newsn->negated = not; |
|
/* newsn->next = NULL; */ |
if (type == ST_EXPR) { |
if (type == ST_EXPR) { |
av += parse_expr(&newsn->u.expr, av + 1); |
av += parse_expr(&newsn->u.expr, av + 1); |
} else { |
} else { |
Line 602 parse_expr(struct search_node **headp, char *argv[])
|
Line 634 parse_expr(struct search_node **headp, char *argv[])
|
if (not) |
if (not) |
errorx(1, _("illegal trailing \"!\"")); |
errorx(1, _("illegal trailing \"!\"")); |
|
|
return av - argv; | debug_return_int(av - argv); |
} |
} |
|
|
static int | static bool |
match_expr(struct search_node *head, struct log_info *log) |
match_expr(struct search_node *head, struct log_info *log) |
{ |
{ |
struct search_node *sn; |
struct search_node *sn; |
int matched = 1, rc; | bool matched = true; |
| int rc; |
| debug_decl(match_expr, SUDO_DEBUG_UTIL) |
|
|
for (sn = head; sn; sn = sn->next) { |
for (sn = head; sn; sn = sn->next) { |
/* If we have no match, skip ahead to the next OR entry. */ |
/* If we have no match, skip ahead to the next OR entry. */ |
Line 658 match_expr(struct search_node *head, struct log_info *
|
Line 692 match_expr(struct search_node *head, struct log_info *
|
if (sn->negated) |
if (sn->negated) |
matched = !matched; |
matched = !matched; |
} |
} |
return matched; | debug_return_bool(matched); |
} |
} |
|
|
static int | static struct log_info * |
list_session(char *logfile, REGEX_T *re, const char *user, const char *tty) | parse_logfile(char *logfile) |
{ |
{ |
FILE *fp; |
FILE *fp; |
char *buf = NULL, *cmd = NULL, *cwd = NULL, idbuf[7], *idstr, *cp; | char *buf = NULL, *cp, *ep; |
struct log_info li; | |
size_t bufsize = 0, cwdsize = 0, cmdsize = 0; |
size_t bufsize = 0, cwdsize = 0, cmdsize = 0; |
int rval = -1; | struct log_info *li = NULL; |
| debug_decl(list_session, SUDO_DEBUG_UTIL) |
|
|
fp = fopen(logfile, "r"); |
fp = fopen(logfile, "r"); |
if (fp == NULL) { |
if (fp == NULL) { |
warning(_("unable to open %s"), logfile); |
warning(_("unable to open %s"), logfile); |
goto done; | goto bad; |
} |
} |
|
|
/* |
/* |
Line 682 list_session(char *logfile, REGEX_T *re, const char *u
|
Line 716 list_session(char *logfile, REGEX_T *re, const char *u
|
* 2) cwd |
* 2) cwd |
* 3) command with args |
* 3) command with args |
*/ |
*/ |
|
li = ecalloc(1, sizeof(*li)); |
if (getline(&buf, &bufsize, fp) == -1 || |
if (getline(&buf, &bufsize, fp) == -1 || |
getline(&cwd, &cwdsize, fp) == -1 || | getline(&li->cwd, &cwdsize, fp) == -1 || |
getline(&cmd, &cmdsize, fp) == -1) { | getline(&li->cmd, &cmdsize, fp) == -1) { |
goto done; | goto bad; |
} |
} |
|
|
/* crack the log line: timestamp:user:runas_user:runas_group:tty */ | /* Strip the newline from the cwd and command. */ |
| li->cwd[strcspn(li->cwd, "\n")] = '\0'; |
| li->cmd[strcspn(li->cmd, "\n")] = '\0'; |
| |
| /* |
| * Crack the log line (rows and cols not present in old versions). |
| * timestamp:user:runas_user:runas_group:tty:rows:cols |
| */ |
buf[strcspn(buf, "\n")] = '\0'; |
buf[strcspn(buf, "\n")] = '\0'; |
if ((li.tstamp = atoi(buf)) == 0) |
|
goto done; |
|
|
|
if ((cp = strchr(buf, ':')) == NULL) | /* timestamp */ |
goto done; | if ((ep = strchr(buf, ':')) == NULL) |
*cp++ = '\0'; | goto bad; |
li.user = cp; | if ((li->tstamp = atoi(buf)) == 0) |
| goto bad; |
|
|
if ((cp = strchr(cp, ':')) == NULL) | /* user */ |
goto done; | cp = ep + 1; |
*cp++ = '\0'; | if ((ep = strchr(cp, ':')) == NULL) |
li.runas_user = cp; | goto bad; |
| li->user = estrndup(cp, (size_t)(ep - cp)); |
|
|
if ((cp = strchr(cp, ':')) == NULL) | /* runas user */ |
goto done; | cp = ep + 1; |
*cp++ = '\0'; | if ((ep = strchr(cp, ':')) == NULL) |
li.runas_group = cp; | goto bad; |
| li->runas_user = estrndup(cp, (size_t)(ep - cp)); |
|
|
if ((cp = strchr(cp, ':')) == NULL) | /* runas group */ |
goto done; | cp = ep + 1; |
*cp++ = '\0'; | if ((ep = strchr(cp, ':')) == NULL) |
li.tty = cp; | goto bad; |
| if (cp != ep) |
| li->runas_group = estrndup(cp, (size_t)(ep - cp)); |
|
|
cwd[strcspn(cwd, "\n")] = '\0'; | /* tty, followed by optional rows + columns */ |
li.cwd = cwd; | cp = ep + 1; |
| if ((ep = strchr(cp, ':')) == NULL) { |
| li->tty = estrdup(cp); |
| } else { |
| li->tty = estrndup(cp, (size_t)(ep - cp)); |
| cp = ep + 1; |
| li->rows = atoi(cp); |
| if ((ep = strchr(cp, ':')) != NULL) { |
| cp = ep + 1; |
| li->cols = atoi(cp); |
| } |
| } |
| fclose(fp); |
| efree(buf); |
| debug_return_ptr(li); |
|
|
cmd[strcspn(cmd, "\n")] = '\0'; | bad: |
li.cmd = cmd; | fclose(fp); |
| efree(buf); |
| free_log_info(li); |
| debug_return_ptr(NULL); |
| } |
|
|
|
static void |
|
free_log_info(struct log_info *li) |
|
{ |
|
if (li != NULL) { |
|
efree(li->cwd); |
|
efree(li->user); |
|
efree(li->runas_user); |
|
efree(li->runas_group); |
|
efree(li->tty); |
|
efree(li->cmd); |
|
efree(li); |
|
} |
|
} |
|
|
|
static int |
|
list_session(char *logfile, REGEX_T *re, const char *user, const char *tty) |
|
{ |
|
char idbuf[7], *idstr, *cp; |
|
struct log_info *li; |
|
int rval = -1; |
|
debug_decl(list_session, SUDO_DEBUG_UTIL) |
|
|
|
if ((li = parse_logfile(logfile)) == NULL) |
|
goto done; |
|
|
/* Match on search expression if there is one. */ |
/* Match on search expression if there is one. */ |
if (search_expr && !match_expr(search_expr, &li)) | if (search_expr && !match_expr(search_expr, li)) |
goto done; |
goto done; |
|
|
/* Convert from /var/log/sudo-sessions/00/00/01/log to 000001 */ |
/* Convert from /var/log/sudo-sessions/00/00/01/log to 000001 */ |
cp = logfile + strlen(session_dir) + 1; |
cp = logfile + strlen(session_dir) + 1; |
if (IS_IDLOG(cp)) { |
if (IS_IDLOG(cp)) { |
idbuf[0] = cp[7]; | idbuf[0] = cp[0]; |
idbuf[1] = cp[6]; | idbuf[1] = cp[1]; |
idbuf[2] = cp[4]; | idbuf[2] = cp[3]; |
idbuf[3] = cp[3]; | idbuf[3] = cp[4]; |
idbuf[4] = cp[1]; | idbuf[4] = cp[6]; |
idbuf[5] = cp[0]; | idbuf[5] = cp[7]; |
idbuf[6] = '\0'; |
idbuf[6] = '\0'; |
idstr = idbuf; |
idstr = idbuf; |
} else { |
} else { |
Line 739 list_session(char *logfile, REGEX_T *re, const char *u
|
Line 827 list_session(char *logfile, REGEX_T *re, const char *u
|
cp[strlen(cp) - 4] = '\0'; |
cp[strlen(cp) - 4] = '\0'; |
idstr = cp; |
idstr = cp; |
} |
} |
|
/* XXX - print rows + cols? */ |
printf("%s : %s : TTY=%s ; CWD=%s ; USER=%s ; ", |
printf("%s : %s : TTY=%s ; CWD=%s ; USER=%s ; ", |
get_timestr(li.tstamp, 1), li.user, li.tty, li.cwd, li.runas_user); | get_timestr(li->tstamp, 1), li->user, li->tty, li->cwd, li->runas_user); |
if (*li.runas_group) | if (li->runas_group) |
printf("GROUP=%s ; ", li.runas_group); | printf("GROUP=%s ; ", li->runas_group); |
printf("TSID=%s ; COMMAND=%s\n", idstr, li.cmd); | printf("TSID=%s ; COMMAND=%s\n", idstr, li->cmd); |
|
|
rval = 0; |
rval = 0; |
|
|
done: |
done: |
fclose(fp); | free_log_info(li); |
return rval; | debug_return_int(rval); |
} |
} |
|
|
static int |
static int |
|
session_compare(const void *v1, const void *v2) |
|
{ |
|
const char *s1 = *(const char **)v1; |
|
const char *s2 = *(const char **)v2; |
|
return strcmp(s1, s2); |
|
} |
|
|
|
/* XXX - always returns 0, calls error() on failure */ |
|
static int |
find_sessions(const char *dir, REGEX_T *re, const char *user, const char *tty) |
find_sessions(const char *dir, REGEX_T *re, const char *user, const char *tty) |
{ |
{ |
DIR *d; |
DIR *d; |
struct dirent *dp; |
struct dirent *dp; |
struct stat sb; |
struct stat sb; |
size_t sdlen; | size_t sdlen, sessions_len = 0, sessions_size = 36*36; |
int len; | int i, len; |
char pathbuf[PATH_MAX]; | char pathbuf[PATH_MAX], **sessions = NULL; |
| debug_decl(find_sessions, SUDO_DEBUG_UTIL) |
|
|
d = opendir(dir); |
d = opendir(dir); |
if (d == NULL) |
if (d == NULL) |
Line 774 find_sessions(const char *dir, REGEX_T *re, const char
|
Line 873 find_sessions(const char *dir, REGEX_T *re, const char
|
} |
} |
pathbuf[sdlen++] = '/'; |
pathbuf[sdlen++] = '/'; |
pathbuf[sdlen] = '\0'; |
pathbuf[sdlen] = '\0'; |
|
|
|
/* Store potential session dirs for sorting. */ |
|
sessions = emalloc2(sessions_size, sizeof(char *)); |
while ((dp = readdir(d)) != NULL) { |
while ((dp = readdir(d)) != NULL) { |
/* Skip "." and ".." */ |
/* Skip "." and ".." */ |
if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || |
if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || |
(dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) |
(dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) |
continue; |
continue; |
|
#ifdef HAVE_STRUCT_DIRENT_D_TYPE |
|
if (dp->d_type != DT_DIR) |
|
continue; |
|
#endif |
|
|
|
/* Add name to session list. */ |
|
if (sessions_len + 1 > sessions_size) { |
|
sessions_size <<= 1; |
|
sessions = erealloc3(sessions, sessions_size, sizeof(char *)); |
|
} |
|
sessions[sessions_len++] = estrdup(dp->d_name); |
|
} |
|
closedir(d); |
|
|
|
/* Sort and list the sessions. */ |
|
qsort(sessions, sessions_len, sizeof(char *), session_compare); |
|
for (i = 0; i < sessions_len; i++) { |
len = snprintf(&pathbuf[sdlen], sizeof(pathbuf) - sdlen, |
len = snprintf(&pathbuf[sdlen], sizeof(pathbuf) - sdlen, |
"%s/log", dp->d_name); | "%s/log", sessions[i]); |
if (len <= 0 || len >= sizeof(pathbuf) - sdlen) { |
if (len <= 0 || len >= sizeof(pathbuf) - sdlen) { |
errno = ENAMETOOLONG; |
errno = ENAMETOOLONG; |
error(1, "%s/%s/log", dir, dp->d_name); | error(1, "%s/%s/log", dir, sessions[i]); |
} |
} |
|
efree(sessions[i]); |
|
|
/* Check for dir with a log file. */ |
/* Check for dir with a log file. */ |
if (lstat(pathbuf, &sb) == 0 && S_ISREG(sb.st_mode)) { |
if (lstat(pathbuf, &sb) == 0 && S_ISREG(sb.st_mode)) { |
Line 793 find_sessions(const char *dir, REGEX_T *re, const char
|
Line 912 find_sessions(const char *dir, REGEX_T *re, const char
|
} else { |
} else { |
/* Strip off "/log" and recurse if a dir. */ |
/* Strip off "/log" and recurse if a dir. */ |
pathbuf[sdlen + len - 4] = '\0'; |
pathbuf[sdlen + len - 4] = '\0'; |
|
#ifndef HAVE_STRUCT_DIRENT_D_TYPE |
if (lstat(pathbuf, &sb) == 0 && S_ISDIR(sb.st_mode)) |
if (lstat(pathbuf, &sb) == 0 && S_ISDIR(sb.st_mode)) |
|
#endif |
find_sessions(pathbuf, re, user, tty); |
find_sessions(pathbuf, re, user, tty); |
} |
} |
} |
} |
closedir(d); | efree(sessions); |
|
|
return 0; | debug_return_int(0); |
} |
} |
|
|
|
/* XXX - always returns 0, calls error() on failure */ |
static int |
static int |
list_sessions(int argc, char **argv, const char *pattern, const char *user, |
list_sessions(int argc, char **argv, const char *pattern, const char *user, |
const char *tty) |
const char *tty) |
{ |
{ |
REGEX_T rebuf, *re = NULL; |
REGEX_T rebuf, *re = NULL; |
|
debug_decl(list_sessions, SUDO_DEBUG_UTIL) |
|
|
/* Parse search expression if present */ |
/* Parse search expression if present */ |
parse_expr(&search_expr, argv); |
parse_expr(&search_expr, argv); |
Line 822 list_sessions(int argc, char **argv, const char *patte
|
Line 945 list_sessions(int argc, char **argv, const char *patte
|
re = (char *) pattern; |
re = (char *) pattern; |
#endif /* HAVE_REGCOMP */ |
#endif /* HAVE_REGCOMP */ |
|
|
return find_sessions(session_dir, re, user, tty); | debug_return_int(find_sessions(session_dir, re, user, tty)); |
} |
} |
|
|
/* |
/* |
Line 837 check_input(int ttyfd, double *speed)
|
Line 960 check_input(int ttyfd, double *speed)
|
struct timeval tv; |
struct timeval tv; |
char ch; |
char ch; |
ssize_t n; |
ssize_t n; |
|
debug_decl(check_input, SUDO_DEBUG_UTIL) |
|
|
fdsr = (fd_set *)emalloc2(howmany(ttyfd + 1, NFDBITS), sizeof(fd_mask)); | fdsr = ecalloc(howmany(ttyfd + 1, NFDBITS), sizeof(fd_mask)); |
| |
for (;;) { |
for (;;) { |
FD_SET(ttyfd, fdsr); |
FD_SET(ttyfd, fdsr); |
tv.tv_sec = 0; |
tv.tv_sec = 0; |
Line 868 check_input(int ttyfd, double *speed)
|
Line 991 check_input(int ttyfd, double *speed)
|
} |
} |
} |
} |
free(fdsr); |
free(fdsr); |
|
debug_return; |
} |
} |
|
|
/* |
/* |
Line 889 parse_timing(buf, decimal, idx, seconds, nbytes)
|
Line 1013 parse_timing(buf, decimal, idx, seconds, nbytes)
|
long l; |
long l; |
double d, fract = 0; |
double d, fract = 0; |
char *cp, *ep; |
char *cp, *ep; |
|
debug_decl(parse_timing, SUDO_DEBUG_UTIL) |
|
|
/* Parse index */ |
/* Parse index */ |
ul = strtoul(buf, &ep, 10); |
ul = strtoul(buf, &ep, 10); |
Line 929 parse_timing(buf, decimal, idx, seconds, nbytes)
|
Line 1054 parse_timing(buf, decimal, idx, seconds, nbytes)
|
goto bad; |
goto bad; |
*nbytes = (size_t)ul; |
*nbytes = (size_t)ul; |
|
|
return 1; | debug_return_int(1); |
bad: |
bad: |
return 0; | debug_return_int(0); |
} |
} |
|
|
static void |
static void |