]> granicus.if.org Git - sudo/commitdiff
Move updating of the window size to the monitor process.
authorTodd C. Miller <Todd.Miller@sudo.ws>
Mon, 20 Aug 2018 16:04:14 +0000 (10:04 -0600)
committerTodd C. Miller <Todd.Miller@sudo.ws>
Mon, 20 Aug 2018 16:04:14 +0000 (10:04 -0600)
This will allow us to close the slave in the main sudo process in
the future so only the command and monitor have it open.

lib/util/term.c
src/exec_monitor.c
src/exec_pty.c
src/sudo.h

index 41e23d7f115323418d66ac501e675c53202f0579..657fb6605af9b2a7c4d84dee2bc381d47d2b1174 100644 (file)
@@ -17,6 +17,7 @@
 #include <config.h>
 
 #include <sys/types.h>
+#include <sys/ioctl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #ifdef HAVE_STRING_H
@@ -255,6 +256,7 @@ bool
 sudo_term_copy_v1(int src, int dst)
 {
     struct termios tt_src, tt_dst;
+    struct winsize wsize;
     speed_t speed;
     int i;
     debug_decl(sudo_term_copy, SUDO_DEBUG_UTIL)
@@ -285,7 +287,11 @@ sudo_term_copy_v1(int src, int dst)
     speed = cfgetispeed(&tt_src);
     cfsetispeed(&tt_dst, speed);
 
-    if (tcsetattr_nobg(dst, TCSASOFT|TCSAFLUSH, &tt_dst) == 0)
-       debug_return_bool(true);
-    debug_return_bool(false);
+    if (tcsetattr_nobg(dst, TCSASOFT|TCSAFLUSH, &tt_dst) == -1)
+       debug_return_bool(false);
+
+    if (ioctl(src, TIOCGWINSZ, &wsize) == 0)
+       (void)ioctl(dst, TIOCSWINSZ, &wsize);
+
+    debug_return_bool(true);
 }
index 1dc1d370d7d7ab32aba1cfa8e4ff3ad6c3806dd4..4b4a7f92e8f83a0aea81b07e96a579257eb8521f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2017 Todd C. Miller <Todd.Miller@sudo.ws>
+ * Copyright (c) 2009-2018 Todd C. Miller <Todd.Miller@sudo.ws>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -17,6 +17,7 @@
 #include <config.h>
 
 #include <sys/types.h>
+#include <sys/ioctl.h>
 #include <sys/socket.h>
 #include <sys/wait.h>
 #include <stdio.h>
@@ -32,6 +33,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <signal.h>
+#include <termios.h>
 
 #include "sudo.h"
 #include "sudo_event.h"
@@ -58,6 +60,8 @@ struct monitor_closure {
     struct sudo_event *sigchld_event;
 };
 
+static bool tty_initialized;
+
 /*
  * Deliver a signal to the running command.
  * The signal was either forwarded to us by the parent sudo process
@@ -97,6 +101,11 @@ deliver_signal(struct monitor_closure *mc, int signo, bool from_parent)
                "%s: unable to set foreground pgrp to %d (command)",
                __func__, (int)mc->cmnd_pgrp);
        }
+       /* Lazily initialize the pty if needed. */
+       if (!tty_initialized) {
+           if (sudo_term_copy(io_fds[SFD_USERTTY], io_fds[SFD_SLAVE]))
+                   tty_initialized = true;
+       }
        killpg(mc->cmnd_pid, SIGCONT);
        break;
     case SIGCONT_BG:
@@ -119,6 +128,34 @@ deliver_signal(struct monitor_closure *mc, int signo, bool from_parent)
     debug_return;
 }
 
+/*
+ * Unpack rows and cols from a CMD_TTYWINCH value, set the new window
+ * size on the pty slave and inform the command of the change.
+ */
+static void
+handle_winch(struct monitor_closure *mc, unsigned int wsize_packed)
+{
+    struct winsize wsize, owsize;
+    debug_decl(handle_winch, SUDO_DEBUG_EXEC);
+
+    /* Rows and colums are stored as two shorts packed into a single int. */
+    wsize.ws_row = wsize_packed & 0xffff;
+    wsize.ws_col = (wsize_packed >> 16) & 0xffff;
+
+    if (ioctl(io_fds[SFD_SLAVE], TIOCGWINSZ, &owsize) == 0 &&
+       (wsize.ws_row != owsize.ws_row || wsize.ws_col != owsize.ws_col)) {
+
+       sudo_debug_printf(SUDO_DEBUG_INFO,
+           "window size change %dx%d -> %dx%d",
+           owsize.ws_col, owsize.ws_row, wsize.ws_col, wsize.ws_row);
+
+       (void)ioctl(io_fds[SFD_SLAVE], TIOCSWINSZ, &wsize);
+       deliver_signal(mc, SIGWINCH, true);
+    }
+
+    debug_return;
+}
+
 /*
  * Send status to parent over socketpair.
  * Return value is the same as send(2).
@@ -210,7 +247,7 @@ mon_handle_sigchld(struct monitor_closure *mc)
                send_status(mc->backchannel, mc->cstat);
            }
        }
-    } else {                       
+    } else {
        sudo_debug_printf(SUDO_DEBUG_WARN,
            "%s: not overwriting command status %d,%d with %d,%d",
            __func__, mc->cstat->type, mc->cstat->val, CMD_WSTATUS, status);
@@ -328,10 +365,16 @@ mon_backchannel_cb(int fd, int what, void *v)
        mc->cstat->val = n ? EIO : ECONNRESET;
        sudo_ev_loopbreak(mc->evbase);
     } else {
-       if (cstmp.type == CMD_SIGNO) {
+       switch (cstmp.type) {
+       case CMD_TTYWINCH:
+           handle_winch(mc, cstmp.val);
+           break;
+       case CMD_SIGNO:
            deliver_signal(mc, cstmp.val, true);
-       } else {
+           break;
+       default:
            sudo_warnx(U_("unexpected reply type on backchannel: %d"), cstmp.type);
+           break;
        }
     }
     debug_return;
@@ -414,7 +457,7 @@ fill_exec_closure_monitor(struct monitor_closure *mc,
     /* Setup event base and events. */
     mc->evbase = sudo_ev_base_alloc();
     if (mc->evbase == NULL)
-        sudo_fatal(NULL);
+       sudo_fatal(NULL);
 
     /* Event for command status via errfd. */
     mc->errpipe_event = sudo_ev_alloc(errfd,
@@ -513,11 +556,9 @@ exec_monitor(struct command_details *details, sigset_t *oset,
     int errpipe[2];
     debug_decl(exec_monitor, SUDO_DEBUG_EXEC);
 
-    /* Close unused fds. */
+    /* The pty master is not used by the monitor. */
     if (io_fds[SFD_MASTER] != -1)
        close(io_fds[SFD_MASTER]);
-    if (io_fds[SFD_USERTTY] != -1)
-       close(io_fds[SFD_USERTTY]);
 
     /* Ignore any SIGTTIN or SIGTTOU we receive (shouldn't be possible). */
     memset(&sa, 0, sizeof(sa));
@@ -529,6 +570,10 @@ exec_monitor(struct command_details *details, sigset_t *oset,
     if (sudo_sigaction(SIGTTOU, &sa, NULL) != 0)
        sudo_warn(U_("unable to set handler for signal %d"), SIGTTOU);
 
+    /* If we are starting in the foreground, the pty was already initialized. */
+    if (foreground)
+       tty_initialized = true;
+
     /*
      * Start a new session with the parent as the session leader
      * and the slave pty as the controlling terminal.
@@ -559,6 +604,8 @@ exec_monitor(struct command_details *details, sigset_t *oset,
        sigprocmask(SIG_SETMASK, oset, NULL);
        close(backchannel);
        close(errpipe[0]);
+       if (io_fds[SFD_USERTTY] != -1)
+           close(io_fds[SFD_USERTTY]);
        restore_signals();
 
        /* setup tty and exec command */
index 814b0e4975aaacfd947aa87dba17ec84083231bb..d3f96edaf8eb09b103140e888fe9d133239fc563 100644 (file)
 #define TERM_COOKED    0
 #define TERM_RAW       1
 
-/* We keep a tailq of signals to forward to the monitor. */
-struct sigforward {
-    TAILQ_ENTRY(sigforward) entries;
-    int signo;
+/* Tail queue of messages to send to the monitor. */
+struct monitor_message {
+    TAILQ_ENTRY(monitor_message) entries;
+    struct command_status cstat;
 };
-TAILQ_HEAD(sigfwd_list, sigforward);
+TAILQ_HEAD(monitor_message_list, monitor_message);
 
 struct exec_closure_pty {
     pid_t monitor_pid;
@@ -62,6 +62,7 @@ struct exec_closure_pty {
     struct command_details *details;
     struct sudo_event_base *evbase;
     struct sudo_event *backchannel_event;
+    struct sudo_event *fwdchannel_event;
     struct sudo_event *sigint_event;
     struct sudo_event *sigquit_event;
     struct sudo_event *sigtstp_event;
@@ -72,8 +73,7 @@ struct exec_closure_pty {
     struct sudo_event *sigusr2_event;
     struct sudo_event *sigchld_event;
     struct sudo_event *sigwinch_event;
-    struct sudo_event *sigfwd_event;
-    struct sigfwd_list sigfwd_list;
+    struct monitor_message_list monitor_messages;
 };
 
 /*
@@ -98,17 +98,16 @@ SLIST_HEAD(io_buffer_list, io_buffer);
 static char slavename[PATH_MAX];
 int io_fds[6] = { -1, -1, -1, -1, -1, -1};
 static bool foreground, pipeline;
-static bool tty_initialized;
 static int ttymode = TERM_COOKED;
 static sigset_t ttyblock;
 static struct io_buffer_list iobufs;
 static const char *utmp_user;
 
 static void del_io_events(bool nonblocking);
-static void sync_ttysize(int src, int dst);
+static void sync_ttysize(struct exec_closure_pty *ec);
 static int safe_close(int fd);
 static void ev_free_by_fd(struct sudo_event_base *evbase, int fd);
-static void check_foreground(pid_t ppgrp);
+static void check_foreground(struct exec_closure_pty *ec);
 static void add_io_events(struct sudo_event_base *evbase);
 static void schedule_signal(struct exec_closure_pty *ec, int signo);
 
@@ -161,10 +160,14 @@ pty_setup(uid_t uid, const char *tty)
     debug_return_bool(true);
 }
 
+/*
+ * Make the tty slave the controlling tty.
+ * This is only used by the monitor but slavename[] is static.
+ */
 int
 pty_make_controlling(void)
 {
-    if (io_fds[SFD_USERTTY] != -1) {
+    if (io_fds[SFD_SLAVE] != -1) {
 #ifdef TIOCSCTTY
        if (ioctl(io_fds[SFD_SLAVE], TIOCSCTTY, NULL) != 0)
            return -1;
@@ -410,21 +413,15 @@ log_winchange(unsigned int rows, unsigned int cols)
  * the pty slave as needed.
  */
 static void
-check_foreground(pid_t ppgrp)
+check_foreground(struct exec_closure_pty *ec)
 {
     debug_decl(check_foreground, SUDO_DEBUG_EXEC);
 
     if (io_fds[SFD_USERTTY] != -1) {
-       /* Always check for window size changes. */
-       sync_ttysize(io_fds[SFD_USERTTY], io_fds[SFD_SLAVE]);
+       foreground = tcgetpgrp(io_fds[SFD_USERTTY]) == ec->ppgrp;
 
-       foreground = tcgetpgrp(io_fds[SFD_USERTTY]) == ppgrp;
-       if (foreground) {
-           if (!tty_initialized) {
-               if (sudo_term_copy(io_fds[SFD_USERTTY], io_fds[SFD_SLAVE]))
-                   tty_initialized = true;
-           }
-       }
+       /* Also check for window size changes. */
+       sync_ttysize(ec);
     }
 
     debug_return;
@@ -436,7 +433,7 @@ check_foreground(pid_t ppgrp)
  * foreground or SIGCONT_BG if it is a background process.
  */
 static int
-suspend_sudo(int signo, pid_t ppgrp)
+suspend_sudo(struct exec_closure_pty *ec, int signo)
 {
     char signame[SIG2STR_MAX];
     struct sigaction sa, osa;
@@ -451,7 +448,7 @@ suspend_sudo(int signo, pid_t ppgrp)
         * in the foreground.  If not, we'll suspend sudo and resume later.
         */
        if (!foreground)
-           check_foreground(ppgrp);
+           check_foreground(ec);
        if (foreground) {
            if (ttymode != TERM_RAW) {
                if (sudo_term_raw(io_fds[SFD_USERTTY], 0))
@@ -483,11 +480,11 @@ suspend_sudo(int signo, pid_t ppgrp)
                sudo_warn(U_("unable to set handler for signal %d"), signo);
        }
        sudo_debug_printf(SUDO_DEBUG_INFO, "kill parent SIG%s", signame);
-       if (killpg(ppgrp, signo) != 0)
-           sudo_warn("killpg(%d, SIG%s)", (int)ppgrp, signame);
+       if (killpg(ec->ppgrp, signo) != 0)
+           sudo_warn("killpg(%d, SIG%s)", (int)ec->ppgrp, signame);
 
        /* Check foreground/background status on resume. */
-       check_foreground(ppgrp);
+       check_foreground(ec);
 
        /*
         * We always resume the command in the foreground if sudo itself
@@ -804,13 +801,36 @@ pty_close(struct command_status *cstat)
     debug_return;
 }
 
+/*
+ * Send command status to the monitor (signal or window size change).
+ */
+static void
+send_command_status(struct exec_closure_pty *ec, int type, int val)
+{
+    struct monitor_message *msg;
+    debug_decl(send_command, SUDO_DEBUG_EXEC)
+
+    if ((msg = calloc(1, sizeof(*msg))) == NULL)
+       sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
+    msg->cstat.type = type;
+    msg->cstat.val = val;
+    TAILQ_INSERT_TAIL(&ec->monitor_messages, msg, entries);
+
+    if (sudo_ev_add(ec->evbase, ec->fwdchannel_event, NULL, true) == -1)
+       sudo_fatal(U_("unable to add event to queue"));
+
+    /* Restart event loop to send the command immediately. */
+    sudo_ev_loopcontinue(ec->evbase);
+
+    debug_return;
+}
+
 /*
  * Schedule a signal to be forwarded.
  */
 static void
 schedule_signal(struct exec_closure_pty *ec, int signo)
 {
-    struct sigforward *sigfwd;
     char signame[SIG2STR_MAX];
     debug_decl(schedule_signal, SUDO_DEBUG_EXEC)
 
@@ -822,16 +842,7 @@ schedule_signal(struct exec_closure_pty *ec, int signo)
        snprintf(signame, sizeof(signame), "%d", signo);
     sudo_debug_printf(SUDO_DEBUG_DIAG, "scheduled SIG%s for command", signame);
 
-    if ((sigfwd = calloc(1, sizeof(*sigfwd))) == NULL)
-       sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
-    sigfwd->signo = signo;
-    TAILQ_INSERT_TAIL(&ec->sigfwd_list, sigfwd, entries);
-
-    if (sudo_ev_add(ec->evbase, ec->sigfwd_event, NULL, true) == -1)
-       sudo_fatal(U_("unable to add event to queue"));
-
-    /* Restart event loop to service signal immediately. */
-    sudo_ev_loopcontinue(ec->evbase);
+    send_command_status(ec, CMD_SIGNO, signo);
 
     debug_return;
 }
@@ -894,7 +905,7 @@ backchannel_cb(int fd, int what, void *v)
                /* Suspend parent and tell monitor how to resume on return. */
                sudo_debug_printf(SUDO_DEBUG_INFO,
                    "command stopped, suspending parent");
-               signo = suspend_sudo(WSTOPSIG(cstat.val), ec->ppgrp);
+               signo = suspend_sudo(ec, WSTOPSIG(cstat.val));
                schedule_signal(ec, signo);
                /* Re-enable I/O events */
                add_io_events(ec->evbase);
@@ -962,7 +973,7 @@ handle_sigchld_pty(struct exec_closure_pty *ec)
     if (WIFSTOPPED(status)) {
        sudo_debug_printf(SUDO_DEBUG_INFO,
            "monitor stopped, suspending sudo");
-       n = suspend_sudo(WSTOPSIG(status), ec->ppgrp);
+       n = suspend_sudo(ec, WSTOPSIG(status));
        kill(pid, SIGCONT);
        schedule_signal(ec, n);
        /* Re-enable I/O events */
@@ -1005,7 +1016,7 @@ signal_cb_pty(int signo, int what, void *v)
        handle_sigchld_pty(ec);
        break;
     case SIGWINCH:
-       sync_ttysize(io_fds[SFD_USERTTY], io_fds[SFD_SLAVE]);
+       sync_ttysize(ec);
        break;
     default:
        /*
@@ -1032,41 +1043,52 @@ signal_cb_pty(int signo, int what, void *v)
 }
 
 /*
- * Forward signals in sigfwd_list to the monitor so it can
+ * Forward signals in monitor_messages to the monitor so it can
  * deliver them to the command.
  */
 static void
-sigfwd_cb(int sock, int what, void *v)
+fwdchannel_cb(int sock, int what, void *v)
 {
     struct exec_closure_pty *ec = v;
     char signame[SIG2STR_MAX];
-    struct sigforward *sigfwd;
-    struct command_status cstat;
+    struct monitor_message *msg;
     ssize_t nsent;
-    debug_decl(sigfwd_cb, SUDO_DEBUG_EXEC)
-
-    while ((sigfwd = TAILQ_FIRST(&ec->sigfwd_list)) != NULL) {
-       if (sigfwd->signo == SIGCONT_FG)
-           strlcpy(signame, "CONT_FG", sizeof(signame));
-       else if (sigfwd->signo == SIGCONT_BG)
-           strlcpy(signame, "CONT_BG", sizeof(signame));
-       else if (sig2str(sigfwd->signo, signame) == -1)
-           snprintf(signame, sizeof(signame), "%d", sigfwd->signo);
-       sudo_debug_printf(SUDO_DEBUG_INFO,
-           "sending SIG%s to monitor over backchannel", signame);
-       cstat.type = CMD_SIGNO;
-       cstat.val = sigfwd->signo;
-       TAILQ_REMOVE(&ec->sigfwd_list, sigfwd, entries);
-       free(sigfwd);
-       nsent = send(sock, &cstat, sizeof(cstat), 0);
-       if (nsent != sizeof(cstat)) {
+    debug_decl(fwdchannel_cb, SUDO_DEBUG_EXEC)
+
+    while ((msg = TAILQ_FIRST(&ec->monitor_messages)) != NULL) {
+       switch (msg->cstat.type) {
+       case CMD_SIGNO:
+           if (msg->cstat.val == SIGCONT_FG)
+               strlcpy(signame, "CONT_FG", sizeof(signame));
+           else if (msg->cstat.val == SIGCONT_BG)
+               strlcpy(signame, "CONT_BG", sizeof(signame));
+           else if (sig2str(msg->cstat.val, signame) == -1)
+               snprintf(signame, sizeof(signame), "%d", msg->cstat.val);
+           sudo_debug_printf(SUDO_DEBUG_INFO,
+               "sending SIG%s to monitor over backchannel", signame);
+           break;
+       case CMD_TTYWINCH:
+           sudo_debug_printf(SUDO_DEBUG_INFO, "sending window size change "
+               "to monitor over backchannelL %d x %d",
+               msg->cstat.val & 0xffff, (msg->cstat.val >> 16) & 0xffff);
+           break;
+       default:
+           sudo_debug_printf(SUDO_DEBUG_INFO,
+               "sending cstat type %d, value %d to monitor over backchannel",
+               msg->cstat.type, msg->cstat.val);
+           break;
+       }
+       TAILQ_REMOVE(&ec->monitor_messages, msg, entries);
+       nsent = send(sock, &msg->cstat, sizeof(msg->cstat), 0);
+       if (nsent != sizeof(msg->cstat)) {
            if (errno == EPIPE) {
                sudo_debug_printf(SUDO_DEBUG_ERROR,
                    "broken pipe writing to monitor over backchannel");
-               /* Other end of socket gone, empty out sigfwd_list. */
-               while ((sigfwd = TAILQ_FIRST(&ec->sigfwd_list)) != NULL) {
-                   TAILQ_REMOVE(&ec->sigfwd_list, sigfwd, entries);
-                   free(sigfwd);
+               /* Other end of socket gone, empty out monitor_messages. */
+               free(msg);
+               while ((msg = TAILQ_FIRST(&ec->monitor_messages)) != NULL) {
+                   TAILQ_REMOVE(&ec->monitor_messages, msg, entries);
+                   free(msg);
                }
                /* XXX - need new CMD_ type for monitor errors. */
                ec->cstat->type = CMD_ERRNO;
@@ -1075,6 +1097,7 @@ sigfwd_cb(int sock, int what, void *v)
            }
            break;
        }
+       free(msg);
     }
 }
 
@@ -1094,7 +1117,7 @@ fill_exec_closure_pty(struct exec_closure_pty *ec, struct command_status *cstat,
     ec->ppgrp = ppgrp;
     ec->cstat = cstat;
     ec->details = details;
-    TAILQ_INIT(&ec->sigfwd_list);
+    TAILQ_INIT(&ec->monitor_messages);
 
     /* Setup event base and events. */
     ec->evbase = sudo_ev_base_alloc();
@@ -1182,9 +1205,9 @@ fill_exec_closure_pty(struct exec_closure_pty *ec, struct command_status *cstat,
        sudo_fatal(U_("unable to add event to queue"));
 
     /* The signal forwarding event gets added on demand. */
-    ec->sigfwd_event = sudo_ev_alloc(backchannel,
-       SUDO_EV_WRITE, sigfwd_cb, ec);
-    if (ec->sigfwd_event == NULL)
+    ec->fwdchannel_event = sudo_ev_alloc(backchannel,
+       SUDO_EV_WRITE, fwdchannel_cb, ec);
+    if (ec->fwdchannel_event == NULL)
        sudo_fatal(NULL);
 
     /* Set the default event base. */
@@ -1203,6 +1226,7 @@ free_exec_closure_pty(struct exec_closure_pty *ec)
 
     sudo_ev_base_free(ec->evbase);
     sudo_ev_free(ec->backchannel_event);
+    sudo_ev_free(ec->fwdchannel_event);
     sudo_ev_free(ec->sigint_event);
     sudo_ev_free(ec->sigquit_event);
     sudo_ev_free(ec->sigtstp_event);
@@ -1213,7 +1237,6 @@ free_exec_closure_pty(struct exec_closure_pty *ec)
     sudo_ev_free(ec->sigusr2_event);
     sudo_ev_free(ec->sigchld_event);
     sudo_ev_free(ec->sigwinch_event);
-    sudo_ev_free(ec->sigfwd_event);
 
     debug_return;
 }
@@ -1229,7 +1252,7 @@ exec_pty(struct command_details *details, struct command_status *cstat)
 {
     int io_pipe[3][2] = { { -1, -1 }, { -1, -1 }, { -1, -1 } };
     bool interpose[3] = { false, false, false };
-    struct sigforward *sigfwd, *sigfwd_next;
+    struct monitor_message *msg;
     struct exec_closure_pty ec = { 0 };
     struct plugin_container *plugin;
     sigset_t set, oset;
@@ -1393,13 +1416,12 @@ exec_pty(struct command_details *details, struct command_status *cstat)
        }
     }
 
-    /* Set pty window size. */
-    sync_ttysize(io_fds[SFD_USERTTY], io_fds[SFD_SLAVE]);
-
     if (foreground) {
        /* Copy terminal attrs from user tty -> pty slave. */
-       if (sudo_term_copy(io_fds[SFD_USERTTY], io_fds[SFD_SLAVE]))
-           tty_initialized = true;
+       if (!sudo_term_copy(io_fds[SFD_USERTTY], io_fds[SFD_SLAVE])) {
+            sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO,
+                "%s: unable to copy terminal settings to pty", __func__);
+       }
 
        /* Start out in raw mode unless part of a pipeline or backgrounded. */
        if (!pipeline && !ISSET(details->flags, CD_EXEC_BG)) {
@@ -1505,8 +1527,9 @@ exec_pty(struct command_details *details, struct command_status *cstat)
 
     /* Free things up. */
     free_exec_closure_pty(&ec);
-    TAILQ_FOREACH_SAFE(sigfwd, &ec.sigfwd_list, entries, sigfwd_next) {
-       free(sigfwd);
+    while ((msg = TAILQ_FIRST(&ec.monitor_messages)) != NULL) {
+       TAILQ_REMOVE(&ec.monitor_messages, msg, entries);
+       free(msg);
     }
     debug_return_bool(true);
 }
@@ -1651,31 +1674,30 @@ del_io_events(bool nonblocking)
 }
 
 /*
- * Propagates tty size change signals to pty being used by the command
- * and passes new window size to the I/O plugin.
+ * Check for tty size changes.
+ * Passes the new window size to the I/O plugin and to the monitor.
  */
 static void
-sync_ttysize(int src, int dst)
+sync_ttysize(struct exec_closure_pty *ec)
 {
-    struct winsize wsize, owsize;
-    pid_t pgrp;
+    static struct winsize owsize;
+    struct winsize wsize;
     debug_decl(sync_ttysize, SUDO_DEBUG_EXEC);
 
-    if (ioctl(src, TIOCGWINSZ, &wsize) == 0 &&
-       ioctl(dst, TIOCGWINSZ, &owsize) == 0 &&
-       (wsize.ws_row != owsize.ws_row || wsize.ws_col != owsize.ws_col)) {
+    if (ioctl(io_fds[SFD_USERTTY], TIOCGWINSZ, &wsize) == 0) {
+       if (wsize.ws_row != owsize.ws_row || wsize.ws_col != owsize.ws_col) {
+           const unsigned int wsize_packed = (wsize.ws_row & 0xffff) |
+               ((wsize.ws_col & 0xffff) << 16);
 
-       sudo_debug_printf(SUDO_DEBUG_INFO,
-           "window size change %dx%d -> %dx%d",
-           owsize.ws_col, owsize.ws_row, wsize.ws_col, wsize.ws_row);
+           /* Log window change event. */
+           log_winchange(wsize.ws_row, wsize.ws_col);
 
-       (void)ioctl(dst, TIOCSWINSZ, &wsize);
-       if ((pgrp = tcgetpgrp(dst)) != -1)
-           killpg(pgrp, SIGWINCH);
+           /* Send window change event to monitor process. */
+           send_command_status(ec, CMD_TTYWINCH, wsize_packed);
 
-       /* Only log window size changes, not the initial setting. */
-       if (tty_initialized)
-           log_winchange(wsize.ws_row, wsize.ws_col);
+           /* Update old value. */
+           owsize = wsize;
+       }
     }
 
     debug_return;
index a4a92f6bb3ba9a3ec23e623fe6d3f59d5b48bbed..a2a4b5a5baa8e82a6140dc7be05c2cd42128da59 100644 (file)
@@ -172,11 +172,12 @@ struct command_details {
 
 /* Status passed between parent and child via socketpair */
 struct command_status {
-#define CMD_INVALID 0
-#define CMD_ERRNO 1
-#define CMD_WSTATUS 2
-#define CMD_SIGNO 3
-#define CMD_PID 4
+#define CMD_INVALID    0
+#define CMD_ERRNO      1
+#define CMD_WSTATUS    2
+#define CMD_SIGNO      3
+#define CMD_PID                4
+#define CMD_TTYWINCH   5
     int type;
     int val;
 };