--- embedaddon/sudo/plugins/sudoers/iolog.c 2012/02/21 16:23:02 1.1 +++ embedaddon/sudo/plugins/sudoers/iolog.c 2013/10/14 07:56:34 1.1.1.5 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2011 Todd C. Miller + * Copyright (c) 2009-2013 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -17,7 +17,6 @@ #include #include -#include #include #include #include @@ -44,7 +43,6 @@ #include #include #include -#include #include #include #ifdef HAVE_ZLIB_H @@ -52,18 +50,8 @@ #endif #include "sudoers.h" +#include "iolog.h" -/* plugin_error.c */ -extern sigjmp_buf error_jmp; - -union io_fd { - FILE *f; -#ifdef HAVE_ZLIB_H - gzFile g; -#endif - void *v; -}; - struct script_buf { int len; /* buffer length (how much read in) */ int off; /* write position (how much already consumed) */ @@ -82,58 +70,92 @@ struct iolog_details { const char *iolog_path; struct passwd *runas_pw; struct group *runas_gr; - int iolog_stdin; - int iolog_stdout; - int iolog_stderr; - int iolog_ttyin; - int iolog_ttyout; + int lines; + int cols; }; -#define IOFD_STDIN 0 -#define IOFD_STDOUT 1 -#define IOFD_STDERR 2 -#define IOFD_TTYIN 3 -#define IOFD_TTYOUT 4 -#define IOFD_TIMING 5 -#define IOFD_MAX 6 - -#define SESSID_MAX 2176782336U - static int iolog_compress; static struct timeval last_time; -static union io_fd io_fds[IOFD_MAX]; -extern struct io_plugin sudoers_io; +static unsigned int sessid_max = SESSID_MAX; +/* sudoers_io is declared at the end of this file. */ +extern __dso_public struct io_plugin sudoers_io; + /* - * Create parent directories for path as needed, but not path itself. + * Create path and any parent directories as needed. + * If is_temp is set, use mkdtemp() for the final directory. */ static void -mkdir_parents(char *path) +io_mkdirs(char *path, mode_t mode, bool is_temp) { struct stat sb; + gid_t parent_gid = 0; char *slash = path; + debug_decl(io_mkdirs, SUDO_DEBUG_UTIL) - for (;;) { - if ((slash = strchr(slash + 1, '/')) == NULL) - break; + /* Fast path: not a temporary and already exists. */ + if (!is_temp && stat(path, &sb) == 0) { + if (!S_ISDIR(sb.st_mode)) { + log_fatal(0, N_("%s exists but is not a directory (0%o)"), + path, (unsigned int) sb.st_mode); + } + debug_return; + } + + while ((slash = strchr(slash + 1, '/')) != NULL) { *slash = '\0'; if (stat(path, &sb) != 0) { - if (mkdir(path, S_IRWXU) != 0) - log_error(USE_ERRNO, _("unable to mkdir %s"), path); + if (mkdir(path, mode) != 0) + log_fatal(USE_ERRNO, N_("unable to mkdir %s"), path); + ignore_result(chown(path, (uid_t)-1, parent_gid)); } else if (!S_ISDIR(sb.st_mode)) { - log_error(0, _("%s: %s"), path, strerror(ENOTDIR)); + log_fatal(0, N_("%s exists but is not a directory (0%o)"), + path, (unsigned int) sb.st_mode); + } else { + /* Inherit gid of parent dir for ownership. */ + parent_gid = sb.st_gid; } *slash = '/'; } + /* Create final path component. */ + if (is_temp) { + if (mkdtemp(path) == NULL) + log_fatal(USE_ERRNO, N_("unable to mkdir %s"), path); + ignore_result(chown(path, (uid_t)-1, parent_gid)); + } else { + if (mkdir(path, mode) != 0 && errno != EEXIST) + log_fatal(USE_ERRNO, N_("unable to mkdir %s"), path); + ignore_result(chown(path, (uid_t)-1, parent_gid)); + } + debug_return; } /* + * Set max session ID (aka sequence number) + */ +int +io_set_max_sessid(const char *maxval) +{ + unsigned long ulval; + char *ep; + + errno = 0; + ulval = strtoul(maxval, &ep, 0); + if (*maxval != '\0' && *ep == '\0' && + (errno != ERANGE || ulval != ULONG_MAX)) { + sessid_max = MIN((unsigned int)ulval, SESSID_MAX); + return true; + } + return false; +} + +/* * Read the on-disk sequence number, set sessid to the next * number, and update the on-disk copy. * Uses file locking to avoid sequence number collisions. */ void -io_nextid(char *iolog_dir, char sessid[7]) +io_nextid(char *iolog_dir, char *iolog_dir_fallback, char sessid[7]) { struct stat sb; char buf[32], *ep; @@ -143,18 +165,12 @@ io_nextid(char *iolog_dir, char sessid[7]) ssize_t nread; char pathbuf[PATH_MAX]; static const char b36char[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + debug_decl(io_nextid, SUDO_DEBUG_UTIL) /* * Create I/O log directory if it doesn't already exist. */ - mkdir_parents(iolog_dir); - if (stat(iolog_dir, &sb) != 0) { - if (mkdir(iolog_dir, S_IRWXU) != 0) - log_error(USE_ERRNO, _("unable to mkdir %s"), iolog_dir); - } else if (!S_ISDIR(sb.st_mode)) { - log_error(0, _("%s exists but is not a directory (0%o)"), - iolog_dir, (unsigned int) sb.st_mode); - } + io_mkdirs(iolog_dir, S_IRWXU, false); /* * Open sequence file @@ -162,22 +178,49 @@ io_nextid(char *iolog_dir, char sessid[7]) len = snprintf(pathbuf, sizeof(pathbuf), "%s/seq", iolog_dir); if (len <= 0 || len >= sizeof(pathbuf)) { errno = ENAMETOOLONG; - log_error(USE_ERRNO, "%s/seq", pathbuf); + log_fatal(USE_ERRNO, "%s/seq", pathbuf); } fd = open(pathbuf, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR); if (fd == -1) - log_error(USE_ERRNO, _("unable to open %s"), pathbuf); + log_fatal(USE_ERRNO, N_("unable to open %s"), pathbuf); lock_file(fd, SUDO_LOCK); - /* Read seq number (base 36). */ - nread = read(fd, buf, sizeof(buf)); - if (nread != 0) { - if (nread == -1) - log_error(USE_ERRNO, _("unable to read %s"), pathbuf); - id = strtoul(buf, &ep, 36); - if (buf == ep || id >= SESSID_MAX) - log_error(0, _("invalid sequence number %s"), pathbuf); + /* + * If there is no seq file in iolog_dir and a fallback dir was + * specified, look for seq in the fallback dir. This is to work + * around a bug in sudo 1.8.5 and older where iolog_dir was not + * expanded before the sequence number was updated. + */ + if (iolog_dir_fallback != NULL && fstat(fd, &sb) == 0 && sb.st_size == 0) { + char fallback[PATH_MAX]; + + len = snprintf(fallback, sizeof(fallback), "%s/seq", + iolog_dir_fallback); + if (len > 0 && len < sizeof(fallback)) { + int fd2 = open(fallback, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR); + if (fd2 != -1) { + nread = read(fd2, buf, sizeof(buf)); + if (nread > 0) { + id = strtoul(buf, &ep, 36); + if (buf == ep || id >= sessid_max) + id = 0; + } + close(fd2); + } + } } + + /* Read current seq number (base 36). */ + if (id == 0) { + nread = read(fd, buf, sizeof(buf)); + if (nread != 0) { + if (nread == -1) + log_fatal(USE_ERRNO, N_("unable to read %s"), pathbuf); + id = strtoul(buf, &ep, 36); + if (buf == ep || id >= sessid_max) + id = 0; + } + } id++; /* @@ -190,14 +233,16 @@ io_nextid(char *iolog_dir, char sessid[7]) } buf[6] = '\n'; - /* Stash id logging purposes */ + /* Stash id for logging purposes. */ memcpy(sessid, buf, 6); sessid[6] = '\0'; /* Rewind and overwrite old seq file. */ - if (lseek(fd, 0, SEEK_SET) == (off_t)-1 || write(fd, buf, 7) != 7) - log_error(USE_ERRNO, _("unable to write to %s"), pathbuf); + if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1 || write(fd, buf, 7) != 7) + log_fatal(USE_ERRNO, N_("unable to write to %s"), pathbuf); close(fd); + + debug_return; } /* @@ -208,81 +253,99 @@ static size_t mkdir_iopath(const char *iolog_path, char *pathbuf, size_t pathsize) { size_t len; + bool is_temp = false; + debug_decl(mkdir_iopath, SUDO_DEBUG_UTIL) len = strlcpy(pathbuf, iolog_path, pathsize); if (len >= pathsize) { errno = ENAMETOOLONG; - log_error(USE_ERRNO, "%s", iolog_path); + log_fatal(USE_ERRNO, "%s", iolog_path); } /* * Create path and intermediate subdirs as needed. * If path ends in at least 6 Xs (ala POSIX mktemp), use mkdtemp(). */ - mkdir_parents(pathbuf); - if (len >= 6 && strcmp(&pathbuf[len - 6], "XXXXXX") == 0) { - if (mkdtemp(pathbuf) == NULL) - log_error(USE_ERRNO, _("unable to create %s"), pathbuf); - } else { - if (mkdir(pathbuf, S_IRWXU) != 0) - log_error(USE_ERRNO, _("unable to create %s"), pathbuf); - } + if (len >= 6 && strcmp(&pathbuf[len - 6], "XXXXXX") == 0) + is_temp = true; + io_mkdirs(pathbuf, S_IRWXU, is_temp); - return len; + debug_return_size_t(len); } /* * Append suffix to pathbuf after len chars and open the resulting file. * Note that the size of pathbuf is assumed to be PATH_MAX. - * Uses zlib if docompress is TRUE. - * Returns the open file handle which has the close-on-exec flag set. + * Uses zlib if docompress is true. + * Stores the open file handle which has the close-on-exec flag set. */ -static void * -open_io_fd(char *pathbuf, size_t len, const char *suffix, int docompress) +static void +open_io_fd(char *pathbuf, size_t len, struct io_log_file *iol, bool docompress) { - void *vfd = NULL; int fd; + debug_decl(open_io_fd, SUDO_DEBUG_UTIL) pathbuf[len] = '\0'; - strlcat(pathbuf, suffix, PATH_MAX); - fd = open(pathbuf, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR); - if (fd != -1) { - fcntl(fd, F_SETFD, FD_CLOEXEC); + strlcat(pathbuf, iol->suffix, PATH_MAX); + if (iol->enabled) { + fd = open(pathbuf, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR); + if (fd != -1) { + fcntl(fd, F_SETFD, FD_CLOEXEC); #ifdef HAVE_ZLIB_H - if (docompress) - vfd = gzdopen(fd, "w"); - else + if (docompress) + iol->fd.g = gzdopen(fd, "w"); + else #endif - vfd = fdopen(fd, "w"); + iol->fd.f = fdopen(fd, "w"); + } + if (fd == -1 || iol->fd.v == NULL) + log_fatal(USE_ERRNO, N_("unable to create %s"), pathbuf); + } else { + /* Remove old log file if we recycled sequence numbers. */ + unlink(pathbuf); } - return vfd; + debug_return; } /* * Pull out I/O log related data from user_info and command_info arrays. + * Returns true if I/O logging is enabled, else false. */ -static void +static bool 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; + const char *errstr; + char idbuf[MAX_UID_T_LEN + 2]; char * const *cur; - unsigned long ulval; + id_t id; uid_t runas_uid = 0; gid_t runas_gid = 0; + debug_decl(iolog_deserialize_info, SUDO_DEBUG_UTIL) - memset(details, 0, sizeof(*details)); + details->lines = 24; + details->cols = 80; for (cur = user_info; *cur != NULL; cur++) { switch (**cur) { case 'c': + if (strncmp(*cur, "cols=", sizeof("cols=") - 1) == 0) { + details->cols = atoi(*cur + sizeof("cols=") - 1); + continue; + } if (strncmp(*cur, "cwd=", sizeof("cwd=") - 1) == 0) { details->cwd = *cur + sizeof("cwd=") - 1; continue; } break; + case 'l': + if (strncmp(*cur, "lines=", sizeof("lines=") - 1) == 0) { + details->lines = atoi(*cur + sizeof("lines=") - 1); + continue; + } + break; case 't': if (strncmp(*cur, "tty=", sizeof("tty=") - 1) == 0) { details->tty = *cur + sizeof("tty=") - 1; @@ -312,36 +375,40 @@ iolog_deserialize_info(struct iolog_details *details, continue; } if (strncmp(*cur, "iolog_stdin=", sizeof("iolog_stdin=") - 1) == 0) { - if (atobool(*cur + sizeof("iolog_stdin=") - 1) == TRUE) - details->iolog_stdin = TRUE; + if (atobool(*cur + sizeof("iolog_stdin=") - 1) == true) + io_log_files[IOFD_STDIN].enabled = true; continue; } if (strncmp(*cur, "iolog_stdout=", sizeof("iolog_stdout=") - 1) == 0) { - if (atobool(*cur + sizeof("iolog_stdout=") - 1) == TRUE) - details->iolog_stdout = TRUE; + if (atobool(*cur + sizeof("iolog_stdout=") - 1) == true) + io_log_files[IOFD_STDOUT].enabled = true; continue; } if (strncmp(*cur, "iolog_stderr=", sizeof("iolog_stderr=") - 1) == 0) { - if (atobool(*cur + sizeof("iolog_stderr=") - 1) == TRUE) - details->iolog_stderr = TRUE; + if (atobool(*cur + sizeof("iolog_stderr=") - 1) == true) + io_log_files[IOFD_STDERR].enabled = true; continue; } if (strncmp(*cur, "iolog_ttyin=", sizeof("iolog_ttyin=") - 1) == 0) { - if (atobool(*cur + sizeof("iolog_ttyin=") - 1) == TRUE) - details->iolog_ttyin = TRUE; + if (atobool(*cur + sizeof("iolog_ttyin=") - 1) == true) + io_log_files[IOFD_TTYIN].enabled = true; continue; } if (strncmp(*cur, "iolog_ttyout=", sizeof("iolog_ttyout=") - 1) == 0) { - if (atobool(*cur + sizeof("iolog_ttyout=") - 1) == TRUE) - details->iolog_ttyout = TRUE; + if (atobool(*cur + sizeof("iolog_ttyout=") - 1) == true) + io_log_files[IOFD_TTYOUT].enabled = 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 */ + if (atobool(*cur + sizeof("iolog_compress=") - 1) == true) + iolog_compress = true; /* must be global */ continue; } break; + case 'm': + if (strncmp(*cur, "maxseq=", sizeof("maxseq=") - 1) == 0) + io_set_max_sessid(*cur + sizeof("maxseq=") - 1); + break; case 'r': if (strncmp(*cur, "runas_gid=", sizeof("runas_gid=") - 1) == 0) { runas_gid_str = *cur + sizeof("runas_gid=") - 1; @@ -369,66 +436,100 @@ iolog_deserialize_info(struct iolog_details *details, 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; - } + id = atoid(runas_uid_str, NULL, NULL, &errstr); + if (errstr != NULL) + warningx("runas uid %s: %s", runas_uid_str, _(errstr)); + else + runas_uid = (uid_t)id; } 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; - } + id = atoid(runas_gid_str, NULL, NULL, &errstr); + if (errstr != NULL) + warningx("runas gid %s: %s", runas_gid_str, _(errstr)); + else + runas_gid = (gid_t)id; } 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); + idbuf[0] = '#'; + strlcpy(&idbuf[1], runas_uid_str, sizeof(idbuf) - 1); + details->runas_pw = sudo_fakepwnam(idbuf, 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); + idbuf[0] = '#'; + strlcpy(&idbuf[1], runas_gid_str, sizeof(idbuf) - 1); + details->runas_gr = sudo_fakegrnam(idbuf); } } + debug_return_bool( + io_log_files[IOFD_STDIN].enabled || io_log_files[IOFD_STDOUT].enabled || + io_log_files[IOFD_STDERR].enabled || io_log_files[IOFD_TTYIN].enabled || + io_log_files[IOFD_TTYOUT].enabled); } +/* + * Write the "/log" file that contains the user and command info. + */ +void +write_info_log(char *pathbuf, size_t len, struct iolog_details *details, + char * const argv[], struct timeval *now) +{ + char * const *av; + FILE *fp; + int fd; + + pathbuf[len] = '\0'; + strlcat(pathbuf, "/log", PATH_MAX); + fd = open(pathbuf, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR); + if (fd == -1 || (fp = fdopen(fd, "w")) == NULL) + log_fatal(USE_ERRNO, N_("unable to create %s"), pathbuf); + + fprintf(fp, "%lld:%s:%s:%s:%s:%d:%d\n%s\n%s", (long long)now->tv_sec, + details->user ? details->user : "unknown", details->runas_pw->pw_name, + details->runas_gr ? details->runas_gr->gr_name : "", + details->tty ? details->tty : "unknown", details->lines, details->cols, + details->cwd ? details->cwd : "unknown", + details->command ? details->command : "unknown"); + for (av = argv + 1; *av != NULL; av++) { + fputc(' ', fp); + fputs(*av, fp); + } + fputc('\n', fp); + fclose(fp); +} + static int sudoers_io_open(unsigned int version, sudo_conv_t conversation, sudo_printf_t plugin_printf, char * const settings[], 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[], char * const args[]) { struct iolog_details details; char pathbuf[PATH_MAX], sessid[7]; char *tofree = NULL; char * const *cur; - FILE *io_logfile; + const char *debug_flags = NULL; size_t len; - int rval = -1; + int i, rval = -1; + debug_decl(sudoers_io_open, SUDO_DEBUG_PLUGIN) - if (!sudo_conv) - sudo_conv = conversation; - if (!sudo_printf) - sudo_printf = plugin_printf; + sudo_conv = conversation; + sudo_printf = plugin_printf; /* If we have no command (because -V was specified) just return. */ if (argc == 0) - return TRUE; + debug_return_bool(true); - if (sigsetjmp(error_jmp, 1)) { - /* called via error(), errorx() or log_error() */ + memset(&details, 0, sizeof(details)); + + if (fatal_setjmp() != 0) { + /* called via fatal(), fatalx() or log_fatal() */ rval = -1; goto done; } @@ -439,14 +540,20 @@ sudoers_io_open(unsigned int version, sudo_conv_t conv sudo_setgrent(); /* - * Pull iolog settings out of command_info, if any. + * Check for debug flags in settings list. */ - iolog_deserialize_info(&details, user_info, command_info); - /* Did policy module disable I/O logging? */ - if (!details.iolog_stdin && !details.iolog_ttyin && - !details.iolog_stdout && !details.iolog_stderr && - !details.iolog_ttyout) { - rval = FALSE; + for (cur = settings; *cur != NULL; cur++) { + if (strncmp(*cur, "debug_flags=", sizeof("debug_flags=") - 1) == 0) + debug_flags = *cur + sizeof("debug_flags=") - 1; + } + if (debug_flags != NULL) + sudo_debug_init(NULL, debug_flags); + + /* + * Pull iolog settings out of command_info. + */ + if (!iolog_deserialize_info(&details, user_info, command_info)) { + rval = false; goto done; } @@ -455,7 +562,7 @@ sudoers_io_open(unsigned int version, sudo_conv_t conv /* Get next session ID and convert it into a path. */ tofree = emalloc(sizeof(_PATH_SUDO_IO_LOGDIR) + sizeof(sessid) + 2); memcpy(tofree, _PATH_SUDO_IO_LOGDIR, sizeof(_PATH_SUDO_IO_LOGDIR)); - io_nextid(tofree, sessid); + io_nextid(tofree, NULL, sessid); snprintf(tofree + sizeof(_PATH_SUDO_IO_LOGDIR), sizeof(sessid) + 2, "%c%c/%c%c/%c%c", sessid[0], sessid[1], sessid[2], sessid[3], sessid[4], sessid[5]); @@ -470,123 +577,83 @@ sudoers_io_open(unsigned int version, sudo_conv_t conv if (len >= sizeof(pathbuf)) goto done; - /* - * We create 7 files: a log file, a timing file and 5 for input/output. - */ - io_logfile = open_io_fd(pathbuf, len, "/log", FALSE); - if (io_logfile == NULL) - log_error(USE_ERRNO, _("unable to create %s"), pathbuf); + /* Write log file with user and command details. */ + gettimeofday(&last_time, NULL); + write_info_log(pathbuf, len, &details, argv, &last_time); - io_fds[IOFD_TIMING].v = open_io_fd(pathbuf, len, "/timing", - iolog_compress); - if (io_fds[IOFD_TIMING].v == NULL) - log_error(USE_ERRNO, _("unable to create %s"), pathbuf); + /* Create the timing I/O log files. */ + for (i = 0; i < IOFD_MAX; i++) + open_io_fd(pathbuf, len, &io_log_files[i], iolog_compress); - if (details.iolog_ttyin) { - io_fds[IOFD_TTYIN].v = open_io_fd(pathbuf, len, "/ttyin", - iolog_compress); - if (io_fds[IOFD_TTYIN].v == NULL) - log_error(USE_ERRNO, _("unable to create %s"), pathbuf); - } else { - sudoers_io.log_ttyin = NULL; - } - if (details.iolog_stdin) { - io_fds[IOFD_STDIN].v = open_io_fd(pathbuf, len, "/stdin", - iolog_compress); - if (io_fds[IOFD_STDIN].v == NULL) - log_error(USE_ERRNO, _("unable to create %s"), pathbuf); - } else { + /* + * Clear I/O log function pointers for disabled log functions. + */ + if (!io_log_files[IOFD_STDIN].enabled) sudoers_io.log_stdin = NULL; - } - if (details.iolog_ttyout) { - io_fds[IOFD_TTYOUT].v = open_io_fd(pathbuf, len, "/ttyout", - iolog_compress); - if (io_fds[IOFD_TTYOUT].v == NULL) - log_error(USE_ERRNO, _("unable to create %s"), pathbuf); - } else { - sudoers_io.log_ttyout = NULL; - } - if (details.iolog_stdout) { - io_fds[IOFD_STDOUT].v = open_io_fd(pathbuf, len, "/stdout", - iolog_compress); - if (io_fds[IOFD_STDOUT].v == NULL) - log_error(USE_ERRNO, _("unable to create %s"), pathbuf); - } else { + if (!io_log_files[IOFD_STDOUT].enabled) sudoers_io.log_stdout = NULL; - } - if (details.iolog_stderr) { - io_fds[IOFD_STDERR].v = open_io_fd(pathbuf, len, "/stderr", - iolog_compress); - if (io_fds[IOFD_STDERR].v == NULL) - log_error(USE_ERRNO, _("unable to create %s"), pathbuf); - } else { + if (!io_log_files[IOFD_STDERR].enabled) sudoers_io.log_stderr = NULL; - } + if (!io_log_files[IOFD_TTYIN].enabled) + sudoers_io.log_ttyin = NULL; + if (!io_log_files[IOFD_TTYOUT].enabled) + sudoers_io.log_ttyout = NULL; - gettimeofday(&last_time, NULL); + rval = true; - fprintf(io_logfile, "%ld:%s:%s:%s:%s\n", (long)last_time.tv_sec, - details.user ? details.user : "unknown", details.runas_pw->pw_name, - details.runas_gr ? details.runas_gr->gr_name : "", - details.tty ? details.tty : "unknown"); - fputs(details.cwd ? details.cwd : "unknown", io_logfile); - fputc('\n', io_logfile); - fputs(details.command ? details.command : "unknown", io_logfile); - for (cur = &argv[1]; *cur != NULL; cur++) { - fputc(' ', io_logfile); - fputs(*cur, io_logfile); - } - fputc('\n', io_logfile); - fclose(io_logfile); - - rval = TRUE; - done: + fatal_disable_setjmp(); efree(tofree); if (details.runas_pw) - pw_delref(details.runas_pw); + sudo_pw_delref(details.runas_pw); sudo_endpwent(); if (details.runas_gr) - gr_delref(details.runas_gr); + sudo_gr_delref(details.runas_gr); sudo_endgrent(); - return rval; + debug_return_bool(rval); } static void sudoers_io_close(int exit_status, int error) { int i; + debug_decl(sudoers_io_close, SUDO_DEBUG_PLUGIN) - if (sigsetjmp(error_jmp, 1)) { - /* called via error(), errorx() or log_error() */ - return; + if (fatal_setjmp() != 0) { + /* called via fatal(), fatalx() or log_fatal() */ + fatal_disable_setjmp(); + debug_return; } for (i = 0; i < IOFD_MAX; i++) { - if (io_fds[i].v == NULL) + if (io_log_files[i].fd.v == NULL) continue; #ifdef HAVE_ZLIB_H if (iolog_compress) - gzclose(io_fds[i].g); + gzclose(io_log_files[i].fd.g); else #endif - fclose(io_fds[i].f); + fclose(io_log_files[i].fd.f); } + debug_return; } static int sudoers_io_version(int verbose) { - if (sigsetjmp(error_jmp, 1)) { - /* called via error(), errorx() or log_error() */ - return -1; + debug_decl(sudoers_io_version, SUDO_DEBUG_PLUGIN) + + if (fatal_setjmp() != 0) { + /* called via fatal(), fatalx() or log_fatal() */ + fatal_disable_setjmp(); + debug_return_bool(-1); } sudo_printf(SUDO_CONV_INFO_MSG, "Sudoers I/O plugin version %s\n", PACKAGE_VERSION); - return TRUE; + debug_return_bool(true); } /* @@ -596,35 +663,37 @@ static int sudoers_io_log(const char *buf, unsigned int len, int idx) { struct timeval now, delay; + debug_decl(sudoers_io_version, SUDO_DEBUG_PLUGIN) gettimeofday(&now, NULL); - if (sigsetjmp(error_jmp, 1)) { - /* called via error(), errorx() or log_error() */ - return -1; + if (fatal_setjmp() != 0) { + /* called via fatal(), fatalx() or log_fatal() */ + fatal_disable_setjmp(); + debug_return_bool(-1); } #ifdef HAVE_ZLIB_H if (iolog_compress) - gzwrite(io_fds[idx].g, buf, len); + ignore_result(gzwrite(io_log_files[idx].fd.g, (const voidp)buf, len)); else #endif - fwrite(buf, 1, len, io_fds[idx].f); + ignore_result(fwrite(buf, 1, len, io_log_files[idx].fd.f)); delay.tv_sec = now.tv_sec; delay.tv_usec = now.tv_usec; timevalsub(&delay, &last_time); #ifdef HAVE_ZLIB_H if (iolog_compress) - gzprintf(io_fds[IOFD_TIMING].g, "%d %f %d\n", idx, + gzprintf(io_log_files[IOFD_TIMING].fd.g, "%d %f %d\n", idx, delay.tv_sec + ((double)delay.tv_usec / 1000000), len); else #endif - fprintf(io_fds[IOFD_TIMING].f, "%d %f %d\n", idx, + fprintf(io_log_files[IOFD_TIMING].fd.f, "%d %f %d\n", idx, delay.tv_sec + ((double)delay.tv_usec / 1000000), len); last_time.tv_sec = now.tv_sec; last_time.tv_usec = now.tv_usec; - return TRUE; + debug_return_bool(true); } static int @@ -657,7 +726,7 @@ sudoers_io_log_stderr(const char *buf, unsigned int le return sudoers_io_log(buf, len, IOFD_STDERR); } -struct io_plugin sudoers_io = { +__dso_public struct io_plugin sudoers_io = { SUDO_IO_PLUGIN, SUDO_API_VERSION, sudoers_io_open,