|
|
889f5f |
From 83567748f5f5c4eabc233680a553f3edd803a24d Mon Sep 17 00:00:00 2001
|
|
|
889f5f |
From: Ray Strode <rstrode@redhat.com>
|
|
|
889f5f |
Date: Thu, 4 May 2017 12:04:05 -0400
|
|
|
889f5f |
Subject: [PATCH] daemon: don't treat explicitly requested users as "cached"
|
|
|
889f5f |
|
|
|
889f5f |
The ListCachedUsers method currently returns users that have
|
|
|
889f5f |
been explicitly requested by a client. It's weird that merely
|
|
|
889f5f |
querying a user can make it show up in login screen user lists.
|
|
|
889f5f |
Furthermore, UncacheUser is broken since commit
|
|
|
889f5f |
177509e9460b149ecbf85e75c930be2ea00b7d05 because the user has
|
|
|
889f5f |
been explicitly requested in order to uncache it. So trying
|
|
|
889f5f |
to uncache a user inadvertently caches the user.
|
|
|
889f5f |
|
|
|
889f5f |
This commit fixes that.
|
|
|
889f5f |
|
|
|
889f5f |
https://bugs.freedesktop.org/show_bug.cgi?id=101052
|
|
|
889f5f |
---
|
|
|
889f5f |
src/daemon.c | 71 +++++++++++++++++++++++++++++++++++++++---------------------
|
|
|
889f5f |
src/user.c | 17 +++++++++++++++
|
|
|
889f5f |
src/user.h | 3 +++
|
|
|
889f5f |
3 files changed, 66 insertions(+), 25 deletions(-)
|
|
|
889f5f |
|
|
|
889f5f |
diff --git a/src/daemon.c b/src/daemon.c
|
|
|
889f5f |
index 4586eff..fce5a60 100644
|
|
|
889f5f |
--- a/src/daemon.c
|
|
|
889f5f |
+++ b/src/daemon.c
|
|
|
889f5f |
@@ -481,100 +481,108 @@ entry_generator_requested_users (Daemon *daemon,
|
|
|
889f5f |
while (node != NULL) {
|
|
|
889f5f |
const char *name;
|
|
|
889f5f |
|
|
|
889f5f |
name = node->data;
|
|
|
889f5f |
node = node->next;
|
|
|
889f5f |
|
|
|
889f5f |
*state = node;
|
|
|
889f5f |
|
|
|
889f5f |
if (!g_hash_table_lookup (users, name)) {
|
|
|
889f5f |
pwent = getpwnam (name);
|
|
|
889f5f |
if (pwent == NULL) {
|
|
|
889f5f |
g_debug ("user '%s' requested previously but not present on system", name);
|
|
|
889f5f |
} else {
|
|
|
889f5f |
*shadow_entry = getspnam (pwent->pw_name);
|
|
|
889f5f |
|
|
|
889f5f |
return pwent;
|
|
|
889f5f |
}
|
|
|
889f5f |
}
|
|
|
889f5f |
}
|
|
|
889f5f |
}
|
|
|
889f5f |
|
|
|
889f5f |
/* Last iteration */
|
|
|
889f5f |
|
|
|
889f5f |
*state = NULL;
|
|
|
889f5f |
return NULL;
|
|
|
889f5f |
}
|
|
|
889f5f |
|
|
|
889f5f |
static void
|
|
|
889f5f |
load_entries (Daemon *daemon,
|
|
|
889f5f |
GHashTable *users,
|
|
|
889f5f |
- gboolean allow_system_users,
|
|
|
889f5f |
+ gboolean explicitly_requested,
|
|
|
889f5f |
EntryGeneratorFunc entry_generator)
|
|
|
889f5f |
{
|
|
|
889f5f |
gpointer generator_state = NULL;
|
|
|
889f5f |
struct passwd *pwent;
|
|
|
889f5f |
struct spwd *spent = NULL;
|
|
|
889f5f |
User *user = NULL;
|
|
|
889f5f |
|
|
|
889f5f |
g_assert (entry_generator != NULL);
|
|
|
889f5f |
|
|
|
889f5f |
for (;;) {
|
|
|
889f5f |
spent = NULL;
|
|
|
889f5f |
pwent = entry_generator (daemon, users, &generator_state, &spent);
|
|
|
889f5f |
if (pwent == NULL)
|
|
|
889f5f |
break;
|
|
|
889f5f |
|
|
|
889f5f |
/* Skip system users... */
|
|
|
889f5f |
- if (!allow_system_users && !user_classify_is_human (pwent->pw_uid, pwent->pw_name, pwent->pw_shell, spent? spent->sp_pwdp : NULL)) {
|
|
|
889f5f |
+ if (!explicitly_requested && !user_classify_is_human (pwent->pw_uid, pwent->pw_name, pwent->pw_shell, spent? spent->sp_pwdp : NULL)) {
|
|
|
889f5f |
g_debug ("skipping user: %s", pwent->pw_name);
|
|
|
889f5f |
continue;
|
|
|
889f5f |
}
|
|
|
889f5f |
|
|
|
889f5f |
- /* ignore duplicate entries */
|
|
|
889f5f |
- if (g_hash_table_lookup (users, pwent->pw_name)) {
|
|
|
889f5f |
- continue;
|
|
|
889f5f |
- }
|
|
|
889f5f |
+ /* Only process users that haven't been processed yet.
|
|
|
889f5f |
+ * We do always make sure entries get promoted
|
|
|
889f5f |
+ * to "cached" status if they are supposed to be
|
|
|
889f5f |
+ */
|
|
|
889f5f |
+
|
|
|
889f5f |
+ user = g_hash_table_lookup (users, pwent->pw_name);
|
|
|
889f5f |
|
|
|
889f5f |
- user = g_hash_table_lookup (daemon->priv->users, pwent->pw_name);
|
|
|
889f5f |
if (user == NULL) {
|
|
|
889f5f |
- user = user_new (daemon, pwent->pw_uid);
|
|
|
889f5f |
- } else {
|
|
|
889f5f |
- g_object_ref (user);
|
|
|
889f5f |
- }
|
|
|
889f5f |
+ user = g_hash_table_lookup (daemon->priv->users, pwent->pw_name);
|
|
|
889f5f |
+ if (user == NULL) {
|
|
|
889f5f |
+ user = user_new (daemon, pwent->pw_uid);
|
|
|
889f5f |
+ } else {
|
|
|
889f5f |
+ g_object_ref (user);
|
|
|
889f5f |
+ }
|
|
|
889f5f |
+
|
|
|
889f5f |
+ /* freeze & update users not already in the new list */
|
|
|
889f5f |
+ g_object_freeze_notify (G_OBJECT (user));
|
|
|
889f5f |
+ user_update_from_pwent (user, pwent, spent);
|
|
|
889f5f |
|
|
|
889f5f |
- /* freeze & update users not already in the new list */
|
|
|
889f5f |
- g_object_freeze_notify (G_OBJECT (user));
|
|
|
889f5f |
- user_update_from_pwent (user, pwent, spent);
|
|
|
889f5f |
+ g_hash_table_insert (users, g_strdup (user_get_user_name (user)), user);
|
|
|
889f5f |
+ g_debug ("loaded user: %s", user_get_user_name (user));
|
|
|
889f5f |
+ }
|
|
|
889f5f |
|
|
|
889f5f |
- g_hash_table_insert (users, g_strdup (user_get_user_name (user)), user);
|
|
|
889f5f |
- g_debug ("loaded user: %s", user_get_user_name (user));
|
|
|
889f5f |
+ if (!explicitly_requested) {
|
|
|
889f5f |
+ user_set_cached (user, TRUE);
|
|
|
889f5f |
+ }
|
|
|
889f5f |
}
|
|
|
889f5f |
|
|
|
889f5f |
/* Generator should have cleaned up */
|
|
|
889f5f |
g_assert (generator_state == NULL);
|
|
|
889f5f |
}
|
|
|
889f5f |
|
|
|
889f5f |
static GHashTable *
|
|
|
889f5f |
create_users_hash_table (void)
|
|
|
889f5f |
{
|
|
|
889f5f |
return g_hash_table_new_full (g_str_hash,
|
|
|
889f5f |
g_str_equal,
|
|
|
889f5f |
g_free,
|
|
|
889f5f |
g_object_unref);
|
|
|
889f5f |
}
|
|
|
889f5f |
|
|
|
889f5f |
static void
|
|
|
889f5f |
reload_users (Daemon *daemon)
|
|
|
889f5f |
{
|
|
|
889f5f |
GHashTable *users;
|
|
|
889f5f |
GHashTable *old_users;
|
|
|
889f5f |
GHashTable *local;
|
|
|
889f5f |
GHashTableIter iter;
|
|
|
889f5f |
gpointer name;
|
|
|
889f5f |
User *user;
|
|
|
889f5f |
|
|
|
889f5f |
/* Track the users that we saw during our (re)load */
|
|
|
889f5f |
users = create_users_hash_table ();
|
|
|
889f5f |
|
|
|
889f5f |
/*
|
|
|
889f5f |
* NOTE: As we load data from all the sources, notifies are
|
|
|
889f5f |
@@ -586,71 +594,79 @@ reload_users (Daemon *daemon)
|
|
|
889f5f |
load_entries (daemon, users, FALSE, entry_generator_fgetpwent);
|
|
|
889f5f |
local = g_hash_table_new (g_str_hash, g_str_equal);
|
|
|
889f5f |
g_hash_table_iter_init (&iter, users);
|
|
|
889f5f |
while (g_hash_table_iter_next (&iter, &name, NULL))
|
|
|
889f5f |
g_hash_table_add (local, name);
|
|
|
889f5f |
|
|
|
889f5f |
/* and add users to hash table that were explicitly requested */
|
|
|
889f5f |
load_entries (daemon, users, TRUE, entry_generator_requested_users);
|
|
|
889f5f |
|
|
|
889f5f |
/* Now add/update users from other sources, possibly non-local */
|
|
|
889f5f |
load_entries (daemon, users, FALSE, entry_generator_cachedir);
|
|
|
889f5f |
|
|
|
889f5f |
#ifdef HAVE_UTMPX_H
|
|
|
889f5f |
wtmp_update_login_frequencies (users);
|
|
|
889f5f |
#endif
|
|
|
889f5f |
|
|
|
889f5f |
/* Mark which users are local, which are not */
|
|
|
889f5f |
g_hash_table_iter_init (&iter, users);
|
|
|
889f5f |
while (g_hash_table_iter_next (&iter, &name, (gpointer *)&user))
|
|
|
889f5f |
user_update_local_account_property (user, g_hash_table_lookup (local, name) != NULL);
|
|
|
889f5f |
|
|
|
889f5f |
g_hash_table_destroy (local);
|
|
|
889f5f |
|
|
|
889f5f |
/* Swap out the users */
|
|
|
889f5f |
old_users = daemon->priv->users;
|
|
|
889f5f |
daemon->priv->users = users;
|
|
|
889f5f |
|
|
|
889f5f |
/* Remove all the old users */
|
|
|
889f5f |
g_hash_table_iter_init (&iter, old_users);
|
|
|
889f5f |
while (g_hash_table_iter_next (&iter, &name, (gpointer *)&user)) {
|
|
|
889f5f |
- if (!g_hash_table_lookup (users, name)) {
|
|
|
889f5f |
+ User *refreshed_user;
|
|
|
889f5f |
+
|
|
|
889f5f |
+ refreshed_user = g_hash_table_lookup (users, name);
|
|
|
889f5f |
+
|
|
|
889f5f |
+ if (!refreshed_user || !user_get_cached (refreshed_user)) {
|
|
|
889f5f |
user_unregister (user);
|
|
|
889f5f |
accounts_accounts_emit_user_deleted (ACCOUNTS_ACCOUNTS (daemon),
|
|
|
889f5f |
user_get_object_path (user));
|
|
|
889f5f |
}
|
|
|
889f5f |
}
|
|
|
889f5f |
|
|
|
889f5f |
/* Register all the new users */
|
|
|
889f5f |
g_hash_table_iter_init (&iter, users);
|
|
|
889f5f |
while (g_hash_table_iter_next (&iter, &name, (gpointer *)&user)) {
|
|
|
889f5f |
- if (!g_hash_table_lookup (old_users, name)) {
|
|
|
889f5f |
+ User *stale_user;
|
|
|
889f5f |
+
|
|
|
889f5f |
+ stale_user = g_hash_table_lookup (old_users, name);
|
|
|
889f5f |
+
|
|
|
889f5f |
+ if (!stale_user || !user_get_cached (stale_user) && user_get_cached (user)) {
|
|
|
889f5f |
user_register (user);
|
|
|
889f5f |
accounts_accounts_emit_user_added (ACCOUNTS_ACCOUNTS (daemon),
|
|
|
889f5f |
user_get_object_path (user));
|
|
|
889f5f |
}
|
|
|
889f5f |
g_object_thaw_notify (G_OBJECT (user));
|
|
|
889f5f |
}
|
|
|
889f5f |
|
|
|
889f5f |
g_hash_table_destroy (old_users);
|
|
|
889f5f |
}
|
|
|
889f5f |
|
|
|
889f5f |
static gboolean
|
|
|
889f5f |
reload_users_timeout (Daemon *daemon)
|
|
|
889f5f |
{
|
|
|
889f5f |
reload_users (daemon);
|
|
|
889f5f |
daemon->priv->reload_id = 0;
|
|
|
889f5f |
|
|
|
889f5f |
return FALSE;
|
|
|
889f5f |
}
|
|
|
889f5f |
|
|
|
889f5f |
static gboolean load_autologin (Daemon *daemon,
|
|
|
889f5f |
gchar **name,
|
|
|
889f5f |
gboolean *enabled,
|
|
|
889f5f |
GError **error);
|
|
|
889f5f |
|
|
|
889f5f |
static gboolean
|
|
|
889f5f |
reload_autologin_timeout (Daemon *daemon)
|
|
|
889f5f |
{
|
|
|
889f5f |
gboolean enabled;
|
|
|
889f5f |
gchar *name = NULL;
|
|
|
889f5f |
GError *error = NULL;
|
|
|
889f5f |
@@ -1063,60 +1079,65 @@ list_user_data_new (Daemon *daemon,
|
|
|
889f5f |
static void
|
|
|
889f5f |
list_user_data_free (ListUserData *data)
|
|
|
889f5f |
{
|
|
|
889f5f |
g_object_unref (data->daemon);
|
|
|
889f5f |
g_free (data);
|
|
|
889f5f |
}
|
|
|
889f5f |
|
|
|
889f5f |
static gboolean
|
|
|
889f5f |
finish_list_cached_users (gpointer user_data)
|
|
|
889f5f |
{
|
|
|
889f5f |
ListUserData *data = user_data;
|
|
|
889f5f |
GPtrArray *object_paths;
|
|
|
889f5f |
GHashTableIter iter;
|
|
|
889f5f |
const gchar *name;
|
|
|
889f5f |
User *user;
|
|
|
889f5f |
uid_t uid;
|
|
|
889f5f |
const gchar *shell;
|
|
|
889f5f |
|
|
|
889f5f |
object_paths = g_ptr_array_new ();
|
|
|
889f5f |
|
|
|
889f5f |
g_hash_table_iter_init (&iter, data->daemon->priv->users);
|
|
|
889f5f |
while (g_hash_table_iter_next (&iter, (gpointer *)&name, (gpointer *)&user)) {
|
|
|
889f5f |
uid = user_get_uid (user);
|
|
|
889f5f |
shell = user_get_shell (user);
|
|
|
889f5f |
|
|
|
889f5f |
if (!user_classify_is_human (uid, name, shell, NULL)) {
|
|
|
889f5f |
g_debug ("user %s %ld excluded", name, (long) uid);
|
|
|
889f5f |
continue;
|
|
|
889f5f |
}
|
|
|
889f5f |
|
|
|
889f5f |
+ if (!user_get_cached (user)) {
|
|
|
889f5f |
+ g_debug ("user %s %ld not cached", name, (long) uid);
|
|
|
889f5f |
+ continue;
|
|
|
889f5f |
+ }
|
|
|
889f5f |
+
|
|
|
889f5f |
g_debug ("user %s %ld not excluded", name, (long) uid);
|
|
|
889f5f |
g_ptr_array_add (object_paths, (gpointer) user_get_object_path (user));
|
|
|
889f5f |
}
|
|
|
889f5f |
g_ptr_array_add (object_paths, NULL);
|
|
|
889f5f |
|
|
|
889f5f |
accounts_accounts_complete_list_cached_users (NULL, data->context, (const gchar * const *) object_paths->pdata);
|
|
|
889f5f |
|
|
|
889f5f |
g_ptr_array_free (object_paths, TRUE);
|
|
|
889f5f |
|
|
|
889f5f |
list_user_data_free (data);
|
|
|
889f5f |
|
|
|
889f5f |
return FALSE;
|
|
|
889f5f |
}
|
|
|
889f5f |
|
|
|
889f5f |
static gboolean
|
|
|
889f5f |
daemon_list_cached_users (AccountsAccounts *accounts,
|
|
|
889f5f |
GDBusMethodInvocation *context)
|
|
|
889f5f |
{
|
|
|
889f5f |
Daemon *daemon = (Daemon*)accounts;
|
|
|
889f5f |
ListUserData *data;
|
|
|
889f5f |
|
|
|
889f5f |
data = list_user_data_new (daemon, context);
|
|
|
889f5f |
|
|
|
889f5f |
if (daemon->priv->reload_id > 0) {
|
|
|
889f5f |
/* reload in progress, wait a bit */
|
|
|
889f5f |
g_idle_add (finish_list_cached_users, data);
|
|
|
889f5f |
}
|
|
|
889f5f |
else {
|
|
|
889f5f |
finish_list_cached_users (data);
|
|
|
889f5f |
}
|
|
|
889f5f |
@@ -1303,123 +1324,123 @@ daemon_cache_user (AccountsAccounts *accounts,
|
|
|
889f5f |
static void
|
|
|
889f5f |
daemon_uncache_user_authorized_cb (Daemon *daemon,
|
|
|
889f5f |
User *dummy,
|
|
|
889f5f |
GDBusMethodInvocation *context,
|
|
|
889f5f |
gpointer data)
|
|
|
889f5f |
{
|
|
|
889f5f |
const gchar *user_name = data;
|
|
|
889f5f |
gchar *filename;
|
|
|
889f5f |
User *user;
|
|
|
889f5f |
|
|
|
889f5f |
sys_log (context, "uncache user '%s'", user_name);
|
|
|
889f5f |
|
|
|
889f5f |
user = daemon_local_find_user_by_name (daemon, user_name);
|
|
|
889f5f |
if (user == NULL) {
|
|
|
889f5f |
throw_error (context, ERROR_USER_DOES_NOT_EXIST,
|
|
|
889f5f |
"No user with the name %s found", user_name);
|
|
|
889f5f |
return;
|
|
|
889f5f |
}
|
|
|
889f5f |
|
|
|
889f5f |
/* Always use the canonical user name looked up */
|
|
|
889f5f |
user_name = user_get_user_name (user);
|
|
|
889f5f |
|
|
|
889f5f |
filename = g_build_filename (USERDIR, user_name, NULL);
|
|
|
889f5f |
g_remove (filename);
|
|
|
889f5f |
g_free (filename);
|
|
|
889f5f |
|
|
|
889f5f |
filename = g_build_filename (ICONDIR, user_name, NULL);
|
|
|
889f5f |
g_remove (filename);
|
|
|
889f5f |
g_free (filename);
|
|
|
889f5f |
|
|
|
889f5f |
+ user_set_cached (user, FALSE);
|
|
|
889f5f |
+
|
|
|
889f5f |
accounts_accounts_complete_uncache_user (NULL, context);
|
|
|
889f5f |
|
|
|
889f5f |
queue_reload_users (daemon);
|
|
|
889f5f |
}
|
|
|
889f5f |
|
|
|
889f5f |
static gboolean
|
|
|
889f5f |
daemon_uncache_user (AccountsAccounts *accounts,
|
|
|
889f5f |
GDBusMethodInvocation *context,
|
|
|
889f5f |
const gchar *user_name)
|
|
|
889f5f |
{
|
|
|
889f5f |
Daemon *daemon = (Daemon*)accounts;
|
|
|
889f5f |
|
|
|
889f5f |
daemon_local_check_auth (daemon,
|
|
|
889f5f |
NULL,
|
|
|
889f5f |
"org.freedesktop.accounts.user-administration",
|
|
|
889f5f |
TRUE,
|
|
|
889f5f |
daemon_uncache_user_authorized_cb,
|
|
|
889f5f |
context,
|
|
|
889f5f |
g_strdup (user_name),
|
|
|
889f5f |
g_free);
|
|
|
889f5f |
|
|
|
889f5f |
return TRUE;
|
|
|
889f5f |
}
|
|
|
889f5f |
|
|
|
889f5f |
typedef struct {
|
|
|
889f5f |
uid_t uid;
|
|
|
889f5f |
gboolean remove_files;
|
|
|
889f5f |
} DeleteUserData;
|
|
|
889f5f |
|
|
|
889f5f |
static void
|
|
|
889f5f |
daemon_delete_user_authorized_cb (Daemon *daemon,
|
|
|
889f5f |
User *dummy,
|
|
|
889f5f |
GDBusMethodInvocation *context,
|
|
|
889f5f |
gpointer data)
|
|
|
889f5f |
|
|
|
889f5f |
{
|
|
|
889f5f |
DeleteUserData *ud = data;
|
|
|
889f5f |
GError *error;
|
|
|
889f5f |
gchar *filename;
|
|
|
889f5f |
struct passwd *pwent;
|
|
|
889f5f |
const gchar *argv[6];
|
|
|
889f5f |
+ User *user;
|
|
|
889f5f |
|
|
|
889f5f |
pwent = getpwuid (ud->uid);
|
|
|
889f5f |
|
|
|
889f5f |
if (pwent == NULL) {
|
|
|
889f5f |
throw_error (context, ERROR_USER_DOES_NOT_EXIST, "No user with uid %d found", ud->uid);
|
|
|
889f5f |
|
|
|
889f5f |
return;
|
|
|
889f5f |
}
|
|
|
889f5f |
|
|
|
889f5f |
sys_log (context, "delete user '%s' (%d)", pwent->pw_name, ud->uid);
|
|
|
889f5f |
|
|
|
889f5f |
- if (daemon->priv->autologin != NULL) {
|
|
|
889f5f |
- User *user;
|
|
|
889f5f |
+ user = daemon_local_find_user_by_id (daemon, ud->uid);
|
|
|
889f5f |
|
|
|
889f5f |
- user = daemon_local_find_user_by_id (daemon, ud->uid);
|
|
|
889f5f |
+ if (user != NULL) {
|
|
|
889f5f |
+ user_set_cached (user, FALSE);
|
|
|
889f5f |
|
|
|
889f5f |
- g_assert (user != NULL);
|
|
|
889f5f |
-
|
|
|
889f5f |
- if (daemon->priv->autologin == user) {
|
|
|
889f5f |
+ if (daemon->priv->autologin == user) {
|
|
|
889f5f |
daemon_local_set_automatic_login (daemon, user, FALSE, NULL);
|
|
|
889f5f |
}
|
|
|
889f5f |
-
|
|
|
889f5f |
}
|
|
|
889f5f |
|
|
|
889f5f |
filename = g_build_filename (USERDIR, pwent->pw_name, NULL);
|
|
|
889f5f |
g_remove (filename);
|
|
|
889f5f |
g_free (filename);
|
|
|
889f5f |
|
|
|
889f5f |
filename = g_build_filename (ICONDIR, pwent->pw_name, NULL);
|
|
|
889f5f |
g_remove (filename);
|
|
|
889f5f |
g_free (filename);
|
|
|
889f5f |
|
|
|
889f5f |
argv[0] = "/usr/sbin/userdel";
|
|
|
889f5f |
if (ud->remove_files) {
|
|
|
889f5f |
argv[1] = "-f";
|
|
|
889f5f |
argv[2] = "-r";
|
|
|
889f5f |
argv[3] = "--";
|
|
|
889f5f |
argv[4] = pwent->pw_name;
|
|
|
889f5f |
argv[5] = NULL;
|
|
|
889f5f |
}
|
|
|
889f5f |
else {
|
|
|
889f5f |
argv[1] = "-f";
|
|
|
889f5f |
argv[2] = "--";
|
|
|
889f5f |
argv[3] = pwent->pw_name;
|
|
|
889f5f |
argv[4] = NULL;
|
|
|
889f5f |
}
|
|
|
889f5f |
|
|
|
889f5f |
error = NULL;
|
|
|
889f5f |
if (!spawn_with_login_uid (context, argv, &error)) {
|
|
|
889f5f |
throw_error (context, ERROR_FAILED, "running '%s' failed: %s", argv[0], error->message);
|
|
|
889f5f |
g_error_free (error);
|
|
|
889f5f |
return;
|
|
|
889f5f |
diff --git a/src/user.c b/src/user.c
|
|
|
889f5f |
index 247ca2f..056be2f 100644
|
|
|
889f5f |
--- a/src/user.c
|
|
|
889f5f |
+++ b/src/user.c
|
|
|
889f5f |
@@ -77,60 +77,61 @@ struct User {
|
|
|
889f5f |
|
|
|
889f5f |
GDBusConnection *system_bus_connection;
|
|
|
889f5f |
gchar *object_path;
|
|
|
889f5f |
|
|
|
889f5f |
Daemon *daemon;
|
|
|
889f5f |
|
|
|
889f5f |
GKeyFile *keyfile;
|
|
|
889f5f |
|
|
|
889f5f |
uid_t uid;
|
|
|
889f5f |
gid_t gid;
|
|
|
889f5f |
gchar *user_name;
|
|
|
889f5f |
gchar *real_name;
|
|
|
889f5f |
AccountType account_type;
|
|
|
889f5f |
PasswordMode password_mode;
|
|
|
889f5f |
gchar *password_hint;
|
|
|
889f5f |
gchar *home_dir;
|
|
|
889f5f |
gchar *shell;
|
|
|
889f5f |
gchar *email;
|
|
|
889f5f |
gchar *language;
|
|
|
889f5f |
gchar *x_session;
|
|
|
889f5f |
gchar *location;
|
|
|
889f5f |
guint64 login_frequency;
|
|
|
889f5f |
gint64 login_time;
|
|
|
889f5f |
GVariant *login_history;
|
|
|
889f5f |
gchar *icon_file;
|
|
|
889f5f |
gchar *default_icon_file;
|
|
|
889f5f |
gboolean locked;
|
|
|
889f5f |
gboolean automatic_login;
|
|
|
889f5f |
gboolean system_account;
|
|
|
889f5f |
gboolean local_account;
|
|
|
889f5f |
+ gboolean cached;
|
|
|
889f5f |
};
|
|
|
889f5f |
|
|
|
889f5f |
typedef struct UserClass
|
|
|
889f5f |
{
|
|
|
889f5f |
AccountsUserSkeletonClass parent_class;
|
|
|
889f5f |
} UserClass;
|
|
|
889f5f |
|
|
|
889f5f |
static void user_accounts_user_iface_init (AccountsUserIface *iface);
|
|
|
889f5f |
|
|
|
889f5f |
G_DEFINE_TYPE_WITH_CODE (User, user, ACCOUNTS_TYPE_USER_SKELETON, G_IMPLEMENT_INTERFACE (ACCOUNTS_TYPE_USER, user_accounts_user_iface_init));
|
|
|
889f5f |
|
|
|
889f5f |
static gint
|
|
|
889f5f |
account_type_from_pwent (struct passwd *pwent)
|
|
|
889f5f |
{
|
|
|
889f5f |
struct group *grp;
|
|
|
889f5f |
gint i;
|
|
|
889f5f |
|
|
|
889f5f |
if (pwent->pw_uid == 0) {
|
|
|
889f5f |
g_debug ("user is root so account type is administrator");
|
|
|
889f5f |
return ACCOUNT_TYPE_ADMINISTRATOR;
|
|
|
889f5f |
}
|
|
|
889f5f |
|
|
|
889f5f |
grp = getgrnam (ADMIN_GROUP);
|
|
|
889f5f |
if (grp == NULL) {
|
|
|
889f5f |
g_debug (ADMIN_GROUP " group not found");
|
|
|
889f5f |
return ACCOUNT_TYPE_STANDARD;
|
|
|
889f5f |
}
|
|
|
889f5f |
|
|
|
889f5f |
for (i = 0; grp->gr_mem[i] != NULL; i++) {
|
|
|
889f5f |
if (g_strcmp0 (grp->gr_mem[i], pwent->pw_name) == 0) {
|
|
|
889f5f |
@@ -323,109 +324,112 @@ user_update_from_keyfile (User *user,
|
|
|
889f5f |
user->location = s;
|
|
|
889f5f |
g_object_notify (G_OBJECT (user), "location");
|
|
|
889f5f |
}
|
|
|
889f5f |
|
|
|
889f5f |
s = g_key_file_get_string (keyfile, "User", "PasswordHint", NULL);
|
|
|
889f5f |
if (s != NULL) {
|
|
|
889f5f |
g_free (user->password_hint);
|
|
|
889f5f |
user->password_hint = s;
|
|
|
889f5f |
g_object_notify (G_OBJECT (user), "password-hint");
|
|
|
889f5f |
}
|
|
|
889f5f |
|
|
|
889f5f |
s = g_key_file_get_string (keyfile, "User", "Icon", NULL);
|
|
|
889f5f |
if (s != NULL) {
|
|
|
889f5f |
g_free (user->icon_file);
|
|
|
889f5f |
user->icon_file = s;
|
|
|
889f5f |
g_object_notify (G_OBJECT (user), "icon-file");
|
|
|
889f5f |
}
|
|
|
889f5f |
|
|
|
889f5f |
if (g_key_file_has_key (keyfile, "User", "SystemAccount", NULL)) {
|
|
|
889f5f |
gboolean system_account;
|
|
|
889f5f |
|
|
|
889f5f |
system_account = g_key_file_get_boolean (keyfile, "User", "SystemAccount", NULL);
|
|
|
889f5f |
if (system_account != user->system_account) {
|
|
|
889f5f |
user->system_account = system_account;
|
|
|
889f5f |
g_object_notify (G_OBJECT (user), "system-account");
|
|
|
889f5f |
}
|
|
|
889f5f |
}
|
|
|
889f5f |
|
|
|
889f5f |
g_clear_pointer (&user->keyfile, g_key_file_unref);
|
|
|
889f5f |
user->keyfile = g_key_file_ref (keyfile);
|
|
|
889f5f |
+ user_set_cached (user, TRUE);
|
|
|
889f5f |
|
|
|
889f5f |
g_object_thaw_notify (G_OBJECT (user));
|
|
|
889f5f |
}
|
|
|
889f5f |
|
|
|
889f5f |
void
|
|
|
889f5f |
user_update_local_account_property (User *user,
|
|
|
889f5f |
gboolean local)
|
|
|
889f5f |
{
|
|
|
889f5f |
if (local == user->local_account)
|
|
|
889f5f |
return;
|
|
|
889f5f |
user->local_account = local;
|
|
|
889f5f |
g_object_notify (G_OBJECT (user), "local-account");
|
|
|
889f5f |
}
|
|
|
889f5f |
|
|
|
889f5f |
void
|
|
|
889f5f |
user_update_system_account_property (User *user,
|
|
|
889f5f |
gboolean system)
|
|
|
889f5f |
{
|
|
|
889f5f |
if (system == user->system_account)
|
|
|
889f5f |
return;
|
|
|
889f5f |
user->system_account = system;
|
|
|
889f5f |
g_object_notify (G_OBJECT (user), "system-account");
|
|
|
889f5f |
}
|
|
|
889f5f |
|
|
|
889f5f |
static void
|
|
|
889f5f |
user_save_to_keyfile (User *user,
|
|
|
889f5f |
GKeyFile *keyfile)
|
|
|
889f5f |
{
|
|
|
889f5f |
g_key_file_remove_group (keyfile, "User", NULL);
|
|
|
889f5f |
|
|
|
889f5f |
if (user->email)
|
|
|
889f5f |
g_key_file_set_string (keyfile, "User", "Email", user->email);
|
|
|
889f5f |
|
|
|
889f5f |
if (user->language)
|
|
|
889f5f |
g_key_file_set_string (keyfile, "User", "Language", user->language);
|
|
|
889f5f |
|
|
|
889f5f |
if (user->x_session)
|
|
|
889f5f |
g_key_file_set_string (keyfile, "User", "XSession", user->x_session);
|
|
|
889f5f |
|
|
|
889f5f |
if (user->location)
|
|
|
889f5f |
g_key_file_set_string (keyfile, "User", "Location", user->location);
|
|
|
889f5f |
|
|
|
889f5f |
if (user->password_hint)
|
|
|
889f5f |
g_key_file_set_string (keyfile, "User", "PasswordHint", user->password_hint);
|
|
|
889f5f |
|
|
|
889f5f |
if (user->icon_file)
|
|
|
889f5f |
g_key_file_set_string (keyfile, "User", "Icon", user->icon_file);
|
|
|
889f5f |
|
|
|
889f5f |
g_key_file_set_boolean (keyfile, "User", "SystemAccount", user->system_account);
|
|
|
889f5f |
+
|
|
|
889f5f |
+ user_set_cached (user, TRUE);
|
|
|
889f5f |
}
|
|
|
889f5f |
|
|
|
889f5f |
static void
|
|
|
889f5f |
save_extra_data (User *user)
|
|
|
889f5f |
{
|
|
|
889f5f |
gchar *filename;
|
|
|
889f5f |
gchar *data;
|
|
|
889f5f |
GError *error;
|
|
|
889f5f |
|
|
|
889f5f |
user_save_to_keyfile (user, user->keyfile);
|
|
|
889f5f |
|
|
|
889f5f |
error = NULL;
|
|
|
889f5f |
data = g_key_file_to_data (user->keyfile, NULL, &error);
|
|
|
889f5f |
if (error == NULL) {
|
|
|
889f5f |
filename = g_build_filename (USERDIR,
|
|
|
889f5f |
user->user_name,
|
|
|
889f5f |
NULL);
|
|
|
889f5f |
g_file_set_contents (filename, data, -1, &error);
|
|
|
889f5f |
g_free (filename);
|
|
|
889f5f |
g_free (data);
|
|
|
889f5f |
}
|
|
|
889f5f |
if (error) {
|
|
|
889f5f |
g_warning ("Saving data for user %s failed: %s",
|
|
|
889f5f |
user->user_name, error->message);
|
|
|
889f5f |
g_error_free (error);
|
|
|
889f5f |
}
|
|
|
889f5f |
}
|
|
|
889f5f |
|
|
|
889f5f |
static void
|
|
|
889f5f |
move_extra_data (const gchar *old_name,
|
|
|
889f5f |
@@ -524,60 +528,73 @@ user_get_user_name (User *user)
|
|
|
889f5f |
gboolean
|
|
|
889f5f |
user_get_system_account (User *user)
|
|
|
889f5f |
{
|
|
|
889f5f |
return user->system_account;
|
|
|
889f5f |
}
|
|
|
889f5f |
|
|
|
889f5f |
gboolean
|
|
|
889f5f |
user_get_local_account (User *user)
|
|
|
889f5f |
{
|
|
|
889f5f |
return user->local_account;
|
|
|
889f5f |
}
|
|
|
889f5f |
|
|
|
889f5f |
const gchar *
|
|
|
889f5f |
user_get_object_path (User *user)
|
|
|
889f5f |
{
|
|
|
889f5f |
return user->object_path;
|
|
|
889f5f |
}
|
|
|
889f5f |
|
|
|
889f5f |
uid_t
|
|
|
889f5f |
user_get_uid (User *user)
|
|
|
889f5f |
{
|
|
|
889f5f |
return user->uid;
|
|
|
889f5f |
}
|
|
|
889f5f |
|
|
|
889f5f |
const gchar *
|
|
|
889f5f |
user_get_shell(User *user)
|
|
|
889f5f |
{
|
|
|
889f5f |
return user->shell;
|
|
|
889f5f |
}
|
|
|
889f5f |
|
|
|
889f5f |
+gboolean
|
|
|
889f5f |
+user_get_cached (User *user)
|
|
|
889f5f |
+{
|
|
|
889f5f |
+ return user->cached;
|
|
|
889f5f |
+}
|
|
|
889f5f |
+
|
|
|
889f5f |
+void
|
|
|
889f5f |
+user_set_cached (User *user,
|
|
|
889f5f |
+ gboolean cached)
|
|
|
889f5f |
+{
|
|
|
889f5f |
+ user->cached = cached;
|
|
|
889f5f |
+}
|
|
|
889f5f |
+
|
|
|
889f5f |
static void
|
|
|
889f5f |
throw_error (GDBusMethodInvocation *context,
|
|
|
889f5f |
gint error_code,
|
|
|
889f5f |
const gchar *format,
|
|
|
889f5f |
...)
|
|
|
889f5f |
{
|
|
|
889f5f |
va_list args;
|
|
|
889f5f |
gchar *message;
|
|
|
889f5f |
|
|
|
889f5f |
va_start (args, format);
|
|
|
889f5f |
message = g_strdup_vprintf (format, args);
|
|
|
889f5f |
va_end (args);
|
|
|
889f5f |
|
|
|
889f5f |
g_dbus_method_invocation_return_error (context, ERROR, error_code, "%s", message);
|
|
|
889f5f |
|
|
|
889f5f |
g_free (message);
|
|
|
889f5f |
}
|
|
|
889f5f |
|
|
|
889f5f |
static void
|
|
|
889f5f |
user_change_real_name_authorized_cb (Daemon *daemon,
|
|
|
889f5f |
User *user,
|
|
|
889f5f |
GDBusMethodInvocation *context,
|
|
|
889f5f |
gpointer data)
|
|
|
889f5f |
|
|
|
889f5f |
{
|
|
|
889f5f |
gchar *name = data;
|
|
|
889f5f |
GError *error;
|
|
|
889f5f |
const gchar *argv[6];
|
|
|
889f5f |
|
|
|
889f5f |
if (g_strcmp0 (user->real_name, name) != 0) {
|
|
|
889f5f |
diff --git a/src/user.h b/src/user.h
|
|
|
889f5f |
index 22548f9..39c6f13 100644
|
|
|
889f5f |
--- a/src/user.h
|
|
|
889f5f |
+++ b/src/user.h
|
|
|
889f5f |
@@ -36,47 +36,50 @@ G_BEGIN_DECLS
|
|
|
889f5f |
#define IS_USER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), TYPE_USER))
|
|
|
889f5f |
|
|
|
889f5f |
typedef enum {
|
|
|
889f5f |
ACCOUNT_TYPE_STANDARD,
|
|
|
889f5f |
ACCOUNT_TYPE_ADMINISTRATOR,
|
|
|
889f5f |
#define ACCOUNT_TYPE_LAST ACCOUNT_TYPE_ADMINISTRATOR
|
|
|
889f5f |
} AccountType;
|
|
|
889f5f |
|
|
|
889f5f |
typedef enum {
|
|
|
889f5f |
PASSWORD_MODE_REGULAR,
|
|
|
889f5f |
PASSWORD_MODE_SET_AT_LOGIN,
|
|
|
889f5f |
PASSWORD_MODE_NONE,
|
|
|
889f5f |
#define PASSWORD_MODE_LAST PASSWORD_MODE_NONE
|
|
|
889f5f |
} PasswordMode;
|
|
|
889f5f |
|
|
|
889f5f |
/* local methods */
|
|
|
889f5f |
|
|
|
889f5f |
GType user_get_type (void) G_GNUC_CONST;
|
|
|
889f5f |
User * user_new (Daemon *daemon,
|
|
|
889f5f |
uid_t uid);
|
|
|
889f5f |
|
|
|
889f5f |
void user_update_from_pwent (User *user,
|
|
|
889f5f |
struct passwd *pwent,
|
|
|
889f5f |
struct spwd *spent);
|
|
|
889f5f |
void user_update_from_keyfile (User *user,
|
|
|
889f5f |
GKeyFile *keyfile);
|
|
|
889f5f |
void user_update_local_account_property (User *user,
|
|
|
889f5f |
gboolean local);
|
|
|
889f5f |
void user_update_system_account_property (User *user,
|
|
|
889f5f |
gboolean system);
|
|
|
889f5f |
+gboolean user_get_cached (User *user);
|
|
|
889f5f |
+void user_set_cached (User *user,
|
|
|
889f5f |
+ gboolean cached);
|
|
|
889f5f |
|
|
|
889f5f |
void user_register (User *user);
|
|
|
889f5f |
void user_unregister (User *user);
|
|
|
889f5f |
void user_changed (User *user);
|
|
|
889f5f |
|
|
|
889f5f |
void user_save (User *user);
|
|
|
889f5f |
|
|
|
889f5f |
const gchar * user_get_user_name (User *user);
|
|
|
889f5f |
gboolean user_get_system_account (User *user);
|
|
|
889f5f |
gboolean user_get_local_account (User *user);
|
|
|
889f5f |
const gchar * user_get_object_path (User *user);
|
|
|
889f5f |
uid_t user_get_uid (User *user);
|
|
|
889f5f |
const gchar * user_get_shell (User *user);
|
|
|
889f5f |
|
|
|
889f5f |
G_END_DECLS
|
|
|
889f5f |
|
|
|
889f5f |
#endif
|
|
|
889f5f |
--
|
|
|
889f5f |
2.12.2
|
|
|
889f5f |
|