Replace the double fork with a fork + daemonize.

This commit is contained in:
Todd C. Miller
2008-06-22 20:19:42 +00:00
parent 4578548c45
commit ca6eddf0df
4 changed files with 58 additions and 34 deletions

View File

@@ -341,6 +341,9 @@
/* Define to 1 if you have the `setrlimit' function. */ /* Define to 1 if you have the `setrlimit' function. */
#undef HAVE_SETRLIMIT #undef HAVE_SETRLIMIT
/* Define to 1 if you have the `setsid' function. */
#undef HAVE_SETSID
/* Define to 1 if you have the `set_auth_parameters' function. */ /* Define to 1 if you have the `set_auth_parameters' function. */
#undef HAVE_SET_AUTH_PARAMETERS #undef HAVE_SET_AUTH_PARAMETERS

3
configure vendored
View File

@@ -15506,9 +15506,10 @@ LIBS=$ac_save_LIBS
for ac_func in strchr strrchr memchr memcpy memset sysconf tzset \ for ac_func in strchr strrchr memchr memcpy memset sysconf tzset \
strftime setrlimit initgroups getgroups fstat gettimeofday \ strftime setrlimit initgroups getgroups fstat gettimeofday \
setlocale getaddrinfo setlocale getaddrinfo setsid
do do
as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
{ echo "$as_me:$LINENO: checking for $ac_func" >&5 { echo "$as_me:$LINENO: checking for $ac_func" >&5

View File

@@ -1757,7 +1757,7 @@ dnl
AC_FUNC_GETGROUPS AC_FUNC_GETGROUPS
AC_CHECK_FUNCS(strchr strrchr memchr memcpy memset sysconf tzset \ AC_CHECK_FUNCS(strchr strrchr memchr memcpy memset sysconf tzset \
strftime setrlimit initgroups getgroups fstat gettimeofday \ strftime setrlimit initgroups getgroups fstat gettimeofday \
setlocale getaddrinfo) setlocale getaddrinfo setsid)
if test -z "$SKIP_SETRESUID"; then if test -z "$SKIP_SETRESUID"; then
AC_CHECK_FUNCS(setresuid, [SKIP_SETREUID=yes]) AC_CHECK_FUNCS(setresuid, [SKIP_SETREUID=yes])
fi fi

View File

@@ -27,6 +27,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/param.h> #include <sys/param.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <stdio.h> #include <stdio.h>
#ifdef STDC_HEADERS #ifdef STDC_HEADERS
@@ -52,6 +53,7 @@
#include <signal.h> #include <signal.h>
#include <time.h> #include <time.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h>
#include "sudo.h" #include "sudo.h"
@@ -425,9 +427,9 @@ send_mail(line)
{ {
FILE *mail; FILE *mail;
char *p; char *p;
int pfd[2], status; int fd, pfd[2], status;
pid_t pid, rv; pid_t pid, rv;
sigaction_t sa, saved_sa_pipe; sigaction_t sa;
#ifndef NO_ROOT_MAILER #ifndef NO_ROOT_MAILER
static char *root_envp[] = { static char *root_envp[] = {
"HOME=/", "HOME=/",
@@ -443,20 +445,32 @@ send_mail(line)
if (!def_mailerpath || !def_mailto) if (!def_mailerpath || !def_mailto)
return; return;
/* Fork a child so we can be asyncronous. */ /* Fork and return, child will daemonize. */
switch (pid = fork()) { switch (pid = fork()) {
case -1: case -1:
/* Error. */ /* Error. */
error(1, "cannot fork"); error(1, "cannot fork");
break; break;
case 0: case 0:
/* Child continues below. */ /* Child. */
switch (pid = fork()) {
case -1:
/* Error. */
mysyslog(LOG_ERR, "cannot fork: %m");
_exit(1);
case 0:
/* Grandchild continues below. */
break; break;
default: default:
/* Parent waits and returns. */ /* Parent will wait for us. */
_exit(0);
}
break;
default:
/* Parent. */
do { do {
#ifdef sudo_waitpid #ifdef HAVE_WAITPID
rv = sudo_waitpid(pid, &status, 0); rv = waitpid(pid, &status, 0);
#else #else
rv = wait(&status); rv = wait(&status);
#endif #endif
@@ -464,36 +478,46 @@ send_mail(line)
return; return;
} }
/* Fork again and orphan the grandchild so parent can continue. */ /* Daemonize - disassociate from session/tty. */
switch (pid = fork()) { #ifdef HAVE_SETSID
case -1: if (setsid() == -1)
/* Error. */ warning("setsid");
warning("cannot fork"); #else
_exit(1); setpgrp(0, 0);
break; # ifdef TIOCNOTTY
case 0: if ((fd = open(_PATH_TTY, O_RDWR, 0644)) != -1) {
/* Grandchild continues below. */ ioctl(fd, TIOCNOTTY, NULL);
break; close(fd);
default:
/* Orphan grandchild. */
_exit(0);
} }
# endif
#endif
chdir("/");
if ((fd = open(_PATH_DEVNULL, O_RDWR, 0644)) != -1) {
(void) dup2(fd, STDIN_FILENO);
(void) dup2(fd, STDOUT_FILENO);
(void) dup2(fd, STDERR_FILENO);
}
/* Close password, group and other fds so we don't leak. */
sudo_endpwent();
sudo_endgrent();
closefrom(STDERR_FILENO + 1);
/* 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, NULL);
if (pipe(pfd) == -1) { if (pipe(pfd) == -1) {
warning("cannot open pipe"); mysyslog(LOG_ERR, "cannot open pipe: %m");
_exit(1); _exit(1);
} }
switch (pid = fork()) { switch (pid = fork()) {
case -1: case -1:
/* Error. */ /* Error. */
warning("cannot fork"); mysyslog(LOG_ERR, "cannot fork: %m");
_exit(1); _exit(1);
break; break;
case 0: case 0:
@@ -502,7 +526,7 @@ send_mail(line)
char *mpath, *mflags; char *mpath, *mflags;
int i; int i;
/* Great-grandchild, set stdin to output side of the pipe */ /* Child, 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]);
@@ -525,11 +549,6 @@ send_mail(line)
} }
argv[i] = NULL; argv[i] = NULL;
/* Close password, group and other fds so we don't leak. */
sudo_endpwent();
sudo_endgrent();
closefrom(STDERR_FILENO + 1);
/* /*
* Depending on the config, either run the mailer as root * Depending on the config, either run the mailer as root
* (so user cannot kill it) or as the user (for the paranoid). * (so user cannot kill it) or as the user (for the paranoid).
@@ -541,6 +560,7 @@ send_mail(line)
set_perms(PERM_FULL_USER); set_perms(PERM_FULL_USER);
execv(mpath, argv); execv(mpath, argv);
#endif /* NO_ROOT_MAILER */ #endif /* NO_ROOT_MAILER */
mysyslog(LOG_ERR, "cannot execute %s: %m", mpath);
_exit(127); _exit(127);
} }
break; break;
@@ -573,13 +593,13 @@ send_mail(line)
get_timestr(), user_name, line); get_timestr(), user_name, line);
fclose(mail); fclose(mail);
do { do {
#ifdef sudo_waitpid #ifdef HAVE_WAITPID
rv = sudo_waitpid(pid, &status, 0); rv = waitpid(pid, &status, 0);
#else #else
rv = wait(&status); rv = wait(&status);
#endif #endif
} while (rv == -1 && errno == EINTR); } while (rv == -1 && errno == EINTR);
(void) sigaction(SIGPIPE, &saved_sa_pipe, NULL); _exit(0);
} }
/* /*