user-util: rework how we validate user names

This reworks the user validation infrastructure. There are now two
modes. In regular mode we are strict and test against a strict set of
valid chars. And in "relaxed" mode we just filter out some really
obvious, dangerous stuff. i.e. strict is whitelisting what is OK, but
"relaxed" is blacklisting what is really not OK.

The idea is that we use strict mode whenver we allocate a new user
(i.e. in sysusers.d or homed), while "relaxed" mode is when we process
users registered elsewhere, (i.e. userdb, logind, …)

The requirements on user name validity vary wildly. SSSD thinks its fine
to embedd "@" for example, while the suggested NAME_REGEX field on
Debian does not even allow uppercase chars…

This effectively liberaralizes a lot what we expect from usernames.

The code that warns about questionnable user names is now optional and
only used at places such as unit file parsing, so that it doesn't show
up on every userdb query, but only when processing configuration files
that know better.

Fixes: #15149 #15090
This commit is contained in:
Lennart Poettering
2020-04-08 17:11:20 +02:00
parent 2aea5883f1
commit 7a8867abfa
23 changed files with 302 additions and 245 deletions
+3 -3
View File
@@ -1204,10 +1204,10 @@ int bus_exec_context_set_transient_property(
flags |= UNIT_PRIVATE;
if (streq(name, "User"))
return bus_set_transient_user_compat(u, name, &c->user, message, flags, error);
return bus_set_transient_user_relaxed(u, name, &c->user, message, flags, error);
if (streq(name, "Group"))
return bus_set_transient_user_compat(u, name, &c->group, message, flags, error);
return bus_set_transient_user_relaxed(u, name, &c->group, message, flags, error);
if (streq(name, "TTYPath"))
return bus_set_transient_path(u, name, &c->tty_path, message, flags, error);
@@ -1392,7 +1392,7 @@ int bus_exec_context_set_transient_property(
return r;
STRV_FOREACH(p, l)
if (!isempty(*p) && !valid_user_group_name_or_id_compat(*p))
if (!isempty(*p) && !valid_user_group_name(*p, VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX|VALID_USER_WARN))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
"Invalid supplementary group names");
+1 -1
View File
@@ -1643,7 +1643,7 @@ static int method_lookup_dynamic_user_by_name(sd_bus_message *message, void *use
if (!MANAGER_IS_SYSTEM(m))
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Dynamic users are only supported in the system instance.");
if (!valid_user_group_name(name))
if (!valid_user_group_name(name, VALID_USER_RELAX))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "User name invalid: %s", name);
r = dynamic_user_lookup_name(m, name, &uid);
+2 -2
View File
@@ -278,10 +278,10 @@ static int bus_socket_set_transient_property(
return bus_set_transient_fdname(u, name, &s->fdname, message, flags, error);
if (streq(name, "SocketUser"))
return bus_set_transient_user_compat(u, name, &s->user, message, flags, error);
return bus_set_transient_user_relaxed(u, name, &s->user, message, flags, error);
if (streq(name, "SocketGroup"))
return bus_set_transient_user_compat(u, name, &s->group, message, flags, error);
return bus_set_transient_user_relaxed(u, name, &s->group, message, flags, error);
if (streq(name, "BindIPv6Only"))
return bus_set_transient_bind_ipv6_only(u, name, &s->bind_ipv6_only, message, flags, error);
+6 -1
View File
@@ -30,7 +30,12 @@ int bus_property_get_triggered_unit(
BUS_DEFINE_SET_TRANSIENT(mode_t, "u", uint32_t, mode_t, "%040o");
BUS_DEFINE_SET_TRANSIENT(unsigned, "u", uint32_t, unsigned, "%" PRIu32);
BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(user_compat, valid_user_group_name_or_id_compat);
static inline bool valid_user_group_name_or_id_relaxed(const char *u) {
return valid_user_group_name(u, VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX);
}
BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(user_relaxed, valid_user_group_name_or_id_relaxed);
BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(path, path_is_absolute);
int bus_set_transient_string(
+1 -1
View File
@@ -236,7 +236,7 @@ int bus_property_get_triggered_unit(sd_bus *bus, const char *path, const char *i
int bus_set_transient_mode_t(Unit *u, const char *name, mode_t *p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
int bus_set_transient_unsigned(Unit *u, const char *name, unsigned *p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
int bus_set_transient_user_compat(Unit *u, const char *name, char **p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
int bus_set_transient_user_relaxed(Unit *u, const char *name, char **p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
int bus_set_transient_path(Unit *u, const char *name, char **p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
int bus_set_transient_string(Unit *u, const char *name, char **p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
int bus_set_transient_bool(Unit *u, const char *name, bool *p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
+1 -1
View File
@@ -116,7 +116,7 @@ static int dynamic_user_acquire(Manager *m, const char *name, DynamicUser** ret)
return 0;
}
if (!valid_user_group_name_or_id(name))
if (!valid_user_group_name(name, VALID_USER_ALLOW_NUMERIC))
return -EINVAL;
if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, storage_socket) < 0)
+2 -2
View File
@@ -2068,7 +2068,7 @@ int config_parse_user_group_compat(
return -ENOEXEC;
}
if (!valid_user_group_name_or_id_compat(k)) {
if (!valid_user_group_name(k, VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX|VALID_USER_WARN)) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid user/group name or numeric ID: %s", k);
return -ENOEXEC;
}
@@ -2122,7 +2122,7 @@ int config_parse_user_group_strv_compat(
return -ENOEXEC;
}
if (!valid_user_group_name_or_id_compat(k)) {
if (!valid_user_group_name(k, VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX|VALID_USER_WARN)) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid user/group name or numeric ID: %s", k);
return -ENOEXEC;
}
+1 -1
View File
@@ -4287,7 +4287,7 @@ static int user_from_unit_name(Unit *u, char **ret) {
if (r < 0)
return r;
if (valid_user_group_name(n)) {
if (valid_user_group_name(n, 0)) {
*ret = TAKE_PTR(n);
return 0;
}