]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
userdbd: simplify logic for generating NSS listings 19538/head
authorLennart Poettering <lennart@poettering.net>
Thu, 6 May 2021 14:01:44 +0000 (16:01 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 7 May 2021 20:19:41 +0000 (22:19 +0200)
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
src/userdb/userwork.c

index f0a319679598f8ce98114e7c8e684f1a734c06af..d69c6db034014c8750351cd4c30bfbc13eb257b8 100644 (file)
@@ -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);
index c62a21974a1e4ae499aa97af5092e1d0f7297c90..71251ccf1d105f8cf8394053cb036d1fedd05206 100644 (file)
@@ -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) {