|
|
baf615 |
From dc41728b9c4ec35fb7bd41cdc646b77dcb41f6dd Mon Sep 17 00:00:00 2001
|
|
|
baf615 |
From: Ray Strode <rstrode@redhat.com>
|
|
|
baf615 |
Date: Mon, 2 Oct 2017 15:45:01 -0400
|
|
|
baf615 |
Subject: [PATCH 06/13] daemon: add new HasMultipleUsers and HasNoUsers
|
|
|
baf615 |
properties
|
|
|
baf615 |
|
|
|
baf615 |
Every gnome-shell instance wants to know if the system has multiple
|
|
|
baf615 |
users or not, in order to know whether or not to show the
|
|
|
baf615 |
'Switch User' feature in the menu.
|
|
|
baf615 |
|
|
|
baf615 |
accountsservice doesn't provide this information directly, though,
|
|
|
baf615 |
so libaccountsservice instead requests a list of all users on the
|
|
|
baf615 |
system and counts the provided list, filtering out system users.
|
|
|
baf615 |
|
|
|
baf615 |
This is a lot of work for every gnome-shell instance to do, when
|
|
|
baf615 |
it doesn't actually need the list of users at all.
|
|
|
baf615 |
|
|
|
baf615 |
This adds a new property HasMultipleUsers which libaccountsservice
|
|
|
baf615 |
can watch for instead. For good measure, this commit also adds a
|
|
|
baf615 |
HasNoUsers boolean which can be used to know whether or not to start
|
|
|
baf615 |
gnome-initial-setup.
|
|
|
baf615 |
---
|
|
|
baf615 |
data/org.freedesktop.Accounts.xml | 20 ++++++++++++++++++++
|
|
|
baf615 |
src/daemon.c | 24 +++++++++++++++++++++---
|
|
|
baf615 |
2 files changed, 41 insertions(+), 3 deletions(-)
|
|
|
baf615 |
|
|
|
baf615 |
diff --git a/data/org.freedesktop.Accounts.xml b/data/org.freedesktop.Accounts.xml
|
|
|
baf615 |
index 692540a..ed7db50 100644
|
|
|
baf615 |
--- a/data/org.freedesktop.Accounts.xml
|
|
|
baf615 |
+++ b/data/org.freedesktop.Accounts.xml
|
|
|
baf615 |
@@ -197,32 +197,52 @@
|
|
|
baf615 |
<doc:para>
|
|
|
baf615 |
Emitted when a user is added.
|
|
|
baf615 |
</doc:para>
|
|
|
baf615 |
</doc:description>
|
|
|
baf615 |
</doc:doc>
|
|
|
baf615 |
</signal>
|
|
|
baf615 |
|
|
|
baf615 |
<signal name="UserDeleted">
|
|
|
baf615 |
<arg name="user" type="o">
|
|
|
baf615 |
<doc:doc><doc:summary>Object path of the user that was deleted.</doc:summary></doc:doc>
|
|
|
baf615 |
</arg>
|
|
|
baf615 |
<doc:doc>
|
|
|
baf615 |
<doc:description>
|
|
|
baf615 |
<doc:para>
|
|
|
baf615 |
Emitted when a user is deleted.
|
|
|
baf615 |
</doc:para>
|
|
|
baf615 |
</doc:description>
|
|
|
baf615 |
</doc:doc>
|
|
|
baf615 |
</signal>
|
|
|
baf615 |
|
|
|
baf615 |
<property name="DaemonVersion" type="s" access="read">
|
|
|
baf615 |
<doc:doc>
|
|
|
baf615 |
<doc:description>
|
|
|
baf615 |
<doc:para>
|
|
|
baf615 |
The version of the running daemon.
|
|
|
baf615 |
</doc:para>
|
|
|
baf615 |
</doc:description>
|
|
|
baf615 |
</doc:doc>
|
|
|
baf615 |
</property>
|
|
|
baf615 |
|
|
|
baf615 |
+ <property name="HasNoUsers" type="b" access="read">
|
|
|
baf615 |
+ <doc:doc>
|
|
|
baf615 |
+ <doc:description>
|
|
|
baf615 |
+ <doc:para>
|
|
|
baf615 |
+ Whether or not the system has no users
|
|
|
baf615 |
+ </doc:para>
|
|
|
baf615 |
+ </doc:description>
|
|
|
baf615 |
+ </doc:doc>
|
|
|
baf615 |
+ </property>
|
|
|
baf615 |
+
|
|
|
baf615 |
+ <property name="HasMultipleUsers" type="b" access="read">
|
|
|
baf615 |
+ <doc:doc>
|
|
|
baf615 |
+ <doc:description>
|
|
|
baf615 |
+ <doc:para>
|
|
|
baf615 |
+ Whether or not the system has multiple users
|
|
|
baf615 |
+ </doc:para>
|
|
|
baf615 |
+ </doc:description>
|
|
|
baf615 |
+ </doc:doc>
|
|
|
baf615 |
+ </property>
|
|
|
baf615 |
+
|
|
|
baf615 |
</interface>
|
|
|
baf615 |
</node>
|
|
|
baf615 |
diff --git a/src/daemon.c b/src/daemon.c
|
|
|
baf615 |
index 6e3e4b3..a4e18df 100644
|
|
|
baf615 |
--- a/src/daemon.c
|
|
|
baf615 |
+++ b/src/daemon.c
|
|
|
baf615 |
@@ -35,60 +35,61 @@
|
|
|
baf615 |
#include <unistd.h>
|
|
|
baf615 |
#include <errno.h>
|
|
|
baf615 |
#include <sys/types.h>
|
|
|
baf615 |
|
|
|
baf615 |
#include <glib.h>
|
|
|
baf615 |
#include <glib/gi18n.h>
|
|
|
baf615 |
#include <glib-object.h>
|
|
|
baf615 |
#include <glib/gstdio.h>
|
|
|
baf615 |
#include <gio/gio.h>
|
|
|
baf615 |
#include <polkit/polkit.h>
|
|
|
baf615 |
|
|
|
baf615 |
#include "user-classify.h"
|
|
|
baf615 |
#include "wtmp-helper.h"
|
|
|
baf615 |
#include "daemon.h"
|
|
|
baf615 |
#include "util.h"
|
|
|
baf615 |
|
|
|
baf615 |
#define PATH_PASSWD "/etc/passwd"
|
|
|
baf615 |
#define PATH_SHADOW "/etc/shadow"
|
|
|
baf615 |
#define PATH_GROUP "/etc/group"
|
|
|
baf615 |
#define PATH_GDM_CUSTOM "/etc/gdm/custom.conf"
|
|
|
baf615 |
|
|
|
baf615 |
enum {
|
|
|
baf615 |
PROP_0,
|
|
|
baf615 |
PROP_DAEMON_VERSION
|
|
|
baf615 |
};
|
|
|
baf615 |
|
|
|
baf615 |
struct DaemonPrivate {
|
|
|
baf615 |
GDBusConnection *bus_connection;
|
|
|
baf615 |
|
|
|
baf615 |
GHashTable *users;
|
|
|
baf615 |
+ gsize number_of_normal_users;
|
|
|
baf615 |
GList *explicitly_requested_users;
|
|
|
baf615 |
|
|
|
baf615 |
User *autologin;
|
|
|
baf615 |
|
|
|
baf615 |
GFileMonitor *passwd_monitor;
|
|
|
baf615 |
GFileMonitor *shadow_monitor;
|
|
|
baf615 |
GFileMonitor *group_monitor;
|
|
|
baf615 |
GFileMonitor *gdm_monitor;
|
|
|
baf615 |
GFileMonitor *wtmp_monitor;
|
|
|
baf615 |
|
|
|
baf615 |
guint reload_id;
|
|
|
baf615 |
guint autologin_id;
|
|
|
baf615 |
|
|
|
baf615 |
PolkitAuthority *authority;
|
|
|
baf615 |
GHashTable *extension_ifaces;
|
|
|
baf615 |
};
|
|
|
baf615 |
|
|
|
baf615 |
typedef struct passwd * (* EntryGeneratorFunc) (Daemon *, GHashTable *, gpointer *, struct spwd **shadow_entry);
|
|
|
baf615 |
|
|
|
baf615 |
static void daemon_accounts_accounts_iface_init (AccountsAccountsIface *iface);
|
|
|
baf615 |
|
|
|
baf615 |
G_DEFINE_TYPE_WITH_CODE (Daemon, daemon, ACCOUNTS_TYPE_ACCOUNTS_SKELETON, G_IMPLEMENT_INTERFACE (ACCOUNTS_TYPE_ACCOUNTS, daemon_accounts_accounts_iface_init));
|
|
|
baf615 |
|
|
|
baf615 |
#define DAEMON_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_DAEMON, DaemonPrivate))
|
|
|
baf615 |
|
|
|
baf615 |
static const GDBusErrorEntry accounts_error_entries[] =
|
|
|
baf615 |
{
|
|
|
baf615 |
{ ERROR_FAILED, "org.freedesktop.Accounts.Error.Failed" },
|
|
|
baf615 |
{ ERROR_USER_EXISTS, "org.freedesktop.Accounts.Error.UserExists" },
|
|
|
baf615 |
{ ERROR_USER_DOES_NOT_EXIST, "org.freedesktop.Accounts.Error.UserDoesNotExist" },
|
|
|
baf615 |
@@ -395,98 +396,115 @@ load_entries (Daemon *daemon,
|
|
|
baf615 |
|
|
|
baf615 |
/* freeze & update users not already in the new list */
|
|
|
baf615 |
g_object_freeze_notify (G_OBJECT (user));
|
|
|
baf615 |
user_update_from_pwent (user, pwent, spent);
|
|
|
baf615 |
|
|
|
baf615 |
g_hash_table_insert (users, g_strdup (user_get_user_name (user)), user);
|
|
|
baf615 |
g_debug ("loaded user: %s", user_get_user_name (user));
|
|
|
baf615 |
}
|
|
|
baf615 |
|
|
|
baf615 |
if (!explicitly_requested) {
|
|
|
baf615 |
user_set_cached (user, TRUE);
|
|
|
baf615 |
}
|
|
|
baf615 |
}
|
|
|
baf615 |
|
|
|
baf615 |
/* Generator should have cleaned up */
|
|
|
baf615 |
g_assert (generator_state == NULL);
|
|
|
baf615 |
}
|
|
|
baf615 |
|
|
|
baf615 |
static GHashTable *
|
|
|
baf615 |
create_users_hash_table (void)
|
|
|
baf615 |
{
|
|
|
baf615 |
return g_hash_table_new_full (g_str_hash,
|
|
|
baf615 |
g_str_equal,
|
|
|
baf615 |
g_free,
|
|
|
baf615 |
g_object_unref);
|
|
|
baf615 |
}
|
|
|
baf615 |
|
|
|
baf615 |
static void
|
|
|
baf615 |
reload_users (Daemon *daemon)
|
|
|
baf615 |
{
|
|
|
baf615 |
+ AccountsAccounts *accounts = ACCOUNTS_ACCOUNTS (daemon);
|
|
|
baf615 |
+ gboolean had_no_users, has_no_users, had_multiple_users, has_multiple_users;
|
|
|
baf615 |
GHashTable *users;
|
|
|
baf615 |
GHashTable *old_users;
|
|
|
baf615 |
GHashTable *local;
|
|
|
baf615 |
GHashTableIter iter;
|
|
|
baf615 |
+ gsize number_of_normal_users = 0;
|
|
|
baf615 |
gpointer name;
|
|
|
baf615 |
User *user;
|
|
|
baf615 |
|
|
|
baf615 |
/* Track the users that we saw during our (re)load */
|
|
|
baf615 |
users = create_users_hash_table ();
|
|
|
baf615 |
|
|
|
baf615 |
/*
|
|
|
baf615 |
* NOTE: As we load data from all the sources, notifies are
|
|
|
baf615 |
* frozen in load_entries() and then thawed as we process
|
|
|
baf615 |
* them below.
|
|
|
baf615 |
*/
|
|
|
baf615 |
|
|
|
baf615 |
/* Load the local users into our hash table */
|
|
|
baf615 |
load_entries (daemon, users, FALSE, entry_generator_fgetpwent);
|
|
|
baf615 |
local = g_hash_table_new (g_str_hash, g_str_equal);
|
|
|
baf615 |
g_hash_table_iter_init (&iter, users);
|
|
|
baf615 |
while (g_hash_table_iter_next (&iter, &name, NULL))
|
|
|
baf615 |
g_hash_table_add (local, name);
|
|
|
baf615 |
|
|
|
baf615 |
/* and add users to hash table that were explicitly requested */
|
|
|
baf615 |
load_entries (daemon, users, TRUE, entry_generator_requested_users);
|
|
|
baf615 |
|
|
|
baf615 |
/* Now add/update users from other sources, possibly non-local */
|
|
|
baf615 |
load_entries (daemon, users, FALSE, entry_generator_cachedir);
|
|
|
baf615 |
|
|
|
baf615 |
wtmp_helper_update_login_frequencies (users);
|
|
|
baf615 |
|
|
|
baf615 |
- /* Mark which users are local, which are not */
|
|
|
baf615 |
+ /* Count the non-system users. Mark which users are local, which are not. */
|
|
|
baf615 |
g_hash_table_iter_init (&iter, users);
|
|
|
baf615 |
- while (g_hash_table_iter_next (&iter, &name, (gpointer *)&user))
|
|
|
baf615 |
+ while (g_hash_table_iter_next (&iter, &name, (gpointer *)&user)) {
|
|
|
baf615 |
+ if (!user_get_system_account (user))
|
|
|
baf615 |
+ number_of_normal_users++;
|
|
|
baf615 |
user_update_local_account_property (user, g_hash_table_lookup (local, name) != NULL);
|
|
|
baf615 |
-
|
|
|
baf615 |
+ }
|
|
|
baf615 |
g_hash_table_destroy (local);
|
|
|
baf615 |
|
|
|
baf615 |
+ had_no_users = accounts_accounts_get_has_no_users (accounts);
|
|
|
baf615 |
+ has_no_users = number_of_normal_users == 0;
|
|
|
baf615 |
+
|
|
|
baf615 |
+ if (had_no_users != has_no_users)
|
|
|
baf615 |
+ accounts_accounts_set_has_no_users (accounts, has_no_users);
|
|
|
baf615 |
+
|
|
|
baf615 |
+ had_multiple_users = accounts_accounts_get_has_multiple_users (accounts);
|
|
|
baf615 |
+ has_multiple_users = number_of_normal_users > 1;
|
|
|
baf615 |
+
|
|
|
baf615 |
+ if (had_multiple_users != has_multiple_users)
|
|
|
baf615 |
+ accounts_accounts_set_has_multiple_users (accounts, has_multiple_users);
|
|
|
baf615 |
+
|
|
|
baf615 |
/* Swap out the users */
|
|
|
baf615 |
old_users = daemon->priv->users;
|
|
|
baf615 |
daemon->priv->users = users;
|
|
|
baf615 |
|
|
|
baf615 |
/* Remove all the old users */
|
|
|
baf615 |
g_hash_table_iter_init (&iter, old_users);
|
|
|
baf615 |
while (g_hash_table_iter_next (&iter, &name, (gpointer *)&user)) {
|
|
|
baf615 |
User *refreshed_user;
|
|
|
baf615 |
|
|
|
baf615 |
refreshed_user = g_hash_table_lookup (users, name);
|
|
|
baf615 |
|
|
|
baf615 |
if (!refreshed_user || !user_get_cached (refreshed_user)) {
|
|
|
baf615 |
user_unregister (user);
|
|
|
baf615 |
accounts_accounts_emit_user_deleted (ACCOUNTS_ACCOUNTS (daemon),
|
|
|
baf615 |
user_get_object_path (user));
|
|
|
baf615 |
}
|
|
|
baf615 |
}
|
|
|
baf615 |
|
|
|
baf615 |
/* Register all the new users */
|
|
|
baf615 |
g_hash_table_iter_init (&iter, users);
|
|
|
baf615 |
while (g_hash_table_iter_next (&iter, &name, (gpointer *)&user)) {
|
|
|
baf615 |
User *stale_user;
|
|
|
baf615 |
|
|
|
baf615 |
stale_user = g_hash_table_lookup (old_users, name);
|
|
|
baf615 |
|
|
|
baf615 |
if (!stale_user || !user_get_cached (stale_user) && user_get_cached (user)) {
|
|
|
baf615 |
user_register (user);
|
|
|
baf615 |
accounts_accounts_emit_user_added (ACCOUNTS_ACCOUNTS (daemon),
|
|
|
baf615 |
user_get_object_path (user));
|
|
|
baf615 |
}
|
|
|
baf615 |
--
|
|
|
baf615 |
2.14.1
|
|
|
baf615 |
|