From 80d88a8267401387645166c22724e2ad912fade4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 6 May 2021 15:46:30 +0200 Subject: [PATCH 1/3] userdb: rename userdb lookup flags a bit Let's use "exclude" for flags that really exclude records from our lookup. Let's use "avoid" referring to concepts that when flag is set we'll not use but we have a fallback path for that should yield the same result. Let' use "suppress" for suppressing partial info, even if we return the record otherwise. So far we used "avoid" for all these cases, which was confusing. Whiel we are at it, let's reassign the bits a bit, leaving some space for bits follow-up commits are going to add. --- src/login/logind-core.c | 4 ++-- src/nss-systemd/nss-systemd.c | 2 +- src/nss-systemd/userdb-glue.c | 4 ++-- src/shared/userdb.c | 36 +++++++++++++++++------------------ src/shared/userdb.h | 13 ++++++++----- src/userdb/userdbctl.c | 4 ++-- 6 files changed, 33 insertions(+), 30 deletions(-) diff --git a/src/login/logind-core.c b/src/login/logind-core.c index cd3a3742012..22031f485a0 100644 --- a/src/login/logind-core.c +++ b/src/login/logind-core.c @@ -176,7 +176,7 @@ int manager_add_user_by_name( assert(m); assert(name); - r = userdb_by_name(name, USERDB_AVOID_SHADOW, &ur); + r = userdb_by_name(name, USERDB_SUPPRESS_SHADOW, &ur); if (r < 0) return r; @@ -194,7 +194,7 @@ int manager_add_user_by_uid( assert(m); assert(uid_is_valid(uid)); - r = userdb_by_uid(uid, USERDB_AVOID_SHADOW, &ur); + r = userdb_by_uid(uid, USERDB_SUPPRESS_SHADOW, &ur); if (r < 0) return r; diff --git a/src/nss-systemd/nss-systemd.c b/src/nss-systemd/nss-systemd.c index 5592eaa3aa4..14712f8735d 100644 --- a/src/nss-systemd/nss-systemd.c +++ b/src/nss-systemd/nss-systemd.c @@ -582,7 +582,7 @@ enum nss_status _nss_systemd_initgroups_dyn( /* The group might be defined via traditional NSS only, hence let's do a full look-up without * disabling NSS. This means we are operating recursively here. */ - r = groupdb_by_name(group_name, (nss_glue_userdb_flags() & ~USERDB_AVOID_NSS) | USERDB_AVOID_SHADOW, &g); + r = groupdb_by_name(group_name, (nss_glue_userdb_flags() & ~USERDB_EXCLUDE_NSS) | USERDB_SUPPRESS_SHADOW, &g); if (r == -ESRCH) continue; if (r < 0) { diff --git a/src/nss-systemd/userdb-glue.c b/src/nss-systemd/userdb-glue.c index 8f8988579b8..73941b2ba56 100644 --- a/src/nss-systemd/userdb-glue.c +++ b/src/nss-systemd/userdb-glue.c @@ -11,11 +11,11 @@ #include "userdb.h" UserDBFlags nss_glue_userdb_flags(void) { - UserDBFlags flags = USERDB_AVOID_NSS; + UserDBFlags flags = USERDB_EXCLUDE_NSS; /* Make sure that we don't go in circles when allocating a dynamic UID by checking our own database */ if (getenv_bool_secure("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0) - flags |= USERDB_AVOID_DYNAMIC_USER; + flags |= USERDB_EXCLUDE_DYNAMIC_USER; return flags; } diff --git a/src/shared/userdb.c b/src/shared/userdb.c index e4a04123c0e..d856625dd3a 100644 --- a/src/shared/userdb.c +++ b/src/shared/userdb.c @@ -422,7 +422,7 @@ static int userdb_start_query( } /* First, let's talk to the multiplexer, if we can */ - if ((flags & (USERDB_AVOID_MULTIPLEXER|USERDB_AVOID_DYNAMIC_USER|USERDB_AVOID_NSS|USERDB_DONT_SYNTHESIZE)) == 0 && + if ((flags & (USERDB_AVOID_MULTIPLEXER|USERDB_EXCLUDE_DYNAMIC_USER|USERDB_EXCLUDE_NSS|USERDB_DONT_SYNTHESIZE)) == 0 && !strv_contains(except, "io.systemd.Multiplexer") && (!only || strv_contains(only, "io.systemd.Multiplexer"))) { _cleanup_(json_variant_unrefp) JsonVariant *patched_query = json_variant_ref(query); @@ -454,7 +454,7 @@ static int userdb_start_query( if (streq(de->d_name, "io.systemd.Multiplexer")) /* We already tried this above, don't try this again */ continue; - if (FLAGS_SET(flags, USERDB_AVOID_DYNAMIC_USER) && + if (FLAGS_SET(flags, USERDB_EXCLUDE_DYNAMIC_USER) && streq(de->d_name, "io.systemd.DynamicUser")) continue; @@ -463,7 +463,7 @@ static int userdb_start_query( * (and when we run as part of systemd-userdbd.service we don't want to talk to ourselves * anyway). */ is_nss = streq(de->d_name, "io.systemd.NameServiceSwitch"); - if ((flags & (USERDB_AVOID_NSS|USERDB_AVOID_MULTIPLEXER)) && is_nss) + if ((flags & (USERDB_EXCLUDE_NSS|USERDB_AVOID_MULTIPLEXER)) && is_nss) continue; if (strv_contains(except, de->d_name)) @@ -621,13 +621,13 @@ int userdb_by_name(const char *name, UserDBFlags flags, UserRecord **ret) { return r; } - if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !iterator->nss_covered) { + if (!FLAGS_SET(flags, USERDB_EXCLUDE_NSS) && !iterator->nss_covered) { /* Make sure the NSS lookup doesn't recurse back to us. */ r = userdb_iterator_block_nss_systemd(iterator); if (r >= 0) { /* Client-side NSS fallback */ - r = nss_user_record_by_name(name, !FLAGS_SET(flags, USERDB_AVOID_SHADOW), ret); + r = nss_user_record_by_name(name, !FLAGS_SET(flags, USERDB_SUPPRESS_SHADOW), ret); if (r >= 0) return r; } @@ -668,11 +668,11 @@ int userdb_by_uid(uid_t uid, UserDBFlags flags, UserRecord **ret) { return r; } - if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !iterator->nss_covered) { + if (!FLAGS_SET(flags, USERDB_EXCLUDE_NSS) && !iterator->nss_covered) { r = userdb_iterator_block_nss_systemd(iterator); if (r >= 0) { /* Client-side NSS fallback */ - r = nss_user_record_by_uid(uid, !FLAGS_SET(flags, USERDB_AVOID_SHADOW), ret); + r = nss_user_record_by_uid(uid, !FLAGS_SET(flags, USERDB_SUPPRESS_SHADOW), ret); if (r >= 0) return r; } @@ -703,7 +703,7 @@ int userdb_all(UserDBFlags flags, UserDBIterator **ret) { r = userdb_start_query(iterator, "io.systemd.UserDatabase.GetUserRecord", true, NULL, flags); - if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && (r < 0 || !iterator->nss_covered)) { + if (!FLAGS_SET(flags, USERDB_EXCLUDE_NSS) && (r < 0 || !iterator->nss_covered)) { r = userdb_iterator_block_nss_systemd(iterator); if (r < 0) return r; @@ -740,7 +740,7 @@ int userdb_iterator_get(UserDBIterator *iterator, UserRecord **ret) { if (pw->pw_uid == UID_NOBODY) iterator->synthesize_nobody = false; - if (!FLAGS_SET(iterator->flags, USERDB_AVOID_SHADOW)) { + if (!FLAGS_SET(iterator->flags, USERDB_SUPPRESS_SHADOW)) { r = nss_spwd_for_passwd(pw, &spwd, &buffer); if (r < 0) { log_debug_errno(r, "Failed to acquire shadow entry for user %s, ignoring: %m", pw->pw_name); @@ -832,10 +832,10 @@ int groupdb_by_name(const char *name, UserDBFlags flags, GroupRecord **ret) { return r; } - if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !(iterator && iterator->nss_covered)) { + if (!FLAGS_SET(flags, USERDB_EXCLUDE_NSS) && !(iterator && iterator->nss_covered)) { r = userdb_iterator_block_nss_systemd(iterator); if (r >= 0) { - r = nss_group_record_by_name(name, !FLAGS_SET(flags, USERDB_AVOID_SHADOW), ret); + r = nss_group_record_by_name(name, !FLAGS_SET(flags, USERDB_SUPPRESS_SHADOW), ret); if (r >= 0) return r; } @@ -876,10 +876,10 @@ int groupdb_by_gid(gid_t gid, UserDBFlags flags, GroupRecord **ret) { return r; } - if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !(iterator && iterator->nss_covered)) { + if (!FLAGS_SET(flags, USERDB_EXCLUDE_NSS) && !(iterator && iterator->nss_covered)) { r = userdb_iterator_block_nss_systemd(iterator); if (r >= 0) { - r = nss_group_record_by_gid(gid, !FLAGS_SET(flags, USERDB_AVOID_SHADOW), ret); + r = nss_group_record_by_gid(gid, !FLAGS_SET(flags, USERDB_SUPPRESS_SHADOW), ret); if (r >= 0) return r; } @@ -910,7 +910,7 @@ int groupdb_all(UserDBFlags flags, UserDBIterator **ret) { r = userdb_start_query(iterator, "io.systemd.UserDatabase.GetGroupRecord", true, NULL, flags); - if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && (r < 0 || !iterator->nss_covered)) { + if (!FLAGS_SET(flags, USERDB_EXCLUDE_NSS) && (r < 0 || !iterator->nss_covered)) { r = userdb_iterator_block_nss_systemd(iterator); if (r < 0) return r; @@ -945,7 +945,7 @@ int groupdb_iterator_get(UserDBIterator *iterator, GroupRecord **ret) { if (gr->gr_gid == GID_NOBODY) iterator->synthesize_nobody = false; - if (!FLAGS_SET(iterator->flags, USERDB_AVOID_SHADOW)) { + if (!FLAGS_SET(iterator->flags, USERDB_SUPPRESS_SHADOW)) { r = nss_sgrp_for_group(gr, &sgrp, &buffer); if (r < 0) { log_debug_errno(r, "Failed to acquire shadow entry for group %s, ignoring: %m", gr->gr_name); @@ -1016,7 +1016,7 @@ int membershipdb_by_user(const char *name, UserDBFlags flags, UserDBIterator **r return -ENOMEM; r = userdb_start_query(iterator, "io.systemd.UserDatabase.GetMemberships", true, query, flags); - if ((r >= 0 && iterator->nss_covered) || FLAGS_SET(flags, USERDB_AVOID_NSS)) + if ((r >= 0 && iterator->nss_covered) || FLAGS_SET(flags, USERDB_EXCLUDE_NSS)) goto finish; r = userdb_iterator_block_nss_systemd(iterator); @@ -1059,7 +1059,7 @@ int membershipdb_by_group(const char *name, UserDBFlags flags, UserDBIterator ** return -ENOMEM; r = userdb_start_query(iterator, "io.systemd.UserDatabase.GetMemberships", true, query, flags); - if ((r >= 0 && iterator->nss_covered) || FLAGS_SET(flags, USERDB_AVOID_NSS)) + if ((r >= 0 && iterator->nss_covered) || FLAGS_SET(flags, USERDB_EXCLUDE_NSS)) goto finish; r = userdb_iterator_block_nss_systemd(iterator); @@ -1100,7 +1100,7 @@ int membershipdb_all(UserDBFlags flags, UserDBIterator **ret) { return -ENOMEM; r = userdb_start_query(iterator, "io.systemd.UserDatabase.GetMemberships", true, NULL, flags); - if ((r >= 0 && iterator->nss_covered) || FLAGS_SET(flags, USERDB_AVOID_NSS)) + if ((r >= 0 && iterator->nss_covered) || FLAGS_SET(flags, USERDB_EXCLUDE_NSS)) goto finish; r = userdb_iterator_block_nss_systemd(iterator); diff --git a/src/shared/userdb.h b/src/shared/userdb.h index ee207b518ed..055cf627a48 100644 --- a/src/shared/userdb.h +++ b/src/shared/userdb.h @@ -15,11 +15,14 @@ UserDBIterator *userdb_iterator_free(UserDBIterator *iterator); DEFINE_TRIVIAL_CLEANUP_FUNC(UserDBIterator*, userdb_iterator_free); typedef enum UserDBFlags { - USERDB_AVOID_NSS = 1 << 0, /* don't do client-side nor server-side NSS */ - USERDB_AVOID_SHADOW = 1 << 1, /* don't do client-side shadow calls (server side might happen though) */ - USERDB_AVOID_DYNAMIC_USER = 1 << 2, /* exclude looking up in io.systemd.DynamicUser */ - USERDB_AVOID_MULTIPLEXER = 1 << 3, /* exclude looking up via io.systemd.Multiplexer */ - USERDB_DONT_SYNTHESIZE = 1 << 4, /* don't synthesize root/nobody */ + /* The main sources */ + USERDB_EXCLUDE_NSS = 1 << 0, /* don't do client-side nor server-side NSS */ + + /* Modifications */ + USERDB_SUPPRESS_SHADOW = 1 << 3, /* don't do client-side shadow calls (server side might happen though) */ + 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 */ } UserDBFlags; int userdb_by_name(const char *name, UserDBFlags flags, UserRecord **ret); diff --git a/src/userdb/userdbctl.c b/src/userdb/userdbctl.c index e9c6957143a..56511eae447 100644 --- a/src/userdb/userdbctl.c +++ b/src/userdb/userdbctl.c @@ -717,7 +717,7 @@ static int parse_argv(int argc, char *argv[]) { break; case 'N': - arg_userdb_flags |= USERDB_AVOID_NSS|USERDB_DONT_SYNTHESIZE; + arg_userdb_flags |= USERDB_EXCLUDE_NSS|USERDB_DONT_SYNTHESIZE; break; case ARG_WITH_NSS: @@ -725,7 +725,7 @@ static int parse_argv(int argc, char *argv[]) { if (r < 0) return r; - SET_FLAG(arg_userdb_flags, USERDB_AVOID_NSS, !r); + SET_FLAG(arg_userdb_flags, USERDB_EXCLUDE_NSS, !r); break; case ARG_SYNTHESIZE: From b214825433ba716ec87a0cafb8cbf9870efc21c1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 6 May 2021 15:51:30 +0200 Subject: [PATCH 2/3] userdb: add new flag for excluding varlink data in lookups This is useful to later-on use the userdb infra for only some sources. --- src/shared/userdb.c | 3 +++ src/shared/userdb.h | 1 + 2 files changed, 4 insertions(+) diff --git a/src/shared/userdb.c b/src/shared/userdb.c index d856625dd3a..caef7cdf063 100644 --- a/src/shared/userdb.c +++ b/src/shared/userdb.c @@ -402,6 +402,9 @@ static int userdb_start_query( assert(iterator); assert(method); + if (FLAGS_SET(flags, USERDB_EXCLUDE_VARLINK)) + return -ENOLINK; + e = getenv("SYSTEMD_BYPASS_USERDB"); if (e) { r = parse_boolean(e); diff --git a/src/shared/userdb.h b/src/shared/userdb.h index 055cf627a48..f0a31967959 100644 --- a/src/shared/userdb.h +++ b/src/shared/userdb.h @@ -17,6 +17,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(UserDBIterator*, userdb_iterator_free); typedef enum UserDBFlags { /* The main sources */ USERDB_EXCLUDE_NSS = 1 << 0, /* don't do client-side nor server-side NSS */ + USERDB_EXCLUDE_VARLINK = 1 << 1, /* don't talk to any varlink services */ /* Modifications */ USERDB_SUPPRESS_SHADOW = 1 << 3, /* don't do client-side shadow calls (server side might happen though) */ From 134ff8f4d1bbfe189957fb9418d88392ab315867 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 6 May 2021 16:01:44 +0200 Subject: [PATCH 3/3] 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 | 447 +++++++++++------------------------------- 2 files changed, 122 insertions(+), 328 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 = nss_spwd_for_passwd(pw, &spwd, &sbuf); - 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; - } - } - - 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 = userdb_iterator_get(iterator, &z); + if (r == -ESRCH) + break; if (r < 0) return r; - for (;;) { - _cleanup_(user_record_unrefp) UserRecord *z = NULL; - - r = userdb_iterator_get(iterator, &z); - if (r == -ESRCH) - break; + if (last) { + r = varlink_notify(link, last); 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; + last = json_variant_unref(last); } - if (!last) - return varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL); - - return varlink_reply(link, last); + r = build_user_json(link, z, &last); + if (r < 0) + return r; } - } else - return varlink_error(link, "io.systemd.UserDatabase.BadService", NULL); + + if (!last) + return varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", 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")) { + r = userdb_flags_from_service(link, p.service, &userdb_flags); + if (r < 0) + return r; - 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; + 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; - setgrent(); + r = groupdb_all(userdb_flags, &iterator); + if (r < 0) + return r; - for (;;) { - _cleanup_(group_record_unrefp) GroupRecord *z = NULL; - _cleanup_free_ char *sbuf = NULL; - struct group *grp; - struct sgrp sgrp; + for (;;) { + _cleanup_(group_record_unrefp) GroupRecord *z = NULL; - errno = 0; - grp = getgrent(); - if (!grp) { - if (errno != 0) - log_debug_errno(errno, "Failure while iterating through NSS group database, ignoring: %m"); - - break; - } - - r = nss_sgrp_for_group(grp, &sgrp, &sbuf); - 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; - } - } - - 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 = groupdb_iterator_get(iterator, &z); + if (r == -ESRCH) + break; if (r < 0) return r; - for (;;) { - _cleanup_(group_record_unrefp) GroupRecord *z = NULL; - - r = groupdb_iterator_get(iterator, &z); - if (r == -ESRCH) - break; + if (last) { + r = varlink_notify(link, last); 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; + last = json_variant_unref(last); } - if (!last) - return varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", NULL); - - return varlink_reply(link, last); + r = build_group_json(link, z, &last); + if (r < 0) + return r; } - } else - return varlink_error(link, "io.systemd.UserDatabase.BadService", NULL); + + if (!last) + return varlink_error(link, "io.systemd.UserDatabase.NoRecordFound", 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")) { + r = userdb_flags_from_service(link, p.service, &userdb_flags); + if (r < 0) + return r; - if (p.group_name) { - _cleanup_(group_record_unrefp) GroupRecord *g = NULL; - const char *last = NULL; - char **i; + 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; - 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; + for (;;) { + _cleanup_free_ char *user_name = NULL, *group_name = NULL; - 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)))); - } - - } else if (streq_ptr(p.service, "io.systemd.Multiplexer")) { - - _cleanup_free_ char *last_user_name = NULL, *last_group_name = NULL; - _cleanup_(userdb_iterator_freep) UserDBIterator *iterator = 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); + free(last_user_name); + free(last_group_name); } - 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)))); + last_user_name = TAKE_PTR(user_name); + last_group_name = TAKE_PTR(group_name); } - return varlink_error(link, "io.systemd.UserDatabase.BadService", NULL); + 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)))); } static int process_connection(VarlinkServer *server, int fd) {