Move updating of the window size to the monitor process.
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.
This commit is contained in:
@@ -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 */
|
||||
|
Reference in New Issue
Block a user