#include "tcpwrap.h"
#include "exit-status.h"
#include "missing.h"
+#include "utmp-wtmp.h"
/* This assumes there is a 'tty' group */
#define TTY_MODE 0620
"%i\n"
"%s\n"
"%i\n",
- output == EXEC_OUTPUT_KMSG ? "kmsg" : "syslog",
+ output == EXEC_OUTPUT_KMSG ? "kmsg" :
+ output == EXEC_OUTPUT_KMSG_AND_CONSOLE ? "kmsg+console" :
+ output == EXEC_OUTPUT_SYSLOG ? "syslog" :
+ "syslog+console",
context->syslog_priority,
context->syslog_identifier ? context->syslog_identifier : ident,
context->syslog_level_prefix);
return open_terminal_as(tty_path(context), O_WRONLY, STDOUT_FILENO);
case EXEC_OUTPUT_SYSLOG:
+ case EXEC_OUTPUT_SYSLOG_AND_CONSOLE:
case EXEC_OUTPUT_KMSG:
+ case EXEC_OUTPUT_KMSG_AND_CONSOLE:
return connect_logger_as(context, o, ident, STDOUT_FILENO);
case EXEC_OUTPUT_SOCKET:
return open_terminal_as(tty_path(context), O_WRONLY, STDERR_FILENO);
case EXEC_OUTPUT_SYSLOG:
+ case EXEC_OUTPUT_SYSLOG_AND_CONSOLE:
case EXEC_OUTPUT_KMSG:
+ case EXEC_OUTPUT_KMSG_AND_CONSOLE:
return connect_logger_as(context, e, ident, STDERR_FILENO);
case EXEC_OUTPUT_SOCKET:
/* If there are multiple users with the same id, make
* sure to leave $USER to the configured value instead
- * of the first occurence in the database. However if
+ * of the first occurrence in the database. However if
* the uid was configured by a numeric uid, then let's
* pick the real username from /etc/passwd. */
if (*username && p)
assert(context);
- /* Lookup and ser GID and supplementary group list. Here too
+ /* Lookup and set GID and supplementary group list. Here too
* we avoid NSS lookups for gid=0. */
if (context->group || username) {
/* First step: If we need to keep capabilities but
* drop privileges we need to make sure we keep our
- * caps, whiel we drop priviliges. */
+ * caps, whiel we drop privileges. */
if (uid != 0) {
int sb = context->secure_bits|SECURE_KEEP_CAPS;
return -errno;
}
- /* Second step: set the capabilites. This will reduce
+ /* Second step: set the capabilities. This will reduce
* the capabilities to the minimum we need. */
if (!(d = cap_dup(context->capabilities)))
assert(pam_env);
/* We set up PAM in the parent process, then fork. The child
- * will then stay around untill killed via PR_GET_PDEATHSIG or
+ * will then stay around until killed via PR_GET_PDEATHSIG or
* systemd via the cgroup logic. It will then remove the PAM
* session again. The parent process will exec() the actual
* daemon. We do things this way to ensure that the main PID
/* Wait until our parent died. This will most likely
* not work since the kernel does not allow
- * unpriviliged paretns kill their priviliged children
+ * unprivileged parents kill their privileged children
* this way. We rely on the control groups kill logic
* to do the rest for us. */
if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
goto fail;
}
+ if (context->utmp_id)
+ utmp_put_init_process(0, context->utmp_id, getpid(), getsid(0), context->tty_path);
+
if (context->user) {
username = context->user;
if (get_user_creds(&username, &uid, &gid, &home) < 0) {
goto fail;
}
- /* PR_GET_SECUREBITS is not priviliged, while
+ /* PR_GET_SECUREBITS is not privileged, while
* PR_SET_SECUREBITS is. So to suppress
* potential EPERMs we'll try not to call
* PR_SET_SECUREBITS unless necessary. */
}
}
- if (!(our_env = new0(char*, 6))) {
+ if (!(our_env = new0(char*, 7))) {
r = EXIT_MEMORY;
goto fail;
}
goto fail;
}
- assert(n_env <= 6);
+ if (is_terminal_input(context->std_input) ||
+ context->std_output == EXEC_OUTPUT_TTY ||
+ context->std_error == EXEC_OUTPUT_TTY)
+ if (!(our_env[n_env++] = strdup(default_term_for_tty(tty_path(context))))) {
+ r = EXIT_MEMORY;
+ goto fail;
+ }
+
+ assert(n_env <= 7);
if (!(final_env = strv_env_merge(
4,
goto fail;
}
+ final_env = strv_env_clean(final_env);
+
execve(command->path, final_argv, final_env);
r = EXIT_EXEC;
c->syslog_level_prefix = true;
c->mount_flags = MS_SHARED;
c->kill_signal = SIGTERM;
+ c->send_sigkill = true;
}
void exec_context_done(ExecContext *c) {
if (c->cpuset)
CPU_FREE(c->cpuset);
+
+ free(c->utmp_id);
+ c->utmp_id = NULL;
}
void exec_command_done(ExecCommand *c) {
prefix, c->tty_path);
if (c->std_output == EXEC_OUTPUT_SYSLOG || c->std_output == EXEC_OUTPUT_KMSG ||
- c->std_error == EXEC_OUTPUT_SYSLOG || c->std_error == EXEC_OUTPUT_KMSG)
+ c->std_output == EXEC_OUTPUT_SYSLOG_AND_CONSOLE || c->std_output == EXEC_OUTPUT_KMSG_AND_CONSOLE ||
+ c->std_error == EXEC_OUTPUT_SYSLOG || c->std_error == EXEC_OUTPUT_KMSG ||
+ c->std_error == EXEC_OUTPUT_SYSLOG_AND_CONSOLE || c->std_error == EXEC_OUTPUT_KMSG_AND_CONSOLE)
fprintf(f,
"%sSyslogFacility: %s\n"
"%sSyslogLevel: %s\n",
fprintf(f,
"%sKillMode: %s\n"
- "%sKillSignal: SIG%s\n",
+ "%sKillSignal: SIG%s\n"
+ "%sSendSIGKILL: %s\n",
prefix, kill_mode_to_string(c->kill_mode),
- prefix, signal_to_string(c->kill_signal));
+ prefix, signal_to_string(c->kill_signal),
+ prefix, yes_no(c->send_sigkill));
+
+ if (c->utmp_id)
+ fprintf(f,
+ "%sUtmpIdentifier: %s\n",
+ prefix, c->utmp_id);
}
void exec_status_start(ExecStatus *s, pid_t pid) {
dual_timestamp_get(&s->start_timestamp);
}
-void exec_status_exit(ExecStatus *s, pid_t pid, int code, int status) {
+void exec_status_exit(ExecStatus *s, pid_t pid, int code, int status, const char *utmp_id) {
assert(s);
if ((s->pid && s->pid != pid) ||
s->code = code;
s->status = status;
+
+ if (utmp_id)
+ utmp_put_dead_process(utmp_id, pid, code, status);
}
void exec_status_dump(ExecStatus *s, FILE *f, const char *prefix) {
assert(e);
if (*l) {
- /* It's kinda important that we keep the order here */
+ /* It's kind of important, that we keep the order here */
LIST_FIND_TAIL(ExecCommand, command, *l, end);
LIST_INSERT_AFTER(ExecCommand, command, *l, end, e);
} else
[EXEC_INPUT_SOCKET] = "socket"
};
+DEFINE_STRING_TABLE_LOOKUP(exec_input, ExecInput);
+
static const char* const exec_output_table[_EXEC_OUTPUT_MAX] = {
[EXEC_OUTPUT_INHERIT] = "inherit",
[EXEC_OUTPUT_NULL] = "null",
[EXEC_OUTPUT_TTY] = "tty",
[EXEC_OUTPUT_SYSLOG] = "syslog",
+ [EXEC_OUTPUT_SYSLOG_AND_CONSOLE] = "syslog+console",
[EXEC_OUTPUT_KMSG] = "kmsg",
+ [EXEC_OUTPUT_KMSG_AND_CONSOLE] = "kmsg+console",
[EXEC_OUTPUT_SOCKET] = "socket"
};
DEFINE_STRING_TABLE_LOOKUP(exec_output, ExecOutput);
-DEFINE_STRING_TABLE_LOOKUP(exec_input, ExecInput);
+static const char* const kill_mode_table[_KILL_MODE_MAX] = {
+ [KILL_CONTROL_GROUP] = "control-group",
+ [KILL_PROCESS_GROUP] = "process-group",
+ [KILL_PROCESS] = "process",
+ [KILL_NONE] = "none"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(kill_mode, KillMode);
+
+static const char* const kill_who_table[_KILL_WHO_MAX] = {
+ [KILL_MAIN] = "main",
+ [KILL_CONTROL] = "control",
+ [KILL_ALL] = "all"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);