* 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.
This commit is contained in:
nekral-guest 2009-09-08 20:39:15 +00:00
parent da18e77e9a
commit 756700ddf3
4 changed files with 91 additions and 7 deletions

View File

@ -1,3 +1,11 @@
2009-09-08 Nicolas François <nicolas.francois@centraliens.net>
* 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 <nicolas.francois@centraliens.net> 2009-09-08 Nicolas François <nicolas.francois@centraliens.net>
* src/useradd.c: The default value for the CREATE_MAIL_SPOOL * src/useradd.c: The default value for the CREATE_MAIL_SPOOL

6
NEWS
View File

@ -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 * report usage error to stderr, but report usage help to stdout (and return
zero) when explicitly requested (e.g. with --help). 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 shadow-4.1.4.1 -> shadow-4.1.4.2 2009-07-24
- general - general

View File

@ -358,6 +358,53 @@
</variablelist> </variablelist>
</refsect1> </refsect1>
<refsect1 id='exit_values'>
<title>EXIT VALUES</title>
<para>
On success, <command>su</command> returns the exit value of the
command it executed.
</para>
<para>
If this command was terminated by a signal, <command>su</command>
returns the number of this signal plus 128.
</para>
<para>
If su has to kill the command (because it was asked to terminate,
and the command did not terminate in time), <command>su</command>
returns 255.
</para>
<para>
Some exit values from <command>su</command> are independent from the
executed command:
<variablelist>
<varlistentry>
<term><replaceable>0</replaceable></term>
<listitem>
<para>success (<option>--help</option> only)</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable>1</replaceable></term>
<listitem>
<para>System or authentication failure</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable>126</replaceable></term>
<listitem>
<para>The requested command was not found</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable>127</replaceable></term>
<listitem>
<para>The requested command could not be executed</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</refsect1>
<refsect1 id='see_also'> <refsect1 id='see_also'>
<title>SEE ALSO</title> <title>SEE ALSO</title>
<para><citerefentry> <para><citerefentry>

View File

@ -78,6 +78,8 @@
* Global variables * Global variables
*/ */
char *Prog; 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 */ /* not needed by sulog.c anymore */
static char name[BUFSIZ]; static char name[BUFSIZ];
@ -103,11 +105,16 @@ extern size_t newenvc;
/* local function prototypes */ /* local function prototypes */
static void execve_shell (const char *shellstr,
char *args[],
char *const envp[]);
static RETSIGTYPE kill_child (int s);
#ifndef USE_PAM #ifndef USE_PAM
static RETSIGTYPE die (int); static RETSIGTYPE die (int);
static int iswheel (const char *); static int iswheel (const char *);
#endif /* !USE_PAM */
#ifndef USE_PAM
/* /*
* die - set or reset termio modes. * die - set or reset termio modes.
* *
@ -126,7 +133,7 @@ static RETSIGTYPE die (int killed)
if (killed) { if (killed) {
closelog (); closelog ();
exit (killed); exit (128+killed);
} }
} }
@ -143,6 +150,18 @@ static int iswheel (const char *username)
} }
#endif /* !USE_PAM */ #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" */ /* borrowed from GNU sh-utils' "su.c" */
static bool restricted_shell (const char *shellstr) static bool restricted_shell (const char *shellstr)
{ {
@ -252,6 +271,7 @@ static void run_shell (const char *shellstr, char *args[], bool doshell,
exit (1); exit (1);
} }
/* parent only */ /* parent only */
pid_child = child;
sigfillset (&ourset); sigfillset (&ourset);
if (sigprocmask (SIG_BLOCK, &ourset, NULL) != 0) { if (sigprocmask (SIG_BLOCK, &ourset, NULL) != 0) {
(void) fprintf (stderr, "%s: signal malfunction\n", Prog); (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) { if (caught) {
fprintf (stderr, "\nSession terminated, killing shell..."); (void) fputs ("\n", stderr);
(void) fputs (_("Session terminated, terminating shell..."),
stderr);
kill (child, SIGTERM); kill (child, SIGTERM);
} }
@ -309,10 +331,11 @@ static void run_shell (const char *shellstr, char *args[], bool doshell,
ret = pam_end (pamh, PAM_SUCCESS); ret = pam_end (pamh, PAM_SUCCESS);
if (caught) { if (caught) {
sleep (2); (void) signal (SIGALRM, kill_child);
kill (child, SIGKILL); (void) alarm (2);
fprintf (stderr, " ...killed.\n");
exit (-1); (void) wait (&status);
(void) fputs (_(" ...terminated.\n"), stderr);
} }
exit ((0 != WIFEXITED (status)) ? WEXITSTATUS (status) exit ((0 != WIFEXITED (status)) ? WEXITSTATUS (status)