From: Todd C. Miller <Todd.Miller@courtesan.com>
Date: Wed, 12 Jul 2017 11:47:28 +0000 (-0600)
Subject: Log window size change events in the sudoers I/O plugin.
X-Git-Tag: SUDO_1_8_21^2~42
X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f79a236533da8e5a3fdc22b1da205fa4be79e6df;p=sudo

Log window size change events in the sudoers I/O plugin.
Let sudoreplay parse a timing file with window change events
(currently ignored).
---

diff --git a/plugins/sudoers/iolog.c b/plugins/sudoers/iolog.c
index 18543ff01..52cbe28c8 100644
--- a/plugins/sudoers/iolog.c
+++ b/plugins/sudoers/iolog.c
@@ -961,8 +961,11 @@ sudoers_io_open(unsigned int version, sudo_conv_t conversation,
 	goto done;
 
     /* Write log file with user and command details. */
-    if (gettimeofday(&last_time, NULL) == -1)
+    if (gettimeofday(&last_time, NULL) == -1) {
+	sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
+	    "%s: unable to get time of day", __func__);
 	goto done;
+    }
     write_info_log(pathbuf, len, &iolog_details, argv, &last_time);
 
     /* Create the timing and I/O log files. */
@@ -1060,7 +1063,7 @@ sudoers_io_log(const char *buf, unsigned int len, int idx)
     char tbuf[1024];
     const char *errstr = NULL;
     int ret = -1;
-    debug_decl(sudoers_io_version, SUDOERS_DEBUG_PLUGIN)
+    debug_decl(sudoers_io_log, SUDOERS_DEBUG_PLUGIN)
 
     if (io_log_files[idx].fd.v == NULL) {
 	sudo_warnx(U_("%s: internal error, file index %d not open"),
@@ -1068,7 +1071,12 @@ sudoers_io_log(const char *buf, unsigned int len, int idx)
 	debug_return_int(-1);
     }
 
-    gettimeofday(&now, NULL);
+    if (gettimeofday(&now, NULL) == -1) {
+	sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
+	    "%s: unable to get time of day", __func__);
+	errstr = strerror(errno);
+	goto done;
+    }
 
     /* Write I/O log file entry. */
     errstr = iolog_write(buf, len, idx);
@@ -1141,6 +1149,57 @@ sudoers_io_log_stderr(const char *buf, unsigned int len)
     return sudoers_io_log(buf, len, IOFD_STDERR);
 }
 
+static int
+sudoers_io_change_winsize(unsigned int lines, unsigned int cols)
+{
+    struct timeval now, delay;
+    unsigned int len;
+    char tbuf[1024];
+    const char *errstr = NULL;
+    int ret = -1;
+    debug_decl(sudoers_io_change_winsize, SUDOERS_DEBUG_PLUGIN)
+
+    if (gettimeofday(&now, NULL) == -1) {
+	sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
+	    "%s: unable to get time of day", __func__);
+	errstr = strerror(errno);
+	goto done;
+    }
+
+    /* Write window change event to the timing file. */
+    sudo_timevalsub(&now, &last_time, &delay);
+    len = (unsigned int)snprintf(tbuf, sizeof(tbuf), "%d %f %u %u\n",
+	IOFD_TIMING, delay.tv_sec + ((double)delay.tv_usec / 1000000),
+	lines, cols);
+    if (len >= sizeof(tbuf)) {
+	/* Not actually possible due to the size of tbuf[]. */
+	errstr = strerror(EOVERFLOW);
+	goto done;
+    }
+    errstr = iolog_write(tbuf, len, IOFD_TIMING);
+    if (errstr != NULL)
+	goto done;
+
+done:
+    last_time.tv_sec = now.tv_sec;
+    last_time.tv_usec = now.tv_usec;
+
+    if (ret == -1) {
+	if (errstr != NULL && !warned) {
+	    /* Only warn about I/O log file errors once. */
+	    log_warning(SLOG_SEND_MAIL,
+		N_("unable to write to I/O log file: %s"), errstr);
+	    warned = true;
+	}
+
+	/* Ignore errors if they occur if the policy says so. */
+	if (iolog_details.ignore_iolog_errors)
+	    ret = 1;
+    }
+
+    debug_return_int(ret);
+}
+
 __dso_public struct io_plugin sudoers_io = {
     SUDO_IO_PLUGIN,
     SUDO_API_VERSION,
@@ -1151,5 +1210,8 @@ __dso_public struct io_plugin sudoers_io = {
     sudoers_io_log_ttyout,
     sudoers_io_log_stdin,
     sudoers_io_log_stdout,
-    sudoers_io_log_stderr
+    sudoers_io_log_stderr,
+    NULL, /* register_hooks */
+    NULL, /* deregister_hooks */
+    sudoers_io_change_winsize
 };
diff --git a/plugins/sudoers/sudoreplay.c b/plugins/sudoers/sudoreplay.c
index 5deb17d06..80ada701b 100644
--- a/plugins/sudoers/sudoreplay.c
+++ b/plugins/sudoers/sudoreplay.c
@@ -453,7 +453,7 @@ replay_session(const double max_wait, const char *decimal)
 	sudo_ev_loop(evbase, 0);
 
 	/* Even if we are not replaying, we still have to delay. */
-	if (idx >= IOFD_MAX || io_log_files[idx].fd.v == NULL)
+	if (idx >= IOFD_TIMING || io_log_files[idx].fd.v == NULL)
 	    continue;
 
 	/* Check whether we need to convert newline to CR LF pairs. */
@@ -1196,7 +1196,7 @@ parse_timing(const char *buf, const char *decimal, int *idx, double *seconds,
     ul = strtoul(buf, &ep, 10);
     if (ep == buf || !isspace((unsigned char) *ep))
 	goto bad;
-    if (ul >= IOFD_TIMING) {
+    if (ul >= IOFD_MAX) {
 	if (ul != 6)
 	    goto bad;
 	/* work around a bug in timing files generated by sudo 1.8.7 */
@@ -1232,7 +1232,8 @@ parse_timing(const char *buf, const char *decimal, int *idx, double *seconds,
 
     errno = 0;
     ul = strtoul(cp, &ep, 10);
-    if (ep == cp || *ep != '\0' || (errno == ERANGE && ul == ULONG_MAX))
+    if (ep == cp || (*ep != '\0' && !isspace((unsigned char) *ep)) ||
+	(errno == ERANGE && ul == ULONG_MAX))
 	goto bad;
     *nbytes = (size_t)ul;