Change how the mailer is waited for. Instead of having a SIGCHLD
handler, use the double fork trick to orphan the child that opens the pipe to sendmail. Fixes a problem running su on some Linux distros.
This commit is contained in:
79
logging.c
79
logging.c
@@ -425,8 +425,8 @@ send_mail(line)
|
|||||||
{
|
{
|
||||||
FILE *mail;
|
FILE *mail;
|
||||||
char *p;
|
char *p;
|
||||||
int pfd[2];
|
int pfd[2], status;
|
||||||
pid_t pid;
|
pid_t pid, rv;
|
||||||
sigaction_t sa, saved_sa_pipe;
|
sigaction_t sa, saved_sa_pipe;
|
||||||
#ifndef NO_ROOT_MAILER
|
#ifndef NO_ROOT_MAILER
|
||||||
static char *root_envp[] = {
|
static char *root_envp[] = {
|
||||||
@@ -443,19 +443,58 @@ send_mail(line)
|
|||||||
if (!def_mailerpath || !def_mailto)
|
if (!def_mailerpath || !def_mailto)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* Fork a child so we can be asyncronous. */
|
||||||
|
switch (pid = fork()) {
|
||||||
|
case -1:
|
||||||
|
/* Error. */
|
||||||
|
error(1, "cannot fork");
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
/* Child continues below. */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Parent waits and returns. */
|
||||||
|
do {
|
||||||
|
#ifdef sudo_waitpid
|
||||||
|
rv = sudo_waitpid(pid, &status, 0);
|
||||||
|
#else
|
||||||
|
rv = wait(&status);
|
||||||
|
#endif
|
||||||
|
} while (rv == -1 && errno == EINTR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fork again and orphan the grandchild so parent can continue. */
|
||||||
|
switch (pid = fork()) {
|
||||||
|
case -1:
|
||||||
|
/* Error. */
|
||||||
|
warning("cannot fork");
|
||||||
|
_exit(1);
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
/* Grandchild continues below. */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Orphan grandchild. */
|
||||||
|
_exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
/* Ignore SIGPIPE in case mailer exits prematurely (or is missing). */
|
/* Ignore SIGPIPE in case mailer exits prematurely (or is missing). */
|
||||||
sigemptyset(&sa.sa_mask);
|
sigemptyset(&sa.sa_mask);
|
||||||
sa.sa_flags = 0;
|
sa.sa_flags = 0;
|
||||||
sa.sa_handler = SIG_IGN;
|
sa.sa_handler = SIG_IGN;
|
||||||
(void) sigaction(SIGPIPE, &sa, &saved_sa_pipe);
|
(void) sigaction(SIGPIPE, &sa, &saved_sa_pipe);
|
||||||
|
|
||||||
if (pipe(pfd) == -1)
|
if (pipe(pfd) == -1) {
|
||||||
error(1, "cannot open pipe");
|
warning("cannot open pipe");
|
||||||
|
_exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
switch (pid = fork()) {
|
switch (pid = fork()) {
|
||||||
case -1:
|
case -1:
|
||||||
/* Error. */
|
/* Error. */
|
||||||
error(1, "cannot fork");
|
warning("cannot fork");
|
||||||
|
_exit(1);
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
{
|
{
|
||||||
@@ -463,7 +502,7 @@ send_mail(line)
|
|||||||
char *mpath, *mflags;
|
char *mpath, *mflags;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* Child, set stdin to output side of the pipe */
|
/* Great-grandchild, set stdin to output side of the pipe */
|
||||||
if (pfd[0] != STDIN_FILENO) {
|
if (pfd[0] != STDIN_FILENO) {
|
||||||
(void) dup2(pfd[0], STDIN_FILENO);
|
(void) dup2(pfd[0], STDIN_FILENO);
|
||||||
(void) close(pfd[0]);
|
(void) close(pfd[0]);
|
||||||
@@ -533,7 +572,13 @@ send_mail(line)
|
|||||||
(void) fprintf(mail, "\n\n%s : %s : %s : %s\n\n", user_host,
|
(void) fprintf(mail, "\n\n%s : %s : %s : %s\n\n", user_host,
|
||||||
get_timestr(), user_name, line);
|
get_timestr(), user_name, line);
|
||||||
fclose(mail);
|
fclose(mail);
|
||||||
|
do {
|
||||||
|
#ifdef sudo_waitpid
|
||||||
|
rv = sudo_waitpid(pid, &status, 0);
|
||||||
|
#else
|
||||||
|
rv = wait(&status);
|
||||||
|
#endif
|
||||||
|
} while (rv == -1 && errno == EINTR);
|
||||||
(void) sigaction(SIGPIPE, &saved_sa_pipe, NULL);
|
(void) sigaction(SIGPIPE, &saved_sa_pipe, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -551,26 +596,6 @@ should_mail(status)
|
|||||||
(def_mail_no_perms && !ISSET(status, VALIDATE_OK)));
|
(def_mail_no_perms && !ISSET(status, VALIDATE_OK)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* SIGCHLD sig handler--wait for children as they die.
|
|
||||||
*/
|
|
||||||
RETSIGTYPE
|
|
||||||
reapchild(sig)
|
|
||||||
int sig;
|
|
||||||
{
|
|
||||||
int status, serrno = errno;
|
|
||||||
#ifdef sudo_waitpid
|
|
||||||
pid_t pid;
|
|
||||||
|
|
||||||
do {
|
|
||||||
pid = sudo_waitpid(-1, &status, WNOHANG);
|
|
||||||
} while (pid != 0 && (pid != -1 || errno == EINTR));
|
|
||||||
#else
|
|
||||||
(void) wait(&status);
|
|
||||||
#endif
|
|
||||||
errno = serrno;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return an ascii string with the current date + time
|
* Return an ascii string with the current date + time
|
||||||
* Uses strftime() if available, else falls back to ctime().
|
* Uses strftime() if available, else falls back to ctime().
|
||||||
|
5
sudo.c
5
sudo.c
@@ -153,7 +153,7 @@ login_cap_t *lc;
|
|||||||
#ifdef HAVE_BSD_AUTH_H
|
#ifdef HAVE_BSD_AUTH_H
|
||||||
char *login_style;
|
char *login_style;
|
||||||
#endif /* HAVE_BSD_AUTH_H */
|
#endif /* HAVE_BSD_AUTH_H */
|
||||||
sigaction_t saved_sa_int, saved_sa_quit, saved_sa_tstp, saved_sa_chld;
|
sigaction_t saved_sa_int, saved_sa_quit, saved_sa_tstp;
|
||||||
static char *runas_user;
|
static char *runas_user;
|
||||||
static char *runas_group;
|
static char *runas_group;
|
||||||
static struct sudo_nss_list *snl;
|
static struct sudo_nss_list *snl;
|
||||||
@@ -208,8 +208,6 @@ main(argc, argv, envp)
|
|||||||
(void) sigaction(SIGINT, &sa, &saved_sa_int);
|
(void) sigaction(SIGINT, &sa, &saved_sa_int);
|
||||||
(void) sigaction(SIGQUIT, &sa, &saved_sa_quit);
|
(void) sigaction(SIGQUIT, &sa, &saved_sa_quit);
|
||||||
(void) sigaction(SIGTSTP, &sa, &saved_sa_tstp);
|
(void) sigaction(SIGTSTP, &sa, &saved_sa_tstp);
|
||||||
sa.sa_handler = reapchild;
|
|
||||||
(void) sigaction(SIGCHLD, &sa, &saved_sa_chld);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Turn off core dumps and make sure fds 0-2 are open.
|
* Turn off core dumps and make sure fds 0-2 are open.
|
||||||
@@ -492,7 +490,6 @@ main(argc, argv, envp)
|
|||||||
(void) sigaction(SIGINT, &saved_sa_int, NULL);
|
(void) sigaction(SIGINT, &saved_sa_int, NULL);
|
||||||
(void) sigaction(SIGQUIT, &saved_sa_quit, NULL);
|
(void) sigaction(SIGQUIT, &saved_sa_quit, NULL);
|
||||||
(void) sigaction(SIGTSTP, &saved_sa_tstp, NULL);
|
(void) sigaction(SIGTSTP, &saved_sa_tstp, NULL);
|
||||||
(void) sigaction(SIGCHLD, &saved_sa_chld, NULL);
|
|
||||||
|
|
||||||
/* Close the password and group files and free up memory. */
|
/* Close the password and group files and free up memory. */
|
||||||
sudo_endpwent();
|
sudo_endpwent();
|
||||||
|
@@ -59,7 +59,7 @@
|
|||||||
__unused static const char rcsid[] = "$Sudo$";
|
__unused static const char rcsid[] = "$Sudo$";
|
||||||
#endif /* lint */
|
#endif /* lint */
|
||||||
|
|
||||||
extern sigaction_t saved_sa_int, saved_sa_quit, saved_sa_tstp, saved_sa_chld;
|
extern sigaction_t saved_sa_int, saved_sa_quit, saved_sa_tstp;
|
||||||
extern char **environ;
|
extern char **environ;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -226,11 +226,10 @@ int sudo_edit(argc, argv, envp)
|
|||||||
nargv[ac++] = tf[i++].tfile;
|
nargv[ac++] = tf[i++].tfile;
|
||||||
nargv[ac] = NULL;
|
nargv[ac] = NULL;
|
||||||
|
|
||||||
/* We wait for our own children and can be suspended. */
|
/* Allow the editor to be suspended. */
|
||||||
sigemptyset(&sa.sa_mask);
|
sigemptyset(&sa.sa_mask);
|
||||||
sa.sa_flags = SA_RESTART;
|
sa.sa_flags = SA_RESTART;
|
||||||
sa.sa_handler = SIG_DFL;
|
sa.sa_handler = SIG_DFL;
|
||||||
(void) sigaction(SIGCHLD, &sa, NULL);
|
|
||||||
(void) sigaction(SIGTSTP, &saved_sa_tstp, NULL);
|
(void) sigaction(SIGTSTP, &saved_sa_tstp, NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -246,7 +245,6 @@ int sudo_edit(argc, argv, envp)
|
|||||||
/* child */
|
/* child */
|
||||||
(void) sigaction(SIGINT, &saved_sa_int, NULL);
|
(void) sigaction(SIGINT, &saved_sa_int, NULL);
|
||||||
(void) sigaction(SIGQUIT, &saved_sa_quit, NULL);
|
(void) sigaction(SIGQUIT, &saved_sa_quit, NULL);
|
||||||
(void) sigaction(SIGCHLD, &saved_sa_chld, NULL);
|
|
||||||
set_perms(PERM_FULL_USER);
|
set_perms(PERM_FULL_USER);
|
||||||
closefrom(def_closefrom + 1);
|
closefrom(def_closefrom + 1);
|
||||||
execvp(nargv[0], nargv);
|
execvp(nargv[0], nargv);
|
||||||
|
18
visudo.c
18
visudo.c
@@ -651,19 +651,13 @@ run_command(path, argv)
|
|||||||
char **argv;
|
char **argv;
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
pid_t pid;
|
pid_t pid, rv;
|
||||||
sigset_t set, oset;
|
|
||||||
|
|
||||||
(void) sigemptyset(&set);
|
|
||||||
(void) sigaddset(&set, SIGCHLD);
|
|
||||||
(void) sigprocmask(SIG_BLOCK, &set, &oset);
|
|
||||||
|
|
||||||
switch (pid = fork()) {
|
switch (pid = fork()) {
|
||||||
case -1:
|
case -1:
|
||||||
error(1, "unable to run %s", path);
|
error(1, "unable to run %s", path);
|
||||||
break; /* NOTREACHED */
|
break; /* NOTREACHED */
|
||||||
case 0:
|
case 0:
|
||||||
(void) sigprocmask(SIG_SETMASK, &oset, NULL);
|
|
||||||
sudo_endpwent();
|
sudo_endpwent();
|
||||||
sudo_endgrent();
|
sudo_endgrent();
|
||||||
closefrom(STDERR_FILENO + 1);
|
closefrom(STDERR_FILENO + 1);
|
||||||
@@ -673,15 +667,15 @@ run_command(path, argv)
|
|||||||
break; /* NOTREACHED */
|
break; /* NOTREACHED */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
#ifdef sudo_waitpid
|
#ifdef sudo_waitpid
|
||||||
pid = sudo_waitpid(pid, &status, 0);
|
rv = sudo_waitpid(pid, &status, 0);
|
||||||
#else
|
#else
|
||||||
pid = wait(&status);
|
rv = wait(&status);
|
||||||
#endif
|
#endif
|
||||||
|
} while (rv == -1 && errno == EINTR);
|
||||||
|
|
||||||
(void) sigprocmask(SIG_SETMASK, &oset, NULL);
|
if (rv == -1 || !WIFEXITED(status))
|
||||||
|
|
||||||
if (pid == -1 || !WIFEXITED(status))
|
|
||||||
return(-1);
|
return(-1);
|
||||||
return(WEXITSTATUS(status));
|
return(WEXITSTATUS(status));
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user