diff --git a/ChangeLog b/ChangeLog index 7bbc7a4b..027c8b05 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2009-09-08 Nicolas François + + * NEWS, src/su.c: When su receives a signal, wait for the child to + terminate (after sending a SIGTERM), and kill it only if it did + not terminate by itself. No delay will be enforced if the child + cooperates. See http://bugs.gentoo.org/282094 + * NEWS, man/su.1.xml: Document su's exit values. + 2009-09-08 Nicolas François * src/useradd.c: The default value for the CREATE_MAIL_SPOOL diff --git a/NEWS b/NEWS index 8451ad77..dcc0ee28 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,12 @@ shadow-4.1.4.2 -> shadow-4.1.4.3 UNRELEASED * report usage error to stderr, but report usage help to stdout (and return zero) when explicitly requested (e.g. with --help). +- su + * Document the su exit values. + * When su receives a signal, wait for the child to terminate (after + sending a SIGTERM), and kill it only if it did not terminate by itself. + No delay will be enforced if the child cooperates. + shadow-4.1.4.1 -> shadow-4.1.4.2 2009-07-24 - general diff --git a/man/su.1.xml b/man/su.1.xml index d965705f..fc0afed0 100644 --- a/man/su.1.xml +++ b/man/su.1.xml @@ -358,6 +358,53 @@ + + EXIT VALUES + + On success, su returns the exit value of the + command it executed. + + + If this command was terminated by a signal, su + returns the number of this signal plus 128. + + + If su has to kill the command (because it was asked to terminate, + and the command did not terminate in time), su + returns 255. + + + Some exit values from su are independent from the + executed command: + + + 0 + + success ( only) + + + + 1 + + System or authentication failure + + + + 126 + + The requested command was not found + + + + 127 + + The requested command could not be executed + + + + + + SEE ALSO diff --git a/src/su.c b/src/su.c index 716cbf63..072c51d1 100644 --- a/src/su.c +++ b/src/su.c @@ -78,6 +78,8 @@ * Global variables */ char *Prog; +/* PID of the child, in case it needs to be killed */ +static pid_t pid_child = 0; /* not needed by sulog.c anymore */ static char name[BUFSIZ]; @@ -103,11 +105,16 @@ extern size_t newenvc; /* local function prototypes */ +static void execve_shell (const char *shellstr, + char *args[], + char *const envp[]); +static RETSIGTYPE kill_child (int s); #ifndef USE_PAM - static RETSIGTYPE die (int); static int iswheel (const char *); +#endif /* !USE_PAM */ +#ifndef USE_PAM /* * die - set or reset termio modes. * @@ -126,7 +133,7 @@ static RETSIGTYPE die (int killed) if (killed) { closelog (); - exit (killed); + exit (128+killed); } } @@ -143,6 +150,18 @@ static int iswheel (const char *username) } #endif /* !USE_PAM */ +static RETSIGTYPE kill_child (int unused(s)) +{ + if (0 != pid_child) { + (void) kill (pid_child, SIGKILL); + (void) fputs (_(" ...killed.\n"), stderr); + } else { + (void) fputs (_(" ...waiting for child to terminate.\n"), + stderr); + } + exit (255); +} + /* borrowed from GNU sh-utils' "su.c" */ static bool restricted_shell (const char *shellstr) { @@ -252,6 +271,7 @@ static void run_shell (const char *shellstr, char *args[], bool doshell, exit (1); } /* parent only */ + pid_child = child; sigfillset (&ourset); if (sigprocmask (SIG_BLOCK, &ourset, NULL) != 0) { (void) fprintf (stderr, "%s: signal malfunction\n", Prog); @@ -293,7 +313,9 @@ static void run_shell (const char *shellstr, char *args[], bool doshell, } if (caught) { - fprintf (stderr, "\nSession terminated, killing shell..."); + (void) fputs ("\n", stderr); + (void) fputs (_("Session terminated, terminating shell..."), + stderr); kill (child, SIGTERM); } @@ -309,10 +331,11 @@ static void run_shell (const char *shellstr, char *args[], bool doshell, ret = pam_end (pamh, PAM_SUCCESS); if (caught) { - sleep (2); - kill (child, SIGKILL); - fprintf (stderr, " ...killed.\n"); - exit (-1); + (void) signal (SIGALRM, kill_child); + (void) alarm (2); + + (void) wait (&status); + (void) fputs (_(" ...terminated.\n"), stderr); } exit ((0 != WIFEXITED (status)) ? WEXITSTATUS (status)