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:
@@ -86,8 +86,8 @@ static int dispatch_per_machine(const char *name, JsonVariant *variant, JsonDisp
|
||||
{ "matchMachineId", _JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 },
|
||||
{ "matchHostname", _JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 },
|
||||
{ "gid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(GroupRecord, gid), 0 },
|
||||
{ "members", JSON_VARIANT_ARRAY, json_dispatch_user_group_list, offsetof(GroupRecord, members), 0 },
|
||||
{ "administrators", JSON_VARIANT_ARRAY, json_dispatch_user_group_list, offsetof(GroupRecord, administrators), 0 },
|
||||
{ "members", JSON_VARIANT_ARRAY, json_dispatch_user_group_list, offsetof(GroupRecord, members), JSON_RELAX},
|
||||
{ "administrators", JSON_VARIANT_ARRAY, json_dispatch_user_group_list, offsetof(GroupRecord, administrators), JSON_RELAX},
|
||||
{},
|
||||
};
|
||||
|
||||
@@ -190,14 +190,14 @@ int group_record_load(
|
||||
UserRecordLoadFlags load_flags) {
|
||||
|
||||
static const JsonDispatch group_dispatch_table[] = {
|
||||
{ "groupName", JSON_VARIANT_STRING, json_dispatch_user_group_name, offsetof(GroupRecord, group_name), 0 },
|
||||
{ "groupName", JSON_VARIANT_STRING, json_dispatch_user_group_name, offsetof(GroupRecord, group_name), JSON_RELAX},
|
||||
{ "realm", JSON_VARIANT_STRING, json_dispatch_realm, offsetof(GroupRecord, realm), 0 },
|
||||
{ "disposition", JSON_VARIANT_STRING, json_dispatch_user_disposition, offsetof(GroupRecord, disposition), 0 },
|
||||
{ "service", JSON_VARIANT_STRING, json_dispatch_string, offsetof(GroupRecord, service), JSON_SAFE },
|
||||
{ "lastChangeUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(GroupRecord, last_change_usec), 0 },
|
||||
{ "gid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(GroupRecord, gid), 0 },
|
||||
{ "members", JSON_VARIANT_ARRAY, json_dispatch_user_group_list, offsetof(GroupRecord, members), 0 },
|
||||
{ "administrators", JSON_VARIANT_ARRAY, json_dispatch_user_group_list, offsetof(GroupRecord, administrators), 0 },
|
||||
{ "members", JSON_VARIANT_ARRAY, json_dispatch_user_group_list, offsetof(GroupRecord, members), JSON_RELAX},
|
||||
{ "administrators", JSON_VARIANT_ARRAY, json_dispatch_user_group_list, offsetof(GroupRecord, administrators), JSON_RELAX},
|
||||
|
||||
{ "privileged", JSON_VARIANT_OBJECT, dispatch_privileged, 0, 0 },
|
||||
|
||||
|
||||
+1
-1
@@ -4107,7 +4107,7 @@ int json_dispatch_user_group_name(const char *name, JsonVariant *variant, JsonDi
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
|
||||
|
||||
n = json_variant_string(variant);
|
||||
if (!valid_user_group_name_compat(n))
|
||||
if (!valid_user_group_name(n, FLAGS_SET(flags, JSON_RELAX) ? VALID_USER_RELAX : 0))
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid user/group name.", strna(name));
|
||||
|
||||
r = free_and_strdup(s, n);
|
||||
|
||||
@@ -255,6 +255,7 @@ typedef enum JsonDispatchFlags {
|
||||
JSON_MANDATORY = 1 << 1, /* Should existence of this property be mandatory? */
|
||||
JSON_LOG = 1 << 2, /* Should the parser log about errors? */
|
||||
JSON_SAFE = 1 << 3, /* Don't accept "unsafe" strings in json_dispatch_string() + json_dispatch_string() */
|
||||
JSON_RELAX = 1 << 4, /* Use relaxed user name checking in json_dispatch_user_group_name */
|
||||
|
||||
/* The following two may be passed into log_json() in addition to the three above */
|
||||
JSON_DEBUG = 1 << 4, /* Indicates that this log message is a debug message */
|
||||
|
||||
@@ -600,7 +600,7 @@ int json_dispatch_user_group_list(const char *name, JsonVariant *variant, JsonDi
|
||||
if (!json_variant_is_string(e))
|
||||
return json_log(e, flags, SYNTHETIC_ERRNO(EINVAL), "JSON array element is not a string.");
|
||||
|
||||
if (!valid_user_group_name_compat(json_variant_string(e)))
|
||||
if (!valid_user_group_name(json_variant_string(e), FLAGS_SET(flags, JSON_RELAX) ? VALID_USER_RELAX : 0))
|
||||
return json_log(e, flags, SYNTHETIC_ERRNO(EINVAL), "JSON array element is not a valid user/group name: %s", json_variant_string(e));
|
||||
|
||||
r = strv_extend(&l, json_variant_string(e));
|
||||
@@ -938,7 +938,7 @@ static int dispatch_per_machine(const char *name, JsonVariant *variant, JsonDisp
|
||||
{ "imagePath", JSON_VARIANT_STRING, json_dispatch_path, offsetof(UserRecord, image_path), 0 },
|
||||
{ "uid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(UserRecord, uid), 0 },
|
||||
{ "gid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(UserRecord, gid), 0 },
|
||||
{ "memberOf", JSON_VARIANT_ARRAY, json_dispatch_user_group_list, offsetof(UserRecord, member_of), 0 },
|
||||
{ "memberOf", JSON_VARIANT_ARRAY, json_dispatch_user_group_list, offsetof(UserRecord, member_of), JSON_RELAX},
|
||||
{ "fileSystemType", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, file_system_type), JSON_SAFE },
|
||||
{ "partitionUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, partition_uuid), 0 },
|
||||
{ "luksUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, luks_uuid), 0 },
|
||||
@@ -1231,7 +1231,7 @@ int user_group_record_mangle(
|
||||
int user_record_load(UserRecord *h, JsonVariant *v, UserRecordLoadFlags load_flags) {
|
||||
|
||||
static const JsonDispatch user_dispatch_table[] = {
|
||||
{ "userName", JSON_VARIANT_STRING, json_dispatch_user_group_name, offsetof(UserRecord, user_name), 0 },
|
||||
{ "userName", JSON_VARIANT_STRING, json_dispatch_user_group_name, offsetof(UserRecord, user_name), JSON_RELAX},
|
||||
{ "realm", JSON_VARIANT_STRING, json_dispatch_realm, offsetof(UserRecord, realm), 0 },
|
||||
{ "realName", JSON_VARIANT_STRING, json_dispatch_gecos, offsetof(UserRecord, real_name), 0 },
|
||||
{ "emailAddress", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, email_address), JSON_SAFE },
|
||||
@@ -1270,7 +1270,7 @@ int user_record_load(UserRecord *h, JsonVariant *v, UserRecordLoadFlags load_fla
|
||||
{ "homeDirectory", JSON_VARIANT_STRING, json_dispatch_home_directory, offsetof(UserRecord, home_directory), 0 },
|
||||
{ "uid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(UserRecord, uid), 0 },
|
||||
{ "gid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(UserRecord, gid), 0 },
|
||||
{ "memberOf", JSON_VARIANT_ARRAY, json_dispatch_user_group_list, offsetof(UserRecord, member_of), 0 },
|
||||
{ "memberOf", JSON_VARIANT_ARRAY, json_dispatch_user_group_list, offsetof(UserRecord, member_of), JSON_RELAX},
|
||||
{ "fileSystemType", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, file_system_type), JSON_SAFE },
|
||||
{ "partitionUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, partition_uuid), 0 },
|
||||
{ "luksUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, luks_uuid), 0 },
|
||||
|
||||
+4
-4
@@ -587,7 +587,7 @@ int userdb_by_name(const char *name, UserDBFlags flags, UserRecord **ret) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *query = NULL;
|
||||
int r;
|
||||
|
||||
if (!valid_user_group_name_compat(name))
|
||||
if (!valid_user_group_name(name, VALID_USER_RELAX))
|
||||
return -EINVAL;
|
||||
|
||||
r = json_build(&query, JSON_BUILD_OBJECT(
|
||||
@@ -795,7 +795,7 @@ int groupdb_by_name(const char *name, UserDBFlags flags, GroupRecord **ret) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *query = NULL;
|
||||
int r;
|
||||
|
||||
if (!valid_user_group_name_compat(name))
|
||||
if (!valid_user_group_name(name, VALID_USER_RELAX))
|
||||
return -EINVAL;
|
||||
|
||||
r = json_build(&query, JSON_BUILD_OBJECT(
|
||||
@@ -982,7 +982,7 @@ int membershipdb_by_user(const char *name, UserDBFlags flags, UserDBIterator **r
|
||||
|
||||
assert(ret);
|
||||
|
||||
if (!valid_user_group_name_compat(name))
|
||||
if (!valid_user_group_name(name, VALID_USER_RELAX))
|
||||
return -EINVAL;
|
||||
|
||||
r = json_build(&query, JSON_BUILD_OBJECT(
|
||||
@@ -1025,7 +1025,7 @@ int membershipdb_by_group(const char *name, UserDBFlags flags, UserDBIterator **
|
||||
|
||||
assert(ret);
|
||||
|
||||
if (!valid_user_group_name_compat(name))
|
||||
if (!valid_user_group_name(name, VALID_USER_RELAX))
|
||||
return -EINVAL;
|
||||
|
||||
r = json_build(&query, JSON_BUILD_OBJECT(
|
||||
|
||||
Reference in New Issue
Block a user