Annotation of embedaddon/sudo/src/exec.c, revision 1.1.1.2
1.1 misho 1: /*
1.1.1.2 ! misho 2: * Copyright (c) 2009-2012 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/param.h>
21: #ifdef HAVE_SYS_SYSMACROS_H
22: # include <sys/sysmacros.h>
23: #endif
24: #include <sys/socket.h>
25: #include <sys/stat.h>
26: #include <sys/time.h>
27: #include <sys/wait.h>
28: #include <sys/ioctl.h>
29: #ifdef HAVE_SYS_SELECT_H
30: # include <sys/select.h>
31: #endif /* HAVE_SYS_SELECT_H */
32: #include <stdio.h>
33: #ifdef STDC_HEADERS
34: # include <stdlib.h>
35: # include <stddef.h>
36: #else
37: # ifdef HAVE_STDLIB_H
38: # include <stdlib.h>
39: # endif
40: #endif /* STDC_HEADERS */
41: #ifdef HAVE_STRING_H
42: # include <string.h>
43: #endif /* HAVE_STRING_H */
44: #ifdef HAVE_STRINGS_H
45: # include <strings.h>
46: #endif /* HAVE_STRINGS_H */
47: #ifdef HAVE_UNISTD_H
48: # include <unistd.h>
49: #endif /* HAVE_UNISTD_H */
50: #if TIME_WITH_SYS_TIME
51: # include <time.h>
52: #endif
53: #ifdef HAVE_SETLOCALE
54: # include <locale.h>
55: #endif
56: #include <errno.h>
57: #include <fcntl.h>
58: #include <signal.h>
59: #include <termios.h>
60:
61: #include "sudo.h"
62: #include "sudo_exec.h"
63: #include "sudo_plugin.h"
64: #include "sudo_plugin_int.h"
65:
66: /* Shared with exec_pty.c for use with handler(). */
67: int signal_pipe[2];
68:
69: /* We keep a tailq of signals to forward to child. */
70: struct sigforward {
71: struct sigforward *prev, *next;
72: int signo;
73: };
74: TQ_DECLARE(sigforward)
75: static struct sigforward_list sigfwd_list;
76:
1.1.1.2 ! misho 77: static int handle_signals(int sv[2], pid_t child, int log_io,
1.1 misho 78: struct command_status *cstat);
79: static void forward_signals(int fd);
80: static void schedule_signal(int signo);
1.1.1.2 ! misho 81: #ifdef SA_SIGINFO
! 82: static void handler_nofwd(int s, siginfo_t *info, void *context);
! 83: #endif
1.1 misho 84:
85: /*
86: * Fork and execute a command, returns the child's pid.
87: * Sends errno back on sv[1] if execve() fails.
88: */
89: static int fork_cmnd(struct command_details *details, int sv[2])
90: {
91: struct command_status cstat;
92: sigaction_t sa;
93: pid_t child;
1.1.1.2 ! misho 94: debug_decl(fork_cmnd, SUDO_DEBUG_EXEC)
1.1 misho 95:
96: zero_bytes(&sa, sizeof(sa));
97: sigemptyset(&sa.sa_mask);
98: sa.sa_flags = SA_INTERRUPT; /* do not restart syscalls */
99: sa.sa_handler = handler;
100: sigaction(SIGCONT, &sa, NULL);
101:
1.1.1.2 ! misho 102: /*
! 103: * The policy plugin's session init must be run before we fork
! 104: * or certain pam modules won't be able to track their state.
! 105: */
! 106: if (policy_init_session(details) != true)
! 107: errorx(1, _("policy plugin failed session initialization"));
! 108:
! 109: child = sudo_debug_fork();
1.1 misho 110: switch (child) {
111: case -1:
112: error(1, _("unable to fork"));
113: break;
114: case 0:
115: /* child */
116: close(sv[0]);
117: close(signal_pipe[0]);
118: close(signal_pipe[1]);
119: fcntl(sv[1], F_SETFD, FD_CLOEXEC);
120: restore_signals();
1.1.1.2 ! misho 121: if (exec_setup(details, NULL, -1) == true) {
1.1 misho 122: /* headed for execve() */
1.1.1.2 ! misho 123: sudo_debug_execve(SUDO_DEBUG_INFO, details->command,
! 124: details->argv, details->envp);
! 125: if (details->closefrom >= 0) {
! 126: int maxfd = details->closefrom;
! 127: dup2(sv[1], maxfd);
! 128: (void)fcntl(maxfd, F_SETFD, FD_CLOEXEC);
! 129: sv[1] = maxfd++;
! 130: if (sudo_debug_fd_set(maxfd) != -1)
! 131: maxfd++;
! 132: closefrom(maxfd);
! 133: }
1.1 misho 134: #ifdef HAVE_SELINUX
1.1.1.2 ! misho 135: if (ISSET(details->flags, CD_RBAC_ENABLED)) {
! 136: selinux_execve(details->command, details->argv, details->envp,
! 137: ISSET(details->flags, CD_NOEXEC));
! 138: } else
1.1 misho 139: #endif
1.1.1.2 ! misho 140: {
! 141: sudo_execve(details->command, details->argv, details->envp,
! 142: ISSET(details->flags, CD_NOEXEC));
! 143: }
! 144: sudo_debug_printf(SUDO_DEBUG_ERROR, "unable to exec %s: %s",
! 145: details->command, strerror(errno));
1.1 misho 146: }
147: cstat.type = CMD_ERRNO;
148: cstat.val = errno;
149: send(sv[1], &cstat, sizeof(cstat), 0);
1.1.1.2 ! misho 150: sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys, 1);
1.1 misho 151: _exit(1);
152: }
1.1.1.2 ! misho 153: debug_return_int(child);
1.1 misho 154: }
155:
156: static struct signal_state {
157: int signo;
158: sigaction_t sa;
159: } saved_signals[] = {
160: { SIGALRM },
161: { SIGCHLD },
162: { SIGCONT },
163: { SIGHUP },
164: { SIGINT },
165: { SIGPIPE },
166: { SIGQUIT },
167: { SIGTERM },
168: { SIGTSTP },
169: { SIGTTIN },
170: { SIGTTOU },
171: { SIGUSR1 },
172: { SIGUSR2 },
173: { -1 }
174: };
175:
176: /*
177: * Save signal handler state so it can be restored before exec.
178: */
179: void
180: save_signals(void)
181: {
182: struct signal_state *ss;
1.1.1.2 ! misho 183: debug_decl(save_signals, SUDO_DEBUG_EXEC)
1.1 misho 184:
185: for (ss = saved_signals; ss->signo != -1; ss++)
186: sigaction(ss->signo, NULL, &ss->sa);
1.1.1.2 ! misho 187:
! 188: debug_return;
1.1 misho 189: }
190:
191: /*
192: * Restore signal handlers to initial state.
193: */
194: void
195: restore_signals(void)
196: {
197: struct signal_state *ss;
1.1.1.2 ! misho 198: debug_decl(restore_signals, SUDO_DEBUG_EXEC)
1.1 misho 199:
200: for (ss = saved_signals; ss->signo != -1; ss++)
201: sigaction(ss->signo, &ss->sa, NULL);
1.1.1.2 ! misho 202:
! 203: debug_return;
1.1 misho 204: }
205:
206: /*
207: * Execute a command, potentially in a pty with I/O loggging.
208: * This is a little bit tricky due to how POSIX job control works and
209: * we fact that we have two different controlling terminals to deal with.
210: */
211: int
1.1.1.2 ! misho 212: sudo_execute(struct command_details *details, struct command_status *cstat)
1.1 misho 213: {
1.1.1.2 ! misho 214: int maxfd, n, nready, sv[2];
1.1 misho 215: const char *utmp_user = NULL;
1.1.1.2 ! misho 216: bool log_io = false;
1.1 misho 217: fd_set *fdsr, *fdsw;
218: sigaction_t sa;
219: pid_t child;
1.1.1.2 ! misho 220: debug_decl(sudo_execute, SUDO_DEBUG_EXEC)
1.1 misho 221:
222: /* If running in background mode, fork and exit. */
223: if (ISSET(details->flags, CD_BACKGROUND)) {
1.1.1.2 ! misho 224: switch (sudo_debug_fork()) {
1.1 misho 225: case -1:
226: cstat->type = CMD_ERRNO;
227: cstat->val = errno;
1.1.1.2 ! misho 228: debug_return_int(-1);
1.1 misho 229: case 0:
230: /* child continues without controlling terminal */
231: (void)setpgid(0, 0);
232: break;
233: default:
234: /* parent exits (but does not flush buffers) */
1.1.1.2 ! misho 235: sudo_debug_exit_int(__func__, __FILE__, __LINE__,
! 236: sudo_debug_subsys, 0);
1.1 misho 237: _exit(0);
238: }
239: }
240:
241: /*
242: * If we have an I/O plugin or the policy plugin has requested one, we
243: * need to allocate a pty. It is OK to set log_io in the pty-only case
244: * as the io plugin tailqueue will be empty and no I/O logging will occur.
245: */
246: if (!tq_empty(&io_plugins) || ISSET(details->flags, CD_USE_PTY)) {
1.1.1.2 ! misho 247: log_io = true;
1.1 misho 248: if (ISSET(details->flags, CD_SET_UTMP))
249: utmp_user = details->utmp_user ? details->utmp_user : user_details.username;
1.1.1.2 ! misho 250: sudo_debug_printf(SUDO_DEBUG_INFO, "allocate pty for I/O logging");
1.1 misho 251: pty_setup(details->euid, user_details.tty, utmp_user);
252: }
253:
254: /*
255: * We communicate with the child over a bi-directional pair of sockets.
256: * Parent sends signal info to child and child sends back wait status.
257: */
258: if (socketpair(PF_UNIX, SOCK_DGRAM, 0, sv) == -1)
259: error(1, _("unable to create sockets"));
260:
261: /*
262: * We use a pipe to atomically handle signal notification within
263: * the select() loop.
264: */
265: if (pipe_nonblock(signal_pipe) != 0)
266: error(1, _("unable to create pipe"));
267:
268: zero_bytes(&sa, sizeof(sa));
269: sigemptyset(&sa.sa_mask);
270:
271: /*
1.1.1.2 ! misho 272: * Signals to forward to the child process (excluding SIGALRM and SIGCHLD).
1.1 misho 273: * Note: HP-UX select() will not be interrupted if SA_RESTART set.
274: */
275: sa.sa_flags = SA_INTERRUPT; /* do not restart syscalls */
276: sa.sa_handler = handler;
277: sigaction(SIGALRM, &sa, NULL);
278: sigaction(SIGCHLD, &sa, NULL);
279: sigaction(SIGPIPE, &sa, NULL);
280: sigaction(SIGTERM, &sa, NULL);
281: sigaction(SIGUSR1, &sa, NULL);
282: sigaction(SIGUSR2, &sa, NULL);
283:
1.1.1.2 ! misho 284: /*
! 285: * When not running the command in a pty, we do not want to
! 286: * forward signals generated by the kernel that the child will
! 287: * already have received either by virtue of being in the
! 288: * controlling tty's process group (SIGINT, SIGQUIT) or because
! 289: * the session is terminating (SIGHUP).
! 290: */
! 291: #ifdef SA_SIGINFO
! 292: if (!log_io) {
! 293: sa.sa_flags |= SA_SIGINFO;
! 294: sa.sa_sigaction = handler_nofwd;
! 295: }
! 296: #endif
! 297: sigaction(SIGHUP, &sa, NULL);
! 298: sigaction(SIGINT, &sa, NULL);
! 299: sigaction(SIGQUIT, &sa, NULL);
! 300:
1.1 misho 301: /* Max fd we will be selecting on. */
302: maxfd = MAX(sv[0], signal_pipe[0]);
303:
304: /*
305: * Child will run the command in the pty, parent will pass data
306: * to and from pty. Adjusts maxfd as needed.
307: */
308: if (log_io)
309: child = fork_pty(details, sv, &maxfd);
310: else
311: child = fork_cmnd(details, sv);
312: close(sv[1]);
313:
314: /* Set command timeout if specified. */
315: if (ISSET(details->flags, CD_SET_TIMEOUT))
316: alarm(details->timeout);
317:
318: #ifdef HAVE_SETLOCALE
319: /*
320: * I/O logging must be in the C locale for floating point numbers
321: * to be logged consistently.
322: */
323: setlocale(LC_ALL, "C");
324: #endif
325:
326: /*
327: * In the event loop we pass input from user tty to master
328: * and pass output from master to stdout and IO plugin.
329: */
1.1.1.2 ! misho 330: fdsr = emalloc2(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask));
! 331: fdsw = emalloc2(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask));
1.1 misho 332: for (;;) {
1.1.1.2 ! misho 333: memset(fdsw, 0, howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask));
! 334: memset(fdsr, 0, howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask));
1.1 misho 335:
336: FD_SET(signal_pipe[0], fdsr);
337: FD_SET(sv[0], fdsr);
338: if (!tq_empty(&sigfwd_list))
339: FD_SET(sv[0], fdsw);
340: if (log_io)
341: fd_set_iobs(fdsr, fdsw); /* XXX - better name */
342: nready = select(maxfd + 1, fdsr, fdsw, NULL, NULL);
1.1.1.2 ! misho 343: sudo_debug_printf(SUDO_DEBUG_DEBUG, "select returns %d", nready);
1.1 misho 344: if (nready == -1) {
1.1.1.2 ! misho 345: if (errno == EINTR || errno == ENOMEM)
1.1 misho 346: continue;
1.1.1.2 ! misho 347: if (errno == EBADF || errno == EIO) {
! 348: /* One of the ttys must have gone away. */
! 349: goto do_tty_io;
! 350: }
! 351: warning(_("select failed"));
! 352: sudo_debug_printf(SUDO_DEBUG_ERROR,
! 353: "select failure, terminating child");
! 354: schedule_signal(SIGKILL);
! 355: forward_signals(sv[0]);
! 356: break;
1.1 misho 357: }
358: if (FD_ISSET(sv[0], fdsw)) {
359: forward_signals(sv[0]);
360: }
361: if (FD_ISSET(signal_pipe[0], fdsr)) {
1.1.1.2 ! misho 362: n = handle_signals(sv, child, log_io, cstat);
1.1 misho 363: if (n == 0) {
364: /* Child has exited, cstat is set, we are done. */
1.1.1.2 ! misho 365: break;
1.1 misho 366: }
367: if (n == -1) {
368: /* Error reading signal_pipe[0], should not happen. */
369: break;
370: }
371: /* Restart event loop so signals get sent to child immediately. */
372: continue;
373: }
374: if (FD_ISSET(sv[0], fdsr)) {
375: /* read child status */
376: n = recv(sv[0], cstat, sizeof(*cstat), 0);
1.1.1.2 ! misho 377: if (n != sizeof(*cstat)) {
! 378: if (n == -1) {
! 379: if (errno == EINTR)
! 380: continue;
! 381: /*
! 382: * If not logging I/O we may receive ECONNRESET when
! 383: * the command is executed and sv is closed.
! 384: * It is safe to ignore this.
! 385: */
! 386: if (log_io && errno != EAGAIN) {
! 387: cstat->type = CMD_ERRNO;
! 388: cstat->val = errno;
! 389: break;
! 390: }
! 391: sudo_debug_printf(SUDO_DEBUG_ERROR,
! 392: "failed to read child status: %s", strerror(errno));
! 393: } else {
! 394: /* Short read or EOF. */
! 395: sudo_debug_printf(SUDO_DEBUG_ERROR,
! 396: "failed to read child status: %s",
! 397: n ? "short read" : "EOF");
! 398: /* XXX - should set cstat */
1.1 misho 399: break;
400: }
401: }
402: if (cstat->type == CMD_WSTATUS) {
403: if (WIFSTOPPED(cstat->val)) {
404: /* Suspend parent and tell child how to resume on return. */
1.1.1.2 ! misho 405: sudo_debug_printf(SUDO_DEBUG_INFO,
! 406: "child stopped, suspending parent");
1.1 misho 407: n = suspend_parent(WSTOPSIG(cstat->val));
408: schedule_signal(n);
409: continue;
410: } else {
411: /* Child exited or was killed, either way we are done. */
1.1.1.2 ! misho 412: sudo_debug_printf(SUDO_DEBUG_INFO, "child exited or was killed");
1.1 misho 413: break;
414: }
415: } else if (cstat->type == CMD_ERRNO) {
416: /* Child was unable to execute command or broken pipe. */
1.1.1.2 ! misho 417: sudo_debug_printf(SUDO_DEBUG_INFO, "errno from child: %s",
! 418: strerror(cstat->val));
1.1 misho 419: break;
420: }
421: }
1.1.1.2 ! misho 422: do_tty_io:
1.1 misho 423: if (perform_io(fdsr, fdsw, cstat) != 0) {
424: /* I/O error, kill child if still alive and finish. */
1.1.1.2 ! misho 425: sudo_debug_printf(SUDO_DEBUG_ERROR, "I/O error, terminating child");
1.1 misho 426: schedule_signal(SIGKILL);
427: forward_signals(sv[0]);
428: break;
429: }
430: }
431:
432: if (log_io) {
433: /* Flush any remaining output and free pty-related memory. */
434: pty_close(cstat);
435: }
436:
437: #ifdef HAVE_SELINUX
438: if (ISSET(details->flags, CD_RBAC_ENABLED)) {
439: /* This is probably not needed in log_io mode. */
440: if (selinux_restore_tty() != 0)
441: warningx(_("unable to restore tty label"));
442: }
443: #endif
444:
445: efree(fdsr);
446: efree(fdsw);
447: while (!tq_empty(&sigfwd_list)) {
448: struct sigforward *sigfwd = tq_first(&sigfwd_list);
449: tq_remove(&sigfwd_list, sigfwd);
450: efree(sigfwd);
451: }
452:
1.1.1.2 ! misho 453: debug_return_int(cstat->type == CMD_ERRNO ? -1 : 0);
1.1 misho 454: }
455:
456: /*
457: * Read signals on fd written to by handler().
458: * Returns -1 on error, 0 on child exit, else 1.
459: */
460: static int
1.1.1.2 ! misho 461: handle_signals(int sv[2], pid_t child, int log_io, struct command_status *cstat)
1.1 misho 462: {
463: unsigned char signo;
464: ssize_t nread;
465: int status;
466: pid_t pid;
1.1.1.2 ! misho 467: debug_decl(handle_signals, SUDO_DEBUG_EXEC)
1.1 misho 468:
469: for (;;) {
470: /* read signal pipe */
471: nread = read(signal_pipe[0], &signo, sizeof(signo));
472: if (nread <= 0) {
473: /* It should not be possible to get EOF but just in case. */
474: if (nread == 0)
475: errno = ECONNRESET;
476: /* Restart if interrupted by signal so the pipe doesn't fill. */
477: if (errno == EINTR)
478: continue;
479: /* If pipe is empty, we are done. */
480: if (errno == EAGAIN)
481: break;
1.1.1.2 ! misho 482: sudo_debug_printf(SUDO_DEBUG_ERROR, "error reading signal pipe %s",
! 483: strerror(errno));
1.1 misho 484: cstat->type = CMD_ERRNO;
485: cstat->val = errno;
1.1.1.2 ! misho 486: debug_return_int(-1);
1.1 misho 487: }
1.1.1.2 ! misho 488: sudo_debug_printf(SUDO_DEBUG_DIAG, "received signal %d", signo);
1.1 misho 489: if (signo == SIGCHLD) {
490: /*
491: * If logging I/O, child is the intermediate process,
492: * otherwise it is the command itself.
493: */
494: do {
495: pid = waitpid(child, &status, WUNTRACED|WNOHANG);
496: } while (pid == -1 && errno == EINTR);
497: if (pid == child) {
1.1.1.2 ! misho 498: if (log_io) {
! 499: /*
! 500: * On BSD we get ECONNRESET on sv[0] if monitor dies
! 501: * and select() will return with sv[0] readable.
! 502: * On Linux that doesn't appear to happen so if the
! 503: * monitor dies, shut down the socketpair to force a
! 504: * select() notification.
! 505: */
! 506: (void) shutdown(sv[0], SHUT_WR);
! 507: } else {
1.1 misho 508: if (WIFSTOPPED(status)) {
509: /*
510: * Save the controlling terminal's process group
511: * so we can restore it after we resume.
512: */
513: pid_t saved_pgrp = (pid_t)-1;
514: int fd = open(_PATH_TTY, O_RDWR|O_NOCTTY, 0);
515: if (fd != -1)
516: saved_pgrp = tcgetpgrp(fd);
517: if (kill(getpid(), WSTOPSIG(status)) != 0) {
518: warning("kill(%d, %d)", (int)getpid(),
519: WSTOPSIG(status));
520: }
521: if (fd != -1) {
522: if (saved_pgrp != (pid_t)-1)
523: (void)tcsetpgrp(fd, saved_pgrp);
524: close(fd);
525: }
526: } else {
527: /* Child has exited, we are done. */
528: cstat->type = CMD_WSTATUS;
529: cstat->val = status;
1.1.1.2 ! misho 530: debug_return_int(0);
1.1 misho 531: }
532: }
533: }
534: } else {
535: if (log_io) {
536: /* Schedule signo to be forwared to the child. */
537: schedule_signal(signo);
538: } else {
539: /* Nothing listening on sv[0], send directly. */
540: if (signo == SIGALRM)
1.1.1.2 ! misho 541: terminate_child(child, false);
1.1 misho 542: else if (kill(child, signo) != 0)
543: warning("kill(%d, %d)", (int)child, signo);
544: }
545: }
546: }
1.1.1.2 ! misho 547: debug_return_int(1);
1.1 misho 548: }
549:
550: /*
551: * Forward signals in sigfwd_list to child listening on fd.
552: */
553: static void
554: forward_signals(int sock)
555: {
556: struct sigforward *sigfwd;
557: struct command_status cstat;
558: ssize_t nsent;
1.1.1.2 ! misho 559: debug_decl(forward_signals, SUDO_DEBUG_EXEC)
1.1 misho 560:
561: while (!tq_empty(&sigfwd_list)) {
562: sigfwd = tq_first(&sigfwd_list);
1.1.1.2 ! misho 563: sudo_debug_printf(SUDO_DEBUG_INFO,
! 564: "sending signal %d to child over backchannel", sigfwd->signo);
1.1 misho 565: cstat.type = CMD_SIGNO;
566: cstat.val = sigfwd->signo;
567: do {
568: nsent = send(sock, &cstat, sizeof(cstat), 0);
569: } while (nsent == -1 && errno == EINTR);
570: tq_remove(&sigfwd_list, sigfwd);
571: efree(sigfwd);
572: if (nsent != sizeof(cstat)) {
573: if (errno == EPIPE) {
1.1.1.2 ! misho 574: sudo_debug_printf(SUDO_DEBUG_ERROR,
! 575: "broken pipe writing to child over backchannel");
1.1 misho 576: /* Other end of socket gone, empty out sigfwd_list. */
577: while (!tq_empty(&sigfwd_list)) {
578: sigfwd = tq_first(&sigfwd_list);
579: tq_remove(&sigfwd_list, sigfwd);
580: efree(sigfwd);
581: }
1.1.1.2 ! misho 582: /* XXX - child (monitor) is dead, we should exit too? */
1.1 misho 583: }
584: break;
585: }
586: }
1.1.1.2 ! misho 587: debug_return;
1.1 misho 588: }
589:
590: /*
591: * Schedule a signal to be forwared.
592: */
593: static void
594: schedule_signal(int signo)
595: {
596: struct sigforward *sigfwd;
1.1.1.2 ! misho 597: debug_decl(schedule_signal, SUDO_DEBUG_EXEC)
1.1 misho 598:
1.1.1.2 ! misho 599: sudo_debug_printf(SUDO_DEBUG_DIAG, "forwarding signal %d to child", signo);
! 600:
! 601: sigfwd = ecalloc(1, sizeof(*sigfwd));
1.1 misho 602: sigfwd->prev = sigfwd;
1.1.1.2 ! misho 603: /* sigfwd->next = NULL; */
1.1 misho 604: sigfwd->signo = signo;
605: tq_append(&sigfwd_list, sigfwd);
1.1.1.2 ! misho 606:
! 607: debug_return;
1.1 misho 608: }
609:
610: /*
611: * Generic handler for signals passed from parent -> child.
612: * The other end of signal_pipe is checked in the main event loop.
613: */
614: void
615: handler(int s)
616: {
617: unsigned char signo = (unsigned char)s;
618:
619: /*
620: * The pipe is non-blocking, if we overflow the kernel's pipe
621: * buffer we drop the signal. This is not a problem in practice.
622: */
1.1.1.2 ! misho 623: ignore_result(write(signal_pipe[1], &signo, sizeof(signo)));
! 624: }
! 625:
! 626: #ifdef SA_SIGINFO
! 627: /*
! 628: * Generic handler for signals passed from parent -> child.
! 629: * The other end of signal_pipe is checked in the main event loop.
! 630: * This version is for the non-pty case and does not forward
! 631: * signals that are generated by the kernel.
! 632: */
! 633: static void
! 634: handler_nofwd(int s, siginfo_t *info, void *context)
! 635: {
! 636: unsigned char signo = (unsigned char)s;
! 637:
! 638: /* Only forward user-generated signals. */
! 639: if (info == NULL || info->si_code <= 0) {
! 640: /*
! 641: * The pipe is non-blocking, if we overflow the kernel's pipe
! 642: * buffer we drop the signal. This is not a problem in practice.
! 643: */
! 644: ignore_result(write(signal_pipe[1], &signo, sizeof(signo)));
! 645: }
1.1 misho 646: }
1.1.1.2 ! misho 647: #endif /* SA_SIGINFO */
1.1 misho 648:
649: /*
650: * Open a pipe and make both ends non-blocking.
651: * Returns 0 on success and -1 on error.
652: */
653: int
654: pipe_nonblock(int fds[2])
655: {
656: int flags, rval;
1.1.1.2 ! misho 657: debug_decl(pipe_nonblock, SUDO_DEBUG_EXEC)
1.1 misho 658:
659: rval = pipe(fds);
660: if (rval != -1) {
661: flags = fcntl(fds[0], F_GETFL, 0);
662: if (flags != -1 && !ISSET(flags, O_NONBLOCK))
663: rval = fcntl(fds[0], F_SETFL, flags | O_NONBLOCK);
664: if (rval != -1) {
665: flags = fcntl(fds[1], F_GETFL, 0);
666: if (flags != -1 && !ISSET(flags, O_NONBLOCK))
667: rval = fcntl(fds[1], F_SETFL, flags | O_NONBLOCK);
668: }
669: if (rval == -1) {
670: close(fds[0]);
671: close(fds[1]);
672: }
673: }
674:
1.1.1.2 ! misho 675: debug_return_int(rval);
1.1 misho 676: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>