From 45e587d822e60f643c0cf69584d7ef1ff03818a5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 21 Jan 2025 23:28:12 +0100 Subject: [PATCH 1/3] userdbd: separate parameter structure of GetMemberships() varlink call from the GetUserRecord() one The GetUserRecord() and GetMemberships() have quite different arguments, hence let's use separate structures for both. This makes sense on its own, since it makes the structures a bit smaller, but is also preparation for a later commit that adds a bunch of new fields to one of the structs but not the other. --- src/userdb/userwork.c | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/src/userdb/userwork.c b/src/userdb/userwork.c index dce60e2ebd..c8fef87326 100644 --- a/src/userdb/userwork.c +++ b/src/userdb/userwork.c @@ -29,8 +29,7 @@ #define LISTEN_IDLE_USEC (90 * USEC_PER_SEC) typedef struct LookupParameters { - const char *user_name; - const char *group_name; + const char *name; union { uid_t uid; gid_t gid; @@ -135,9 +134,9 @@ static int userdb_flags_from_service(sd_varlink *link, const char *service, User static int vl_method_get_user_record(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) { static const sd_json_dispatch_field dispatch_table[] = { - { "uid", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uid_gid, offsetof(LookupParameters, uid), 0 }, - { "userName", SD_JSON_VARIANT_STRING, json_dispatch_const_user_group_name, offsetof(LookupParameters, user_name), SD_JSON_RELAX }, - { "service", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(LookupParameters, service), 0 }, + { "uid", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uid_gid, offsetof(LookupParameters, uid), 0 }, + { "userName", SD_JSON_VARIANT_STRING, json_dispatch_const_user_group_name, offsetof(LookupParameters, name), SD_JSON_RELAX }, + { "service", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(LookupParameters, service), 0 }, {} }; @@ -162,8 +161,8 @@ static int vl_method_get_user_record(sd_varlink *link, sd_json_variant *paramete if (uid_is_valid(p.uid)) r = userdb_by_uid(p.uid, userdb_flags, &hr); - else if (p.user_name) - r = userdb_by_name(p.user_name, userdb_flags, &hr); + else if (p.name) + r = userdb_by_name(p.name, userdb_flags, &hr); else { _cleanup_(userdb_iterator_freep) UserDBIterator *iterator = NULL; _cleanup_(sd_json_variant_unrefp) sd_json_variant *last = NULL; @@ -215,7 +214,7 @@ static int vl_method_get_user_record(sd_varlink *link, sd_json_variant *paramete } if ((uid_is_valid(p.uid) && hr->uid != p.uid) || - (p.user_name && !user_record_matches_user_name(hr, p.user_name))) + (p.name && !user_record_matches_user_name(hr, p.name))) return sd_varlink_error(link, "io.systemd.UserDatabase.ConflictingRecordFound", NULL); r = build_user_json(link, hr, &v); @@ -272,9 +271,9 @@ static int build_group_json(sd_varlink *link, GroupRecord *gr, sd_json_variant * static int vl_method_get_group_record(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) { static const sd_json_dispatch_field dispatch_table[] = { - { "gid", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uid_gid, offsetof(LookupParameters, gid), 0 }, - { "groupName", SD_JSON_VARIANT_STRING, json_dispatch_const_user_group_name, offsetof(LookupParameters, group_name), SD_JSON_RELAX }, - { "service", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(LookupParameters, service), 0 }, + { "gid", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uid_gid, offsetof(LookupParameters, gid), 0 }, + { "groupName", SD_JSON_VARIANT_STRING, json_dispatch_const_user_group_name, offsetof(LookupParameters, name), SD_JSON_RELAX }, + { "service", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(LookupParameters, service), 0 }, {} }; @@ -298,8 +297,8 @@ static int vl_method_get_group_record(sd_varlink *link, sd_json_variant *paramet if (gid_is_valid(p.gid)) r = groupdb_by_gid(p.gid, userdb_flags, &g); - else if (p.group_name) - r = groupdb_by_name(p.group_name, userdb_flags, &g); + else if (p.name) + r = groupdb_by_name(p.name, userdb_flags, &g); else { _cleanup_(userdb_iterator_freep) UserDBIterator *iterator = NULL; _cleanup_(sd_json_variant_unrefp) sd_json_variant *last = NULL; @@ -345,7 +344,7 @@ static int vl_method_get_group_record(sd_varlink *link, sd_json_variant *paramet } if ((uid_is_valid(p.gid) && g->gid != p.gid) || - (p.group_name && !group_record_matches_group_name(g, p.group_name))) + (p.name && !group_record_matches_group_name(g, p.name))) return sd_varlink_error(link, "io.systemd.UserDatabase.ConflictingRecordFound", NULL); r = build_group_json(link, g, &v); @@ -355,17 +354,23 @@ static int vl_method_get_group_record(sd_varlink *link, sd_json_variant *paramet return sd_varlink_reply(link, v); } +typedef struct MembershipLookupParameters { + const char *user_name; + const char *group_name; + const char *service; +} MembershipLookupParameters; + static int vl_method_get_memberships(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) { static const sd_json_dispatch_field dispatch_table[] = { - { "userName", SD_JSON_VARIANT_STRING, json_dispatch_const_user_group_name, offsetof(LookupParameters, user_name), SD_JSON_RELAX }, - { "groupName", SD_JSON_VARIANT_STRING, json_dispatch_const_user_group_name, offsetof(LookupParameters, group_name), SD_JSON_RELAX }, - { "service", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(LookupParameters, service), 0 }, + { "userName", SD_JSON_VARIANT_STRING, json_dispatch_const_user_group_name, offsetof(MembershipLookupParameters, user_name), SD_JSON_RELAX }, + { "groupName", SD_JSON_VARIANT_STRING, json_dispatch_const_user_group_name, offsetof(MembershipLookupParameters, group_name), SD_JSON_RELAX }, + { "service", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(MembershipLookupParameters, service), 0 }, {} }; _cleanup_free_ char *last_user_name = NULL, *last_group_name = NULL; _cleanup_(userdb_iterator_freep) UserDBIterator *iterator = NULL; - LookupParameters p = {}; + MembershipLookupParameters p = {}; UserDBFlags userdb_flags; int r; From 6a43f0a73c33cb417a218de89858fde006214db7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 22 Jan 2025 16:34:16 +0100 Subject: [PATCH 2/3] userdb: move setting of 'service' varlink parameter into userdb_connect() We currently set this at two distinct places right before calling userdb_connect(). let's do this inside of userdb_connect() instead, and derive it directly from the socket path. This doesn't change behaviour but simplifies things a bit. --- src/shared/userdb.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/shared/userdb.c b/src/shared/userdb.c index a1da514884..32f851b0f3 100644 --- a/src/shared/userdb.c +++ b/src/shared/userdb.c @@ -384,10 +384,21 @@ static int userdb_connect( if (r < 0) return log_debug_errno(r, "Failed to bind reply callback: %m"); + _cleanup_free_ char *service = NULL; + r = path_extract_filename(path, &service); + if (r < 0) + return log_debug_errno(r, "Failed to extract service name from socket path: %m"); + assert(r != O_DIRECTORY); + + _cleanup_(sd_json_variant_unrefp) sd_json_variant *patched_query = sd_json_variant_ref(query); + r = sd_json_variant_set_field_string(&patched_query, "service", service); + if (r < 0) + return log_debug_errno(r, "Unable to set service JSON field: %m"); + if (more) - r = sd_varlink_observe(vl, method, query); + r = sd_varlink_observe(vl, method, patched_query); else - r = sd_varlink_invoke(vl, method, query); + r = sd_varlink_invoke(vl, method, patched_query); if (r < 0) return log_debug_errno(r, "Failed to invoke varlink method: %m"); @@ -438,13 +449,7 @@ static int userdb_start_query( if ((flags & (USERDB_AVOID_MULTIPLEXER|USERDB_EXCLUDE_DYNAMIC_USER|USERDB_EXCLUDE_NSS|USERDB_EXCLUDE_DROPIN|USERDB_DONT_SYNTHESIZE_INTRINSIC|USERDB_DONT_SYNTHESIZE_FOREIGN)) == 0 && !strv_contains(except, "io.systemd.Multiplexer") && (!only || strv_contains(only, "io.systemd.Multiplexer"))) { - _cleanup_(sd_json_variant_unrefp) sd_json_variant *patched_query = sd_json_variant_ref(query); - - r = sd_json_variant_set_field_string(&patched_query, "service", "io.systemd.Multiplexer"); - if (r < 0) - return log_debug_errno(r, "Unable to set service JSON field: %m"); - - r = userdb_connect(iterator, "/run/systemd/userdb/io.systemd.Multiplexer", method, more, patched_query); + r = userdb_connect(iterator, "/run/systemd/userdb/io.systemd.Multiplexer", method, more, query); if (r >= 0) { iterator->nss_covered = true; /* The multiplexer does NSS */ iterator->dropin_covered = true; /* It also handles drop-in stuff */ @@ -461,7 +466,6 @@ static int userdb_start_query( } FOREACH_DIRENT(de, d, return -errno) { - _cleanup_(sd_json_variant_unrefp) sd_json_variant *patched_query = NULL; _cleanup_free_ char *p = NULL; bool is_nss, is_dropin; @@ -495,12 +499,7 @@ static int userdb_start_query( if (!p) return -ENOMEM; - patched_query = sd_json_variant_ref(query); - r = sd_json_variant_set_field_string(&patched_query, "service", de->d_name); - if (r < 0) - return log_debug_errno(r, "Unable to set service JSON field: %m"); - - r = userdb_connect(iterator, p, method, more, patched_query); + r = userdb_connect(iterator, p, method, more, query); if (is_nss && r >= 0) /* Turn off fallback NSS + dropin if we found the NSS/dropin service * and could connect to it */ iterator->nss_covered = true; From 83eabe102a91d4c4ac0080c31252cd60476af7ca Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 22 Jan 2025 16:24:17 +0100 Subject: [PATCH 3/3] user-record: make a NULL UserDBMatch be equivalent to no filtering --- src/shared/group-record.c | 4 +++- src/shared/user-record.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/shared/group-record.c b/src/shared/group-record.c index 3aa2665718..6d696bdaaa 100644 --- a/src/shared/group-record.c +++ b/src/shared/group-record.c @@ -346,7 +346,9 @@ bool group_record_matches_group_name(const GroupRecord *g, const char *group_nam int group_record_match(GroupRecord *h, const UserDBMatch *match) { assert(h); - assert(match); + + if (!match) + return true; if (h->gid < match->gid_min || h->gid > match->gid_max) return false; diff --git a/src/shared/user-record.c b/src/shared/user-record.c index 9feac30933..ebdbb28065 100644 --- a/src/shared/user-record.c +++ b/src/shared/user-record.c @@ -2694,7 +2694,9 @@ bool user_name_fuzzy_match(const char *names[], size_t n_names, char **matches) int user_record_match(UserRecord *u, const UserDBMatch *match) { assert(u); - assert(match); + + if (!match) + return true; if (u->uid < match->uid_min || u->uid > match->uid_max) return false;