* src/su.c (prepare_pam_close_session): Extract the creation of a
child and listening for signal in the parent from run_shell(). prepare_pam_close_session() is now executed before the creation of the pam session and before the UID is changed. This allows to close the session as root.
This commit is contained in:
parent
69371ba2c2
commit
e9045e9f55
@ -1,3 +1,11 @@
|
|||||||
|
2011-06-13 Nicolas François <nicolas.francois@centraliens.net>
|
||||||
|
|
||||||
|
* src/su.c (prepare_pam_close_session): Extract the creation of a
|
||||||
|
child and listening for signal in the parent from run_shell().
|
||||||
|
prepare_pam_close_session() is now executed before the creation of
|
||||||
|
the pam session and before the UID is changed. This allows to
|
||||||
|
close the session as root.
|
||||||
|
|
||||||
2011-06-12 Nicolas François <nicolas.francois@centraliens.net>
|
2011-06-12 Nicolas François <nicolas.francois@centraliens.net>
|
||||||
|
|
||||||
* src/su.c (save_caller_context): Extract from main() the code
|
* src/su.c (save_caller_context): Extract from main() the code
|
||||||
|
2
NEWS
2
NEWS
@ -46,6 +46,8 @@ shadow-4.1.4.3 -> shadow-4.1.5 UNRELEASED
|
|||||||
* Do not forward the controlling terminal to commands executed with -c.
|
* Do not forward the controlling terminal to commands executed with -c.
|
||||||
This prevents tty hijacking which could lead to execution with the
|
This prevents tty hijacking which could lead to execution with the
|
||||||
caller's privileges.
|
caller's privileges.
|
||||||
|
* Close PAM sessions as root. This will be more friendly to PAM modules
|
||||||
|
like pam_mount or pam_systemd.
|
||||||
- newgrp, sg, groupmems
|
- newgrp, sg, groupmems
|
||||||
* Fix parsing of gshadow entries.
|
* Fix parsing of gshadow entries.
|
||||||
- useradd
|
- useradd
|
||||||
|
77
src/su.c
77
src/su.c
@ -257,49 +257,31 @@ static void catch_signals (int sig)
|
|||||||
caught = sig;
|
caught = sig;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This I ripped out of su.c from sh-utils after the Mandrake pam patch
|
/*
|
||||||
* have been applied. Some work was needed to get it integrated into
|
* Create a session and fork.
|
||||||
* su.c from shadow.
|
* Only the child returns. The parent will wait for the child to terminate
|
||||||
|
* and exit.
|
||||||
*/
|
*/
|
||||||
static void run_shell (const char *shellstr, char *args[], bool doshell,
|
static void prepare_pam_close_session (void)
|
||||||
char *const envp[])
|
|
||||||
{
|
{
|
||||||
pid_t child;
|
|
||||||
sigset_t ourset;
|
sigset_t ourset;
|
||||||
int status;
|
int status;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
child = fork ();
|
pid_child = fork ();
|
||||||
if (child == 0) { /* child shell */
|
if (pid_child == 0) { /* child shell */
|
||||||
/*
|
return; /* Only the child will return from pam_create_session */
|
||||||
* PAM_DATA_SILENT is not supported by some modules, and
|
} else if ((pid_t)-1 == pid_child) {
|
||||||
* there is no strong need to clean up the process space's
|
|
||||||
* memory since we will either call exec or exit.
|
|
||||||
pam_end (pamh, PAM_SUCCESS | PAM_DATA_SILENT);
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (doshell) {
|
|
||||||
(void) shell (shellstr, (char *) args[0], envp);
|
|
||||||
} else {
|
|
||||||
/* There is no need for a controlling terminal.
|
|
||||||
* This avoids the callee to inject commands on
|
|
||||||
* the caller's tty. */
|
|
||||||
(void) setsid ();
|
|
||||||
|
|
||||||
execve_shell (shellstr, (char **) args, envp);
|
|
||||||
}
|
|
||||||
|
|
||||||
exit (errno == ENOENT ? E_CMD_NOTFOUND : E_CMD_NOEXEC);
|
|
||||||
} else if ((pid_t)-1 == child) {
|
|
||||||
(void) fprintf (stderr,
|
(void) fprintf (stderr,
|
||||||
_("%s: Cannot fork user shell\n"),
|
_("%s: Cannot fork user shell\n"),
|
||||||
Prog);
|
Prog);
|
||||||
SYSLOG ((LOG_WARN, "Cannot execute %s", shellstr));
|
SYSLOG ((LOG_WARN, "Cannot execute %s", shellstr));
|
||||||
closelog ();
|
closelog ();
|
||||||
exit (1);
|
exit (1);
|
||||||
|
/* Only the child returns. See above. */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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,
|
(void) fprintf (stderr,
|
||||||
@ -320,8 +302,8 @@ static void run_shell (const char *shellstr, char *args[], bool doshell,
|
|||||||
|| (sigaction (SIGTERM, &action, NULL) != 0)
|
|| (sigaction (SIGTERM, &action, NULL) != 0)
|
||||||
|| ( !doshell /* handle SIGINT (Ctrl-C), SIGQUIT
|
|| ( !doshell /* handle SIGINT (Ctrl-C), SIGQUIT
|
||||||
* (Ctrl-\), and SIGTSTP (Ctrl-Z)
|
* (Ctrl-\), and SIGTSTP (Ctrl-Z)
|
||||||
* since the child does not control
|
* since the child will not control
|
||||||
* the tty anymore.
|
* the tty.
|
||||||
*/
|
*/
|
||||||
&& ( (sigaddset (&ourset, SIGINT) != 0)
|
&& ( (sigaddset (&ourset, SIGINT) != 0)
|
||||||
|| (sigaddset (&ourset, SIGQUIT) != 0)
|
|| (sigaddset (&ourset, SIGQUIT) != 0)
|
||||||
@ -359,7 +341,7 @@ static void run_shell (const char *shellstr, char *args[], bool doshell,
|
|||||||
* We will SIGSTOP ourself on the next
|
* We will SIGSTOP ourself on the next
|
||||||
* waitpid round.
|
* waitpid round.
|
||||||
*/
|
*/
|
||||||
kill (child, SIGSTOP);
|
kill (pid_child, SIGSTOP);
|
||||||
stop = false;
|
stop = false;
|
||||||
} else if ( ((pid_t)-1 != pid)
|
} else if ( ((pid_t)-1 != pid)
|
||||||
&& (0 != WIFSTOPPED (status))) {
|
&& (0 != WIFSTOPPED (status))) {
|
||||||
@ -377,7 +359,7 @@ static void run_shell (const char *shellstr, char *args[], bool doshell,
|
|||||||
(void) fputs ("\n", stderr);
|
(void) fputs ("\n", stderr);
|
||||||
(void) fputs (_("Session terminated, terminating shell..."),
|
(void) fputs (_("Session terminated, terminating shell..."),
|
||||||
stderr);
|
stderr);
|
||||||
(void) kill (child, caught);
|
(void) kill (pid_child, caught);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = pam_close_session (pamh, 0);
|
ret = pam_close_session (pamh, 0);
|
||||||
@ -401,8 +383,33 @@ static void run_shell (const char *shellstr, char *args[], bool doshell,
|
|||||||
|
|
||||||
exit ((0 != WIFEXITED (status)) ? WEXITSTATUS (status)
|
exit ((0 != WIFEXITED (status)) ? WEXITSTATUS (status)
|
||||||
: WTERMSIG (status) + 128);
|
: WTERMSIG (status) + 128);
|
||||||
|
/* Only the child returns. See above. */
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
static void run_shell (const char *shellstr, char *args[], bool doshell,
|
||||||
|
char *const envp[])
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* PAM_DATA_SILENT is not supported by some modules, and
|
||||||
|
* there is no strong need to clean up the process space's
|
||||||
|
* memory since we will either call exec or exit.
|
||||||
|
pam_end (pamh, PAM_SUCCESS | PAM_DATA_SILENT);
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (doshell) {
|
||||||
|
(void) shell (shellstr, (char *) args[0], envp);
|
||||||
|
} else {
|
||||||
|
/* There is no need for a controlling terminal.
|
||||||
|
* This avoids the callee to inject commands on
|
||||||
|
* the caller's tty. */
|
||||||
|
(void) setsid ();
|
||||||
|
|
||||||
|
execve_shell (shellstr, (char **) args, envp);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit (errno == ENOENT ? E_CMD_NOTFOUND : E_CMD_NOEXEC);
|
||||||
|
}
|
||||||
|
#endif /* USE_PAM */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* usage - print command line syntax and exit
|
* usage - print command line syntax and exit
|
||||||
@ -1020,6 +1027,8 @@ int main (int argc, char **argv)
|
|||||||
exit (1);
|
exit (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prepare_pam_close_session ();
|
||||||
|
|
||||||
/* become the new user */
|
/* become the new user */
|
||||||
if (change_uid (pw) != 0) {
|
if (change_uid (pw) != 0) {
|
||||||
pam_close_session (pamh, 0);
|
pam_close_session (pamh, 0);
|
||||||
|
Loading…
Reference in New Issue
Block a user