From e4d07d1a2d66fd200abdd977b70fc6ac69a369ce Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 9 May 2025 11:18:02 +0900 Subject: [PATCH] userdb: introduce USERDB_SYNTHESIZE_NUMERIC flag When the flag is set, even if the specified UID/GID does not exist, create a synthetic user record for the UID/GID. Currently, only system UID/GID are supported. --- src/shared/userdb.c | 56 +++++++++++++++++++++++++++++++++++++++++++++ src/shared/userdb.h | 1 + 2 files changed, 57 insertions(+) diff --git a/src/shared/userdb.c b/src/shared/userdb.c index 5480caa4cf3..2972def56a3 100644 --- a/src/shared/userdb.c +++ b/src/shared/userdb.c @@ -742,6 +742,31 @@ static int synthetic_foreign_user_build(uid_t foreign_uid, UserRecord **ret) { SD_JSON_BUILD_PAIR("disposition", JSON_BUILD_CONST_STRING("foreign"))); } +static int synthetic_numeric_user_build(uid_t uid, UserRecord **ret) { + assert(ret); + + if (uid == 0) /* This should be handled by synthetic_root_user_build() */ + return -ESRCH; + + if (!uid_is_system(uid)) + return -ESRCH; + + _cleanup_free_ char *un = NULL; + if (asprintf(&un, "unknown-" UID_FMT, uid) < 0) + return -ENOMEM; + + _cleanup_free_ char *rn = NULL; + if (asprintf(&rn, "Unknown System UID " UID_FMT, uid) < 0) + return -ENOMEM; + + return user_record_buildo( + ret, + SD_JSON_BUILD_PAIR_STRING("userName", un), + SD_JSON_BUILD_PAIR_STRING("realName", rn), + SD_JSON_BUILD_PAIR_UNSIGNED("uid", uid), + SD_JSON_BUILD_PAIR_STRING("disposition", "system")); +} + static int user_name_foreign_extract_uid(const char *name, uid_t *ret_uid) { int r; @@ -963,6 +988,9 @@ static int userdb_by_uid_fallbacks( if (!FLAGS_SET(flags, USERDB_DONT_SYNTHESIZE_FOREIGN) && uid_is_foreign(uid)) return synthetic_foreign_user_build(uid - FOREIGN_UID_BASE, ret); + if (FLAGS_SET(flags, USERDB_SYNTHESIZE_NUMERIC)) + return synthetic_numeric_user_build(uid, ret); + return -ESRCH; } @@ -1232,6 +1260,31 @@ static int synthetic_foreign_group_build(gid_t foreign_gid, GroupRecord **ret) { SD_JSON_BUILD_PAIR("disposition", JSON_BUILD_CONST_STRING("foreign"))); } +static int synthetic_numeric_group_build(gid_t gid, GroupRecord **ret) { + assert(ret); + + if (gid == 0) /* This should be handled by synthetic_root_group_build() */ + return -ESRCH; + + if (!gid_is_system(gid)) + return -ESRCH; + + _cleanup_free_ char *gn = NULL; + if (asprintf(&gn, "unknown-" GID_FMT, gid) < 0) + return -ENOMEM; + + _cleanup_free_ char *d = NULL; + if (asprintf(&d, "Unknown System GID " UID_FMT, gid) < 0) + return -ENOMEM; + + return group_record_buildo( + ret, + SD_JSON_BUILD_PAIR_STRING("groupName", gn), + SD_JSON_BUILD_PAIR_STRING("description", d), + SD_JSON_BUILD_PAIR_UNSIGNED("gid", gid), + SD_JSON_BUILD_PAIR_STRING("disposition", "system")); +} + static int query_append_gid_match(sd_json_variant **query, const UserDBMatch *match) { int r; @@ -1387,6 +1440,9 @@ static int groupdb_by_gid_fallbacks( if (!FLAGS_SET(flags, USERDB_DONT_SYNTHESIZE_FOREIGN) && gid_is_foreign(gid)) return synthetic_foreign_group_build(gid - FOREIGN_UID_BASE, ret); + if (FLAGS_SET(flags, USERDB_SYNTHESIZE_NUMERIC)) + return synthetic_numeric_group_build(gid, ret); + return -ESRCH; } diff --git a/src/shared/userdb.h b/src/shared/userdb.h index 783e39d5911..683b94a6df4 100644 --- a/src/shared/userdb.h +++ b/src/shared/userdb.h @@ -32,6 +32,7 @@ typedef enum UserDBFlags { USERDB_DROPIN_ONLY = USERDB_EXCLUDE_NSS|USERDB_EXCLUDE_VARLINK|USERDB_DONT_SYNTHESIZE_INTRINSIC|USERDB_DONT_SYNTHESIZE_FOREIGN, USERDB_PARSE_NUMERIC = 1 << 8, /* if a numeric UID is specified as name, parse it and look up by UID/GID */ + USERDB_SYNTHESIZE_NUMERIC = 1 << 8, /* synthesize system UID/GID even if it does not exist */ } UserDBFlags; /* Well-known errors we'll return here: -- 2.47.3