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) {