Avoid relying on globals filled in by the sudoers policy module for

the sudoers I/O log module.  The I/O log open function now pulls the
bits it needs out of user_info and command_info.
This commit is contained in:
Todd C. Miller
2010-12-29 17:32:04 -05:00
parent 97b7ae8892
commit fec059a890

View File

@@ -70,6 +70,26 @@ struct script_buf {
char buf[16 * 1024]; char buf[16 * 1024];
}; };
/* XXX - separate sudoers.h and iolog.h? */
#undef runas_pw
#undef runas_gr
struct iolog_details {
const char *cwd;
const char *tty;
const char *user;
const char *command;
const char *iolog_file;
char *iolog_dir;
struct passwd *runas_pw;
struct group *runas_gr;
int iolog_stdin;
int iolog_stdout;
int iolog_stderr;
int iolog_ttyin;
int iolog_ttyout;
};
#define IOFD_STDIN 0 #define IOFD_STDIN 0
#define IOFD_STDOUT 1 #define IOFD_STDOUT 1
#define IOFD_STDERR 2 #define IOFD_STDERR 2
@@ -256,18 +276,168 @@ open_io_fd(char *pathbuf, int len, const char *suffix, int docompress)
return vfd; return vfd;
} }
/*
* Pull out I/O log related data from user_info and command_info arrays.
*/
static void
iolog_deserialize_info(struct iolog_details *details, char * const user_info[],
char * const command_info[])
{
const char *runas_uid_str = "0", *runas_euid_str = NULL;
const char *runas_gid_str = "0", *runas_egid_str = NULL;
char id[MAX_UID_T_LEN + 2], *ep;
char * const *cur;
unsigned long ulval;
uid_t runas_uid = 0;
gid_t runas_gid = 0;
memset(details, 0, sizeof(*details));
for (cur = user_info; *cur != NULL; cur++) {
switch (**cur) {
case 'c':
if (strncmp(*cur, "cwd=", sizeof("cwd=") - 1) == 0) {
details->cwd = *cur + sizeof("cwd=") - 1;
continue;
}
break;
case 't':
if (strncmp(*cur, "tty=", sizeof("tty=") - 1) == 0) {
details->tty = *cur + sizeof("tty=") - 1;
continue;
}
break;
case 'u':
if (strncmp(*cur, "user=", sizeof("user=") - 1) == 0) {
details->user = *cur + sizeof("user=") - 1;
continue;
}
break;
}
}
for (cur = command_info; *cur != NULL; cur++) {
switch (**cur) {
case 'c':
if (strncmp(*cur, "command=", sizeof("command=") - 1) == 0) {
details->command = *cur + sizeof("command=") - 1;
continue;
}
break;
case 'i':
if (strncmp(*cur, "iolog_file=", sizeof("iolog_file=") - 1) == 0) {
details->iolog_file = *cur + sizeof("iolog_file=") - 1;
continue;
}
if (strncmp(*cur, "iolog_dir=", sizeof("iolog_dir=") - 1) == 0) {
details->iolog_dir = *cur + sizeof("iolog_dir=") - 1;
continue;
}
if (strncmp(*cur, "iolog_stdin=", sizeof("iolog_stdin=") - 1) == 0) {
if (atobool(*cur + sizeof("iolog_stdin=") - 1) == TRUE)
details->iolog_stdin = TRUE;
continue;
}
if (strncmp(*cur, "iolog_stdout=", sizeof("iolog_stdout=") - 1) == 0) {
if (atobool(*cur + sizeof("iolog_stdout=") - 1) == TRUE)
details->iolog_stdout = TRUE;
continue;
}
if (strncmp(*cur, "iolog_stderr=", sizeof("iolog_stderr=") - 1) == 0) {
if (atobool(*cur + sizeof("iolog_stderr=") - 1) == TRUE)
details->iolog_stderr = TRUE;
continue;
}
if (strncmp(*cur, "iolog_ttyin=", sizeof("iolog_ttyin=") - 1) == 0) {
if (atobool(*cur + sizeof("iolog_ttyin=") - 1) == TRUE)
details->iolog_ttyin = TRUE;
continue;
}
if (strncmp(*cur, "iolog_ttyout=", sizeof("iolog_ttyout=") - 1) == 0) {
if (atobool(*cur + sizeof("iolog_ttyout=") - 1) == TRUE)
details->iolog_ttyout = TRUE;
continue;
}
if (strncmp(*cur, "iolog_compress=", sizeof("iolog_compress=") - 1) == 0) {
if (atobool(*cur + sizeof("iolog_compress=") - 1) == TRUE)
iolog_compress = TRUE; /* must be global */
continue;
}
break;
case 'r':
if (strncmp(*cur, "runas_gid=", sizeof("runas_gid=") - 1) == 0) {
runas_gid_str = *cur + sizeof("runas_gid=") - 1;
continue;
}
if (strncmp(*cur, "runas_egid=", sizeof("runas_egid=") - 1) == 0) {
runas_egid_str = *cur + sizeof("runas_egid=") - 1;
continue;
}
if (strncmp(*cur, "runas_uid=", sizeof("runas_uid=") - 1) == 0) {
runas_uid_str = *cur + sizeof("runas_uid=") - 1;
continue;
}
if (strncmp(*cur, "runas_euid=", sizeof("runas_euid=") - 1) == 0) {
runas_euid_str = *cur + sizeof("runas_euid=") - 1;
continue;
}
break;
}
}
/*
* Lookup runas user and group, preferring effective over real uid/gid.
*/
if (runas_euid_str != NULL)
runas_uid_str = runas_euid_str;
if (runas_uid_str != NULL) {
errno = 0;
ulval = strtoul(runas_uid_str, &ep, 0);
if (*runas_uid_str != '\0' && *ep == '\0' &&
(errno != ERANGE || ulval != ULONG_MAX)) {
runas_uid = (uid_t)ulval;
}
}
if (runas_egid_str != NULL)
runas_gid_str = runas_egid_str;
if (runas_gid_str != NULL) {
errno = 0;
ulval = strtoul(runas_gid_str, &ep, 0);
if (*runas_gid_str != '\0' && *ep == '\0' &&
(errno != ERANGE || ulval != ULONG_MAX)) {
runas_gid = (gid_t)ulval;
}
}
details->runas_pw = sudo_getpwuid(runas_uid);
if (details->runas_pw == NULL) {
id[0] = '#';
strlcpy(&id[1], runas_uid_str, sizeof(id) - 1);
details->runas_pw = sudo_fakepwnam(id, runas_gid);
}
if (runas_gid != details->runas_pw->pw_gid) {
details->runas_gr = sudo_getgrgid(runas_gid);
if (details->runas_gr == NULL) {
id[0] = '#';
strlcpy(&id[1], runas_gid_str, sizeof(id) - 1);
details->runas_gr = sudo_fakegrnam(id);
}
}
}
static int static int
sudoers_io_open(unsigned int version, sudo_conv_t conversation, sudoers_io_open(unsigned int version, sudo_conv_t conversation,
sudo_printf_t plugin_printf, char * const settings[], sudo_printf_t plugin_printf, char * const settings[],
char * const user_info[], char * const command_info[], char * const user_info[], char * const command_info[],
int argc, char * const argv[], char * const user_env[]) int argc, char * const argv[], char * const user_env[])
{ {
struct iolog_details details;
char pathbuf[PATH_MAX], sessid[9]; char pathbuf[PATH_MAX], sessid[9];
char *tofree = NULL, *iolog_dir = NULL, *iolog_file = NULL; char *tofree = NULL;
char * const *cur; char * const *cur;
FILE *io_logfile; FILE *io_logfile;
int len, iolog_stdin = FALSE, iolog_stdout = FALSE, iolog_stderr = FALSE; int len;
int iolog_ttyin = FALSE, iolog_ttyout = FALSE, iolog_compress = FALSE;
int rval = -1; int rval = -1;
if (!sudo_conv) if (!sudo_conv)
@@ -285,64 +455,27 @@ sudoers_io_open(unsigned int version, sudo_conv_t conversation,
goto done; goto done;
} }
sudo_setpwent();
sudo_setgrent();
/* /*
* Pull iolog settings out of command_info, if any. * Pull iolog settings out of command_info, if any.
*/ */
for (cur = command_info; *cur != NULL; cur++) { iolog_deserialize_info(&details, user_info, command_info);
if (**cur != 'i')
continue;
if (strncmp(*cur, "iolog_file=", sizeof("iolog_file=") - 1) == 0) {
iolog_file = *cur + sizeof("iolog_file=") - 1;
continue;
}
if (strncmp(*cur, "iolog_dir=", sizeof("iolog_dir=") - 1) == 0) {
iolog_dir = *cur + sizeof("iolog_dir=") - 1;
continue;
}
if (strncmp(*cur, "iolog_stdin=", sizeof("iolog_stdin=") - 1) == 0) {
if (atobool(*cur + sizeof("iolog_stdin=") - 1) == TRUE)
iolog_stdin = TRUE;
continue;
}
if (strncmp(*cur, "iolog_stdout=", sizeof("iolog_stdout=") - 1) == 0) {
if (atobool(*cur + sizeof("iolog_stdout=") - 1) == TRUE)
iolog_stdout = TRUE;
continue;
}
if (strncmp(*cur, "iolog_stderr=", sizeof("iolog_stderr=") - 1) == 0) {
if (atobool(*cur + sizeof("iolog_stderr=") - 1) == TRUE)
iolog_stderr = TRUE;
continue;
}
if (strncmp(*cur, "iolog_ttyin=", sizeof("iolog_ttyin=") - 1) == 0) {
if (atobool(*cur + sizeof("iolog_ttyin=") - 1) == TRUE)
iolog_ttyin = TRUE;
continue;
}
if (strncmp(*cur, "iolog_ttyout=", sizeof("iolog_ttyout=") - 1) == 0) {
if (atobool(*cur + sizeof("iolog_ttyout=") - 1) == TRUE)
iolog_ttyout = TRUE;
continue;
}
if (strncmp(*cur, "iolog_compress=", sizeof("iolog_compress=") - 1) == 0) {
if (atobool(*cur + sizeof("iolog_compress=") - 1) == TRUE)
iolog_compress = TRUE;
continue;
}
}
/* Did policy module disable I/O logging? */ /* Did policy module disable I/O logging? */
if (!iolog_stdin && !iolog_ttyin && !iolog_stdout && !iolog_stderr && if (!details.iolog_stdin && !details.iolog_ttyin &&
!iolog_ttyout) { !details.iolog_stdout && !details.iolog_stderr &&
!details.iolog_ttyout) {
rval = FALSE; rval = FALSE;
goto done; goto done;
} }
/* If no I/O log file defined we need to figure it out ourselves. */ /* If no I/O log file defined we need to figure it out ourselves. */
if (iolog_dir == NULL) if (details.iolog_dir == NULL)
iolog_dir = tofree = estrdup(_PATH_SUDO_IO_LOGDIR); details.iolog_dir = tofree = estrdup(_PATH_SUDO_IO_LOGDIR);
if (iolog_file == NULL) { if (details.iolog_file == NULL) {
/* Get next session ID and convert it into a path. */ /* Get next session ID and convert it into a path. */
io_nextid(iolog_dir, sessid); io_nextid(details.iolog_dir, sessid);
sessid[8] = '\0'; sessid[8] = '\0';
sessid[7] = sessid[5]; sessid[7] = sessid[5];
sessid[6] = sessid[4]; sessid[6] = sessid[4];
@@ -350,11 +483,12 @@ sudoers_io_open(unsigned int version, sudo_conv_t conversation,
sessid[4] = sessid[3]; sessid[4] = sessid[3];
sessid[3] = sessid[2]; sessid[3] = sessid[2];
sessid[2] = '/'; sessid[2] = '/';
iolog_file = sessid; details.iolog_file = sessid;
} }
/* Build a path from I/O file and dir, creating intermediate subdirs. */ /* Build a path from I/O file and dir, creating intermediate subdirs. */
len = build_iopath(iolog_dir, iolog_file, pathbuf, sizeof(pathbuf)); len = build_iopath(details.iolog_dir, details.iolog_file,
pathbuf, sizeof(pathbuf));
if (len < 0 || len >= sizeof(pathbuf)) if (len < 0 || len >= sizeof(pathbuf))
goto done; goto done;
@@ -365,40 +499,46 @@ sudoers_io_open(unsigned int version, sudo_conv_t conversation,
if (io_logfile == NULL) if (io_logfile == NULL)
log_error(USE_ERRNO, "Can't create %s", pathbuf); log_error(USE_ERRNO, "Can't create %s", pathbuf);
io_fds[IOFD_TIMING].v = open_io_fd(pathbuf, len, "/timing", iolog_compress); io_fds[IOFD_TIMING].v = open_io_fd(pathbuf, len, "/timing",
iolog_compress);
if (io_fds[IOFD_TIMING].v == NULL) if (io_fds[IOFD_TIMING].v == NULL)
log_error(USE_ERRNO, "Can't create %s", pathbuf); log_error(USE_ERRNO, "Can't create %s", pathbuf);
if (iolog_ttyin) { if (details.iolog_ttyin) {
io_fds[IOFD_TTYIN].v = open_io_fd(pathbuf, len, "/ttyin", iolog_compress); io_fds[IOFD_TTYIN].v = open_io_fd(pathbuf, len, "/ttyin",
iolog_compress);
if (io_fds[IOFD_TTYIN].v == NULL) if (io_fds[IOFD_TTYIN].v == NULL)
log_error(USE_ERRNO, "Can't create %s", pathbuf); log_error(USE_ERRNO, "Can't create %s", pathbuf);
} else { } else {
sudoers_io.log_ttyin = NULL; sudoers_io.log_ttyin = NULL;
} }
if (iolog_stdin) { if (details.iolog_stdin) {
io_fds[IOFD_STDIN].v = open_io_fd(pathbuf, len, "/stdin", iolog_compress); io_fds[IOFD_STDIN].v = open_io_fd(pathbuf, len, "/stdin",
iolog_compress);
if (io_fds[IOFD_STDIN].v == NULL) if (io_fds[IOFD_STDIN].v == NULL)
log_error(USE_ERRNO, "Can't create %s", pathbuf); log_error(USE_ERRNO, "Can't create %s", pathbuf);
} else { } else {
sudoers_io.log_stdin = NULL; sudoers_io.log_stdin = NULL;
} }
if (iolog_ttyout) { if (details.iolog_ttyout) {
io_fds[IOFD_TTYOUT].v = open_io_fd(pathbuf, len, "/ttyout", iolog_compress); io_fds[IOFD_TTYOUT].v = open_io_fd(pathbuf, len, "/ttyout",
iolog_compress);
if (io_fds[IOFD_TTYOUT].v == NULL) if (io_fds[IOFD_TTYOUT].v == NULL)
log_error(USE_ERRNO, "Can't create %s", pathbuf); log_error(USE_ERRNO, "Can't create %s", pathbuf);
} else { } else {
sudoers_io.log_ttyout = NULL; sudoers_io.log_ttyout = NULL;
} }
if (iolog_stdout) { if (details.iolog_stdout) {
io_fds[IOFD_STDOUT].v = open_io_fd(pathbuf, len, "/stdout", iolog_compress); io_fds[IOFD_STDOUT].v = open_io_fd(pathbuf, len, "/stdout",
iolog_compress);
if (io_fds[IOFD_STDOUT].v == NULL) if (io_fds[IOFD_STDOUT].v == NULL)
log_error(USE_ERRNO, "Can't create %s", pathbuf); log_error(USE_ERRNO, "Can't create %s", pathbuf);
} else { } else {
sudoers_io.log_stdout = NULL; sudoers_io.log_stdout = NULL;
} }
if (iolog_stderr) { if (details.iolog_stderr) {
io_fds[IOFD_STDERR].v = open_io_fd(pathbuf, len, "/stderr", iolog_compress); io_fds[IOFD_STDERR].v = open_io_fd(pathbuf, len, "/stderr",
iolog_compress);
if (io_fds[IOFD_STDERR].v == NULL) if (io_fds[IOFD_STDERR].v == NULL)
log_error(USE_ERRNO, "Can't create %s", pathbuf); log_error(USE_ERRNO, "Can't create %s", pathbuf);
} else { } else {
@@ -407,19 +547,29 @@ sudoers_io_open(unsigned int version, sudo_conv_t conversation,
gettimeofday(&last_time, NULL); gettimeofday(&last_time, NULL);
/* XXX - log more stuff? window size? environment? */ fprintf(io_logfile, "%ld:%s:%s:%s:%s\n", (long)last_time.tv_sec,
/* XXX - don't rely on policy module globals */ details.user ? details.user : "unknown", details.runas_pw->pw_name,
fprintf(io_logfile, "%ld:%s:%s:%s:%s\n", (long)last_time.tv_sec, user_name, details.runas_gr ? details.runas_gr->gr_name : "",
runas_pw->pw_name, runas_gr ? runas_gr->gr_name : "", user_tty); details.tty ? details.tty : "unknown");
fprintf(io_logfile, "%s\n", user_cwd); fputs(details.command ? details.command : "unknown", io_logfile);
fprintf(io_logfile, "%s%s%s\n", user_cmnd, user_args ? " " : "", for (cur = &argv[1]; *cur != NULL; cur++) {
user_args ? user_args : ""); if (cur != &argv[1])
fputc(' ', io_logfile);
fputs(*cur, io_logfile);
}
fputc('\n', io_logfile);
fclose(io_logfile); fclose(io_logfile);
rval = TRUE; rval = TRUE;
done: done:
efree(tofree); efree(tofree);
if (details.runas_pw)
pw_delref(details.runas_pw);
sudo_endpwent();
if (details.runas_gr)
gr_delref(details.runas_gr);
sudo_endgrent();
return rval; return rval;
} }