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:
parent
7ba7c5835e
commit
282263c113
@ -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 */
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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. */
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user