Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

start-stop-daemon: fix: pam_start before chrooting #517

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 28 additions & 8 deletions man/start-stop-daemon.8
Original file line number Diff line number Diff line change
Expand Up @@ -139,22 +139,22 @@ is an integer, it is passed directly to sched_setscheduler(2).
Sets the priority parameter of the scheduling policy of the daemon. See sched(7) for details.
.It Fl 1 , -stdout Ar logfile
Redirect the standard output of the process to logfile when started with
.Fl background .
.Fl -background .
The logfile Must be an absolute pathname, but relative to the path
optionally given with
.Fl r , -chroot .
The logfile can also be a named pipe.
.It Fl 2 , -stderr Ar logfile
Redirect the standard error of the process to logfile when started with
.Fl background .
.Fl -background .
The logfile must be an absolute pathname, but relative to the path
optionally given with
.Fl r , -chroot .
The logfile can also be a named pipe.
.It Fl 3 , -stdout-logger Ar cmd
Run cmd as a child process redirecting the standard output to the
standard input of cmd when started with
.Fl background .
.Fl -background .
Cmd must be an absolute pathname, but relative to the path optionally given with
.Fl r , -chroot .
This process must be prepared to accept input on stdin and be able to
Expand All @@ -163,11 +163,35 @@ log it or send it to another location.
Run cmd as a child process and
Redirect the standard error of the process to the standard input of cmd
when started with
.Fl background .
.Fl -background .
Cmd must be an absolute pathname, but relative to the path optionally given with
.Fl r , -chroot .
This process must be prepared to accept input on stdin and be able to
log it or send it to another location.
.It Fl 5 , -stdout-before-chroot Ar logfile
Same as
.Fl -stdout ,
except that
.Ar logfile
is opened before entering the chroot.
.It Fl 6 , -stderr-before-chroot Ar logfile
Same as
.Fl -stderr ,
except that
.Ar logfile
is opened before entering the chroot.
.It Fl 7 , -stdout-logger-before-chroot Ar cmd
Same as
.Fl -stdout-logger ,
except that
.Ar cmd
is executed before entering the chroot.
.It Fl 8 , -stderr-logger-before-chroot Ar cmd
Same as
.Fl -stderr-logger ,
except that
.Ar cmd
is executed before entering the chroot.
.It Fl -capabilities Ar cap-list
Start the daemon with the listed inheritable, ambient and bounding capabilities.
The format is the same as in cap_iab(3).
Expand All @@ -183,10 +207,6 @@ Wait
after starting and check that daemon is still running.
Useful for daemons that check configuration after forking or stopping race
conditions where the pidfile is written out after forking.
.It Fl 2 , -stderr Ar logfile
The same thing as
.Fl 1 , -stdout
but with the standard error output.
.El
.Pp
These options are only used for stopping daemons:
Expand Down
213 changes: 130 additions & 83 deletions src/start-stop-daemon/start-stop-daemon.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,43 +94,47 @@ enum {

const char *applet = NULL;
const char *extraopts = NULL;
const char getoptstring[] = "I:KN:PR:Sa:bc:d:e:g:ik:mn:op:s:tu:r:w:x:1:2:3:4:" \
const char getoptstring[] = "I:KN:PR:Sa:bc:d:e:g:ik:mn:op:s:tu:r:w:x:1:2:3:4:5:6:7:8:" \
getoptstring_COMMON;
const struct option longopts[] = {
{ "capabilities", 1, NULL, LONGOPT_CAPABILITIES},
{ "secbits", 1, NULL, LONGOPT_SECBITS},
{ "no-new-privs", 0, NULL, LONGOPT_NO_NEW_PRIVS},
{ "ionice", 1, NULL, 'I'},
{ "stop", 0, NULL, 'K'},
{ "nicelevel", 1, NULL, 'N'},
{ "oom-score-adj",1, NULL, LONGOPT_OOM_SCORE_ADJ},
{ "retry", 1, NULL, 'R'},
{ "start", 0, NULL, 'S'},
{ "startas", 1, NULL, 'a'},
{ "background", 0, NULL, 'b'},
{ "chuid", 1, NULL, 'c'},
{ "chdir", 1, NULL, 'd'},
{ "env", 1, NULL, 'e'},
{ "umask", 1, NULL, 'k'},
{ "group", 1, NULL, 'g'},
{ "interpreted", 0, NULL, 'i'},
{ "make-pidfile", 0, NULL, 'm'},
{ "name", 1, NULL, 'n'},
{ "oknodo", 0, NULL, 'o'},
{ "pidfile", 1, NULL, 'p'},
{ "signal", 1, NULL, 's'},
{ "test", 0, NULL, 't'},
{ "user", 1, NULL, 'u'},
{ "chroot", 1, NULL, 'r'},
{ "wait", 1, NULL, 'w'},
{ "exec", 1, NULL, 'x'},
{ "stdout", 1, NULL, '1'},
{ "stderr", 1, NULL, '2'},
{ "stdout-logger",1, NULL, '3'},
{ "stderr-logger",1, NULL, '4'},
{ "progress", 0, NULL, 'P'},
{ "scheduler", 1, NULL, LONGOPT_SCHEDULER},
{ "scheduler-priority", 1, NULL, LONGOPT_SCHEDULER_PRIO},
{ "capabilities", 1, NULL, LONGOPT_CAPABILITIES},
{ "secbits", 1, NULL, LONGOPT_SECBITS},
{ "no-new-privs", 0, NULL, LONGOPT_NO_NEW_PRIVS},
{ "ionice", 1, NULL, 'I'},
{ "stop", 0, NULL, 'K'},
{ "nicelevel", 1, NULL, 'N'},
{ "oom-score-adj", 1, NULL, LONGOPT_OOM_SCORE_ADJ},
{ "retry", 1, NULL, 'R'},
{ "start", 0, NULL, 'S'},
{ "startas", 1, NULL, 'a'},
{ "background", 0, NULL, 'b'},
{ "chuid", 1, NULL, 'c'},
{ "chdir", 1, NULL, 'd'},
{ "env", 1, NULL, 'e'},
{ "umask", 1, NULL, 'k'},
{ "group", 1, NULL, 'g'},
{ "interpreted", 0, NULL, 'i'},
{ "make-pidfile", 0, NULL, 'm'},
{ "name", 1, NULL, 'n'},
{ "oknodo", 0, NULL, 'o'},
{ "pidfile", 1, NULL, 'p'},
{ "signal", 1, NULL, 's'},
{ "test", 0, NULL, 't'},
{ "user", 1, NULL, 'u'},
{ "chroot", 1, NULL, 'r'},
{ "wait", 1, NULL, 'w'},
{ "exec", 1, NULL, 'x'},
{ "stdout", 1, NULL, '1'},
{ "stderr", 1, NULL, '2'},
{ "stdout-logger", 1, NULL, '3'},
{ "stderr-logger", 1, NULL, '4'},
{ "stdout-before-chroot", 1, NULL, '5'},
{ "stderr-before-chroot", 1, NULL, '6'},
{ "stdout-logger-before-chroot", 1, NULL, '7'},
{ "stderr-logger-before-chroot", 1, NULL, '8'},
{ "progress", 0, NULL, 'P'},
{ "scheduler", 1, NULL, LONGOPT_SCHEDULER},
{ "scheduler-priority", 1, NULL, LONGOPT_SCHEDULER_PRIO},
longopts_COMMON
};
const char * const longopts_help[] = {
Expand Down Expand Up @@ -165,6 +169,10 @@ const char * const longopts_help[] = {
"Redirect stderr to file",
"Redirect stdout to process",
"Redirect stderr to process",
"Redirect stdout to file, opened before chrooting",
"Redirect stderr to file, opened before chrooting",
"Redirect stdout to process, executed before chrooting",
"Redirect stderr to process, ecxcuted before chrooting",
"Print dots each second while waiting",
"Set process scheduler",
"Set process scheduler priority",
Expand Down Expand Up @@ -320,10 +328,14 @@ int main(int argc, char **argv)
gid_t gid = 0;
char *home = NULL;
int tid = 0;
char *redirect_stderr = NULL;
char *redirect_stdout = NULL;
char *stderr_process = NULL;
char *redirect_stderr = NULL;
char *stdout_process = NULL;
char *stderr_process = NULL;
char *redirect_stdout_before_chroot = NULL;
char *redirect_stderr_before_chroot = NULL;
char *stdout_process_before_chroot = NULL;
char *stderr_process_before_chroot = NULL;
int stdin_fd;
int stdout_fd;
int stderr_fd;
Expand Down Expand Up @@ -609,6 +621,22 @@ int main(int argc, char **argv)
stderr_process = optarg;
break;

case '5': /* --stdout-before-chroot /path/to/stdout.logfile */
redirect_stdout_before_chroot = optarg;
break;

case '6': /* --stderr-before-chroot /path/to/stderr.logfile */
redirect_stderr_before_chroot = optarg;
break;

case '7': /* --stdout-logger-before-chroot "command outside of chroot to run for stdout logging" */
stdout_process_before_chroot = optarg;
break;

case '8': /* --stderr-logger-before-chroot "command outside of chroot to run for stderr logging" */
stderr_process_before_chroot = optarg;
break;

case LONGOPT_SCHEDULER: /* --scheduler "Process scheduler policy" */
scheduler = optarg;
break;
Expand Down Expand Up @@ -653,6 +681,13 @@ int main(int argc, char **argv)
++argc;
};

if ((redirect_stdout_before_chroot && redirect_stdout)
|| (redirect_stderr_before_chroot && redirect_stderr)
|| (stdout_process_before_chroot && stdout_process)
|| (stderr_process_before_chroot && stderr_process))
eerrorx("%s: stream redirection and logging options can't be used together with"
" their before-chroot variants", applet);

if (stop || sig != -1) {
if (sig == -1)
sig = SIGTERM;
Expand Down Expand Up @@ -899,6 +934,60 @@ int main(int argc, char **argv)
fclose(fp);
}

#ifdef HAVE_PAM
if (changeuser != NULL) {
pamr = pam_start("start-stop-daemon",
changeuser, &conv, &pamh);

if (pamr == PAM_SUCCESS)
pamr = pam_acct_mgmt(pamh, PAM_SILENT);
if (pamr == PAM_SUCCESS)
pamr = pam_open_session(pamh, PAM_SILENT);
if (pamr != PAM_SUCCESS)
eerrorx("%s: pam error: %s",
applet, pam_strerror(pamh, pamr));
}
#endif

stdin_fd = devnull_fd;
stdout_fd = devnull_fd;
stderr_fd = devnull_fd;

#define log_redirection(redirect_stdout,redirect_stderr,stdout_process,stderr_process) \
if (redirect_stdout) { \
if ((stdout_fd = open(redirect_stdout, \
O_WRONLY | O_CREAT | O_APPEND, \
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) == -1) \
eerrorx("%s: unable to open the logfile" \
" for stdout `%s': %s", \
applet, redirect_stdout, strerror(errno)); \
}else if (stdout_process) { \
stdout_fd = rc_pipe_command(stdout_process); \
if (stdout_fd == -1) \
eerrorx("%s: unable to open the logging process" \
" for stdout `%s': %s", \
applet, stdout_process, strerror(errno)); \
} \
if (redirect_stderr) { \
if ((stderr_fd = open(redirect_stderr, \
O_WRONLY | O_CREAT | O_APPEND, \
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) == -1) \
eerrorx("%s: unable to open the logfile" \
" for stderr `%s': %s", \
applet, redirect_stderr, strerror(errno)); \
}else if (stderr_process) { \
stderr_fd = rc_pipe_command(stderr_process); \
if (stderr_fd == -1) \
eerrorx("%s: unable to open the logging process" \
" for stderr `%s': %s", \
applet, stderr_process, strerror(errno)); \
}

log_redirection(redirect_stdout_before_chroot,
redirect_stderr_before_chroot,
stdout_process_before_chroot,
stderr_process_before_chroot)

if (ch_root && chroot(ch_root) < 0)
eerrorx("%s: chroot `%s': %s",
applet, ch_root, strerror(errno));
Expand All @@ -916,21 +1005,6 @@ int main(int argc, char **argv)
fclose(fp);
}

#ifdef HAVE_PAM
if (changeuser != NULL) {
pamr = pam_start("start-stop-daemon",
changeuser, &conv, &pamh);

if (pamr == PAM_SUCCESS)
pamr = pam_acct_mgmt(pamh, PAM_SILENT);
if (pamr == PAM_SUCCESS)
pamr = pam_open_session(pamh, PAM_SILENT);
if (pamr != PAM_SUCCESS)
eerrorx("%s: pam error: %s",
applet, pam_strerror(pamh, pamr));
}
#endif

if (gid && setgid(gid))
eerrorx("%s: unable to set groupid to %d",
applet, gid);
Expand Down Expand Up @@ -1043,37 +1117,10 @@ int main(int argc, char **argv)
setenv("PATH", newpath, 1);
}

stdin_fd = devnull_fd;
stdout_fd = devnull_fd;
stderr_fd = devnull_fd;
if (redirect_stdout) {
if ((stdout_fd = open(redirect_stdout,
O_WRONLY | O_CREAT | O_APPEND,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) == -1)
eerrorx("%s: unable to open the logfile"
" for stdout `%s': %s",
applet, redirect_stdout, strerror(errno));
}else if (stdout_process) {
stdout_fd = rc_pipe_command(stdout_process);
if (stdout_fd == -1)
eerrorx("%s: unable to open the logging process"
" for stdout `%s': %s",
applet, stdout_process, strerror(errno));
}
if (redirect_stderr) {
if ((stderr_fd = open(redirect_stderr,
O_WRONLY | O_CREAT | O_APPEND,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) == -1)
eerrorx("%s: unable to open the logfile"
" for stderr `%s': %s",
applet, redirect_stderr, strerror(errno));
}else if (stderr_process) {
stderr_fd = rc_pipe_command(stderr_process);
if (stderr_fd == -1)
eerrorx("%s: unable to open the logging process"
" for stderr `%s': %s",
applet, stderr_process, strerror(errno));
}
log_redirection(redirect_stdout,
redirect_stderr,
stdout_process,
stderr_process)

if (background)
dup2(stdin_fd, STDIN_FILENO);
Expand Down
12 changes: 6 additions & 6 deletions src/supervise-daemon/supervise-daemon.c
Original file line number Diff line number Diff line change
Expand Up @@ -406,12 +406,6 @@ static void child_process(char *exec, char **argv)
fclose(fp);
}

if (ch_root && chroot(ch_root) < 0)
eerrorx("%s: chroot `%s': %s", applet, ch_root, strerror(errno));

if (ch_dir && chdir(ch_dir) < 0)
eerrorx("%s: chdir `%s': %s", applet, ch_dir, strerror(errno));

#ifdef HAVE_PAM
if (changeuser != NULL) {
pamr = pam_start("supervise-daemon",
Expand All @@ -426,6 +420,12 @@ static void child_process(char *exec, char **argv)
}
#endif

if (ch_root && chroot(ch_root) < 0)
eerrorx("%s: chroot `%s': %s", applet, ch_root, strerror(errno));

if (ch_dir && chdir(ch_dir) < 0)
eerrorx("%s: chdir `%s': %s", applet, ch_dir, strerror(errno));

if (gid && setgid(gid))
eerrorx("%s: unable to set groupid to %d", applet, gid);
if (changeuser && initgroups(changeuser, gid))
Expand Down