From 134ff8f4d1bbfe189957fb9418d88392ab315867 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 6 May 2021 16:01:44 +0200 Subject: [PATCH] userdbd: simplify logic for generating NSS listings So far we basically had two ways to iterate through NSS records: one via the varlink IPC and one via the userdb.[ch] infra, with slightly different implementations. Let's clean this up, and always use userdb.[ch] also when resolving via userdbd. The different codepaths for the NameServiceSwitch and the Multiplexer varlink service now differ only in the different flags passed to the userdb lookup. Behaviour shouldn't change by this. This is mostly refactoring, reducing redundant codepaths. --- src/shared/userdb.h | 3 + src/userdb/userwork.c | 441 +++++++++++------------------------------- 2 files changed, 119 insertions(+), 325 deletions(-) diff --git a/src/shared/userdb.h b/src/shared/userdb.h index f0a31967959..d69c6db0340 100644 --- a/src/shared/userdb.h +++ b/src/shared/userdb.h @@ -24,6 +24,9 @@ typedef enum UserDBFlags { USERDB_EXCLUDE_DYNAMIC_USER = 1 << 4, /* exclude looking up in io.systemd.DynamicUser */ USERDB_AVOID_MULTIPLEXER = 1 << 5, /* exclude looking up via io.systemd.Multiplexer */ USERDB_DONT_SYNTHESIZE = 1 << 6, /* don't synthesize root/nobody */ + + /* Combinations */ + USERDB_NSS_ONLY = USERDB_EXCLUDE_VARLINK|USERDB_DONT_SYNTHESIZE, } UserDBFlags; int userdb_by_name(const char *name, UserDBFlags flags, UserRecord **ret); diff --git a/src/userdb/userwork.c b/src/userdb/userwork.c index c62a21974a1..71251ccf1d1 100644 --- a/src/userdb/userwork.c +++ b/src/userdb/userwork.c @@ -113,6 +113,21 @@ static int build_user_json(Varlink *link, UserRecord *ur, JsonVariant **ret) { JSON_BUILD_PAIR("incomplete", JSON_BUILD_BOOLEAN(stripped->incomplete)))); } +static int userdb_flags_from_service(Varlink *link, const char *service, UserDBFlags *ret) { + assert(link); + assert(service); + assert(ret); + + if (streq_ptr(service, "io.systemd.NameServiceSwitch")) + *ret = USERDB_NSS_ONLY|USERDB_AVOID_MULTIPLEXER; + else if (streq_ptr(service, "io.systemd.Multiplexer")) + *ret = USERDB_AVOID_MULTIPLEXER; + else + return varlink_error(link, "io.systemd.UserDatabase.BadService", NULL); + + return 0; +} + static int vl_method_get_user_record(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) { static const JsonDispatch dispatch_table[] = { @@ -127,6 +142,7 @@ static int vl_method_get_user_record(Varlink *link, JsonVariant *parameters, Var LookupParameters p = { .uid = UID_INVALID, }; + UserDBFlags userdb_flags; int r; assert(parameters); @@ -135,109 +151,49 @@ static int vl_method_get_user_record(Varlink *link, JsonVariant *parameters, Var if (r < 0) return r; - if (streq_ptr(p.service, "io.systemd.NameServiceSwitch")) { - if (uid_is_valid(p.uid)) - r = nss_user_record_by_uid(p.uid, true, &hr); - else if (p.user_name) - r = nss_user_record_by_name(p.user_name, true, &hr); - else { - _cleanup_(json_variant_unrefp) JsonVariant *last = NULL; + r = userdb_flags_from_service(link, p.service, &userdb_flags); + if (r < 0) + return r; - setpwent(); + 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 { + _cleanup_(userdb_iterator_freep) UserDBIterator *iterator = NULL; + _cleanup_(json_variant_unrefp) JsonVariant *last = NULL; - for (;;) { - _cleanup_(user_record_unrefp) UserRecord *z = NULL; - _cleanup_free_ char *sbuf = NULL; - struct passwd *pw; - struct spwd spwd; + r = userdb_all(userdb_flags, &iterator); + if (r < 0) + return r; - errno = 0; - pw = getpwent(); - if (!pw) { - if (errno != 0) - log_debug_errno(errno, "Failure while iterating through NSS user database, ignoring: %m"); + for (;;) { + _cleanup_(user_record_unrefp) UserRecord *z = NULL; - break; - } + r = userdb_iterator_get(iterator, &z); + if (r == -ESRCH) + break; + if (r < 0) + return r; - r = nss_spwd_for_passwd(pw, &spwd, &sbuf); + if (last) { + r = varlink_notify(link, last); if (r < 0) - log_debug_errno(r, "Failed to acquire shadow entry for user %s, ignoring: %m", pw->pw_name); - - r = nss_passwd_to_user_record(pw, NULL, &z); - if (r < 0) { - endpwent(); return r; - } - - if (last) { - r = varlink_notify(link, last); - if (r < 0) { - endpwent(); - return r; - } - last = json_variant_unref(last); - } - - r = build_user_json(link, z, &last); - if (r < 0) { - endpwent(); - return r; - } + last = json_variant_unref(last); } - endpwent(); - - if (!last) - return varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL); - - return varlink_reply(link, last); - } - - } else if (streq_ptr(p.service, "io.systemd.Multiplexer")) { - - if (uid_is_valid(p.uid)) - r = userdb_by_uid(p.uid, USERDB_AVOID_MULTIPLEXER, &hr); - else if (p.user_name) - r = userdb_by_name(p.user_name, USERDB_AVOID_MULTIPLEXER, &hr); - else { - _cleanup_(userdb_iterator_freep) UserDBIterator *iterator = NULL; - _cleanup_(json_variant_unrefp) JsonVariant *last = NULL; - - r = userdb_all(USERDB_AVOID_MULTIPLEXER, &iterator); + r = build_user_json(link, z, &last); if (r < 0) return r; + } - for (;;) { - _cleanup_(user_record_unrefp) UserRecord *z = NULL; - - r = userdb_iterator_get(iterator, &z); - if (r == -ESRCH) - break; - if (r < 0) - return r; - - if (last) { - r = varlink_notify(link, last); - if (r < 0) - return r; - - last = json_variant_unref(last); - } - - r = build_user_json(link, z, &last); - if (r < 0) - return r; - } - - if (!last) - return varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL); + if (!last) + return varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL); - return varlink_reply(link, last); - } - } else - return varlink_error(link, "io.systemd.UserDatabase.BadService", NULL); + return varlink_reply(link, last); + } if (r == -ESRCH) return varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL); if (r < 0) { @@ -313,6 +269,7 @@ static int vl_method_get_group_record(Varlink *link, JsonVariant *parameters, Va LookupParameters p = { .gid = GID_INVALID, }; + UserDBFlags userdb_flags; int r; assert(parameters); @@ -321,110 +278,49 @@ static int vl_method_get_group_record(Varlink *link, JsonVariant *parameters, Va if (r < 0) return r; - if (streq_ptr(p.service, "io.systemd.NameServiceSwitch")) { - - if (gid_is_valid(p.gid)) - r = nss_group_record_by_gid(p.gid, true, &g); - else if (p.group_name) - r = nss_group_record_by_name(p.group_name, true, &g); - else { - _cleanup_(json_variant_unrefp) JsonVariant *last = NULL; + r = userdb_flags_from_service(link, p.service, &userdb_flags); + if (r < 0) + return r; - setgrent(); + 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 { + _cleanup_(userdb_iterator_freep) UserDBIterator *iterator = NULL; + _cleanup_(json_variant_unrefp) JsonVariant *last = NULL; - for (;;) { - _cleanup_(group_record_unrefp) GroupRecord *z = NULL; - _cleanup_free_ char *sbuf = NULL; - struct group *grp; - struct sgrp sgrp; + r = groupdb_all(userdb_flags, &iterator); + if (r < 0) + return r; - errno = 0; - grp = getgrent(); - if (!grp) { - if (errno != 0) - log_debug_errno(errno, "Failure while iterating through NSS group database, ignoring: %m"); + for (;;) { + _cleanup_(group_record_unrefp) GroupRecord *z = NULL; - break; - } + r = groupdb_iterator_get(iterator, &z); + if (r == -ESRCH) + break; + if (r < 0) + return r; - r = nss_sgrp_for_group(grp, &sgrp, &sbuf); + if (last) { + r = varlink_notify(link, last); if (r < 0) - log_debug_errno(r, "Failed to acquire shadow entry for group %s, ignoring: %m", grp->gr_name); - - r = nss_group_to_group_record(grp, r >= 0 ? &sgrp : NULL, &z); - if (r < 0) { - endgrent(); return r; - } - if (last) { - r = varlink_notify(link, last); - if (r < 0) { - endgrent(); - return r; - } - - last = json_variant_unref(last); - } - - r = build_group_json(link, z, &last); - if (r < 0) { - endgrent(); - return r; - } + last = json_variant_unref(last); } - endgrent(); - - if (!last) - return varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL); - - return varlink_reply(link, last); - } - - } else if (streq_ptr(p.service, "io.systemd.Multiplexer")) { - - if (gid_is_valid(p.gid)) - r = groupdb_by_gid(p.gid, USERDB_AVOID_MULTIPLEXER, &g); - else if (p.group_name) - r = groupdb_by_name(p.group_name, USERDB_AVOID_MULTIPLEXER, &g); - else { - _cleanup_(userdb_iterator_freep) UserDBIterator *iterator = NULL; - _cleanup_(json_variant_unrefp) JsonVariant *last = NULL; - - r = groupdb_all(USERDB_AVOID_MULTIPLEXER, &iterator); + r = build_group_json(link, z, &last); if (r < 0) return r; + } - for (;;) { - _cleanup_(group_record_unrefp) GroupRecord *z = NULL; - - r = groupdb_iterator_get(iterator, &z); - if (r == -ESRCH) - break; - if (r < 0) - return r; - - if (last) { - r = varlink_notify(link, last); - if (r < 0) - return r; - - last = json_variant_unref(last); - } - - r = build_group_json(link, z, &last); - if (r < 0) - return r; - } - - if (!last) - return varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL); + if (!last) + return varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL); - return varlink_reply(link, last); - } - } else - return varlink_error(link, "io.systemd.UserDatabase.BadService", NULL); + return varlink_reply(link, last); + } if (r == -ESRCH) return varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL); if (r < 0) { @@ -451,7 +347,10 @@ static int vl_method_get_memberships(Varlink *link, JsonVariant *parameters, Var {} }; + _cleanup_free_ char *last_user_name = NULL, *last_group_name = NULL; + _cleanup_(userdb_iterator_freep) UserDBIterator *iterator = NULL; LookupParameters p = {}; + UserDBFlags userdb_flags; int r; assert(parameters); @@ -460,167 +359,59 @@ static int vl_method_get_memberships(Varlink *link, JsonVariant *parameters, Var if (r < 0) return r; - if (streq_ptr(p.service, "io.systemd.NameServiceSwitch")) { - - if (p.group_name) { - _cleanup_(group_record_unrefp) GroupRecord *g = NULL; - const char *last = NULL; - char **i; - - r = nss_group_record_by_name(p.group_name, true, &g); - if (r == -ESRCH) - return varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL); - if (r < 0) - return r; - - STRV_FOREACH(i, g->members) { - - if (p.user_name && !streq_ptr(p.user_name, *i)) - continue; - - if (last) { - r = varlink_notifyb(link, JSON_BUILD_OBJECT( - JSON_BUILD_PAIR("userName", JSON_BUILD_STRING(last)), - JSON_BUILD_PAIR("groupName", JSON_BUILD_STRING(g->group_name)))); - if (r < 0) - return r; - } - - last = *i; - } - - if (!last) - return varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL); - - return varlink_replyb(link, JSON_BUILD_OBJECT( - JSON_BUILD_PAIR("userName", JSON_BUILD_STRING(last)), - JSON_BUILD_PAIR("groupName", JSON_BUILD_STRING(g->group_name)))); - } else { - _cleanup_free_ char *last_user_name = NULL, *last_group_name = NULL; - - setgrent(); - - for (;;) { - struct group *grp; - const char* two[2], **users, **i; - - errno = 0; - grp = getgrent(); - if (!grp) { - if (errno != 0) - log_debug_errno(errno, "Failure while iterating through NSS group database, ignoring: %m"); - - break; - } - - if (p.user_name) { - if (!strv_contains(grp->gr_mem, p.user_name)) - continue; - - two[0] = p.user_name; - two[1] = NULL; - - users = two; - } else - users = (const char**) grp->gr_mem; - - STRV_FOREACH(i, users) { - - if (last_user_name) { - assert(last_group_name); - - r = varlink_notifyb(link, JSON_BUILD_OBJECT( - JSON_BUILD_PAIR("userName", JSON_BUILD_STRING(last_user_name)), - JSON_BUILD_PAIR("groupName", JSON_BUILD_STRING(last_group_name)))); - if (r < 0) { - endgrent(); - return r; - } - - free(last_user_name); - free(last_group_name); - } - - last_user_name = strdup(*i); - last_group_name = strdup(grp->gr_name); - if (!last_user_name || !last_group_name) { - endgrent(); - return -ENOMEM; - } - } - } - - endgrent(); - - if (!last_user_name) { - assert(!last_group_name); - return varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL); - } - - assert(last_group_name); - - return varlink_replyb(link, JSON_BUILD_OBJECT( - JSON_BUILD_PAIR("userName", JSON_BUILD_STRING(last_user_name)), - JSON_BUILD_PAIR("groupName", JSON_BUILD_STRING(last_group_name)))); - } + r = userdb_flags_from_service(link, p.service, &userdb_flags); + if (r < 0) + return r; - } else if (streq_ptr(p.service, "io.systemd.Multiplexer")) { + if (p.group_name) + r = membershipdb_by_group(p.group_name, userdb_flags, &iterator); + else if (p.user_name) + r = membershipdb_by_user(p.user_name, userdb_flags, &iterator); + else + r = membershipdb_all(userdb_flags, &iterator); + if (r < 0) + return r; - _cleanup_free_ char *last_user_name = NULL, *last_group_name = NULL; - _cleanup_(userdb_iterator_freep) UserDBIterator *iterator = NULL; + for (;;) { + _cleanup_free_ char *user_name = NULL, *group_name = NULL; - if (p.group_name) - r = membershipdb_by_group(p.group_name, USERDB_AVOID_MULTIPLEXER, &iterator); - else if (p.user_name) - r = membershipdb_by_user(p.user_name, USERDB_AVOID_MULTIPLEXER, &iterator); - else - r = membershipdb_all(USERDB_AVOID_MULTIPLEXER, &iterator); + r = membershipdb_iterator_get(iterator, &user_name, &group_name); + if (r == -ESRCH) + break; if (r < 0) return r; - for (;;) { - _cleanup_free_ char *user_name = NULL, *group_name = NULL; + /* If both group + user are specified do a-posteriori filtering */ + if (p.group_name && p.user_name && !streq(group_name, p.group_name)) + continue; - r = membershipdb_iterator_get(iterator, &user_name, &group_name); - if (r == -ESRCH) - break; + if (last_user_name) { + assert(last_group_name); + + r = varlink_notifyb(link, JSON_BUILD_OBJECT( + JSON_BUILD_PAIR("userName", JSON_BUILD_STRING(last_user_name)), + JSON_BUILD_PAIR("groupName", JSON_BUILD_STRING(last_group_name)))); if (r < 0) return r; - /* If both group + user are specified do a-posteriori filtering */ - if (p.group_name && p.user_name && !streq(group_name, p.group_name)) - continue; - - if (last_user_name) { - assert(last_group_name); - - r = varlink_notifyb(link, JSON_BUILD_OBJECT( - JSON_BUILD_PAIR("userName", JSON_BUILD_STRING(last_user_name)), - JSON_BUILD_PAIR("groupName", JSON_BUILD_STRING(last_group_name)))); - if (r < 0) - return r; - - free(last_user_name); - free(last_group_name); - } - - last_user_name = TAKE_PTR(user_name); - last_group_name = TAKE_PTR(group_name); - } - - if (!last_user_name) { - assert(!last_group_name); - return varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL); + free(last_user_name); + free(last_group_name); } - assert(last_group_name); + last_user_name = TAKE_PTR(user_name); + last_group_name = TAKE_PTR(group_name); + } - return varlink_replyb(link, JSON_BUILD_OBJECT( - JSON_BUILD_PAIR("userName", JSON_BUILD_STRING(last_user_name)), - JSON_BUILD_PAIR("groupName", JSON_BUILD_STRING(last_group_name)))); + if (!last_user_name) { + assert(!last_group_name); + return varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL); } - return varlink_error(link, "io.systemd.UserDatabase.BadService", NULL); + assert(last_group_name); + + return varlink_replyb(link, JSON_BUILD_OBJECT( + JSON_BUILD_PAIR("userName", JSON_BUILD_STRING(last_user_name)), + JSON_BUILD_PAIR("groupName", JSON_BUILD_STRING(last_group_name)))); } static int process_connection(VarlinkServer *server, int fd) { -- 2.47.3