diff options
author | Lennart Poettering <lennart@poettering.net> | 2013-12-16 04:59:31 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2013-12-16 04:59:31 +0100 |
commit | 2cfbd749af308bdbe56edcfed7f3eea0fc2b93d2 (patch) | |
tree | ee79409a34b1f30d7323bb68064aed7183b0e0a6 /src | |
parent | 213298fb822258bb69c6b85b7c8d7f019fd2306a (diff) |
core: refuse doing %h, %s, %U specifier resolving in PID 1
These specifiers require NSS lookups to work, and we really shouldn't do
them from PID 1 hence. With this change they are now only supported for
user systemd instance, or when the configured user for a unit is root.
Diffstat (limited to 'src')
-rw-r--r-- | src/core/unit-printf.c | 188 | ||||
-rw-r--r-- | src/shared/util.c | 51 | ||||
-rw-r--r-- | src/shared/util.h | 1 |
3 files changed, 169 insertions, 71 deletions
diff --git a/src/core/unit-printf.c b/src/core/unit-printf.c index 1a29a986e9..4e18afab8b 100644 --- a/src/core/unit-printf.c +++ b/src/core/unit-printf.c @@ -83,11 +83,10 @@ static int specifier_instance_unescaped(char specifier, void *data, void *userda assert(u); - if (u->instance) - n = unit_name_unescape(u->instance); - else - n = strdup(""); + if (!u->instance) + return -ENOTSUP; + n = unit_name_unescape(u->instance); if (!n) return -ENOMEM; @@ -105,7 +104,6 @@ static int specifier_filename(char specifier, void *data, void *userdata, char * n = unit_name_path_unescape(u->instance); else n = unit_name_to_path(u->id); - if (!n) return -ENOMEM; @@ -119,7 +117,10 @@ static int specifier_cgroup(char specifier, void *data, void *userdata, char **r assert(u); - n = unit_default_cgroup_path(u); + if (u->cgroup_path) + n = strdup(u->cgroup_path); + else + n = unit_default_cgroup_path(u); if (!n) return -ENOMEM; @@ -156,63 +157,81 @@ static int specifier_cgroup_root(char specifier, void *data, void *userdata, cha static int specifier_runtime(char specifier, void *data, void *userdata, char **ret) { Unit *u = userdata; + const char *e; char *n = NULL; assert(u); - if (u->manager->running_as == SYSTEMD_USER) { - const char *e; - + if (u->manager->running_as == SYSTEMD_SYSTEM) + e = "/run"; + else { e = getenv("XDG_RUNTIME_DIR"); - if (e) { - n = strdup(e); - if (!n) - return -ENOMEM; - } + if (!e) + return -ENOTSUP; } - if (!n) { - n = strdup("/run"); - if (!n) - return -ENOMEM; - } + n = strdup(e); + if (!n) + return -ENOMEM; *ret = n; return 0; } static int specifier_user_name(char specifier, void *data, void *userdata, char **ret) { + char *printed = NULL; Unit *u = userdata; ExecContext *c; int r; - const char *username; - _cleanup_free_ char *tmp = NULL; - uid_t uid; - char *printed = NULL; assert(u); c = unit_get_exec_context(u); + if (!c) + return -ENOTSUP; - if (c && c->user) - username = c->user; - else - /* get USER env from env or our own uid */ - username = tmp = getusername_malloc(); - - /* fish username from passwd */ - r = get_user_creds(&username, &uid, NULL, NULL, NULL); - if (r < 0) - return r; - - switch (specifier) { - case 'U': - if (asprintf(&printed, "%d", uid) < 0) - return -ENOMEM; - break; - case 'u': + if (u->manager->running_as == SYSTEMD_SYSTEM) { + + /* We cannot use NSS from PID 1, hence try to make the + * best of it in that case, and fail if we can't help + * it */ + + if (!c->user || streq(c->user, "root") || streq(c->user, "0")) + printed = strdup(specifier == 'u' ? "root" : "0"); + else { + if (specifier == 'u') + printed = strdup(c->user); + else { + uid_t uid; + + r = parse_uid(c->user, &uid); + if (r < 0) + return -ENODATA; + + asprintf(&printed, "%lu", (unsigned long) uid); + } + } + + } else { + _cleanup_free_ char *tmp = NULL; + const char *username = NULL; + uid_t uid; + + if (c->user) + username = c->user; + else + /* get USER env from env or our own uid */ + username = tmp = getusername_malloc(); + + /* fish username from passwd */ + r = get_user_creds(&username, &uid, NULL, NULL, NULL); + if (r < 0) + return r; + + if (specifier == 'u') printed = strdup(username); - break; + else + asprintf(&printed, "%lu", (unsigned long) uid); } if (!printed) @@ -225,32 +244,44 @@ static int specifier_user_name(char specifier, void *data, void *userdata, char static int specifier_user_home(char specifier, void *data, void *userdata, char **ret) { Unit *u = userdata; ExecContext *c; - int r; - const char *username, *home; char *n; + int r; assert(u); c = unit_get_exec_context(u); + if (!c) + return -ENOTSUP; - /* return HOME if set, otherwise from passwd */ - if (!c || !c->user) { - char *h; + if (u->manager->running_as == SYSTEMD_SYSTEM) { - r = get_home_dir(&h); - if (r < 0) - return r; + /* We cannot use NSS from PID 1, hence try to make the + * best of it if we can, but fail if we can't */ - *ret = h; - return 0; - } + if (!c->user || streq(c->user, "root") || streq(c->user, "0")) + n = strdup("/root"); + else + return -ENOTSUP; + + } else { - username = c->user; - r = get_user_creds(&username, NULL, NULL, &home, NULL); - if (r < 0) - return r; + /* return HOME if set, otherwise from passwd */ + if (!c || !c->user) { + r = get_home_dir(&n); + if (r < 0) + return r; + } else { + const char *username, *home; + + username = c->user; + r = get_user_creds(&username, NULL, NULL, &home, NULL); + if (r < 0) + return r; + + n = strdup(home); + } + } - n = strdup(home); if (!n) return -ENOMEM; @@ -261,25 +292,44 @@ static int specifier_user_home(char specifier, void *data, void *userdata, char static int specifier_user_shell(char specifier, void *data, void *userdata, char **ret) { Unit *u = userdata; ExecContext *c; - int r; - const char *username, *shell; char *n; + int r; assert(u); c = unit_get_exec_context(u); + if (!c) + return -ENOTSUP; - if (c && c->user) - username = c->user; - else - username = "root"; + if (u->manager->running_as == SYSTEMD_SYSTEM) { + + /* We cannot use NSS from PID 1, hence try to make the + * best of it if we can, but fail if we can't */ + + if (!c->user || streq(c->user, "root") || streq(c->user, "0")) + n = strdup("/bin/sh"); + else + return -ENOTSUP; - /* return /bin/sh for root, otherwise the value from passwd */ - r = get_user_creds(&username, NULL, NULL, NULL, &shell); - if (r < 0) - return r; + } else { + + /* return /bin/sh for root, otherwise the value from passwd */ + if (!c->user) { + r = get_shell(&n); + if (r < 0) + return r; + } else { + const char *username, *shell; + + username = c->user; + r = get_user_creds(&username, NULL, NULL, NULL, &shell); + if (r < 0) + return r; + + n = strdup(shell); + } + } - n = strdup(shell); if (!n) return -ENOMEM; @@ -321,7 +371,7 @@ int unit_full_printf(Unit *u, const char *format, char **ret) { * * %f the the instance if set, otherwise the id * %c cgroup path of unit - * %r where units in this slice are place in the cgroup tree + * %r where units in this slice are placed in the cgroup tree * %R the root of this systemd's instance tree * %t the runtime directory to place sockets in (e.g. "/run" or $XDG_RUNTIME_DIR) * %U the UID of the configured user or running user diff --git a/src/shared/util.c b/src/shared/util.c index b5ffaa1c3c..20aec2a5c9 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -5220,10 +5220,10 @@ int make_console_stdio(void) { } int get_home_dir(char **_h) { - char *h; + struct passwd *p; const char *e; + char *h; uid_t u; - struct passwd *p; assert(_h); @@ -5266,6 +5266,53 @@ int get_home_dir(char **_h) { return 0; } +int get_shell(char **_s) { + struct passwd *p; + const char *e; + char *s; + uid_t u; + + assert(_s); + + /* Take the user specified one */ + e = getenv("SHELL"); + if (e) { + s = strdup(e); + if (!s) + return -ENOMEM; + + *_s = s; + return 0; + } + + /* Hardcode home directory for root to avoid NSS */ + u = getuid(); + if (u == 0) { + s = strdup("/bin/sh"); + if (!s) + return -ENOMEM; + + *_s = s; + return 0; + } + + /* Check the database... */ + errno = 0; + p = getpwuid(u); + if (!p) + return errno > 0 ? -errno : -ESRCH; + + if (!path_is_absolute(p->pw_shell)) + return -EINVAL; + + s = strdup(p->pw_shell); + if (!s) + return -ENOMEM; + + *_s = s; + return 0; +} + bool filename_is_safe(const char *p) { if (isempty(p)) diff --git a/src/shared/util.h b/src/shared/util.h index d5fa81c6a5..6fc77808d4 100644 --- a/src/shared/util.h +++ b/src/shared/util.h @@ -552,6 +552,7 @@ bool in_initrd(void); void warn_melody(void); int get_home_dir(char **ret); +int get_shell(char **_ret); static inline void freep(void *p) { free(*(void**) p); |