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

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

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