From: Todd C. Miller Date: Thu, 22 Jan 2004 02:57:01 +0000 (+0000) Subject: Fix suspending the editor in -e mode. Because we do a fork() first X-Git-Tag: SUDO_1_6_8~210 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5ccddf81762a1789be375fca241a2c85b9d78fe4;p=sudo Fix suspending the editor in -e mode. Because we do a fork() first we need to be notified when the child has been stopped and then send that same signal to ourself so the shell can do its job control thing. --- diff --git a/sudo.c b/sudo.c index d8292180a..ff127c2ee 100644 --- a/sudo.c +++ b/sudo.c @@ -152,6 +152,7 @@ login_cap_t *lc; #ifdef HAVE_BSD_AUTH_H char *login_style; #endif /* HAVE_BSD_AUTH_H */ +sigaction_t saved_sa_int, saved_sa_quit, saved_sa_tstp, saved_sa_chld; void (*set_perms) __P((int)); @@ -167,7 +168,7 @@ main(argc, argv, envp) int sudo_mode; int pwflag; char **new_environ; - sigaction_t sa, saved_sa_int, saved_sa_quit, saved_sa_tstp, saved_sa_chld; + sigaction_t sa; extern int printmatches; extern char **environ; @@ -413,15 +414,15 @@ main(argc, argv, envp) warn("unable to change directory to %s", runas_pw->pw_dir); } + if (sudo_mode & MODE_EDIT) + exit(sudo_edit(NewArgc, NewArgv)); + /* Restore signal handlers before we exec. */ (void) sigaction(SIGINT, &saved_sa_int, NULL); (void) sigaction(SIGQUIT, &saved_sa_quit, NULL); (void) sigaction(SIGTSTP, &saved_sa_tstp, NULL); (void) sigaction(SIGCHLD, &saved_sa_chld, NULL); - if (sudo_mode & MODE_EDIT) - exit(sudo_edit(NewArgc, NewArgv)); - #ifndef PROFILING if ((sudo_mode & MODE_BACKGROUND) && fork() > 0) exit(0); diff --git a/sudo_edit.c b/sudo_edit.c index b6bfd9b49..3bdcb5743 100644 --- a/sudo_edit.c +++ b/sudo_edit.c @@ -64,6 +64,7 @@ #endif /* HAVE_ERR_H */ #include #include +#include #include #include @@ -73,6 +74,8 @@ static const char rcsid[] = "$Sudo$"; #endif /* lint */ +extern sigaction_t saved_sa_int, saved_sa_quit, saved_sa_tstp, saved_sa_chld; + /* * Wrapper to allow users to edit privileged files with their own uid. */ @@ -81,11 +84,12 @@ int sudo_edit(argc, argv) char **argv; { ssize_t nread, nwritten; - pid_t pid; + pid_t kidpid, pid; const char *tmpdir; char **nargv, **ap, *editor, *cp; char buf[BUFSIZ]; int i, ac, ofd, tfd, nargc, rval; + sigaction_t sa; struct stat sb; struct tempfile { char *tfile; @@ -207,28 +211,49 @@ int sudo_edit(argc, argv) nargv[ac++] = tf[i++].tfile; nargv[ac] = NULL; + /* We wait for our own children and can be suspended. */ + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + sa.sa_handler = SIG_DFL; + (void) sigaction(SIGCHLD, &sa, NULL); + (void) sigaction(SIGTSTP, &saved_sa_tstp, NULL); + /* * Fork and exec the editor as with the invoking user's creds. */ - pid = fork(); - if (pid == -1) { + kidpid = fork(); + if (kidpid == -1) { warn("fork"); goto cleanup; - } else if (pid == 0) { + } else if (kidpid == 0) { /* child */ + (void) sigaction(SIGINT, &saved_sa_int, NULL); + (void) sigaction(SIGQUIT, &saved_sa_quit, NULL); + (void) sigaction(SIGCHLD, &saved_sa_chld, NULL); set_perms(PERM_FULL_USER); execvp(nargv[0], nargv); warn("unable to execute %s", nargv[0]); _exit(127); } - /* In parent, wait for child to finish. */ + /* Anxious parent, waiting for letters home from camp... */ + do { #ifdef sudo_waitpid - pid = sudo_waitpid(pid, &i, 0); + pid = sudo_waitpid(kidpid, &i, WUNTRACED); #else - pid = wait(&i); + pid = wait(&i); #endif - rval = pid == -1 ? -1 : (i >> 8); + if (pid == kidpid) { + if (WIFSTOPPED(i)) + kill(getpid(), WSTOPSIG(i)); + else + break; + } + } while (pid != -1 || errno == EINTR); + if (pid == -1 || !WIFEXITED(i)) + rval = 1; + else + rval = WEXITSTATUS(i); /* Copy contents of temp files to real ones */ for (i = 0; i < argc - 1; i++) {