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>