Replace tty_mode global with term_raw flag in struct exec_closure.
The pty_cleanup hook needs access to the closure so add pty_cleanup_init() to store a pointer to the closure for use by pty_cleanup_hook().
This commit is contained in:
@@ -36,8 +36,6 @@
|
|||||||
#include "sudo_plugin.h"
|
#include "sudo_plugin.h"
|
||||||
#include "sudo_plugin_int.h"
|
#include "sudo_plugin_int.h"
|
||||||
|
|
||||||
int ttymode = TERM_COOKED;
|
|
||||||
|
|
||||||
struct io_buffer_list iobufs = SLIST_HEAD_INITIALIZER(&iobufs);
|
struct io_buffer_list iobufs = SLIST_HEAD_INITIALIZER(&iobufs);
|
||||||
|
|
||||||
int io_fds[6] = { -1, -1, -1, -1, -1, -1 };
|
int io_fds[6] = { -1, -1, -1, -1, -1, -1 };
|
||||||
@@ -144,7 +142,7 @@ io_buf_new(int rfd, int wfd,
|
|||||||
* resuming from suspend.
|
* resuming from suspend.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
add_io_events(struct sudo_event_base *evbase)
|
add_io_events(struct exec_closure *ec)
|
||||||
{
|
{
|
||||||
struct io_buffer *iob;
|
struct io_buffer *iob;
|
||||||
debug_decl(add_io_events, SUDO_DEBUG_EXEC);
|
debug_decl(add_io_events, SUDO_DEBUG_EXEC);
|
||||||
@@ -157,12 +155,12 @@ add_io_events(struct sudo_event_base *evbase)
|
|||||||
SLIST_FOREACH(iob, &iobufs, entries) {
|
SLIST_FOREACH(iob, &iobufs, entries) {
|
||||||
/* Don't read from /dev/tty if we are not in the foreground. */
|
/* Don't read from /dev/tty if we are not in the foreground. */
|
||||||
if (iob->revent != NULL &&
|
if (iob->revent != NULL &&
|
||||||
(ttymode == TERM_RAW || !USERTTY_EVENT(iob->revent))) {
|
(ec->term_raw || !USERTTY_EVENT(iob->revent))) {
|
||||||
if (iob->len != sizeof(iob->buf)) {
|
if (iob->len != sizeof(iob->buf)) {
|
||||||
sudo_debug_printf(SUDO_DEBUG_INFO,
|
sudo_debug_printf(SUDO_DEBUG_INFO,
|
||||||
"added I/O revent %p, fd %d, events %d",
|
"added I/O revent %p, fd %d, events %d",
|
||||||
iob->revent, iob->revent->fd, iob->revent->events);
|
iob->revent, iob->revent->fd, iob->revent->events);
|
||||||
if (sudo_ev_add(evbase, iob->revent, NULL, false) == -1)
|
if (sudo_ev_add(ec->evbase, iob->revent, NULL, false) == -1)
|
||||||
sudo_fatal("%s", U_("unable to add event to queue"));
|
sudo_fatal("%s", U_("unable to add event to queue"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -172,7 +170,7 @@ add_io_events(struct sudo_event_base *evbase)
|
|||||||
sudo_debug_printf(SUDO_DEBUG_INFO,
|
sudo_debug_printf(SUDO_DEBUG_INFO,
|
||||||
"added I/O wevent %p, fd %d, events %d",
|
"added I/O wevent %p, fd %d, events %d",
|
||||||
iob->wevent, iob->wevent->fd, iob->wevent->events);
|
iob->wevent, iob->wevent->fd, iob->wevent->events);
|
||||||
if (sudo_ev_add(evbase, iob->wevent, NULL, false) == -1)
|
if (sudo_ev_add(ec->evbase, iob->wevent, NULL, false) == -1)
|
||||||
sudo_fatal("%s", U_("unable to add event to queue"));
|
sudo_fatal("%s", U_("unable to add event to queue"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-License-Identifier: ISC
|
* SPDX-License-Identifier: ISC
|
||||||
*
|
*
|
||||||
* Copyright (c) 2009-2022 Todd C. Miller <Todd.Miller@sudo.ws>
|
* Copyright (c) 2009-2023 Todd C. Miller <Todd.Miller@sudo.ws>
|
||||||
*
|
*
|
||||||
* 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
|
||||||
@@ -680,7 +680,7 @@ exec_nopty(struct command_details *details, struct command_status *cstat)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Enable any I/O log events. */
|
/* Enable any I/O log events. */
|
||||||
add_io_events(ec.evbase);
|
add_io_events(&ec);
|
||||||
|
|
||||||
/* Restore signal mask now that signal handlers are setup. */
|
/* Restore signal mask now that signal handlers are setup. */
|
||||||
sigprocmask(SIG_SETMASK, &oset, NULL);
|
sigprocmask(SIG_SETMASK, &oset, NULL);
|
||||||
|
133
src/exec_pty.c
133
src/exec_pty.c
@@ -64,24 +64,6 @@ static const char *utmp_user;
|
|||||||
static void sync_ttysize(struct exec_closure *ec);
|
static void sync_ttysize(struct exec_closure *ec);
|
||||||
static void schedule_signal(struct exec_closure *ec, int signo);
|
static void schedule_signal(struct exec_closure *ec, int signo);
|
||||||
|
|
||||||
/*
|
|
||||||
* Cleanup hook for sudo_fatal()/sudo_fatalx()
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
pty_cleanup(void)
|
|
||||||
{
|
|
||||||
debug_decl(cleanup, SUDO_DEBUG_EXEC);
|
|
||||||
|
|
||||||
if (ttymode != TERM_COOKED) {
|
|
||||||
if (!sudo_term_restore(io_fds[SFD_USERTTY], false))
|
|
||||||
sudo_warn("%s", U_("unable to restore terminal settings"));
|
|
||||||
}
|
|
||||||
if (utmp_user != NULL)
|
|
||||||
utmp_logout(ptyname, 0);
|
|
||||||
|
|
||||||
debug_return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate a pty if /dev/tty is a tty.
|
* Allocate a pty if /dev/tty is a tty.
|
||||||
* Fills in io_fds[SFD_USERTTY], io_fds[SFD_LEADER], io_fds[SFD_FOLLOWER]
|
* Fills in io_fds[SFD_USERTTY], io_fds[SFD_LEADER], io_fds[SFD_FOLLOWER]
|
||||||
@@ -121,6 +103,68 @@ pty_setup(struct command_details *details, const char *tty)
|
|||||||
debug_return_bool(true);
|
debug_return_bool(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Restore user's terminal settings and update utmp, as needed.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
pty_cleanup_int(struct exec_closure *ec, int wstatus, bool init_only)
|
||||||
|
{
|
||||||
|
static struct exec_closure *saved_ec;
|
||||||
|
debug_decl(pty_cleanup, SUDO_DEBUG_EXEC);
|
||||||
|
|
||||||
|
/* If initializing, just store a pointer to the closure and return. */
|
||||||
|
if (init_only) {
|
||||||
|
saved_ec = ec;
|
||||||
|
debug_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Use the stored closure if one is not specified. */
|
||||||
|
if (ec == NULL) {
|
||||||
|
if (saved_ec == NULL)
|
||||||
|
debug_return;
|
||||||
|
ec = saved_ec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Restore terminal settings. */
|
||||||
|
if (ec->term_raw) {
|
||||||
|
/* Only restore the terminal if sudo is the foreground process. */
|
||||||
|
const pid_t tcpgrp = tcgetpgrp(io_fds[SFD_USERTTY]);
|
||||||
|
if (tcpgrp == ec->ppgrp) {
|
||||||
|
if (sudo_term_restore(io_fds[SFD_USERTTY], false))
|
||||||
|
ec->term_raw = false;
|
||||||
|
else
|
||||||
|
sudo_warn("%s", U_("unable to restore terminal settings"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update utmp */
|
||||||
|
if (utmp_user != NULL)
|
||||||
|
utmp_logout(ptyname, wstatus);
|
||||||
|
|
||||||
|
debug_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
pty_cleanup(struct exec_closure *ec, int wstatus)
|
||||||
|
{
|
||||||
|
pty_cleanup_int(ec, wstatus, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
pty_cleanup_init(struct exec_closure *ec)
|
||||||
|
{
|
||||||
|
pty_cleanup_int(ec, 0, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Cleanup hook for sudo_fatal()/sudo_fatalx()
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
pty_cleanup_hook(void)
|
||||||
|
{
|
||||||
|
pty_cleanup_int(NULL, 0, false);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make the tty follower the controlling tty.
|
* Make the tty follower the controlling tty.
|
||||||
* This is only used by the monitor but ptyname[] is static.
|
* This is only used by the monitor but ptyname[] is static.
|
||||||
@@ -184,17 +228,18 @@ resume_terminal(struct exec_closure *ec)
|
|||||||
}
|
}
|
||||||
sync_ttysize(ec);
|
sync_ttysize(ec);
|
||||||
|
|
||||||
sudo_debug_printf(SUDO_DEBUG_INFO, "parent is in %s, ttymode %d -> %d",
|
sudo_debug_printf(SUDO_DEBUG_INFO, "parent is in %s (%s -> %s)",
|
||||||
ec->foreground ? "foreground" : "background", ttymode,
|
ec->foreground ? "foreground" : "background",
|
||||||
ec->foreground ? TERM_RAW : TERM_COOKED);
|
ec->term_raw ? "raw" : "cooked",
|
||||||
|
ec->foreground ? "raw" : "cooked");
|
||||||
|
|
||||||
if (ec->foreground) {
|
if (ec->foreground) {
|
||||||
/* Foreground process, set tty to raw mode. */
|
/* Foreground process, set tty to raw mode. */
|
||||||
if (sudo_term_raw(io_fds[SFD_USERTTY], 0))
|
if (sudo_term_raw(io_fds[SFD_USERTTY], 0))
|
||||||
ttymode = TERM_RAW;
|
ec->term_raw = true;
|
||||||
} else {
|
} else {
|
||||||
/* Background process, no access to tty. */
|
/* Background process, no access to tty. */
|
||||||
ttymode = TERM_COOKED;
|
ec->term_raw = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug_return_bool(true);
|
debug_return_bool(true);
|
||||||
@@ -244,9 +289,9 @@ suspend_sudo_pty(struct exec_closure *ec, int signo)
|
|||||||
sudo_debug_printf(SUDO_DEBUG_INFO,
|
sudo_debug_printf(SUDO_DEBUG_INFO,
|
||||||
"%s: command received SIG%s, parent running in the foregound",
|
"%s: command received SIG%s, parent running in the foregound",
|
||||||
__func__, signame);
|
__func__, signame);
|
||||||
if (ttymode != TERM_RAW) {
|
if (!ec->term_raw) {
|
||||||
if (sudo_term_raw(io_fds[SFD_USERTTY], 0))
|
if (sudo_term_raw(io_fds[SFD_USERTTY], 0))
|
||||||
ttymode = TERM_RAW;
|
ec->term_raw = true;
|
||||||
}
|
}
|
||||||
ret = SIGCONT_FG; /* resume command in foreground */
|
ret = SIGCONT_FG; /* resume command in foreground */
|
||||||
break;
|
break;
|
||||||
@@ -259,8 +304,10 @@ suspend_sudo_pty(struct exec_closure *ec, int signo)
|
|||||||
del_io_events(true);
|
del_io_events(true);
|
||||||
|
|
||||||
/* Restore original tty mode before suspending. */
|
/* Restore original tty mode before suspending. */
|
||||||
if (ttymode != TERM_COOKED) {
|
if (ec->term_raw) {
|
||||||
if (!sudo_term_restore(io_fds[SFD_USERTTY], false))
|
if (sudo_term_restore(io_fds[SFD_USERTTY], false))
|
||||||
|
ec->term_raw = false;
|
||||||
|
else
|
||||||
sudo_warn("%s", U_("unable to restore terminal settings"));
|
sudo_warn("%s", U_("unable to restore terminal settings"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,7 +364,7 @@ suspend_sudo_pty(struct exec_closure *ec, int signo)
|
|||||||
* command will be runnable. Otherwise, we can get into a
|
* command will be runnable. Otherwise, we can get into a
|
||||||
* situation where the command will immediately suspend itself.
|
* situation where the command will immediately suspend itself.
|
||||||
*/
|
*/
|
||||||
ret = ttymode == TERM_RAW ? SIGCONT_FG : SIGCONT_BG;
|
ret = ec->term_raw ? SIGCONT_FG : SIGCONT_BG;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -512,7 +559,7 @@ write_callback(int fd, int what, void *v)
|
|||||||
*/
|
*/
|
||||||
if (iob->revent != NULL && iob->len != sizeof(iob->buf)) {
|
if (iob->revent != NULL && iob->len != sizeof(iob->buf)) {
|
||||||
if (!USERTTY_EVENT(iob->revent) ||
|
if (!USERTTY_EVENT(iob->revent) ||
|
||||||
(ttymode == TERM_RAW && iob->ec->cmnd_pid != -1)) {
|
(iob->ec->term_raw && iob->ec->cmnd_pid != -1)) {
|
||||||
if (sudo_ev_add(evbase, iob->revent, NULL, false) == -1)
|
if (sudo_ev_add(evbase, iob->revent, NULL, false) == -1)
|
||||||
sudo_fatal("%s", U_("unable to add event to queue"));
|
sudo_fatal("%s", U_("unable to add event to queue"));
|
||||||
}
|
}
|
||||||
@@ -542,19 +589,8 @@ pty_finish(struct exec_closure *ec, struct command_status *cstat)
|
|||||||
del_io_events(false);
|
del_io_events(false);
|
||||||
free_io_bufs();
|
free_io_bufs();
|
||||||
|
|
||||||
/* Restore terminal settings. */
|
/* Restore terminal settings and update utmp. */
|
||||||
if (ttymode != TERM_COOKED) {
|
pty_cleanup(ec, cstat->type == CMD_WSTATUS ? cstat->val : 0);
|
||||||
/* Only restore the terminal if sudo is the foreground process. */
|
|
||||||
const pid_t tcpgrp = tcgetpgrp(io_fds[SFD_USERTTY]);
|
|
||||||
if (tcpgrp == ec->ppgrp) {
|
|
||||||
if (!sudo_term_restore(io_fds[SFD_USERTTY], false))
|
|
||||||
sudo_warn("%s", U_("unable to restore terminal settings"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update utmp */
|
|
||||||
if (utmp_user != NULL)
|
|
||||||
utmp_logout(ptyname, cstat->type == CMD_WSTATUS ? cstat->val : 0);
|
|
||||||
|
|
||||||
debug_return;
|
debug_return;
|
||||||
}
|
}
|
||||||
@@ -703,7 +739,7 @@ backchannel_cb(int fd, int what, void *v)
|
|||||||
signo = suspend_sudo_pty(ec, WSTOPSIG(cstat.val));
|
signo = suspend_sudo_pty(ec, WSTOPSIG(cstat.val));
|
||||||
schedule_signal(ec, signo);
|
schedule_signal(ec, signo);
|
||||||
/* Re-enable I/O events */
|
/* Re-enable I/O events */
|
||||||
add_io_events(ec->evbase);
|
add_io_events(ec);
|
||||||
} else {
|
} else {
|
||||||
/* Command exited or was killed, either way we are done. */
|
/* Command exited or was killed, either way we are done. */
|
||||||
sudo_debug_printf(SUDO_DEBUG_INFO, "command exited or was killed");
|
sudo_debug_printf(SUDO_DEBUG_INFO, "command exited or was killed");
|
||||||
@@ -798,7 +834,7 @@ handle_sigchld_pty(struct exec_closure *ec)
|
|||||||
kill(pid, SIGCONT);
|
kill(pid, SIGCONT);
|
||||||
schedule_signal(ec, n);
|
schedule_signal(ec, n);
|
||||||
/* Re-enable I/O events */
|
/* Re-enable I/O events */
|
||||||
add_io_events(ec->evbase);
|
add_io_events(ec);
|
||||||
} else {
|
} else {
|
||||||
sudo_debug_printf(SUDO_DEBUG_WARN,
|
sudo_debug_printf(SUDO_DEBUG_WARN,
|
||||||
"%s: unexpected wait status 0x%x for process (%d)",
|
"%s: unexpected wait status 0x%x for process (%d)",
|
||||||
@@ -1076,7 +1112,8 @@ exec_pty(struct command_details *details, struct command_status *cstat)
|
|||||||
debug_return_bool(false);
|
debug_return_bool(false);
|
||||||
|
|
||||||
/* Register cleanup function */
|
/* Register cleanup function */
|
||||||
sudo_fatal_callback_register(pty_cleanup);
|
pty_cleanup_init(&ec);
|
||||||
|
sudo_fatal_callback_register(pty_cleanup_hook);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We communicate with the monitor over a bi-directional pair of sockets.
|
* We communicate with the monitor over a bi-directional pair of sockets.
|
||||||
@@ -1253,7 +1290,7 @@ exec_pty(struct command_details *details, struct command_status *cstat)
|
|||||||
if (ec.foreground) {
|
if (ec.foreground) {
|
||||||
if (!pipeline && !ISSET(details->flags, CD_EXEC_BG)) {
|
if (!pipeline && !ISSET(details->flags, CD_EXEC_BG)) {
|
||||||
if (sudo_term_raw(io_fds[SFD_USERTTY], 0))
|
if (sudo_term_raw(io_fds[SFD_USERTTY], 0))
|
||||||
ttymode = TERM_RAW;
|
ec.term_raw = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1289,7 +1326,7 @@ exec_pty(struct command_details *details, struct command_status *cstat)
|
|||||||
close(io_pipe[STDERR_FILENO][0]);
|
close(io_pipe[STDERR_FILENO][0]);
|
||||||
|
|
||||||
/* Only run the cleanup hook in the parent. */
|
/* Only run the cleanup hook in the parent. */
|
||||||
sudo_fatal_callback_deregister(pty_cleanup);
|
sudo_fatal_callback_deregister(pty_cleanup_hook);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If stdin/stdout is not a tty, start command in the background
|
* If stdin/stdout is not a tty, start command in the background
|
||||||
@@ -1372,7 +1409,7 @@ exec_pty(struct command_details *details, struct command_status *cstat)
|
|||||||
* and pass output from leader to stdout and IO plugin.
|
* and pass output from leader to stdout and IO plugin.
|
||||||
* Try to recover on ENXIO, it means the tty was revoked.
|
* Try to recover on ENXIO, it means the tty was revoked.
|
||||||
*/
|
*/
|
||||||
add_io_events(ec.evbase);
|
add_io_events(&ec);
|
||||||
do {
|
do {
|
||||||
if (sudo_ev_dispatch(ec.evbase) == -1)
|
if (sudo_ev_dispatch(ec.evbase) == -1)
|
||||||
sudo_warn("%s", U_("error in event loop"));
|
sudo_warn("%s", U_("error in event loop"));
|
||||||
|
@@ -81,6 +81,7 @@ struct exec_closure {
|
|||||||
short rows;
|
short rows;
|
||||||
short cols;
|
short cols;
|
||||||
bool foreground;
|
bool foreground;
|
||||||
|
bool term_raw;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -201,7 +202,7 @@ void io_buf_new(int rfd, int wfd, bool (*action)(const char *, unsigned int, str
|
|||||||
int safe_close(int fd);
|
int safe_close(int fd);
|
||||||
void ev_free_by_fd(struct sudo_event_base *evbase, int fd);
|
void ev_free_by_fd(struct sudo_event_base *evbase, int fd);
|
||||||
void free_io_bufs(void);
|
void free_io_bufs(void);
|
||||||
void add_io_events(struct sudo_event_base *evbase);
|
void add_io_events(struct exec_closure *ec);
|
||||||
void del_io_events(bool nonblocking);
|
void del_io_events(bool nonblocking);
|
||||||
void init_ttyblock(void);
|
void init_ttyblock(void);
|
||||||
extern struct io_buffer_list iobufs;
|
extern struct io_buffer_list iobufs;
|
||||||
|
Reference in New Issue
Block a user