Diff for /embedaddon/sudo/plugins/sudoers/iolog.c between versions 1.1.1.3 and 1.1.1.5

version 1.1.1.3, 2012/10/09 09:29:52 version 1.1.1.5, 2013/10/14 07:56:34
Line 1 Line 1
 /*  /*
 * Copyright (c) 2009-2011 Todd C. Miller <Todd.Miller@courtesan.com> * Copyright (c) 2009-2013 Todd C. Miller <Todd.Miller@courtesan.com>
  *   *
  * Permission to use, copy, modify, and distribute this software for any   * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above   * purpose with or without fee is hereby granted, provided that the above
Line 17 Line 17
 #include <config.h>  #include <config.h>
   
 #include <sys/types.h>  #include <sys/types.h>
 #include <sys/param.h>  
 #include <sys/stat.h>  #include <sys/stat.h>
 #include <sys/time.h>  #include <sys/time.h>
 #include <stdio.h>  #include <stdio.h>
Line 44 Line 43
 #include <errno.h>  #include <errno.h>
 #include <fcntl.h>  #include <fcntl.h>
 #include <signal.h>  #include <signal.h>
 #include <setjmp.h>  
 #include <pwd.h>  #include <pwd.h>
 #include <grp.h>  #include <grp.h>
 #ifdef HAVE_ZLIB_H  #ifdef HAVE_ZLIB_H
Line 52 Line 50
 #endif  #endif
   
 #include "sudoers.h"  #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 {  struct script_buf {
     int len; /* buffer length (how much read in) */      int len; /* buffer length (how much read in) */
     int off; /* write position (how much already consumed) */      int off; /* write position (how much already consumed) */
Line 82  struct iolog_details { Line 70  struct iolog_details {
     const char *iolog_path;      const char *iolog_path;
     struct passwd *runas_pw;      struct passwd *runas_pw;
     struct group *runas_gr;      struct group *runas_gr;
    int iolog_stdin;    int lines;
    int iolog_stdout;    int cols;
    int iolog_stderr; 
    int iolog_ttyin; 
    int iolog_ttyout; 
 };  };
   
 #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 int iolog_compress;
 static struct timeval last_time;  static struct timeval last_time;
static union io_fd io_fds[IOFD_MAX];static unsigned int sessid_max = SESSID_MAX;
extern struct io_plugin sudoers_io; 
   
   /* 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  static void
mkdir_parents(char *path)io_mkdirs(char *path, mode_t mode, bool is_temp)
 {  {
     struct stat sb;      struct stat sb;
       gid_t parent_gid = 0;
     char *slash = path;      char *slash = path;
    debug_decl(mkdir_parents, SUDO_DEBUG_UTIL)    debug_decl(io_mkdirs, SUDO_DEBUG_UTIL)
   
    for (;;) {    /* Fast path: not a temporary and already exists. */
        if ((slash = strchr(slash + 1, '/')) == NULL)    if (!is_temp && stat(path, &sb) == 0) {
            break;        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';          *slash = '\0';
         if (stat(path, &sb) != 0) {          if (stat(path, &sb) != 0) {
            if (mkdir(path, S_IRWXU) != 0)            if (mkdir(path, mode) != 0)
                log_fatal(USE_ERRNO, _("unable to mkdir %s"), path);                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)) {          } else if (!S_ISDIR(sb.st_mode)) {
            log_fatal(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 = '/';          *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;      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   * Read the on-disk sequence number, set sessid to the next
  * number, and update the on-disk copy.   * number, and update the on-disk copy.
  * Uses file locking to avoid sequence number collisions.   * Uses file locking to avoid sequence number collisions.
Line 150  io_nextid(char *iolog_dir, char *iolog_dir_fallback, c Line 170  io_nextid(char *iolog_dir, char *iolog_dir_fallback, c
     /*      /*
      * Create I/O log directory if it doesn't already exist.       * Create I/O log directory if it doesn't already exist.
      */       */
    mkdir_parents(iolog_dir);    io_mkdirs(iolog_dir, S_IRWXU, false);
    if (stat(iolog_dir, &sb) != 0) { 
        if (mkdir(iolog_dir, S_IRWXU) != 0) 
            log_fatal(USE_ERRNO, _("unable to mkdir %s"), iolog_dir); 
    } else if (!S_ISDIR(sb.st_mode)) { 
        log_fatal(0, _("%s exists but is not a directory (0%o)"), 
            iolog_dir, (unsigned int) sb.st_mode); 
    } 
   
     /*      /*
      * Open sequence file       * Open sequence file
Line 169  io_nextid(char *iolog_dir, char *iolog_dir_fallback, c Line 182  io_nextid(char *iolog_dir, char *iolog_dir_fallback, c
     }      }
     fd = open(pathbuf, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);      fd = open(pathbuf, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
     if (fd == -1)      if (fd == -1)
        log_fatal(USE_ERRNO, _("unable to open %s"), pathbuf);        log_fatal(USE_ERRNO, N_("unable to open %s"), pathbuf);
     lock_file(fd, SUDO_LOCK);      lock_file(fd, SUDO_LOCK);
   
     /*      /*
Line 189  io_nextid(char *iolog_dir, char *iolog_dir_fallback, c Line 202  io_nextid(char *iolog_dir, char *iolog_dir_fallback, c
                 nread = read(fd2, buf, sizeof(buf));                  nread = read(fd2, buf, sizeof(buf));
                 if (nread > 0) {                  if (nread > 0) {
                     id = strtoul(buf, &ep, 36);                      id = strtoul(buf, &ep, 36);
                    if (buf == ep || id >= SESSID_MAX)                    if (buf == ep || id >= sessid_max)
                         id = 0;                          id = 0;
                 }                  }
                 close(fd2);                  close(fd2);
Line 202  io_nextid(char *iolog_dir, char *iolog_dir_fallback, c Line 215  io_nextid(char *iolog_dir, char *iolog_dir_fallback, c
         nread = read(fd, buf, sizeof(buf));          nread = read(fd, buf, sizeof(buf));
         if (nread != 0) {          if (nread != 0) {
             if (nread == -1)              if (nread == -1)
                log_fatal(USE_ERRNO, _("unable to read %s"), pathbuf);                log_fatal(USE_ERRNO, N_("unable to read %s"), pathbuf);
             id = strtoul(buf, &ep, 36);              id = strtoul(buf, &ep, 36);
            if (buf == ep || id >= SESSID_MAX)            if (buf == ep || id >= sessid_max)
                log_fatal(0, _("invalid sequence number %s"), pathbuf);                id = 0;
         }          }
     }      }
     id++;      id++;
Line 226  io_nextid(char *iolog_dir, char *iolog_dir_fallback, c Line 239  io_nextid(char *iolog_dir, char *iolog_dir_fallback, c
   
     /* Rewind and overwrite old seq file. */      /* Rewind and overwrite old seq file. */
     if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1 || write(fd, buf, 7) != 7)      if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1 || write(fd, buf, 7) != 7)
        log_fatal(USE_ERRNO, _("unable to write to %s"), pathbuf);        log_fatal(USE_ERRNO, N_("unable to write to %s"), pathbuf);
     close(fd);      close(fd);
   
     debug_return;      debug_return;
Line 240  static size_t Line 253  static size_t
 mkdir_iopath(const char *iolog_path, char *pathbuf, size_t pathsize)  mkdir_iopath(const char *iolog_path, char *pathbuf, size_t pathsize)
 {  {
     size_t len;      size_t len;
       bool is_temp = false;
     debug_decl(mkdir_iopath, SUDO_DEBUG_UTIL)      debug_decl(mkdir_iopath, SUDO_DEBUG_UTIL)
   
     len = strlcpy(pathbuf, iolog_path, pathsize);      len = strlcpy(pathbuf, iolog_path, pathsize);
Line 252  mkdir_iopath(const char *iolog_path, char *pathbuf, si Line 266  mkdir_iopath(const char *iolog_path, char *pathbuf, si
      * 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().
      */       */
    mkdir_parents(pathbuf);    if (len >= 6 && strcmp(&pathbuf[len - 6], "XXXXXX") == 0)
    if (len >= 6 && strcmp(&pathbuf[len - 6], "XXXXXX") == 0) {        is_temp = true;
        if (mkdtemp(pathbuf) == NULL)    io_mkdirs(pathbuf, S_IRWXU, is_temp);
            log_fatal(USE_ERRNO, _("unable to create %s"), pathbuf); 
    } else { 
        if (mkdir(pathbuf, S_IRWXU) != 0) 
            log_fatal(USE_ERRNO, _("unable to create %s"), pathbuf); 
    } 
   
     debug_return_size_t(len);      debug_return_size_t(len);
 }  }
Line 268  mkdir_iopath(const char *iolog_path, char *pathbuf, si Line 277  mkdir_iopath(const char *iolog_path, char *pathbuf, si
  * Append suffix to pathbuf after len chars and open the resulting file.   * Append suffix to pathbuf after len chars and open the resulting file.
  * Note that the size of pathbuf is assumed to be PATH_MAX.   * Note that the size of pathbuf is assumed to be PATH_MAX.
  * Uses zlib if docompress is true.   * Uses zlib if docompress is true.
 * Returns the open file handle which has the close-on-exec flag set. * Stores the open file handle which has the close-on-exec flag set.
  */   */
static void *static void
open_io_fd(char *pathbuf, size_t len, const char *suffix, bool docompress)open_io_fd(char *pathbuf, size_t len, struct io_log_file *iol, bool docompress)
 {  {
     void *vfd = NULL;  
     int fd;      int fd;
     debug_decl(open_io_fd, SUDO_DEBUG_UTIL)      debug_decl(open_io_fd, SUDO_DEBUG_UTIL)
   
     pathbuf[len] = '\0';      pathbuf[len] = '\0';
    strlcat(pathbuf, suffix, PATH_MAX);    strlcat(pathbuf, iol->suffix, PATH_MAX);
    fd = open(pathbuf, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR);    if (iol->enabled) {
    if (fd != -1) {        fd = open(pathbuf, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR);
        fcntl(fd, F_SETFD, FD_CLOEXEC);        if (fd != -1) {
             fcntl(fd, F_SETFD, FD_CLOEXEC);
 #ifdef HAVE_ZLIB_H  #ifdef HAVE_ZLIB_H
        if (docompress)            if (docompress)
            vfd = gzdopen(fd, "w");                iol->fd.g = gzdopen(fd, "w");
        else            else
 #endif  #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);
     }      }
    debug_return_ptr(vfd);    debug_return;
 }  }
   
 /*  /*
  * Pull out I/O log related data from user_info and command_info arrays.   * 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 voidstatic bool
 iolog_deserialize_info(struct iolog_details *details, char * const user_info[],  iolog_deserialize_info(struct iolog_details *details, char * const user_info[],
     char * const command_info[])      char * const command_info[])
 {  {
     const char *runas_uid_str = "0", *runas_euid_str = NULL;      const char *runas_uid_str = "0", *runas_euid_str = NULL;
     const char *runas_gid_str = "0", *runas_egid_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;      char * const *cur;
    unsigned long ulval;    id_t id;
     uid_t runas_uid = 0;      uid_t runas_uid = 0;
     gid_t runas_gid = 0;      gid_t runas_gid = 0;
     debug_decl(iolog_deserialize_info, SUDO_DEBUG_UTIL)      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++) {      for (cur = user_info; *cur != NULL; cur++) {
         switch (**cur) {          switch (**cur) {
         case 'c':          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) {              if (strncmp(*cur, "cwd=", sizeof("cwd=") - 1) == 0) {
                 details->cwd = *cur + sizeof("cwd=") - 1;                  details->cwd = *cur + sizeof("cwd=") - 1;
                 continue;                  continue;
             }              }
             break;              break;
           case 'l':
               if (strncmp(*cur, "lines=", sizeof("lines=") - 1) == 0) {
                   details->lines = atoi(*cur + sizeof("lines=") - 1);
                   continue;
               }
               break;
         case 't':          case 't':
             if (strncmp(*cur, "tty=", sizeof("tty=") - 1) == 0) {              if (strncmp(*cur, "tty=", sizeof("tty=") - 1) == 0) {
                 details->tty = *cur + sizeof("tty=") - 1;                  details->tty = *cur + sizeof("tty=") - 1;
Line 348  iolog_deserialize_info(struct iolog_details *details,  Line 376  iolog_deserialize_info(struct iolog_details *details, 
             }              }
             if (strncmp(*cur, "iolog_stdin=", sizeof("iolog_stdin=") - 1) == 0) {              if (strncmp(*cur, "iolog_stdin=", sizeof("iolog_stdin=") - 1) == 0) {
                 if (atobool(*cur + sizeof("iolog_stdin=") - 1) == true)                  if (atobool(*cur + sizeof("iolog_stdin=") - 1) == true)
                    details->iolog_stdin = true;                    io_log_files[IOFD_STDIN].enabled = true;
                 continue;                  continue;
             }              }
             if (strncmp(*cur, "iolog_stdout=", sizeof("iolog_stdout=") - 1) == 0) {              if (strncmp(*cur, "iolog_stdout=", sizeof("iolog_stdout=") - 1) == 0) {
                 if (atobool(*cur + sizeof("iolog_stdout=") - 1) == true)                  if (atobool(*cur + sizeof("iolog_stdout=") - 1) == true)
                    details->iolog_stdout = true;                    io_log_files[IOFD_STDOUT].enabled = true;
                 continue;                  continue;
             }              }
             if (strncmp(*cur, "iolog_stderr=", sizeof("iolog_stderr=") - 1) == 0) {              if (strncmp(*cur, "iolog_stderr=", sizeof("iolog_stderr=") - 1) == 0) {
                 if (atobool(*cur + sizeof("iolog_stderr=") - 1) == true)                  if (atobool(*cur + sizeof("iolog_stderr=") - 1) == true)
                    details->iolog_stderr = true;                    io_log_files[IOFD_STDERR].enabled = true;
                 continue;                  continue;
             }              }
             if (strncmp(*cur, "iolog_ttyin=", sizeof("iolog_ttyin=") - 1) == 0) {              if (strncmp(*cur, "iolog_ttyin=", sizeof("iolog_ttyin=") - 1) == 0) {
                 if (atobool(*cur + sizeof("iolog_ttyin=") - 1) == true)                  if (atobool(*cur + sizeof("iolog_ttyin=") - 1) == true)
                    details->iolog_ttyin = true;                    io_log_files[IOFD_TTYIN].enabled = true;
                 continue;                  continue;
             }              }
             if (strncmp(*cur, "iolog_ttyout=", sizeof("iolog_ttyout=") - 1) == 0) {              if (strncmp(*cur, "iolog_ttyout=", sizeof("iolog_ttyout=") - 1) == 0) {
                 if (atobool(*cur + sizeof("iolog_ttyout=") - 1) == true)                  if (atobool(*cur + sizeof("iolog_ttyout=") - 1) == true)
                    details->iolog_ttyout = true;                    io_log_files[IOFD_TTYOUT].enabled = true;
                 continue;                  continue;
             }              }
             if (strncmp(*cur, "iolog_compress=", sizeof("iolog_compress=") - 1) == 0) {              if (strncmp(*cur, "iolog_compress=", sizeof("iolog_compress=") - 1) == 0) {
Line 377  iolog_deserialize_info(struct iolog_details *details,  Line 405  iolog_deserialize_info(struct iolog_details *details, 
                 continue;                  continue;
             }              }
             break;              break;
           case 'm':
               if (strncmp(*cur, "maxseq=", sizeof("maxseq=") - 1) == 0)
                   io_set_max_sessid(*cur + sizeof("maxseq=") - 1);
               break;
         case 'r':          case 'r':
             if (strncmp(*cur, "runas_gid=", sizeof("runas_gid=") - 1) == 0) {              if (strncmp(*cur, "runas_gid=", sizeof("runas_gid=") - 1) == 0) {
                 runas_gid_str = *cur + sizeof("runas_gid=") - 1;                  runas_gid_str = *cur + sizeof("runas_gid=") - 1;
Line 404  iolog_deserialize_info(struct iolog_details *details,  Line 436  iolog_deserialize_info(struct iolog_details *details, 
     if (runas_euid_str != NULL)      if (runas_euid_str != NULL)
         runas_uid_str = runas_euid_str;          runas_uid_str = runas_euid_str;
     if (runas_uid_str != NULL) {      if (runas_uid_str != NULL) {
        errno = 0;        id = atoid(runas_uid_str, NULL, NULL, &errstr);
        ulval = strtoul(runas_uid_str, &ep, 0);        if (errstr != NULL)
        if (*runas_uid_str != '\0' && *ep == '\0' &&            warningx("runas uid %s: %s", runas_uid_str, _(errstr));
            (errno != ERANGE || ulval != ULONG_MAX)) {        else
            runas_uid = (uid_t)ulval;            runas_uid = (uid_t)id;
        } 
     }      }
     if (runas_egid_str != NULL)      if (runas_egid_str != NULL)
         runas_gid_str = runas_egid_str;          runas_gid_str = runas_egid_str;
     if (runas_gid_str != NULL) {      if (runas_gid_str != NULL) {
        errno = 0;        id = atoid(runas_gid_str, NULL, NULL, &errstr);
        ulval = strtoul(runas_gid_str, &ep, 0);        if (errstr != NULL)
        if (*runas_gid_str != '\0' && *ep == '\0' &&            warningx("runas gid %s: %s", runas_gid_str, _(errstr));
            (errno != ERANGE || ulval != ULONG_MAX)) {        else
            runas_gid = (gid_t)ulval;            runas_gid = (gid_t)id;
        } 
     }      }
   
     details->runas_pw = sudo_getpwuid(runas_uid);      details->runas_pw = sudo_getpwuid(runas_uid);
     if (details->runas_pw == NULL) {      if (details->runas_pw == NULL) {
        id[0] = '#';        idbuf[0] = '#';
        strlcpy(&id[1], runas_uid_str, sizeof(id) - 1);        strlcpy(&idbuf[1], runas_uid_str, sizeof(idbuf) - 1);
        details->runas_pw = sudo_fakepwnam(id, runas_gid);        details->runas_pw = sudo_fakepwnam(idbuf, runas_gid);
     }      }
   
     if (runas_gid != details->runas_pw->pw_gid) {      if (runas_gid != details->runas_pw->pw_gid) {
         details->runas_gr = sudo_getgrgid(runas_gid);          details->runas_gr = sudo_getgrgid(runas_gid);
         if (details->runas_gr == NULL) {          if (details->runas_gr == NULL) {
            id[0] = '#';            idbuf[0] = '#';
            strlcpy(&id[1], runas_gid_str, sizeof(id) - 1);            strlcpy(&idbuf[1], runas_gid_str, sizeof(idbuf) - 1);
            details->runas_gr = sudo_fakegrnam(id);            details->runas_gr = sudo_fakegrnam(idbuf);
         }          }
     }      }
    debug_return;    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  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[],
Line 451  sudoers_io_open(unsigned int version, sudo_conv_t conv Line 515  sudoers_io_open(unsigned int version, sudo_conv_t conv
     char *tofree = NULL;      char *tofree = NULL;
     char * const *cur;      char * const *cur;
     const char *debug_flags = NULL;      const char *debug_flags = NULL;
     FILE *io_logfile;  
     size_t len;      size_t len;
    int rval = -1;    int i, rval = -1;
     debug_decl(sudoers_io_open, SUDO_DEBUG_PLUGIN)      debug_decl(sudoers_io_open, SUDO_DEBUG_PLUGIN)
   
    if (!sudo_conv)    sudo_conv = conversation;
        sudo_conv = conversation;    sudo_printf = plugin_printf;
    if (!sudo_printf) 
        sudo_printf = plugin_printf; 
   
     /* If we have no command (because -V was specified) just return. */      /* If we have no command (because -V was specified) just return. */
     if (argc == 0)      if (argc == 0)
         debug_return_bool(true);          debug_return_bool(true);
   
    if (sigsetjmp(error_jmp, 1)) {    memset(&details, 0, sizeof(details));
        /* called via error(), errorx() or log_fatal() */
     if (fatal_setjmp() != 0) {
         /* called via fatal(), fatalx() or log_fatal() */
         rval = -1;          rval = -1;
         goto done;          goto done;
     }      }
Line 487  sudoers_io_open(unsigned int version, sudo_conv_t conv Line 550  sudoers_io_open(unsigned int version, sudo_conv_t conv
         sudo_debug_init(NULL, debug_flags);          sudo_debug_init(NULL, debug_flags);
   
     /*      /*
     * Pull iolog settings out of command_info, if any.     * Pull iolog settings out of command_info.
      */       */
    iolog_deserialize_info(&details, user_info, command_info);    if (!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;          rval = false;
         goto done;          goto done;
     }      }
Line 518  sudoers_io_open(unsigned int version, sudo_conv_t conv Line 577  sudoers_io_open(unsigned int version, sudo_conv_t conv
     if (len >= sizeof(pathbuf))      if (len >= sizeof(pathbuf))
         goto done;          goto done;
   
    /*    /* Write log file with user and command details. */
     * We create 7 files: a log file, a timing file and 5 for input/output.    gettimeofday(&last_time, NULL);
     */    write_info_log(pathbuf, len, &details, argv, &last_time);
    io_logfile = open_io_fd(pathbuf, len, "/log", false); 
    if (io_logfile == NULL) 
        log_fatal(USE_ERRNO, _("unable to create %s"), pathbuf); 
   
    io_fds[IOFD_TIMING].v = open_io_fd(pathbuf, len, "/timing",    /* Create the timing I/O log files. */
        iolog_compress);    for (i = 0; i < IOFD_MAX; i++)
    if (io_fds[IOFD_TIMING].v == NULL)        open_io_fd(pathbuf, len, &io_log_files[i], iolog_compress);
        log_fatal(USE_ERRNO, _("unable to create %s"), pathbuf); 
   
    if (details.iolog_ttyin) {    /*
        io_fds[IOFD_TTYIN].v = open_io_fd(pathbuf, len, "/ttyin",     * Clear I/O log function pointers for disabled log functions.
            iolog_compress);     */
        if (io_fds[IOFD_TTYIN].v == NULL)    if (!io_log_files[IOFD_STDIN].enabled)
            log_fatal(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_fatal(USE_ERRNO, _("unable to create %s"), pathbuf); 
    } else { 
         sudoers_io.log_stdin = NULL;          sudoers_io.log_stdin = NULL;
    }    if (!io_log_files[IOFD_STDOUT].enabled)
    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_fatal(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_fatal(USE_ERRNO, _("unable to create %s"), pathbuf); 
    } else { 
         sudoers_io.log_stdout = NULL;          sudoers_io.log_stdout = NULL;
    }    if (!io_log_files[IOFD_STDERR].enabled)
    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_fatal(USE_ERRNO, _("unable to create %s"), pathbuf); 
    } else { 
         sudoers_io.log_stderr = NULL;          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);  
   
     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;      rval = true;
   
 done:  done:
       fatal_disable_setjmp();
     efree(tofree);      efree(tofree);
     if (details.runas_pw)      if (details.runas_pw)
         sudo_pw_delref(details.runas_pw);          sudo_pw_delref(details.runas_pw);
Line 607  sudoers_io_close(int exit_status, int error) Line 620  sudoers_io_close(int exit_status, int error)
     int i;      int i;
     debug_decl(sudoers_io_close, SUDO_DEBUG_PLUGIN)      debug_decl(sudoers_io_close, SUDO_DEBUG_PLUGIN)
   
    if (sigsetjmp(error_jmp, 1)) {    if (fatal_setjmp() != 0) {
        /* called via error(), errorx() or log_fatal() */        /* called via fatal(), fatalx() or log_fatal() */
         fatal_disable_setjmp();
         debug_return;          debug_return;
     }      }
   
     for (i = 0; i < IOFD_MAX; i++) {      for (i = 0; i < IOFD_MAX; i++) {
        if (io_fds[i].v == NULL)        if (io_log_files[i].fd.v == NULL)
             continue;              continue;
 #ifdef HAVE_ZLIB_H  #ifdef HAVE_ZLIB_H
         if (iolog_compress)          if (iolog_compress)
            gzclose(io_fds[i].g);            gzclose(io_log_files[i].fd.g);
         else          else
 #endif  #endif
            fclose(io_fds[i].f);            fclose(io_log_files[i].fd.f);
     }      }
     debug_return;      debug_return;
 }  }
Line 630  sudoers_io_version(int verbose) Line 644  sudoers_io_version(int verbose)
 {  {
     debug_decl(sudoers_io_version, SUDO_DEBUG_PLUGIN)      debug_decl(sudoers_io_version, SUDO_DEBUG_PLUGIN)
   
    if (sigsetjmp(error_jmp, 1)) {    if (fatal_setjmp() != 0) {
        /* called via error(), errorx() or log_fatal() */        /* called via fatal(), fatalx() or log_fatal() */
         fatal_disable_setjmp();
         debug_return_bool(-1);          debug_return_bool(-1);
     }      }
   
Line 652  sudoers_io_log(const char *buf, unsigned int len, int  Line 667  sudoers_io_log(const char *buf, unsigned int len, int 
   
     gettimeofday(&now, NULL);      gettimeofday(&now, NULL);
   
    if (sigsetjmp(error_jmp, 1)) {    if (fatal_setjmp() != 0) {
        /* called via error(), errorx() or log_fatal() */        /* called via fatal(), fatalx() or log_fatal() */
         fatal_disable_setjmp();
         debug_return_bool(-1);          debug_return_bool(-1);
     }      }
   
 #ifdef HAVE_ZLIB_H  #ifdef HAVE_ZLIB_H
     if (iolog_compress)      if (iolog_compress)
        ignore_result(gzwrite(io_fds[idx].g, (const voidp)buf, len));        ignore_result(gzwrite(io_log_files[idx].fd.g, (const voidp)buf, len));
     else      else
 #endif  #endif
        ignore_result(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_sec = now.tv_sec;
     delay.tv_usec = now.tv_usec;      delay.tv_usec = now.tv_usec;
     timevalsub(&delay, &last_time);      timevalsub(&delay, &last_time);
 #ifdef HAVE_ZLIB_H  #ifdef HAVE_ZLIB_H
     if (iolog_compress)      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);              delay.tv_sec + ((double)delay.tv_usec / 1000000), len);
     else      else
 #endif  #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);              delay.tv_sec + ((double)delay.tv_usec / 1000000), len);
     last_time.tv_sec = now.tv_sec;      last_time.tv_sec = now.tv_sec;
     last_time.tv_usec = now.tv_usec;      last_time.tv_usec = now.tv_usec;

Removed from v.1.1.1.3  
changed lines
  Added in v.1.1.1.5


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>