Annotation of embedaddon/sudo/src/exec_pty.c, revision 1.1.1.5

1.1       misho       1: /*
1.1.1.4   misho       2:  * Copyright (c) 2009-2013 Todd C. Miller <Todd.Miller@courtesan.com>
1.1       misho       3:  *
                      4:  * Permission to use, copy, modify, and distribute this software for any
                      5:  * purpose with or without fee is hereby granted, provided that the above
                      6:  * copyright notice and this permission notice appear in all copies.
                      7:  *
                      8:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                      9:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     10:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     11:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     12:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     13:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     14:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     15:  */
                     16: 
                     17: #include <config.h>
                     18: 
                     19: #include <sys/types.h>
                     20: #include <sys/socket.h>
                     21: #include <sys/time.h>
                     22: #include <sys/wait.h>
                     23: #include <sys/ioctl.h>
                     24: #include <stdio.h>
                     25: #ifdef STDC_HEADERS
                     26: # include <stdlib.h>
                     27: # include <stddef.h>
                     28: #else
                     29: # ifdef HAVE_STDLIB_H
                     30: #  include <stdlib.h>
                     31: # endif
                     32: #endif /* STDC_HEADERS */
                     33: #ifdef HAVE_STRING_H
                     34: # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
                     35: #  include <memory.h>
                     36: # endif
                     37: # include <string.h>
                     38: #endif /* HAVE_STRING_H */
                     39: #ifdef HAVE_STRINGS_H
                     40: # include <strings.h>
                     41: #endif /* HAVE_STRINGS_H */
                     42: #ifdef HAVE_UNISTD_H
                     43: # include <unistd.h>
                     44: #endif /* HAVE_UNISTD_H */
1.1.1.5 ! misho      45: #ifdef TIME_WITH_SYS_TIME
1.1       misho      46: # include <time.h>
                     47: #endif
                     48: #include <errno.h>
                     49: #include <fcntl.h>
                     50: #include <signal.h>
                     51: #include <termios.h>
                     52: 
                     53: #include "sudo.h"
1.1.1.5 ! misho      54: #include "sudo_event.h"
1.1       misho      55: #include "sudo_exec.h"
                     56: #include "sudo_plugin.h"
                     57: #include "sudo_plugin_int.h"
                     58: 
                     59: #define SFD_STDIN      0
                     60: #define SFD_STDOUT     1
                     61: #define SFD_STDERR     2
                     62: #define SFD_MASTER     3
                     63: #define SFD_SLAVE      4
                     64: #define SFD_USERTTY    5
                     65: 
1.1.1.5 ! misho      66: /* Evaluates to true if the event has /dev/tty as its fd. */
        !            67: #define USERTTY_EVENT(_ev)     (sudo_ev_get_fd((_ev)) == io_fds[SFD_USERTTY])
        !            68: 
1.1       misho      69: #define TERM_COOKED    0
                     70: #define TERM_RAW       1
                     71: 
                     72: /* Compatibility with older tty systems. */
                     73: #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
                     74: # define TIOCGWINSZ    TIOCGSIZE
                     75: # define TIOCSWINSZ    TIOCSSIZE
                     76: # define winsize       ttysize
                     77: #endif
                     78: 
                     79: struct io_buffer {
1.1.1.5 ! misho      80:     SLIST_ENTRY(io_buffer) entries;
        !            81:     struct sudo_event *revent;
        !            82:     struct sudo_event *wevent;
        !            83:     bool (*action)(const char *buf, unsigned int len);
1.1       misho      84:     int len; /* buffer length (how much produced) */
                     85:     int off; /* write position (how much already consumed) */
1.1.1.4   misho      86:     char buf[32 * 1024];
1.1       misho      87: };
                     88: 
1.1.1.5 ! misho      89: SLIST_HEAD(io_buffer_list, io_buffer);
        !            90: 
1.1       misho      91: static char slavename[PATH_MAX];
1.1.1.2   misho      92: static bool foreground, pipeline, tty_initialized;
1.1       misho      93: static int io_fds[6] = { -1, -1, -1, -1, -1, -1};
                     94: static int ttymode = TERM_COOKED;
1.1.1.4   misho      95: static pid_t ppgrp, cmnd_pgrp, mon_pgrp;
1.1       misho      96: static sigset_t ttyblock;
1.1.1.5 ! misho      97: static struct io_buffer_list iobufs;
1.1       misho      98: 
1.1.1.5 ! misho      99: static void del_io_events(void);
1.1       misho     100: static int exec_monitor(struct command_details *details, int backchannel);
1.1.1.4   misho     101: static void exec_pty(struct command_details *details,
1.1.1.5 ! misho     102:     struct command_status *cstat, int errfd);
1.1       misho     103: static void sigwinch(int s);
                    104: static void sync_ttysize(int src, int dst);
1.1.1.2   misho     105: static void deliver_signal(pid_t pid, int signo, bool from_parent);
1.1       misho     106: static int safe_close(int fd);
1.1.1.5 ! misho     107: static void ev_free_by_fd(struct sudo_event_base *evbase, int fd);
1.1.1.2   misho     108: static void check_foreground(void);
1.1       misho     109: 
                    110: /*
1.1.1.4   misho     111:  * Cleanup hook for fatal()/fatalx()
1.1       misho     112:  */
1.1.1.4   misho     113: static void
                    114: pty_cleanup(void)
1.1       misho     115: {
1.1.1.2   misho     116:     debug_decl(cleanup, SUDO_DEBUG_EXEC);
                    117: 
1.1.1.5 ! misho     118:     if (!TAILQ_EMPTY(&io_plugins) && io_fds[SFD_USERTTY] != -1)
        !           119:        term_restore(io_fds[SFD_USERTTY], 0);
1.1       misho     120: #ifdef HAVE_SELINUX
                    121:     selinux_restore_tty();
                    122: #endif
                    123:     utmp_logout(slavename, 0); /* XXX - only if CD_SET_UTMP */
1.1.1.2   misho     124: 
                    125:     debug_return;
1.1       misho     126: }
                    127: 
                    128: /*
1.1.1.3   misho     129:  * Generic handler for signals recieved by the monitor process.
                    130:  * The other end of signal_pipe is checked in the monitor event loop.
                    131:  */
                    132: #ifdef SA_SIGINFO
1.1.1.5 ! misho     133: static void
1.1.1.3   misho     134: mon_handler(int s, siginfo_t *info, void *context)
                    135: {
                    136:     unsigned char signo = (unsigned char)s;
                    137: 
                    138:     /*
                    139:      * If the signal came from the command we ran, just ignore
                    140:      * it since we don't want the command to indirectly kill itself.
                    141:      * This can happen with, e.g. BSD-derived versions of reboot
                    142:      * that call kill(-1, SIGTERM) to kill all other processes.
                    143:      */
                    144:     if (info != NULL && info->si_code == SI_USER && info->si_pid == cmnd_pid)
                    145:            return;
                    146: 
                    147:     /*
                    148:      * The pipe is non-blocking, if we overflow the kernel's pipe
                    149:      * buffer we drop the signal.  This is not a problem in practice.
                    150:      */
                    151:     ignore_result(write(signal_pipe[1], &signo, sizeof(signo)));
                    152: }
                    153: #else
1.1.1.5 ! misho     154: static void
1.1.1.3   misho     155: mon_handler(int s)
                    156: {
                    157:     unsigned char signo = (unsigned char)s;
                    158: 
                    159:     /*
                    160:      * The pipe is non-blocking, if we overflow the kernel's pipe
                    161:      * buffer we drop the signal.  This is not a problem in practice.
                    162:      */
                    163:     ignore_result(write(signal_pipe[1], &signo, sizeof(signo)));
                    164: }
                    165: #endif
                    166: 
                    167: /*
1.1       misho     168:  * Allocate a pty if /dev/tty is a tty.
                    169:  * Fills in io_fds[SFD_USERTTY], io_fds[SFD_MASTER], io_fds[SFD_SLAVE]
                    170:  * and slavename globals.
                    171:  */
                    172: void
                    173: pty_setup(uid_t uid, const char *tty, const char *utmp_user)
                    174: {
1.1.1.2   misho     175:     debug_decl(pty_setup, SUDO_DEBUG_EXEC);
                    176: 
1.1       misho     177:     io_fds[SFD_USERTTY] = open(_PATH_TTY, O_RDWR|O_NOCTTY, 0);
                    178:     if (io_fds[SFD_USERTTY] != -1) {
                    179:        if (!get_pty(&io_fds[SFD_MASTER], &io_fds[SFD_SLAVE],
                    180:            slavename, sizeof(slavename), uid))
1.1.1.5 ! misho     181:            fatal(U_("unable to allocate pty"));
1.1       misho     182:        /* Add entry to utmp/utmpx? */
                    183:        if (utmp_user != NULL)
                    184:            utmp_login(tty, slavename, io_fds[SFD_SLAVE], utmp_user);
                    185:     }
1.1.1.2   misho     186: 
                    187:     debug_return;
1.1       misho     188: }
                    189: 
                    190: /* Call I/O plugin tty input log method. */
1.1.1.2   misho     191: static bool
1.1       misho     192: log_ttyin(const char *buf, unsigned int n)
                    193: {
                    194:     struct plugin_container *plugin;
                    195:     sigset_t omask;
1.1.1.2   misho     196:     bool rval = true;
                    197:     debug_decl(log_ttyin, SUDO_DEBUG_EXEC);
1.1       misho     198: 
                    199:     sigprocmask(SIG_BLOCK, &ttyblock, &omask);
1.1.1.5 ! misho     200:     TAILQ_FOREACH(plugin, &io_plugins, entries) {
1.1       misho     201:        if (plugin->u.io->log_ttyin) {
                    202:            if (!plugin->u.io->log_ttyin(buf, n)) {
1.1.1.2   misho     203:                rval = false;
1.1       misho     204:                break;
                    205:            }
                    206:        }
                    207:     }
                    208:     sigprocmask(SIG_SETMASK, &omask, NULL);
1.1.1.2   misho     209: 
                    210:     debug_return_bool(rval);
1.1       misho     211: }
                    212: 
                    213: /* Call I/O plugin stdin log method. */
1.1.1.2   misho     214: static bool
1.1       misho     215: log_stdin(const char *buf, unsigned int n)
                    216: {
                    217:     struct plugin_container *plugin;
                    218:     sigset_t omask;
1.1.1.2   misho     219:     bool rval = true;
                    220:     debug_decl(log_stdin, SUDO_DEBUG_EXEC);
1.1       misho     221: 
                    222:     sigprocmask(SIG_BLOCK, &ttyblock, &omask);
1.1.1.5 ! misho     223:     TAILQ_FOREACH(plugin, &io_plugins, entries) {
1.1       misho     224:        if (plugin->u.io->log_stdin) {
                    225:            if (!plugin->u.io->log_stdin(buf, n)) {
1.1.1.2   misho     226:                rval = false;
1.1       misho     227:                break;
                    228:            }
                    229:        }
                    230:     }
                    231:     sigprocmask(SIG_SETMASK, &omask, NULL);
1.1.1.2   misho     232: 
                    233:     debug_return_bool(rval);
1.1       misho     234: }
                    235: 
                    236: /* Call I/O plugin tty output log method. */
1.1.1.2   misho     237: static bool
1.1       misho     238: log_ttyout(const char *buf, unsigned int n)
                    239: {
                    240:     struct plugin_container *plugin;
                    241:     sigset_t omask;
1.1.1.2   misho     242:     bool rval = true;
                    243:     debug_decl(log_ttyout, SUDO_DEBUG_EXEC);
1.1       misho     244: 
                    245:     sigprocmask(SIG_BLOCK, &ttyblock, &omask);
1.1.1.5 ! misho     246:     TAILQ_FOREACH(plugin, &io_plugins, entries) {
1.1       misho     247:        if (plugin->u.io->log_ttyout) {
                    248:            if (!plugin->u.io->log_ttyout(buf, n)) {
1.1.1.2   misho     249:                rval = false;
1.1       misho     250:                break;
                    251:            }
                    252:        }
                    253:     }
                    254:     sigprocmask(SIG_SETMASK, &omask, NULL);
1.1.1.2   misho     255: 
                    256:     debug_return_bool(rval);
1.1       misho     257: }
                    258: 
                    259: /* Call I/O plugin stdout log method. */
1.1.1.2   misho     260: static bool
1.1       misho     261: log_stdout(const char *buf, unsigned int n)
                    262: {
                    263:     struct plugin_container *plugin;
                    264:     sigset_t omask;
1.1.1.2   misho     265:     bool rval = true;
                    266:     debug_decl(log_stdout, SUDO_DEBUG_EXEC);
1.1       misho     267: 
                    268:     sigprocmask(SIG_BLOCK, &ttyblock, &omask);
1.1.1.5 ! misho     269:     TAILQ_FOREACH(plugin, &io_plugins, entries) {
1.1       misho     270:        if (plugin->u.io->log_stdout) {
                    271:            if (!plugin->u.io->log_stdout(buf, n)) {
1.1.1.2   misho     272:                rval = false;
1.1       misho     273:                break;
                    274:            }
                    275:        }
                    276:     }
                    277:     sigprocmask(SIG_SETMASK, &omask, NULL);
1.1.1.2   misho     278: 
                    279:     debug_return_bool(rval);
1.1       misho     280: }
                    281: 
                    282: /* Call I/O plugin stderr log method. */
1.1.1.2   misho     283: static bool
1.1       misho     284: log_stderr(const char *buf, unsigned int n)
                    285: {
                    286:     struct plugin_container *plugin;
                    287:     sigset_t omask;
1.1.1.2   misho     288:     bool rval = true;
                    289:     debug_decl(log_stderr, SUDO_DEBUG_EXEC);
1.1       misho     290: 
                    291:     sigprocmask(SIG_BLOCK, &ttyblock, &omask);
1.1.1.5 ! misho     292:     TAILQ_FOREACH(plugin, &io_plugins, entries) {
1.1       misho     293:        if (plugin->u.io->log_stderr) {
                    294:            if (!plugin->u.io->log_stderr(buf, n)) {
1.1.1.2   misho     295:                rval = false;
1.1       misho     296:                break;
                    297:            }
                    298:        }
                    299:     }
                    300:     sigprocmask(SIG_SETMASK, &omask, NULL);
1.1.1.2   misho     301: 
                    302:     debug_return_bool(rval);
1.1       misho     303: }
                    304: 
                    305: /*
                    306:  * Check whether we are running in the foregroup.
                    307:  * Updates the foreground global and does lazy init of the
                    308:  * the pty slave as needed.
                    309:  */
                    310: static void
                    311: check_foreground(void)
                    312: {
1.1.1.2   misho     313:     debug_decl(check_foreground, SUDO_DEBUG_EXEC);
                    314: 
1.1       misho     315:     if (io_fds[SFD_USERTTY] != -1) {
                    316:        foreground = tcgetpgrp(io_fds[SFD_USERTTY]) == ppgrp;
                    317:        if (foreground && !tty_initialized) {
                    318:            if (term_copy(io_fds[SFD_USERTTY], io_fds[SFD_SLAVE])) {
1.1.1.2   misho     319:                tty_initialized = true;
1.1       misho     320:                sync_ttysize(io_fds[SFD_USERTTY], io_fds[SFD_SLAVE]);
                    321:            }
                    322:        }
                    323:     }
1.1.1.2   misho     324: 
                    325:     debug_return;
1.1       misho     326: }
                    327: 
                    328: /*
                    329:  * Suspend sudo if the underlying command is suspended.
1.1.1.3   misho     330:  * Returns SIGCONT_FG if the command should be resumed in the
1.1       misho     331:  * foreground or SIGCONT_BG if it is a background process.
                    332:  */
                    333: int
                    334: suspend_parent(int signo)
                    335: {
1.1.1.3   misho     336:     char signame[SIG2STR_MAX];
1.1       misho     337:     sigaction_t sa, osa;
1.1.1.4   misho     338:     int n, rval = 0;
1.1.1.2   misho     339:     debug_decl(suspend_parent, SUDO_DEBUG_EXEC);
1.1       misho     340: 
                    341:     switch (signo) {
                    342:     case SIGTTOU:
                    343:     case SIGTTIN:
                    344:        /*
1.1.1.4   misho     345:         * If sudo is already the foreground process, just resume the command
                    346:         * in the foreground.  If not, we'll suspend sudo and resume later.
1.1       misho     347:         */
                    348:        if (!foreground)
                    349:            check_foreground();
                    350:        if (foreground) {
                    351:            if (ttymode != TERM_RAW) {
                    352:                do {
                    353:                    n = term_raw(io_fds[SFD_USERTTY], 0);
                    354:                } while (!n && errno == EINTR);
                    355:                ttymode = TERM_RAW;
                    356:            }
1.1.1.3   misho     357:            rval = SIGCONT_FG; /* resume command in foreground */
1.1       misho     358:            break;
                    359:        }
                    360:        /* FALLTHROUGH */
                    361:     case SIGSTOP:
                    362:     case SIGTSTP:
1.1.1.5 ! misho     363:        /* Flush any remaining output and deschedule I/O events. */
        !           364:        del_io_events();
1.1       misho     365: 
                    366:        /* Restore original tty mode before suspending. */
1.1.1.5 ! misho     367:        if (ttymode != TERM_COOKED)
        !           368:            term_restore(io_fds[SFD_USERTTY], 0);
1.1       misho     369: 
1.1.1.3   misho     370:        if (sig2str(signo, signame) == -1)
                    371:            snprintf(signame, sizeof(signame), "%d", signo);
                    372: 
                    373:        /* Suspend self and continue command when we resume. */
1.1.1.4   misho     374:        if (signo != SIGSTOP) {
                    375:            memset(&sa, 0, sizeof(sa));
                    376:            sigemptyset(&sa.sa_mask);
                    377:            sa.sa_flags = SA_RESTART;
                    378:            sa.sa_handler = SIG_DFL;
                    379:            sudo_sigaction(signo, &sa, &osa);
                    380:        }
1.1.1.3   misho     381:        sudo_debug_printf(SUDO_DEBUG_INFO, "kill parent SIG%s", signame);
1.1       misho     382:        if (killpg(ppgrp, signo) != 0)
1.1.1.3   misho     383:            warning("killpg(%d, SIG%s)", (int)ppgrp, signame);
1.1       misho     384: 
                    385:        /* Check foreground/background status on resume. */
                    386:        check_foreground();
                    387: 
                    388:        /*
1.1.1.4   misho     389:         * We always resume the command in the foreground if sudo itself
                    390:         * is the foreground process.  This helps work around poorly behaved
                    391:         * programs that catch SIGTTOU/SIGTTIN but suspend themselves with
                    392:         * SIGSTOP.  At worst, sudo will go into the background but upon
                    393:         * resume the command will be runnable.  Otherwise, we can get into
                    394:         * a situation where the command will immediately suspend itself.
1.1       misho     395:         */
1.1.1.2   misho     396:        sudo_debug_printf(SUDO_DEBUG_INFO, "parent is in %s, ttymode %d -> %d",
1.1.1.4   misho     397:            foreground ? "foreground" : "background", ttymode,
                    398:            foreground ? TERM_RAW : TERM_COOKED);
1.1       misho     399: 
1.1.1.4   misho     400:        if (foreground) {
                    401:            /* Foreground process, set tty to raw mode. */
                    402:            do {
                    403:                n = term_raw(io_fds[SFD_USERTTY], 0);
                    404:            } while (!n && errno == EINTR);
                    405:            ttymode = TERM_RAW;
                    406:        } else {
                    407:            /* Background process, no access to tty. */
                    408:            ttymode = TERM_COOKED;
1.1       misho     409:        }
                    410: 
1.1.1.4   misho     411:        if (signo != SIGSTOP)
                    412:            sudo_sigaction(signo, &osa, NULL);
1.1       misho     413:        rval = ttymode == TERM_RAW ? SIGCONT_FG : SIGCONT_BG;
                    414:        break;
                    415:     }
                    416: 
1.1.1.2   misho     417:     debug_return_int(rval);
1.1       misho     418: }
                    419: 
                    420: /*
1.1.1.3   misho     421:  * Kill command with increasing urgency.
1.1       misho     422:  */
                    423: void
1.1.1.3   misho     424: terminate_command(pid_t pid, bool use_pgrp)
1.1       misho     425: {
1.1.1.3   misho     426:     debug_decl(terminate_command, SUDO_DEBUG_EXEC);
1.1.1.2   misho     427: 
1.1       misho     428:     /*
                    429:      * Note that SIGCHLD will interrupt the sleep()
                    430:      */
                    431:     if (use_pgrp) {
1.1.1.2   misho     432:        sudo_debug_printf(SUDO_DEBUG_INFO, "killpg %d SIGHUP", (int)pid);
1.1       misho     433:        killpg(pid, SIGHUP);
1.1.1.2   misho     434:        sudo_debug_printf(SUDO_DEBUG_INFO, "killpg %d SIGTERM", (int)pid);
1.1       misho     435:        killpg(pid, SIGTERM);
                    436:        sleep(2);
1.1.1.2   misho     437:        sudo_debug_printf(SUDO_DEBUG_INFO, "killpg %d SIGKILL", (int)pid);
1.1       misho     438:        killpg(pid, SIGKILL);
                    439:     } else {
1.1.1.2   misho     440:        sudo_debug_printf(SUDO_DEBUG_INFO, "kill %d SIGHUP", (int)pid);
1.1       misho     441:        kill(pid, SIGHUP);
1.1.1.2   misho     442:        sudo_debug_printf(SUDO_DEBUG_INFO, "kill %d SIGTERM", (int)pid);
1.1       misho     443:        kill(pid, SIGTERM);
                    444:        sleep(2);
1.1.1.2   misho     445:        sudo_debug_printf(SUDO_DEBUG_INFO, "kill %d SIGKILL", (int)pid);
1.1       misho     446:        kill(pid, SIGKILL);
                    447:     }
1.1.1.2   misho     448: 
                    449:     debug_return;
1.1       misho     450: }
                    451: 
                    452: /*
1.1.1.5 ! misho     453:  * Read/write an iobuf that is ready.
1.1       misho     454:  */
1.1.1.5 ! misho     455: static void
        !           456: io_callback(int fd, int what, void *v)
1.1       misho     457: {
1.1.1.5 ! misho     458:     struct io_buffer *iob = v;
        !           459:     struct sudo_event_base *evbase;
        !           460:     int n;
        !           461:     debug_decl(io_callback, SUDO_DEBUG_EXEC);
1.1       misho     462: 
1.1.1.5 ! misho     463:     if (ISSET(what, SUDO_EV_READ)) {
        !           464:        evbase = sudo_ev_get_base(iob->revent);
        !           465:        do {
        !           466:            n = read(fd, iob->buf + iob->len, sizeof(iob->buf) - iob->len);
        !           467:        } while (n == -1 && errno == EINTR);
        !           468:        switch (n) {
        !           469:            case -1:
        !           470:                if (errno == EAGAIN)
1.1       misho     471:                    break;
1.1.1.5 ! misho     472:                /* treat read error as fatal and close the fd */
        !           473:                sudo_debug_printf(SUDO_DEBUG_ERROR,
        !           474:                    "error reading fd %d: %s", fd, strerror(errno));
        !           475:                /* FALLTHROUGH */
        !           476:            case 0:
        !           477:                /* got EOF or pty has gone away */
        !           478:                if (n == 0) {
1.1.1.2   misho     479:                    sudo_debug_printf(SUDO_DEBUG_INFO,
1.1.1.5 ! misho     480:                        "read EOF from fd %d", fd);
1.1       misho     481:                }
1.1.1.5 ! misho     482:                safe_close(fd);
        !           483:                ev_free_by_fd(evbase, fd);
        !           484:                /* If writer already consumed the buffer, close it too. */
        !           485:                if (iob->wevent != NULL && iob->off == iob->len) {
        !           486:                    safe_close(sudo_ev_get_fd(iob->wevent));
        !           487:                    ev_free_by_fd(evbase, sudo_ev_get_fd(iob->wevent));
        !           488:                    iob->off = iob->len = 0;
1.1.1.2   misho     489:                }
1.1.1.5 ! misho     490:                break;
        !           491:            default:
1.1.1.2   misho     492:                sudo_debug_printf(SUDO_DEBUG_INFO,
1.1.1.5 ! misho     493:                    "read %d bytes from fd %d", n, fd);
        !           494:                if (!iob->action(iob->buf + iob->len, n))
        !           495:                    terminate_command(cmnd_pid, true);
        !           496:                iob->len += n;
        !           497:                /* Enable writer if not /dev/tty or we are foreground pgrp. */
        !           498:                if (iob->wevent != NULL &&
        !           499:                    (foreground || !USERTTY_EVENT(iob->wevent))) {
        !           500:                    if (sudo_ev_add(evbase, iob->wevent, NULL, false) == -1)
        !           501:                        fatal(U_("unable to add event to queue"));
        !           502:                }
        !           503:                /* Re-enable reader if buffer is not full. */
        !           504:                if (iob->len != sizeof(iob->buf)) {
        !           505:                    if (sudo_ev_add(evbase, iob->revent, NULL, false) == -1)
        !           506:                        fatal(U_("unable to add event to queue"));
        !           507:                }
        !           508:                break;
1.1       misho     509:        }
                    510:     }
1.1.1.5 ! misho     511:     if (ISSET(what, SUDO_EV_WRITE)) {
        !           512:        evbase = sudo_ev_get_base(iob->wevent);
        !           513:        do {
        !           514:            n = write(fd, iob->buf + iob->off, iob->len - iob->off);
        !           515:        } while (n == -1 && errno == EINTR);
        !           516:        if (n == -1) {
        !           517:            switch (errno) {
        !           518:            case EPIPE:
        !           519:            case ENXIO:
        !           520:            case EIO:
        !           521:            case EBADF:
        !           522:                /* other end of pipe closed or pty revoked */
        !           523:                sudo_debug_printf(SUDO_DEBUG_INFO,
        !           524:                    "unable to write %d bytes to fd %d",
        !           525:                    iob->len - iob->off, fd);
        !           526:                if (iob->revent != NULL) {
        !           527:                    safe_close(sudo_ev_get_fd(iob->revent));
        !           528:                    ev_free_by_fd(evbase, sudo_ev_get_fd(iob->revent));
        !           529:                }
        !           530:                safe_close(fd);
        !           531:                ev_free_by_fd(evbase, fd);
        !           532:                break;
        !           533:            case EAGAIN:
        !           534:                /* not an error */
        !           535:                break;
        !           536:            default:
        !           537: #if 0 /* XXX -- how to set cstat? stash in iobufs instead? */
        !           538:                if (cstat != NULL) {
        !           539:                    cstat->type = CMD_ERRNO;
        !           540:                    cstat->val = errno;
        !           541:                }
        !           542: #endif /* XXX */
        !           543:                sudo_debug_printf(SUDO_DEBUG_ERROR,
        !           544:                    "error writing fd %d: %s", fd, strerror(errno));
        !           545:                sudo_ev_loopbreak(evbase);
        !           546:                break;
        !           547:            }
        !           548:        } else {
        !           549:            sudo_debug_printf(SUDO_DEBUG_INFO,
        !           550:                "wrote %d bytes to fd %d", n, fd);
        !           551:            iob->off += n;
        !           552:            /* Reset buffer if fully consumed. */
        !           553:            if (iob->off == iob->len) {
        !           554:                iob->off = iob->len = 0;
        !           555:                /* Forward the EOF from reader to writer. */
        !           556:                if (iob->revent == NULL) {
        !           557:                    safe_close(fd);
        !           558:                    ev_free_by_fd(evbase, fd);
        !           559:                }
        !           560:            }
        !           561:            /* Re-enable writer if buffer is not empty. */
        !           562:            if (iob->len > iob->off) {
        !           563:                if (sudo_ev_add(evbase, iob->wevent, NULL, false) == -1)
        !           564:                    fatal(U_("unable to add event to queue"));
        !           565:            }
        !           566:            /* Enable reader if buffer is not full. */
        !           567:            if (iob->revent != NULL &&
        !           568:                (ttymode == TERM_RAW || !USERTTY_EVENT(iob->revent))) {
        !           569:                if (iob->len != sizeof(iob->buf)) {
        !           570:                    if (sudo_ev_add(evbase, iob->revent, NULL, false) == -1)
        !           571:                        fatal(U_("unable to add event to queue"));
        !           572:                }
        !           573:            }
        !           574:        }
1.1       misho     575:     }
1.1.1.5 ! misho     576: }
        !           577: 
        !           578: static void
        !           579: io_buf_new(int rfd, int wfd, bool (*action)(const char *, unsigned int),
        !           580:     struct io_buffer_list *head)
        !           581: {
        !           582:     int n;
        !           583:     struct io_buffer *iob;
        !           584:     debug_decl(io_buf_new, SUDO_DEBUG_EXEC);
        !           585: 
        !           586:     /* Set non-blocking mode. */
        !           587:     n = fcntl(rfd, F_GETFL, 0);
        !           588:     if (n != -1 && !ISSET(n, O_NONBLOCK))
        !           589:        (void) fcntl(rfd, F_SETFL, n | O_NONBLOCK);
        !           590:     n = fcntl(wfd, F_GETFL, 0);
        !           591:     if (n != -1 && !ISSET(n, O_NONBLOCK))
        !           592:        (void) fcntl(wfd, F_SETFL, n | O_NONBLOCK);
        !           593: 
        !           594:     /* Allocate and add to head of list. */
        !           595:     iob = emalloc(sizeof(*iob));
        !           596:     iob->revent = sudo_ev_alloc(rfd, SUDO_EV_READ, io_callback, iob);
        !           597:     iob->wevent = sudo_ev_alloc(wfd, SUDO_EV_WRITE, io_callback, iob);
        !           598:     iob->len = 0;
        !           599:     iob->off = 0;
        !           600:     iob->action = action;
        !           601:     iob->buf[0] = '\0';
        !           602:     if (iob->revent == NULL || iob->wevent == NULL)
        !           603:        fatal(NULL);
        !           604:     SLIST_INSERT_HEAD(head, iob, entries);
        !           605: 
        !           606:     debug_return;
1.1       misho     607: }
                    608: 
                    609: /*
                    610:  * Fork a monitor process which runs the actual command as its own child
                    611:  * process with std{in,out,err} hooked up to the pty or pipes as appropriate.
                    612:  * Returns the child pid.
                    613:  */
                    614: int
1.1.1.5 ! misho     615: fork_pty(struct command_details *details, int sv[], sigset_t *omask)
1.1       misho     616: {
                    617:     struct command_status cstat;
                    618:     int io_pipe[3][2], n;
                    619:     sigaction_t sa;
1.1.1.3   misho     620:     sigset_t mask;
                    621:     pid_t child;
1.1.1.2   misho     622:     debug_decl(fork_pty, SUDO_DEBUG_EXEC);
1.1.1.4   misho     623: 
1.1       misho     624:     ppgrp = getpgrp(); /* parent's pgrp, so child can signal us */
1.1.1.4   misho     625: 
                    626:     memset(&sa, 0, sizeof(sa));
1.1       misho     627:     sigemptyset(&sa.sa_mask);
1.1.1.4   misho     628: 
1.1       misho     629:     if (io_fds[SFD_USERTTY] != -1) {
                    630:        sa.sa_flags = SA_RESTART;
                    631:        sa.sa_handler = sigwinch;
1.1.1.4   misho     632:        sudo_sigaction(SIGWINCH, &sa, NULL);
1.1       misho     633:     }
                    634: 
                    635:     /* So we can block tty-generated signals */
                    636:     sigemptyset(&ttyblock);
                    637:     sigaddset(&ttyblock, SIGINT);
                    638:     sigaddset(&ttyblock, SIGQUIT);
                    639:     sigaddset(&ttyblock, SIGTSTP);
                    640:     sigaddset(&ttyblock, SIGTTIN);
                    641:     sigaddset(&ttyblock, SIGTTOU);
                    642: 
                    643:     /*
                    644:      * Setup stdin/stdout/stderr for child, to be duped after forking.
                    645:      * In background mode there is no stdin.
                    646:      */
                    647:     if (!ISSET(details->flags, CD_BACKGROUND))
                    648:        io_fds[SFD_STDIN] = io_fds[SFD_SLAVE];
                    649:     io_fds[SFD_STDOUT] = io_fds[SFD_SLAVE];
                    650:     io_fds[SFD_STDERR] = io_fds[SFD_SLAVE];
                    651: 
                    652:     if (io_fds[SFD_USERTTY] != -1) {
                    653:        /* Read from /dev/tty, write to pty master */
                    654:        if (!ISSET(details->flags, CD_BACKGROUND)) {
1.1.1.5 ! misho     655:            io_buf_new(io_fds[SFD_USERTTY], io_fds[SFD_MASTER],
        !           656:                log_ttyin, &iobufs);
1.1       misho     657:        }
                    658: 
                    659:        /* Read from pty master, write to /dev/tty */
1.1.1.5 ! misho     660:        io_buf_new(io_fds[SFD_MASTER], io_fds[SFD_USERTTY],
        !           661:            log_ttyout, &iobufs);
1.1       misho     662: 
                    663:        /* Are we the foreground process? */
                    664:        foreground = tcgetpgrp(io_fds[SFD_USERTTY]) == ppgrp;
                    665:     }
                    666: 
                    667:     /*
                    668:      * If either stdin, stdout or stderr is not a tty we use a pipe
                    669:      * to interpose ourselves instead of duping the pty fd.
                    670:      */
                    671:     memset(io_pipe, 0, sizeof(io_pipe));
                    672:     if (io_fds[SFD_STDIN] == -1 || !isatty(STDIN_FILENO)) {
1.1.1.2   misho     673:        sudo_debug_printf(SUDO_DEBUG_INFO, "stdin not a tty, creating a pipe");
                    674:        pipeline = true;
1.1       misho     675:        if (pipe(io_pipe[STDIN_FILENO]) != 0)
1.1.1.5 ! misho     676:            fatal(U_("unable to create pipe"));
        !           677:        io_buf_new(STDIN_FILENO, io_pipe[STDIN_FILENO][1],
        !           678:            log_stdin, &iobufs);
1.1       misho     679:        io_fds[SFD_STDIN] = io_pipe[STDIN_FILENO][0];
                    680:     }
                    681:     if (io_fds[SFD_STDOUT] == -1 || !isatty(STDOUT_FILENO)) {
1.1.1.2   misho     682:        sudo_debug_printf(SUDO_DEBUG_INFO, "stdout not a tty, creating a pipe");
                    683:        pipeline = true;
1.1       misho     684:        if (pipe(io_pipe[STDOUT_FILENO]) != 0)
1.1.1.5 ! misho     685:            fatal(U_("unable to create pipe"));
        !           686:        io_buf_new(io_pipe[STDOUT_FILENO][0], STDOUT_FILENO,
        !           687:            log_stdout, &iobufs);
1.1       misho     688:        io_fds[SFD_STDOUT] = io_pipe[STDOUT_FILENO][1];
                    689:     }
                    690:     if (io_fds[SFD_STDERR] == -1 || !isatty(STDERR_FILENO)) {
1.1.1.2   misho     691:        sudo_debug_printf(SUDO_DEBUG_INFO, "stderr not a tty, creating a pipe");
1.1       misho     692:        if (pipe(io_pipe[STDERR_FILENO]) != 0)
1.1.1.5 ! misho     693:            fatal(U_("unable to create pipe"));
        !           694:        io_buf_new(io_pipe[STDERR_FILENO][0], STDERR_FILENO,
        !           695:            log_stderr, &iobufs);
1.1       misho     696:        io_fds[SFD_STDERR] = io_pipe[STDERR_FILENO][1];
                    697:     }
                    698: 
1.1.1.4   misho     699:     /* We don't want to receive SIGTTIN/SIGTTOU, getting EIO is preferable. */
                    700:     sa.sa_handler = SIG_IGN;
                    701:     sudo_sigaction(SIGTTIN, &sa, NULL);
                    702:     sudo_sigaction(SIGTTOU, &sa, NULL);
                    703: 
1.1       misho     704:     /* Job control signals to relay from parent to child. */
1.1.1.4   misho     705:     sigfillset(&sa.sa_mask);
1.1       misho     706:     sa.sa_flags = SA_INTERRUPT; /* do not restart syscalls */
1.1.1.3   misho     707: #ifdef SA_SIGINFO
                    708:     sa.sa_flags |= SA_SIGINFO;
                    709:     sa.sa_sigaction = handler;
                    710: #else
1.1       misho     711:     sa.sa_handler = handler;
1.1.1.3   misho     712: #endif
1.1.1.4   misho     713:     sudo_sigaction(SIGTSTP, &sa, NULL);
1.1.1.2   misho     714: 
1.1       misho     715:     if (foreground) {
                    716:        /* Copy terminal attrs from user tty -> pty slave. */
                    717:        if (term_copy(io_fds[SFD_USERTTY], io_fds[SFD_SLAVE])) {
1.1.1.2   misho     718:            tty_initialized = true;
1.1       misho     719:            sync_ttysize(io_fds[SFD_USERTTY], io_fds[SFD_SLAVE]);
                    720:        }
                    721: 
1.1.1.4   misho     722:        /* Start out in raw mode unless part of a pipeline or backgrounded. */
                    723:        if (!pipeline && !ISSET(details->flags, CD_EXEC_BG)) {
1.1       misho     724:            ttymode = TERM_RAW;
                    725:            do {
                    726:                n = term_raw(io_fds[SFD_USERTTY], 0);
                    727:            } while (!n && errno == EINTR);
                    728:            if (!n)
1.1.1.5 ! misho     729:                fatal(U_("unable to set terminal to raw mode"));
1.1       misho     730:        }
                    731:     }
                    732: 
1.1.1.2   misho     733:     /*
                    734:      * The policy plugin's session init must be run before we fork
                    735:      * or certain pam modules won't be able to track their state.
                    736:      */
                    737:     if (policy_init_session(details) != true)
1.1.1.5 ! misho     738:        fatalx(U_("policy plugin failed session initialization"));
1.1.1.2   misho     739: 
1.1.1.3   misho     740:     /*
                    741:      * Block some signals until cmnd_pid is set in the parent to avoid a
                    742:      * race between exec of the command and receipt of a fatal signal from it.
                    743:      */
                    744:     sigemptyset(&mask);
                    745:     sigaddset(&mask, SIGTERM);
                    746:     sigaddset(&mask, SIGHUP);
                    747:     sigaddset(&mask, SIGINT);
                    748:     sigaddset(&mask, SIGQUIT);
                    749:     sigprocmask(SIG_BLOCK, &mask, omask);
                    750: 
1.1.1.2   misho     751:     child = sudo_debug_fork();
1.1       misho     752:     switch (child) {
                    753:     case -1:
1.1.1.5 ! misho     754:        fatal(U_("unable to fork"));
1.1       misho     755:        break;
                    756:     case 0:
                    757:        /* child */
                    758:        close(sv[0]);
                    759:        close(signal_pipe[0]);
                    760:        close(signal_pipe[1]);
                    761:        fcntl(sv[1], F_SETFD, FD_CLOEXEC);
1.1.1.3   misho     762:        sigprocmask(SIG_SETMASK, omask, NULL);
1.1.1.4   misho     763:        /* Close the other end of the stdin/stdout/stderr pipes and exec. */
                    764:        if (io_pipe[STDIN_FILENO][1])
                    765:            close(io_pipe[STDIN_FILENO][1]);
                    766:        if (io_pipe[STDOUT_FILENO][0])
                    767:            close(io_pipe[STDOUT_FILENO][0]);
                    768:        if (io_pipe[STDERR_FILENO][0])
                    769:            close(io_pipe[STDERR_FILENO][0]);
                    770:        exec_monitor(details, sv[1]);
1.1       misho     771:        cstat.type = CMD_ERRNO;
                    772:        cstat.val = errno;
1.1.1.3   misho     773:        ignore_result(send(sv[1], &cstat, sizeof(cstat), 0));
1.1       misho     774:        _exit(1);
                    775:     }
                    776: 
                    777:     /* Close the other end of the stdin/stdout/stderr pipes. */
                    778:     if (io_pipe[STDIN_FILENO][0])
                    779:        close(io_pipe[STDIN_FILENO][0]);
                    780:     if (io_pipe[STDOUT_FILENO][1])
                    781:        close(io_pipe[STDOUT_FILENO][1]);
1.1.1.4   misho     782:     if (io_pipe[STDERR_FILENO][1])
1.1       misho     783:        close(io_pipe[STDERR_FILENO][1]);
                    784: 
1.1.1.2   misho     785:     debug_return_int(child);
1.1       misho     786: }
                    787: 
                    788: void
                    789: pty_close(struct command_status *cstat)
                    790: {
1.1.1.5 ! misho     791:     struct io_buffer *iob;
1.1       misho     792:     int n;
1.1.1.2   misho     793:     debug_decl(pty_close, SUDO_DEBUG_EXEC);
1.1       misho     794: 
                    795:     /* Flush any remaining output (the plugin already got it) */
                    796:     if (io_fds[SFD_USERTTY] != -1) {
                    797:        n = fcntl(io_fds[SFD_USERTTY], F_GETFL, 0);
                    798:        if (n != -1 && ISSET(n, O_NONBLOCK)) {
                    799:            CLR(n, O_NONBLOCK);
                    800:            (void) fcntl(io_fds[SFD_USERTTY], F_SETFL, n);
                    801:        }
                    802:     }
1.1.1.5 ! misho     803:     del_io_events();
1.1       misho     804: 
1.1.1.5 ! misho     805:     /* Free I/O buffers. */
        !           806:     while ((iob = SLIST_FIRST(&iobufs)) != NULL) {
        !           807:        SLIST_REMOVE_HEAD(&iobufs, entries);
        !           808:        efree(iob);
1.1       misho     809:     }
                    810: 
1.1.1.5 ! misho     811:     /* Restore terminal settings. */
        !           812:     if (io_fds[SFD_USERTTY] != -1)
        !           813:        term_restore(io_fds[SFD_USERTTY], 0);
        !           814: 
1.1       misho     815:     /* If child was signalled, write the reason to stdout like the shell. */
                    816:     if (cstat->type == CMD_WSTATUS && WIFSIGNALED(cstat->val)) {
                    817:        int signo = WTERMSIG(cstat->val);
                    818:        if (signo && signo != SIGINT && signo != SIGPIPE) {
                    819:            const char *reason = strsignal(signo);
                    820:            n = io_fds[SFD_USERTTY] != -1 ?
                    821:                io_fds[SFD_USERTTY] : STDOUT_FILENO;
                    822:            if (write(n, reason, strlen(reason)) != -1) {
                    823:                if (WCOREDUMP(cstat->val)) {
1.1.1.2   misho     824:                    ignore_result(write(n, " (core dumped)", 14));
1.1       misho     825:                }
1.1.1.2   misho     826:                ignore_result(write(n, "\n", 1));
1.1       misho     827:            }
                    828:        }
                    829:     }
                    830:     utmp_logout(slavename, cstat->type == CMD_WSTATUS ? cstat->val : 0); /* XXX - only if CD_SET_UTMP */
1.1.1.2   misho     831:     debug_return;
1.1       misho     832: }
                    833: 
                    834: /*
1.1.1.5 ! misho     835:  * Schedule I/O events before starting the main event loop or
        !           836:  * resuming from suspend.
1.1       misho     837:  */
                    838: void
1.1.1.5 ! misho     839: add_io_events(struct sudo_event_base *evbase)
1.1       misho     840: {
                    841:     struct io_buffer *iob;
1.1.1.5 ! misho     842:     debug_decl(add_io_events, SUDO_DEBUG_EXEC);
1.1       misho     843: 
1.1.1.5 ! misho     844:     /*
        !           845:      * Schedule all readers as long as the buffer is not full.
        !           846:      * Schedule writers that contain buffered data.
        !           847:      * Normally, write buffers are added on demand when data is read.
        !           848:      */
        !           849:     SLIST_FOREACH(iob, &iobufs, entries) {
        !           850:        /* Don't read/write from /dev/tty if we are not in the foreground. */
        !           851:        if (iob->revent != NULL &&
        !           852:            (ttymode == TERM_RAW || !USERTTY_EVENT(iob->revent))) {
        !           853:            if (iob->len != sizeof(iob->buf)) {
        !           854:                sudo_debug_printf(SUDO_DEBUG_INFO,
        !           855:                    "added I/O revent %p, fd %d, events %d",
        !           856:                    iob->revent, iob->revent->fd, iob->revent->events);
        !           857:                if (sudo_ev_add(evbase, iob->revent, NULL, false) == -1)
        !           858:                    fatal(U_("unable to add event to queue"));
1.1       misho     859:            }
                    860:        }
1.1.1.5 ! misho     861:        if (iob->wevent != NULL &&
        !           862:            (foreground || !USERTTY_EVENT(iob->wevent))) {
        !           863:            if (iob->len > iob->off) {
        !           864:                sudo_debug_printf(SUDO_DEBUG_INFO,
        !           865:                    "added I/O wevent %p, fd %d, events %d",
        !           866:                    iob->wevent, iob->wevent->fd, iob->wevent->events);
        !           867:                if (sudo_ev_add(evbase, iob->wevent, NULL, false) == -1)
        !           868:                    fatal(U_("unable to add event to queue"));
        !           869:            }
1.1       misho     870:        }
                    871:     }
1.1.1.2   misho     872:     debug_return;
1.1       misho     873: }
                    874: 
1.1.1.5 ! misho     875: /*
        !           876:  * Flush any output buffered in iobufs or readable from fds other
        !           877:  * than /dev/tty.  Removes I/O events from the event base when done.
        !           878:  */
        !           879: static void
        !           880: del_io_events(void)
        !           881: {
        !           882:     struct io_buffer *iob;
        !           883:     struct sudo_event_base *evbase;
        !           884:     debug_decl(del_io_events, SUDO_DEBUG_EXEC);
        !           885: 
        !           886:     /* Remove iobufs from existing event base. */
        !           887:     SLIST_FOREACH(iob, &iobufs, entries) {
        !           888:        if (iob->revent != NULL) {
        !           889:            sudo_debug_printf(SUDO_DEBUG_INFO,
        !           890:                "deleted I/O revent %p, fd %d, events %d",
        !           891:                iob->revent, iob->revent->fd, iob->revent->events);
        !           892:            sudo_ev_del(NULL, iob->revent);
        !           893:        }
        !           894:        if (iob->wevent != NULL) {
        !           895:            sudo_debug_printf(SUDO_DEBUG_INFO,
        !           896:                "deleted I/O wevent %p, fd %d, events %d",
        !           897:                iob->wevent, iob->wevent->fd, iob->wevent->events);
        !           898:            sudo_ev_del(NULL, iob->wevent);
        !           899:        }
        !           900:     }
        !           901: 
        !           902:     /* Create temporary event base for flushing. */
        !           903:     evbase = sudo_ev_base_alloc();
        !           904:     if (evbase == NULL)
        !           905:        fatal(NULL);
        !           906: 
        !           907:     /* Avoid reading from /dev/tty, just flush existing data. */
        !           908:     SLIST_FOREACH(iob, &iobufs, entries) {
        !           909:        /* Don't read from /dev/tty while flushing. */
        !           910:        if (iob->revent != NULL && !USERTTY_EVENT(iob->revent)) {
        !           911:            if (iob->len != sizeof(iob->buf)) {
        !           912:                if (sudo_ev_add(evbase, iob->revent, NULL, false) == -1)
        !           913:                    fatal(U_("unable to add event to queue"));
        !           914:            }
        !           915:        }
        !           916:        /* Flush any write buffers with data in them. */
        !           917:        if (iob->wevent != NULL) {
        !           918:            if (iob->len > iob->off) {
        !           919:                if (sudo_ev_add(evbase, iob->wevent, NULL, false) == -1)
        !           920:                    fatal(U_("unable to add event to queue"));
        !           921:            }
        !           922:        }
        !           923:     }
        !           924: 
        !           925:     (void) sudo_ev_loop(evbase, SUDO_EVLOOP_NONBLOCK);
        !           926: 
        !           927:     /* Free temporary event base, removing its events. */
        !           928:     sudo_ev_base_free(evbase);
        !           929: 
        !           930:     debug_return;
        !           931: }
        !           932: 
1.1       misho     933: static void
1.1.1.2   misho     934: deliver_signal(pid_t pid, int signo, bool from_parent)
1.1       misho     935: {
1.1.1.3   misho     936:     char signame[SIG2STR_MAX];
1.1       misho     937:     int status;
1.1.1.2   misho     938:     debug_decl(deliver_signal, SUDO_DEBUG_EXEC);
1.1       misho     939: 
1.1.1.4   misho     940:     if (signo == SIGCONT_FG)
                    941:        strlcpy(signame, "CONT_FG", sizeof(signame));
                    942:     else if (signo == SIGCONT_BG)
                    943:        strlcpy(signame, "CONT_BG", sizeof(signame));
                    944:     else if (sig2str(signo, signame) == -1)
1.1.1.3   misho     945:        snprintf(signame, sizeof(signame), "%d", signo);
                    946: 
1.1       misho     947:     /* Handle signal from parent. */
1.1.1.3   misho     948:     sudo_debug_printf(SUDO_DEBUG_INFO, "received SIG%s%s",
                    949:        signame, from_parent ? " from parent" : "");
1.1       misho     950:     switch (signo) {
                    951:     case SIGALRM:
1.1.1.3   misho     952:        terminate_command(pid, true);
1.1       misho     953:        break;
                    954:     case SIGCONT_FG:
                    955:        /* Continue in foreground, grant it controlling tty. */
                    956:        do {
1.1.1.3   misho     957:            status = tcsetpgrp(io_fds[SFD_SLAVE], cmnd_pgrp);
1.1       misho     958:        } while (status == -1 && errno == EINTR);
                    959:        killpg(pid, SIGCONT);
                    960:        break;
                    961:     case SIGCONT_BG:
                    962:        /* Continue in background, I take controlling tty. */
                    963:        do {
1.1.1.4   misho     964:            status = tcsetpgrp(io_fds[SFD_SLAVE], mon_pgrp);
1.1       misho     965:        } while (status == -1 && errno == EINTR);
                    966:        killpg(pid, SIGCONT);
                    967:        break;
                    968:     case SIGKILL:
                    969:        _exit(1); /* XXX */
                    970:        /* NOTREACHED */
                    971:     default:
1.1.1.3   misho     972:        /* Relay signal to command. */
1.1       misho     973:        killpg(pid, signo);
                    974:        break;
                    975:     }
1.1.1.2   misho     976:     debug_return;
1.1       misho     977: }
                    978: 
                    979: /*
                    980:  * Send status to parent over socketpair.
                    981:  * Return value is the same as send(2).
                    982:  */
                    983: static int
                    984: send_status(int fd, struct command_status *cstat)
                    985: {
                    986:     int n = -1;
1.1.1.2   misho     987:     debug_decl(send_status, SUDO_DEBUG_EXEC);
1.1       misho     988: 
                    989:     if (cstat->type != CMD_INVALID) {
1.1.1.2   misho     990:        sudo_debug_printf(SUDO_DEBUG_INFO,
                    991:            "sending status message to parent: [%d, %d]",
                    992:            cstat->type, cstat->val);
1.1       misho     993:        do {
                    994:            n = send(fd, cstat, sizeof(*cstat), 0);
                    995:        } while (n == -1 && errno == EINTR);
                    996:        if (n != sizeof(*cstat)) {
1.1.1.2   misho     997:            sudo_debug_printf(SUDO_DEBUG_ERROR,
                    998:                "unable to send status to parent: %s", strerror(errno));
1.1       misho     999:        }
                   1000:        cstat->type = CMD_INVALID; /* prevent re-sending */
                   1001:     }
1.1.1.2   misho    1002:     debug_return_int(n);
1.1       misho    1003: }
                   1004: 
                   1005: /*
1.1.1.3   misho    1006:  * Wait for command status after receiving SIGCHLD.
                   1007:  * If the command was stopped, the status is send back to the parent.
1.1       misho    1008:  * Otherwise, cstat is filled in but not sent.
1.1.1.3   misho    1009:  * Returns true if command is still alive, else false.
1.1       misho    1010:  */
1.1.1.2   misho    1011: static bool
1.1       misho    1012: handle_sigchld(int backchannel, struct command_status *cstat)
                   1013: {
1.1.1.2   misho    1014:     bool alive = true;
                   1015:     int status;
1.1       misho    1016:     pid_t pid;
1.1.1.2   misho    1017:     debug_decl(handle_sigchld, SUDO_DEBUG_EXEC);
1.1       misho    1018: 
1.1.1.3   misho    1019:     /* read command status */
1.1       misho    1020:     do {
1.1.1.3   misho    1021:        pid = waitpid(cmnd_pid, &status, WUNTRACED|WNOHANG);
1.1       misho    1022:     } while (pid == -1 && errno == EINTR);
1.1.1.3   misho    1023:     if (pid == cmnd_pid) {
1.1       misho    1024:        if (cstat->type != CMD_ERRNO) {
1.1.1.3   misho    1025:            char signame[SIG2STR_MAX];
                   1026: 
1.1       misho    1027:            cstat->type = CMD_WSTATUS;
                   1028:            cstat->val = status;
                   1029:            if (WIFSTOPPED(status)) {
1.1.1.3   misho    1030:                if (sig2str(WSTOPSIG(status), signame) == -1)
                   1031:                    snprintf(signame, sizeof(signame), "%d", WSTOPSIG(status));
                   1032:                sudo_debug_printf(SUDO_DEBUG_INFO,
                   1033:                    "command stopped, SIG%s", signame);
1.1.1.4   misho    1034:                /* Saved the foreground pgid so we can restore it later. */
1.1       misho    1035:                do {
1.1.1.4   misho    1036:                    pid = tcgetpgrp(io_fds[SFD_SLAVE]);
                   1037:                } while (pid == -1 && errno == EINTR);
                   1038:                if (pid != mon_pgrp)
                   1039:                    cmnd_pgrp = pid;
1.1       misho    1040:                if (send_status(backchannel, cstat) == -1)
                   1041:                    return alive; /* XXX */
                   1042:            } else if (WIFSIGNALED(status)) {
1.1.1.3   misho    1043:                if (sig2str(WTERMSIG(status), signame) == -1)
                   1044:                    snprintf(signame, sizeof(signame), "%d", WTERMSIG(status));
                   1045:                sudo_debug_printf(SUDO_DEBUG_INFO,
                   1046:                    "command killed, SIG%s", signame);
1.1       misho    1047:            } else {
1.1.1.2   misho    1048:                sudo_debug_printf(SUDO_DEBUG_INFO, "command exited: %d",
                   1049:                    WEXITSTATUS(status));
1.1       misho    1050:            }
                   1051:        }
                   1052:        if (!WIFSTOPPED(status))
1.1.1.2   misho    1053:            alive = false;
1.1       misho    1054:     }
1.1.1.2   misho    1055:     debug_return_bool(alive);
1.1       misho    1056: }
                   1057: 
1.1.1.5 ! misho    1058: struct monitor_closure {
        !          1059:     struct sudo_event_base *evbase;
        !          1060:     struct sudo_event *errpipe_event;
        !          1061:     struct sudo_event *backchannel_event;
        !          1062:     struct sudo_event *signal_pipe_event;
        !          1063:     struct command_status *cstat;
        !          1064:     int backchannel;
        !          1065:     bool alive;
        !          1066: };
        !          1067: 
        !          1068: static void
        !          1069: mon_signal_pipe_cb(int fd, int what, void *v)
        !          1070: {
        !          1071:     struct monitor_closure *mc = v;
        !          1072:     unsigned char signo;
        !          1073:     ssize_t n;
        !          1074:     debug_decl(mon_signal_pipe_cb, SUDO_DEBUG_EXEC);
        !          1075: 
        !          1076:     n = read(fd, &signo, sizeof(signo));
        !          1077:     if (n == -1) {
        !          1078:        if (errno != EINTR && errno != EAGAIN) {
        !          1079:            warning(U_("error reading from signal pipe"));
        !          1080:            sudo_ev_loopbreak(mc->evbase);
        !          1081:        }
        !          1082:     } else {
        !          1083:        /*
        !          1084:         * Handle SIGCHLD specially and deliver other signals
        !          1085:         * directly to the command.
        !          1086:         */
        !          1087:        if (signo == SIGCHLD) {
        !          1088:            mc->alive = handle_sigchld(mc->backchannel, mc->cstat);
        !          1089:            if (!mc->alive) {
        !          1090:                /* Remove all but the errpipe event. */
        !          1091:                sudo_ev_del(mc->evbase, mc->backchannel_event);
        !          1092:                sudo_ev_del(mc->evbase, mc->signal_pipe_event);
        !          1093:            }
        !          1094:        } else {
        !          1095:            deliver_signal(cmnd_pid, signo, false);
        !          1096:        }
        !          1097:     }
        !          1098:     debug_return;
        !          1099: }
        !          1100: 
        !          1101: static void
        !          1102: mon_errpipe_cb(int fd, int what, void *v)
        !          1103: {
        !          1104:     struct monitor_closure *mc = v;
        !          1105:     ssize_t n;
        !          1106:     debug_decl(mon_errpipe_cb, SUDO_DEBUG_EXEC);
        !          1107: 
        !          1108:     /* read errno or EOF from command pipe */
        !          1109:     n = read(fd, mc->cstat, sizeof(struct command_status));
        !          1110:     if (n == -1) {
        !          1111:        if (errno != EINTR && errno != EAGAIN) {
        !          1112:            warning(U_("error reading from pipe"));
        !          1113:            sudo_ev_loopbreak(mc->evbase);
        !          1114:        }
        !          1115:     } else {
        !          1116:        /* Got errno or EOF, either way we are done with errpipe. */
        !          1117:        sudo_ev_del(mc->evbase, mc->errpipe_event);
        !          1118:        close(fd);
        !          1119:     }
        !          1120:     debug_return;
        !          1121: }
        !          1122: 
        !          1123: static void
        !          1124: mon_backchannel_cb(int fd, int what, void *v)
        !          1125: {
        !          1126:     struct monitor_closure *mc = v;
        !          1127:     struct command_status cstmp;
        !          1128:     ssize_t n;
        !          1129:     debug_decl(mon_backchannel_cb, SUDO_DEBUG_EXEC);
        !          1130: 
        !          1131:     /* read command from backchannel, should be a signal */
        !          1132:     n = recv(fd, &cstmp, sizeof(cstmp), MSG_WAITALL);
        !          1133:     if (n != sizeof(cstmp)) {
        !          1134:        if (n == -1) {
        !          1135:            if (errno == EINTR || errno == EAGAIN)
        !          1136:                debug_return;
        !          1137:            warning(U_("error reading from socketpair"));
        !          1138:        } else {
        !          1139:            /* short read or EOF, parent process died? */
        !          1140:        }
        !          1141:        sudo_ev_loopbreak(mc->evbase);
        !          1142:     } else {
        !          1143:        if (cstmp.type == CMD_SIGNO) {
        !          1144:            deliver_signal(cmnd_pid, cstmp.val, true);
        !          1145:        } else {
        !          1146:            warningx(U_("unexpected reply type on backchannel: %d"), cstmp.type);
        !          1147:        }
        !          1148:     }
        !          1149:     debug_return;
        !          1150: }
        !          1151: 
1.1       misho    1152: /*
                   1153:  * Monitor process that creates a new session with the controlling tty,
                   1154:  * resets signal handlers and forks a child to call exec_pty().
                   1155:  * Waits for status changes from the command and relays them to the
                   1156:  * parent and relays signals from the parent to the command.
                   1157:  * Returns an error if fork(2) fails, else calls _exit(2).
                   1158:  */
                   1159: static int
                   1160: exec_monitor(struct command_details *details, int backchannel)
                   1161: {
                   1162:     struct command_status cstat;
1.1.1.5 ! misho    1163:     struct sudo_event_base *evbase;
        !          1164:     struct monitor_closure mc;
1.1       misho    1165:     sigaction_t sa;
1.1.1.5 ! misho    1166:     int errpipe[2], n;
1.1.1.2   misho    1167:     debug_decl(exec_monitor, SUDO_DEBUG_EXEC);
1.1       misho    1168: 
                   1169:     /* Close unused fds. */
                   1170:     if (io_fds[SFD_MASTER] != -1)
                   1171:        close(io_fds[SFD_MASTER]);
                   1172:     if (io_fds[SFD_USERTTY] != -1)
                   1173:        close(io_fds[SFD_USERTTY]);
                   1174: 
                   1175:     /*
                   1176:      * We use a pipe to atomically handle signal notification within
1.1.1.5 ! misho    1177:      * the event loop.
1.1       misho    1178:      */
                   1179:     if (pipe_nonblock(signal_pipe) != 0)
1.1.1.5 ! misho    1180:        fatal(U_("unable to create pipe"));
1.1       misho    1181: 
                   1182:     /* Reset SIGWINCH and SIGALRM. */
1.1.1.4   misho    1183:     memset(&sa, 0, sizeof(sa));
1.1       misho    1184:     sigemptyset(&sa.sa_mask);
                   1185:     sa.sa_flags = SA_RESTART;
                   1186:     sa.sa_handler = SIG_DFL;
1.1.1.4   misho    1187:     sudo_sigaction(SIGWINCH, &sa, NULL);
                   1188:     sudo_sigaction(SIGALRM, &sa, NULL);
1.1       misho    1189: 
                   1190:     /* Ignore any SIGTTIN or SIGTTOU we get. */
                   1191:     sa.sa_handler = SIG_IGN;
1.1.1.4   misho    1192:     sudo_sigaction(SIGTTIN, &sa, NULL);
                   1193:     sudo_sigaction(SIGTTOU, &sa, NULL);
                   1194: 
                   1195:     /* Block all signals in mon_handler(). */
                   1196:     sigfillset(&sa.sa_mask);
1.1       misho    1197: 
1.1.1.5 ! misho    1198:     /* Note: HP-UX poll() will not be interrupted if SA_RESTART is set. */
1.1       misho    1199:     sa.sa_flags = SA_INTERRUPT;
1.1.1.3   misho    1200: #ifdef SA_SIGINFO
                   1201:     sa.sa_flags |= SA_SIGINFO;
                   1202:     sa.sa_sigaction = mon_handler;
                   1203: #else
                   1204:     sa.sa_handler = mon_handler;
                   1205: #endif
1.1.1.4   misho    1206:     sudo_sigaction(SIGCHLD, &sa, NULL);
1.1       misho    1207: 
1.1.1.2   misho    1208:     /* Catch common signals so we can cleanup properly. */
                   1209:     sa.sa_flags = SA_RESTART;
1.1.1.3   misho    1210: #ifdef SA_SIGINFO
                   1211:     sa.sa_flags |= SA_SIGINFO;
                   1212:     sa.sa_sigaction = mon_handler;
                   1213: #else
                   1214:     sa.sa_handler = mon_handler;
                   1215: #endif
1.1.1.4   misho    1216:     sudo_sigaction(SIGHUP, &sa, NULL);
                   1217:     sudo_sigaction(SIGINT, &sa, NULL);
                   1218:     sudo_sigaction(SIGQUIT, &sa, NULL);
                   1219:     sudo_sigaction(SIGTERM, &sa, NULL);
                   1220:     sudo_sigaction(SIGTSTP, &sa, NULL);
                   1221:     sudo_sigaction(SIGUSR1, &sa, NULL);
                   1222:     sudo_sigaction(SIGUSR2, &sa, NULL);
1.1.1.2   misho    1223: 
1.1       misho    1224:     /*
                   1225:      * Start a new session with the parent as the session leader
                   1226:      * and the slave pty as the controlling terminal.
1.1.1.3   misho    1227:      * This allows us to be notified when the command has been suspended.
1.1       misho    1228:      */
                   1229:     if (setsid() == -1) {
                   1230:        warning("setsid");
                   1231:        goto bad;
                   1232:     }
                   1233:     if (io_fds[SFD_SLAVE] != -1) {
                   1234: #ifdef TIOCSCTTY
                   1235:        if (ioctl(io_fds[SFD_SLAVE], TIOCSCTTY, NULL) != 0)
1.1.1.5 ! misho    1236:            fatal(U_("unable to set controlling tty"));
1.1       misho    1237: #else
                   1238:        /* Set controlling tty by reopening slave. */
                   1239:        if ((n = open(slavename, O_RDWR)) >= 0)
                   1240:            close(n);
                   1241: #endif
                   1242:     }
                   1243: 
1.1.1.4   misho    1244:     mon_pgrp = getpgrp();      /* save a copy of our process group */
                   1245: 
1.1       misho    1246:     /*
                   1247:      * If stdin/stdout is not a tty, start command in the background
                   1248:      * since it might be part of a pipeline that reads from /dev/tty.
                   1249:      * In this case, we rely on the command receiving SIGTTOU or SIGTTIN
                   1250:      * when it needs access to the controlling tty.
                   1251:      */
                   1252:     if (pipeline)
1.1.1.2   misho    1253:        foreground = false;
1.1       misho    1254: 
                   1255:     /* Start command and wait for it to stop or exit */
                   1256:     if (pipe(errpipe) == -1)
1.1.1.5 ! misho    1257:        fatal(U_("unable to create pipe"));
1.1.1.3   misho    1258:     cmnd_pid = sudo_debug_fork();
                   1259:     if (cmnd_pid == -1) {
1.1.1.5 ! misho    1260:        warning(U_("unable to fork"));
1.1       misho    1261:        goto bad;
                   1262:     }
1.1.1.3   misho    1263:     if (cmnd_pid == 0) {
1.1       misho    1264:        /* We pass errno back to our parent via pipe on exec failure. */
                   1265:        close(backchannel);
                   1266:        close(signal_pipe[0]);
                   1267:        close(signal_pipe[1]);
                   1268:        close(errpipe[0]);
                   1269:        fcntl(errpipe[1], F_SETFD, FD_CLOEXEC);
                   1270:        restore_signals();
                   1271: 
                   1272:        /* setup tty and exec command */
1.1.1.5 ! misho    1273:        exec_pty(details, &cstat, errpipe[1]);
1.1.1.2   misho    1274:        ignore_result(write(errpipe[1], &cstat, sizeof(cstat)));
1.1       misho    1275:        _exit(1);
                   1276:     }
                   1277:     close(errpipe[1]);
                   1278: 
1.1.1.3   misho    1279:     /* Send the command's pid to main sudo process. */
                   1280:     cstat.type = CMD_PID;
                   1281:     cstat.val = cmnd_pid;
                   1282:     ignore_result(send(backchannel, &cstat, sizeof(cstat), 0));
                   1283: 
1.1       misho    1284:     /* If any of stdin/stdout/stderr are pipes, close them in parent. */
                   1285:     if (io_fds[SFD_STDIN] != io_fds[SFD_SLAVE])
                   1286:        close(io_fds[SFD_STDIN]);
                   1287:     if (io_fds[SFD_STDOUT] != io_fds[SFD_SLAVE])
                   1288:        close(io_fds[SFD_STDOUT]);
                   1289:     if (io_fds[SFD_STDERR] != io_fds[SFD_SLAVE])
                   1290:        close(io_fds[SFD_STDERR]);
                   1291: 
1.1.1.4   misho    1292:     /* Put command in its own process group. */
1.1.1.3   misho    1293:     cmnd_pgrp = cmnd_pid;
                   1294:     setpgid(cmnd_pid, cmnd_pgrp);
1.1.1.4   misho    1295: 
                   1296:     /* Make the command the foreground process for the pty slave. */
                   1297:     if (foreground && !ISSET(details->flags, CD_EXEC_BG)) {
1.1       misho    1298:        do {
1.1.1.4   misho    1299:            n = tcsetpgrp(io_fds[SFD_SLAVE], cmnd_pgrp);
                   1300:        } while (n == -1 && errno == EINTR);
1.1       misho    1301:     }
                   1302: 
1.1.1.5 ! misho    1303:     /*
        !          1304:      * Create new event base and register read events for the
        !          1305:      * signal pipe, error pipe, and backchannel.
        !          1306:      */
        !          1307:     evbase = sudo_ev_base_alloc();
        !          1308:     if (evbase == NULL)
        !          1309:        fatal(NULL);
1.1       misho    1310: 
1.1.1.5 ! misho    1311:     memset(&cstat, 0, sizeof(cstat));
        !          1312:     mc.cstat = &cstat;
        !          1313:     mc.evbase = evbase;
        !          1314:     mc.backchannel = backchannel;
        !          1315:     mc.alive = true;
        !          1316: 
        !          1317:     mc.signal_pipe_event = sudo_ev_alloc(signal_pipe[0],
        !          1318:        SUDO_EV_READ|SUDO_EV_PERSIST, mon_signal_pipe_cb, &mc);
        !          1319:     if (mc.signal_pipe_event == NULL)
        !          1320:        fatal(NULL);
        !          1321:     if (sudo_ev_add(evbase, mc.signal_pipe_event, NULL, false) == -1)
        !          1322:        fatal(U_("unable to add event to queue"));
        !          1323: 
        !          1324:     mc.errpipe_event = sudo_ev_alloc(errpipe[0],
        !          1325:        SUDO_EV_READ|SUDO_EV_PERSIST, mon_errpipe_cb, &mc);
        !          1326:     if (mc.errpipe_event == NULL)
        !          1327:        fatal(NULL);
        !          1328:     if (sudo_ev_add(evbase, mc.errpipe_event, NULL, false) == -1)
        !          1329:        fatal(U_("unable to add event to queue"));
        !          1330: 
        !          1331:     mc.backchannel_event = sudo_ev_alloc(backchannel,
        !          1332:        SUDO_EV_READ|SUDO_EV_PERSIST, mon_backchannel_cb, &mc);
        !          1333:     if (mc.backchannel_event == NULL)
        !          1334:        fatal(NULL);
        !          1335:     if (sudo_ev_add(evbase, mc.backchannel_event, NULL, false) == -1)
        !          1336:        fatal(U_("unable to add event to queue"));
1.1       misho    1337: 
1.1.1.5 ! misho    1338:     /*
        !          1339:      * Wait for errno on pipe, signal on backchannel or for SIGCHLD.
        !          1340:      * The event loop ends when the child is no longer running and
        !          1341:      * the error pipe is closed.
        !          1342:      */
        !          1343:     (void) sudo_ev_loop(evbase, 0);
        !          1344:     if (mc.alive) {
        !          1345:        /* XXX An error occurred, should send a message back. */
        !          1346:        sudo_debug_printf(SUDO_DEBUG_ERROR,
        !          1347:            "Command still running after event loop exit, sending SIGKILL");
1.1.1.3   misho    1348:        kill(cmnd_pid, SIGKILL);
1.1       misho    1349:     } else {
                   1350:        /* Send parent status. */
                   1351:        send_status(backchannel, &cstat);
                   1352:     }
1.1.1.2   misho    1353:     sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys, 1);
1.1       misho    1354:     _exit(1);
                   1355: 
                   1356: bad:
1.1.1.2   misho    1357:     debug_return_int(errno);
1.1       misho    1358: }
                   1359: 
                   1360: /*
                   1361:  * Sets up std{in,out,err} and executes the actual command.
                   1362:  * Returns only if execve() fails.
                   1363:  */
                   1364: static void
1.1.1.4   misho    1365: exec_pty(struct command_details *details,
1.1.1.5 ! misho    1366:     struct command_status *cstat, int errfd)
1.1       misho    1367: {
                   1368:     pid_t self = getpid();
1.1.1.2   misho    1369:     debug_decl(exec_pty, SUDO_DEBUG_EXEC);
1.1       misho    1370: 
1.1.1.4   misho    1371:     /* Register cleanup function */
                   1372:     fatal_callback_register(pty_cleanup);
                   1373: 
1.1.1.3   misho    1374:     /* Set command process group here too to avoid a race. */
1.1       misho    1375:     setpgid(0, self);
                   1376: 
                   1377:     /* Wire up standard fds, note that stdout/stderr may be pipes. */
                   1378:     if (dup2(io_fds[SFD_STDIN], STDIN_FILENO) == -1 ||
                   1379:        dup2(io_fds[SFD_STDOUT], STDOUT_FILENO) == -1 ||
                   1380:        dup2(io_fds[SFD_STDERR], STDERR_FILENO) == -1)
1.1.1.4   misho    1381:        fatal("dup2");
1.1       misho    1382: 
                   1383:     /* Wait for parent to grant us the tty if we are foreground. */
1.1.1.4   misho    1384:     if (foreground && !ISSET(details->flags, CD_EXEC_BG)) {
1.1       misho    1385:        while (tcgetpgrp(io_fds[SFD_SLAVE]) != self)
                   1386:            ; /* spin */
                   1387:     }
                   1388: 
                   1389:     /* We have guaranteed that the slave fd is > 2 */
                   1390:     if (io_fds[SFD_SLAVE] != -1)
                   1391:        close(io_fds[SFD_SLAVE]);
                   1392:     if (io_fds[SFD_STDIN] != io_fds[SFD_SLAVE])
                   1393:        close(io_fds[SFD_STDIN]);
                   1394:     if (io_fds[SFD_STDOUT] != io_fds[SFD_SLAVE])
                   1395:        close(io_fds[SFD_STDOUT]);
                   1396:     if (io_fds[SFD_STDERR] != io_fds[SFD_SLAVE])
                   1397:        close(io_fds[SFD_STDERR]);
                   1398: 
1.1.1.4   misho    1399:     /* Execute command; only returns on error. */
                   1400:     exec_cmnd(details, cstat, errfd);
1.1.1.2   misho    1401: 
                   1402:     debug_return;
1.1       misho    1403: }
                   1404: 
                   1405: /*
                   1406:  * Propagates tty size change signals to pty being used by the command.
                   1407:  */
                   1408: static void
                   1409: sync_ttysize(int src, int dst)
                   1410: {
                   1411: #ifdef TIOCGWINSZ
                   1412:     struct winsize wsize;
                   1413:     pid_t pgrp;
1.1.1.2   misho    1414:     debug_decl(sync_ttysize, SUDO_DEBUG_EXEC);
1.1       misho    1415: 
                   1416:     if (ioctl(src, TIOCGWINSZ, &wsize) == 0) {
                   1417:            ioctl(dst, TIOCSWINSZ, &wsize);
                   1418:            if ((pgrp = tcgetpgrp(dst)) != -1)
                   1419:                killpg(pgrp, SIGWINCH);
                   1420:     }
1.1.1.2   misho    1421: 
                   1422:     debug_return;
1.1       misho    1423: #endif
                   1424: }
                   1425: 
                   1426: /*
                   1427:  * Handler for SIGWINCH in parent.
                   1428:  */
                   1429: static void
                   1430: sigwinch(int s)
                   1431: {
                   1432:     int serrno = errno;
                   1433: 
                   1434:     sync_ttysize(io_fds[SFD_USERTTY], io_fds[SFD_SLAVE]);
                   1435:     errno = serrno;
                   1436: }
                   1437: 
                   1438: /*
1.1.1.5 ! misho    1439:  * Remove and free any events associated with the specified
        !          1440:  * file descriptor present in the I/O buffers list.
        !          1441:  */
        !          1442: static void
        !          1443: ev_free_by_fd(struct sudo_event_base *evbase, int fd)
        !          1444: {
        !          1445:     struct io_buffer *iob;
        !          1446:     debug_decl(ev_free_by_fd, SUDO_DEBUG_EXEC);
        !          1447: 
        !          1448:     /* Deschedule any users of the fd and free up the events. */
        !          1449:     SLIST_FOREACH(iob, &iobufs, entries) {
        !          1450:        if (iob->revent != NULL) {
        !          1451:            if (sudo_ev_get_fd(iob->revent) == fd) {
        !          1452:                sudo_debug_printf(SUDO_DEBUG_INFO,
        !          1453:                    "%s: deleting and freeing revent %p with fd %d",
        !          1454:                    __func__, iob->revent, fd);
        !          1455:                sudo_ev_del(evbase, iob->revent);
        !          1456:                sudo_ev_free(iob->revent);
        !          1457:                iob->revent = NULL;
        !          1458:            }
        !          1459:        }
        !          1460:        if (iob->wevent != NULL) {
        !          1461:            if (sudo_ev_get_fd(iob->wevent) == fd) {
        !          1462:                sudo_debug_printf(SUDO_DEBUG_INFO,
        !          1463:                    "%s: deleting and freeing wevent %p with fd %d",
        !          1464:                    __func__, iob->wevent, fd);
        !          1465:                sudo_ev_del(evbase, iob->wevent);
        !          1466:                sudo_ev_free(iob->wevent);
        !          1467:                iob->wevent = NULL;
        !          1468:            }
        !          1469:        }
        !          1470:     }
        !          1471:     debug_return;
        !          1472: }
        !          1473: 
        !          1474: /*
1.1       misho    1475:  * Only close the fd if it is not /dev/tty or std{in,out,err}.
1.1.1.5 ! misho    1476:  * Return value is the same as close(2).
1.1       misho    1477:  */
                   1478: static int
                   1479: safe_close(int fd)
                   1480: {
1.1.1.2   misho    1481:     debug_decl(safe_close, SUDO_DEBUG_EXEC);
                   1482: 
1.1       misho    1483:     /* Avoid closing /dev/tty or std{in,out,err}. */
                   1484:     if (fd < 3 || fd == io_fds[SFD_USERTTY]) {
1.1.1.5 ! misho    1485:        sudo_debug_printf(SUDO_DEBUG_INFO,
        !          1486:            "%s: not closing fd %d (/dev/tty)", __func__, fd);
1.1       misho    1487:        errno = EINVAL;
1.1.1.2   misho    1488:        debug_return_int(-1);
1.1       misho    1489:     }
1.1.1.5 ! misho    1490:     sudo_debug_printf(SUDO_DEBUG_INFO, "%s: closing fd %d", __func__, fd);
1.1.1.2   misho    1491:     debug_return_int(close(fd));
1.1       misho    1492: }

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