Diff for /embedaddon/sudo/plugins/sudoers/iolog.c between versions 1.1.1.4 and 1.1.1.6

version 1.1.1.4, 2013/07/22 10:46:12 version 1.1.1.6, 2014/06/15 16:12:54
Line 1 Line 1
 /*  /*
 * Copyright (c) 2009-2013 Todd C. Miller <Todd.Miller@courtesan.com> * Copyright (c) 2009-2014 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 37 Line 37
 #ifdef HAVE_UNISTD_H  #ifdef HAVE_UNISTD_H
 # include <unistd.h>  # include <unistd.h>
 #endif /* HAVE_UNISTD_H */  #endif /* HAVE_UNISTD_H */
#if TIME_WITH_SYS_TIME#ifdef TIME_WITH_SYS_TIME
 # include <time.h>  # include <time.h>
 #endif  #endif
 #include <errno.h>  #include <errno.h>
Line 50 Line 50
 #endif  #endif
   
 #include "sudoers.h"  #include "sudoers.h"
   #include "iolog.h"
   
 struct script_buf {  struct script_buf {
     int len; /* buffer length (how much read in) */      int len; /* buffer length (how much read in) */
Line 73  struct iolog_details { Line 74  struct iolog_details {
     int cols;      int cols;
 };  };
   
 union io_fd {  
     FILE *f;  
 #ifdef HAVE_ZLIB_H  
     gzFile g;  
 #endif  
     void *v;  
 };  
   
 static struct io_log_file {  
     bool enabled;  
     const char *suffix;  
     union io_fd fd;  
 } io_log_files[] = {  
 #define IOFD_LOG        0  
     { true,  "/log" },  
 #define IOFD_TIMING     1  
     { true,  "/timing" },  
 #define IOFD_STDIN      2  
     { false, "/stdin" },  
 #define IOFD_STDOUT     3  
     { false, "/stdout" },  
 #define IOFD_STDERR     4  
     { false, "/stderr" },  
 #define IOFD_TTYIN      5  
     { false, "/ttyin" },  
 #define IOFD_TTYOUT     6  
     { false, "/ttyout" },  
 #define IOFD_MAX        7  
     { false, NULL }  
 };  
   
 #define SESSID_MAX      2176782336U  
   
 static int iolog_compress;  static int iolog_compress;
 static struct timeval last_time;  static struct timeval last_time;
 static unsigned int sessid_max = SESSID_MAX;  static unsigned int sessid_max = SESSID_MAX;
Line 168  io_mkdirs(char *path, mode_t mode, bool is_temp) Line 136  io_mkdirs(char *path, mode_t mode, bool is_temp)
 int  int
 io_set_max_sessid(const char *maxval)  io_set_max_sessid(const char *maxval)
 {  {
    unsigned long ulval;    const char *errstr;
    char *ep;    unsigned int value;
     debug_decl(io_set_max_sessid, SUDO_DEBUG_UTIL)
   
    errno = 0;    value = strtonum(maxval, 0, SESSID_MAX, &errstr);
    ulval = strtoul(maxval, &ep, 0);    if (errstr != NULL) {
    if (*maxval != '\0' && *ep == '\0' &&        if (errno != ERANGE) {
        (errno != ERANGE || ulval != ULONG_MAX)) {            sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
        sessid_max = MIN((unsigned int)ulval, SESSID_MAX);                "bad maxseq: %s: %s", maxval, errstr);
        return true;            debug_return_bool(false);
         }
         /* Out of range, clamp to SESSID_MAX as documented. */
         value = SESSID_MAX;
     }      }
    return false;    sessid_max = value;
     debug_return_bool(true);
 }  }
   
 /*  /*
Line 208  io_nextid(char *iolog_dir, char *iolog_dir_fallback, c Line 181  io_nextid(char *iolog_dir, char *iolog_dir_fallback, c
      * Open sequence file       * Open sequence file
      */       */
     len = snprintf(pathbuf, sizeof(pathbuf), "%s/seq", iolog_dir);      len = snprintf(pathbuf, sizeof(pathbuf), "%s/seq", iolog_dir);
    if (len <= 0 || len >= sizeof(pathbuf)) {    if (len <= 0 || (size_t)len >= sizeof(pathbuf)) {
         errno = ENAMETOOLONG;          errno = ENAMETOOLONG;
         log_fatal(USE_ERRNO, "%s/seq", pathbuf);          log_fatal(USE_ERRNO, "%s/seq", pathbuf);
     }      }
Line 228  io_nextid(char *iolog_dir, char *iolog_dir_fallback, c Line 201  io_nextid(char *iolog_dir, char *iolog_dir_fallback, c
   
         len = snprintf(fallback, sizeof(fallback), "%s/seq",          len = snprintf(fallback, sizeof(fallback), "%s/seq",
             iolog_dir_fallback);              iolog_dir_fallback);
        if (len > 0 && len < sizeof(fallback)) {        if (len > 0 && (size_t)len < sizeof(fallback)) {
             int fd2 = open(fallback, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);              int fd2 = open(fallback, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
             if (fd2 != -1) {              if (fd2 != -1) {
                nread = read(fd2, buf, sizeof(buf));                nread = read(fd2, buf, sizeof(buf) - 1);
                 if (nread > 0) {                  if (nread > 0) {
                       if (buf[nread - 1] == '\n')
                           nread--;
                       buf[nread] = '\0';
                     id = strtoul(buf, &ep, 36);                      id = strtoul(buf, &ep, 36);
                    if (buf == ep || id >= sessid_max)                    if (ep == buf || *ep != '\0' || id >= sessid_max) {
                         sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
                             "%s: bad sequence number: %s", fallback, buf);
                         id = 0;                          id = 0;
                       }
                 }                  }
                 close(fd2);                  close(fd2);
             }              }
Line 244  io_nextid(char *iolog_dir, char *iolog_dir_fallback, c Line 223  io_nextid(char *iolog_dir, char *iolog_dir_fallback, c
   
     /* Read current seq number (base 36). */      /* Read current seq number (base 36). */
     if (id == 0) {      if (id == 0) {
        nread = read(fd, buf, sizeof(buf));        nread = read(fd, buf, sizeof(buf) - 1);
         if (nread != 0) {          if (nread != 0) {
             if (nread == -1)              if (nread == -1)
                 log_fatal(USE_ERRNO, N_("unable to read %s"), pathbuf);                  log_fatal(USE_ERRNO, N_("unable to read %s"), pathbuf);
               if (buf[nread - 1] == '\n')
                   nread--;
               buf[nread] = '\0';
             id = strtoul(buf, &ep, 36);              id = strtoul(buf, &ep, 36);
            if (buf == ep || id >= sessid_max)            if (ep == buf || *ep != '\0' || id >= sessid_max) {
                 sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
                     "%s: bad sequence number: %s", pathbuf, buf);
                 id = 0;                  id = 0;
               }
         }          }
     }      }
     id++;      id++;
Line 269  io_nextid(char *iolog_dir, char *iolog_dir_fallback, c Line 254  io_nextid(char *iolog_dir, char *iolog_dir_fallback, c
     memcpy(sessid, buf, 6);      memcpy(sessid, buf, 6);
     sessid[6] = '\0';      sessid[6] = '\0';
   
    /* Rewind and overwrite old seq file. */    /* Rewind and overwrite old seq file, including the NUL byte. */
     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, N_("unable to write to %s"), pathbuf);          log_fatal(USE_ERRNO, N_("unable to write to %s"), pathbuf);
     close(fd);      close(fd);
Line 320  open_io_fd(char *pathbuf, size_t len, struct io_log_fi Line 305  open_io_fd(char *pathbuf, size_t len, struct io_log_fi
     pathbuf[len] = '\0';      pathbuf[len] = '\0';
     strlcat(pathbuf, iol->suffix, PATH_MAX);      strlcat(pathbuf, iol->suffix, PATH_MAX);
     if (iol->enabled) {      if (iol->enabled) {
        fd = open(pathbuf, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR);        fd = open(pathbuf, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR);
         if (fd != -1) {          if (fd != -1) {
             fcntl(fd, F_SETFD, FD_CLOEXEC);              fcntl(fd, F_SETFD, FD_CLOEXEC);
 #ifdef HAVE_ZLIB_H  #ifdef HAVE_ZLIB_H
Line 330  open_io_fd(char *pathbuf, size_t len, struct io_log_fi Line 315  open_io_fd(char *pathbuf, size_t len, struct io_log_fi
 #endif  #endif
                 iol->fd.f = fdopen(fd, "w");                  iol->fd.f = fdopen(fd, "w");
         }          }
        if (fd == -1 || iol->fd.v == NULL) {        if (fd == -1 || iol->fd.v == NULL)
             log_fatal(USE_ERRNO, N_("unable to create %s"), pathbuf);              log_fatal(USE_ERRNO, N_("unable to create %s"), pathbuf);
             if (fd != -1)  
                 close(fd);  
         }  
     } else {      } else {
         /* Remove old log file if we recycled sequence numbers. */          /* Remove old log file if we recycled sequence numbers. */
         unlink(pathbuf);          unlink(pathbuf);
Line 352  iolog_deserialize_info(struct iolog_details *details,  Line 334  iolog_deserialize_info(struct iolog_details *details, 
 {  {
     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)
Line 366  iolog_deserialize_info(struct iolog_details *details,  Line 349  iolog_deserialize_info(struct iolog_details *details, 
         switch (**cur) {          switch (**cur) {
         case 'c':          case 'c':
             if (strncmp(*cur, "cols=", sizeof("cols=") - 1) == 0) {              if (strncmp(*cur, "cols=", sizeof("cols=") - 1) == 0) {
                details->cols = atoi(*cur + sizeof("cols=") - 1);                int n = strtonum(*cur + sizeof("cols=") - 1, 1, INT_MAX, NULL);
                 if (n > 0)
                     details->cols = n;
                 continue;                  continue;
             }              }
             if (strncmp(*cur, "cwd=", sizeof("cwd=") - 1) == 0) {              if (strncmp(*cur, "cwd=", sizeof("cwd=") - 1) == 0) {
Line 376  iolog_deserialize_info(struct iolog_details *details,  Line 361  iolog_deserialize_info(struct iolog_details *details, 
             break;              break;
         case 'l':          case 'l':
             if (strncmp(*cur, "lines=", sizeof("lines=") - 1) == 0) {              if (strncmp(*cur, "lines=", sizeof("lines=") - 1) == 0) {
                details->lines = atoi(*cur + sizeof("lines=") - 1);                int n = strtonum(*cur + sizeof("lines=") - 1, 1, INT_MAX, NULL);
                 if (n > 0)
                     details->lines = n;
                 continue;                  continue;
             }              }
             break;              break;
Line 470  iolog_deserialize_info(struct iolog_details *details,  Line 457  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, U_(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, U_(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_bool(      debug_return_bool(
Line 509  iolog_deserialize_info(struct iolog_details *details,  Line 494  iolog_deserialize_info(struct iolog_details *details, 
         io_log_files[IOFD_TTYOUT].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_TRUNC|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 582  sudoers_io_open(unsigned int version, sudo_conv_t conv Line 598  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. 
     */ 
    for (i = 0; i < IOFD_MAX; i++) { 
        open_io_fd(pathbuf, len, &io_log_files[i], i ? iolog_compress : false); 
    } 
 
     gettimeofday(&last_time, NULL);      gettimeofday(&last_time, NULL);
    fprintf(io_log_files[IOFD_LOG].fd.f, "%lld:%s:%s:%s:%s:%d:%d\n%s\n%s",    write_info_log(pathbuf, len, &details, argv, &last_time);
        (long 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", details.lines, details.cols, 
        details.cwd ? details.cwd : "unknown", 
        details.command ? details.command : "unknown"); 
    for (cur = &argv[1]; *cur != NULL; cur++) { 
        fputc(' ', io_log_files[IOFD_LOG].fd.f); 
        fputs(*cur, io_log_files[IOFD_LOG].fd.f); 
    } 
    fputc('\n', io_log_files[IOFD_LOG].fd.f); 
    fclose(io_log_files[IOFD_LOG].fd.f); 
    io_log_files[IOFD_LOG].fd.f = NULL; 
   
       /* Create the timing and I/O log files. */
       for (i = 0; i < IOFD_MAX; i++)
           open_io_fd(pathbuf, len, &io_log_files[i], iolog_compress);
   
     /*      /*
      * Clear I/O log function pointers for disabled log functions.       * Clear I/O log function pointers for disabled log functions.
      */       */
Line 699  sudoers_io_log(const char *buf, unsigned int len, int  Line 700  sudoers_io_log(const char *buf, unsigned int len, int 
     else      else
 #endif  #endif
         ignore_result(fwrite(buf, 1, len, io_log_files[idx].fd.f));          ignore_result(fwrite(buf, 1, len, io_log_files[idx].fd.f));
    delay.tv_sec = now.tv_sec;    sudo_timevalsub(&now, &last_time, &delay);
    delay.tv_usec = now.tv_usec; 
    timevalsub(&delay, &last_time); 
 #ifdef HAVE_ZLIB_H  #ifdef HAVE_ZLIB_H
     if (iolog_compress)      if (iolog_compress)
        gzprintf(io_log_files[IOFD_TIMING].fd.g, "%d %f %d\n", idx,        gzprintf(io_log_files[IOFD_TIMING].fd.g, "%d %f %u\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_log_files[IOFD_TIMING].fd.f, "%d %f %d\n", idx,        fprintf(io_log_files[IOFD_TIMING].fd.f, "%d %f %u\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.4  
changed lines
  Added in v.1.1.1.6


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