]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
user-record: add support for alias user names to user record
authorLennart Poettering <lennart@poettering.net>
Thu, 16 Jan 2025 13:15:52 +0000 (14:15 +0100)
committerLennart Poettering <lennart@poettering.net>
Tue, 21 Jan 2025 08:58:50 +0000 (09:58 +0100)
docs/USER_RECORD.md
src/shared/user-record-show.c
src/shared/user-record.c
src/shared/user-record.h

index 1a219fed417be077b09f6dc13aabc49c3a91bd7b..a8e02b2c5ec4d47e6285205e457b6f9dc5c16f89 100644 (file)
@@ -226,6 +226,14 @@ This field is optional, when unset the user should not be considered part of any
 A user record with a realm set is never compatible (for the purpose of updates,
 see above) with a user record without one set, even if the `userName` field matches.
 
+`aliases` → An array of strings, each being a valid UNIX user name. If
+specified, a list of additional UNIX user names this record shall be known
+under. These are *alias* names only, the name in `userName` is always the
+primary name. Typically, a user record that carries this field shall be
+retrievable and resolvable under every name listed here, pretty much everywhere
+the primary user name is. If logging in is attempted via an alias name it
+should be normalized to the primary name.
+
 `blobDirectory` → The absolute path to a world-readable copy of the user's blob
 directory. See [Blob Directories](/USER_RECORD_BLOB_DIRS) for more details.
 
index a828ffa0a73502588d74422f61f7f98b163a158a..acff25d0712a7abb81db31117a1c7b94530db5c8 100644 (file)
@@ -65,6 +65,13 @@ void user_record_show(UserRecord *hr, bool show_full_group_info) {
         printf("   User name: %s\n",
                user_record_user_name_and_realm(hr));
 
+        if (!strv_isempty(hr->aliases)) {
+                STRV_FOREACH(i, hr->aliases)
+                        printf(i == hr->aliases ?
+                               "       Alias: %s" : ", %s", *i);
+                putchar('\n');
+        }
+
         if (hr->state) {
                 const char *color;
 
index e63736a74237b4cf11f22a2c4f9e85dfa35162b8..9feac30933ff9b341d15fd61bd2cdd9fa57b01bc 100644 (file)
@@ -140,6 +140,7 @@ static UserRecord* user_record_free(UserRecord *h) {
         free(h->user_name);
         free(h->realm);
         free(h->user_name_and_realm_auto);
+        strv_free(h->aliases);
         free(h->real_name);
         free(h->email_address);
         erase_and_free(h->password_hint);
@@ -1538,6 +1539,7 @@ int user_record_load(UserRecord *h, sd_json_variant *v, UserRecordLoadFlags load
 
         static const sd_json_dispatch_field user_dispatch_table[] = {
                 { "userName",                   SD_JSON_VARIANT_STRING,        json_dispatch_user_group_name,        offsetof(UserRecord, user_name),                     SD_JSON_RELAX  },
+                { "aliases",                    SD_JSON_VARIANT_ARRAY,         json_dispatch_user_group_list,        offsetof(UserRecord, aliases),                       SD_JSON_RELAX  },
                 { "realm",                      SD_JSON_VARIANT_STRING,        json_dispatch_realm,                  offsetof(UserRecord, realm),                         0              },
                 { "blobDirectory",              SD_JSON_VARIANT_STRING,        json_dispatch_path,                   offsetof(UserRecord, blob_directory),                SD_JSON_STRICT },
                 { "blobManifest",               SD_JSON_VARIANT_OBJECT,        dispatch_blob_manifest,               offsetof(UserRecord, blob_manifest),                 0              },
@@ -2635,6 +2637,15 @@ bool user_record_matches_user_name(const UserRecord *u, const char *user_name) {
         if (streq_ptr(u->user_name_and_realm_auto, user_name))
                 return true;
 
+        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;
+
         return false;
 }
 
@@ -2704,7 +2715,8 @@ int user_record_match(UserRecord *u, const UserDBMatch *match) {
                         u->cifs_user_name,
                 };
 
-                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**) u->aliases, strv_length(u->aliases), match->fuzzy_names))
                         return false;
         }
 
index 48b97ce28a3ed068079fe875098d9289a18231de..d80a46130a9b1e734f1795d6205f3dda0870641a 100644 (file)
@@ -239,6 +239,7 @@ typedef struct UserRecord {
         char *user_name;
         char *realm;
         char *user_name_and_realm_auto; /* the user_name field concatenated with '@' and the realm, if the latter is defined */
+        char **aliases;
         char *real_name;
         char *email_address;
         char *password_hint;