X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fbasic%2Fuser-util.c;h=893790f78f861ac7affb9158223195634246601c;hp=e6f3803a3b5b8bc476ec6c9176a01df62fc18769;hb=1e2c11636861da69c5637e59afe207a11dd4f386;hpb=00b05b66b96a48fa4714589e2c82fd6c0265dd95 diff --git a/src/basic/user-util.c b/src/basic/user-util.c index e6f3803a3..893790f78 100644 --- a/src/basic/user-util.c +++ b/src/basic/user-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,17 +17,31 @@ along with systemd; If not, see . ***/ +#include +#include +#include #include #include +#include +#include +#include +#include +#include +#include +#include +#include #include "alloc-util.h" #include "fd-util.h" +#include "formats-util.h" #include "macro.h" +#include "missing.h" #include "parse-util.h" #include "path-util.h" #include "string-util.h" +#include "strv.h" #include "user-util.h" -#include "util.h" +#include "utf8.h" bool uid_is_valid(uid_t uid) { @@ -67,7 +79,6 @@ int parse_uid(const char *s, uid_t *ret) { return 0; } -#if 0 /// UNNEEDED by elogind char* getlogname_malloc(void) { uid_t uid; struct stat st; @@ -80,6 +91,7 @@ char* getlogname_malloc(void) { return uid_to_name(uid); } +#if 0 /// UNNEEDED by elogind char *getusername_malloc(void) { const char *e; @@ -166,6 +178,35 @@ int get_user_creds( return 0; } +int get_user_creds_clean( + const char **username, + uid_t *uid, gid_t *gid, + const char **home, + const char **shell) { + + int r; + + /* Like get_user_creds(), but resets home/shell to NULL if they don't contain anything relevant. */ + + r = get_user_creds(username, uid, gid, home, shell); + if (r < 0) + return r; + + if (shell && + (isempty(*shell) || PATH_IN_SET(*shell, + "/bin/nologin", + "/sbin/nologin", + "/usr/bin/nologin", + "/usr/sbin/nologin"))) + *shell = NULL; + + if (home && + (isempty(*home) || path_equal(*home, "/"))) + *home = NULL; + + return 0; +} + int get_group_creds(const char **groupname, gid_t *gid) { struct group *g; gid_t id; @@ -422,9 +463,11 @@ int get_shell(char **_s) { #endif // 0 int reset_uid_gid(void) { + int r; - if (setgroups(0, NULL) < 0) - return -errno; + r = maybe_setgroups(0, NULL); + if (r < 0) + return r; if (setresgid(0, 0, 0) < 0) return -errno; @@ -454,7 +497,7 @@ int take_etc_passwd_lock(const char *root) { * * Note that shadow-utils also takes per-database locks in * addition to lckpwdf(). However, we don't given that they - * are redundant as they they invoke lckpwdf() first and keep + * are redundant as they invoke lckpwdf() first and keep * it during everything they do. The per-database locks are * awfully racy, and thus we just won't do them. */ @@ -476,3 +519,123 @@ int take_etc_passwd_lock(const char *root) { return fd; } #endif // 0 + +bool valid_user_group_name(const char *u) { + const char *i; + long sz; + + /* Checks if the specified name is a valid user/group name. */ + + if (isempty(u)) + return false; + + if (!(u[0] >= 'a' && u[0] <= 'z') && + !(u[0] >= 'A' && u[0] <= 'Z') && + u[0] != '_') + return false; + + for (i = u+1; *i; i++) { + if (!(*i >= 'a' && *i <= 'z') && + !(*i >= 'A' && *i <= 'Z') && + !(*i >= '0' && *i <= '9') && + *i != '_' && + *i != '-') + return false; + } + + sz = sysconf(_SC_LOGIN_NAME_MAX); + assert_se(sz > 0); + + if ((size_t) (i-u) > (size_t) sz) + return false; + + if ((size_t) (i-u) > UT_NAMESIZE - 1) + return false; + + return true; +} + +bool valid_user_group_name_or_id(const char *u) { + + /* Similar as above, but is also fine with numeric UID/GID specifications, as long as they are in the right + * range, and not the invalid user ids. */ + + if (isempty(u)) + return false; + + if (valid_user_group_name(u)) + return true; + + return parse_uid(u, NULL) >= 0; +} + +bool valid_gecos(const char *d) { + + if (!d) + return false; + + if (!utf8_is_valid(d)) + return false; + + if (string_has_cc(d, NULL)) + return false; + + /* Colons are used as field separators, and hence not OK */ + if (strchr(d, ':')) + return false; + + return true; +} + +bool valid_home(const char *p) { + + if (isempty(p)) + return false; + + if (!utf8_is_valid(p)) + return false; + + if (string_has_cc(p, NULL)) + return false; + + if (!path_is_absolute(p)) + return false; + + if (!path_is_safe(p)) + return false; + + /* Colons are used as field separators, and hence not OK */ + if (strchr(p, ':')) + return false; + + return true; +} + +int maybe_setgroups(size_t size, const gid_t *list) { + int r; + + /* Check if setgroups is allowed before we try to drop all the auxiliary groups */ + if (size == 0) { /* Dropping all aux groups? */ + _cleanup_free_ char *setgroups_content = NULL; + bool can_setgroups; + + r = read_one_line_file("/proc/self/setgroups", &setgroups_content); + if (r == -ENOENT) + /* Old kernels don't have /proc/self/setgroups, so assume we can use setgroups */ + can_setgroups = true; + else if (r < 0) + return r; + else + can_setgroups = streq(setgroups_content, "allow"); + + if (!can_setgroups) { + log_debug("Skipping setgroups(), /proc/self/setgroups is set to 'deny'"); + return 0; + } + } + + if (setgroups(size, list) < 0) + return -errno; + + return 0; +}