mirror of
https://github.com/systemd/systemd-stable.git
synced 2024-10-28 03:25:27 +03:00
Merge pull request #3818 from poettering/exit-status-env
beef up /var/tmp and /tmp handling; set $SERVICE_RESULT/$EXIT_CODE/$EXIT_STATUS on ExecStop= and make sure root/nobody are always resolvable
This commit is contained in:
commit
3bb81a80bd
10
TODO
10
TODO
@ -35,27 +35,17 @@ Features:
|
|||||||
|
|
||||||
* RemoveIPC= in unit files for removing POSIX/SysV IPC objects
|
* RemoveIPC= in unit files for removing POSIX/SysV IPC objects
|
||||||
|
|
||||||
* Set SERVICE_RESULT= as env var while running ExecStop=
|
|
||||||
|
|
||||||
* Introduce ProtectSystem=strict for making the entire OS hierarchy read-only
|
* Introduce ProtectSystem=strict for making the entire OS hierarchy read-only
|
||||||
except for a select few
|
except for a select few
|
||||||
|
|
||||||
* nspawn: start UID allocation loop from hash of container name
|
* nspawn: start UID allocation loop from hash of container name
|
||||||
|
|
||||||
* in the DynamicUser=1 nss module, also map "nobody" and "root" statically
|
|
||||||
|
|
||||||
* pid1: log about all processes we kill with with SIGKILL or in abandoned scopes, as this should normally not happen
|
|
||||||
|
|
||||||
* nspawn: support that /proc, /sys/, /dev are pre-mounted
|
* nspawn: support that /proc, /sys/, /dev are pre-mounted
|
||||||
|
|
||||||
* nspawn: mount esp, so that bootctl can work
|
|
||||||
|
|
||||||
* define gpt header bits to select volatility mode
|
* define gpt header bits to select volatility mode
|
||||||
|
|
||||||
* nspawn: mount loopback filesystems with "discard"
|
* nspawn: mount loopback filesystems with "discard"
|
||||||
|
|
||||||
* Make TasksMax= take percentages, taken relative to the pids_max sysctl and pids.max cgroup limit
|
|
||||||
|
|
||||||
* ProtectKernelLogs= (drops CAP_SYSLOG, add seccomp for syslog() syscall, and DeviceAllow to /dev/kmsg) in service files
|
* ProtectKernelLogs= (drops CAP_SYSLOG, add seccomp for syslog() syscall, and DeviceAllow to /dev/kmsg) in service files
|
||||||
|
|
||||||
* ProtectClock= (drops CAP_SYS_TIMES, adds seecomp filters for settimeofday, adjtimex), sets DeviceAllow o /dev/rtc
|
* ProtectClock= (drops CAP_SYS_TIMES, adds seecomp filters for settimeofday, adjtimex), sets DeviceAllow o /dev/rtc
|
||||||
|
22
configure.ac
22
configure.ac
@ -556,12 +556,30 @@ AC_SUBST(CERTIFICATEROOT)
|
|||||||
|
|
||||||
AC_ARG_WITH([support-url],
|
AC_ARG_WITH([support-url],
|
||||||
AS_HELP_STRING([--with-support-url=URL],
|
AS_HELP_STRING([--with-support-url=URL],
|
||||||
[Specify the supoport URL to show in catalog entries included in systemd]),
|
[Specify the support URL to show in catalog entries included in systemd]),
|
||||||
[SUPPORT_URL="$withval"],
|
[SUPPORT_URL="$withval"],
|
||||||
[SUPPORT_URL=http://lists.freedesktop.org/mailman/listinfo/systemd-devel])
|
[SUPPORT_URL=http://lists.freedesktop.org/mailman/listinfo/systemd-devel])
|
||||||
|
|
||||||
AC_SUBST(SUPPORT_URL)
|
AC_SUBST(SUPPORT_URL)
|
||||||
|
|
||||||
|
AC_ARG_WITH([nobody-user],
|
||||||
|
AS_HELP_STRING([--with-nobody-user=NAME],
|
||||||
|
[Specify the name of the nobody user (the one with UID 65534)]),
|
||||||
|
[NOBODY_USER_NAME="$withval"],
|
||||||
|
[NOBODY_USER_NAME=nobody])
|
||||||
|
|
||||||
|
AC_SUBST(NOBODY_USER_NAME)
|
||||||
|
AC_DEFINE_UNQUOTED(NOBODY_USER_NAME, ["$NOBODY_USER_NAME"], [The name of the nobody user (the one with UID 65534)])
|
||||||
|
|
||||||
|
AC_ARG_WITH([nobody-group],
|
||||||
|
AS_HELP_STRING([--with-nobody-group=NAME],
|
||||||
|
[Specify the name of the nobody group (the one with GID 65534)]),
|
||||||
|
[NOBODY_GROUP_NAME="$withval"],
|
||||||
|
[NOBODY_GROUP_NAME=nobody])
|
||||||
|
|
||||||
|
AC_SUBST(NOBODY_GROUP_NAME)
|
||||||
|
AC_DEFINE_UNQUOTED(NOBODY_GROUP_NAME, ["$NOBODY_GROUP_NAME"], [The name of the nobody group (the one with GID 65534)])
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
have_xz=no
|
have_xz=no
|
||||||
AC_ARG_ENABLE(xz, AS_HELP_STRING([--disable-xz], [Disable optional XZ support]))
|
AC_ARG_ENABLE(xz, AS_HELP_STRING([--disable-xz], [Disable optional XZ support]))
|
||||||
@ -1677,6 +1695,8 @@ AC_MSG_RESULT([
|
|||||||
Maximum System GID: ${SYSTEM_GID_MAX}
|
Maximum System GID: ${SYSTEM_GID_MAX}
|
||||||
Certificate root: ${CERTIFICATEROOT}
|
Certificate root: ${CERTIFICATEROOT}
|
||||||
Support URL: ${SUPPORT_URL}
|
Support URL: ${SUPPORT_URL}
|
||||||
|
Nobody User Name: ${NOBODY_USER_NAME}
|
||||||
|
Nobody Group Name: ${NOBODY_GROUP_NAME}
|
||||||
|
|
||||||
CFLAGS: ${OUR_CFLAGS} ${CFLAGS}
|
CFLAGS: ${OUR_CFLAGS} ${CFLAGS}
|
||||||
CPPFLAGS: ${OUR_CPPFLAGS} ${CPPFLAGS}
|
CPPFLAGS: ${OUR_CPPFLAGS} ${CPPFLAGS}
|
||||||
|
@ -61,6 +61,10 @@
|
|||||||
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for details on
|
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for details on
|
||||||
this option.</para>
|
this option.</para>
|
||||||
|
|
||||||
|
<para>This module also ensures that the root and nobody users and groups (i.e. the users/groups with the UIDs/GIDs
|
||||||
|
0 and 65534) remain resolvable at all times, even if they aren't listed in <filename>/etc/passwd</filename> or
|
||||||
|
<filename>/etc/group</filename>, or if these files are missing.</para>
|
||||||
|
|
||||||
<para>To activate the NSS module, add <literal>systemd</literal> to the lines starting with
|
<para>To activate the NSS module, add <literal>systemd</literal> to the lines starting with
|
||||||
<literal>passwd:</literal> and <literal>group:</literal> in <filename>/etc/nsswitch.conf</filename>.</para>
|
<literal>passwd:</literal> and <literal>group:</literal> in <filename>/etc/nsswitch.conf</filename>.</para>
|
||||||
|
|
||||||
|
@ -1602,6 +1602,43 @@
|
|||||||
functions) if their standard output or standard error output is connected to the journal anyway, thus enabling
|
functions) if their standard output or standard error output is connected to the journal anyway, thus enabling
|
||||||
delivery of structured metadata along with logged messages.</para></listitem>
|
delivery of structured metadata along with logged messages.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><varname>$SERVICE_RESULT</varname></term>
|
||||||
|
|
||||||
|
<listitem><para>Only defined for the service unit type, this environment variable is passed to all
|
||||||
|
<varname>ExecStop=</varname> and <varname>ExecStopPost=</varname> processes, and encodes the service
|
||||||
|
"result". Currently, the following values are defined: <literal>timeout</literal> (in case of an operation
|
||||||
|
timeout), <literal>exit-code</literal> (if a service process exited with a non-zero exit code; see
|
||||||
|
<varname>$EXIT_STATUS</varname> below for the actual exit status returned), <literal>signal</literal> (if a
|
||||||
|
service process was terminated abnormally by a signal; see <varname>$EXIT_STATUS</varname> below for the actual
|
||||||
|
signal used for the termination), <literal>core-dump</literal> (if a service process terminated abnormally and
|
||||||
|
dumped core), <literal>watchdog</literal> (if the watchdog keep-alive ping was enabled for the service but it
|
||||||
|
missed the deadline), or <literal>resources</literal> (a catch-all condition in case a system operation
|
||||||
|
failed).</para>
|
||||||
|
|
||||||
|
<para>This environment variable is useful to monitor failure or successful termination of a service. Even
|
||||||
|
though this variable is available in both <varname>ExecStop=</varname> and <varname>ExecStopPost=</varname>, it
|
||||||
|
is usually a better choice to place monitoring tools in the latter, as the former is only invoked for services
|
||||||
|
that managed to start up correctly, and the latter covers both services that failed during their start-up and
|
||||||
|
those which failed during their runtime.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><varname>$EXIT_CODE</varname></term>
|
||||||
|
<term><varname>$EXIT_STATUS</varname></term>
|
||||||
|
|
||||||
|
<listitem><para>Only defined for the service unit type, these environment variables are passed to all
|
||||||
|
<varname>ExecStop=</varname>, <varname>ExecStopPost=</varname> processes and contain exit status/code
|
||||||
|
information of the main process of the service. For the precise definition of the exit code and status, see
|
||||||
|
<citerefentry><refentrytitle>wait</refentrytitle><manvolnum>2</manvolnum></citerefentry>. <varname>$EXIT_CODE</varname>
|
||||||
|
is one of <literal>exited</literal>, <literal>killed</literal>,
|
||||||
|
<literal>dumped</literal>. <varname>$EXIT_STATUS</varname> contains the numeric exit code formatted as string
|
||||||
|
if <varname>$EXIT_CODE</varname> is <literal>exited</literal>, and the signal name in all other cases. Note
|
||||||
|
that these environment variables are only set if the service manager succeeded to start and identify the main
|
||||||
|
process of the service.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
|
||||||
<para>Additional variables may be configured by the following
|
<para>Additional variables may be configured by the following
|
||||||
|
@ -429,7 +429,13 @@
|
|||||||
service failed to start up correctly. Commands configured with this setting need to be able to operate even if
|
service failed to start up correctly. Commands configured with this setting need to be able to operate even if
|
||||||
the service failed starting up half-way and left incompletely initialized data around. As the service's
|
the service failed starting up half-way and left incompletely initialized data around. As the service's
|
||||||
processes have been terminated already when the commands specified with this setting are executed they should
|
processes have been terminated already when the commands specified with this setting are executed they should
|
||||||
not attempt to communicate with them.</para></listitem>
|
not attempt to communicate with them.</para>
|
||||||
|
|
||||||
|
<para>Note that all commands that are configured with this setting are invoked with the result code of the
|
||||||
|
service, as well as the main process' exit code and status, set in the <varname>$SERVICE_RESULT</varname>,
|
||||||
|
<varname>$EXIT_CODE</varname> and <varname>$EXIT_STATUS</varname> environment variables, see
|
||||||
|
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
|
||||||
|
details.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
|
@ -1168,8 +1168,8 @@ int tempfn_random_child(const char *p, const char *extra, char **ret) {
|
|||||||
char *t, *x;
|
char *t, *x;
|
||||||
uint64_t u;
|
uint64_t u;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
int r;
|
||||||
|
|
||||||
assert(p);
|
|
||||||
assert(ret);
|
assert(ret);
|
||||||
|
|
||||||
/* Turns this:
|
/* Turns this:
|
||||||
@ -1178,6 +1178,12 @@ int tempfn_random_child(const char *p, const char *extra, char **ret) {
|
|||||||
* /foo/bar/waldo/.#<extra>3c2b6219aa75d7d0
|
* /foo/bar/waldo/.#<extra>3c2b6219aa75d7d0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
if (!p) {
|
||||||
|
r = tmp_dir(&p);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
if (!extra)
|
if (!extra)
|
||||||
extra = "";
|
extra = "";
|
||||||
|
|
||||||
@ -1264,10 +1270,13 @@ int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space)
|
|||||||
|
|
||||||
int open_tmpfile_unlinkable(const char *directory, int flags) {
|
int open_tmpfile_unlinkable(const char *directory, int flags) {
|
||||||
char *p;
|
char *p;
|
||||||
int fd;
|
int fd, r;
|
||||||
|
|
||||||
if (!directory)
|
if (!directory) {
|
||||||
directory = "/tmp";
|
r = tmp_dir(&directory);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
/* Returns an unlinked temporary file that cannot be linked into the file system anymore */
|
/* Returns an unlinked temporary file that cannot be linked into the file system anymore */
|
||||||
|
|
||||||
|
@ -496,34 +496,94 @@ int get_files_in_directory(const char *path, char ***list) {
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
int var_tmp(char **ret) {
|
static int getenv_tmp_dir(const char **ret_path) {
|
||||||
const char *tmp_dir = NULL;
|
const char *n;
|
||||||
const char *env_tmp_dir = NULL;
|
int r, ret = 0;
|
||||||
char *c = NULL;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(ret);
|
assert(ret_path);
|
||||||
|
|
||||||
env_tmp_dir = getenv("TMPDIR");
|
/* We use the same order of environment variables python uses in tempfile.gettempdir():
|
||||||
if (env_tmp_dir != NULL) {
|
* https://docs.python.org/3/library/tempfile.html#tempfile.gettempdir */
|
||||||
r = is_dir(env_tmp_dir, true);
|
FOREACH_STRING(n, "TMPDIR", "TEMP", "TMP") {
|
||||||
if (r < 0 && r != -ENOENT)
|
const char *e;
|
||||||
return r;
|
|
||||||
if (r > 0)
|
e = secure_getenv(n);
|
||||||
tmp_dir = env_tmp_dir;
|
if (!e)
|
||||||
|
continue;
|
||||||
|
if (!path_is_absolute(e)) {
|
||||||
|
r = -ENOTDIR;
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
if (!path_is_safe(e)) {
|
||||||
|
r = -EPERM;
|
||||||
|
goto next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tmp_dir)
|
r = is_dir(e, true);
|
||||||
tmp_dir = "/var/tmp";
|
if (r < 0)
|
||||||
|
goto next;
|
||||||
|
if (r == 0) {
|
||||||
|
r = -ENOTDIR;
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
|
||||||
c = strdup(tmp_dir);
|
*ret_path = e;
|
||||||
if (!c)
|
return 1;
|
||||||
return -ENOMEM;
|
|
||||||
*ret = c;
|
|
||||||
|
|
||||||
|
next:
|
||||||
|
/* Remember first error, to make this more debuggable */
|
||||||
|
if (ret >= 0)
|
||||||
|
ret = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
*ret_path = NULL;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tmp_dir_internal(const char *def, const char **ret) {
|
||||||
|
const char *e;
|
||||||
|
int r, k;
|
||||||
|
|
||||||
|
assert(def);
|
||||||
|
assert(ret);
|
||||||
|
|
||||||
|
r = getenv_tmp_dir(&e);
|
||||||
|
if (r > 0) {
|
||||||
|
*ret = e;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
k = is_dir(def, true);
|
||||||
|
if (k == 0)
|
||||||
|
k = -ENOTDIR;
|
||||||
|
if (k < 0)
|
||||||
|
return r < 0 ? r : k;
|
||||||
|
|
||||||
|
*ret = def;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int var_tmp_dir(const char **ret) {
|
||||||
|
|
||||||
|
/* Returns the location for "larger" temporary files, that is backed by physical storage if available, and thus
|
||||||
|
* even might survive a boot: /var/tmp. If $TMPDIR (or related environment variables) are set, its value is
|
||||||
|
* returned preferably however. Note that both this function and tmp_dir() below are affected by $TMPDIR,
|
||||||
|
* making it a variable that overrides all temporary file storage locations. */
|
||||||
|
|
||||||
|
return tmp_dir_internal("/var/tmp", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
int tmp_dir(const char **ret) {
|
||||||
|
|
||||||
|
/* Similar to var_tmp_dir() above, but returns the location for "smaller" temporary files, which is usually
|
||||||
|
* backed by an in-memory file system: /tmp. */
|
||||||
|
|
||||||
|
return tmp_dir_internal("/tmp", ret);
|
||||||
|
}
|
||||||
|
|
||||||
int inotify_add_watch_fd(int fd, int what, uint32_t mask) {
|
int inotify_add_watch_fd(int fd, int what, uint32_t mask) {
|
||||||
char path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
|
char path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
|
||||||
int r;
|
int r;
|
||||||
|
@ -61,7 +61,8 @@ int mkfifo_atomic(const char *path, mode_t mode);
|
|||||||
|
|
||||||
int get_files_in_directory(const char *path, char ***list);
|
int get_files_in_directory(const char *path, char ***list);
|
||||||
|
|
||||||
int var_tmp(char **ret);
|
int tmp_dir(const char **ret);
|
||||||
|
int var_tmp_dir(const char **ret);
|
||||||
|
|
||||||
#define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX + 1)
|
#define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX + 1)
|
||||||
|
|
||||||
|
@ -301,7 +301,7 @@ static void automount_dump(Unit *u, FILE *f, const char *prefix) {
|
|||||||
static void automount_enter_dead(Automount *a, AutomountResult f) {
|
static void automount_enter_dead(Automount *a, AutomountResult f) {
|
||||||
assert(a);
|
assert(a);
|
||||||
|
|
||||||
if (f != AUTOMOUNT_SUCCESS)
|
if (a->result == AUTOMOUNT_SUCCESS)
|
||||||
a->result = f;
|
a->result = f;
|
||||||
|
|
||||||
automount_set_state(a, a->result != AUTOMOUNT_SUCCESS ? AUTOMOUNT_FAILED : AUTOMOUNT_DEAD);
|
automount_set_state(a, a->result != AUTOMOUNT_SUCCESS ? AUTOMOUNT_FAILED : AUTOMOUNT_DEAD);
|
||||||
|
@ -442,7 +442,7 @@ fail:
|
|||||||
static void busname_enter_dead(BusName *n, BusNameResult f) {
|
static void busname_enter_dead(BusName *n, BusNameResult f) {
|
||||||
assert(n);
|
assert(n);
|
||||||
|
|
||||||
if (f != BUSNAME_SUCCESS)
|
if (n->result == BUSNAME_SUCCESS)
|
||||||
n->result = f;
|
n->result = f;
|
||||||
|
|
||||||
busname_set_state(n, n->result != BUSNAME_SUCCESS ? BUSNAME_FAILED : BUSNAME_DEAD);
|
busname_set_state(n, n->result != BUSNAME_SUCCESS ? BUSNAME_FAILED : BUSNAME_DEAD);
|
||||||
@ -454,7 +454,7 @@ static void busname_enter_signal(BusName *n, BusNameState state, BusNameResult f
|
|||||||
|
|
||||||
assert(n);
|
assert(n);
|
||||||
|
|
||||||
if (f != BUSNAME_SUCCESS)
|
if (n->result == BUSNAME_SUCCESS)
|
||||||
n->result = f;
|
n->result = f;
|
||||||
|
|
||||||
kill_context_init(&kill_context);
|
kill_context_init(&kill_context);
|
||||||
@ -882,7 +882,7 @@ static void busname_sigchld_event(Unit *u, pid_t pid, int code, int status) {
|
|||||||
log_unit_full(u, f == BUSNAME_SUCCESS ? LOG_DEBUG : LOG_NOTICE, 0,
|
log_unit_full(u, f == BUSNAME_SUCCESS ? LOG_DEBUG : LOG_NOTICE, 0,
|
||||||
"Control process exited, code=%s status=%i", sigchld_code_to_string(code), status);
|
"Control process exited, code=%s status=%i", sigchld_code_to_string(code), status);
|
||||||
|
|
||||||
if (f != BUSNAME_SUCCESS)
|
if (n->result == BUSNAME_SUCCESS)
|
||||||
n->result = f;
|
n->result = f;
|
||||||
|
|
||||||
switch (n->state) {
|
switch (n->state) {
|
||||||
|
@ -427,7 +427,7 @@ static int setup_input(
|
|||||||
return STDIN_FILENO;
|
return STDIN_FILENO;
|
||||||
}
|
}
|
||||||
|
|
||||||
i = fixup_input(context->std_input, socket_fd, params->apply_tty_stdin);
|
i = fixup_input(context->std_input, socket_fd, params->flags & EXEC_APPLY_TTY_STDIN);
|
||||||
|
|
||||||
switch (i) {
|
switch (i) {
|
||||||
|
|
||||||
@ -502,7 +502,7 @@ static int setup_output(
|
|||||||
return STDERR_FILENO;
|
return STDERR_FILENO;
|
||||||
}
|
}
|
||||||
|
|
||||||
i = fixup_input(context->std_input, socket_fd, params->apply_tty_stdin);
|
i = fixup_input(context->std_input, socket_fd, params->flags & EXEC_APPLY_TTY_STDIN);
|
||||||
o = fixup_output(context->std_output, socket_fd);
|
o = fixup_output(context->std_output, socket_fd);
|
||||||
|
|
||||||
if (fileno == STDERR_FILENO) {
|
if (fileno == STDERR_FILENO) {
|
||||||
@ -1425,7 +1425,7 @@ static int build_environment(
|
|||||||
our_env[n_env++] = x;
|
our_env[n_env++] = x;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p->watchdog_usec > 0) {
|
if ((p->flags & EXEC_SET_WATCHDOG) && p->watchdog_usec > 0) {
|
||||||
if (asprintf(&x, "WATCHDOG_PID="PID_FMT, getpid()) < 0)
|
if (asprintf(&x, "WATCHDOG_PID="PID_FMT, getpid()) < 0)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
our_env[n_env++] = x;
|
our_env[n_env++] = x;
|
||||||
@ -1675,7 +1675,7 @@ static int exec_child(
|
|||||||
|
|
||||||
exec_context_tty_reset(context, params);
|
exec_context_tty_reset(context, params);
|
||||||
|
|
||||||
if (params->confirm_spawn) {
|
if (params->flags & EXEC_CONFIRM_SPAWN) {
|
||||||
char response;
|
char response;
|
||||||
|
|
||||||
r = ask_for_confirmation(&response, argv);
|
r = ask_for_confirmation(&response, argv);
|
||||||
@ -1940,7 +1940,7 @@ static int exec_child(
|
|||||||
|
|
||||||
umask(context->umask);
|
umask(context->umask);
|
||||||
|
|
||||||
if (params->apply_permissions && !command->privileged) {
|
if ((params->flags & EXEC_APPLY_PERMISSIONS) && !command->privileged) {
|
||||||
r = enforce_groups(context, username, gid);
|
r = enforce_groups(context, username, gid);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
*exit_status = EXIT_GROUP;
|
*exit_status = EXIT_GROUP;
|
||||||
@ -2010,7 +2010,7 @@ static int exec_child(
|
|||||||
}
|
}
|
||||||
|
|
||||||
r = setup_namespace(
|
r = setup_namespace(
|
||||||
params->apply_chroot ? context->root_directory : NULL,
|
(params->flags & EXEC_APPLY_CHROOT) ? context->root_directory : NULL,
|
||||||
context->read_write_paths,
|
context->read_write_paths,
|
||||||
context->read_only_paths,
|
context->read_only_paths,
|
||||||
context->inaccessible_paths,
|
context->inaccessible_paths,
|
||||||
@ -2041,7 +2041,7 @@ static int exec_child(
|
|||||||
else
|
else
|
||||||
wd = "/";
|
wd = "/";
|
||||||
|
|
||||||
if (params->apply_chroot) {
|
if (params->flags & EXEC_APPLY_CHROOT) {
|
||||||
if (!needs_mount_namespace && context->root_directory)
|
if (!needs_mount_namespace && context->root_directory)
|
||||||
if (chroot(context->root_directory) < 0) {
|
if (chroot(context->root_directory) < 0) {
|
||||||
*exit_status = EXIT_CHROOT;
|
*exit_status = EXIT_CHROOT;
|
||||||
@ -2065,7 +2065,12 @@ static int exec_child(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_SELINUX
|
#ifdef HAVE_SELINUX
|
||||||
if (params->apply_permissions && mac_selinux_use() && params->selinux_context_net && socket_fd >= 0 && !command->privileged) {
|
if ((params->flags & EXEC_APPLY_PERMISSIONS) &&
|
||||||
|
mac_selinux_use() &&
|
||||||
|
params->selinux_context_net &&
|
||||||
|
socket_fd >= 0 &&
|
||||||
|
!command->privileged) {
|
||||||
|
|
||||||
r = mac_selinux_get_child_mls_label(socket_fd, command->path, context->selinux_context, &mac_selinux_context_net);
|
r = mac_selinux_get_child_mls_label(socket_fd, command->path, context->selinux_context, &mac_selinux_context_net);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
*exit_status = EXIT_SELINUX_CONTEXT;
|
*exit_status = EXIT_SELINUX_CONTEXT;
|
||||||
@ -2090,7 +2095,7 @@ static int exec_child(
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params->apply_permissions && !command->privileged) {
|
if ((params->flags & EXEC_APPLY_PERMISSIONS) && !command->privileged) {
|
||||||
|
|
||||||
bool use_address_families = context->address_families_whitelist ||
|
bool use_address_families = context->address_families_whitelist ||
|
||||||
!set_isempty(context->address_families);
|
!set_isempty(context->address_families);
|
||||||
@ -2964,12 +2969,12 @@ void exec_status_dump(ExecStatus *s, FILE *f, const char *prefix) {
|
|||||||
"%sPID: "PID_FMT"\n",
|
"%sPID: "PID_FMT"\n",
|
||||||
prefix, s->pid);
|
prefix, s->pid);
|
||||||
|
|
||||||
if (s->start_timestamp.realtime > 0)
|
if (dual_timestamp_is_set(&s->start_timestamp))
|
||||||
fprintf(f,
|
fprintf(f,
|
||||||
"%sStart Timestamp: %s\n",
|
"%sStart Timestamp: %s\n",
|
||||||
prefix, format_timestamp(buf, sizeof(buf), s->start_timestamp.realtime));
|
prefix, format_timestamp(buf, sizeof(buf), s->start_timestamp.realtime));
|
||||||
|
|
||||||
if (s->exit_timestamp.realtime > 0)
|
if (dual_timestamp_is_set(&s->exit_timestamp))
|
||||||
fprintf(f,
|
fprintf(f,
|
||||||
"%sExit Timestamp: %s\n"
|
"%sExit Timestamp: %s\n"
|
||||||
"%sExit Code: %s\n"
|
"%sExit Code: %s\n"
|
||||||
|
@ -208,6 +208,19 @@ struct ExecContext {
|
|||||||
bool no_new_privileges_set:1;
|
bool no_new_privileges_set:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef enum ExecFlags {
|
||||||
|
EXEC_CONFIRM_SPAWN = 1U << 0,
|
||||||
|
EXEC_APPLY_PERMISSIONS = 1U << 1,
|
||||||
|
EXEC_APPLY_CHROOT = 1U << 2,
|
||||||
|
EXEC_APPLY_TTY_STDIN = 1U << 3,
|
||||||
|
|
||||||
|
/* The following are not used by execute.c, but by consumers internally */
|
||||||
|
EXEC_PASS_FDS = 1U << 4,
|
||||||
|
EXEC_IS_CONTROL = 1U << 5,
|
||||||
|
EXEC_SETENV_RESULT = 1U << 6,
|
||||||
|
EXEC_SET_WATCHDOG = 1U << 7,
|
||||||
|
} ExecFlags;
|
||||||
|
|
||||||
struct ExecParameters {
|
struct ExecParameters {
|
||||||
char **argv;
|
char **argv;
|
||||||
char **environment;
|
char **environment;
|
||||||
@ -216,11 +229,7 @@ struct ExecParameters {
|
|||||||
char **fd_names;
|
char **fd_names;
|
||||||
unsigned n_fds;
|
unsigned n_fds;
|
||||||
|
|
||||||
bool apply_permissions:1;
|
ExecFlags flags;
|
||||||
bool apply_chroot:1;
|
|
||||||
bool apply_tty_stdin:1;
|
|
||||||
|
|
||||||
bool confirm_spawn:1;
|
|
||||||
bool selinux_context_net:1;
|
bool selinux_context_net:1;
|
||||||
|
|
||||||
bool cgroup_delegate:1;
|
bool cgroup_delegate:1;
|
||||||
|
@ -701,9 +701,7 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
|
|||||||
pid_t pid;
|
pid_t pid;
|
||||||
int r;
|
int r;
|
||||||
ExecParameters exec_params = {
|
ExecParameters exec_params = {
|
||||||
.apply_permissions = true,
|
.flags = EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN,
|
||||||
.apply_chroot = true,
|
|
||||||
.apply_tty_stdin = true,
|
|
||||||
.stdin_fd = -1,
|
.stdin_fd = -1,
|
||||||
.stdout_fd = -1,
|
.stdout_fd = -1,
|
||||||
.stderr_fd = -1,
|
.stderr_fd = -1,
|
||||||
@ -732,7 +730,7 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
|
|||||||
return r;
|
return r;
|
||||||
|
|
||||||
exec_params.environment = UNIT(m)->manager->environment;
|
exec_params.environment = UNIT(m)->manager->environment;
|
||||||
exec_params.confirm_spawn = UNIT(m)->manager->confirm_spawn;
|
exec_params.flags |= UNIT(m)->manager->confirm_spawn ? EXEC_CONFIRM_SPAWN : 0;
|
||||||
exec_params.cgroup_supported = UNIT(m)->manager->cgroup_supported;
|
exec_params.cgroup_supported = UNIT(m)->manager->cgroup_supported;
|
||||||
exec_params.cgroup_path = UNIT(m)->cgroup_path;
|
exec_params.cgroup_path = UNIT(m)->cgroup_path;
|
||||||
exec_params.cgroup_delegate = m->cgroup_context.delegate;
|
exec_params.cgroup_delegate = m->cgroup_context.delegate;
|
||||||
@ -761,7 +759,7 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
|
|||||||
static void mount_enter_dead(Mount *m, MountResult f) {
|
static void mount_enter_dead(Mount *m, MountResult f) {
|
||||||
assert(m);
|
assert(m);
|
||||||
|
|
||||||
if (f != MOUNT_SUCCESS)
|
if (m->result == MOUNT_SUCCESS)
|
||||||
m->result = f;
|
m->result = f;
|
||||||
|
|
||||||
mount_set_state(m, m->result != MOUNT_SUCCESS ? MOUNT_FAILED : MOUNT_DEAD);
|
mount_set_state(m, m->result != MOUNT_SUCCESS ? MOUNT_FAILED : MOUNT_DEAD);
|
||||||
@ -777,7 +775,7 @@ static void mount_enter_dead(Mount *m, MountResult f) {
|
|||||||
static void mount_enter_mounted(Mount *m, MountResult f) {
|
static void mount_enter_mounted(Mount *m, MountResult f) {
|
||||||
assert(m);
|
assert(m);
|
||||||
|
|
||||||
if (f != MOUNT_SUCCESS)
|
if (m->result == MOUNT_SUCCESS)
|
||||||
m->result = f;
|
m->result = f;
|
||||||
|
|
||||||
mount_set_state(m, MOUNT_MOUNTED);
|
mount_set_state(m, MOUNT_MOUNTED);
|
||||||
@ -788,7 +786,7 @@ static void mount_enter_signal(Mount *m, MountState state, MountResult f) {
|
|||||||
|
|
||||||
assert(m);
|
assert(m);
|
||||||
|
|
||||||
if (f != MOUNT_SUCCESS)
|
if (m->result == MOUNT_SUCCESS)
|
||||||
m->result = f;
|
m->result = f;
|
||||||
|
|
||||||
r = unit_kill_context(
|
r = unit_kill_context(
|
||||||
@ -1160,7 +1158,7 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
|
|||||||
else
|
else
|
||||||
assert_not_reached("Unknown code");
|
assert_not_reached("Unknown code");
|
||||||
|
|
||||||
if (f != MOUNT_SUCCESS)
|
if (m->result == MOUNT_SUCCESS)
|
||||||
m->result = f;
|
m->result = f;
|
||||||
|
|
||||||
if (m->control_command) {
|
if (m->control_command) {
|
||||||
|
@ -454,7 +454,7 @@ static int path_coldplug(Unit *u) {
|
|||||||
static void path_enter_dead(Path *p, PathResult f) {
|
static void path_enter_dead(Path *p, PathResult f) {
|
||||||
assert(p);
|
assert(p);
|
||||||
|
|
||||||
if (f != PATH_SUCCESS)
|
if (p->result == PATH_SUCCESS)
|
||||||
p->result = f;
|
p->result = f;
|
||||||
|
|
||||||
path_set_state(p, p->result != PATH_SUCCESS ? PATH_FAILED : PATH_DEAD);
|
path_set_state(p, p->result != PATH_SUCCESS ? PATH_FAILED : PATH_DEAD);
|
||||||
|
@ -221,7 +221,7 @@ static void scope_dump(Unit *u, FILE *f, const char *prefix) {
|
|||||||
static void scope_enter_dead(Scope *s, ScopeResult f) {
|
static void scope_enter_dead(Scope *s, ScopeResult f) {
|
||||||
assert(s);
|
assert(s);
|
||||||
|
|
||||||
if (f != SCOPE_SUCCESS)
|
if (s->result == SCOPE_SUCCESS)
|
||||||
s->result = f;
|
s->result = f;
|
||||||
|
|
||||||
scope_set_state(s, s->result != SCOPE_SUCCESS ? SCOPE_FAILED : SCOPE_DEAD);
|
scope_set_state(s, s->result != SCOPE_SUCCESS ? SCOPE_FAILED : SCOPE_DEAD);
|
||||||
@ -233,7 +233,7 @@ static void scope_enter_signal(Scope *s, ScopeState state, ScopeResult f) {
|
|||||||
|
|
||||||
assert(s);
|
assert(s);
|
||||||
|
|
||||||
if (f != SCOPE_SUCCESS)
|
if (s->result == SCOPE_SUCCESS)
|
||||||
s->result = f;
|
s->result = f;
|
||||||
|
|
||||||
unit_watch_all_pids(UNIT(s));
|
unit_watch_all_pids(UNIT(s));
|
||||||
|
@ -1171,11 +1171,7 @@ static int service_spawn(
|
|||||||
Service *s,
|
Service *s,
|
||||||
ExecCommand *c,
|
ExecCommand *c,
|
||||||
usec_t timeout,
|
usec_t timeout,
|
||||||
bool pass_fds,
|
ExecFlags flags,
|
||||||
bool apply_permissions,
|
|
||||||
bool apply_chroot,
|
|
||||||
bool apply_tty_stdin,
|
|
||||||
bool is_control,
|
|
||||||
pid_t *_pid) {
|
pid_t *_pid) {
|
||||||
|
|
||||||
_cleanup_strv_free_ char **argv = NULL, **final_env = NULL, **our_env = NULL, **fd_names = NULL;
|
_cleanup_strv_free_ char **argv = NULL, **final_env = NULL, **our_env = NULL, **fd_names = NULL;
|
||||||
@ -1185,9 +1181,7 @@ static int service_spawn(
|
|||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
ExecParameters exec_params = {
|
ExecParameters exec_params = {
|
||||||
.apply_permissions = apply_permissions,
|
.flags = flags,
|
||||||
.apply_chroot = apply_chroot,
|
|
||||||
.apply_tty_stdin = apply_tty_stdin,
|
|
||||||
.stdin_fd = -1,
|
.stdin_fd = -1,
|
||||||
.stdout_fd = -1,
|
.stdout_fd = -1,
|
||||||
.stderr_fd = -1,
|
.stderr_fd = -1,
|
||||||
@ -1199,6 +1193,14 @@ static int service_spawn(
|
|||||||
assert(c);
|
assert(c);
|
||||||
assert(_pid);
|
assert(_pid);
|
||||||
|
|
||||||
|
if (flags & EXEC_IS_CONTROL) {
|
||||||
|
/* If this is a control process, mask the permissions/chroot application if this is requested. */
|
||||||
|
if (s->permissions_start_only)
|
||||||
|
exec_params.flags &= ~EXEC_APPLY_PERMISSIONS;
|
||||||
|
if (s->root_directory_start_only)
|
||||||
|
exec_params.flags &= ~EXEC_APPLY_CHROOT;
|
||||||
|
}
|
||||||
|
|
||||||
(void) unit_realize_cgroup(UNIT(s));
|
(void) unit_realize_cgroup(UNIT(s));
|
||||||
if (s->reset_cpu_usage) {
|
if (s->reset_cpu_usage) {
|
||||||
(void) unit_reset_cpu_usage(UNIT(s));
|
(void) unit_reset_cpu_usage(UNIT(s));
|
||||||
@ -1213,7 +1215,7 @@ static int service_spawn(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (pass_fds ||
|
if ((flags & EXEC_PASS_FDS) ||
|
||||||
s->exec_context.std_input == EXEC_INPUT_SOCKET ||
|
s->exec_context.std_input == EXEC_INPUT_SOCKET ||
|
||||||
s->exec_context.std_output == EXEC_OUTPUT_SOCKET ||
|
s->exec_context.std_output == EXEC_OUTPUT_SOCKET ||
|
||||||
s->exec_context.std_error == EXEC_OUTPUT_SOCKET) {
|
s->exec_context.std_error == EXEC_OUTPUT_SOCKET) {
|
||||||
@ -1233,11 +1235,11 @@ static int service_spawn(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
our_env = new0(char*, 6);
|
our_env = new0(char*, 9);
|
||||||
if (!our_env)
|
if (!our_env)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
if (is_control ? s->notify_access == NOTIFY_ALL : s->notify_access != NOTIFY_NONE)
|
if ((flags & EXEC_IS_CONTROL) ? s->notify_access == NOTIFY_ALL : s->notify_access != NOTIFY_NONE)
|
||||||
if (asprintf(our_env + n_env++, "NOTIFY_SOCKET=%s", UNIT(s)->manager->notify_socket) < 0)
|
if (asprintf(our_env + n_env++, "NOTIFY_SOCKET=%s", UNIT(s)->manager->notify_socket) < 0)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
@ -1245,7 +1247,7 @@ static int service_spawn(
|
|||||||
if (asprintf(our_env + n_env++, "MAINPID="PID_FMT, s->main_pid) < 0)
|
if (asprintf(our_env + n_env++, "MAINPID="PID_FMT, s->main_pid) < 0)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
if (!MANAGER_IS_SYSTEM(UNIT(s)->manager))
|
if (MANAGER_IS_USER(UNIT(s)->manager))
|
||||||
if (asprintf(our_env + n_env++, "MANAGERPID="PID_FMT, getpid()) < 0)
|
if (asprintf(our_env + n_env++, "MANAGERPID="PID_FMT, getpid()) < 0)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
@ -1281,22 +1283,40 @@ static int service_spawn(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (flags & EXEC_SETENV_RESULT) {
|
||||||
|
if (asprintf(our_env + n_env++, "SERVICE_RESULT=%s", service_result_to_string(s->result)) < 0)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (s->main_exec_status.pid > 0 &&
|
||||||
|
dual_timestamp_is_set(&s->main_exec_status.exit_timestamp)) {
|
||||||
|
if (asprintf(our_env + n_env++, "EXIT_CODE=%s", sigchld_code_to_string(s->main_exec_status.code)) < 0)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (s->main_exec_status.code == CLD_EXITED)
|
||||||
|
r = asprintf(our_env + n_env++, "EXIT_STATUS=%i", s->main_exec_status.status);
|
||||||
|
else
|
||||||
|
r = asprintf(our_env + n_env++, "EXIT_STATUS=%s", signal_to_string(s->main_exec_status.status));
|
||||||
|
if (r < 0)
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final_env = strv_env_merge(2, UNIT(s)->manager->environment, our_env, NULL);
|
final_env = strv_env_merge(2, UNIT(s)->manager->environment, our_env, NULL);
|
||||||
if (!final_env)
|
if (!final_env)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
if (is_control && UNIT(s)->cgroup_path) {
|
if ((flags & EXEC_IS_CONTROL) && UNIT(s)->cgroup_path) {
|
||||||
path = strjoina(UNIT(s)->cgroup_path, "/control");
|
path = strjoina(UNIT(s)->cgroup_path, "/control");
|
||||||
(void) cg_create(SYSTEMD_CGROUP_CONTROLLER, path);
|
(void) cg_create(SYSTEMD_CGROUP_CONTROLLER, path);
|
||||||
} else
|
} else
|
||||||
path = UNIT(s)->cgroup_path;
|
path = UNIT(s)->cgroup_path;
|
||||||
|
|
||||||
exec_params.argv = argv;
|
exec_params.argv = argv;
|
||||||
|
exec_params.environment = final_env;
|
||||||
exec_params.fds = fds;
|
exec_params.fds = fds;
|
||||||
exec_params.fd_names = fd_names;
|
exec_params.fd_names = fd_names;
|
||||||
exec_params.n_fds = n_fds;
|
exec_params.n_fds = n_fds;
|
||||||
exec_params.environment = final_env;
|
exec_params.flags |= UNIT(s)->manager->confirm_spawn ? EXEC_CONFIRM_SPAWN : 0;
|
||||||
exec_params.confirm_spawn = UNIT(s)->manager->confirm_spawn;
|
|
||||||
exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported;
|
exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported;
|
||||||
exec_params.cgroup_path = path;
|
exec_params.cgroup_path = path;
|
||||||
exec_params.cgroup_delegate = s->cgroup_context.delegate;
|
exec_params.cgroup_delegate = s->cgroup_context.delegate;
|
||||||
@ -1422,7 +1442,7 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
|
|||||||
int r;
|
int r;
|
||||||
assert(s);
|
assert(s);
|
||||||
|
|
||||||
if (f != SERVICE_SUCCESS)
|
if (s->result == SERVICE_SUCCESS)
|
||||||
s->result = f;
|
s->result = f;
|
||||||
|
|
||||||
service_set_state(s, s->result != SERVICE_SUCCESS ? SERVICE_FAILED : SERVICE_DEAD);
|
service_set_state(s, s->result != SERVICE_SUCCESS ? SERVICE_FAILED : SERVICE_DEAD);
|
||||||
@ -1471,7 +1491,7 @@ static void service_enter_stop_post(Service *s, ServiceResult f) {
|
|||||||
int r;
|
int r;
|
||||||
assert(s);
|
assert(s);
|
||||||
|
|
||||||
if (f != SERVICE_SUCCESS)
|
if (s->result == SERVICE_SUCCESS)
|
||||||
s->result = f;
|
s->result = f;
|
||||||
|
|
||||||
service_unwatch_control_pid(s);
|
service_unwatch_control_pid(s);
|
||||||
@ -1484,11 +1504,7 @@ static void service_enter_stop_post(Service *s, ServiceResult f) {
|
|||||||
r = service_spawn(s,
|
r = service_spawn(s,
|
||||||
s->control_command,
|
s->control_command,
|
||||||
s->timeout_stop_usec,
|
s->timeout_stop_usec,
|
||||||
false,
|
EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN|EXEC_IS_CONTROL|EXEC_SETENV_RESULT,
|
||||||
!s->permissions_start_only,
|
|
||||||
!s->root_directory_start_only,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
&s->control_pid);
|
&s->control_pid);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -1528,7 +1544,7 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f
|
|||||||
|
|
||||||
assert(s);
|
assert(s);
|
||||||
|
|
||||||
if (f != SERVICE_SUCCESS)
|
if (s->result == SERVICE_SUCCESS)
|
||||||
s->result = f;
|
s->result = f;
|
||||||
|
|
||||||
unit_watch_all_pids(UNIT(s));
|
unit_watch_all_pids(UNIT(s));
|
||||||
@ -1586,7 +1602,7 @@ static void service_enter_stop(Service *s, ServiceResult f) {
|
|||||||
|
|
||||||
assert(s);
|
assert(s);
|
||||||
|
|
||||||
if (f != SERVICE_SUCCESS)
|
if (s->result == SERVICE_SUCCESS)
|
||||||
s->result = f;
|
s->result = f;
|
||||||
|
|
||||||
service_unwatch_control_pid(s);
|
service_unwatch_control_pid(s);
|
||||||
@ -1599,11 +1615,7 @@ static void service_enter_stop(Service *s, ServiceResult f) {
|
|||||||
r = service_spawn(s,
|
r = service_spawn(s,
|
||||||
s->control_command,
|
s->control_command,
|
||||||
s->timeout_stop_usec,
|
s->timeout_stop_usec,
|
||||||
false,
|
EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|EXEC_SETENV_RESULT,
|
||||||
!s->permissions_start_only,
|
|
||||||
!s->root_directory_start_only,
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
&s->control_pid);
|
&s->control_pid);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -1642,7 +1654,7 @@ static bool service_good(Service *s) {
|
|||||||
static void service_enter_running(Service *s, ServiceResult f) {
|
static void service_enter_running(Service *s, ServiceResult f) {
|
||||||
assert(s);
|
assert(s);
|
||||||
|
|
||||||
if (f != SERVICE_SUCCESS)
|
if (s->result == SERVICE_SUCCESS)
|
||||||
s->result = f;
|
s->result = f;
|
||||||
|
|
||||||
service_unwatch_control_pid(s);
|
service_unwatch_control_pid(s);
|
||||||
@ -1680,11 +1692,7 @@ static void service_enter_start_post(Service *s) {
|
|||||||
r = service_spawn(s,
|
r = service_spawn(s,
|
||||||
s->control_command,
|
s->control_command,
|
||||||
s->timeout_start_usec,
|
s->timeout_start_usec,
|
||||||
false,
|
EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL,
|
||||||
!s->permissions_start_only,
|
|
||||||
!s->root_directory_start_only,
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
&s->control_pid);
|
&s->control_pid);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -1754,11 +1762,7 @@ static void service_enter_start(Service *s) {
|
|||||||
r = service_spawn(s,
|
r = service_spawn(s,
|
||||||
c,
|
c,
|
||||||
timeout,
|
timeout,
|
||||||
true,
|
EXEC_PASS_FDS|EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN|EXEC_SET_WATCHDOG,
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
&pid);
|
&pid);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -1817,11 +1821,7 @@ static void service_enter_start_pre(Service *s) {
|
|||||||
r = service_spawn(s,
|
r = service_spawn(s,
|
||||||
s->control_command,
|
s->control_command,
|
||||||
s->timeout_start_usec,
|
s->timeout_start_usec,
|
||||||
false,
|
EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|EXEC_APPLY_TTY_STDIN,
|
||||||
!s->permissions_start_only,
|
|
||||||
!s->root_directory_start_only,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
&s->control_pid);
|
&s->control_pid);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -1896,11 +1896,7 @@ static void service_enter_reload(Service *s) {
|
|||||||
r = service_spawn(s,
|
r = service_spawn(s,
|
||||||
s->control_command,
|
s->control_command,
|
||||||
s->timeout_start_usec,
|
s->timeout_start_usec,
|
||||||
false,
|
EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL,
|
||||||
!s->permissions_start_only,
|
|
||||||
!s->root_directory_start_only,
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
&s->control_pid);
|
&s->control_pid);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -1938,12 +1934,9 @@ static void service_run_next_control(Service *s) {
|
|||||||
r = service_spawn(s,
|
r = service_spawn(s,
|
||||||
s->control_command,
|
s->control_command,
|
||||||
timeout,
|
timeout,
|
||||||
false,
|
EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|
|
||||||
!s->permissions_start_only,
|
(IN_SET(s->control_command_id, SERVICE_EXEC_START_PRE, SERVICE_EXEC_STOP_POST) ? EXEC_APPLY_TTY_STDIN : 0)|
|
||||||
!s->root_directory_start_only,
|
(IN_SET(s->control_command_id, SERVICE_EXEC_STOP, SERVICE_EXEC_STOP_POST) ? EXEC_SETENV_RESULT : 0),
|
||||||
s->control_command_id == SERVICE_EXEC_START_PRE ||
|
|
||||||
s->control_command_id == SERVICE_EXEC_STOP_POST,
|
|
||||||
true,
|
|
||||||
&s->control_pid);
|
&s->control_pid);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -1981,11 +1974,7 @@ static void service_run_next_main(Service *s) {
|
|||||||
r = service_spawn(s,
|
r = service_spawn(s,
|
||||||
s->main_command,
|
s->main_command,
|
||||||
s->timeout_start_usec,
|
s->timeout_start_usec,
|
||||||
true,
|
EXEC_PASS_FDS|EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN|EXEC_SET_WATCHDOG,
|
||||||
true,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
&pid);
|
&pid);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -2656,7 +2645,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
|
|||||||
"EXIT_STATUS=%i", status,
|
"EXIT_STATUS=%i", status,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
if (f != SERVICE_SUCCESS)
|
if (s->result == SERVICE_SUCCESS)
|
||||||
s->result = f;
|
s->result = f;
|
||||||
|
|
||||||
if (s->main_command &&
|
if (s->main_command &&
|
||||||
@ -2737,7 +2726,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
|
|||||||
"Control process exited, code=%s status=%i",
|
"Control process exited, code=%s status=%i",
|
||||||
sigchld_code_to_string(code), status);
|
sigchld_code_to_string(code), status);
|
||||||
|
|
||||||
if (f != SERVICE_SUCCESS)
|
if (s->result == SERVICE_SUCCESS)
|
||||||
s->result = f;
|
s->result = f;
|
||||||
|
|
||||||
/* Immediately get rid of the cgroup, so that the
|
/* Immediately get rid of the cgroup, so that the
|
||||||
|
@ -1749,9 +1749,7 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
|
|||||||
pid_t pid;
|
pid_t pid;
|
||||||
int r;
|
int r;
|
||||||
ExecParameters exec_params = {
|
ExecParameters exec_params = {
|
||||||
.apply_permissions = true,
|
.flags = EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN,
|
||||||
.apply_chroot = true,
|
|
||||||
.apply_tty_stdin = true,
|
|
||||||
.stdin_fd = -1,
|
.stdin_fd = -1,
|
||||||
.stdout_fd = -1,
|
.stdout_fd = -1,
|
||||||
.stderr_fd = -1,
|
.stderr_fd = -1,
|
||||||
@ -1785,7 +1783,7 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
|
|||||||
|
|
||||||
exec_params.argv = argv;
|
exec_params.argv = argv;
|
||||||
exec_params.environment = UNIT(s)->manager->environment;
|
exec_params.environment = UNIT(s)->manager->environment;
|
||||||
exec_params.confirm_spawn = UNIT(s)->manager->confirm_spawn;
|
exec_params.flags |= UNIT(s)->manager->confirm_spawn ? EXEC_CONFIRM_SPAWN : 0;
|
||||||
exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported;
|
exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported;
|
||||||
exec_params.cgroup_path = UNIT(s)->cgroup_path;
|
exec_params.cgroup_path = UNIT(s)->cgroup_path;
|
||||||
exec_params.cgroup_delegate = s->cgroup_context.delegate;
|
exec_params.cgroup_delegate = s->cgroup_context.delegate;
|
||||||
@ -1897,7 +1895,7 @@ fail:
|
|||||||
static void socket_enter_dead(Socket *s, SocketResult f) {
|
static void socket_enter_dead(Socket *s, SocketResult f) {
|
||||||
assert(s);
|
assert(s);
|
||||||
|
|
||||||
if (f != SOCKET_SUCCESS)
|
if (s->result == SOCKET_SUCCESS)
|
||||||
s->result = f;
|
s->result = f;
|
||||||
|
|
||||||
socket_set_state(s, s->result != SOCKET_SUCCESS ? SOCKET_FAILED : SOCKET_DEAD);
|
socket_set_state(s, s->result != SOCKET_SUCCESS ? SOCKET_FAILED : SOCKET_DEAD);
|
||||||
@ -1916,7 +1914,7 @@ static void socket_enter_stop_post(Socket *s, SocketResult f) {
|
|||||||
int r;
|
int r;
|
||||||
assert(s);
|
assert(s);
|
||||||
|
|
||||||
if (f != SOCKET_SUCCESS)
|
if (s->result == SOCKET_SUCCESS)
|
||||||
s->result = f;
|
s->result = f;
|
||||||
|
|
||||||
socket_unwatch_control_pid(s);
|
socket_unwatch_control_pid(s);
|
||||||
@ -1944,7 +1942,7 @@ static void socket_enter_signal(Socket *s, SocketState state, SocketResult f) {
|
|||||||
|
|
||||||
assert(s);
|
assert(s);
|
||||||
|
|
||||||
if (f != SOCKET_SUCCESS)
|
if (s->result == SOCKET_SUCCESS)
|
||||||
s->result = f;
|
s->result = f;
|
||||||
|
|
||||||
r = unit_kill_context(
|
r = unit_kill_context(
|
||||||
@ -1988,7 +1986,7 @@ static void socket_enter_stop_pre(Socket *s, SocketResult f) {
|
|||||||
int r;
|
int r;
|
||||||
assert(s);
|
assert(s);
|
||||||
|
|
||||||
if (f != SOCKET_SUCCESS)
|
if (s->result == SOCKET_SUCCESS)
|
||||||
s->result = f;
|
s->result = f;
|
||||||
|
|
||||||
socket_unwatch_control_pid(s);
|
socket_unwatch_control_pid(s);
|
||||||
@ -2770,7 +2768,7 @@ static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) {
|
|||||||
"Control process exited, code=%s status=%i",
|
"Control process exited, code=%s status=%i",
|
||||||
sigchld_code_to_string(code), status);
|
sigchld_code_to_string(code), status);
|
||||||
|
|
||||||
if (f != SOCKET_SUCCESS)
|
if (s->result == SOCKET_SUCCESS)
|
||||||
s->result = f;
|
s->result = f;
|
||||||
|
|
||||||
if (s->control_command &&
|
if (s->control_command &&
|
||||||
|
@ -611,9 +611,7 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
|
|||||||
pid_t pid;
|
pid_t pid;
|
||||||
int r;
|
int r;
|
||||||
ExecParameters exec_params = {
|
ExecParameters exec_params = {
|
||||||
.apply_permissions = true,
|
.flags = EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN,
|
||||||
.apply_chroot = true,
|
|
||||||
.apply_tty_stdin = true,
|
|
||||||
.stdin_fd = -1,
|
.stdin_fd = -1,
|
||||||
.stdout_fd = -1,
|
.stdout_fd = -1,
|
||||||
.stderr_fd = -1,
|
.stderr_fd = -1,
|
||||||
@ -642,7 +640,7 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
|
|||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
exec_params.environment = UNIT(s)->manager->environment;
|
exec_params.environment = UNIT(s)->manager->environment;
|
||||||
exec_params.confirm_spawn = UNIT(s)->manager->confirm_spawn;
|
exec_params.flags |= UNIT(s)->manager->confirm_spawn ? EXEC_CONFIRM_SPAWN : 0;
|
||||||
exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported;
|
exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported;
|
||||||
exec_params.cgroup_path = UNIT(s)->cgroup_path;
|
exec_params.cgroup_path = UNIT(s)->cgroup_path;
|
||||||
exec_params.cgroup_delegate = s->cgroup_context.delegate;
|
exec_params.cgroup_delegate = s->cgroup_context.delegate;
|
||||||
@ -675,7 +673,7 @@ fail:
|
|||||||
static void swap_enter_dead(Swap *s, SwapResult f) {
|
static void swap_enter_dead(Swap *s, SwapResult f) {
|
||||||
assert(s);
|
assert(s);
|
||||||
|
|
||||||
if (f != SWAP_SUCCESS)
|
if (s->result == SWAP_SUCCESS)
|
||||||
s->result = f;
|
s->result = f;
|
||||||
|
|
||||||
swap_set_state(s, s->result != SWAP_SUCCESS ? SWAP_FAILED : SWAP_DEAD);
|
swap_set_state(s, s->result != SWAP_SUCCESS ? SWAP_FAILED : SWAP_DEAD);
|
||||||
@ -691,7 +689,7 @@ static void swap_enter_dead(Swap *s, SwapResult f) {
|
|||||||
static void swap_enter_active(Swap *s, SwapResult f) {
|
static void swap_enter_active(Swap *s, SwapResult f) {
|
||||||
assert(s);
|
assert(s);
|
||||||
|
|
||||||
if (f != SWAP_SUCCESS)
|
if (s->result == SWAP_SUCCESS)
|
||||||
s->result = f;
|
s->result = f;
|
||||||
|
|
||||||
swap_set_state(s, SWAP_ACTIVE);
|
swap_set_state(s, SWAP_ACTIVE);
|
||||||
@ -702,7 +700,7 @@ static void swap_enter_signal(Swap *s, SwapState state, SwapResult f) {
|
|||||||
|
|
||||||
assert(s);
|
assert(s);
|
||||||
|
|
||||||
if (f != SWAP_SUCCESS)
|
if (s->result == SWAP_SUCCESS)
|
||||||
s->result = f;
|
s->result = f;
|
||||||
|
|
||||||
r = unit_kill_context(
|
r = unit_kill_context(
|
||||||
@ -999,7 +997,7 @@ static void swap_sigchld_event(Unit *u, pid_t pid, int code, int status) {
|
|||||||
else
|
else
|
||||||
assert_not_reached("Unknown code");
|
assert_not_reached("Unknown code");
|
||||||
|
|
||||||
if (f != SWAP_SUCCESS)
|
if (s->result == SWAP_SUCCESS)
|
||||||
s->result = f;
|
s->result = f;
|
||||||
|
|
||||||
if (s->control_command) {
|
if (s->control_command) {
|
||||||
|
@ -291,7 +291,7 @@ static int timer_coldplug(Unit *u) {
|
|||||||
static void timer_enter_dead(Timer *t, TimerResult f) {
|
static void timer_enter_dead(Timer *t, TimerResult f) {
|
||||||
assert(t);
|
assert(t);
|
||||||
|
|
||||||
if (f != TIMER_SUCCESS)
|
if (t->result == TIMER_SUCCESS)
|
||||||
t->result = f;
|
t->result = f;
|
||||||
|
|
||||||
timer_set_state(t, t->result != TIMER_SUCCESS ? TIMER_FAILED : TIMER_DEAD);
|
timer_set_state(t, t->result != TIMER_SUCCESS ? TIMER_FAILED : TIMER_DEAD);
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include "compress.h"
|
#include "compress.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "fileio.h"
|
#include "fileio.h"
|
||||||
|
#include "fs-util.h"
|
||||||
#include "journal-internal.h"
|
#include "journal-internal.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
@ -609,7 +610,13 @@ static int save_core(sd_journal *j, int fd, char **path, bool *unlink_temp) {
|
|||||||
char *temp = NULL;
|
char *temp = NULL;
|
||||||
|
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
temp = strdup("/var/tmp/coredump-XXXXXX");
|
const char *vt;
|
||||||
|
|
||||||
|
r = var_tmp_dir(&vt);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to acquire temporary directory path: %m");
|
||||||
|
|
||||||
|
temp = strjoin(vt, "/coredump-XXXXXX", NULL);
|
||||||
if (!temp)
|
if (!temp)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
|
@ -826,7 +826,7 @@ int journal_file_verify(
|
|||||||
int data_fd = -1, entry_fd = -1, entry_array_fd = -1;
|
int data_fd = -1, entry_fd = -1, entry_array_fd = -1;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
bool found_last = false;
|
bool found_last = false;
|
||||||
_cleanup_free_ char *tmp_dir = NULL;
|
const char *tmp_dir = NULL;
|
||||||
|
|
||||||
#ifdef HAVE_GCRYPT
|
#ifdef HAVE_GCRYPT
|
||||||
uint64_t last_tag = 0;
|
uint64_t last_tag = 0;
|
||||||
@ -846,7 +846,7 @@ int journal_file_verify(
|
|||||||
} else if (f->seal)
|
} else if (f->seal)
|
||||||
return -ENOKEY;
|
return -ENOKEY;
|
||||||
|
|
||||||
r = var_tmp(&tmp_dir);
|
r = var_tmp_dir(&tmp_dir);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_error_errno(r, "Failed to determine temporary directory: %m");
|
log_error_errno(r, "Failed to determine temporary directory: %m");
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -954,7 +954,7 @@ static int method_clean_pool(sd_bus_message *message, void *userdata, sd_bus_err
|
|||||||
/* Create a temporary file we can dump information about deleted images into. We use a temporary file for this
|
/* Create a temporary file we can dump information about deleted images into. We use a temporary file for this
|
||||||
* instead of a pipe or so, since this might grow quit large in theory and we don't want to process this
|
* instead of a pipe or so, since this might grow quit large in theory and we don't want to process this
|
||||||
* continuously */
|
* continuously */
|
||||||
result_fd = open_tmpfile_unlinkable("/tmp/", O_RDWR|O_CLOEXEC);
|
result_fd = open_tmpfile_unlinkable(NULL, O_RDWR|O_CLOEXEC);
|
||||||
if (result_fd < 0)
|
if (result_fd < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
|
@ -26,9 +26,52 @@
|
|||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
#include "nss-util.h"
|
#include "nss-util.h"
|
||||||
#include "signal-util.h"
|
#include "signal-util.h"
|
||||||
|
#include "string-util.h"
|
||||||
#include "user-util.h"
|
#include "user-util.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
#ifndef NOBODY_USER_NAME
|
||||||
|
#define NOBODY_USER_NAME "nobody"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NOBODY_GROUP_NAME
|
||||||
|
#define NOBODY_GROUP_NAME "nobody"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const struct passwd root_passwd = {
|
||||||
|
.pw_name = (char*) "root",
|
||||||
|
.pw_passwd = (char*) "x", /* see shadow file */
|
||||||
|
.pw_uid = 0,
|
||||||
|
.pw_gid = 0,
|
||||||
|
.pw_gecos = (char*) "Super User",
|
||||||
|
.pw_dir = (char*) "/root",
|
||||||
|
.pw_shell = (char*) "/bin/sh",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct passwd nobody_passwd = {
|
||||||
|
.pw_name = (char*) NOBODY_USER_NAME,
|
||||||
|
.pw_passwd = (char*) "*", /* locked */
|
||||||
|
.pw_uid = 65534,
|
||||||
|
.pw_gid = 65534,
|
||||||
|
.pw_gecos = (char*) "User Nobody",
|
||||||
|
.pw_dir = (char*) "/",
|
||||||
|
.pw_shell = (char*) "/sbin/nologin",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct group root_group = {
|
||||||
|
.gr_name = (char*) "root",
|
||||||
|
.gr_gid = 0,
|
||||||
|
.gr_passwd = (char*) "x", /* see shadow file */
|
||||||
|
.gr_mem = (char*[]) { NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct group nobody_group = {
|
||||||
|
.gr_name = (char*) NOBODY_GROUP_NAME,
|
||||||
|
.gr_gid = 65534,
|
||||||
|
.gr_passwd = (char*) "*", /* locked */
|
||||||
|
.gr_mem = (char*[]) { NULL },
|
||||||
|
};
|
||||||
|
|
||||||
NSS_GETPW_PROTOTYPES(systemd);
|
NSS_GETPW_PROTOTYPES(systemd);
|
||||||
NSS_GETGR_PROTOTYPES(systemd);
|
NSS_GETGR_PROTOTYPES(systemd);
|
||||||
|
|
||||||
@ -50,6 +93,23 @@ enum nss_status _nss_systemd_getpwnam_r(
|
|||||||
assert(name);
|
assert(name);
|
||||||
assert(pwd);
|
assert(pwd);
|
||||||
|
|
||||||
|
if (!valid_user_group_name(name)) {
|
||||||
|
r = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Synthesize entries for the root and nobody users, in case they are missing in /etc/passwd */
|
||||||
|
if (streq(name, root_passwd.pw_name)) {
|
||||||
|
*pwd = root_passwd;
|
||||||
|
*errnop = 0;
|
||||||
|
return NSS_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
if (streq(name, nobody_passwd.pw_name)) {
|
||||||
|
*pwd = nobody_passwd;
|
||||||
|
*errnop = 0;
|
||||||
|
return NSS_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
/* Make sure that we don't go in circles when allocating a dynamic UID by checking our own database */
|
/* Make sure that we don't go in circles when allocating a dynamic UID by checking our own database */
|
||||||
if (getenv_bool("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
|
if (getenv_bool("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
|
||||||
goto not_found;
|
goto not_found;
|
||||||
@ -126,6 +186,18 @@ enum nss_status _nss_systemd_getpwuid_r(
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Synthesize data for the root user and for nobody in case they are missing from /etc/passwd */
|
||||||
|
if (uid == root_passwd.pw_uid) {
|
||||||
|
*pwd = root_passwd;
|
||||||
|
*errnop = 0;
|
||||||
|
return NSS_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
if (uid == nobody_passwd.pw_uid) {
|
||||||
|
*pwd = nobody_passwd;
|
||||||
|
*errnop = 0;
|
||||||
|
return NSS_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
if (uid <= SYSTEM_UID_MAX)
|
if (uid <= SYSTEM_UID_MAX)
|
||||||
goto not_found;
|
goto not_found;
|
||||||
|
|
||||||
@ -202,6 +274,23 @@ enum nss_status _nss_systemd_getgrnam_r(
|
|||||||
assert(name);
|
assert(name);
|
||||||
assert(gr);
|
assert(gr);
|
||||||
|
|
||||||
|
if (!valid_user_group_name(name)) {
|
||||||
|
r = -EINVAL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Synthesize records for root and nobody, in case they are missing form /etc/group */
|
||||||
|
if (streq(name, root_group.gr_name)) {
|
||||||
|
*gr = root_group;
|
||||||
|
*errnop = 0;
|
||||||
|
return NSS_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
if (streq(name, nobody_group.gr_name)) {
|
||||||
|
*gr = nobody_group;
|
||||||
|
*errnop = 0;
|
||||||
|
return NSS_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
if (getenv_bool("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
|
if (getenv_bool("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
|
||||||
goto not_found;
|
goto not_found;
|
||||||
|
|
||||||
@ -275,6 +364,18 @@ enum nss_status _nss_systemd_getgrgid_r(
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Synthesize records for root and nobody, in case they are missing from /etc/group */
|
||||||
|
if (gid == root_group.gr_gid) {
|
||||||
|
*gr = root_group;
|
||||||
|
*errnop = 0;
|
||||||
|
return NSS_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
if (gid == nobody_group.gr_gid) {
|
||||||
|
*gr = nobody_group;
|
||||||
|
*errnop = 0;
|
||||||
|
return NSS_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
if (gid <= SYSTEM_GID_MAX)
|
if (gid <= SYSTEM_GID_MAX)
|
||||||
goto not_found;
|
goto not_found;
|
||||||
|
|
||||||
|
@ -83,47 +83,35 @@ static void test_get_files_in_directory(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void test_var_tmp(void) {
|
static void test_var_tmp(void) {
|
||||||
char *tmp_dir = NULL;
|
_cleanup_free_ char *tmpdir_backup = NULL;
|
||||||
char *tmpdir_backup = NULL;
|
const char *tmp_dir = NULL, *t;
|
||||||
const char *default_var_tmp = NULL;
|
|
||||||
const char *var_name;
|
|
||||||
bool do_overwrite = true;
|
|
||||||
|
|
||||||
default_var_tmp = "/var/tmp";
|
t = getenv("TMPDIR");
|
||||||
var_name = "TMPDIR";
|
if (t) {
|
||||||
|
tmpdir_backup = strdup(t);
|
||||||
if (getenv(var_name) != NULL) {
|
assert_se(tmpdir_backup);
|
||||||
tmpdir_backup = strdup(getenv(var_name));
|
|
||||||
assert_se(tmpdir_backup != NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsetenv(var_name);
|
assert(unsetenv("TMPDIR") >= 0);
|
||||||
|
|
||||||
var_tmp(&tmp_dir);
|
assert_se(var_tmp_dir(&tmp_dir) >= 0);
|
||||||
assert_se(!strcmp(tmp_dir, default_var_tmp));
|
assert_se(streq(tmp_dir, "/var/tmp"));
|
||||||
|
|
||||||
free(tmp_dir);
|
assert_se(setenv("TMPDIR", "/tmp", true) >= 0);
|
||||||
|
assert_se(streq(getenv("TMPDIR"), "/tmp"));
|
||||||
|
|
||||||
setenv(var_name, "/tmp", do_overwrite);
|
assert_se(var_tmp_dir(&tmp_dir) >= 0);
|
||||||
assert_se(!strcmp(getenv(var_name), "/tmp"));
|
assert_se(streq(tmp_dir, "/tmp"));
|
||||||
|
|
||||||
var_tmp(&tmp_dir);
|
assert_se(setenv("TMPDIR", "/88_does_not_exist_88", true) >= 0);
|
||||||
assert_se(!strcmp(tmp_dir, "/tmp"));
|
assert_se(streq(getenv("TMPDIR"), "/88_does_not_exist_88"));
|
||||||
|
|
||||||
free(tmp_dir);
|
assert_se(var_tmp_dir(&tmp_dir) >= 0);
|
||||||
|
assert_se(streq(tmp_dir, "/var/tmp"));
|
||||||
|
|
||||||
setenv(var_name, "/88_does_not_exist_88", do_overwrite);
|
if (tmpdir_backup) {
|
||||||
assert_se(!strcmp(getenv(var_name), "/88_does_not_exist_88"));
|
assert_se(setenv("TMPDIR", tmpdir_backup, true) >= 0);
|
||||||
|
assert_se(streq(getenv("TMPDIR"), tmpdir_backup));
|
||||||
var_tmp(&tmp_dir);
|
|
||||||
assert_se(!strcmp(tmp_dir, default_var_tmp));
|
|
||||||
|
|
||||||
free(tmp_dir);
|
|
||||||
|
|
||||||
if (tmpdir_backup != NULL) {
|
|
||||||
setenv(var_name, tmpdir_backup, do_overwrite);
|
|
||||||
assert_se(!strcmp(getenv(var_name), tmpdir_backup));
|
|
||||||
free(tmpdir_backup);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user