Accept NSS aliases for canonicalized user records (#42452)
This PR fixes userdb lookups for NSS users that are resolved through an alias but returned with a canonical user name. Some NSS providers, such as SSSD, can successfully resolve a user by an alias-like name, for example a Kerberos/AD UPN (for example testuser@example.test) while returning a passwd record with the canonical login name. The original lookup name was not preserved. Later, the userdb worker checked whether the returned record matched the requested name with user_record_matches_user_name(). Since the requested name was testuser@example.test, but the record only contained testuser, the lookup was rejected as: `io.systemd.UserDatabase.ConflictingRecordFound` This also caused pam_systemd to fail opening sessions for such users with: `pam_systemd(...:session): Failed to get user record` In my case, this broke graphical logins for Samba users logging in with a UPN on systems where SSSD canonicalizes the NSS result. My solution preserves the requested name as a UserRecord alias when an NSS lookup by name succeeds but the returned pw_name differs from the requested name. This allows user_record_matches_user_name() to accept the canonicalized NSS result instead of treating it as a conflicting record. The patch does not invent new aliases. It only records the name that NSS itself already accepted and resolved successfully. I'm not an expert on working with systemd, so I'm asking for a review of my PR.
This commit is contained in:
@@ -34,6 +34,7 @@ static GroupRecord *group_record_free(GroupRecord *g) {
|
||||
free(g->group_name);
|
||||
free(g->realm);
|
||||
free(g->group_name_and_realm_auto);
|
||||
strv_free(g->aliases);
|
||||
free(g->description);
|
||||
|
||||
strv_free(g->members);
|
||||
@@ -92,6 +93,7 @@ static int dispatch_per_machine(const char *name, sd_json_variant *variant, sd_j
|
||||
{ "matchMachineId", _SD_JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 },
|
||||
{ "matchHostname", _SD_JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 },
|
||||
{ "gid", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uid_gid, offsetof(GroupRecord, gid), 0 },
|
||||
{ "aliases", SD_JSON_VARIANT_ARRAY, json_dispatch_user_group_list, offsetof(GroupRecord, aliases), SD_JSON_RELAX },
|
||||
{ "members", SD_JSON_VARIANT_ARRAY, json_dispatch_user_group_list, offsetof(GroupRecord, members), SD_JSON_RELAX },
|
||||
{ "administrators", SD_JSON_VARIANT_ARRAY, json_dispatch_user_group_list, offsetof(GroupRecord, administrators), SD_JSON_RELAX },
|
||||
{},
|
||||
@@ -176,6 +178,7 @@ int group_record_load(
|
||||
|
||||
static const sd_json_dispatch_field group_dispatch_table[] = {
|
||||
{ "groupName", SD_JSON_VARIANT_STRING, json_dispatch_user_group_name, offsetof(GroupRecord, group_name), SD_JSON_RELAX },
|
||||
{ "aliases", SD_JSON_VARIANT_ARRAY, json_dispatch_user_group_list, offsetof(GroupRecord, aliases), SD_JSON_RELAX },
|
||||
{ "realm", SD_JSON_VARIANT_STRING, json_dispatch_realm, offsetof(GroupRecord, realm), 0 },
|
||||
{ "uuid", SD_JSON_VARIANT_STRING, sd_json_dispatch_id128, offsetof(GroupRecord, uuid), 0 },
|
||||
{ "description", SD_JSON_VARIANT_STRING, json_dispatch_gecos, offsetof(GroupRecord, description), 0 },
|
||||
@@ -345,6 +348,12 @@ bool group_record_matches_group_name(const GroupRecord *g, const char *group_nam
|
||||
if (streq_ptr(g->group_name_and_realm_auto, group_name))
|
||||
return true;
|
||||
|
||||
if (strv_contains(g->aliases, group_name))
|
||||
return true;
|
||||
|
||||
if (record_name_matches_alias_realm(group_name, (char * const*) g->aliases, g->realm))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -370,7 +379,8 @@ bool group_record_match(GroupRecord *h, const UserDBMatch *match) {
|
||||
h->description,
|
||||
};
|
||||
|
||||
if (!user_name_fuzzy_match(names, ELEMENTSOF(names), match->fuzzy_names))
|
||||
if (!user_name_fuzzy_match(names, ELEMENTSOF(names), match->fuzzy_names) &&
|
||||
!user_name_fuzzy_match((const char**) h->aliases, strv_length(h->aliases), match->fuzzy_names))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ typedef struct GroupRecord {
|
||||
char *group_name;
|
||||
char *realm;
|
||||
char *group_name_and_realm_auto;
|
||||
char **aliases;
|
||||
sd_id128_t uuid;
|
||||
|
||||
char *description;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "errno-util.h"
|
||||
#include "format-util.h"
|
||||
#include "group-record.h"
|
||||
#include "json-util.h"
|
||||
#include "libcrypt-util.h"
|
||||
#include "log.h"
|
||||
#include "string-util.h"
|
||||
@@ -45,9 +46,23 @@ static int strv_extend_strv_utf8_only(char ***dst, char **src, bool filter_dupli
|
||||
return strv_extend_strv(dst, t, filter_duplicates);
|
||||
}
|
||||
|
||||
static int nss_add_valid_alias(char ***aliases, const char *name, const char *alias_name) {
|
||||
assert(aliases);
|
||||
assert(name);
|
||||
|
||||
if (isempty(alias_name) || streq_ptr(alias_name, name))
|
||||
return 0;
|
||||
|
||||
if (!valid_user_group_name(alias_name, VALID_USER_RELAX))
|
||||
return 0;
|
||||
|
||||
return strv_extend(aliases, alias_name);
|
||||
}
|
||||
|
||||
int nss_passwd_to_user_record(
|
||||
const struct passwd *pwd,
|
||||
const struct spwd *spwd,
|
||||
const char *alias_name,
|
||||
UserRecord **ret) {
|
||||
|
||||
_cleanup_(user_record_unrefp) UserRecord *hr = NULL;
|
||||
@@ -69,6 +84,10 @@ int nss_passwd_to_user_record(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = nss_add_valid_alias(&hr->aliases, hr->user_name, alias_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Some bad NSS modules synthesize GECOS fields with embedded ":" or "\n" characters, which are not
|
||||
* something we can output in /etc/passwd compatible format, since these are record separators
|
||||
* there. We normally refuse that, but we need to maintain compatibility with arbitrary NSS modules,
|
||||
@@ -150,6 +169,7 @@ int nss_passwd_to_user_record(
|
||||
r = sd_json_buildo(
|
||||
&hr->json,
|
||||
SD_JSON_BUILD_PAIR_STRING("userName", hr->user_name),
|
||||
JSON_BUILD_PAIR_STRV_NON_EMPTY("aliases", hr->aliases),
|
||||
SD_JSON_BUILD_PAIR_UNSIGNED("uid", hr->uid),
|
||||
SD_JSON_BUILD_PAIR_UNSIGNED("gid", user_record_gid(hr)),
|
||||
SD_JSON_BUILD_PAIR_CONDITION(!!hr->real_name, "realName", SD_JSON_BUILD_STRING(hr->real_name)),
|
||||
@@ -240,7 +260,7 @@ int nss_user_record_by_name(
|
||||
} else
|
||||
incomplete = true;
|
||||
|
||||
r = nss_passwd_to_user_record(result, sresult, ret);
|
||||
r = nss_passwd_to_user_record(result, sresult, name, ret);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -274,7 +294,7 @@ int nss_user_record_by_uid(
|
||||
} else
|
||||
incomplete = true;
|
||||
|
||||
r = nss_passwd_to_user_record(result, sresult, ret);
|
||||
r = nss_passwd_to_user_record(result, sresult, /* alias_name= */ NULL, ret);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -286,6 +306,7 @@ int nss_user_record_by_uid(
|
||||
int nss_group_to_group_record(
|
||||
const struct group *grp,
|
||||
const struct sgrp *sgrp,
|
||||
const char *alias_name,
|
||||
GroupRecord **ret) {
|
||||
|
||||
_cleanup_(group_record_unrefp) GroupRecord *g = NULL;
|
||||
@@ -307,6 +328,10 @@ int nss_group_to_group_record(
|
||||
if (!g->group_name)
|
||||
return -ENOMEM;
|
||||
|
||||
r = nss_add_valid_alias(&g->aliases, g->group_name, alias_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = strv_extend_strv_utf8_only(&g->members, grp->gr_mem, false);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -332,6 +357,7 @@ int nss_group_to_group_record(
|
||||
r = sd_json_buildo(
|
||||
&g->json,
|
||||
SD_JSON_BUILD_PAIR_STRING("groupName", g->group_name),
|
||||
JSON_BUILD_PAIR_STRV_NON_EMPTY("aliases", g->aliases),
|
||||
SD_JSON_BUILD_PAIR_UNSIGNED("gid", g->gid),
|
||||
SD_JSON_BUILD_PAIR_CONDITION(!strv_isempty(g->members), "members", SD_JSON_BUILD_STRV(g->members)),
|
||||
SD_JSON_BUILD_PAIR_CONDITION(!strv_isempty(g->hashed_password), "privileged", SD_JSON_BUILD_OBJECT(SD_JSON_BUILD_PAIR_STRV("hashedPassword", g->hashed_password))),
|
||||
@@ -412,7 +438,7 @@ int nss_group_record_by_name(
|
||||
} else
|
||||
incomplete = true;
|
||||
|
||||
r = nss_group_to_group_record(result, sresult, ret);
|
||||
r = nss_group_to_group_record(result, sresult, name, ret);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -446,7 +472,7 @@ int nss_group_record_by_gid(
|
||||
} else
|
||||
incomplete = true;
|
||||
|
||||
r = nss_group_to_group_record(result, sresult, ret);
|
||||
r = nss_group_to_group_record(result, sresult, /* alias_name= */ NULL, ret);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
|
||||
/* Synthesize UserRecord and GroupRecord objects from NSS data */
|
||||
|
||||
int nss_passwd_to_user_record(const struct passwd *pwd, const struct spwd *spwd, UserRecord **ret);
|
||||
int nss_passwd_to_user_record(const struct passwd *pwd, const struct spwd *spwd, const char *alias_name, UserRecord **ret);
|
||||
int nss_spwd_for_passwd(const struct passwd *pwd, struct spwd *ret_spwd, char **ret_buffer);
|
||||
|
||||
int nss_user_record_by_name(const char *name, bool with_shadow, UserRecord **ret);
|
||||
int nss_user_record_by_uid(uid_t uid, bool with_shadow, UserRecord **ret);
|
||||
|
||||
int nss_group_to_group_record(const struct group *grp, const struct sgrp *sgrp, GroupRecord **ret);
|
||||
int nss_group_to_group_record(const struct group *grp, const struct sgrp *sgrp, const char *alias_name, GroupRecord **ret);
|
||||
int nss_sgrp_for_group(const struct group *grp, struct sgrp *ret_sgrp, char **ret_buffer);
|
||||
|
||||
int nss_group_record_by_name(const char *name, bool with_shadow, GroupRecord **ret);
|
||||
|
||||
@@ -2775,11 +2775,24 @@ bool user_record_matches_user_name(const UserRecord *u, const char *user_name) {
|
||||
if (strv_contains(u->aliases, user_name))
|
||||
return true;
|
||||
|
||||
const char *realm = strrchr(user_name, '@');
|
||||
if (realm && streq_ptr(realm+1, u->realm))
|
||||
STRV_FOREACH(a, u->aliases)
|
||||
if (startswith(user_name, *a) == realm)
|
||||
return true;
|
||||
if (record_name_matches_alias_realm(user_name, (char * const*) u->aliases, u->realm))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool record_name_matches_alias_realm(const char *name, char * const *aliases, const char *realm) {
|
||||
const char *suffix;
|
||||
|
||||
assert(name);
|
||||
|
||||
suffix = strrchr(name, '@');
|
||||
if (!suffix || !streq_ptr(suffix + 1, realm))
|
||||
return false;
|
||||
|
||||
STRV_FOREACH(a, aliases)
|
||||
if (startswith(name, *a) == suffix)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -546,6 +546,7 @@ bool userdb_match_is_set(const UserDBMatch *match) _pure_;
|
||||
|
||||
void userdb_match_done(UserDBMatch *match);
|
||||
|
||||
bool record_name_matches_alias_realm(const char *name, char * const *aliases, const char *realm);
|
||||
bool user_name_fuzzy_match(const char *names[], size_t n_names, char **matches);
|
||||
bool user_record_match(UserRecord *u, const UserDBMatch *match);
|
||||
|
||||
|
||||
+2
-2
@@ -1124,7 +1124,7 @@ static int userdb_iterator_get_one(UserDBIterator *iterator, UserRecord **ret) {
|
||||
incomplete = true;
|
||||
}
|
||||
|
||||
r = nss_passwd_to_user_record(pw, r >= 0 ? &spwd : NULL, ret);
|
||||
r = nss_passwd_to_user_record(pw, r >= 0 ? &spwd : NULL, /* alias_name= */ NULL, ret);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -1570,7 +1570,7 @@ static int groupdb_iterator_get_one(UserDBIterator *iterator, GroupRecord **ret)
|
||||
incomplete = true;
|
||||
}
|
||||
|
||||
r = nss_group_to_group_record(gr, r >= 0 ? &sgrp : NULL, ret);
|
||||
r = nss_group_to_group_record(gr, r >= 0 ? &sgrp : NULL, /* alias_name= */ NULL, ret);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
@@ -114,6 +114,7 @@ simple_tests += files(
|
||||
'test-fstab-util.c',
|
||||
'test-glob-util.c',
|
||||
'test-gpt.c',
|
||||
'test-group-record-nss.c',
|
||||
'test-gunicode.c',
|
||||
'test-hash-funcs.c',
|
||||
'test-hexdecoct.c',
|
||||
@@ -221,6 +222,7 @@ simple_tests += files(
|
||||
'test-unaligned.c',
|
||||
'test-unit-file.c',
|
||||
'test-user-record.c',
|
||||
'test-user-record-nss.c',
|
||||
'test-user-util.c',
|
||||
'test-utf8.c',
|
||||
'test-verbs.c',
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <grp.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "sd-json.h"
|
||||
#include "group-record.h"
|
||||
#include "strv.h"
|
||||
#include "tests.h"
|
||||
#include "user-record-nss.h"
|
||||
|
||||
TEST(nss_group_alias) {
|
||||
static const struct group grp = {
|
||||
.gr_name = (char*) "domain users",
|
||||
.gr_gid = 1000,
|
||||
};
|
||||
_cleanup_(group_record_unrefp) GroupRecord *g = NULL;
|
||||
sd_json_variant *aliases;
|
||||
|
||||
ASSERT_OK(nss_group_to_group_record(&grp, NULL, "domain users@example.test", &g));
|
||||
ASSERT_TRUE(group_record_matches_group_name(g, "domain users@example.test"));
|
||||
ASSERT_TRUE(strv_contains(g->aliases, "domain users@example.test"));
|
||||
|
||||
aliases = ASSERT_NOT_NULL(sd_json_variant_by_key(g->json, "aliases"));
|
||||
ASSERT_STREQ(sd_json_variant_string(sd_json_variant_by_index(aliases, 0)), "domain users@example.test");
|
||||
}
|
||||
|
||||
TEST(nss_group_invalid_alias) {
|
||||
static const struct group grp = {
|
||||
.gr_name = (char*) "domain users",
|
||||
.gr_gid = 1000,
|
||||
};
|
||||
_cleanup_(group_record_unrefp) GroupRecord *g = NULL;
|
||||
|
||||
ASSERT_OK(nss_group_to_group_record(&grp, NULL, "domain/users", &g));
|
||||
ASSERT_FALSE(group_record_matches_group_name(g, "domain/users"));
|
||||
ASSERT_TRUE(strv_isempty(g->aliases));
|
||||
ASSERT_NULL(sd_json_variant_by_key(g->json, "aliases"));
|
||||
}
|
||||
|
||||
TEST(nss_group_alias_realm) {
|
||||
static const struct group grp = {
|
||||
.gr_name = (char*) "domain users",
|
||||
.gr_gid = 1000,
|
||||
};
|
||||
_cleanup_(group_record_unrefp) GroupRecord *g = NULL;
|
||||
|
||||
ASSERT_OK(nss_group_to_group_record(&grp, NULL, "domain-users", &g));
|
||||
g->realm = ASSERT_NOT_NULL(strdup("example.test"));
|
||||
|
||||
ASSERT_TRUE(group_record_matches_group_name(g, "domain-users@example.test"));
|
||||
}
|
||||
|
||||
TEST(nss_group_alias_same_as_canonical_noop) {
|
||||
static const struct group grp = {
|
||||
.gr_name = (char*) "domain users",
|
||||
.gr_gid = 1000,
|
||||
};
|
||||
_cleanup_(group_record_unrefp) GroupRecord *g = NULL;
|
||||
|
||||
ASSERT_OK(nss_group_to_group_record(&grp, NULL, "domain users", &g));
|
||||
ASSERT_TRUE(strv_isempty(g->aliases));
|
||||
ASSERT_NULL(sd_json_variant_by_key(g->json, "aliases"));
|
||||
}
|
||||
|
||||
TEST(nss_group_null_alias_noop) {
|
||||
static const struct group grp = {
|
||||
.gr_name = (char*) "domain users",
|
||||
.gr_gid = 1000,
|
||||
};
|
||||
_cleanup_(group_record_unrefp) GroupRecord *g = NULL;
|
||||
|
||||
ASSERT_OK(nss_group_to_group_record(&grp, NULL, NULL, &g));
|
||||
ASSERT_TRUE(strv_isempty(g->aliases));
|
||||
ASSERT_NULL(sd_json_variant_by_key(g->json, "aliases"));
|
||||
}
|
||||
|
||||
TEST(nss_group_alias_fuzzy_match) {
|
||||
static const struct group grp = {
|
||||
.gr_name = (char*) "canonical group",
|
||||
.gr_gid = 1000,
|
||||
};
|
||||
_cleanup_(group_record_unrefp) GroupRecord *g = NULL;
|
||||
UserDBMatch match = USERDB_MATCH_NULL;
|
||||
|
||||
ASSERT_OK(nss_group_to_group_record(&grp, NULL, "external-group", &g));
|
||||
match.fuzzy_names = ASSERT_NOT_NULL(strv_new("ternal"));
|
||||
|
||||
ASSERT_TRUE(group_record_match(g, &match));
|
||||
userdb_match_done(&match);
|
||||
}
|
||||
|
||||
DEFINE_TEST_MAIN(LOG_INFO);
|
||||
@@ -0,0 +1,117 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <pwd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "sd-json.h"
|
||||
#include "strv.h"
|
||||
#include "tests.h"
|
||||
#include "user-record.h"
|
||||
#include "user-record-nss.h"
|
||||
|
||||
TEST(nss_user_alias) {
|
||||
static const struct passwd pwd = {
|
||||
.pw_name = (char*) "testuser",
|
||||
.pw_uid = 1000,
|
||||
.pw_gid = 1000,
|
||||
.pw_gecos = (char*) "testuser",
|
||||
.pw_dir = (char*) "/home/testuser",
|
||||
.pw_shell = (char*) "/bin/bash",
|
||||
};
|
||||
_cleanup_(user_record_unrefp) UserRecord *u = NULL;
|
||||
sd_json_variant *aliases;
|
||||
|
||||
ASSERT_OK(nss_passwd_to_user_record(&pwd, NULL, "testuser@example.test", &u));
|
||||
ASSERT_TRUE(user_record_matches_user_name(u, "testuser@example.test"));
|
||||
ASSERT_TRUE(strv_contains(u->aliases, "testuser@example.test"));
|
||||
|
||||
aliases = ASSERT_NOT_NULL(sd_json_variant_by_key(u->json, "aliases"));
|
||||
ASSERT_STREQ(sd_json_variant_string(sd_json_variant_by_index(aliases, 0)), "testuser@example.test");
|
||||
}
|
||||
|
||||
TEST(nss_user_invalid_alias) {
|
||||
static const struct passwd pwd = {
|
||||
.pw_name = (char*) "testuser",
|
||||
.pw_uid = 1000,
|
||||
.pw_gid = 1000,
|
||||
.pw_gecos = (char*) "testuser",
|
||||
.pw_dir = (char*) "/home/testuser",
|
||||
.pw_shell = (char*) "/bin/bash",
|
||||
};
|
||||
_cleanup_(user_record_unrefp) UserRecord *u = NULL;
|
||||
|
||||
ASSERT_OK(nss_passwd_to_user_record(&pwd, NULL, "testuser/bad", &u));
|
||||
ASSERT_FALSE(user_record_matches_user_name(u, "testuser/bad"));
|
||||
ASSERT_TRUE(strv_isempty(u->aliases));
|
||||
ASSERT_NULL(sd_json_variant_by_key(u->json, "aliases"));
|
||||
}
|
||||
|
||||
TEST(nss_user_alias_realm) {
|
||||
static const struct passwd pwd = {
|
||||
.pw_name = (char*) "testuser",
|
||||
.pw_uid = 1000,
|
||||
.pw_gid = 1000,
|
||||
.pw_gecos = (char*) "testuser",
|
||||
.pw_dir = (char*) "/home/testuser",
|
||||
.pw_shell = (char*) "/bin/bash",
|
||||
};
|
||||
_cleanup_(user_record_unrefp) UserRecord *u = NULL;
|
||||
|
||||
ASSERT_OK(nss_passwd_to_user_record(&pwd, NULL, "testuser-short", &u));
|
||||
u->realm = ASSERT_NOT_NULL(strdup("example.test"));
|
||||
|
||||
ASSERT_TRUE(user_record_matches_user_name(u, "testuser-short@example.test"));
|
||||
}
|
||||
|
||||
TEST(nss_user_alias_same_as_canonical_noop) {
|
||||
static const struct passwd pwd = {
|
||||
.pw_name = (char*) "testuser",
|
||||
.pw_uid = 1000,
|
||||
.pw_gid = 1000,
|
||||
.pw_gecos = (char*) "testuser",
|
||||
.pw_dir = (char*) "/home/testuser",
|
||||
.pw_shell = (char*) "/bin/bash",
|
||||
};
|
||||
_cleanup_(user_record_unrefp) UserRecord *u = NULL;
|
||||
|
||||
ASSERT_OK(nss_passwd_to_user_record(&pwd, NULL, "testuser", &u));
|
||||
ASSERT_TRUE(strv_isempty(u->aliases));
|
||||
ASSERT_NULL(sd_json_variant_by_key(u->json, "aliases"));
|
||||
}
|
||||
|
||||
TEST(nss_user_null_alias_noop) {
|
||||
static const struct passwd pwd = {
|
||||
.pw_name = (char*) "testuser",
|
||||
.pw_uid = 1000,
|
||||
.pw_gid = 1000,
|
||||
.pw_gecos = (char*) "testuser",
|
||||
.pw_dir = (char*) "/home/testuser",
|
||||
.pw_shell = (char*) "/bin/bash",
|
||||
};
|
||||
_cleanup_(user_record_unrefp) UserRecord *u = NULL;
|
||||
|
||||
ASSERT_OK(nss_passwd_to_user_record(&pwd, NULL, NULL, &u));
|
||||
ASSERT_TRUE(strv_isempty(u->aliases));
|
||||
ASSERT_NULL(sd_json_variant_by_key(u->json, "aliases"));
|
||||
}
|
||||
|
||||
TEST(nss_user_alias_fuzzy_match) {
|
||||
static const struct passwd pwd = {
|
||||
.pw_name = (char*) "canonical",
|
||||
.pw_uid = 1000,
|
||||
.pw_gid = 1000,
|
||||
.pw_gecos = (char*) "canonical",
|
||||
.pw_dir = (char*) "/home/canonical",
|
||||
.pw_shell = (char*) "/bin/bash",
|
||||
};
|
||||
_cleanup_(user_record_unrefp) UserRecord *u = NULL;
|
||||
UserDBMatch match = USERDB_MATCH_NULL;
|
||||
|
||||
ASSERT_OK(nss_passwd_to_user_record(&pwd, NULL, "external-login", &u));
|
||||
match.fuzzy_names = ASSERT_NOT_NULL(strv_new("ternal"));
|
||||
|
||||
ASSERT_TRUE(user_record_match(u, &match));
|
||||
userdb_match_done(&match);
|
||||
}
|
||||
|
||||
DEFINE_TEST_MAIN(LOG_INFO);
|
||||
+11
-7
@@ -176,10 +176,12 @@ static int vl_method_get_user_record(sd_varlink *link, sd_json_variant *paramete
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (uid_is_valid(p.uid))
|
||||
r = userdb_by_uid(p.uid, &p.match, userdb_flags, &hr);
|
||||
else if (p.name)
|
||||
/* Prefer lookup by name if both name and UID are specified, so NSS-backed records preserve
|
||||
* the requested lookup name as an alias before we check the UID below. */
|
||||
if (p.name)
|
||||
r = userdb_by_name(p.name, &p.match, userdb_flags, &hr);
|
||||
else if (uid_is_valid(p.uid))
|
||||
r = userdb_by_uid(p.uid, &p.match, userdb_flags, &hr);
|
||||
else {
|
||||
_cleanup_(userdb_iterator_freep) UserDBIterator *iterator = NULL;
|
||||
|
||||
@@ -317,10 +319,12 @@ static int vl_method_get_group_record(sd_varlink *link, sd_json_variant *paramet
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (gid_is_valid(p.gid))
|
||||
r = groupdb_by_gid(p.gid, &p.match, userdb_flags, &g);
|
||||
else if (p.name)
|
||||
/* Prefer lookup by name if both name and GID are specified, so NSS-backed records preserve
|
||||
* the requested lookup name as an alias before we check the GID below. */
|
||||
if (p.name)
|
||||
r = groupdb_by_name(p.name, &p.match, userdb_flags, &g);
|
||||
else if (gid_is_valid(p.gid))
|
||||
r = groupdb_by_gid(p.gid, &p.match, userdb_flags, &g);
|
||||
else {
|
||||
_cleanup_(userdb_iterator_freep) UserDBIterator *iterator = NULL;
|
||||
|
||||
@@ -360,7 +364,7 @@ static int vl_method_get_group_record(sd_varlink *link, sd_json_variant *paramet
|
||||
return sd_varlink_error(link, "io.systemd.UserDatabase.ServiceNotAvailable", NULL);
|
||||
}
|
||||
|
||||
if ((uid_is_valid(p.gid) && g->gid != p.gid) ||
|
||||
if ((gid_is_valid(p.gid) && g->gid != p.gid) ||
|
||||
(p.name && !group_record_matches_group_name(g, p.name)))
|
||||
return sd_varlink_error(link, "io.systemd.UserDatabase.ConflictingRecordFound", NULL);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user