diff options
author | Marco Trevisan (Treviño) <mail@3v1n0.net> | 2021-03-16 04:38:59 +0100 |
---|---|---|
committer | Marco Trevisan (Treviño) <mail@3v1n0.net> | 2021-03-16 16:31:47 +0100 |
commit | cb2f9784f3671b278a94cceefa96fb767ef3c149 (patch) | |
tree | b2a993c472f8b647bd48a7776dd48075df60c958 | |
parent | 2252008c22abf69dd3d1c8942369017e89161fde (diff) |
user-manager: Update users tables on username changes
Accounts service provides the user's set_user_name() function that
allows to change an user username, but if this happens the user won't
ever be moved by index in the containing hash table, causing the user to
be never deleted when calling delete_user() and it will be always
exposed when listing or fetching it.
In fact we refer to the users only by their usernames but this may
change and in such situation they'd be left stale in the containing
table.
So, add ability to get an user by the UID, and use this function to
check if the user has been renamed during the "changed" callback and if
so, update its hashtable key.
-rw-r--r-- | src/libaccountsservice/act-user-manager.c | 53 |
1 files changed, 52 insertions, 1 deletions
diff --git a/src/libaccountsservice/act-user-manager.c b/src/libaccountsservice/act-user-manager.c index f32a06b..b1b7d7b 100644 --- a/src/libaccountsservice/act-user-manager.c +++ b/src/libaccountsservice/act-user-manager.c @@ -790,17 +790,68 @@ remove_user (ActUserManager *manager, g_object_unref (user); } +static const char * +find_username_for_uid (GHashTable *users_table, + uid_t user_id) +{ + GHashTableIter iter; + gpointer key, value; + + g_hash_table_iter_init (&iter, users_table); + while (g_hash_table_iter_next (&iter, &key, &value)) { + if (act_user_get_uid (ACT_USER (value)) == user_id) { + return key; + } + } + + return NULL; +} + static void update_user (ActUserManager *manager, ActUser *user) { ActUserManagerPrivate *priv = act_user_manager_get_instance_private (manager); const char *username; + const char *system_user; g_debug ("ActUserManager: updating %s", describe_user (user)); username = act_user_get_user_name (user); - if (g_hash_table_lookup (priv->system_users_by_name, username) != NULL) { + system_user = g_hash_table_lookup (priv->system_users_by_name, username); + + if (system_user == NULL) { + const char *normal_user; + const char *old_username; + + normal_user = g_hash_table_lookup (priv->normal_users_by_name, username); + if (normal_user == NULL) { + uid_t uid = act_user_get_uid (user); + old_username = find_username_for_uid (priv->normal_users_by_name, uid); + GHashTable *users_table = NULL; + + if (old_username) { + users_table = priv->normal_users_by_name; + } else { + old_username = find_username_for_uid (priv->system_users_by_name, uid); + if (old_username) { + users_table = priv->system_users_by_name; + system_user = username; + } + } + + if (users_table != NULL) { + g_debug ("ActUserManager: %s is the new username for %s", + describe_user (user), old_username); + g_hash_table_insert (users_table, + g_strdup (username), + g_object_ref (user)); + g_hash_table_remove (users_table, old_username); + } + } + } + + if (system_user != NULL) { if (!act_user_is_system_account (user)) { g_debug ("ActUserManager: %s is no longer a system account, treating as normal user", describe_user (user)); |