execute.c revision 35b8ca3aaf8cb044ad76675dfcad89e000dd4a5c
d657c51f14601d0235434ffb78cf6ac0f27cc83cLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering This file is part of systemd.
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering Copyright 2010 Lennart Poettering
4c2413bffa7861bd3c4b3589c821ab7e0ac51c83Jan Engelhardt systemd is free software; you can redistribute it and/or modify it
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering under the terms of the GNU General Public License as published by
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering the Free Software Foundation; either version 2 of the License, or
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering (at your option) any later version.
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering systemd is distributed in the hope that it will be useful, but
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering General Public License for more details.
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering You should have received a copy of the GNU General Public License
4c2413bffa7861bd3c4b3589c821ab7e0ac51c83Jan Engelhardt along with systemd; If not, see <http://www.gnu.org/licenses/>.
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering/* This assumes there is a 'tty' group */
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poetteringstatic int shift_fds(int fds[], unsigned n_fds) {
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering /* Modifies the fds array! (sorts it) */
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering /* Already at right index? */
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering if ((nfd = fcntl(fds[i], F_DUPFD, i+3)) < 0)
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering /* Hmm, the fd we wanted isn't free? Then
4c2413bffa7861bd3c4b3589c821ab7e0ac51c83Jan Engelhardt * let's remember that and try again from here*/
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poetteringstatic int flags_fds(const int fds[], unsigned n_fds, bool nonblock) {
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering /* Drops/Sets O_NONBLOCK and FD_CLOEXEC from the file flags */
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering for (i = 0; i < n_fds; i++) {
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering if ((r = fd_nonblock(fds[i], nonblock)) < 0)
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering /* We unconditionally drop FD_CLOEXEC from the fds,
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering * since after all we want to pass these fds to our
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poetteringstatic const char *tty_path(const ExecContext *context) {
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poetteringstatic int open_null_as(int flags, int nfd) {
b97610038a122ff30e60b1996369ca4b979d8b19Kay Sievers if ((fd = open("/dev/null", flags|O_NOCTTY)) < 0)
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poetteringstatic int connect_logger_as(const ExecContext *context, ExecOutput output, const char *ident, int nfd) {
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering strncpy(sa.un.sun_path+1, LOGGER_SOCKET, sizeof(sa.un.sun_path)-1);
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + sizeof(LOGGER_SOCKET) - 1) < 0) {
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering /* We speak a very simple protocol between log server
4c2413bffa7861bd3c4b3589c821ab7e0ac51c83Jan Engelhardt * and client: one line for the log destination (kmsg
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering * or syslog), followed by the priority field,
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering * followed by the process name. Since we replaced
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering * stdin/stderr we simple use stdio to write to
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering * it. Note that we use stderr, to minimize buffer
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering * flushing issues. */
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering output == EXEC_OUTPUT_KMSG_AND_CONSOLE ? "kmsg+console" :
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering output == EXEC_OUTPUT_SYSLOG ? "syslog" :
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering "syslog+console",
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering context->syslog_identifier ? context->syslog_identifier : ident,
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poetteringstatic int open_terminal_as(const char *path, mode_t mode, int nfd) {
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering if ((fd = open_terminal(path, mode | O_NOCTTY)) < 0)
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poetteringstatic bool is_terminal_input(ExecInput i) {
4c2413bffa7861bd3c4b3589c821ab7e0ac51c83Jan Engelhardtstatic int fixup_input(ExecInput std_input, int socket_fd, bool apply_tty_stdin) {
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering if (is_terminal_input(std_input) && !apply_tty_stdin)
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering if (std_input == EXEC_INPUT_SOCKET && socket_fd < 0)
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poetteringstatic int fixup_output(ExecOutput std_output, int socket_fd) {
4c2413bffa7861bd3c4b3589c821ab7e0ac51c83Jan Engelhardt if (std_output == EXEC_OUTPUT_SOCKET && socket_fd < 0)
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poetteringstatic int setup_input(const ExecContext *context, int socket_fd, bool apply_tty_stdin) {
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering return open_null_as(O_RDONLY, STDIN_FILENO);
4c2413bffa7861bd3c4b3589c821ab7e0ac51c83Jan Engelhardt r = dup2(fd, STDIN_FILENO) < 0 ? -errno : STDIN_FILENO;
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering return dup2(socket_fd, STDIN_FILENO) < 0 ? -errno : STDIN_FILENO;
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering assert_not_reached("Unknown input type");
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poetteringstatic int setup_output(const ExecContext *context, int socket_fd, const char *ident, bool apply_tty_stdin) {
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering o = fixup_output(context->std_output, socket_fd);
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering /* This expects the input is already set up */
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering /* If input got downgraded, inherit the original value */
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering if (i == EXEC_INPUT_NULL && is_terminal_input(context->std_input))
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering return open_terminal_as(tty_path(context), O_WRONLY, STDOUT_FILENO);
4c2413bffa7861bd3c4b3589c821ab7e0ac51c83Jan Engelhardt /* If the input is connected to anything that's not a /dev/null, inherit that... */
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering return dup2(STDIN_FILENO, STDOUT_FILENO) < 0 ? -errno : STDOUT_FILENO;
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering /* If we are not started from PID 1 we just inherit STDOUT from our parent process. */
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering /* We need to open /dev/null here anew, to get the
4c2413bffa7861bd3c4b3589c821ab7e0ac51c83Jan Engelhardt * right access mode. So we fall through */
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering return open_null_as(O_WRONLY, STDOUT_FILENO);
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering return dup2(STDIN_FILENO, STDOUT_FILENO) < 0 ? -errno : STDOUT_FILENO;
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering /* We don't reset the terminal if this is just about output */
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering return open_terminal_as(tty_path(context), O_WRONLY, STDOUT_FILENO);
b97610038a122ff30e60b1996369ca4b979d8b19Kay Sievers return connect_logger_as(context, o, ident, STDOUT_FILENO);
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering return dup2(socket_fd, STDOUT_FILENO) < 0 ? -errno : STDOUT_FILENO;
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering assert_not_reached("Unknown output type");
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poetteringstatic int setup_error(const ExecContext *context, int socket_fd, const char *ident, bool apply_tty_stdin) {
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering o = fixup_output(context->std_output, socket_fd);
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering e = fixup_output(context->std_error, socket_fd);
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering /* This expects the input and output are already set up */
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering /* Don't change the stderr file descriptor if we inherit all
4c2413bffa7861bd3c4b3589c821ab7e0ac51c83Jan Engelhardt * the way and are not on a tty */
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering !is_terminal_input(context->std_input) &&
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering /* Duplicate from stdout if possible */
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering if (e == o || e == EXEC_OUTPUT_INHERIT)
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering return dup2(STDOUT_FILENO, STDERR_FILENO) < 0 ? -errno : STDERR_FILENO;
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering return open_null_as(O_WRONLY, STDERR_FILENO);
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering return dup2(STDIN_FILENO, STDERR_FILENO) < 0 ? -errno : STDERR_FILENO;
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering /* We don't reset the terminal if this is just about output */
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering return open_terminal_as(tty_path(context), O_WRONLY, STDERR_FILENO);
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering return connect_logger_as(context, e, ident, STDERR_FILENO);
4c2413bffa7861bd3c4b3589c821ab7e0ac51c83Jan Engelhardt return dup2(socket_fd, STDERR_FILENO) < 0 ? -errno : STDERR_FILENO;
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering assert_not_reached("Unknown error type");
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poetteringstatic int chown_terminal(int fd, uid_t uid) {
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering /* This might fail. What matters are the results. */
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering if (st.st_uid != uid || (st.st_mode & 0777) != TTY_MODE)
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poetteringstatic int setup_confirm_stdio(const ExecContext *context,
e49b5aada0df13c9e8fce7338ae34e075dd7ccd1Lennart Poettering int fd = -1, saved_stdin, saved_stdout = -1, r;
cd4010b37349413db1e553e213e62e654ca28113Lennart Poettering /* This returns positive EXIT_xxx return values instead of
cd4010b37349413db1e553e213e62e654ca28113Lennart Poettering * negative errno style values! */
cd4010b37349413db1e553e213e62e654ca28113Lennart Poettering if ((saved_stdin = fcntl(STDIN_FILENO, F_DUPFD, 3)) < 0)
cd4010b37349413db1e553e213e62e654ca28113Lennart Poettering if ((saved_stdout = fcntl(STDOUT_FILENO, F_DUPFD, 3)) < 0) {
cd4010b37349413db1e553e213e62e654ca28113Lennart Poettering context->std_input == EXEC_INPUT_TTY_FAIL,
cd4010b37349413db1e553e213e62e654ca28113Lennart Poettering context->std_input == EXEC_INPUT_TTY_FORCE,
cd4010b37349413db1e553e213e62e654ca28113Lennart Poettering false)) < 0) {
cd4010b37349413db1e553e213e62e654ca28113Lennart Poetteringstatic int restore_confirm_stdio(const ExecContext *context,
cd4010b37349413db1e553e213e62e654ca28113Lennart Poettering /* This returns positive EXIT_xxx return values instead of
cd4010b37349413db1e553e213e62e654ca28113Lennart Poettering * negative errno style values! */
cd4010b37349413db1e553e213e62e654ca28113Lennart Poettering if (is_terminal_input(context->std_input)) {
cd4010b37349413db1e553e213e62e654ca28113Lennart Poettering /* The service wants terminal input. */
cd4010b37349413db1e553e213e62e654ca28113Lennart Poettering context->std_output == EXEC_OUTPUT_INHERIT ||
cd4010b37349413db1e553e213e62e654ca28113Lennart Poettering /* If the service doesn't want a controlling terminal,
cd4010b37349413db1e553e213e62e654ca28113Lennart Poettering * then we need to get rid entirely of what we have
4f0be680b5323e037314cfbd3dba34f03e637c8fLennart Poettering if (dup2(*saved_stdin, STDIN_FILENO) < 0)
4f0be680b5323e037314cfbd3dba34f03e637c8fLennart Poettering if (dup2(*saved_stdout, STDOUT_FILENO) < 0)
4f0be680b5323e037314cfbd3dba34f03e637c8fLennart Poetteringstatic int get_group_creds(const char *groupname, gid_t *gid) {
4f0be680b5323e037314cfbd3dba34f03e637c8fLennart Poettering unsigned long lu;
4f0be680b5323e037314cfbd3dba34f03e637c8fLennart Poettering /* We enforce some special rules for gid=0: in order to avoid
4f0be680b5323e037314cfbd3dba34f03e637c8fLennart Poettering * NSS lookups for root we hardcode its data. */
4f0be680b5323e037314cfbd3dba34f03e637c8fLennart Poettering if (streq(groupname, "root") || streq(groupname, "0")) {
4f0be680b5323e037314cfbd3dba34f03e637c8fLennart Poetteringstatic int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const char **home) {
4f0be680b5323e037314cfbd3dba34f03e637c8fLennart Poettering unsigned long lu;
4f0be680b5323e037314cfbd3dba34f03e637c8fLennart Poettering /* We enforce some special rules for uid=0: in order to avoid
4f0be680b5323e037314cfbd3dba34f03e637c8fLennart Poettering * NSS lookups for root we hardcode its data. */
4f0be680b5323e037314cfbd3dba34f03e637c8fLennart Poettering if (streq(*username, "root") || streq(*username, "0")) {
4f0be680b5323e037314cfbd3dba34f03e637c8fLennart Poettering /* If there are multiple users with the same id, make
4f0be680b5323e037314cfbd3dba34f03e637c8fLennart Poettering * sure to leave $USER to the configured value instead
4f0be680b5323e037314cfbd3dba34f03e637c8fLennart Poettering * of the first occurrence in the database. However if
4f0be680b5323e037314cfbd3dba34f03e637c8fLennart Poettering * the uid was configured by a numeric uid, then let's
4f0be680b5323e037314cfbd3dba34f03e637c8fLennart Poettering * pick the real username from /etc/passwd. */
4f0be680b5323e037314cfbd3dba34f03e637c8fLennart Poetteringstatic int enforce_groups(const ExecContext *context, const char *username, gid_t gid) {
4f0be680b5323e037314cfbd3dba34f03e637c8fLennart Poettering /* Lookup and set GID and supplementary group list. Here too
4f0be680b5323e037314cfbd3dba34f03e637c8fLennart Poettering * we avoid NSS lookups for gid=0. */
408f281bc7d65c86563f46e99e07efd1a1d9e03aLennart Poettering if ((r = get_group_creds(context->group, &gid)) < 0)
408f281bc7d65c86563f46e99e07efd1a1d9e03aLennart Poettering /* First step, initialize groups from /etc/groups */
408f281bc7d65c86563f46e99e07efd1a1d9e03aLennart Poettering /* Second step, set our gids */
408f281bc7d65c86563f46e99e07efd1a1d9e03aLennart Poettering /* Final step, initialize any manually set supplementary groups */
408f281bc7d65c86563f46e99e07efd1a1d9e03aLennart Poettering ngroups_max = (int) sysconf(_SC_NGROUPS_MAX);
251cc8194228ac86c9a7a4c75a54a94cea2095c7Lennart Poettering if ((k = getgroups(ngroups_max, gids)) < 0) {
251cc8194228ac86c9a7a4c75a54a94cea2095c7Lennart Poettering STRV_FOREACH(i, context->supplementary_groups) {
251cc8194228ac86c9a7a4c75a54a94cea2095c7Lennart Poettering if ((r = get_group_creds(*i, gids+k)) < 0) {
408f281bc7d65c86563f46e99e07efd1a1d9e03aLennart Poetteringstatic int enforce_user(const ExecContext *context, uid_t uid) {
28f5c779e5513ab1301ac103471009711b0961e0Kay Sievers /* Sets (but doesn't lookup) the uid and make sure we keep the
28f5c779e5513ab1301ac103471009711b0961e0Kay Sievers * capabilities while doing so. */
251cc8194228ac86c9a7a4c75a54a94cea2095c7Lennart Poettering CAP_SETUID, /* Necessary so that we can run setresuid() below */
251cc8194228ac86c9a7a4c75a54a94cea2095c7Lennart Poettering CAP_SETPCAP /* Necessary so that we can set PR_SET_SECUREBITS later on */
251cc8194228ac86c9a7a4c75a54a94cea2095c7Lennart Poettering /* First step: If we need to keep capabilities but
251cc8194228ac86c9a7a4c75a54a94cea2095c7Lennart Poettering * drop privileges we need to make sure we keep our
251cc8194228ac86c9a7a4c75a54a94cea2095c7Lennart Poettering * caps, whiel we drop privileges. */
251cc8194228ac86c9a7a4c75a54a94cea2095c7Lennart Poettering int sb = context->secure_bits|SECURE_KEEP_CAPS;
251cc8194228ac86c9a7a4c75a54a94cea2095c7Lennart Poettering /* Second step: set the capabilities. This will reduce
251cc8194228ac86c9a7a4c75a54a94cea2095c7Lennart Poettering * the capabilities to the minimum we need. */
251cc8194228ac86c9a7a4c75a54a94cea2095c7Lennart Poettering if (!(d = cap_dup(context->capabilities)))
251cc8194228ac86c9a7a4c75a54a94cea2095c7Lennart Poettering if (cap_set_flag(d, CAP_EFFECTIVE, ELEMENTSOF(bits), bits, CAP_SET) < 0 ||
4f0be680b5323e037314cfbd3dba34f03e637c8fLennart Poettering cap_set_flag(d, CAP_PERMITTED, ELEMENTSOF(bits), bits, CAP_SET) < 0) {
00aa832b948a27507c33e2157e46963852cffc85Lennart Poettering /* Third step: actually set the uids */
00aa832b948a27507c33e2157e46963852cffc85Lennart Poettering /* At this point we should have all necessary capabilities but
00aa832b948a27507c33e2157e46963852cffc85Lennart Poettering are otherwise a normal user. However, the caps might got
00aa832b948a27507c33e2157e46963852cffc85Lennart Poettering corrupted due to the setresuid() so we need clean them up
00aa832b948a27507c33e2157e46963852cffc85Lennart Poettering later. This is done outside of this call. */
00aa832b948a27507c33e2157e46963852cffc85Lennart Poettering /* We don't support conversations */
00aa832b948a27507c33e2157e46963852cffc85Lennart Poettering /* We set up PAM in the parent process, then fork. The child
00aa832b948a27507c33e2157e46963852cffc85Lennart Poettering * will then stay around until killed via PR_GET_PDEATHSIG or
00aa832b948a27507c33e2157e46963852cffc85Lennart Poettering * systemd via the cgroup logic. It will then remove the PAM
00aa832b948a27507c33e2157e46963852cffc85Lennart Poettering * session again. The parent process will exec() the actual
00aa832b948a27507c33e2157e46963852cffc85Lennart Poettering * daemon. We do things this way to ensure that the main PID
00aa832b948a27507c33e2157e46963852cffc85Lennart Poettering * of the daemon is the one we initially fork()ed. */
00aa832b948a27507c33e2157e46963852cffc85Lennart Poettering if ((pam_code = pam_start(name, user, &conv, &handle)) != PAM_SUCCESS) {
00aa832b948a27507c33e2157e46963852cffc85Lennart Poettering if ((pam_code = pam_set_item(handle, PAM_TTY, tty)) != PAM_SUCCESS)
00aa832b948a27507c33e2157e46963852cffc85Lennart Poettering if ((pam_code = pam_acct_mgmt(handle, PAM_SILENT)) != PAM_SUCCESS)
00aa832b948a27507c33e2157e46963852cffc85Lennart Poettering if ((pam_code = pam_open_session(handle, PAM_SILENT)) != PAM_SUCCESS)
00aa832b948a27507c33e2157e46963852cffc85Lennart Poettering if ((pam_code = pam_setcred(handle, PAM_ESTABLISH_CRED | PAM_SILENT)) != PAM_SUCCESS)
00aa832b948a27507c33e2157e46963852cffc85Lennart Poettering /* Block SIGTERM, so that we know that it won't get lost in
00aa832b948a27507c33e2157e46963852cffc85Lennart Poettering * the child */
00aa832b948a27507c33e2157e46963852cffc85Lennart Poettering sigprocmask(SIG_BLOCK, &ss, &old_ss) < 0)
00aa832b948a27507c33e2157e46963852cffc85Lennart Poettering /* The child's job is to reset the PAM session on
00aa832b948a27507c33e2157e46963852cffc85Lennart Poettering * termination */
00aa832b948a27507c33e2157e46963852cffc85Lennart Poettering /* This string must fit in 10 chars (i.e. the length
00aa832b948a27507c33e2157e46963852cffc85Lennart Poettering /* Make sure we don't keep open the passed fds in this
00aa832b948a27507c33e2157e46963852cffc85Lennart Poettering child. We assume that otherwise only those fds are
00aa832b948a27507c33e2157e46963852cffc85Lennart Poettering open here that have been opened by PAM. */
00aa832b948a27507c33e2157e46963852cffc85Lennart Poettering /* Wait until our parent died. This will most likely
00aa832b948a27507c33e2157e46963852cffc85Lennart Poettering * not work since the kernel does not allow
00aa832b948a27507c33e2157e46963852cffc85Lennart Poettering * unprivileged parents kill their privileged children
00aa832b948a27507c33e2157e46963852cffc85Lennart Poettering * this way. We rely on the control groups kill logic
00aa832b948a27507c33e2157e46963852cffc85Lennart Poettering * to do the rest for us. */
00aa832b948a27507c33e2157e46963852cffc85Lennart Poettering if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
00aa832b948a27507c33e2157e46963852cffc85Lennart Poettering /* Check if our parent process might already have
00aa832b948a27507c33e2157e46963852cffc85Lennart Poettering /* Only if our parent died we'll end the session */
00aa832b948a27507c33e2157e46963852cffc85Lennart Poettering if ((pam_code = pam_close_session(handle, PAM_DATA_SILENT)) != PAM_SUCCESS)
606c24e3bd41207c395f24a56bcfcad791e265a5Lennart Poettering pam_end(handle, pam_code | PAM_DATA_SILENT);
606c24e3bd41207c395f24a56bcfcad791e265a5Lennart Poettering /* If the child was forked off successfully it will do all the
606c24e3bd41207c395f24a56bcfcad791e265a5Lennart Poettering * cleanups, so forget about the handle here. */
2f3fcf85c5fa6c9c483b31823a0efdd28914c756Lennart Poettering /* Unblock SIGSUR1 again in the parent */
2f3fcf85c5fa6c9c483b31823a0efdd28914c756Lennart Poettering if (sigprocmask(SIG_SETMASK, &old_ss, NULL) < 0)
2f3fcf85c5fa6c9c483b31823a0efdd28914c756Lennart Poettering /* We close the log explicitly here, since the PAM modules
2f3fcf85c5fa6c9c483b31823a0efdd28914c756Lennart Poettering * might have opened it, but we don't want this fd around. */
2f3fcf85c5fa6c9c483b31823a0efdd28914c756Lennart Poettering pam_code = pam_close_session(handle, PAM_DATA_SILENT);
2f3fcf85c5fa6c9c483b31823a0efdd28914c756Lennart Poettering pam_end(handle, pam_code | PAM_DATA_SILENT);
2f3fcf85c5fa6c9c483b31823a0efdd28914c756Lennart Poettering if (context->std_input == EXEC_INPUT_SOCKET ||
2f3fcf85c5fa6c9c483b31823a0efdd28914c756Lennart Poettering context->std_output == EXEC_OUTPUT_SOCKET ||
2f3fcf85c5fa6c9c483b31823a0efdd28914c756Lennart Poettering context->std_error == EXEC_OUTPUT_SOCKET) {
2f3fcf85c5fa6c9c483b31823a0efdd28914c756Lennart Poettering if ((r = cgroup_bonding_realize_list(cgroup_bondings)))
ef3b5246879094e29cc99c4d24cbfeb19b7da49bLennart Poettering const char *username = NULL, *home = NULL;
ef3b5246879094e29cc99c4d24cbfeb19b7da49bLennart Poettering char **our_env = NULL, **pam_env = NULL, **final_env = NULL, **final_argv = NULL;
ef3b5246879094e29cc99c4d24cbfeb19b7da49bLennart Poettering bool keep_stdout = false, keep_stdin = false;
ef3b5246879094e29cc99c4d24cbfeb19b7da49bLennart Poettering /* This string must fit in 10 chars (i.e. the length
ef3b5246879094e29cc99c4d24cbfeb19b7da49bLennart Poettering /* We reset exactly these signals, since they are the
ef3b5246879094e29cc99c4d24cbfeb19b7da49bLennart Poettering * only ones we set to SIG_IGN in the main daemon. All
ef3b5246879094e29cc99c4d24cbfeb19b7da49bLennart Poettering * others we leave untouched because we set them to
ef3b5246879094e29cc99c4d24cbfeb19b7da49bLennart Poettering * SIG_DFL or a valid handler initially, both of which
ef3b5246879094e29cc99c4d24cbfeb19b7da49bLennart Poettering * will be demoted to SIG_DFL. */
ef3b5246879094e29cc99c4d24cbfeb19b7da49bLennart Poettering sigprocmask(SIG_SETMASK, &ss, NULL) < 0) {
ef3b5246879094e29cc99c4d24cbfeb19b7da49bLennart Poettering /* Close sockets very early to make sure we don't
7c04ad2da1cf08ebf53b9aa9671c8c1dc9577135Lennart Poettering * block init reexecution because it cannot bind its
ef3b5246879094e29cc99c4d24cbfeb19b7da49bLennart Poettering if (close_all_fds(socket_fd >= 0 ? &socket_fd : fds,
ef3b5246879094e29cc99c4d24cbfeb19b7da49bLennart Poettering if (!socket_tcpwrap(socket_fd, context->tcpwrap_name)) {
cbeabcfbc5a5fa27385e5794780e8f034e090606Zbigniew Jędrzejewski-Szmek for (i = 0; i < (int) n_fds; i++) {
cbeabcfbc5a5fa27385e5794780e8f034e090606Zbigniew Jędrzejewski-Szmek if (!socket_tcpwrap(fds[i], context->tcpwrap_name)) {
ef3b5246879094e29cc99c4d24cbfeb19b7da49bLennart Poettering /* We skip the confirmation step if we shall not apply the TTY */
ef3b5246879094e29cc99c4d24cbfeb19b7da49bLennart Poettering (!is_terminal_input(context->std_input) || apply_tty_stdin)) {
ef3b5246879094e29cc99c4d24cbfeb19b7da49bLennart Poettering /* Set up terminal for the question */
d3a86981d1ae4c1d668e18868c3e6c9d2f23c144Lennart Poettering /* Now ask the question. */
d3a86981d1ae4c1d668e18868c3e6c9d2f23c144Lennart Poettering r = ask(&response, "yns", "Execute %s? [Yes, No, Skip] ", line);
d3a86981d1ae4c1d668e18868c3e6c9d2f23c144Lennart Poettering /* Release terminal for the question */
d3a86981d1ae4c1d668e18868c3e6c9d2f23c144Lennart Poettering /* If a socket is connected to STDIN/STDOUT/STDERR, we
d3a86981d1ae4c1d668e18868c3e6c9d2f23c144Lennart Poettering * must sure to drop O_NONBLOCK */
d3a86981d1ae4c1d668e18868c3e6c9d2f23c144Lennart Poettering if (setup_input(context, socket_fd, apply_tty_stdin) < 0) {
d3a86981d1ae4c1d668e18868c3e6c9d2f23c144Lennart Poettering if (setup_output(context, socket_fd, file_name_from_path(command->path), apply_tty_stdin) < 0) {
d3a86981d1ae4c1d668e18868c3e6c9d2f23c144Lennart Poettering if (setup_error(context, socket_fd, file_name_from_path(command->path), apply_tty_stdin) < 0) {
d3a86981d1ae4c1d668e18868c3e6c9d2f23c144Lennart Poettering if (cgroup_bonding_install_list(cgroup_bondings, 0) < 0) {
d3a86981d1ae4c1d668e18868c3e6c9d2f23c144Lennart Poettering snprintf(t, sizeof(t), "%i", context->oom_score_adjust);
d3a86981d1ae4c1d668e18868c3e6c9d2f23c144Lennart Poettering if (write_one_line_file("/proc/self/oom_score_adj", t) < 0) {
d3a86981d1ae4c1d668e18868c3e6c9d2f23c144Lennart Poettering /* Compatibility with Linux <= 2.6.35 */
9ca3c17f207121b3c19a44217558b056a7585944Lennart Poettering adj = (context->oom_score_adjust * -OOM_DISABLE) / OOM_SCORE_ADJ_MAX;
9ca3c17f207121b3c19a44217558b056a7585944Lennart Poettering adj = CLAMP(adj, OOM_DISABLE, OOM_ADJUST_MAX);
9ca3c17f207121b3c19a44217558b056a7585944Lennart Poettering if (write_one_line_file("/proc/self/oom_adj", t) < 0) {
9ca3c17f207121b3c19a44217558b056a7585944Lennart Poettering if (setpriority(PRIO_PROCESS, 0, context->nice) < 0) {
35911459410714a0e9108b35da78f96919b65ee7Lennart Poettering param.sched_priority = context->cpu_sched_priority;
35911459410714a0e9108b35da78f96919b65ee7Lennart Poettering if (sched_setscheduler(0, context->cpu_sched_policy |
35911459410714a0e9108b35da78f96919b65ee7Lennart Poettering (context->cpu_sched_reset_on_fork ? SCHED_RESET_ON_FORK : 0), ¶m) < 0) {
35911459410714a0e9108b35da78f96919b65ee7Lennart Poettering if (sched_setaffinity(0, CPU_ALLOC_SIZE(context->cpuset_ncpus), context->cpuset) < 0) {
35911459410714a0e9108b35da78f96919b65ee7Lennart Poettering if (ioprio_set(IOPRIO_WHO_PROCESS, 0, context->ioprio) < 0) {
35911459410714a0e9108b35da78f96919b65ee7Lennart Poettering if (prctl(PR_SET_TIMERSLACK, context->timer_slack_nsec) < 0) {
a87197f5a22688626dc9bead29ddc1c572b074b9Zbigniew Jędrzejewski-Szmek utmp_put_init_process(0, context->utmp_id, getpid(), getsid(0), context->tty_path);
35911459410714a0e9108b35da78f96919b65ee7Lennart Poettering if (get_user_creds(&username, &uid, &gid, &home) < 0) {
35911459410714a0e9108b35da78f96919b65ee7Lennart Poettering if (is_terminal_input(context->std_input))
35911459410714a0e9108b35da78f96919b65ee7Lennart Poettering if (chown_terminal(STDIN_FILENO, uid) < 0) {
ab06eef8101866dd1337c4759002f7360a9db416Anatol Pomozov if (setup_pam(context->pam_name, username, context->tty_path, &pam_env, fds, n_fds) < 0) {
35911459410714a0e9108b35da78f96919b65ee7Lennart Poettering if (enforce_groups(context, username, uid) < 0) {
85d683970b7dc2c4470b2b7d60c3d9dce28c1471Lennart Poettering if (strv_length(context->read_write_dirs) > 0 ||
85d683970b7dc2c4470b2b7d60c3d9dce28c1471Lennart Poettering strv_length(context->read_only_dirs) > 0 ||
85d683970b7dc2c4470b2b7d60c3d9dce28c1471Lennart Poettering strv_length(context->inaccessible_dirs) > 0 ||
6aa8d43ade72e24c9426e604f7fc4b7582b9db7cLennart Poettering if (chdir(context->working_directory ? context->working_directory : "/") < 0) {
85d683970b7dc2c4470b2b7d60c3d9dce28c1471Lennart Poettering context->root_directory ? context->root_directory : "",
85d683970b7dc2c4470b2b7d60c3d9dce28c1471Lennart Poettering context->working_directory ? context->working_directory : "") < 0) {
85d683970b7dc2c4470b2b7d60c3d9dce28c1471Lennart Poettering /* We repeat the fd closing here, to make sure that
6aa8d43ade72e24c9426e604f7fc4b7582b9db7cLennart Poettering * nothing is leaked from the PAM modules */
85d683970b7dc2c4470b2b7d60c3d9dce28c1471Lennart Poettering flags_fds(fds, n_fds, context->non_blocking) < 0) {
85d683970b7dc2c4470b2b7d60c3d9dce28c1471Lennart Poettering for (i = 0; i < RLIMIT_NLIMITS; i++) {
85d683970b7dc2c4470b2b7d60c3d9dce28c1471Lennart Poettering if (setrlimit(i, context->rlimit[i]) < 0) {
6aa8d43ade72e24c9426e604f7fc4b7582b9db7cLennart Poettering /* PR_GET_SECUREBITS is not privileged, while
85d683970b7dc2c4470b2b7d60c3d9dce28c1471Lennart Poettering * PR_SET_SECUREBITS is. So to suppress
85d683970b7dc2c4470b2b7d60c3d9dce28c1471Lennart Poettering * potential EPERMs we'll try not to call
85d683970b7dc2c4470b2b7d60c3d9dce28c1471Lennart Poettering * PR_SET_SECUREBITS unless necessary. */
85d683970b7dc2c4470b2b7d60c3d9dce28c1471Lennart Poettering if (prctl(PR_GET_SECUREBITS) != context->secure_bits)
85d683970b7dc2c4470b2b7d60c3d9dce28c1471Lennart Poettering if (prctl(PR_SET_SECUREBITS, context->secure_bits) < 0) {
85d683970b7dc2c4470b2b7d60c3d9dce28c1471Lennart Poettering if (cap_set_proc(context->capabilities) < 0) {
85d683970b7dc2c4470b2b7d60c3d9dce28c1471Lennart Poettering if (asprintf(our_env + n_env++, "LISTEN_PID=%lu", (unsigned long) getpid()) < 0 ||
85d683970b7dc2c4470b2b7d60c3d9dce28c1471Lennart Poettering asprintf(our_env + n_env++, "LISTEN_FDS=%u", n_fds) < 0) {
40e21da873c120936faff0aa42a6533f6933edf7Kay Sievers if (asprintf(our_env + n_env++, "HOME=%s", home) < 0) {
6aa8d43ade72e24c9426e604f7fc4b7582b9db7cLennart Poettering if (asprintf(our_env + n_env++, "LOGNAME=%s", username) < 0 ||
6aa8d43ade72e24c9426e604f7fc4b7582b9db7cLennart Poettering asprintf(our_env + n_env++, "USER=%s", username) < 0) {
85d683970b7dc2c4470b2b7d60c3d9dce28c1471Lennart Poettering if (is_terminal_input(context->std_input) ||
85d683970b7dc2c4470b2b7d60c3d9dce28c1471Lennart Poettering context->std_output == EXEC_OUTPUT_TTY ||
6aa8d43ade72e24c9426e604f7fc4b7582b9db7cLennart Poettering if (!(our_env[n_env++] = strdup(default_term_for_tty(tty_path(context))))) {
85d683970b7dc2c4470b2b7d60c3d9dce28c1471Lennart Poettering if (!(final_argv = replace_env_argv(argv, final_env))) {
85d683970b7dc2c4470b2b7d60c3d9dce28c1471Lennart Poettering execve(command->path, final_argv, final_env);
85d683970b7dc2c4470b2b7d60c3d9dce28c1471Lennart Poettering /* We add the new process to the cgroup both in the child (so
85d683970b7dc2c4470b2b7d60c3d9dce28c1471Lennart Poettering * that we can be sure that no user code is ever executed
85d683970b7dc2c4470b2b7d60c3d9dce28c1471Lennart Poettering * outside of the cgroup) and in the parent (so that we can be
85d683970b7dc2c4470b2b7d60c3d9dce28c1471Lennart Poettering * sure that when we kill the cgroup the process will be
85d683970b7dc2c4470b2b7d60c3d9dce28c1471Lennart Poettering * killed too). */
85d683970b7dc2c4470b2b7d60c3d9dce28c1471Lennart Poettering cgroup_bonding_install_list(cgroup_bondings, pid);
85d683970b7dc2c4470b2b7d60c3d9dce28c1471Lennart Poettering log_debug("Forked %s as %lu", command->path, (unsigned long) pid);
85d683970b7dc2c4470b2b7d60c3d9dce28c1471Lennart Poettering exec_status_start(&command->exec_status, pid);
6aa8d43ade72e24c9426e604f7fc4b7582b9db7cLennart Poettering c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 0);
85d683970b7dc2c4470b2b7d60c3d9dce28c1471Lennart Poettering c->syslog_priority = LOG_DAEMON|LOG_INFO;
85d683970b7dc2c4470b2b7d60c3d9dce28c1471Lennart Poettering for (l = 0; l < ELEMENTSOF(c->rlimit); l++) {
85d683970b7dc2c4470b2b7d60c3d9dce28c1471Lennart Poetteringvoid exec_command_done_array(ExecCommand *c, unsigned n) {
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering for (i = 0; i < n; i++)
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poetteringvoid exec_command_free_list(ExecCommand *c) {
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering while ((i = c)) {
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poetteringvoid exec_command_free_array(ExecCommand **c, unsigned n) {
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering for (i = 0; i < n; i++) {
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poetteringstatic void strv_fprintf(FILE *f, char **l) {
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poetteringvoid exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering "%sUMask: %04o\n"
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering "%sWorkingDirectory: %s\n"
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering "%sRootDirectory: %s\n"
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering "%sNonBlocking: %s\n"
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering "%sPrivateTmp: %s\n",
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering prefix, c->working_directory ? c->working_directory : "/",
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering prefix, c->root_directory ? c->root_directory : "/",
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering for (e = c->environment; *e; e++)
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering fprintf(f, "%sEnvironment: %s\n", prefix, *e);
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering "%sTCPWrapName: %s\n",
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering "%sNice: %i\n",
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering "%sOOMScoreAdjust: %i\n",
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering for (i = 0; i < RLIM_NLIMITS; i++)
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering fprintf(f, "%s%s: %llu\n", prefix, rlimit_to_string(i), (unsigned long long) c->rlimit[i]->rlim_max);
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering "%sIOSchedulingClass: %s\n"
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering "%sIOPriority: %i\n",
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering prefix, ioprio_class_to_string(IOPRIO_PRIO_CLASS(c->ioprio)),
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering prefix, (int) IOPRIO_PRIO_DATA(c->ioprio));
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering "%sCPUSchedulingPolicy: %s\n"
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering "%sCPUSchedulingPriority: %i\n"
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering "%sCPUSchedulingResetOnFork: %s\n",
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering prefix, sched_policy_to_string(c->cpu_sched_policy),
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering prefix, yes_no(c->cpu_sched_reset_on_fork));
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering for (i = 0; i < c->cpuset_ncpus; i++)
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering if (CPU_ISSET_S(i, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset))
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering fprintf(f, "%sTimerSlackNSec: %lu\n", prefix, c->timer_slack_nsec);
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering "%sStandardInput: %s\n"
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering "%sStandardOutput: %s\n"
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering "%sStandardError: %s\n",
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering prefix, exec_input_to_string(c->std_input),
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering prefix, exec_output_to_string(c->std_output),
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering prefix, exec_output_to_string(c->std_error));
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering "%sTTYPath: %s\n",
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering if (c->std_output == EXEC_OUTPUT_SYSLOG || c->std_output == EXEC_OUTPUT_KMSG ||
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering c->std_output == EXEC_OUTPUT_SYSLOG_AND_CONSOLE || c->std_output == EXEC_OUTPUT_KMSG_AND_CONSOLE ||
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering c->std_error == EXEC_OUTPUT_SYSLOG || c->std_error == EXEC_OUTPUT_KMSG ||
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering c->std_error == EXEC_OUTPUT_SYSLOG_AND_CONSOLE || c->std_error == EXEC_OUTPUT_KMSG_AND_CONSOLE)
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering "%sSyslogFacility: %s\n"
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering "%sSyslogLevel: %s\n",
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering prefix, log_facility_to_string(LOG_FAC(c->syslog_priority)),
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering prefix, log_level_to_string(LOG_PRI(c->syslog_priority)));
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering if ((t = cap_to_text(c->capabilities, NULL))) {
8ad2685909f988602eca32ccba5c8ea4159e7f2eLennart Poettering fprintf(f, "%sSecure Bits:%s%s%s%s%s%s\n",
0428ddb729d12563b827510e04663de9cb4056f3Lennart Poettering (c->secure_bits & SECURE_KEEP_CAPS) ? " keep-caps" : "",
0428ddb729d12563b827510e04663de9cb4056f3Lennart Poettering (c->secure_bits & SECURE_KEEP_CAPS_LOCKED) ? " keep-caps-locked" : "",
0428ddb729d12563b827510e04663de9cb4056f3Lennart Poettering (c->secure_bits & SECURE_NO_SETUID_FIXUP) ? " no-setuid-fixup" : "",
0428ddb729d12563b827510e04663de9cb4056f3Lennart Poettering (c->secure_bits & SECURE_NO_SETUID_FIXUP_LOCKED) ? " no-setuid-fixup-locked" : "",
0428ddb729d12563b827510e04663de9cb4056f3Lennart Poettering (c->secure_bits & SECURE_NOROOT) ? " noroot" : "",
0428ddb729d12563b827510e04663de9cb4056f3Lennart Poettering (c->secure_bits & SECURE_NOROOT_LOCKED) ? "noroot-locked" : "");
0428ddb729d12563b827510e04663de9cb4056f3Lennart Poettering fprintf(f, "%sCapabilityBoundingSetDrop:", prefix);
96ec33c079caacdf9c7cdfb2cad2f1bc48dfca65Lennart Poettering for (i = 0; i <= CAP_LAST_CAP; i++)
0428ddb729d12563b827510e04663de9cb4056f3Lennart Poettering if (c->capability_bounding_set_drop & (1 << i)) {
0428ddb729d12563b827510e04663de9cb4056f3Lennart Poettering fprintf(f, "%sUser: %s\n", prefix, c->user);
0428ddb729d12563b827510e04663de9cb4056f3Lennart Poettering fprintf(f, "%sGroup: %s\n", prefix, c->group);
0428ddb729d12563b827510e04663de9cb4056f3Lennart Poettering if (strv_length(c->supplementary_groups) > 0) {
0428ddb729d12563b827510e04663de9cb4056f3Lennart Poettering fprintf(f, "%sSupplementaryGroups:", prefix);
0428ddb729d12563b827510e04663de9cb4056f3Lennart Poettering strv_fprintf(f, c->supplementary_groups);
0428ddb729d12563b827510e04663de9cb4056f3Lennart Poettering fprintf(f, "%sPAMName: %s\n", prefix, c->pam_name);
0428ddb729d12563b827510e04663de9cb4056f3Lennart Poettering if (strv_length(c->read_write_dirs) > 0) {
0428ddb729d12563b827510e04663de9cb4056f3Lennart Poettering if (strv_length(c->read_only_dirs) > 0) {
0428ddb729d12563b827510e04663de9cb4056f3Lennart Poettering if (strv_length(c->inaccessible_dirs) > 0) {
0428ddb729d12563b827510e04663de9cb4056f3Lennart Poettering fprintf(f, "%sInaccessibleDirs:", prefix);
0428ddb729d12563b827510e04663de9cb4056f3Lennart Poettering "%sKillMode: %s\n"
0428ddb729d12563b827510e04663de9cb4056f3Lennart Poettering "%sKillSignal: SIG%s\n"
0428ddb729d12563b827510e04663de9cb4056f3Lennart Poettering "%sSendSIGKILL: %s\n",
0428ddb729d12563b827510e04663de9cb4056f3Lennart Poettering prefix, kill_mode_to_string(c->kill_mode),
0428ddb729d12563b827510e04663de9cb4056f3Lennart Poettering prefix, signal_to_string(c->kill_signal),
0428ddb729d12563b827510e04663de9cb4056f3Lennart Poettering "%sUtmpIdentifier: %s\n",
0428ddb729d12563b827510e04663de9cb4056f3Lennart Poetteringvoid exec_status_start(ExecStatus *s, pid_t pid) {
0428ddb729d12563b827510e04663de9cb4056f3Lennart Poetteringvoid exec_status_exit(ExecStatus *s, pid_t pid, int code, int status, const char *utmp_id) {
0428ddb729d12563b827510e04663de9cb4056f3Lennart Poettering utmp_put_dead_process(utmp_id, pid, code, status);
0428ddb729d12563b827510e04663de9cb4056f3Lennart Poetteringvoid exec_status_dump(ExecStatus *s, FILE *f, const char *prefix) {
0428ddb729d12563b827510e04663de9cb4056f3Lennart Poettering "%sPID: %lu\n",
0428ddb729d12563b827510e04663de9cb4056f3Lennart Poettering "%sStart Timestamp: %s\n",
0428ddb729d12563b827510e04663de9cb4056f3Lennart Poettering prefix, format_timestamp(buf, sizeof(buf), s->start_timestamp.realtime));
6827101ab4df4730a22062f4b3a8f8c2bae5be28Zbigniew Jędrzejewski-Szmek "%sExit Timestamp: %s\n"
139ee8cc316a861bcc8a8ebdf4a8449dffe16f79Lennart Poettering "%sExit Code: %s\n"
139ee8cc316a861bcc8a8ebdf4a8449dffe16f79Lennart Poettering "%sExit Status: %i\n",
139ee8cc316a861bcc8a8ebdf4a8449dffe16f79Lennart Poettering prefix, format_timestamp(buf, sizeof(buf), s->exit_timestamp.realtime),
6827101ab4df4730a22062f4b3a8f8c2bae5be28Zbigniew Jędrzejewski-Szmek prefix, sigchld_code_to_string(s->code),
139ee8cc316a861bcc8a8ebdf4a8449dffe16f79Lennart Poettering char *n, *p, **a;
139ee8cc316a861bcc8a8ebdf4a8449dffe16f79Lennart Poettering if (!(n = new(char, k)))
139ee8cc316a861bcc8a8ebdf4a8449dffe16f79Lennart Poettering *(p++) = '\'';
139ee8cc316a861bcc8a8ebdf4a8449dffe16f79Lennart Poettering *(p++) = '\'';
139ee8cc316a861bcc8a8ebdf4a8449dffe16f79Lennart Poettering /* FIXME: this doesn't really handle arguments that have
139ee8cc316a861bcc8a8ebdf4a8449dffe16f79Lennart Poettering * spaces and ticks in them */
139ee8cc316a861bcc8a8ebdf4a8449dffe16f79Lennart Poetteringvoid exec_command_dump(ExecCommand *c, FILE *f, const char *prefix) {
139ee8cc316a861bcc8a8ebdf4a8449dffe16f79Lennart Poettering "%sCommand Line: %s\n",
139ee8cc316a861bcc8a8ebdf4a8449dffe16f79Lennart Poettering exec_status_dump(&c->exec_status, f, prefix2);
4d92e078e9d7e9a9d346065ea5e4afbafbdadb48Lennart Poetteringvoid exec_command_dump_list(ExecCommand *c, FILE *f, const char *prefix) {
f9b557200b6d59a3dce1623d0873a259ee2fe421Lennart Poetteringvoid exec_command_append_list(ExecCommand **l, ExecCommand *e) {
f9b557200b6d59a3dce1623d0873a259ee2fe421Lennart Poettering /* It's kind of important, that we keep the order here */
f9b557200b6d59a3dce1623d0873a259ee2fe421Lennart Poettering LIST_FIND_TAIL(ExecCommand, command, *l, end);
f9b557200b6d59a3dce1623d0873a259ee2fe421Lennart Poettering LIST_INSERT_AFTER(ExecCommand, command, *l, end, e);
597c52cfedb5edd13ee1635fa6be72fc80e587c3Lennart Poetteringint exec_command_set(ExecCommand *c, const char *path, ...) {
597c52cfedb5edd13ee1635fa6be72fc80e587c3Lennart Poetteringstatic const char* const exec_input_table[_EXEC_INPUT_MAX] = {
075d4ecb4026c5bc55e73bd2d44e3fc4d679adc7Lennart PoetteringDEFINE_STRING_TABLE_LOOKUP(exec_input, ExecInput);
075d4ecb4026c5bc55e73bd2d44e3fc4d679adc7Lennart Poetteringstatic const char* const exec_output_table[_EXEC_OUTPUT_MAX] = {
075d4ecb4026c5bc55e73bd2d44e3fc4d679adc7Lennart Poettering [EXEC_OUTPUT_SYSLOG_AND_CONSOLE] = "syslog+console",
075d4ecb4026c5bc55e73bd2d44e3fc4d679adc7Lennart Poettering [EXEC_OUTPUT_KMSG_AND_CONSOLE] = "kmsg+console",
597c52cfedb5edd13ee1635fa6be72fc80e587c3Lennart PoetteringDEFINE_STRING_TABLE_LOOKUP(exec_output, ExecOutput);
075d4ecb4026c5bc55e73bd2d44e3fc4d679adc7Lennart Poetteringstatic const char* const kill_mode_table[_KILL_MODE_MAX] = {
b6a867398de9f75fb623a84db7c6181d26b0a8d5Lennart PoetteringDEFINE_STRING_TABLE_LOOKUP(kill_mode, KillMode);
b6a867398de9f75fb623a84db7c6181d26b0a8d5Lennart Poetteringstatic const char* const kill_who_table[_KILL_WHO_MAX] = {