Simplify expand_iolog_path()

This commit is contained in:
Todd C. Miller
2019-10-24 20:04:33 -06:00
parent 74a0e686ac
commit ee91b7360b
9 changed files with 233 additions and 227 deletions

View File

@@ -98,12 +98,11 @@ struct iolog_file {
struct iolog_path_escape { struct iolog_path_escape {
const char *name; const char *name;
size_t (*copy_fn)(char *, size_t, char *, void *); size_t (*copy_fn)(char *, size_t, void *);
}; };
/* iolog_path.c */ /* iolog_path.c */
/* XXX - bad API */ bool expand_iolog_path(const char *inpath, char *path, size_t pathlen, 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 */
bool iolog_parse_timing(const char *line, struct timing_closure *timing); bool iolog_parse_timing(const char *line, struct timing_closure *timing);
@@ -119,6 +118,7 @@ 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_mkdtemp(char *path); bool iolog_mkdtemp(char *path);
bool iolog_mkpath(char *path);
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, int dfd, int iofd, const char *mode); bool iolog_open(struct iolog_file *iol, int dfd, int iofd, const char *mode);
bool iolog_rename(const char *from, const char *to); bool iolog_rename(const char *from, const char *to);
@@ -127,7 +127,6 @@ char *iolog_gets(struct iolog_file *iol, char *buf, size_t nbytes, const char **
const char *iolog_fd_to_name(int iofd); const char *iolog_fd_to_name(int iofd);
int iolog_openat(int fdf, const char *path, int flags); int iolog_openat(int fdf, const char *path, int flags);
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);
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);
void iolog_rewind(struct iolog_file *iol); void iolog_rewind(struct iolog_file *iol);

View File

@@ -517,34 +517,28 @@ done:
} }
/* /*
* Copy iolog_path to pathbuf and create the directory and any intermediate * Create path and any intermediate directories.
* directories. If iolog_path ends in 'XXXXXX', use mkdtemp(). * If path ends in 'XXXXXX', use mkdtemp().
* Returns SIZE_MAX on error.
*/ */
size_t bool
mkdir_iopath(const char *iolog_path, char *pathbuf, size_t pathsize) iolog_mkpath(char *path)
{ {
size_t len; size_t len;
bool ok; bool ret;
debug_decl(mkdir_iopath, SUDO_DEBUG_UTIL) debug_decl(iolog_mkpath, SUDO_DEBUG_UTIL)
len = strlcpy(pathbuf, iolog_path, pathsize);
if (len >= pathsize) {
errno = ENAMETOOLONG;
debug_return_size_t((size_t)-1);
}
/* /*
* Create path and intermediate subdirs as needed. * Create path and intermediate subdirs as needed.
* If path ends in at least 6 Xs (ala POSIX mktemp), use mkdtemp(). * If path ends in at least 6 Xs (ala POSIX mktemp), use mkdtemp().
* Sets iolog_gid (if it is not already set) as a side effect. * Sets iolog_gid (if it is not already set) as a side effect.
*/ */
if (len >= 6 && strcmp(&pathbuf[len - 6], "XXXXXX") == 0) len = strlen(path);
ok = iolog_mkdtemp(pathbuf); if (len >= 6 && strcmp(&path[len - 6], "XXXXXX") == 0)
ret = iolog_mkdtemp(path);
else else
ok = iolog_mkdirs(pathbuf); ret = iolog_mkdirs(path);
debug_return_size_t(ok ? len : (size_t)-1); debug_return_bool(ret);
} }
/* /*

View File

@@ -52,135 +52,88 @@
#include "sudo_iolog.h" #include "sudo_iolog.h"
/* /*
* Concatenate dir + file, expanding any escape sequences. * Expand any escape sequences in inpath, returning the expanded path.
* Returns the concatenated path and sets slashp point to
* the path separator between the expanded dir and file.
* XXX - simplify by only expanding one thing and removing prefix
*/ */
char * bool
expand_iolog_path(const char *prefix, const char *dir, const char *file, expand_iolog_path(const char *inpath, char *path, size_t pathlen,
char **slashp, const struct iolog_path_escape *escapes, void *closure) const struct iolog_path_escape *escapes, void *closure)
{ {
size_t len, prelen = 0; char *dst, *pathend, tmpbuf[PATH_MAX];
char *dst, *dst0, *path, *pathend, tmpbuf[PATH_MAX]; const char *endbrace, *src;
char *slash = NULL; bool strfit = false;
const char *endbrace, *src = dir; size_t len;
int pass;
bool strfit;
debug_decl(expand_iolog_path, SUDO_DEBUG_UTIL) debug_decl(expand_iolog_path, SUDO_DEBUG_UTIL)
/* Expanded path must be <= PATH_MAX */ /* Collapse multiple leading slashes. */
if (prefix != NULL) while (inpath[0] == '/' && inpath[1] == '/')
prelen = strlen(prefix); inpath++;
path = malloc(prelen + PATH_MAX);
if (path == NULL) {
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
goto bad;
}
*path = '\0';
pathend = path + prelen + PATH_MAX;
dst = path;
/* Copy prefix, if present. */ pathend = path + pathlen;
if (prefix != NULL) { for (src = inpath, dst = path; *src != '\0'; src++) {
memcpy(path, prefix, prelen); if (src[0] == '%') {
dst += prelen; if (src[1] == '{') {
*dst = '\0'; endbrace = strchr(src + 2, '}');
} if (endbrace != NULL) {
const struct iolog_path_escape *esc;
/* Trim leading slashes from file component. */ len = (size_t)(endbrace - src - 2);
while (*file == '/') for (esc = escapes; esc->name != NULL; esc++) {
file++; if (strncmp(src + 2, esc->name, len) == 0 &&
esc->name[len] == '\0')
for (pass = 0; pass < 3; pass++) { break;
strfit = false; }
switch (pass) { if (esc->name != NULL) {
case 0: len = esc->copy_fn(dst, (size_t)(pathend - dst),
src = dir; closure);
escapes++; /* skip "%{seq}" */ if (len >= (size_t)(pathend - dst))
break; goto bad;
case 1: dst += len;
/* Trim trailing slashes from dir component. */ src = endbrace;
while (dst > path + prelen + 1 && dst[-1] == '/') continue;
dst--;
/* The NUL will be replaced with a '/' at the end. */
if (dst + 1 >= pathend)
goto bad;
slash = dst++;
continue;
case 2:
src = file;
escapes--; /* restore "%{seq}" */
break;
}
dst0 = dst;
for (; *src != '\0'; src++) {
if (src[0] == '%') {
if (src[1] == '{') {
endbrace = strchr(src + 2, '}');
if (endbrace != NULL) {
const struct iolog_path_escape *esc;
len = (size_t)(endbrace - src - 2);
for (esc = escapes; esc->name != NULL; esc++) {
if (strncmp(src + 2, esc->name, len) == 0 &&
esc->name[len] == '\0')
break;
}
if (esc->name != NULL) {
len = esc->copy_fn(dst, (size_t)(pathend - dst),
path + prelen, closure);
if (len >= (size_t)(pathend - dst))
goto bad;
dst += len;
src = endbrace;
continue;
}
} }
} else if (src[1] == '%') {
/* Collapse %% -> % */
src++;
} else {
/* May need strftime() */
strfit = true;
} }
} else if (src[1] == '%') {
/* Collapse %% -> % */
src++;
} else {
/* May need strftime() */
strfit = true;
} }
/* Need at least 2 chars, including the NUL terminator. */
if (dst + 1 >= pathend)
goto bad;
*dst++ = *src;
}
*dst = '\0';
/* Expand strftime escapes as needed. */
if (strfit) {
time_t now;
struct tm *timeptr;
time(&now);
if ((timeptr = localtime(&now)) == NULL)
goto bad;
/* We only call strftime() on the current part of the buffer. */
tmpbuf[sizeof(tmpbuf) - 1] = '\0';
len = strftime(tmpbuf, sizeof(tmpbuf), dst0, timeptr);
if (len == 0 || tmpbuf[sizeof(tmpbuf) - 1] != '\0')
goto bad; /* strftime() failed, buf too small? */
if (len >= (size_t)(pathend - dst0))
goto bad; /* expanded buffer too big to fit. */
memcpy(dst0, tmpbuf, len);
dst = dst0 + len;
*dst = '\0';
} }
/* Need at least 2 chars, including the NUL terminator. */
if (dst + 1 >= pathend)
goto bad;
*dst++ = *src;
} }
if (slash != NULL)
*slash = '/';
if (slashp != NULL)
*slashp = slash;
debug_return_str(path); /* Trim trailing slashes and NUL terminate. */
while (dst > path && dst[-1] == '/')
dst--;
*dst = '\0';
/* Expand strftime escapes as needed. */
if (strfit) {
time_t now;
struct tm *timeptr;
time(&now);
if ((timeptr = localtime(&now)) == NULL)
goto bad;
/* We only call strftime() on the current part of the buffer. */
tmpbuf[sizeof(tmpbuf) - 1] = '\0';
len = strftime(tmpbuf, sizeof(tmpbuf), path, timeptr);
if (len == 0 || tmpbuf[sizeof(tmpbuf) - 1] != '\0')
goto bad; /* strftime() failed, buf too small? */
if (len >= (size_t)(pathend - path))
goto bad; /* expanded buffer too big to fit. */
memcpy(path, tmpbuf, len);
dst = path + len;
*dst = '\0';
}
debug_return_bool(true);
bad: bad:
free(path); debug_return_bool(false);
debug_return_str(NULL);
} }

View File

@@ -27,6 +27,7 @@
#ifdef HAVE_STRINGS_H #ifdef HAVE_STRINGS_H
# include <strings.h> # include <strings.h>
#endif /* HAVE_STRINGS_H */ #endif /* HAVE_STRINGS_H */
#include <limits.h>
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
@@ -69,7 +70,7 @@ reset_escape_data(struct iolog_escape_data *data)
} }
static size_t static size_t
fill_seq(char *str, size_t strsize, char *logdir, void *closure) fill_seq(char *str, size_t strsize, void *unused)
{ {
int len; int len;
@@ -83,37 +84,37 @@ fill_seq(char *str, size_t strsize, char *logdir, void *closure)
} }
static size_t static size_t
fill_user(char *str, size_t strsize, char *unused, void *closure) fill_user(char *str, size_t strsize, void *unused)
{ {
return strlcpy(str, escape_data.user, strsize); return strlcpy(str, escape_data.user, strsize);
} }
static size_t static size_t
fill_group(char *str, size_t strsize, char *unused, void *closure) fill_group(char *str, size_t strsize, void *unused)
{ {
return strlcpy(str, escape_data.group, strsize); return strlcpy(str, escape_data.group, strsize);
} }
static size_t static size_t
fill_runas_user(char *str, size_t strsize, char *unused, void *closure) fill_runas_user(char *str, size_t strsize, void *unused)
{ {
return strlcpy(str, escape_data.runas_user, strsize); return strlcpy(str, escape_data.runas_user, strsize);
} }
static size_t static size_t
fill_runas_group(char *str, size_t strsize, char *unused, void *closure) fill_runas_group(char *str, size_t strsize, void *unused)
{ {
return strlcpy(str, escape_data.runas_group, strsize); return strlcpy(str, escape_data.runas_group, strsize);
} }
static size_t static size_t
fill_hostname(char *str, size_t strsize, char *unused, void *closure) fill_hostname(char *str, size_t strsize, void *unused)
{ {
return strlcpy(str, escape_data.host, strsize); return strlcpy(str, escape_data.host, strsize);
} }
static size_t static size_t
fill_command(char *str, size_t strsize, char *unused, void *closure) fill_command(char *str, size_t strsize, void *unused)
{ {
return strlcpy(str, escape_data.command, strsize); return strlcpy(str, escape_data.command, strsize);
} }
@@ -133,8 +134,8 @@ static struct iolog_path_escape path_escapes[] = {
static int static int
do_check(char *dir_in, char *file_in, char *tdir_out, char *tfile_out) do_check(char *dir_in, char *file_in, char *tdir_out, char *tfile_out)
{ {
char *path, *slash; char dir[PATH_MAX], dir_out[PATH_MAX];
char dir_out[4096], file_out[4096]; char file[PATH_MAX], file_out[PATH_MAX];
struct tm *timeptr; struct tm *timeptr;
time_t now; time_t now;
int error = 0; int error = 0;
@@ -150,19 +151,19 @@ do_check(char *dir_in, char *file_in, char *tdir_out, char *tfile_out)
strftime(dir_out, sizeof(dir_out), tdir_out, timeptr); strftime(dir_out, sizeof(dir_out), tdir_out, timeptr);
strftime(file_out, sizeof(file_out), tfile_out, timeptr); strftime(file_out, sizeof(file_out), tfile_out, timeptr);
path = expand_iolog_path(NULL, dir_in, file_in, &slash, path_escapes, NULL); if (!expand_iolog_path(dir_in, dir, sizeof(dir), &path_escapes[1], NULL))
if (path == NULL) sudo_fatalx("unable to expand I/O log dir");
sudo_fatalx("unable to expand I/O log path"); if (!expand_iolog_path(file_in, file, sizeof(file), &path_escapes[0], dir))
*slash = '\0'; sudo_fatalx("unable to expand I/O log file");
if (strcmp(path, dir_out) != 0) {
sudo_warnx("%s: expected %s, got %s", dir_in, dir_out, path); if (strcmp(dir, dir_out) != 0) {
sudo_warnx("%s: expected %s, got %s", dir_in, dir_out, dir);
error = 1; error = 1;
} }
if (strcmp(slash + 1, file_out) != 0) { if (strcmp(file, file_out) != 0) {
sudo_warnx("%s: expected %s, got %s", file_in, file_out, slash + 1); sudo_warnx("%s: expected %s, got %s", file_in, file_out, file);
error = 1; error = 1;
} }
free(path);
return error; return error;
} }

View File

@@ -66,9 +66,9 @@ wheel
somehost somehost
su su
/var/log/sudo-io/ /var/log/sudo-io/
/%{user}/%{runas_user}/%{command}_%Y%m%s_%H%M //%{user}/%{runas_user}/%{command}_%Y%m%s_%H%M
/var/log/sudo-io /var/log/sudo-io
nobody/root/su_%Y%m%s_%H%M /nobody/root/su_%Y%m%s_%H%M
000001 000001
nobody nobody
@@ -91,6 +91,6 @@ somehost
su su
//////// ////////
%{user}/%{runas_user}/%{command} %{user}/%{runas_user}/%{command}
/
nobody/root/su nobody/root/su

View File

@@ -355,16 +355,21 @@ done:
debug_return_bool(ret); debug_return_bool(ret);
} }
struct iolog_path_closure {
char *iolog_dir;
struct iolog_details *details;
};
static size_t static size_t
fill_seq(char *str, size_t strsize, char *logdir, void *closure) fill_seq(char *str, size_t strsize, void *v)
{ {
struct iolog_details *details = closure; struct iolog_path_closure *closure = v;
char *sessid = details->sessid; char *sessid = closure->details->sessid;
int len; int len;
debug_decl(fill_seq, SUDO_DEBUG_UTIL) debug_decl(fill_seq, SUDO_DEBUG_UTIL)
if (sessid[0] == '\0') { if (sessid[0] == '\0') {
if (!iolog_nextid(logdir, sessid)) if (!iolog_nextid(closure->iolog_dir, sessid))
debug_return_size_t((size_t)-1); debug_return_size_t((size_t)-1);
} }
@@ -380,9 +385,10 @@ fill_seq(char *str, size_t strsize, char *logdir, void *closure)
} }
static size_t static size_t
fill_user(char *str, size_t strsize, char *unused, void *closure) fill_user(char *str, size_t strsize, void *v)
{ {
const struct iolog_details *details = closure; struct iolog_path_closure *closure = v;
const struct iolog_details *details = closure->details;
debug_decl(fill_user, SUDO_DEBUG_UTIL) debug_decl(fill_user, SUDO_DEBUG_UTIL)
if (details->submituser == NULL) { if (details->submituser == NULL) {
@@ -394,9 +400,10 @@ fill_user(char *str, size_t strsize, char *unused, void *closure)
} }
static size_t static size_t
fill_group(char *str, size_t strsize, char *unused, void *closure) fill_group(char *str, size_t strsize, void *v)
{ {
const struct iolog_details *details = closure; struct iolog_path_closure *closure = v;
const struct iolog_details *details = closure->details;
debug_decl(fill_group, SUDO_DEBUG_UTIL) debug_decl(fill_group, SUDO_DEBUG_UTIL)
if (details->submitgroup == NULL) { if (details->submitgroup == NULL) {
@@ -408,9 +415,10 @@ fill_group(char *str, size_t strsize, char *unused, void *closure)
} }
static size_t static size_t
fill_runas_user(char *str, size_t strsize, char *unused, void *closure) fill_runas_user(char *str, size_t strsize, void *v)
{ {
const struct iolog_details *details = closure; struct iolog_path_closure *closure = v;
const struct iolog_details *details = closure->details;
debug_decl(fill_runas_user, SUDO_DEBUG_UTIL) debug_decl(fill_runas_user, SUDO_DEBUG_UTIL)
if (details->runuser == NULL) { if (details->runuser == NULL) {
@@ -422,9 +430,10 @@ fill_runas_user(char *str, size_t strsize, char *unused, void *closure)
} }
static size_t static size_t
fill_runas_group(char *str, size_t strsize, char *unused, void *closure) fill_runas_group(char *str, size_t strsize, void *v)
{ {
const struct iolog_details *details = closure; struct iolog_path_closure *closure = v;
const struct iolog_details *details = closure->details;
debug_decl(fill_runas_group, SUDO_DEBUG_UTIL) debug_decl(fill_runas_group, SUDO_DEBUG_UTIL)
/* FIXME: rungroup not guaranteed to be set */ /* FIXME: rungroup not guaranteed to be set */
@@ -437,9 +446,10 @@ fill_runas_group(char *str, size_t strsize, char *unused, void *closure)
} }
static size_t static size_t
fill_hostname(char *str, size_t strsize, char *unused, void *closure) fill_hostname(char *str, size_t strsize, void *v)
{ {
const struct iolog_details *details = closure; struct iolog_path_closure *closure = v;
const struct iolog_details *details = closure->details;
debug_decl(fill_hostname, SUDO_DEBUG_UTIL) debug_decl(fill_hostname, SUDO_DEBUG_UTIL)
if (details->submithost == NULL) { if (details->submithost == NULL) {
@@ -451,9 +461,10 @@ fill_hostname(char *str, size_t strsize, char *unused, void *closure)
} }
static size_t static size_t
fill_command(char *str, size_t strsize, char *unused, void *closure) fill_command(char *str, size_t strsize, void *v)
{ {
const struct iolog_details *details = closure; struct iolog_path_closure *closure = v;
const struct iolog_details *details = closure->details;
debug_decl(fill_command, SUDO_DEBUG_UTIL) debug_decl(fill_command, SUDO_DEBUG_UTIL)
if (details->command == NULL) { if (details->command == NULL) {
@@ -476,7 +487,6 @@ static const struct iolog_path_escape path_escapes[] = {
{ NULL, NULL } { NULL, NULL }
}; };
/* /*
* Create I/O log path * Create I/O log path
* Sets iolog_path, iolog_file and iolog_dir_fd in the closure * Sets iolog_path, iolog_file and iolog_dir_fd in the closure
@@ -485,38 +495,52 @@ static bool
create_iolog_path(struct connection_closure *closure) create_iolog_path(struct connection_closure *closure)
{ {
struct iolog_details *details = &closure->details; struct iolog_details *details = &closure->details;
char pathbuf[PATH_MAX]; struct iolog_path_closure path_closure;
size_t len, pathlen; char expanded_dir[PATH_MAX], expanded_file[PATH_MAX], pathbuf[PATH_MAX];
size_t len;
debug_decl(create_iolog_path, SUDO_DEBUG_UTIL) debug_decl(create_iolog_path, SUDO_DEBUG_UTIL)
details->iolog_path = expand_iolog_path(NULL, logsrvd_conf_iolog_dir(), path_closure.details = details;
logsrvd_conf_iolog_file(), &details->iolog_file, &path_escapes[0], path_closure.iolog_dir = expanded_dir;
details);
if (details->iolog_path == NULL) { if (!expand_iolog_path(logsrvd_conf_iolog_dir(), expanded_dir,
sizeof(expanded_dir), &path_escapes[1], &path_closure)) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"unable to expand iolog path %s/%s", "unable to expand iolog dir %s", logsrvd_conf_iolog_dir());
logsrvd_conf_iolog_dir(), logsrvd_conf_iolog_file()); goto bad;
}
if (!expand_iolog_path(logsrvd_conf_iolog_file(), expanded_file,
sizeof(expanded_file), &path_escapes[0], &path_closure)) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"unable to expand iolog dir %s", logsrvd_conf_iolog_file());
goto bad;
}
len = snprintf(pathbuf, sizeof(pathbuf), "%s/%s", expanded_dir,
expanded_file);
if (len >= sizeof(pathbuf)) {
errno = ENAMETOOLONG;
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO,
"%s/%s", expanded_dir, expanded_file);
goto bad; goto bad;
} }
pathlen = details->iolog_file - details->iolog_path;
/* /*
* Make local copy of I/O log path and create it, along with any * Create log path, along with any intermediate subdirs.
* intermediate subdirs. Calls mkdtemp() if iolog_path ends in XXXXXX. * Calls mkdtemp() if pathbuf ends in XXXXXX.
*/ */
len = mkdir_iopath(details->iolog_path, pathbuf, sizeof(pathbuf)); if (!iolog_mkpath(pathbuf)) {
if (len >= sizeof(pathbuf)) {
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 mkdir iolog path %s", details->iolog_path); "unable to mkdir iolog path %s", pathbuf);
goto bad; goto bad;
} }
free(details->iolog_path);
if ((details->iolog_path = strdup(pathbuf)) == NULL) { if ((details->iolog_path = strdup(pathbuf)) == 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,
"strdup"); "strdup");
goto bad; goto bad;
} }
details->iolog_file = details->iolog_path + pathlen + 1; details->iolog_file = details->iolog_path + strlen(expanded_dir) + 1;
/* We use iolog_dir_fd in calls to openat(2) */ /* We use iolog_dir_fd in calls to openat(2) */
closure->iolog_dir_fd = closure->iolog_dir_fd =

View File

@@ -431,7 +431,6 @@ sudoers_io_open(unsigned int version, sudo_conv_t conversation,
{ {
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 iolog_path[PATH_MAX], sessid[7]; char iolog_path[PATH_MAX], sessid[7];
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;
@@ -478,30 +477,36 @@ sudoers_io_open(unsigned int version, sudo_conv_t conversation,
/* If no I/O log path defined we need to figure it out ourselves. */ /* If no I/O log path defined we need to figure it out ourselves. */
if (iolog_details.iolog_path == NULL) { if (iolog_details.iolog_path == NULL) {
/* Get next session ID and convert it into a path. */ /* Get next session ID and convert it into a path. */
tofree = malloc(sizeof(_PATH_SUDO_IO_LOGDIR) + sizeof(sessid) + 2); len = strlcpy(iolog_path, _PATH_SUDO_IO_LOGDIR, sizeof(iolog_path));
if (tofree == NULL) { if (len + strlen("/00/00/00") >= sizeof(iolog_path)) {
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); sudo_warnx(U_("internal error, %s overflow"), __func__);
ret = false;
goto done; goto done;
} }
memcpy(tofree, _PATH_SUDO_IO_LOGDIR, sizeof(_PATH_SUDO_IO_LOGDIR)); if (!iolog_nextid(iolog_path, sessid)) {
if (!iolog_nextid(tofree, sessid)) {
log_warning(SLOG_SEND_MAIL, N_("unable to update sequence file")); log_warning(SLOG_SEND_MAIL, N_("unable to update sequence file"));
ret = false; ret = false;
goto done; goto done;
} }
(void)snprintf(tofree + sizeof(_PATH_SUDO_IO_LOGDIR), (void)snprintf(iolog_path + sizeof(_PATH_SUDO_IO_LOGDIR),
sizeof(sessid) + 2, "%c%c/%c%c/%c%c", sessid[0], sessid[1], sizeof(iolog_path) - sizeof(_PATH_SUDO_IO_LOGDIR),
sessid[2], sessid[3], sessid[4], sessid[5]); "/%c%c/%c%c/%c%c", sessid[0], sessid[1], sessid[2],
iolog_details.iolog_path = tofree; sessid[3], sessid[4], sessid[5]);
} else {
len = strlcpy(iolog_path, iolog_details.iolog_path, sizeof(iolog_path));
if (len >= sizeof(iolog_path)) {
sudo_warnx(U_("internal error, %s overflow"), __func__);
ret = false;
goto done;
}
} }
/* /*
* Make local copy of I/O log path and create it, along with any * Create I/O log path along with any * intermediate subdirs.
* intermediate subdirs. Calls mkdtemp() if iolog_path ends in XXXXXX. * Calls mkdtemp() if iolog_path ends in XXXXXX.
*/ */
len = mkdir_iopath(iolog_details.iolog_path, iolog_path, sizeof(iolog_path)); if (!iolog_mkpath(iolog_path)) {
if (len >= sizeof(iolog_path)) { log_warning(SLOG_SEND_MAIL, "%s", iolog_path);
log_warning(SLOG_SEND_MAIL, "%s", iolog_details.iolog_path);
goto done; goto done;
} }
@@ -549,7 +554,6 @@ sudoers_io_open(unsigned int version, sudo_conv_t conversation,
done: done:
if (iolog_dir_fd != -1) if (iolog_dir_fd != -1)
close(iolog_dir_fd); close(iolog_dir_fd);
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);
if (iolog_details.runas_gr) if (iolog_details.runas_gr)

View File

@@ -42,12 +42,13 @@
#include "sudo_iolog.h" #include "sudo_iolog.h"
static size_t static size_t
fill_seq(char *str, size_t strsize, char *logdir, void *closure) fill_seq(char *str, size_t strsize, void *v)
{ {
#ifdef SUDOERS_NO_SEQ #ifdef SUDOERS_NO_SEQ
debug_decl(fill_seq, SUDO_DEBUG_UTIL) debug_decl(fill_seq, SUDO_DEBUG_UTIL)
debug_return_size_t(strlcpy(str, "%{seq}", strsize)); debug_return_size_t(strlcpy(str, "%{seq}", strsize));
#else #else
char *logdir = v;
static char sessid[7]; static char sessid[7];
int len; int len;
debug_decl(fill_seq, SUDO_DEBUG_UTIL) debug_decl(fill_seq, SUDO_DEBUG_UTIL)
@@ -67,14 +68,14 @@ fill_seq(char *str, size_t strsize, char *logdir, void *closure)
} }
static size_t static size_t
fill_user(char *str, size_t strsize, char *unused, void *closure) fill_user(char *str, size_t strsize, void *unused)
{ {
debug_decl(fill_user, SUDO_DEBUG_UTIL) debug_decl(fill_user, SUDO_DEBUG_UTIL)
debug_return_size_t(strlcpy(str, user_name, strsize)); debug_return_size_t(strlcpy(str, user_name, strsize));
} }
static size_t static size_t
fill_group(char *str, size_t strsize, char *unused, void *closure) fill_group(char *str, size_t strsize, void *unused)
{ {
struct group *grp; struct group *grp;
size_t len; size_t len;
@@ -92,14 +93,14 @@ fill_group(char *str, size_t strsize, char *unused, void *closure)
} }
static size_t static size_t
fill_runas_user(char *str, size_t strsize, char *unused, void *closure) fill_runas_user(char *str, size_t strsize, void *unused)
{ {
debug_decl(fill_runas_user, SUDO_DEBUG_UTIL) debug_decl(fill_runas_user, SUDO_DEBUG_UTIL)
debug_return_size_t(strlcpy(str, runas_pw->pw_name, strsize)); debug_return_size_t(strlcpy(str, runas_pw->pw_name, strsize));
} }
static size_t static size_t
fill_runas_group(char *str, size_t strsize, char *unused, void *closure) fill_runas_group(char *str, size_t strsize, void *unused)
{ {
struct group *grp; struct group *grp;
size_t len; size_t len;
@@ -121,14 +122,14 @@ fill_runas_group(char *str, size_t strsize, char *unused, void *closure)
} }
static size_t static size_t
fill_hostname(char *str, size_t strsize, char *unused, void *closure) fill_hostname(char *str, size_t strsize, void *unused)
{ {
debug_decl(fill_hostname, SUDO_DEBUG_UTIL) debug_decl(fill_hostname, SUDO_DEBUG_UTIL)
debug_return_size_t(strlcpy(str, user_shost, strsize)); debug_return_size_t(strlcpy(str, user_shost, strsize));
} }
static size_t static size_t
fill_command(char *str, size_t strsize, char *unused, void *closure) fill_command(char *str, size_t strsize, void *unused)
{ {
debug_decl(fill_command, SUDO_DEBUG_UTIL) debug_decl(fill_command, SUDO_DEBUG_UTIL)
debug_return_size_t(strlcpy(str, user_base, strsize)); debug_return_size_t(strlcpy(str, user_base, strsize));

View File

@@ -233,6 +233,45 @@ cleanup:
debug_return_int(ret); debug_return_int(ret);
} }
/*
* Expand I/O log dir and file into a full path.
* Returns the full I/O log path prefixed with "iolog_path=".
* Sets sudo_user.iolog_file as a side effect.
*/
static char *
format_iolog_path(void)
{
char dir[PATH_MAX], file[PATH_MAX];
char *iolog_path = NULL;
int oldlocale;
bool ok;
debug_decl(format_iolog_path, SUDOERS_DEBUG_PLUGIN)
/* Use sudoers locale for strftime() */
sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale);
ok = expand_iolog_path(def_iolog_dir, dir, sizeof(dir),
&sudoers_iolog_path_escapes[1], NULL);
if (ok) {
ok = expand_iolog_path(def_iolog_file, file, sizeof(file),
&sudoers_iolog_path_escapes[0], dir);
}
sudoers_setlocale(oldlocale, NULL);
if (!ok)
goto done;
if (asprintf(&iolog_path, "iolog_path=%s/%s", dir, file) == -1) {
iolog_path = NULL;
goto done;
}
/* Stash pointer to the I/O log file for use when logging. */
sudo_user.iolog_file =
iolog_path + sizeof("iolog_path=") - 1 + strlen(dir) + 1;
done:
debug_return_str(iolog_path);
}
int int
sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[], sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[],
bool verbose, void *closure) bool verbose, void *closure)
@@ -472,21 +511,12 @@ sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[],
if (ISSET(sudo_mode, (MODE_RUN | MODE_EDIT))) { if (ISSET(sudo_mode, (MODE_RUN | MODE_EDIT))) {
if ((def_log_input || def_log_output) && def_iolog_file && def_iolog_dir) { if ((def_log_input || def_log_output) && def_iolog_file && def_iolog_dir) {
const char prefix[] = "iolog_path="; if ((iolog_path = format_iolog_path()) == NULL) {
/* Use sudoers locale for strftime() */
sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale);
iolog_path = expand_iolog_path(prefix, def_iolog_dir,
def_iolog_file, &sudo_user.iolog_file,
sudoers_iolog_path_escapes, NULL);
sudoers_setlocale(oldlocale, NULL);
if (iolog_path == NULL) {
if (!def_ignore_iolog_errors) if (!def_ignore_iolog_errors)
goto done; goto done;
/* Unable to expand I/O log path, disable I/O logging. */ /* Unable to expand I/O log path, disable I/O logging. */
def_log_input = false; def_log_input = false;
def_log_output = false; def_log_output = false;
} else {
sudo_user.iolog_file++;
} }
} }
} }