mirror of
https://github.com/sudo-project/sudo.git
synced 2025-08-30 13:58:05 +00:00
Use openat(2) when opening files in the I/O log directory.
This commit is contained in:
@@ -102,12 +102,14 @@ struct iolog_path_escape {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* iolog_path.c */
|
/* iolog_path.c */
|
||||||
|
/* XXX - bad API */
|
||||||
char *expand_iolog_path(const char *prefix, const char *dir, const char *file, char **slashp, const struct iolog_path_escape *escapes, void *closure);
|
char *expand_iolog_path(const char *prefix, const char *dir, const char *file, char **slashp, const struct iolog_path_escape *escapes, void *closure);
|
||||||
|
|
||||||
/* iolog_util.c */
|
/* iolog_util.c */
|
||||||
|
/* XXX - prefix these */
|
||||||
bool parse_timing(const char *line, struct timing_closure *timing);
|
bool parse_timing(const char *line, struct timing_closure *timing);
|
||||||
char *parse_delay(const char *cp, struct timespec *delay, const char *decimal_point);
|
char *parse_delay(const char *cp, struct timespec *delay, const char *decimal_point);
|
||||||
struct iolog_info *parse_logfile(const char *logfile);
|
struct iolog_info *parse_logfile(FILE *fp, const char *iolog_dir);
|
||||||
void free_iolog_info(struct iolog_info *li);
|
void free_iolog_info(struct iolog_info *li);
|
||||||
void adjust_delay(struct timespec *delay, struct timespec *max_delay, double scale_factor);
|
void adjust_delay(struct timespec *delay, struct timespec *max_delay, double scale_factor);
|
||||||
|
|
||||||
@@ -117,19 +119,20 @@ struct group;
|
|||||||
bool iolog_close(struct iolog_file *iol, const char **errstr);
|
bool iolog_close(struct iolog_file *iol, const char **errstr);
|
||||||
bool iolog_eof(struct iolog_file *iol);
|
bool iolog_eof(struct iolog_file *iol);
|
||||||
bool iolog_nextid(char *iolog_dir, char sessid[7]);
|
bool iolog_nextid(char *iolog_dir, char sessid[7]);
|
||||||
bool iolog_open(struct iolog_file *iol, char *pathbuf, const char *mode);
|
bool iolog_open(struct iolog_file *iol, int dfd, int iofd, const char *mode);
|
||||||
bool iolog_set_compress(const char *str);
|
bool iolog_set_compress(const char *str);
|
||||||
bool iolog_set_flush(const char *str);
|
bool iolog_set_flush(const char *str);
|
||||||
bool iolog_set_group(const struct group *gr);
|
bool iolog_set_group(const struct group *gr);
|
||||||
bool iolog_set_maxseq(const char *maxval);
|
bool iolog_set_maxseq(const char *maxval);
|
||||||
bool iolog_set_mode(mode_t mode);
|
bool iolog_set_mode(mode_t mode);
|
||||||
bool iolog_set_user(const struct passwd *pw);
|
bool iolog_set_user(const struct passwd *pw);
|
||||||
bool iolog_write_info_file(const char *parent, struct iolog_info *log_info, char * const argv[]);
|
bool iolog_write_info_file(int dfd, const char *parent, struct iolog_info *log_info, char * const argv[]);
|
||||||
char *iolog_gets(struct iolog_file *iol, char *buf, size_t nbytes, const char **errsttr);
|
char *iolog_gets(struct iolog_file *iol, char *buf, size_t nbytes, const char **errsttr);
|
||||||
const char *iolog_fd_to_name(int iofd);
|
const char *iolog_fd_to_name(int iofd);
|
||||||
off_t iolog_seek(struct iolog_file *iol, off_t offset, int whence);
|
off_t iolog_seek(struct iolog_file *iol, off_t offset, int whence);
|
||||||
size_t mkdir_iopath(const char *iolog_path, char *pathbuf, size_t pathsize);
|
size_t mkdir_iopath(const char *iolog_path, char *pathbuf, size_t pathsize);
|
||||||
ssize_t iolog_read(struct iolog_file *iol, void *buf, size_t nbytes, const char **errstr);
|
ssize_t iolog_read(struct iolog_file *iol, void *buf, size_t nbytes, const char **errstr);
|
||||||
ssize_t iolog_write(struct iolog_file *iol, const void *buf, size_t len, const char **errstr);
|
ssize_t iolog_write(struct iolog_file *iol, const void *buf, size_t len, const char **errstr);
|
||||||
|
int iolog_openat(int fdf, const char *path, int flags);
|
||||||
|
|
||||||
#endif /* SUDO_IOLOG_H */
|
#endif /* SUDO_IOLOG_H */
|
||||||
|
@@ -368,25 +368,25 @@ iolog_set_flush(const char *str)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wrapper for open(2) that sets umask and retries as iolog_uid/iolog_gid
|
* Wrapper for openat(2) that sets umask and retries as iolog_uid/iolog_gid
|
||||||
* if open(2) returns EACCES.
|
* if openat(2) returns EACCES.
|
||||||
*/
|
*/
|
||||||
static int
|
int
|
||||||
io_open(const char *path, int flags)
|
iolog_openat(int dfd, const char *path, int flags)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
mode_t omask = S_IRWXG|S_IRWXO;
|
mode_t omask = S_IRWXG|S_IRWXO;
|
||||||
debug_decl(io_open, SUDO_DEBUG_UTIL)
|
debug_decl(iolog_openat, SUDO_DEBUG_UTIL)
|
||||||
|
|
||||||
if (ISSET(flags, O_CREAT)) {
|
if (ISSET(flags, O_CREAT)) {
|
||||||
/* umask must not be more restrictive than the file modes. */
|
/* umask must not be more restrictive than the file modes. */
|
||||||
omask = umask(ACCESSPERMS & ~(iolog_filemode|iolog_dirmode));
|
omask = umask(ACCESSPERMS & ~(iolog_filemode|iolog_dirmode));
|
||||||
}
|
}
|
||||||
fd = open(path, flags, iolog_filemode);
|
fd = openat(dfd, path, flags, iolog_filemode);
|
||||||
if (fd == -1 && errno == EACCES) {
|
if (fd == -1 && errno == EACCES) {
|
||||||
/* Try again as the I/O log owner (for NFS). */
|
/* Try again as the I/O log owner (for NFS). */
|
||||||
if (io_swapids(false)) {
|
if (io_swapids(false)) {
|
||||||
fd = open(path, flags, iolog_filemode);
|
fd = openat(dfd, path, flags, iolog_filemode);
|
||||||
if (!io_swapids(true)) {
|
if (!io_swapids(true)) {
|
||||||
/* io_swapids() warns on error. */
|
/* io_swapids() warns on error. */
|
||||||
if (fd != -1) {
|
if (fd != -1) {
|
||||||
@@ -430,10 +430,14 @@ iolog_nextid(char *iolog_dir, char sessid[7])
|
|||||||
len = snprintf(pathbuf, sizeof(pathbuf), "%s/seq", iolog_dir);
|
len = snprintf(pathbuf, sizeof(pathbuf), "%s/seq", iolog_dir);
|
||||||
if (len < 0 || len >= ssizeof(pathbuf)) {
|
if (len < 0 || len >= ssizeof(pathbuf)) {
|
||||||
errno = ENAMETOOLONG;
|
errno = ENAMETOOLONG;
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
|
||||||
|
"%s: %s/seq", __func__, iolog_dir);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
fd = io_open(pathbuf, O_RDWR|O_CREAT);
|
fd = iolog_openat(AT_FDCWD, pathbuf, O_RDWR|O_CREAT);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
|
||||||
|
"%s: unable to open %s", __func__, pathbuf);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
sudo_lock_file(fd, SUDO_LOCK);
|
sudo_lock_file(fd, SUDO_LOCK);
|
||||||
@@ -483,6 +487,8 @@ iolog_nextid(char *iolog_dir, char sessid[7])
|
|||||||
#else
|
#else
|
||||||
if (lseek(fd, 0, SEEK_SET) == -1 || write(fd, buf, 7) != 7) {
|
if (lseek(fd, 0, SEEK_SET) == -1 || write(fd, buf, 7) != 7) {
|
||||||
#endif
|
#endif
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
|
||||||
|
"%s: unable to write %s", __func__, pathbuf);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
ret = true;
|
ret = true;
|
||||||
@@ -531,9 +537,10 @@ mkdir_iopath(const char *iolog_path, char *pathbuf, size_t pathsize)
|
|||||||
* XXX - move enabled logic into caller?
|
* XXX - move enabled logic into caller?
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
iolog_open(struct iolog_file *iol, char *path, const char *mode)
|
iolog_open(struct iolog_file *iol, int dfd, int iofd, const char *mode)
|
||||||
{
|
{
|
||||||
int flags;
|
int flags;
|
||||||
|
const char *file;
|
||||||
unsigned char magic[2];
|
unsigned char magic[2];
|
||||||
debug_decl(iolog_open, SUDO_DEBUG_UTIL)
|
debug_decl(iolog_open, SUDO_DEBUG_UTIL)
|
||||||
|
|
||||||
@@ -547,16 +554,21 @@ iolog_open(struct iolog_file *iol, char *path, const char *mode)
|
|||||||
"%s: invalid I/O mode %s", __func__, mode);
|
"%s: invalid I/O mode %s", __func__, mode);
|
||||||
debug_return_bool(false);
|
debug_return_bool(false);
|
||||||
}
|
}
|
||||||
|
if ((file = iolog_fd_to_name(iofd)) == NULL) {
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_ERROR,
|
||||||
|
"%s: invalid iofd %d", __func__, iofd);
|
||||||
|
debug_return_bool(false);
|
||||||
|
}
|
||||||
|
|
||||||
iol->compressed = false;
|
iol->compressed = false;
|
||||||
if (iol->enabled) {
|
if (iol->enabled) {
|
||||||
int fd = io_open(path, flags);
|
int fd = iolog_openat(dfd, file, flags);
|
||||||
if (fd != -1) {
|
if (fd != -1) {
|
||||||
if (*mode == 'w') {
|
if (*mode == 'w') {
|
||||||
if (fchown(fd, iolog_uid, iolog_gid) != 0) {
|
if (fchown(fd, iolog_uid, iolog_gid) != 0) {
|
||||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
|
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
|
||||||
"%s: unable to fchown %d:%d %s", __func__,
|
"%s: unable to fchown %d:%d %s", __func__,
|
||||||
(int)iolog_uid, (int)iolog_gid, path);
|
(int)iolog_uid, (int)iolog_gid, file);
|
||||||
}
|
}
|
||||||
iol->compressed = iolog_compress;
|
iol->compressed = iolog_compress;
|
||||||
} else {
|
} else {
|
||||||
@@ -588,7 +600,7 @@ iolog_open(struct iolog_file *iol, char *path, const char *mode)
|
|||||||
} else {
|
} else {
|
||||||
if (*mode == 'w') {
|
if (*mode == 'w') {
|
||||||
/* Remove old log file in case we recycled sequence numbers. */
|
/* Remove old log file in case we recycled sequence numbers. */
|
||||||
(void)unlink(path);
|
(void)unlinkat(dfd, file, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
debug_return_bool(true);
|
debug_return_bool(true);
|
||||||
@@ -806,34 +818,26 @@ iolog_gets(struct iolog_file *iol, char *buf, size_t nbytes,
|
|||||||
* This file is not compressed.
|
* This file is not compressed.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
iolog_write_info_file(const char *parent, struct iolog_info *log_info,
|
iolog_write_info_file(int dfd, const char *parent, struct iolog_info *log_info,
|
||||||
char * const argv[])
|
char * const argv[])
|
||||||
{
|
{
|
||||||
char path[PATH_MAX];
|
|
||||||
char * const *av;
|
char * const *av;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
int error, len, fd;
|
int error, fd;
|
||||||
debug_decl(iolog_info_write_log, SUDO_DEBUG_UTIL)
|
debug_decl(iolog_info_write_log, SUDO_DEBUG_UTIL)
|
||||||
|
|
||||||
len = snprintf(path, sizeof(path), "%s/log", parent);
|
fd = iolog_openat(dfd, "log", O_CREAT|O_TRUNC|O_WRONLY);
|
||||||
if (len < 0 || len >= ssizeof(path)) {
|
|
||||||
errno = ENAMETOOLONG;
|
|
||||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
|
||||||
"%s/log", parent);
|
|
||||||
debug_return_bool(false);
|
|
||||||
}
|
|
||||||
fd = io_open(path, O_CREAT|O_TRUNC|O_WRONLY);
|
|
||||||
if (fd == -1 || (fp = fdopen(fd, "w")) == NULL) {
|
if (fd == -1 || (fp = fdopen(fd, "w")) == NULL) {
|
||||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
||||||
"unable to open %s", path);
|
"unable to open %s/log", parent);
|
||||||
if (fd != -1)
|
if (fd != -1)
|
||||||
close(fd);
|
close(fd);
|
||||||
debug_return_bool(false);
|
debug_return_bool(false);
|
||||||
}
|
}
|
||||||
if (fchown(fd, iolog_uid, iolog_gid) != 0) {
|
if (fchown(fd, iolog_uid, iolog_gid) != 0) {
|
||||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
|
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
|
||||||
"%s: unable to fchown %d:%d %s", __func__,
|
"%s: unable to fchown %d:%d %s/log", __func__,
|
||||||
(int)iolog_uid, (int)iolog_gid, path);
|
(int)iolog_uid, (int)iolog_gid, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(fp, "%lld:%s:%s:%s:%s:%d:%d\n%s\n",
|
fprintf(fp, "%lld:%s:%s:%s:%s:%d:%d\n%s\n",
|
||||||
@@ -853,7 +857,7 @@ iolog_write_info_file(const char *parent, struct iolog_info *log_info,
|
|||||||
fflush(fp);
|
fflush(fp);
|
||||||
if ((error = ferror(fp))) {
|
if ((error = ferror(fp))) {
|
||||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
||||||
"unable to write to I/O log file %s", path);
|
"unable to write to I/O log file %s/log", parent);
|
||||||
}
|
}
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
|
@@ -61,21 +61,14 @@
|
|||||||
static int timing_event_adj;
|
static int timing_event_adj;
|
||||||
|
|
||||||
struct iolog_info *
|
struct iolog_info *
|
||||||
parse_logfile(const char *logfile)
|
parse_logfile(FILE *fp, const char *logfile)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
|
||||||
char *buf = NULL, *cp, *ep;
|
char *buf = NULL, *cp, *ep;
|
||||||
const char *errstr;
|
const char *errstr;
|
||||||
size_t bufsize = 0, cwdsize = 0, cmdsize = 0;
|
size_t bufsize = 0, cwdsize = 0, cmdsize = 0;
|
||||||
struct iolog_info *li = NULL;
|
struct iolog_info *li = NULL;
|
||||||
debug_decl(parse_logfile, SUDO_DEBUG_UTIL)
|
debug_decl(parse_logfile, SUDO_DEBUG_UTIL)
|
||||||
|
|
||||||
fp = fopen(logfile, "r");
|
|
||||||
if (fp == NULL) {
|
|
||||||
sudo_warn(U_("unable to open %s"), logfile);
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ID file has three lines:
|
* ID file has three lines:
|
||||||
* 1) a log info line
|
* 1) a log info line
|
||||||
@@ -174,13 +167,10 @@ parse_logfile(const char *logfile)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fclose(fp);
|
|
||||||
free(buf);
|
free(buf);
|
||||||
debug_return_ptr(li);
|
debug_return_ptr(li);
|
||||||
|
|
||||||
bad:
|
bad:
|
||||||
if (fp != NULL)
|
|
||||||
fclose(fp);
|
|
||||||
free(buf);
|
free(buf);
|
||||||
free_iolog_info(li);
|
free_iolog_info(li);
|
||||||
debug_return_ptr(NULL);
|
debug_return_ptr(NULL);
|
||||||
|
@@ -352,7 +352,7 @@ static const struct iolog_path_escape path_escapes[] = {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Create I/O log path
|
* Create I/O log path
|
||||||
* Sets iolog_dir and iolog_dir_fd in the closure (XXX - not iolog_dir_fd)
|
* Sets iolog_dir and iolog_dir_fd in the closure
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
create_iolog_dir(struct iolog_details *details, struct connection_closure *closure)
|
create_iolog_dir(struct iolog_details *details, struct connection_closure *closure)
|
||||||
@@ -388,15 +388,14 @@ create_iolog_dir(struct iolog_details *details, struct connection_closure *closu
|
|||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* We use iolog_dir_fd in calls to openat(2) */
|
/* We use iolog_dir_fd in calls to openat(2) */
|
||||||
closure->iolog_dir_fd = open(closure->iolog_dir, O_RDONLY);
|
closure->iolog_dir_fd =
|
||||||
|
iolog_openat(AT_FDCWD, closure->iolog_dir, O_RDONLY);
|
||||||
if (closure->iolog_dir_fd == -1) {
|
if (closure->iolog_dir_fd == -1) {
|
||||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
||||||
"%s", closure->iolog_dir);
|
"%s", closure->iolog_dir);
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
debug_return_bool(true);
|
debug_return_bool(true);
|
||||||
bad:
|
bad:
|
||||||
@@ -408,57 +407,30 @@ bad:
|
|||||||
* Write the sudo-style I/O log info file containing user and command info.
|
* Write the sudo-style I/O log info file containing user and command info.
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
iolog_details_write(struct iolog_details *details, struct connection_closure *closure)
|
iolog_details_write(struct iolog_details *details,
|
||||||
|
struct connection_closure *closure)
|
||||||
{
|
{
|
||||||
int fd, i;
|
struct iolog_info log_info;
|
||||||
FILE *fp;
|
|
||||||
int error;
|
|
||||||
debug_decl(iolog_details_write, SUDO_DEBUG_UTIL)
|
debug_decl(iolog_details_write, SUDO_DEBUG_UTIL)
|
||||||
|
|
||||||
#if 0
|
/* Convert to iolog_info */
|
||||||
fd = openat(closure->iolog_dir_fd, "log", O_CREAT|O_EXCL|O_WRONLY, 0600);
|
memset(&log_info, 0, sizeof(log_info));
|
||||||
#else
|
log_info.user = details->submituser;
|
||||||
/* XXX */
|
log_info.runas_user = details->runuser;
|
||||||
char path[PATH_MAX]; // XXX
|
log_info.runas_group = details->rungroup;
|
||||||
snprintf(path, sizeof(path), "%s/log", closure->iolog_dir);
|
log_info.tty = details->ttyname;
|
||||||
fd = open(path, O_CREAT|O_EXCL|O_WRONLY, 0600);
|
log_info.cwd = details->cwd;
|
||||||
#endif
|
log_info.cmd = details->command;
|
||||||
if (fd == -1 || (fp = fdopen(fd, "w")) == NULL) {
|
log_info.lines = details->lines;
|
||||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
log_info.cols = details->columns;
|
||||||
"unable to open %s", closure->iolog_dir);
|
|
||||||
if (fd != -1)
|
|
||||||
close(fd);
|
|
||||||
debug_return_bool(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(fp, "%lld:%s:%s:%s:%s:%d:%d\n%s\n",
|
debug_return_bool(iolog_write_info_file(closure->iolog_dir_fd,
|
||||||
(long long)details->start_time, details->submituser,
|
closure->iolog_dir, &log_info, details->argv));
|
||||||
details->runuser ? details->runuser : RUNAS_DEFAULT,
|
|
||||||
details->rungroup ? details->rungroup : "",
|
|
||||||
details->ttyname ? details->ttyname : "unknown",
|
|
||||||
details->lines, details->columns,
|
|
||||||
details->cwd ? details->cwd : "unknown");
|
|
||||||
fputs(details->command, fp);
|
|
||||||
for (i = 1; i < details->argc; i++) {
|
|
||||||
fputc(' ', fp);
|
|
||||||
fputs(details->argv[i], fp);
|
|
||||||
}
|
|
||||||
fputc('\n', fp);
|
|
||||||
fflush(fp);
|
|
||||||
if ((error = ferror(fp))) {
|
|
||||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
|
||||||
"unable to write to I/O log file %s", closure->iolog_dir);
|
|
||||||
}
|
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
debug_return_bool(!error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
iolog_create(int iofd, struct connection_closure *closure)
|
iolog_create(int iofd, struct connection_closure *closure)
|
||||||
{
|
{
|
||||||
char path[PATH_MAX];
|
|
||||||
int len;
|
|
||||||
debug_decl(iolog_create, SUDO_DEBUG_UTIL)
|
debug_decl(iolog_create, SUDO_DEBUG_UTIL)
|
||||||
|
|
||||||
if (iofd < 0 || iofd >= IOFD_MAX) {
|
if (iofd < 0 || iofd >= IOFD_MAX) {
|
||||||
@@ -467,17 +439,9 @@ iolog_create(int iofd, struct connection_closure *closure)
|
|||||||
debug_return_bool(false);
|
debug_return_bool(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
len = snprintf(path, sizeof(path), "%s/%s", closure->iolog_dir,
|
|
||||||
iolog_fd_to_name(iofd));
|
|
||||||
if (len < 0 || len >= ssizeof(path)) {
|
|
||||||
errno = ENAMETOOLONG;
|
|
||||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
|
||||||
"%s/%s", closure->iolog_dir, iolog_fd_to_name(iofd));
|
|
||||||
debug_return_bool(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
closure->iolog_files[iofd].enabled = true;
|
closure->iolog_files[iofd].enabled = true;
|
||||||
debug_return_bool(iolog_open(&closure->iolog_files[iofd], path, "w"));
|
debug_return_bool(iolog_open(&closure->iolog_files[iofd],
|
||||||
|
closure->iolog_dir_fd, iofd, "w"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -495,10 +459,8 @@ iolog_close_all(struct connection_closure *closure)
|
|||||||
"error closing iofd %d: %s", i, errstr);
|
"error closing iofd %d: %s", i, errstr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if 0
|
|
||||||
if (closure->iolog_dir_fd != -1)
|
if (closure->iolog_dir_fd != -1)
|
||||||
close(closure->iolog_dir_fd);
|
close(closure->iolog_dir_fd);
|
||||||
#endif
|
|
||||||
|
|
||||||
debug_return;
|
debug_return;
|
||||||
}
|
}
|
||||||
@@ -574,7 +536,7 @@ iolog_restart(RestartMessage *msg, struct connection_closure *closure)
|
|||||||
struct timespec target;
|
struct timespec target;
|
||||||
struct timing_closure timing;
|
struct timing_closure timing;
|
||||||
off_t pos;
|
off_t pos;
|
||||||
int i;
|
int iofd;
|
||||||
debug_decl(iolog_init, SUDO_DEBUG_UTIL)
|
debug_decl(iolog_init, SUDO_DEBUG_UTIL)
|
||||||
|
|
||||||
target.tv_sec = msg->resume_point->tv_sec;
|
target.tv_sec = msg->resume_point->tv_sec;
|
||||||
@@ -587,21 +549,24 @@ iolog_restart(RestartMessage *msg, struct connection_closure *closure)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Open existing I/O log files. */
|
/* Open existing I/O log files. */
|
||||||
for (i = 0; i < IOFD_MAX; i++) {
|
for (iofd = 0; iofd < IOFD_MAX; iofd++) {
|
||||||
char path[PATH_MAX];
|
closure->iolog_files[iofd].enabled = true;
|
||||||
int len = snprintf(path, sizeof(path), "%s/%s", closure->iolog_dir,
|
if (!iolog_open(&closure->iolog_files[iofd], closure->iolog_dir_fd,
|
||||||
iolog_fd_to_name(i));
|
iofd, "r+")) {
|
||||||
if (len < 0 || len >= ssizeof(path)) {
|
if (errno != ENOENT) {
|
||||||
errno = ENAMETOOLONG;
|
sudo_debug_printf(
|
||||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
|
SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
|
||||||
"%s: %s/%s", __func__, closure->iolog_dir, iolog_fd_to_name(i));
|
"unable to open %s/%s", closure->iolog_dir,
|
||||||
|
iolog_fd_to_name(iofd));
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
closure->iolog_files[i].enabled = true;
|
|
||||||
(void)iolog_open(&closure->iolog_files[i], path, "r+");
|
|
||||||
}
|
}
|
||||||
if (!closure->iolog_files[IOFD_TIMING].enabled)
|
}
|
||||||
|
if (!closure->iolog_files[IOFD_TIMING].enabled) {
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||||
|
"missing timing file in %s", closure->iolog_dir);
|
||||||
goto bad;
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
/* Parse timing file until we reach the target point. */
|
/* Parse timing file until we reach the target point. */
|
||||||
/* XXX - split up */
|
/* XXX - split up */
|
||||||
|
@@ -87,9 +87,7 @@ struct connection_closure {
|
|||||||
struct sudo_event *write_ev;
|
struct sudo_event *write_ev;
|
||||||
char *iolog_dir;
|
char *iolog_dir;
|
||||||
struct iolog_file iolog_files[IOFD_MAX];
|
struct iolog_file iolog_files[IOFD_MAX];
|
||||||
#if 0
|
|
||||||
int iolog_dir_fd;
|
int iolog_dir_fd;
|
||||||
#endif
|
|
||||||
int sock;
|
int sock;
|
||||||
enum connection_status state;
|
enum connection_status state;
|
||||||
};
|
};
|
||||||
|
@@ -58,7 +58,7 @@
|
|||||||
#include "sendlog.h"
|
#include "sendlog.h"
|
||||||
|
|
||||||
static struct iolog_file iolog_files[IOFD_MAX];
|
static struct iolog_file iolog_files[IOFD_MAX];
|
||||||
static char *iolog_path;
|
static char *iolog_dir;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
usage(void)
|
usage(void)
|
||||||
@@ -188,7 +188,7 @@ read_io_buf(struct client_closure *closure)
|
|||||||
|
|
||||||
if (!iolog_files[timing->event].enabled) {
|
if (!iolog_files[timing->event].enabled) {
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
sudo_warn("%s/%s", iolog_path, iolog_fd_to_name(timing->event));
|
sudo_warn("%s/%s", iolog_dir, iolog_fd_to_name(timing->event));
|
||||||
debug_return_bool(false);
|
debug_return_bool(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,7 +208,7 @@ read_io_buf(struct client_closure *closure)
|
|||||||
nread = iolog_read(&iolog_files[timing->event], closure->buf,
|
nread = iolog_read(&iolog_files[timing->event], closure->buf,
|
||||||
timing->u.nbytes, &errstr);
|
timing->u.nbytes, &errstr);
|
||||||
if (nread != timing->u.nbytes) {
|
if (nread != timing->u.nbytes) {
|
||||||
sudo_warnx(U_("unable to read %s/%s: %s"), iolog_path,
|
sudo_warnx(U_("unable to read %s/%s: %s"), iolog_dir,
|
||||||
iolog_fd_to_name(timing->event), errstr);
|
iolog_fd_to_name(timing->event), errstr);
|
||||||
debug_return_bool(false);
|
debug_return_bool(false);
|
||||||
}
|
}
|
||||||
@@ -1015,29 +1015,27 @@ bad:
|
|||||||
* Open any I/O log files that are present.
|
* Open any I/O log files that are present.
|
||||||
* The timing file must always exist.
|
* The timing file must always exist.
|
||||||
*/
|
*/
|
||||||
bool
|
static bool
|
||||||
iolog_open_all(char *path, size_t dir_len)
|
iolog_open_all(int dfd, const char *iolog_dir)
|
||||||
{
|
{
|
||||||
size_t file_len;
|
int iofd;
|
||||||
int i;
|
|
||||||
debug_decl(iolog_open_all, SUDO_DEBUG_UTIL)
|
debug_decl(iolog_open_all, SUDO_DEBUG_UTIL)
|
||||||
|
|
||||||
for (i = 0; i < IOFD_MAX; i++) {
|
for (iofd = 0; iofd < IOFD_MAX; iofd++) {
|
||||||
path[dir_len] = '\0';
|
iolog_files[iofd].enabled = true;
|
||||||
file_len = strlen(iolog_fd_to_name(i));
|
if (!iolog_open(&iolog_files[iofd], dfd, iofd, "r")) {
|
||||||
if (dir_len + 1 + file_len + 1 >= PATH_MAX) {
|
if (errno != ENOENT) {
|
||||||
errno = ENAMETOOLONG;
|
sudo_warn(U_("unable to open %s/%s"), iolog_dir,
|
||||||
sudo_warn("%s/%s", path, iolog_fd_to_name(i));
|
iolog_fd_to_name(iofd));
|
||||||
debug_return_bool(false);
|
debug_return_bool(false);
|
||||||
}
|
}
|
||||||
path[dir_len++] = '/';
|
|
||||||
memcpy(path + dir_len, iolog_fd_to_name(i), file_len + 1);
|
|
||||||
iolog_files[i].enabled = true;
|
|
||||||
if (!iolog_open(&iolog_files[i], path, "r")) {
|
|
||||||
sudo_warn(U_("unable to open %s"), path);
|
|
||||||
debug_return_bool(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!iolog_files[IOFD_TIMING].enabled) {
|
||||||
|
sudo_warn(U_("unable to open %s/%s"), iolog_dir,
|
||||||
|
iolog_fd_to_name(IOFD_TIMING));
|
||||||
|
debug_return_bool(false);
|
||||||
|
}
|
||||||
debug_return_bool(true);
|
debug_return_bool(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1088,11 +1086,13 @@ main(int argc, char *argv[])
|
|||||||
const char *host = "localhost";
|
const char *host = "localhost";
|
||||||
const char *port = DEFAULT_PORT_STR;
|
const char *port = DEFAULT_PORT_STR;
|
||||||
struct timespec restart = { 0, 0 };
|
struct timespec restart = { 0, 0 };
|
||||||
char pathbuf[PATH_MAX];
|
|
||||||
const char *iolog_id = NULL;
|
const char *iolog_id = NULL;
|
||||||
int ch, len, sock;
|
int ch, sock, iolog_dir_fd, fd;
|
||||||
|
FILE *fp;
|
||||||
debug_decl_vars(main, SUDO_DEBUG_MAIN)
|
debug_decl_vars(main, SUDO_DEBUG_MAIN)
|
||||||
|
|
||||||
|
signal(SIGPIPE, SIG_IGN);
|
||||||
|
|
||||||
initprogname(argc > 0 ? argv[0] : "sendlog");
|
initprogname(argc > 0 ? argv[0] : "sendlog");
|
||||||
setlocale(LC_ALL, "");
|
setlocale(LC_ALL, "");
|
||||||
bindtextdomain("sudo", LOCALEDIR); /* XXX - add logsrvd domain */
|
bindtextdomain("sudo", LOCALEDIR); /* XXX - add logsrvd domain */
|
||||||
@@ -1134,26 +1134,26 @@ main(int argc, char *argv[])
|
|||||||
usage();
|
usage();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remaining arg should be path to I/O log file to send. */
|
/* Remaining arg should be to I/O log dir to send. */
|
||||||
if (argc != 1)
|
if (argc != 1)
|
||||||
usage();
|
usage();
|
||||||
iolog_path = argv[0];
|
iolog_dir = argv[0];
|
||||||
|
if ((iolog_dir_fd = open(iolog_dir, O_RDONLY)) == -1) {
|
||||||
signal(SIGPIPE, SIG_IGN);
|
sudo_warn("%s", iolog_dir);
|
||||||
|
|
||||||
/* Parse I/O info log file. */
|
|
||||||
len = snprintf(pathbuf, sizeof(pathbuf), "%s/log", iolog_path);
|
|
||||||
if (len < 0 || len >= ssizeof(pathbuf)) {
|
|
||||||
errno = ENAMETOOLONG;
|
|
||||||
sudo_warn("%s/log", iolog_path);
|
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
len -= 4;
|
|
||||||
if ((log_info = parse_logfile(pathbuf)) == NULL)
|
/* Parse I/O log info file. */
|
||||||
|
fd = openat(iolog_dir_fd, "log", O_RDONLY, 0);
|
||||||
|
if (fd == -1 || (fp = fdopen(fd, "r")) == NULL) {
|
||||||
|
sudo_warn("%s/log", iolog_dir);
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
if ((log_info = parse_logfile(fp, iolog_dir)) == NULL)
|
||||||
goto bad;
|
goto bad;
|
||||||
|
|
||||||
/* Open the I/O log files. */
|
/* Open the I/O log files. */
|
||||||
if (!iolog_open_all(pathbuf, len))
|
if (!iolog_open_all(iolog_dir_fd, iolog_dir))
|
||||||
goto bad;
|
goto bad;
|
||||||
|
|
||||||
/* Connect to server, setup events. */
|
/* Connect to server, setup events. */
|
||||||
|
@@ -368,17 +368,18 @@ iolog_deserialize_info(struct iolog_details *details, char * const user_info[],
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Write the "/log" file that contains the user and command info.
|
* Write the "log" file that contains the user and command info.
|
||||||
* This file is not compressed.
|
* This file is not compressed.
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
write_info_log(char *pathbuf, size_t len, struct iolog_details *details,
|
write_info_log(int dfd, char *iolog_dir, struct iolog_details *details,
|
||||||
char * const argv[])
|
char * const argv[])
|
||||||
{
|
{
|
||||||
struct iolog_info iolog_info;
|
struct iolog_info iolog_info;
|
||||||
debug_decl(write_info_log, SUDOERS_DEBUG_UTIL)
|
debug_decl(write_info_log, SUDOERS_DEBUG_UTIL)
|
||||||
|
|
||||||
/* XXX - just use iolog_info in the first place? */
|
/* XXX - just use iolog_info in the first place? */
|
||||||
|
memset(&iolog_info, 0, sizeof(iolog_info));
|
||||||
time(&iolog_info.tstamp);
|
time(&iolog_info.tstamp);
|
||||||
iolog_info.user = (char *)details->user;
|
iolog_info.user = (char *)details->user;
|
||||||
iolog_info.runas_user = details->runas_pw->pw_name;
|
iolog_info.runas_user = details->runas_pw->pw_name;
|
||||||
@@ -388,9 +389,8 @@ write_info_log(char *pathbuf, size_t len, struct iolog_details *details,
|
|||||||
iolog_info.cmd = (char *)details->command;
|
iolog_info.cmd = (char *)details->command;
|
||||||
iolog_info.lines = details->lines;
|
iolog_info.lines = details->lines;
|
||||||
iolog_info.cols = details->cols;
|
iolog_info.cols = details->cols;
|
||||||
pathbuf[len] = '\0';
|
|
||||||
|
|
||||||
if (!iolog_write_info_file(pathbuf, &iolog_info, argv)) {
|
if (!iolog_write_info_file(dfd, iolog_dir, &iolog_info, argv)) {
|
||||||
log_warning(SLOG_SEND_MAIL,
|
log_warning(SLOG_SEND_MAIL,
|
||||||
N_("unable to write to I/O log file: %s"), strerror(errno));
|
N_("unable to write to I/O log file: %s"), strerror(errno));
|
||||||
warned = true;
|
warned = true;
|
||||||
@@ -406,12 +406,13 @@ sudoers_io_open(unsigned int version, sudo_conv_t conversation,
|
|||||||
int argc, char * const argv[], char * const user_env[], char * const args[])
|
int argc, char * const argv[], char * const user_env[], char * const args[])
|
||||||
{
|
{
|
||||||
struct sudo_conf_debug_file_list debug_files = TAILQ_HEAD_INITIALIZER(debug_files);
|
struct sudo_conf_debug_file_list debug_files = TAILQ_HEAD_INITIALIZER(debug_files);
|
||||||
char pathbuf[PATH_MAX], sessid[7];
|
char iolog_path[PATH_MAX], sessid[7];
|
||||||
char *tofree = NULL;
|
char *tofree = NULL;
|
||||||
char * const *cur;
|
char * const *cur;
|
||||||
const char *cp, *plugin_path = NULL;
|
const char *cp, *plugin_path = NULL;
|
||||||
size_t len;
|
size_t len;
|
||||||
int i, ret = -1;
|
int i, ret = -1;
|
||||||
|
int iolog_dir_fd = -1;
|
||||||
debug_decl(sudoers_io_open, SUDOERS_DEBUG_PLUGIN)
|
debug_decl(sudoers_io_open, SUDOERS_DEBUG_PLUGIN)
|
||||||
|
|
||||||
sudo_conv = conversation;
|
sudo_conv = conversation;
|
||||||
@@ -474,27 +475,27 @@ sudoers_io_open(unsigned int version, sudo_conv_t conversation,
|
|||||||
* Make local copy of I/O log path and create it, along with any
|
* Make local copy of I/O log path and create it, along with any
|
||||||
* intermediate subdirs. Calls mkdtemp() if iolog_path ends in XXXXXX.
|
* intermediate subdirs. Calls mkdtemp() if iolog_path ends in XXXXXX.
|
||||||
*/
|
*/
|
||||||
len = mkdir_iopath(iolog_details.iolog_path, pathbuf, sizeof(pathbuf));
|
len = mkdir_iopath(iolog_details.iolog_path, iolog_path, sizeof(iolog_path));
|
||||||
if (len >= sizeof(pathbuf)) {
|
if (len >= sizeof(iolog_path)) {
|
||||||
log_warning(SLOG_SEND_MAIL, "%s", iolog_details.iolog_path);
|
log_warning(SLOG_SEND_MAIL, "%s", iolog_details.iolog_path);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iolog_dir_fd = iolog_openat(AT_FDCWD, iolog_path, O_RDONLY);
|
||||||
|
if (iolog_dir_fd == -1) {
|
||||||
|
log_warning(SLOG_SEND_MAIL, "%s", iolog_path);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
/* Write log file with user and command details. */
|
/* Write log file with user and command details. */
|
||||||
if (!write_info_log(pathbuf, len, &iolog_details, argv))
|
if (!write_info_log(iolog_dir_fd, iolog_path, &iolog_details, argv))
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* Create the timing and I/O log files. */
|
/* Create the timing and I/O log files. */
|
||||||
for (i = 0; i < IOFD_MAX; i++) {
|
for (i = 0; i < IOFD_MAX; i++) {
|
||||||
pathbuf[len] = '/';
|
if (!iolog_open(&iolog_files[i], iolog_dir_fd, i, "w")) {
|
||||||
pathbuf[len + 1] = '\0';
|
log_warning(SLOG_SEND_MAIL, N_("unable to create %s/%s"),
|
||||||
if (strlcat(pathbuf, iolog_fd_to_name(i), sizeof(pathbuf)) >= sizeof(pathbuf)) {
|
iolog_path, iolog_fd_to_name(i));
|
||||||
errno = ENAMETOOLONG;
|
|
||||||
log_warning(SLOG_SEND_MAIL, N_("unable to create %s"), pathbuf);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (!iolog_open(&iolog_files[i], pathbuf, "w")) {
|
|
||||||
log_warning(SLOG_SEND_MAIL, N_("unable to create %s"), pathbuf);
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -522,6 +523,8 @@ sudoers_io_open(unsigned int version, sudo_conv_t conversation,
|
|||||||
ret = true;
|
ret = true;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
if (iolog_dir_fd != -1)
|
||||||
|
close(iolog_dir_fd);
|
||||||
free(tofree);
|
free(tofree);
|
||||||
if (iolog_details.runas_pw)
|
if (iolog_details.runas_pw)
|
||||||
sudo_pw_delref(iolog_details.runas_pw);
|
sudo_pw_delref(iolog_details.runas_pw);
|
||||||
|
@@ -84,13 +84,20 @@ sudo_printf_int(int msg_type, const char *fmt, ...)
|
|||||||
bool
|
bool
|
||||||
validate_iolog_info(const char *logfile)
|
validate_iolog_info(const char *logfile)
|
||||||
{
|
{
|
||||||
time_t now;
|
|
||||||
struct iolog_info *info;
|
struct iolog_info *info;
|
||||||
|
time_t now;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
time(&now);
|
time(&now);
|
||||||
|
|
||||||
/* Parse log file. */
|
/* Parse log file. */
|
||||||
if ((info = parse_logfile(logfile)) == NULL)
|
if ((fp = fopen(logfile, "r")) == NULL) {
|
||||||
|
sudo_warn("%s", logfile);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
info = parse_logfile(fp, logfile);
|
||||||
|
fclose(fp);
|
||||||
|
if (info == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (strcmp(info->cwd, "/") != 0) {
|
if (strcmp(info->cwd, "/") != 0) {
|
||||||
|
@@ -91,6 +91,7 @@ struct replay_closure {
|
|||||||
struct sudo_event *sigtstp_ev;
|
struct sudo_event *sigtstp_ev;
|
||||||
struct timespec *max_delay;
|
struct timespec *max_delay;
|
||||||
struct timing_closure timing;
|
struct timing_closure timing;
|
||||||
|
int iolog_dir_fd;
|
||||||
bool interactive;
|
bool interactive;
|
||||||
bool suspend_wait;
|
bool suspend_wait;
|
||||||
struct io_buffer {
|
struct io_buffer {
|
||||||
@@ -178,8 +179,9 @@ static int list_sessions(int, char **, const char *, const char *, const char *)
|
|||||||
static int parse_expr(struct search_node_list *, char **, bool);
|
static int parse_expr(struct search_node_list *, char **, bool);
|
||||||
static void read_keyboard(int fd, int what, void *v);
|
static void read_keyboard(int fd, int what, void *v);
|
||||||
static void help(void) __attribute__((__noreturn__));
|
static void help(void) __attribute__((__noreturn__));
|
||||||
static int replay_session(const char *iolog_dir, struct timespec *max_wait,
|
static int replay_session(int iolog_dir_fd, const char *iolog_dir,
|
||||||
const char *decimal, bool interactive, bool suspend_wait);
|
struct timespec *max_wait, const char *decimal, bool interactive,
|
||||||
|
bool suspend_wait);
|
||||||
static void sudoreplay_cleanup(void);
|
static void sudoreplay_cleanup(void);
|
||||||
static void usage(int);
|
static void usage(int);
|
||||||
static void write_output(int fd, int what, void *v);
|
static void write_output(int fd, int what, void *v);
|
||||||
@@ -205,14 +207,15 @@ __dso_public int main(int argc, char *argv[]);
|
|||||||
int
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int ch, i, plen, exitcode = 0;
|
int ch, fd, i, iolog_dir_fd, len, exitcode = EXIT_FAILURE;
|
||||||
bool def_filter = true, listonly = false;
|
bool def_filter = true, listonly = false;
|
||||||
bool interactive = true, suspend_wait = false, resize = true;
|
bool interactive = true, suspend_wait = false, resize = true;
|
||||||
const char *decimal, *id, *user = NULL, *pattern = NULL, *tty = NULL;
|
const char *decimal, *id, *user = NULL, *pattern = NULL, *tty = NULL;
|
||||||
char *cp, *ep, path[PATH_MAX];
|
char *cp, *ep, iolog_dir[PATH_MAX];
|
||||||
struct iolog_info *li;
|
struct iolog_info *li;
|
||||||
struct timespec max_delay_storage, *max_delay = NULL;
|
struct timespec max_delay_storage, *max_delay = NULL;
|
||||||
double dval;
|
double dval;
|
||||||
|
FILE *fp;
|
||||||
debug_decl(main, SUDO_DEBUG_MAIN)
|
debug_decl(main, SUDO_DEBUG_MAIN)
|
||||||
|
|
||||||
#if defined(SUDO_DEVEL) && defined(__OpenBSD__)
|
#if defined(SUDO_DEVEL) && defined(__OpenBSD__)
|
||||||
@@ -297,6 +300,7 @@ 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);
|
||||||
|
exitcode = EXIT_SUCCESS;
|
||||||
goto done;
|
goto done;
|
||||||
default:
|
default:
|
||||||
usage(1);
|
usage(1);
|
||||||
@@ -325,41 +329,46 @@ main(int argc, char *argv[])
|
|||||||
/* 6 digit ID in base 36, e.g. 01G712AB or free-form name */
|
/* 6 digit ID in base 36, e.g. 01G712AB or free-form name */
|
||||||
id = argv[0];
|
id = argv[0];
|
||||||
if (VALID_ID(id)) {
|
if (VALID_ID(id)) {
|
||||||
plen = snprintf(path, sizeof(path), "%s/%.2s/%.2s/%.2s/timing",
|
len = snprintf(iolog_dir, sizeof(iolog_dir), "%s/%.2s/%.2s/%.2s",
|
||||||
session_dir, id, &id[2], &id[4]);
|
session_dir, id, &id[2], &id[4]);
|
||||||
if (plen < 0 || plen >= ssizeof(path))
|
if (len < 0 || len >= ssizeof(iolog_dir))
|
||||||
sudo_fatalx(U_("%s/%.2s/%.2s/%.2s/timing: %s"), session_dir,
|
sudo_fatalx(U_("%s/%.2s/%.2s/%.2s: %s"), session_dir,
|
||||||
id, &id[2], &id[4], strerror(ENAMETOOLONG));
|
id, &id[2], &id[4], strerror(ENAMETOOLONG));
|
||||||
} else if (id[0] == '/') {
|
} else if (id[0] == '/') {
|
||||||
plen = snprintf(path, sizeof(path), "%s/timing", id);
|
len = snprintf(iolog_dir, sizeof(iolog_dir), "%s", id);
|
||||||
if (plen < 0 || plen >= ssizeof(path))
|
if (len < 0 || len >= ssizeof(iolog_dir))
|
||||||
sudo_fatalx(U_("%s/timing: %s"), id, strerror(ENAMETOOLONG));
|
sudo_fatalx(U_("%s/timing: %s"), id, strerror(ENAMETOOLONG));
|
||||||
} else {
|
} else {
|
||||||
plen = snprintf(path, sizeof(path), "%s/%s/timing", session_dir, id);
|
len = snprintf(iolog_dir, sizeof(iolog_dir), "%s/%s", session_dir, id);
|
||||||
if (plen < 0 || plen >= ssizeof(path)) {
|
if (len < 0 || len >= ssizeof(iolog_dir)) {
|
||||||
sudo_fatalx(U_("%s/%s/timing: %s"), session_dir, id,
|
sudo_fatalx(U_("%s/%s: %s"), session_dir, id,
|
||||||
strerror(ENAMETOOLONG));
|
strerror(ENAMETOOLONG));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
plen -= 7;
|
|
||||||
|
|
||||||
/* Open files for replay, applying replay filter for the -f flag. */
|
/* Open files for replay, applying replay filter for the -f flag. */
|
||||||
|
if ((iolog_dir_fd = iolog_openat(AT_FDCWD, iolog_dir, O_RDONLY)) == -1)
|
||||||
|
sudo_fatal("%s", iolog_dir);
|
||||||
for (i = 0; i < IOFD_MAX; i++) {
|
for (i = 0; i < IOFD_MAX; i++) {
|
||||||
path[plen] = '/';
|
if (!iolog_open(&iolog_files[i], iolog_dir_fd, i, "r")) {
|
||||||
path[plen + 1] = '\0';
|
if (errno != ENOENT) {
|
||||||
if (strlcat(path, iolog_fd_to_name(i), sizeof(path)) >= sizeof(path)) {
|
sudo_fatal(U_("unable to open %s/%s"), iolog_dir,
|
||||||
errno = ENAMETOOLONG;
|
iolog_fd_to_name(i));
|
||||||
sudo_fatal("%s%s", path, iolog_fd_to_name(i));
|
|
||||||
}
|
}
|
||||||
if (!iolog_open(&iolog_files[i], path, "r"))
|
}
|
||||||
sudo_fatal(U_("unable to open %s"), path);
|
}
|
||||||
|
if (!iolog_files[IOFD_TIMING].enabled) {
|
||||||
|
sudo_fatal(U_("unable to open %s/%s"), iolog_dir,
|
||||||
|
iolog_fd_to_name(IOFD_TIMING));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse log file. */
|
/* Parse log file. */
|
||||||
path[plen] = '\0';
|
fd = openat(iolog_dir_fd, "log", O_RDONLY, 0);
|
||||||
strlcat(path, "/log", sizeof(path));
|
if (fd == -1 || (fp = fdopen(fd, "r")) == NULL)
|
||||||
if ((li = parse_logfile(path)) == NULL)
|
sudo_fatal(U_("unable to open %s/%s"), iolog_dir, "log");
|
||||||
exit(1);
|
if ((li = parse_logfile(fp, iolog_dir)) == NULL)
|
||||||
|
goto done;
|
||||||
|
fclose(fp);
|
||||||
printf(_("Replaying sudo session: %s"), li->cmd);
|
printf(_("Replaying sudo session: %s"), li->cmd);
|
||||||
|
|
||||||
/* Setup terminal if appropriate. */
|
/* Setup terminal if appropriate. */
|
||||||
@@ -374,15 +383,14 @@ main(int argc, char *argv[])
|
|||||||
li = NULL;
|
li = NULL;
|
||||||
|
|
||||||
/* Replay session corresponding to iolog_files[]. */
|
/* Replay session corresponding to iolog_files[]. */
|
||||||
path[plen] = '\0';
|
exitcode = replay_session(iolog_dir_fd, iolog_dir, max_delay, decimal,
|
||||||
exitcode = replay_session(path, max_delay, decimal, interactive,
|
interactive, suspend_wait);
|
||||||
suspend_wait);
|
|
||||||
|
|
||||||
restore_terminal_size();
|
restore_terminal_size();
|
||||||
sudo_term_restore(ttyfd, true);
|
sudo_term_restore(ttyfd, true);
|
||||||
done:
|
done:
|
||||||
sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys, exitcode);
|
sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys, exitcode);
|
||||||
exit(exitcode);
|
return exitcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -884,6 +892,8 @@ replay_closure_free(struct replay_closure *closure)
|
|||||||
/*
|
/*
|
||||||
* Free events and event base, then the closure itself.
|
* Free events and event base, then the closure itself.
|
||||||
*/
|
*/
|
||||||
|
if (closure->iolog_dir_fd != -1)
|
||||||
|
close(closure->iolog_dir_fd);
|
||||||
sudo_ev_free(closure->delay_ev);
|
sudo_ev_free(closure->delay_ev);
|
||||||
sudo_ev_free(closure->keyboard_ev);
|
sudo_ev_free(closure->keyboard_ev);
|
||||||
sudo_ev_free(closure->output_ev);
|
sudo_ev_free(closure->output_ev);
|
||||||
@@ -923,8 +933,9 @@ signal_cb(int signo, int what, void *v)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct replay_closure *
|
static struct replay_closure *
|
||||||
replay_closure_alloc(const char *iolog_dir, struct timespec *max_delay,
|
replay_closure_alloc(int iolog_dir_fd, const char *iolog_dir,
|
||||||
const char *decimal, bool interactive, bool suspend_wait)
|
struct timespec *max_delay, const char *decimal, bool interactive,
|
||||||
|
bool suspend_wait)
|
||||||
{
|
{
|
||||||
struct replay_closure *closure;
|
struct replay_closure *closure;
|
||||||
debug_decl(replay_closure_alloc, SUDO_DEBUG_UTIL)
|
debug_decl(replay_closure_alloc, SUDO_DEBUG_UTIL)
|
||||||
@@ -932,6 +943,7 @@ replay_closure_alloc(const char *iolog_dir, struct timespec *max_delay,
|
|||||||
if ((closure = calloc(1, sizeof(*closure))) == NULL)
|
if ((closure = calloc(1, sizeof(*closure))) == NULL)
|
||||||
debug_return_ptr(NULL);
|
debug_return_ptr(NULL);
|
||||||
|
|
||||||
|
closure->iolog_dir_fd = iolog_dir_fd;
|
||||||
closure->iolog_dir = iolog_dir;
|
closure->iolog_dir = iolog_dir;
|
||||||
closure->interactive = interactive;
|
closure->interactive = interactive;
|
||||||
closure->suspend_wait = suspend_wait;
|
closure->suspend_wait = suspend_wait;
|
||||||
@@ -1007,16 +1019,17 @@ bad:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
replay_session(const char *iolog_dir, struct timespec *max_delay,
|
replay_session(int iolog_dir_fd, const char *iolog_dir,
|
||||||
const char *decimal, bool interactive, bool suspend_wait)
|
struct timespec *max_delay, const char *decimal, bool interactive,
|
||||||
|
bool suspend_wait)
|
||||||
{
|
{
|
||||||
struct replay_closure *closure;
|
struct replay_closure *closure;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
debug_decl(replay_session, SUDO_DEBUG_UTIL)
|
debug_decl(replay_session, SUDO_DEBUG_UTIL)
|
||||||
|
|
||||||
/* Allocate the delay closure and read the first timing record. */
|
/* Allocate the delay closure and read the first timing record. */
|
||||||
closure = replay_closure_alloc(iolog_dir, max_delay, decimal, interactive,
|
closure = replay_closure_alloc(iolog_dir_fd, iolog_dir, max_delay, decimal,
|
||||||
suspend_wait);
|
interactive, suspend_wait);
|
||||||
if (read_timing_record(closure) != 0) {
|
if (read_timing_record(closure) != 0) {
|
||||||
ret = 1;
|
ret = 1;
|
||||||
goto done;
|
goto done;
|
||||||
@@ -1309,12 +1322,17 @@ static int
|
|||||||
list_session(char *logfile, regex_t *re, const char *user, const char *tty)
|
list_session(char *logfile, regex_t *re, const char *user, const char *tty)
|
||||||
{
|
{
|
||||||
char idbuf[7], *idstr, *cp;
|
char idbuf[7], *idstr, *cp;
|
||||||
|
struct iolog_info *li = NULL;
|
||||||
const char *timestr;
|
const char *timestr;
|
||||||
struct iolog_info *li;
|
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
FILE *fp;
|
||||||
debug_decl(list_session, SUDO_DEBUG_UTIL)
|
debug_decl(list_session, SUDO_DEBUG_UTIL)
|
||||||
|
|
||||||
if ((li = parse_logfile(logfile)) == NULL)
|
if ((fp = fopen(logfile, "r")) == NULL) {
|
||||||
|
sudo_warn("%s", logfile);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if ((li = parse_logfile(fp, logfile)) == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* Match on search expression if there is one. */
|
/* Match on search expression if there is one. */
|
||||||
@@ -1349,6 +1367,8 @@ list_session(char *logfile, regex_t *re, const char *user, const char *tty)
|
|||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
if (fp != NULL)
|
||||||
|
fclose(fp);
|
||||||
free_iolog_info(li);
|
free_iolog_info(li);
|
||||||
debug_return_int(ret);
|
debug_return_int(ret);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user