]> granicus.if.org Git - sudo/commitdiff
Fix suspending the editor in -e mode. Because we do a fork() first
authorTodd C. Miller <Todd.Miller@courtesan.com>
Thu, 22 Jan 2004 02:57:01 +0000 (02:57 +0000)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Thu, 22 Jan 2004 02:57:01 +0000 (02:57 +0000)
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.

sudo.c
sudo_edit.c

diff --git a/sudo.c b/sudo.c
index d8292180ac34a78a29328402641ac39c61607976..ff127c2eeaa9120719fced23eea106e5c3e5aeb3 100644 (file)
--- 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);
index b6bfd9b491c2d229e40edef53383d53b9511f5fd..3bdcb5743eb73dbb55cae6ac246ddbe1407142bf 100644 (file)
@@ -64,6 +64,7 @@
 #endif /* HAVE_ERR_H */
 #include <ctype.h>
 #include <pwd.h>
+#include <signal.h>
 #include <errno.h>
 #include <fcntl.h>
 
@@ -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++) {