2
0
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:
Todd C. Miller
2019-10-24 20:04:31 -06:00
parent 7ba7c5835e
commit 282263c113
9 changed files with 195 additions and 205 deletions

View File

@@ -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 */

View File

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

View File

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

View File

@@ -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 */

View File

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

View File

@@ -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. */

View File

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

View File

@@ -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) {

View File

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