2
0
mirror of https://github.com/sudo-project/sudo.git synced 2025-08-22 01:49:11 +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 */
/* 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);
/* iolog_util.c */
/* XXX - prefix these */
bool parse_timing(const char *line, struct timing_closure *timing);
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 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_eof(struct iolog_file *iol);
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_flush(const char *str);
bool iolog_set_group(const struct group *gr);
bool iolog_set_maxseq(const char *maxval);
bool iolog_set_mode(mode_t mode);
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);
const char *iolog_fd_to_name(int iofd);
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);
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);
int iolog_openat(int fdf, const char *path, int flags);
#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
* if open(2) returns EACCES.
* Wrapper for openat(2) that sets umask and retries as iolog_uid/iolog_gid
* if openat(2) returns EACCES.
*/
static int
io_open(const char *path, int flags)
int
iolog_openat(int dfd, const char *path, int flags)
{
int fd;
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)) {
/* umask must not be more restrictive than the file modes. */
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) {
/* Try again as the I/O log owner (for NFS). */
if (io_swapids(false)) {
fd = open(path, flags, iolog_filemode);
fd = openat(dfd, path, flags, iolog_filemode);
if (!io_swapids(true)) {
/* io_swapids() warns on error. */
if (fd != -1) {
@ -430,10 +430,14 @@ iolog_nextid(char *iolog_dir, char sessid[7])
len = snprintf(pathbuf, sizeof(pathbuf), "%s/seq", iolog_dir);
if (len < 0 || len >= ssizeof(pathbuf)) {
errno = ENAMETOOLONG;
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
"%s: %s/seq", __func__, iolog_dir);
goto done;
}
fd = io_open(pathbuf, O_RDWR|O_CREAT);
fd = iolog_openat(AT_FDCWD, pathbuf, O_RDWR|O_CREAT);
if (fd == -1) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
"%s: unable to open %s", __func__, pathbuf);
goto done;
}
sudo_lock_file(fd, SUDO_LOCK);
@ -483,6 +487,8 @@ iolog_nextid(char *iolog_dir, char sessid[7])
#else
if (lseek(fd, 0, SEEK_SET) == -1 || write(fd, buf, 7) != 7) {
#endif
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
"%s: unable to write %s", __func__, pathbuf);
goto done;
}
ret = true;
@ -531,9 +537,10 @@ mkdir_iopath(const char *iolog_path, char *pathbuf, size_t pathsize)
* XXX - move enabled logic into caller?
*/
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;
const char *file;
unsigned char magic[2];
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);
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;
if (iol->enabled) {
int fd = io_open(path, flags);
int fd = iolog_openat(dfd, file, flags);
if (fd != -1) {
if (*mode == 'w') {
if (fchown(fd, iolog_uid, iolog_gid) != 0) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
"%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;
} else {
@ -588,7 +600,7 @@ iolog_open(struct iolog_file *iol, char *path, const char *mode)
} else {
if (*mode == 'w') {
/* Remove old log file in case we recycled sequence numbers. */
(void)unlink(path);
(void)unlinkat(dfd, file, 0);
}
}
debug_return_bool(true);
@ -806,34 +818,26 @@ iolog_gets(struct iolog_file *iol, char *buf, size_t nbytes,
* This file is not compressed.
*/
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 path[PATH_MAX];
char * const *av;
FILE *fp;
int error, len, fd;
int error, fd;
debug_decl(iolog_info_write_log, SUDO_DEBUG_UTIL)
len = snprintf(path, sizeof(path), "%s/log", parent);
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);
fd = iolog_openat(dfd, "log", O_CREAT|O_TRUNC|O_WRONLY);
if (fd == -1 || (fp = fdopen(fd, "w")) == NULL) {
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)
close(fd);
debug_return_bool(false);
}
if (fchown(fd, iolog_uid, iolog_gid) != 0) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
"%s: unable to fchown %d:%d %s", __func__,
(int)iolog_uid, (int)iolog_gid, path);
"%s: unable to fchown %d:%d %s/log", __func__,
(int)iolog_uid, (int)iolog_gid, parent);
}
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);
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", path);
"unable to write to I/O log file %s/log", parent);
}
fclose(fp);

View File

@ -61,21 +61,14 @@
static int timing_event_adj;
struct iolog_info *
parse_logfile(const char *logfile)
parse_logfile(FILE *fp, const char *logfile)
{
FILE *fp;
char *buf = NULL, *cp, *ep;
const char *errstr;
size_t bufsize = 0, cwdsize = 0, cmdsize = 0;
struct iolog_info *li = NULL;
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:
* 1) a log info line
@ -174,13 +167,10 @@ parse_logfile(const char *logfile)
}
}
}
fclose(fp);
free(buf);
debug_return_ptr(li);
bad:
if (fp != NULL)
fclose(fp);
free(buf);
free_iolog_info(li);
debug_return_ptr(NULL);

View File

@ -352,7 +352,7 @@ static const struct iolog_path_escape path_escapes[] = {
/*
* 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
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;
}
#if 0
/* 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) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
"%s", closure->iolog_dir);
goto bad;
}
#endif
debug_return_bool(true);
bad:
@ -408,57 +407,30 @@ bad:
* Write the sudo-style I/O log info file containing user and command info.
*/
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;
FILE *fp;
int error;
struct iolog_info log_info;
debug_decl(iolog_details_write, SUDO_DEBUG_UTIL)
#if 0
fd = openat(closure->iolog_dir_fd, "log", O_CREAT|O_EXCL|O_WRONLY, 0600);
#else
/* XXX */
char path[PATH_MAX]; // XXX
snprintf(path, sizeof(path), "%s/log", closure->iolog_dir);
fd = open(path, O_CREAT|O_EXCL|O_WRONLY, 0600);
#endif
if (fd == -1 || (fp = fdopen(fd, "w")) == NULL) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
"unable to open %s", closure->iolog_dir);
if (fd != -1)
close(fd);
debug_return_bool(false);
}
/* Convert to iolog_info */
memset(&log_info, 0, sizeof(log_info));
log_info.user = details->submituser;
log_info.runas_user = details->runuser;
log_info.runas_group = details->rungroup;
log_info.tty = details->ttyname;
log_info.cwd = details->cwd;
log_info.cmd = details->command;
log_info.lines = details->lines;
log_info.cols = details->columns;
fprintf(fp, "%lld:%s:%s:%s:%s:%d:%d\n%s\n",
(long long)details->start_time, details->submituser,
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);
debug_return_bool(iolog_write_info_file(closure->iolog_dir_fd,
closure->iolog_dir, &log_info, details->argv));
}
static bool
iolog_create(int iofd, struct connection_closure *closure)
{
char path[PATH_MAX];
int len;
debug_decl(iolog_create, SUDO_DEBUG_UTIL)
if (iofd < 0 || iofd >= IOFD_MAX) {
@ -467,17 +439,9 @@ iolog_create(int iofd, struct connection_closure *closure)
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;
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
@ -495,10 +459,8 @@ iolog_close_all(struct connection_closure *closure)
"error closing iofd %d: %s", i, errstr);
}
}
#if 0
if (closure->iolog_dir_fd != -1)
close(closure->iolog_dir_fd);
#endif
debug_return;
}
@ -574,7 +536,7 @@ iolog_restart(RestartMessage *msg, struct connection_closure *closure)
struct timespec target;
struct timing_closure timing;
off_t pos;
int i;
int iofd;
debug_decl(iolog_init, SUDO_DEBUG_UTIL)
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. */
for (i = 0; i < IOFD_MAX; i++) {
char path[PATH_MAX];
int len = snprintf(path, sizeof(path), "%s/%s", closure->iolog_dir,
iolog_fd_to_name(i));
if (len < 0 || len >= ssizeof(path)) {
errno = ENAMETOOLONG;
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
"%s: %s/%s", __func__, closure->iolog_dir, iolog_fd_to_name(i));
goto bad;
for (iofd = 0; iofd < IOFD_MAX; iofd++) {
closure->iolog_files[iofd].enabled = true;
if (!iolog_open(&closure->iolog_files[iofd], closure->iolog_dir_fd,
iofd, "r+")) {
if (errno != ENOENT) {
sudo_debug_printf(
SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
"unable to open %s/%s", closure->iolog_dir,
iolog_fd_to_name(iofd));
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;
}
/* Parse timing file until we reach the target point. */
/* XXX - split up */

View File

@ -87,9 +87,7 @@ struct connection_closure {
struct sudo_event *write_ev;
char *iolog_dir;
struct iolog_file iolog_files[IOFD_MAX];
#if 0
int iolog_dir_fd;
#endif
int sock;
enum connection_status state;
};

View File

@ -58,7 +58,7 @@
#include "sendlog.h"
static struct iolog_file iolog_files[IOFD_MAX];
static char *iolog_path;
static char *iolog_dir;
static void
usage(void)
@ -188,7 +188,7 @@ read_io_buf(struct client_closure *closure)
if (!iolog_files[timing->event].enabled) {
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);
}
@ -208,7 +208,7 @@ read_io_buf(struct client_closure *closure)
nread = iolog_read(&iolog_files[timing->event], closure->buf,
timing->u.nbytes, &errstr);
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);
debug_return_bool(false);
}
@ -1015,29 +1015,27 @@ bad:
* Open any I/O log files that are present.
* The timing file must always exist.
*/
bool
iolog_open_all(char *path, size_t dir_len)
static bool
iolog_open_all(int dfd, const char *iolog_dir)
{
size_t file_len;
int i;
int iofd;
debug_decl(iolog_open_all, SUDO_DEBUG_UTIL)
for (i = 0; i < IOFD_MAX; i++) {
path[dir_len] = '\0';
file_len = strlen(iolog_fd_to_name(i));
if (dir_len + 1 + file_len + 1 >= PATH_MAX) {
errno = ENAMETOOLONG;
sudo_warn("%s/%s", path, iolog_fd_to_name(i));
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);
for (iofd = 0; iofd < IOFD_MAX; iofd++) {
iolog_files[iofd].enabled = true;
if (!iolog_open(&iolog_files[iofd], dfd, iofd, "r")) {
if (errno != ENOENT) {
sudo_warn(U_("unable to open %s/%s"), iolog_dir,
iolog_fd_to_name(iofd));
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);
}
@ -1088,11 +1086,13 @@ main(int argc, char *argv[])
const char *host = "localhost";
const char *port = DEFAULT_PORT_STR;
struct timespec restart = { 0, 0 };
char pathbuf[PATH_MAX];
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)
signal(SIGPIPE, SIG_IGN);
initprogname(argc > 0 ? argv[0] : "sendlog");
setlocale(LC_ALL, "");
bindtextdomain("sudo", LOCALEDIR); /* XXX - add logsrvd domain */
@ -1134,26 +1134,26 @@ main(int argc, char *argv[])
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)
usage();
iolog_path = argv[0];
signal(SIGPIPE, SIG_IGN);
/* 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);
iolog_dir = argv[0];
if ((iolog_dir_fd = open(iolog_dir, O_RDONLY)) == -1) {
sudo_warn("%s", iolog_dir);
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;
/* Open the I/O log files. */
if (!iolog_open_all(pathbuf, len))
if (!iolog_open_all(iolog_dir_fd, iolog_dir))
goto bad;
/* 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.
*/
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[])
{
struct iolog_info iolog_info;
debug_decl(write_info_log, SUDOERS_DEBUG_UTIL)
/* XXX - just use iolog_info in the first place? */
memset(&iolog_info, 0, sizeof(iolog_info));
time(&iolog_info.tstamp);
iolog_info.user = (char *)details->user;
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.lines = details->lines;
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,
N_("unable to write to I/O log file: %s"), strerror(errno));
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[])
{
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 * const *cur;
const char *cp, *plugin_path = NULL;
size_t len;
int i, ret = -1;
int iolog_dir_fd = -1;
debug_decl(sudoers_io_open, SUDOERS_DEBUG_PLUGIN)
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
* intermediate subdirs. Calls mkdtemp() if iolog_path ends in XXXXXX.
*/
len = mkdir_iopath(iolog_details.iolog_path, pathbuf, sizeof(pathbuf));
if (len >= sizeof(pathbuf)) {
len = mkdir_iopath(iolog_details.iolog_path, iolog_path, sizeof(iolog_path));
if (len >= sizeof(iolog_path)) {
log_warning(SLOG_SEND_MAIL, "%s", iolog_details.iolog_path);
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. */
if (!write_info_log(pathbuf, len, &iolog_details, argv))
if (!write_info_log(iolog_dir_fd, iolog_path, &iolog_details, argv))
goto done;
/* Create the timing and I/O log files. */
for (i = 0; i < IOFD_MAX; i++) {
pathbuf[len] = '/';
pathbuf[len + 1] = '\0';
if (strlcat(pathbuf, iolog_fd_to_name(i), sizeof(pathbuf)) >= sizeof(pathbuf)) {
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);
if (!iolog_open(&iolog_files[i], iolog_dir_fd, i, "w")) {
log_warning(SLOG_SEND_MAIL, N_("unable to create %s/%s"),
iolog_path, iolog_fd_to_name(i));
goto done;
}
}
@ -522,6 +523,8 @@ sudoers_io_open(unsigned int version, sudo_conv_t conversation,
ret = true;
done:
if (iolog_dir_fd != -1)
close(iolog_dir_fd);
free(tofree);
if (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
validate_iolog_info(const char *logfile)
{
time_t now;
struct iolog_info *info;
time_t now;
FILE *fp;
time(&now);
/* 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;
if (strcmp(info->cwd, "/") != 0) {

View File

@ -91,6 +91,7 @@ struct replay_closure {
struct sudo_event *sigtstp_ev;
struct timespec *max_delay;
struct timing_closure timing;
int iolog_dir_fd;
bool interactive;
bool suspend_wait;
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 void read_keyboard(int fd, int what, void *v);
static void help(void) __attribute__((__noreturn__));
static int replay_session(const char *iolog_dir, struct timespec *max_wait,
const char *decimal, bool interactive, bool suspend_wait);
static int replay_session(int iolog_dir_fd, const char *iolog_dir,
struct timespec *max_wait, const char *decimal, bool interactive,
bool suspend_wait);
static void sudoreplay_cleanup(void);
static void usage(int);
static void write_output(int fd, int what, void *v);
@ -205,14 +207,15 @@ __dso_public int main(int argc, char *argv[]);
int
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 interactive = true, suspend_wait = false, resize = true;
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 timespec max_delay_storage, *max_delay = NULL;
double dval;
FILE *fp;
debug_decl(main, SUDO_DEBUG_MAIN)
#if defined(SUDO_DEVEL) && defined(__OpenBSD__)
@ -297,6 +300,7 @@ main(int argc, char *argv[])
break;
case 'V':
(void) printf(_("%s version %s\n"), getprogname(), PACKAGE_VERSION);
exitcode = EXIT_SUCCESS;
goto done;
default:
usage(1);
@ -325,41 +329,46 @@ main(int argc, char *argv[])
/* 6 digit ID in base 36, e.g. 01G712AB or free-form name */
id = argv[0];
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]);
if (plen < 0 || plen >= ssizeof(path))
sudo_fatalx(U_("%s/%.2s/%.2s/%.2s/timing: %s"), session_dir,
if (len < 0 || len >= ssizeof(iolog_dir))
sudo_fatalx(U_("%s/%.2s/%.2s/%.2s: %s"), session_dir,
id, &id[2], &id[4], strerror(ENAMETOOLONG));
} else if (id[0] == '/') {
plen = snprintf(path, sizeof(path), "%s/timing", id);
if (plen < 0 || plen >= ssizeof(path))
len = snprintf(iolog_dir, sizeof(iolog_dir), "%s", id);
if (len < 0 || len >= ssizeof(iolog_dir))
sudo_fatalx(U_("%s/timing: %s"), id, strerror(ENAMETOOLONG));
} else {
plen = snprintf(path, sizeof(path), "%s/%s/timing", session_dir, id);
if (plen < 0 || plen >= ssizeof(path)) {
sudo_fatalx(U_("%s/%s/timing: %s"), session_dir, id,
len = snprintf(iolog_dir, sizeof(iolog_dir), "%s/%s", session_dir, id);
if (len < 0 || len >= ssizeof(iolog_dir)) {
sudo_fatalx(U_("%s/%s: %s"), session_dir, id,
strerror(ENAMETOOLONG));
}
}
plen -= 7;
/* 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++) {
path[plen] = '/';
path[plen + 1] = '\0';
if (strlcat(path, iolog_fd_to_name(i), sizeof(path)) >= sizeof(path)) {
errno = ENAMETOOLONG;
sudo_fatal("%s%s", path, iolog_fd_to_name(i));
if (!iolog_open(&iolog_files[i], iolog_dir_fd, i, "r")) {
if (errno != ENOENT) {
sudo_fatal(U_("unable to open %s/%s"), iolog_dir,
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. */
path[plen] = '\0';
strlcat(path, "/log", sizeof(path));
if ((li = parse_logfile(path)) == NULL)
exit(1);
fd = openat(iolog_dir_fd, "log", O_RDONLY, 0);
if (fd == -1 || (fp = fdopen(fd, "r")) == NULL)
sudo_fatal(U_("unable to open %s/%s"), iolog_dir, "log");
if ((li = parse_logfile(fp, iolog_dir)) == NULL)
goto done;
fclose(fp);
printf(_("Replaying sudo session: %s"), li->cmd);
/* Setup terminal if appropriate. */
@ -374,15 +383,14 @@ main(int argc, char *argv[])
li = NULL;
/* Replay session corresponding to iolog_files[]. */
path[plen] = '\0';
exitcode = replay_session(path, max_delay, decimal, interactive,
suspend_wait);
exitcode = replay_session(iolog_dir_fd, iolog_dir, max_delay, decimal,
interactive, suspend_wait);
restore_terminal_size();
sudo_term_restore(ttyfd, true);
done:
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.
*/
if (closure->iolog_dir_fd != -1)
close(closure->iolog_dir_fd);
sudo_ev_free(closure->delay_ev);
sudo_ev_free(closure->keyboard_ev);
sudo_ev_free(closure->output_ev);
@ -923,8 +933,9 @@ signal_cb(int signo, int what, void *v)
}
static struct replay_closure *
replay_closure_alloc(const char *iolog_dir, struct timespec *max_delay,
const char *decimal, bool interactive, bool suspend_wait)
replay_closure_alloc(int iolog_dir_fd, const char *iolog_dir,
struct timespec *max_delay, const char *decimal, bool interactive,
bool suspend_wait)
{
struct replay_closure *closure;
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)
debug_return_ptr(NULL);
closure->iolog_dir_fd = iolog_dir_fd;
closure->iolog_dir = iolog_dir;
closure->interactive = interactive;
closure->suspend_wait = suspend_wait;
@ -1007,16 +1019,17 @@ bad:
}
static int
replay_session(const char *iolog_dir, struct timespec *max_delay,
const char *decimal, bool interactive, bool suspend_wait)
replay_session(int iolog_dir_fd, const char *iolog_dir,
struct timespec *max_delay, const char *decimal, bool interactive,
bool suspend_wait)
{
struct replay_closure *closure;
int ret = 0;
debug_decl(replay_session, SUDO_DEBUG_UTIL)
/* Allocate the delay closure and read the first timing record. */
closure = replay_closure_alloc(iolog_dir, max_delay, decimal, interactive,
suspend_wait);
closure = replay_closure_alloc(iolog_dir_fd, iolog_dir, max_delay, decimal,
interactive, suspend_wait);
if (read_timing_record(closure) != 0) {
ret = 1;
goto done;
@ -1309,12 +1322,17 @@ static int
list_session(char *logfile, regex_t *re, const char *user, const char *tty)
{
char idbuf[7], *idstr, *cp;
struct iolog_info *li = NULL;
const char *timestr;
struct iolog_info *li;
int ret = -1;
FILE *fp;
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;
/* 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;
done:
if (fp != NULL)
fclose(fp);
free_iolog_info(li);
debug_return_int(ret);
}