Compare commits
No commits in common. 'c9' and 'cs10' have entirely different histories.
@ -1 +1 @@
|
|||||||
bab4f37144196d8ba06195bc72b4a9937c62b9fd SOURCES/accountsservice-0.6.55.tar.xz
|
78419e5fa8fbb485f6b939e180fe26f2efc3c103 SOURCES/accountsservice-23.13.9.tar.xz
|
||||||
|
@ -1 +1 @@
|
|||||||
SOURCES/accountsservice-0.6.55.tar.xz
|
SOURCES/accountsservice-23.13.9.tar.xz
|
||||||
|
@ -1,304 +0,0 @@
|
|||||||
From 14c902f42a4ea74ce9450eb53817e1bf5be05d26 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Ray Strode <rstrode@redhat.com>
|
|
||||||
Date: Wed, 8 Sep 2021 16:38:17 -0400
|
|
||||||
Subject: [PATCH 1/2] daemon: Allow SystemAccount=false to be set in cache file
|
|
||||||
|
|
||||||
At the moment we do dodgy checks based on uid to decide whether or not
|
|
||||||
an account is a system account.
|
|
||||||
|
|
||||||
For legacy reasons, sometimes normal users have really low UIDs.
|
|
||||||
|
|
||||||
This commit reshuffles things, so the cache file "wins" for deciding
|
|
||||||
whether or not a user is a system user.
|
|
||||||
---
|
|
||||||
src/daemon.c | 24 ++++++++++++------------
|
|
||||||
1 file changed, 12 insertions(+), 12 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/src/daemon.c b/src/daemon.c
|
|
||||||
index 66ac7ba..2b6650b 100644
|
|
||||||
--- a/src/daemon.c
|
|
||||||
+++ b/src/daemon.c
|
|
||||||
@@ -219,60 +219,68 @@ entry_generator_fgetpwent (Daemon *daemon,
|
|
||||||
if (g_hash_table_size (shadow_users) == 0) {
|
|
||||||
g_clear_pointer (&shadow_users, g_hash_table_unref);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
fp = fopen (PATH_PASSWD, "r");
|
|
||||||
if (fp == NULL) {
|
|
||||||
g_clear_pointer (&shadow_users, g_hash_table_unref);
|
|
||||||
g_warning ("Unable to open %s: %s", PATH_PASSWD, g_strerror (errno));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
generator_state = g_malloc0 (sizeof (*generator_state));
|
|
||||||
generator_state->fp = fp;
|
|
||||||
generator_state->users = shadow_users;
|
|
||||||
|
|
||||||
*state = generator_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Every iteration */
|
|
||||||
generator_state = *state;
|
|
||||||
|
|
||||||
if (g_hash_table_size (users) < MAX_LOCAL_USERS) {
|
|
||||||
pwent = fgetpwent (generator_state->fp);
|
|
||||||
if (pwent != NULL) {
|
|
||||||
shadow_entry_buffers = g_hash_table_lookup (generator_state->users, pwent->pw_name);
|
|
||||||
|
|
||||||
if (shadow_entry_buffers != NULL) {
|
|
||||||
*spent = &shadow_entry_buffers->spbuf;
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+ /* Skip system users... */
|
|
||||||
+ if (!user_classify_is_human (pwent->pw_uid, pwent->pw_name, pwent->pw_shell, (*spent)? (*spent)->sp_pwdp : NULL)) {
|
|
||||||
+ g_debug ("skipping user: %s", pwent->pw_name);
|
|
||||||
+
|
|
||||||
+ return entry_generator_fgetpwent (daemon, users, state, spent);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
return pwent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Last iteration */
|
|
||||||
fclose (generator_state->fp);
|
|
||||||
g_hash_table_unref (generator_state->users);
|
|
||||||
g_free (generator_state);
|
|
||||||
*state = NULL;
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct passwd *
|
|
||||||
entry_generator_cachedir (Daemon *daemon,
|
|
||||||
GHashTable *users,
|
|
||||||
gpointer *state,
|
|
||||||
struct spwd **shadow_entry)
|
|
||||||
{
|
|
||||||
struct passwd *pwent;
|
|
||||||
g_autoptr(GError) error = NULL;
|
|
||||||
gboolean regular;
|
|
||||||
GHashTableIter iter;
|
|
||||||
gpointer key, value;
|
|
||||||
GDir *dir;
|
|
||||||
|
|
||||||
/* First iteration */
|
|
||||||
if (*state == NULL) {
|
|
||||||
*state = g_dir_open (USERDIR, 0, &error);
|
|
||||||
if (error != NULL) {
|
|
||||||
@@ -373,66 +381,60 @@ entry_generator_requested_users (Daemon *daemon,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Last iteration */
|
|
||||||
|
|
||||||
*state = NULL;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
load_entries (Daemon *daemon,
|
|
||||||
GHashTable *users,
|
|
||||||
gboolean explicitly_requested,
|
|
||||||
EntryGeneratorFunc entry_generator)
|
|
||||||
{
|
|
||||||
DaemonPrivate *priv = daemon_get_instance_private (daemon);
|
|
||||||
gpointer generator_state = NULL;
|
|
||||||
struct passwd *pwent;
|
|
||||||
struct spwd *spent = NULL;
|
|
||||||
User *user = NULL;
|
|
||||||
|
|
||||||
g_assert (entry_generator != NULL);
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
spent = NULL;
|
|
||||||
pwent = entry_generator (daemon, users, &generator_state, &spent);
|
|
||||||
if (pwent == NULL)
|
|
||||||
break;
|
|
||||||
|
|
||||||
- /* Skip system users... */
|
|
||||||
- if (!explicitly_requested && !user_classify_is_human (pwent->pw_uid, pwent->pw_name, pwent->pw_shell, spent? spent->sp_pwdp : NULL)) {
|
|
||||||
- g_debug ("skipping user: %s", pwent->pw_name);
|
|
||||||
- continue;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
/* Only process users that haven't been processed yet.
|
|
||||||
* We do always make sure entries get promoted
|
|
||||||
* to "cached" status if they are supposed to be
|
|
||||||
*/
|
|
||||||
|
|
||||||
user = g_hash_table_lookup (users, pwent->pw_name);
|
|
||||||
|
|
||||||
if (user == NULL) {
|
|
||||||
user = g_hash_table_lookup (priv->users, pwent->pw_name);
|
|
||||||
if (user == NULL) {
|
|
||||||
user = user_new (daemon, pwent->pw_uid);
|
|
||||||
} else {
|
|
||||||
g_object_ref (user);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* freeze & update users not already in the new list */
|
|
||||||
g_object_freeze_notify (G_OBJECT (user));
|
|
||||||
user_update_from_pwent (user, pwent, spent);
|
|
||||||
|
|
||||||
g_hash_table_insert (users, g_strdup (user_get_user_name (user)), user);
|
|
||||||
g_debug ("loaded user: %s", user_get_user_name (user));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!explicitly_requested) {
|
|
||||||
user_set_cached (user, TRUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Generator should have cleaned up */
|
|
||||||
g_assert (generator_state == NULL);
|
|
||||||
@@ -501,66 +503,66 @@ has_network_realms (Daemon *daemon)
|
|
||||||
|
|
||||||
static void
|
|
||||||
reload_users (Daemon *daemon)
|
|
||||||
{
|
|
||||||
DaemonPrivate *priv = daemon_get_instance_private (daemon);
|
|
||||||
AccountsAccounts *accounts = ACCOUNTS_ACCOUNTS (daemon);
|
|
||||||
gboolean had_no_users, has_no_users, had_multiple_users, has_multiple_users;
|
|
||||||
GHashTable *users;
|
|
||||||
GHashTable *old_users;
|
|
||||||
GHashTable *local;
|
|
||||||
GHashTableIter iter;
|
|
||||||
gsize number_of_normal_users = 0;
|
|
||||||
gpointer name, value;
|
|
||||||
|
|
||||||
/* Track the users that we saw during our (re)load */
|
|
||||||
users = create_users_hash_table ();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* NOTE: As we load data from all the sources, notifies are
|
|
||||||
* frozen in load_entries() and then thawed as we process
|
|
||||||
* them below.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Load the local users into our hash table */
|
|
||||||
load_entries (daemon, users, FALSE, entry_generator_fgetpwent);
|
|
||||||
local = g_hash_table_new (g_str_hash, g_str_equal);
|
|
||||||
g_hash_table_iter_init (&iter, users);
|
|
||||||
while (g_hash_table_iter_next (&iter, &name, NULL))
|
|
||||||
g_hash_table_add (local, name);
|
|
||||||
|
|
||||||
- /* and add users to hash table that were explicitly requested */
|
|
||||||
- load_entries (daemon, users, TRUE, entry_generator_requested_users);
|
|
||||||
-
|
|
||||||
/* Now add/update users from other sources, possibly non-local */
|
|
||||||
load_entries (daemon, users, FALSE, entry_generator_cachedir);
|
|
||||||
|
|
||||||
+ /* and add users to hash table that were explicitly requested */
|
|
||||||
+ load_entries (daemon, users, TRUE, entry_generator_requested_users);
|
|
||||||
+
|
|
||||||
wtmp_helper_update_login_frequencies (users);
|
|
||||||
|
|
||||||
/* Count the non-system users. Mark which users are local, which are not. */
|
|
||||||
g_hash_table_iter_init (&iter, users);
|
|
||||||
while (g_hash_table_iter_next (&iter, &name, &value)) {
|
|
||||||
User *user = value;
|
|
||||||
if (!user_get_system_account (user))
|
|
||||||
number_of_normal_users++;
|
|
||||||
user_update_local_account_property (user, g_hash_table_lookup (local, name) != NULL);
|
|
||||||
}
|
|
||||||
g_hash_table_destroy (local);
|
|
||||||
|
|
||||||
had_no_users = accounts_accounts_get_has_no_users (accounts);
|
|
||||||
has_no_users = number_of_normal_users == 0;
|
|
||||||
|
|
||||||
if (has_no_users && has_network_realms (daemon)) {
|
|
||||||
g_debug ("No local users, but network realms detected, presuming there are remote users");
|
|
||||||
has_no_users = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (had_no_users != has_no_users)
|
|
||||||
accounts_accounts_set_has_no_users (accounts, has_no_users);
|
|
||||||
|
|
||||||
had_multiple_users = accounts_accounts_get_has_multiple_users (accounts);
|
|
||||||
has_multiple_users = number_of_normal_users > 1;
|
|
||||||
|
|
||||||
if (had_multiple_users != has_multiple_users)
|
|
||||||
accounts_accounts_set_has_multiple_users (accounts, has_multiple_users);
|
|
||||||
|
|
||||||
/* Swap out the users */
|
|
||||||
@@ -1017,73 +1019,71 @@ daemon_find_user_by_name (AccountsAccounts *accounts,
|
|
||||||
|
|
||||||
static ListUserData *
|
|
||||||
list_user_data_new (Daemon *daemon,
|
|
||||||
GDBusMethodInvocation *context)
|
|
||||||
{
|
|
||||||
ListUserData *data;
|
|
||||||
|
|
||||||
data = g_new0 (ListUserData, 1);
|
|
||||||
|
|
||||||
data->daemon = g_object_ref (daemon);
|
|
||||||
data->context = context;
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
list_user_data_free (ListUserData *data)
|
|
||||||
{
|
|
||||||
g_object_unref (data->daemon);
|
|
||||||
g_free (data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
finish_list_cached_users (ListUserData *data)
|
|
||||||
{
|
|
||||||
DaemonPrivate *priv = daemon_get_instance_private (data->daemon);
|
|
||||||
g_autoptr(GPtrArray) object_paths = NULL;
|
|
||||||
GHashTableIter iter;
|
|
||||||
gpointer key, value;
|
|
||||||
uid_t uid;
|
|
||||||
- const gchar *shell;
|
|
||||||
|
|
||||||
object_paths = g_ptr_array_new ();
|
|
||||||
|
|
||||||
g_hash_table_iter_init (&iter, priv->users);
|
|
||||||
while (g_hash_table_iter_next (&iter, &key, &value)) {
|
|
||||||
const gchar *name = key;
|
|
||||||
User *user = value;
|
|
||||||
|
|
||||||
uid = user_get_uid (user);
|
|
||||||
- shell = user_get_shell (user);
|
|
||||||
|
|
||||||
- if (!user_classify_is_human (uid, name, shell, NULL)) {
|
|
||||||
+ if (user_get_system_account (user)) {
|
|
||||||
g_debug ("user %s %ld excluded", name, (long) uid);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!user_get_cached (user)) {
|
|
||||||
g_debug ("user %s %ld not cached", name, (long) uid);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_debug ("user %s %ld not excluded", name, (long) uid);
|
|
||||||
g_ptr_array_add (object_paths, (gpointer) user_get_object_path (user));
|
|
||||||
}
|
|
||||||
g_ptr_array_add (object_paths, NULL);
|
|
||||||
|
|
||||||
accounts_accounts_complete_list_cached_users (NULL, data->context, (const gchar * const *) object_paths->pdata);
|
|
||||||
|
|
||||||
list_user_data_free (data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
daemon_list_cached_users (AccountsAccounts *accounts,
|
|
||||||
GDBusMethodInvocation *context)
|
|
||||||
{
|
|
||||||
Daemon *daemon = (Daemon*)accounts;
|
|
||||||
DaemonPrivate *priv = daemon_get_instance_private (daemon);
|
|
||||||
ListUserData *data;
|
|
||||||
|
|
||||||
data = list_user_data_new (daemon, context);
|
|
||||||
|
|
||||||
if (priv->reload_id > 0) {
|
|
||||||
--
|
|
||||||
2.31.1
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
@ -1,88 +0,0 @@
|
|||||||
From 50edc5e45bb984576506e7b2bfb4c267ac566099 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Ray Strode <rstrode@redhat.com>
|
|
||||||
Date: Thu, 9 May 2019 14:58:34 -0400
|
|
||||||
Subject: [PATCH] data: don't send change updates for login-history
|
|
||||||
|
|
||||||
The login-history property of user objects can be quite large.
|
|
||||||
If wtmp is changed frequently, that can lead to memory fragmentation
|
|
||||||
in clients.
|
|
||||||
|
|
||||||
Furthermore, most clients never check login-history, so it's
|
|
||||||
wasted memory and wasted cpu.
|
|
||||||
|
|
||||||
This commit disables change notification for that property. If
|
|
||||||
a client really needs to get updates, they can manually refresh
|
|
||||||
their cache when appropriate.
|
|
||||||
---
|
|
||||||
data/org.freedesktop.Accounts.User.xml | 1 +
|
|
||||||
1 file changed, 1 insertion(+)
|
|
||||||
|
|
||||||
diff --git a/data/org.freedesktop.Accounts.User.xml b/data/org.freedesktop.Accounts.User.xml
|
|
||||||
index 8d3fe1c..3b839a3 100644
|
|
||||||
--- a/data/org.freedesktop.Accounts.User.xml
|
|
||||||
+++ b/data/org.freedesktop.Accounts.User.xml
|
|
||||||
@@ -785,60 +785,61 @@
|
|
||||||
<doc:doc>
|
|
||||||
<doc:description>
|
|
||||||
<doc:para>
|
|
||||||
The users location.
|
|
||||||
</doc:para>
|
|
||||||
</doc:description>
|
|
||||||
</doc:doc>
|
|
||||||
</property>
|
|
||||||
|
|
||||||
<property name="LoginFrequency" type="t" access="read">
|
|
||||||
<doc:doc>
|
|
||||||
<doc:description>
|
|
||||||
<doc:para>
|
|
||||||
How often the user has logged in.
|
|
||||||
</doc:para>
|
|
||||||
</doc:description>
|
|
||||||
</doc:doc>
|
|
||||||
</property>
|
|
||||||
|
|
||||||
<property name="LoginTime" type="x" access="read">
|
|
||||||
<doc:doc>
|
|
||||||
<doc:description>
|
|
||||||
<doc:para>
|
|
||||||
The last login time.
|
|
||||||
</doc:para>
|
|
||||||
</doc:description>
|
|
||||||
</doc:doc>
|
|
||||||
</property>
|
|
||||||
|
|
||||||
<property name="LoginHistory" type="a(xxa{sv})" access="read">
|
|
||||||
+ <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
|
|
||||||
<doc:doc>
|
|
||||||
<doc:description>
|
|
||||||
<doc:para>
|
|
||||||
The login history for this user.
|
|
||||||
Each entry in the array represents a login session. The first two
|
|
||||||
members are the login time and logout time, as timestamps (seconds since the epoch). If the session is still running, the logout time
|
|
||||||
is 0.
|
|
||||||
</doc:para>
|
|
||||||
<doc:para>
|
|
||||||
The a{sv} member is a dictionary containing additional information
|
|
||||||
about the session. Possible members include 'type' (with values like ':0', 'tty0', 'pts/0' etc).
|
|
||||||
</doc:para>
|
|
||||||
</doc:description>
|
|
||||||
</doc:doc>
|
|
||||||
</property>
|
|
||||||
|
|
||||||
<property name="IconFile" type="s" access="read">
|
|
||||||
<doc:doc>
|
|
||||||
<doc:description>
|
|
||||||
<doc:para>
|
|
||||||
The filename of a png file containing the users icon.
|
|
||||||
</doc:para>
|
|
||||||
</doc:description>
|
|
||||||
</doc:doc>
|
|
||||||
</property>
|
|
||||||
|
|
||||||
<property name="Saved" type="b" access="read">
|
|
||||||
<doc:doc>
|
|
||||||
<doc:description>
|
|
||||||
<doc:para>
|
|
||||||
--
|
|
||||||
2.27.0
|
|
||||||
|
|
@ -1,894 +0,0 @@
|
|||||||
From 5124220f12a157ff285072a4f786db2c94c3ca8a Mon Sep 17 00:00:00 2001
|
|
||||||
From: Ray Strode <rstrode@redhat.com>
|
|
||||||
Date: Thu, 14 Jan 2021 15:07:34 -0500
|
|
||||||
Subject: [PATCH] lib: save os when creating user
|
|
||||||
|
|
||||||
In order to identify that a user has upgraded from rhel 7 to
|
|
||||||
rhel 8, we need to know what os they were using when created.
|
|
||||||
|
|
||||||
This commit saves that information using a red hat specific
|
|
||||||
extension to accountsservice.
|
|
||||||
---
|
|
||||||
.../com.redhat.AccountsServiceUser.System.xml | 10 ++
|
|
||||||
data/meson.build | 1 +
|
|
||||||
meson.build | 1 +
|
|
||||||
meson_post_install.py | 15 +++
|
|
||||||
src/libaccountsservice/act-user-manager.c | 123 ++++++++++++++++++
|
|
||||||
src/libaccountsservice/meson.build | 7 +
|
|
||||||
6 files changed, 157 insertions(+)
|
|
||||||
create mode 100644 data/com.redhat.AccountsServiceUser.System.xml
|
|
||||||
|
|
||||||
diff --git a/data/com.redhat.AccountsServiceUser.System.xml b/data/com.redhat.AccountsServiceUser.System.xml
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000..67f5f30
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/data/com.redhat.AccountsServiceUser.System.xml
|
|
||||||
@@ -0,0 +1,10 @@
|
|
||||||
+<node>
|
|
||||||
+ <interface name="com.redhat.AccountsServiceUser.System">
|
|
||||||
+
|
|
||||||
+ <annotation name="org.freedesktop.Accounts.VendorExtension" value="true"/>
|
|
||||||
+
|
|
||||||
+ <property name="id" type="s" access="readwrite"/>
|
|
||||||
+ <property name="version-id" type="s" access="readwrite"/>
|
|
||||||
+
|
|
||||||
+ </interface>
|
|
||||||
+</node>
|
|
||||||
diff --git a/data/meson.build b/data/meson.build
|
|
||||||
index 4987937..2dc57c2 100644
|
|
||||||
--- a/data/meson.build
|
|
||||||
+++ b/data/meson.build
|
|
||||||
@@ -1,33 +1,34 @@
|
|
||||||
ifaces = files(
|
|
||||||
act_namespace + '.xml',
|
|
||||||
act_namespace + '.User.xml',
|
|
||||||
+ 'com.redhat.AccountsServiceUser.System.xml',
|
|
||||||
)
|
|
||||||
|
|
||||||
install_data(
|
|
||||||
ifaces,
|
|
||||||
install_dir: dbus_ifaces_dir,
|
|
||||||
)
|
|
||||||
|
|
||||||
install_data(
|
|
||||||
act_namespace + '.conf',
|
|
||||||
install_dir: dbus_conf_dir,
|
|
||||||
)
|
|
||||||
|
|
||||||
service_conf = configuration_data()
|
|
||||||
service_conf.set('libexecdir', act_libexecdir)
|
|
||||||
|
|
||||||
service = act_namespace + '.service'
|
|
||||||
|
|
||||||
configure_file(
|
|
||||||
input: service + '.in',
|
|
||||||
output: service,
|
|
||||||
configuration: service_conf,
|
|
||||||
install: true,
|
|
||||||
install_dir: dbus_sys_dir,
|
|
||||||
)
|
|
||||||
|
|
||||||
policy = act_namespace.to_lower() + '.policy'
|
|
||||||
|
|
||||||
i18n.merge_file(
|
|
||||||
policy,
|
|
||||||
input: policy + '.in',
|
|
||||||
diff --git a/meson.build b/meson.build
|
|
||||||
index 4465a26..e37c451 100644
|
|
||||||
--- a/meson.build
|
|
||||||
+++ b/meson.build
|
|
||||||
@@ -174,38 +174,39 @@ assert(not enable_systemd or not enable_elogind, 'systemd and elogind support re
|
|
||||||
if enable_systemd
|
|
||||||
logind_dep = dependency('libsystemd', version: '>= 186')
|
|
||||||
endif
|
|
||||||
|
|
||||||
if enable_elogind
|
|
||||||
logind_dep = dependency('libelogind', version: '>= 229.4')
|
|
||||||
endif
|
|
||||||
config_h.set('WITH_SYSTEMD', enable_systemd or enable_elogind)
|
|
||||||
|
|
||||||
subdir('data')
|
|
||||||
subdir('src')
|
|
||||||
subdir('po')
|
|
||||||
|
|
||||||
enable_docbook = get_option('docbook')
|
|
||||||
if enable_docbook
|
|
||||||
subdir('doc/dbus')
|
|
||||||
endif
|
|
||||||
|
|
||||||
if get_option('gtk_doc')
|
|
||||||
subdir('doc/libaccountsservice')
|
|
||||||
endif
|
|
||||||
|
|
||||||
configure_file(
|
|
||||||
output: 'config.h',
|
|
||||||
configuration: config_h,
|
|
||||||
)
|
|
||||||
|
|
||||||
meson.add_install_script(
|
|
||||||
'meson_post_install.py',
|
|
||||||
act_localstatedir,
|
|
||||||
+ act_datadir,
|
|
||||||
)
|
|
||||||
|
|
||||||
output = '\n' + meson.project_name() + ' was configured with the following options:\n'
|
|
||||||
output += '** DocBook documentation build: ' + enable_docbook.to_string() + '\n'
|
|
||||||
output += '** Administrator group: ' + admin_group + '\n'
|
|
||||||
output += '** Extra administrator groups: ' + extra_admin_groups + '\n'
|
|
||||||
output += '** GDM configuration: ' + gdm_conf_file
|
|
||||||
message(output)
|
|
||||||
diff --git a/meson_post_install.py b/meson_post_install.py
|
|
||||||
index 5cc2dc4..e1d5a71 100644
|
|
||||||
--- a/meson_post_install.py
|
|
||||||
+++ b/meson_post_install.py
|
|
||||||
@@ -1,18 +1,33 @@
|
|
||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
destdir = os.environ.get('DESTDIR', '')
|
|
||||||
localstatedir = os.path.normpath(destdir + os.sep + sys.argv[1])
|
|
||||||
+datadir = os.path.normpath(destdir + os.sep + sys.argv[2])
|
|
||||||
+interfacedir = os.path.join(datadir, 'accountsservice', 'interfaces')
|
|
||||||
|
|
||||||
# FIXME: meson will not track the creation of these directories
|
|
||||||
# https://github.com/mesonbuild/meson/blob/master/mesonbuild/scripts/uninstall.py#L39
|
|
||||||
dst_dirs = [
|
|
||||||
(os.path.join(localstatedir, 'lib', 'AccountsService', 'icons'), 0o775),
|
|
||||||
(os.path.join(localstatedir, 'lib', 'AccountsService', 'users'), 0o700),
|
|
||||||
+ (interfacedir, 0o775),
|
|
||||||
]
|
|
||||||
|
|
||||||
for (dst_dir, dst_dir_mode) in dst_dirs:
|
|
||||||
if not os.path.exists(dst_dir):
|
|
||||||
os.makedirs(dst_dir, mode=dst_dir_mode)
|
|
||||||
+
|
|
||||||
+interface_files = [
|
|
||||||
+ 'com.redhat.AccountsServiceUser.System.xml',
|
|
||||||
+]
|
|
||||||
+
|
|
||||||
+for interface_file in interface_files:
|
|
||||||
+ src_path = os.path.join('../../dbus-1/interfaces', interface_file)
|
|
||||||
+ dst_path = os.path.join(interfacedir, interface_file)
|
|
||||||
+ if not os.path.exists(dst_path):
|
|
||||||
+ os.symlink(src_path, dst_path)
|
|
||||||
+
|
|
||||||
+
|
|
||||||
diff --git a/src/libaccountsservice/act-user-manager.c b/src/libaccountsservice/act-user-manager.c
|
|
||||||
index 1b5298d..f4598c4 100644
|
|
||||||
--- a/src/libaccountsservice/act-user-manager.c
|
|
||||||
+++ b/src/libaccountsservice/act-user-manager.c
|
|
||||||
@@ -27,60 +27,61 @@
|
|
||||||
#include <string.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
#ifdef HAVE_PATHS_H
|
|
||||||
#include <paths.h>
|
|
||||||
#endif /* HAVE_PATHS_H */
|
|
||||||
|
|
||||||
#include <glib.h>
|
|
||||||
#include <glib/gi18n-lib.h>
|
|
||||||
#include <glib/gstdio.h>
|
|
||||||
#include <glib-object.h>
|
|
||||||
#include <gio/gio.h>
|
|
||||||
#include <gio/gunixinputstream.h>
|
|
||||||
|
|
||||||
#ifdef WITH_SYSTEMD
|
|
||||||
#include <systemd/sd-login.h>
|
|
||||||
|
|
||||||
/* check if logind is running */
|
|
||||||
#define LOGIND_RUNNING() (access("/run/systemd/seats/", F_OK) >= 0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "act-user-manager.h"
|
|
||||||
#include "act-user-private.h"
|
|
||||||
#include "accounts-generated.h"
|
|
||||||
#include "ck-manager-generated.h"
|
|
||||||
#include "ck-seat-generated.h"
|
|
||||||
#include "ck-session-generated.h"
|
|
||||||
+#include "com.redhat.AccountsServiceUser.System.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SECTION:act-user-manager
|
|
||||||
* @title: ActUserManager
|
|
||||||
* @short_description: manages ActUser objects
|
|
||||||
*
|
|
||||||
* ActUserManager is a manager object that gives access to user
|
|
||||||
* creation, deletion, enumeration, etc.
|
|
||||||
*
|
|
||||||
* There is typically a singleton ActUserManager object, which
|
|
||||||
* can be obtained by act_user_manager_get_default().
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ActUserManager:
|
|
||||||
*
|
|
||||||
* A user manager object.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ACT_USER_MANAGER_ERROR:
|
|
||||||
*
|
|
||||||
* The GError domain for #ActUserManagerError errors
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ActUserManagerError:
|
|
||||||
* @ACT_USER_MANAGER_ERROR_FAILED: Generic failure
|
|
||||||
* @ACT_USER_MANAGER_ERROR_USER_EXISTS: The user already exists
|
|
||||||
* @ACT_USER_MANAGER_ERROR_USER_DOES_NOT_EXIST: The user does not exist
|
|
||||||
@@ -165,60 +166,63 @@ typedef struct
|
|
||||||
ActUser *user;
|
|
||||||
ActUserManagerFetchUserRequestType type;
|
|
||||||
union {
|
|
||||||
char *username;
|
|
||||||
uid_t uid;
|
|
||||||
};
|
|
||||||
char *object_path;
|
|
||||||
char *description;
|
|
||||||
} ActUserManagerFetchUserRequest;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
GHashTable *normal_users_by_name;
|
|
||||||
GHashTable *system_users_by_name;
|
|
||||||
GHashTable *users_by_object_path;
|
|
||||||
GHashTable *sessions;
|
|
||||||
GDBusConnection *connection;
|
|
||||||
AccountsAccounts *accounts_proxy;
|
|
||||||
ConsoleKitManager *ck_manager_proxy;
|
|
||||||
|
|
||||||
ActUserManagerSeat seat;
|
|
||||||
|
|
||||||
GSList *new_sessions;
|
|
||||||
GSList *new_users;
|
|
||||||
GSList *new_users_inhibiting_load;
|
|
||||||
GSList *fetch_user_requests;
|
|
||||||
|
|
||||||
GSList *exclude_usernames;
|
|
||||||
GSList *include_usernames;
|
|
||||||
|
|
||||||
+ char *os_id;
|
|
||||||
+ char *os_version_id;
|
|
||||||
+
|
|
||||||
guint load_id;
|
|
||||||
|
|
||||||
gboolean is_loaded;
|
|
||||||
gboolean has_multiple_users;
|
|
||||||
gboolean getting_sessions;
|
|
||||||
gboolean list_cached_users_done;
|
|
||||||
} ActUserManagerPrivate;
|
|
||||||
|
|
||||||
enum {
|
|
||||||
PROP_0,
|
|
||||||
PROP_INCLUDE_USERNAMES_LIST,
|
|
||||||
PROP_EXCLUDE_USERNAMES_LIST,
|
|
||||||
PROP_IS_LOADED,
|
|
||||||
PROP_HAS_MULTIPLE_USERS
|
|
||||||
};
|
|
||||||
|
|
||||||
enum {
|
|
||||||
USER_ADDED,
|
|
||||||
USER_REMOVED,
|
|
||||||
USER_IS_LOGGED_IN_CHANGED,
|
|
||||||
USER_CHANGED,
|
|
||||||
LAST_SIGNAL
|
|
||||||
};
|
|
||||||
|
|
||||||
static guint signals [LAST_SIGNAL] = { 0, };
|
|
||||||
|
|
||||||
static void act_user_manager_class_init (ActUserManagerClass *klass);
|
|
||||||
static void act_user_manager_init (ActUserManager *user_manager);
|
|
||||||
static void act_user_manager_finalize (GObject *object);
|
|
||||||
|
|
||||||
@@ -2942,100 +2946,173 @@ ensure_accounts_proxy (ActUserManager *manager)
|
|
||||||
G_DBUS_PROXY_FLAGS_NONE,
|
|
||||||
ACCOUNTS_NAME,
|
|
||||||
ACCOUNTS_PATH,
|
|
||||||
NULL,
|
|
||||||
&error);
|
|
||||||
if (error != NULL) {
|
|
||||||
g_debug ("ActUserManager: getting account proxy failed: %s", error->message);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (priv->accounts_proxy), G_MAXINT);
|
|
||||||
|
|
||||||
g_object_bind_property (G_OBJECT (priv->accounts_proxy),
|
|
||||||
"has-multiple-users",
|
|
||||||
G_OBJECT (manager),
|
|
||||||
"has-multiple-users",
|
|
||||||
G_BINDING_SYNC_CREATE);
|
|
||||||
|
|
||||||
g_signal_connect (priv->accounts_proxy,
|
|
||||||
"user-added",
|
|
||||||
G_CALLBACK (on_new_user_in_accounts_service),
|
|
||||||
manager);
|
|
||||||
g_signal_connect (priv->accounts_proxy,
|
|
||||||
"user-deleted",
|
|
||||||
G_CALLBACK (on_user_removed_in_accounts_service),
|
|
||||||
manager);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
+static inline gboolean
|
|
||||||
+is_valid_char (gchar c,
|
|
||||||
+ gboolean first)
|
|
||||||
+{
|
|
||||||
+ return (!first && g_ascii_isdigit (c)) ||
|
|
||||||
+ c == '_' ||
|
|
||||||
+ g_ascii_isalpha (c);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+load_os_release (ActUserManager *manager)
|
|
||||||
+{
|
|
||||||
+ ActUserManagerPrivate *priv = act_user_manager_get_instance_private (manager);
|
|
||||||
+ g_autoptr(GFile) file = NULL;
|
|
||||||
+ g_autoptr(GError) error = NULL;
|
|
||||||
+ g_autofree char *contents = NULL;
|
|
||||||
+ g_auto(GStrv) lines = NULL;
|
|
||||||
+ size_t i;
|
|
||||||
+
|
|
||||||
+ file = g_file_new_for_path ("/etc/os-release");
|
|
||||||
+
|
|
||||||
+ if (!g_file_load_contents (file, NULL, &contents, NULL, NULL, &error)) {
|
|
||||||
+ g_debug ("ActUserManager: couldn't load /etc/os-release: %s", error->message);
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ lines = g_strsplit (contents, "\n", -1);
|
|
||||||
+ for (i = 0; lines[i] != NULL; i++) {
|
|
||||||
+ char *p, *name, *name_end, *value, *value_end;
|
|
||||||
+
|
|
||||||
+ p = lines[i];
|
|
||||||
+
|
|
||||||
+ while (g_ascii_isspace (*p))
|
|
||||||
+ p++;
|
|
||||||
+
|
|
||||||
+ if (*p == '#' || *p == '\0')
|
|
||||||
+ continue;
|
|
||||||
+ name = p;
|
|
||||||
+ while (is_valid_char (*p, p == name))
|
|
||||||
+ p++;
|
|
||||||
+ name_end = p;
|
|
||||||
+ while (g_ascii_isspace (*p))
|
|
||||||
+ p++;
|
|
||||||
+ if (name == name_end || *p != '=') {
|
|
||||||
+ continue;
|
|
||||||
+ }
|
|
||||||
+ *name_end = '\0';
|
|
||||||
+
|
|
||||||
+ p++;
|
|
||||||
+
|
|
||||||
+ while (g_ascii_isspace (*p))
|
|
||||||
+ p++;
|
|
||||||
+
|
|
||||||
+ value = p;
|
|
||||||
+ value_end = value + strlen (value) - 1;
|
|
||||||
+
|
|
||||||
+ if (value != value_end && *value == '"' && *value_end == '"') {
|
|
||||||
+ value++;
|
|
||||||
+ *value_end = '\0';
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (strcmp (name, "ID") == 0) {
|
|
||||||
+ g_debug ("ActUserManager: system OS is '%s'", value);
|
|
||||||
+ priv->os_id = g_strdup (value);
|
|
||||||
+ } else if (strcmp (name, "VERSION_ID") == 0) {
|
|
||||||
+ g_debug ("ActUserManager: system OS version is '%s'", value);
|
|
||||||
+ priv->os_version_id = g_strdup (value);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static void
|
|
||||||
act_user_manager_init (ActUserManager *manager)
|
|
||||||
{
|
|
||||||
ActUserManagerPrivate *priv = act_user_manager_get_instance_private (manager);
|
|
||||||
g_autoptr(GError) error = NULL;
|
|
||||||
|
|
||||||
act_user_manager_error_quark (); /* register dbus errors */
|
|
||||||
|
|
||||||
/* sessions */
|
|
||||||
priv->sessions = g_hash_table_new_full (g_str_hash,
|
|
||||||
g_str_equal,
|
|
||||||
g_free,
|
|
||||||
g_object_unref);
|
|
||||||
|
|
||||||
/* users */
|
|
||||||
priv->normal_users_by_name = g_hash_table_new_full (g_str_hash,
|
|
||||||
g_str_equal,
|
|
||||||
g_free,
|
|
||||||
g_object_unref);
|
|
||||||
priv->system_users_by_name = g_hash_table_new_full (g_str_hash,
|
|
||||||
g_str_equal,
|
|
||||||
g_free,
|
|
||||||
g_object_unref);
|
|
||||||
priv->users_by_object_path = g_hash_table_new_full (g_str_hash,
|
|
||||||
g_str_equal,
|
|
||||||
NULL,
|
|
||||||
g_object_unref);
|
|
||||||
|
|
||||||
priv->connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
|
|
||||||
if (priv->connection == NULL) {
|
|
||||||
if (error != NULL) {
|
|
||||||
g_warning ("Failed to connect to the D-Bus daemon: %s", error->message);
|
|
||||||
} else {
|
|
||||||
g_warning ("Failed to connect to the D-Bus daemon");
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ensure_accounts_proxy (manager);
|
|
||||||
|
|
||||||
+ load_os_release (manager);
|
|
||||||
+
|
|
||||||
priv->seat.state = ACT_USER_MANAGER_SEAT_STATE_UNLOADED;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
act_user_manager_finalize (GObject *object)
|
|
||||||
{
|
|
||||||
ActUserManager *manager = ACT_USER_MANAGER (object);
|
|
||||||
ActUserManagerPrivate *priv = act_user_manager_get_instance_private (manager);
|
|
||||||
GSList *node;
|
|
||||||
|
|
||||||
g_debug ("ActUserManager: finalizing user manager");
|
|
||||||
|
|
||||||
g_slist_foreach (priv->new_sessions,
|
|
||||||
(GFunc) unload_new_session, NULL);
|
|
||||||
g_slist_free (priv->new_sessions);
|
|
||||||
|
|
||||||
g_slist_foreach (priv->fetch_user_requests,
|
|
||||||
(GFunc) free_fetch_user_request, NULL);
|
|
||||||
g_slist_free (priv->fetch_user_requests);
|
|
||||||
|
|
||||||
g_slist_free (priv->new_users_inhibiting_load);
|
|
||||||
|
|
||||||
node = priv->new_users;
|
|
||||||
while (node != NULL) {
|
|
||||||
ActUser *user;
|
|
||||||
GSList *next_node;
|
|
||||||
|
|
||||||
user = ACT_USER (node->data);
|
|
||||||
next_node = node->next;
|
|
||||||
|
|
||||||
@@ -3071,143 +3148,181 @@ act_user_manager_finalize (GObject *object)
|
|
||||||
|
|
||||||
#ifdef WITH_SYSTEMD
|
|
||||||
if (priv->seat.session_monitor != NULL) {
|
|
||||||
sd_login_monitor_unref (priv->seat.session_monitor);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (priv->seat.session_monitor_stream != NULL) {
|
|
||||||
g_object_unref (priv->seat.session_monitor_stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (priv->seat.session_monitor_source_id != 0) {
|
|
||||||
g_source_remove (priv->seat.session_monitor_source_id);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (priv->accounts_proxy != NULL) {
|
|
||||||
g_object_unref (priv->accounts_proxy);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (priv->load_id > 0) {
|
|
||||||
g_source_remove (priv->load_id);
|
|
||||||
priv->load_id = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_hash_table_destroy (priv->sessions);
|
|
||||||
|
|
||||||
g_hash_table_destroy (priv->normal_users_by_name);
|
|
||||||
g_hash_table_destroy (priv->system_users_by_name);
|
|
||||||
g_hash_table_destroy (priv->users_by_object_path);
|
|
||||||
|
|
||||||
+ g_free (priv->os_id);
|
|
||||||
+ g_free (priv->os_version_id);
|
|
||||||
+
|
|
||||||
G_OBJECT_CLASS (act_user_manager_parent_class)->finalize (object);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* act_user_manager_get_default:
|
|
||||||
*
|
|
||||||
* Returns the user manager singleton instance. Calling this function will
|
|
||||||
* automatically being loading the user list if it isn't loaded already.
|
|
||||||
* The #ActUserManager:is-loaded property will be set to %TRUE when the users
|
|
||||||
* are finished loading and then act_user_manager_list_users() can be called.
|
|
||||||
*
|
|
||||||
* Returns: (transfer none): user manager object
|
|
||||||
*/
|
|
||||||
ActUserManager *
|
|
||||||
act_user_manager_get_default (void)
|
|
||||||
{
|
|
||||||
if (user_manager_object == NULL) {
|
|
||||||
user_manager_object = g_object_new (ACT_TYPE_USER_MANAGER, NULL);
|
|
||||||
g_object_add_weak_pointer (user_manager_object,
|
|
||||||
(gpointer *) &user_manager_object);
|
|
||||||
act_user_manager_queue_load (user_manager_object);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ACT_USER_MANAGER (user_manager_object);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* act_user_manager_no_service:
|
|
||||||
* @manager: a #ActUserManager
|
|
||||||
*
|
|
||||||
* Check whether or not the accounts service is running.
|
|
||||||
*
|
|
||||||
* Returns: whether or not accounts service is running
|
|
||||||
*/
|
|
||||||
gboolean
|
|
||||||
act_user_manager_no_service (ActUserManager *manager)
|
|
||||||
{
|
|
||||||
ActUserManagerPrivate *priv = act_user_manager_get_instance_private (manager);
|
|
||||||
return priv->accounts_proxy == NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
+static void
|
|
||||||
+save_system_info (ActUserManager *manager,
|
|
||||||
+ const char *user_path)
|
|
||||||
+{
|
|
||||||
+ ActUserManagerPrivate *priv = act_user_manager_get_instance_private (manager);
|
|
||||||
+ ActUserSystem *user_system_proxy = NULL;
|
|
||||||
+ g_autoptr(GError) error = NULL;
|
|
||||||
+
|
|
||||||
+ if (priv->os_id == NULL && priv->os_version_id == NULL)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ user_system_proxy = act_user_system_proxy_new_sync (priv->connection,
|
|
||||||
+ G_DBUS_PROXY_FLAGS_NONE,
|
|
||||||
+ ACCOUNTS_NAME,
|
|
||||||
+ user_path,
|
|
||||||
+ NULL,
|
|
||||||
+ &error);
|
|
||||||
+ if (user_system_proxy != NULL) {
|
|
||||||
+ if (priv->os_id != NULL)
|
|
||||||
+ act_user_system_set_id (user_system_proxy, priv->os_id);
|
|
||||||
+
|
|
||||||
+ if (priv->os_version_id != NULL)
|
|
||||||
+ act_user_system_set_version_id (user_system_proxy, priv->os_version_id);
|
|
||||||
+ } else {
|
|
||||||
+ /* probably means accountsservice and lib are out of sync */
|
|
||||||
+ g_debug ("ActUserManager: failed to create user system proxy: %s",
|
|
||||||
+ error? error->message: "");
|
|
||||||
+ g_clear_error (&error);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ g_clear_object (&user_system_proxy);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
/**
|
|
||||||
* act_user_manager_create_user:
|
|
||||||
* @manager: a #ActUserManager
|
|
||||||
* @username: a unix user name
|
|
||||||
* @fullname: a unix GECOS value
|
|
||||||
* @accounttype: a #ActUserAccountType
|
|
||||||
* @error: a #GError
|
|
||||||
*
|
|
||||||
* Creates a user account on the system.
|
|
||||||
*
|
|
||||||
* Returns: (transfer full): user object
|
|
||||||
*/
|
|
||||||
ActUser *
|
|
||||||
act_user_manager_create_user (ActUserManager *manager,
|
|
||||||
const char *username,
|
|
||||||
const char *fullname,
|
|
||||||
ActUserAccountType accounttype,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
ActUserManagerPrivate *priv = act_user_manager_get_instance_private (manager);
|
|
||||||
GError *local_error = NULL;
|
|
||||||
gboolean res;
|
|
||||||
g_autofree gchar *path = NULL;
|
|
||||||
ActUser *user;
|
|
||||||
|
|
||||||
g_debug ("ActUserManager: Creating user '%s', '%s', %d",
|
|
||||||
username, fullname, accounttype);
|
|
||||||
|
|
||||||
g_assert (priv->accounts_proxy != NULL);
|
|
||||||
|
|
||||||
res = accounts_accounts_call_create_user_sync (priv->accounts_proxy,
|
|
||||||
username,
|
|
||||||
fullname,
|
|
||||||
accounttype,
|
|
||||||
&path,
|
|
||||||
NULL,
|
|
||||||
&local_error);
|
|
||||||
if (!res) {
|
|
||||||
g_propagate_error (error, local_error);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ save_system_info (manager, path);
|
|
||||||
+
|
|
||||||
user = add_new_user_for_object_path (path, manager);
|
|
||||||
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
act_user_manager_async_complete_handler (GObject *source,
|
|
||||||
GAsyncResult *result,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
GTask *task = user_data;
|
|
||||||
|
|
||||||
g_task_return_pointer (task, g_object_ref (result), g_object_unref);
|
|
||||||
g_object_unref (task);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* act_user_manager_create_user_async:
|
|
||||||
* @manager: a #ActUserManager
|
|
||||||
* @username: a unix user name
|
|
||||||
* @fullname: a unix GECOS value
|
|
||||||
* @accounttype: a #ActUserAccountType
|
|
||||||
* @cancellable: (allow-none): optional #GCancellable object,
|
|
||||||
* %NULL to ignore
|
|
||||||
* @callback: (scope async): a #GAsyncReadyCallback to call
|
|
||||||
* when the request is satisfied
|
|
||||||
* @user_data: (closure): the data to pass to @callback
|
|
||||||
*
|
|
||||||
* Asynchronously creates a user account on the system.
|
|
||||||
*
|
|
||||||
@@ -3253,106 +3368,111 @@ act_user_manager_create_user_async (ActUserManager *manager,
|
|
||||||
* @manager: a #ActUserManager
|
|
||||||
* @result: a #GAsyncResult
|
|
||||||
* @error: a #GError
|
|
||||||
*
|
|
||||||
* Finishes an asynchronous user creation.
|
|
||||||
*
|
|
||||||
* See act_user_manager_create_user_async().
|
|
||||||
*
|
|
||||||
* Returns: (transfer full): user object
|
|
||||||
*
|
|
||||||
* Since: 0.6.27
|
|
||||||
*/
|
|
||||||
ActUser *
|
|
||||||
act_user_manager_create_user_finish (ActUserManager *manager,
|
|
||||||
GAsyncResult *result,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
ActUserManagerPrivate *priv = act_user_manager_get_instance_private (manager);
|
|
||||||
GAsyncResult *inner_result;
|
|
||||||
ActUser *user = NULL;
|
|
||||||
g_autofree gchar *path = NULL;
|
|
||||||
GError *remote_error = NULL;
|
|
||||||
|
|
||||||
inner_result = g_task_propagate_pointer (G_TASK (result), error);
|
|
||||||
if (inner_result == NULL) {
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (accounts_accounts_call_create_user_finish (priv->accounts_proxy,
|
|
||||||
&path, inner_result, &remote_error)) {
|
|
||||||
+
|
|
||||||
+ save_system_info (manager, path);
|
|
||||||
+
|
|
||||||
user = add_new_user_for_object_path (path, manager);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (remote_error) {
|
|
||||||
g_dbus_error_strip_remote_error (remote_error);
|
|
||||||
g_propagate_error (error, remote_error);
|
|
||||||
}
|
|
||||||
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* act_user_manager_cache_user:
|
|
||||||
* @manager: a #ActUserManager
|
|
||||||
* @username: a user name
|
|
||||||
* @error: a #GError
|
|
||||||
*
|
|
||||||
* Caches a user account so it shows up via act_user_manager_list_users().
|
|
||||||
*
|
|
||||||
* Returns: (transfer full): user object
|
|
||||||
*/
|
|
||||||
ActUser *
|
|
||||||
act_user_manager_cache_user (ActUserManager *manager,
|
|
||||||
const char *username,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
ActUserManagerPrivate *priv = act_user_manager_get_instance_private (manager);
|
|
||||||
GError *local_error = NULL;
|
|
||||||
gboolean res;
|
|
||||||
g_autofree gchar *path = NULL;
|
|
||||||
|
|
||||||
g_debug ("ActUserManager: Caching user '%s'",
|
|
||||||
username);
|
|
||||||
|
|
||||||
g_assert (priv->accounts_proxy != NULL);
|
|
||||||
|
|
||||||
res = accounts_accounts_call_cache_user_sync (priv->accounts_proxy,
|
|
||||||
username,
|
|
||||||
&path,
|
|
||||||
NULL,
|
|
||||||
&local_error);
|
|
||||||
if (!res) {
|
|
||||||
g_propagate_error (error, local_error);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ save_system_info (manager, path);
|
|
||||||
+
|
|
||||||
return add_new_user_for_object_path (path, manager);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* act_user_manager_cache_user_async:
|
|
||||||
* @manager: a #ActUserManager
|
|
||||||
* @username: a unix user name
|
|
||||||
* @cancellable: (allow-none): optional #GCancellable object,
|
|
||||||
* %NULL to ignore
|
|
||||||
* @callback: (scope async): a #GAsyncReadyCallback to call
|
|
||||||
* when the request is satisfied
|
|
||||||
* @user_data: (closure): the data to pass to @callback
|
|
||||||
*
|
|
||||||
* Asynchronously caches a user account so it shows up via
|
|
||||||
* act_user_manager_list_users().
|
|
||||||
*
|
|
||||||
* For more details, see act_user_manager_cache_user(), which
|
|
||||||
* is the synchronous version of this call.
|
|
||||||
*
|
|
||||||
* Since: 0.6.27
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
act_user_manager_cache_user_async (ActUserManager *manager,
|
|
||||||
const char *username,
|
|
||||||
GCancellable *cancellable,
|
|
||||||
GAsyncReadyCallback callback,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
ActUserManagerPrivate *priv = act_user_manager_get_instance_private (manager);
|
|
||||||
@@ -3378,60 +3498,63 @@ act_user_manager_cache_user_async (ActUserManager *manager,
|
|
||||||
* @manager: a #ActUserManager
|
|
||||||
* @result: a #GAsyncResult
|
|
||||||
* @error: a #GError
|
|
||||||
*
|
|
||||||
* Finishes an asynchronous user caching.
|
|
||||||
*
|
|
||||||
* See act_user_manager_cache_user_async().
|
|
||||||
*
|
|
||||||
* Returns: (transfer full): user object
|
|
||||||
*
|
|
||||||
* Since: 0.6.27
|
|
||||||
*/
|
|
||||||
ActUser *
|
|
||||||
act_user_manager_cache_user_finish (ActUserManager *manager,
|
|
||||||
GAsyncResult *result,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
ActUserManagerPrivate *priv = act_user_manager_get_instance_private (manager);
|
|
||||||
GAsyncResult *inner_result;
|
|
||||||
ActUser *user = NULL;
|
|
||||||
g_autofree gchar *path = NULL;
|
|
||||||
GError *remote_error = NULL;
|
|
||||||
|
|
||||||
inner_result = g_task_propagate_pointer (G_TASK (result), error);
|
|
||||||
if (inner_result == NULL) {
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (accounts_accounts_call_cache_user_finish (priv->accounts_proxy,
|
|
||||||
&path, inner_result, &remote_error)) {
|
|
||||||
+
|
|
||||||
+ save_system_info (manager, path);
|
|
||||||
+
|
|
||||||
user = add_new_user_for_object_path (path, manager);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (remote_error) {
|
|
||||||
g_dbus_error_strip_remote_error (remote_error);
|
|
||||||
g_propagate_error (error, remote_error);
|
|
||||||
}
|
|
||||||
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* act_user_manager_uncache_user:
|
|
||||||
* @manager: a #ActUserManager
|
|
||||||
* @username: a user name
|
|
||||||
* @error: a #GError
|
|
||||||
*
|
|
||||||
* Releases all metadata about a user account, including icon,
|
|
||||||
* language and session. If the user account is from a remote
|
|
||||||
* server and the user has never logged in before, then that
|
|
||||||
* account will no longer show up in ListCachedUsers() output.
|
|
||||||
*
|
|
||||||
* Returns: %TRUE if successful, otherwise %FALSE
|
|
||||||
*/
|
|
||||||
gboolean
|
|
||||||
act_user_manager_uncache_user (ActUserManager *manager,
|
|
||||||
const char *username,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
ActUserManagerPrivate *priv = act_user_manager_get_instance_private (manager);
|
|
||||||
diff --git a/src/libaccountsservice/meson.build b/src/libaccountsservice/meson.build
|
|
||||||
index 4e134db..9e85bba 100644
|
|
||||||
--- a/src/libaccountsservice/meson.build
|
|
||||||
+++ b/src/libaccountsservice/meson.build
|
|
||||||
@@ -21,60 +21,67 @@ enum_types = 'act-user-enum-types'
|
|
||||||
|
|
||||||
enum_sources = gnome.mkenums(
|
|
||||||
enum_types,
|
|
||||||
sources: headers,
|
|
||||||
c_template: enum_types + '.c.template',
|
|
||||||
h_template: enum_types + '.h.template',
|
|
||||||
install_header: true,
|
|
||||||
install_dir: join_paths(act_pkgincludedir, subdir),
|
|
||||||
)
|
|
||||||
|
|
||||||
dbus_sources = []
|
|
||||||
|
|
||||||
ifaces = [
|
|
||||||
'Manager',
|
|
||||||
'Seat',
|
|
||||||
'Session',
|
|
||||||
]
|
|
||||||
|
|
||||||
namespace = 'ConsoleKit'
|
|
||||||
prefix = 'org.freedesktop.' + namespace
|
|
||||||
|
|
||||||
foreach iface: ifaces
|
|
||||||
dbus_sources += gnome.gdbus_codegen(
|
|
||||||
'ck-@0@-generated'.format(iface.to_lower()),
|
|
||||||
'@0@.@1@.xml'.format(prefix, iface),
|
|
||||||
interface_prefix: prefix,
|
|
||||||
namespace: namespace,
|
|
||||||
)
|
|
||||||
endforeach
|
|
||||||
|
|
||||||
+dbus_sources += gnome.gdbus_codegen(
|
|
||||||
+ 'com.redhat.AccountsServiceUser.System',
|
|
||||||
+ join_paths(data_dir, 'com.redhat.AccountsServiceUser.System.xml'),
|
|
||||||
+ interface_prefix: 'com.redhat.AccountsService',
|
|
||||||
+ namespace: 'Act',
|
|
||||||
+)
|
|
||||||
+
|
|
||||||
deps = [
|
|
||||||
crypt_dep,
|
|
||||||
gio_unix_dep,
|
|
||||||
glib_dep,
|
|
||||||
libaccounts_generated_dep,
|
|
||||||
]
|
|
||||||
|
|
||||||
symbol_map = join_paths(meson.current_source_dir(), 'symbol.map')
|
|
||||||
ldflags = cc.get_supported_link_arguments('-Wl,--version-script,@0@'.format(symbol_map))
|
|
||||||
|
|
||||||
if enable_systemd or enable_elogind
|
|
||||||
deps += logind_dep
|
|
||||||
endif
|
|
||||||
|
|
||||||
libaccountsservice = shared_library(
|
|
||||||
act_name,
|
|
||||||
sources: sources + enum_sources + dbus_sources,
|
|
||||||
version: libversion,
|
|
||||||
include_directories: top_inc,
|
|
||||||
dependencies: deps,
|
|
||||||
c_args: '-DG_LOG_DOMAIN="@0@"'.format(meson.project_name()),
|
|
||||||
link_args: ldflags,
|
|
||||||
link_depends: symbol_map,
|
|
||||||
install: true,
|
|
||||||
)
|
|
||||||
|
|
||||||
libaccountsservice_dep = declare_dependency(
|
|
||||||
sources: enum_sources[1],
|
|
||||||
include_directories: include_directories('.'),
|
|
||||||
dependencies: [gio_dep, glib_dep],
|
|
||||||
--
|
|
||||||
2.27.0
|
|
||||||
|
|
@ -0,0 +1,54 @@
|
|||||||
|
From da65bee12d9118fe1a49c8718d428fe61d232339 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Ray Strode <rstrode@redhat.com>
|
||||||
|
Date: Tue, 11 Apr 2023 10:09:07 -0400
|
||||||
|
Subject: [PATCH 1/2] mocklibc: Fix compiler warning
|
||||||
|
|
||||||
|
print_indent is defined in one file and used in another without a
|
||||||
|
forward declaration. That leads to a compiler warning/error.
|
||||||
|
|
||||||
|
This commit fixes that.
|
||||||
|
---
|
||||||
|
subprojects/mocklibc.wrap | 2 ++
|
||||||
|
subprojects/packagefiles/mocklibc-print-indent.diff | 13 +++++++++++++
|
||||||
|
2 files changed, 15 insertions(+)
|
||||||
|
create mode 100644 subprojects/packagefiles/mocklibc-print-indent.diff
|
||||||
|
|
||||||
|
diff --git a/subprojects/mocklibc.wrap b/subprojects/mocklibc.wrap
|
||||||
|
index af82298..539ee83 100644
|
||||||
|
--- a/subprojects/mocklibc.wrap
|
||||||
|
+++ b/subprojects/mocklibc.wrap
|
||||||
|
@@ -1,10 +1,12 @@
|
||||||
|
[wrap-file]
|
||||||
|
directory = mocklibc-1.0
|
||||||
|
|
||||||
|
source_url = https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/mocklibc/mocklibc-1.0.tar.gz
|
||||||
|
source_filename = mocklibc-1.0.tar.gz
|
||||||
|
source_hash = b2236a6af1028414783e9734a46ea051916ec226479d6a55a3bb823bff68f120
|
||||||
|
|
||||||
|
patch_url = https://wrapdb.mesonbuild.com/v1/projects/mocklibc/1.0/2/get_zip
|
||||||
|
patch_filename = mocklibc-1.0-2-wrap.zip
|
||||||
|
patch_hash = 0280f96a2eeb3c023e5acf4e00cef03d362868218d4a85347ea45137c0ef6c56
|
||||||
|
+
|
||||||
|
+diff_files = mocklibc-print-indent.diff
|
||||||
|
diff --git a/subprojects/packagefiles/mocklibc-print-indent.diff b/subprojects/packagefiles/mocklibc-print-indent.diff
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000..4aaed40
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/subprojects/packagefiles/mocklibc-print-indent.diff
|
||||||
|
@@ -0,0 +1,13 @@
|
||||||
|
+diff -up mocklibc-1.0/src/netgroup-debug.c.print-indent mocklibc-1.0/src/netgroup-debug.c
|
||||||
|
+--- mocklibc-1.0/src/netgroup-debug.c.print-indent 2023-04-11 10:20:53.717381559 -0400
|
||||||
|
++++ mocklibc-1.0/src/netgroup-debug.c 2023-04-11 10:21:02.296270333 -0400
|
||||||
|
+@@ -21,6 +21,9 @@
|
||||||
|
+ #include <stdio.h>
|
||||||
|
+ #include <stdlib.h>
|
||||||
|
+
|
||||||
|
++void print_indent (FILE *stream,
|
||||||
|
++ unsigned int indent);
|
||||||
|
++
|
||||||
|
+ void netgroup_debug_print_entry(struct entry *entry, FILE *stream, unsigned int indent) {
|
||||||
|
+ print_indent(stream, indent);
|
||||||
|
+
|
||||||
|
--
|
||||||
|
2.39.2
|
||||||
|
|
@ -1,925 +0,0 @@
|
|||||||
From 72427bd4fcae931298c670093f9cbd34ad58f59a Mon Sep 17 00:00:00 2001
|
|
||||||
From: Ray Strode <rstrode@redhat.com>
|
|
||||||
Date: Wed, 4 Aug 2021 19:54:59 -0400
|
|
||||||
Subject: [PATCH] user: Introduce user templates for setting default session
|
|
||||||
etc
|
|
||||||
|
|
||||||
At the moment there's no easy way to set a default session, or
|
|
||||||
face icon or whatever for all users. If a user has never logged in
|
|
||||||
before, we just generate their cache file from hardcoded defaults.
|
|
||||||
|
|
||||||
This commit introduces a template system to make it possible for
|
|
||||||
admins to set up defaults on their own.
|
|
||||||
|
|
||||||
Admins can write either
|
|
||||||
/etc/accountsservice/user-templates/administrator
|
|
||||||
or
|
|
||||||
/etc/accountsservice/user-templates/standard
|
|
||||||
|
|
||||||
files. These files follow the same format as
|
|
||||||
|
|
||||||
/var/lib/AccountsService/users/username
|
|
||||||
|
|
||||||
files, but will support substituting $HOME and $USER to the appropriate
|
|
||||||
user specific values.
|
|
||||||
|
|
||||||
User templates also support an additional group [Template] that
|
|
||||||
have an additional key EnvironmentFiles that specify a list
|
|
||||||
of environment files to load (files with KEY=VALUE pairs in them).
|
|
||||||
Any keys listed in those environment files will also get substituted.
|
|
||||||
---
|
|
||||||
data/administrator | 6 +
|
|
||||||
data/meson.build | 10 ++
|
|
||||||
data/standard | 6 +
|
|
||||||
src/daemon.c | 8 +-
|
|
||||||
src/meson.build | 1 +
|
|
||||||
src/user.c | 284 ++++++++++++++++++++++++++++++++++++++++++++-
|
|
||||||
src/user.h | 3 +-
|
|
||||||
7 files changed, 305 insertions(+), 13 deletions(-)
|
|
||||||
create mode 100644 data/administrator
|
|
||||||
create mode 100644 data/standard
|
|
||||||
|
|
||||||
diff --git a/data/administrator b/data/administrator
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000..ea043c9
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/data/administrator
|
|
||||||
@@ -0,0 +1,6 @@
|
|
||||||
+[Template]
|
|
||||||
+#EnvironmentFiles=/etc/os-release;
|
|
||||||
+
|
|
||||||
+[User]
|
|
||||||
+Session=
|
|
||||||
+Icon=${HOME}/.face
|
|
||||||
diff --git a/data/meson.build b/data/meson.build
|
|
||||||
index 2dc57c2..7d9bdcd 100644
|
|
||||||
--- a/data/meson.build
|
|
||||||
+++ b/data/meson.build
|
|
||||||
@@ -22,30 +22,40 @@ service = act_namespace + '.service'
|
|
||||||
configure_file(
|
|
||||||
input: service + '.in',
|
|
||||||
output: service,
|
|
||||||
configuration: service_conf,
|
|
||||||
install: true,
|
|
||||||
install_dir: dbus_sys_dir,
|
|
||||||
)
|
|
||||||
|
|
||||||
policy = act_namespace.to_lower() + '.policy'
|
|
||||||
|
|
||||||
i18n.merge_file(
|
|
||||||
policy,
|
|
||||||
input: policy + '.in',
|
|
||||||
output: policy,
|
|
||||||
po_dir: po_dir,
|
|
||||||
install: true,
|
|
||||||
install_dir: policy_dir,
|
|
||||||
)
|
|
||||||
|
|
||||||
if install_systemd_unit_dir
|
|
||||||
service = 'accounts-daemon.service'
|
|
||||||
|
|
||||||
configure_file(
|
|
||||||
input: service + '.in',
|
|
||||||
output: service,
|
|
||||||
configuration: service_conf,
|
|
||||||
install: true,
|
|
||||||
install_dir: systemd_system_unit_dir,
|
|
||||||
)
|
|
||||||
endif
|
|
||||||
+
|
|
||||||
+install_data(
|
|
||||||
+ 'administrator',
|
|
||||||
+ install_dir: join_paths(act_datadir, 'accountsservice', 'user-templates'),
|
|
||||||
+)
|
|
||||||
+
|
|
||||||
+install_data(
|
|
||||||
+ 'standard',
|
|
||||||
+ install_dir: join_paths(act_datadir, 'accountsservice', 'user-templates'),
|
|
||||||
+)
|
|
||||||
diff --git a/data/standard b/data/standard
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000..ea043c9
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/data/standard
|
|
||||||
@@ -0,0 +1,6 @@
|
|
||||||
+[Template]
|
|
||||||
+#EnvironmentFiles=/etc/os-release;
|
|
||||||
+
|
|
||||||
+[User]
|
|
||||||
+Session=
|
|
||||||
+Icon=${HOME}/.face
|
|
||||||
diff --git a/src/daemon.c b/src/daemon.c
|
|
||||||
index 5ce0216..66ac7ba 100644
|
|
||||||
--- a/src/daemon.c
|
|
||||||
+++ b/src/daemon.c
|
|
||||||
@@ -298,69 +298,63 @@ entry_generator_cachedir (Daemon *daemon,
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* Only load files in this directory */
|
|
||||||
filename = g_build_filename (USERDIR, name, NULL);
|
|
||||||
regular = g_file_test (filename, G_FILE_TEST_IS_REGULAR);
|
|
||||||
|
|
||||||
if (regular) {
|
|
||||||
errno = 0;
|
|
||||||
pwent = getpwnam (name);
|
|
||||||
if (pwent != NULL) {
|
|
||||||
*shadow_entry = getspnam (pwent->pw_name);
|
|
||||||
|
|
||||||
return pwent;
|
|
||||||
} else if (errno == 0) {
|
|
||||||
g_debug ("user '%s' in cache dir but not present on system, removing", name);
|
|
||||||
remove_cache_files (name);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
g_warning ("failed to check if user '%s' in cache dir is present on system: %s",
|
|
||||||
name, g_strerror (errno));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Last iteration */
|
|
||||||
g_dir_close (dir);
|
|
||||||
|
|
||||||
/* Update all the users from the files in the cache dir */
|
|
||||||
g_hash_table_iter_init (&iter, users);
|
|
||||||
while (g_hash_table_iter_next (&iter, &key, &value)) {
|
|
||||||
- const gchar *name = key;
|
|
||||||
User *user = value;
|
|
||||||
- g_autofree gchar *filename = NULL;
|
|
||||||
- g_autoptr(GKeyFile) key_file = NULL;
|
|
||||||
|
|
||||||
- filename = g_build_filename (USERDIR, name, NULL);
|
|
||||||
- key_file = g_key_file_new ();
|
|
||||||
- if (g_key_file_load_from_file (key_file, filename, 0, NULL))
|
|
||||||
- user_update_from_keyfile (user, key_file);
|
|
||||||
+ user_update_from_cache (user);
|
|
||||||
}
|
|
||||||
|
|
||||||
*state = NULL;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct passwd *
|
|
||||||
entry_generator_requested_users (Daemon *daemon,
|
|
||||||
GHashTable *users,
|
|
||||||
gpointer *state,
|
|
||||||
struct spwd **shadow_entry)
|
|
||||||
{
|
|
||||||
DaemonPrivate *priv = daemon_get_instance_private (daemon);
|
|
||||||
struct passwd *pwent;
|
|
||||||
GList *node;
|
|
||||||
|
|
||||||
/* First iteration */
|
|
||||||
if (*state == NULL) {
|
|
||||||
*state = priv->explicitly_requested_users;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Every iteration */
|
|
||||||
|
|
||||||
if (g_hash_table_size (users) < MAX_LOCAL_USERS) {
|
|
||||||
node = *state;
|
|
||||||
while (node != NULL) {
|
|
||||||
const char *name;
|
|
||||||
|
|
||||||
name = node->data;
|
|
||||||
node = node->next;
|
|
||||||
diff --git a/src/meson.build b/src/meson.build
|
|
||||||
index 3970749..d3b0cb9 100644
|
|
||||||
--- a/src/meson.build
|
|
||||||
+++ b/src/meson.build
|
|
||||||
@@ -1,59 +1,60 @@
|
|
||||||
sources = []
|
|
||||||
|
|
||||||
gdbus_headers = []
|
|
||||||
|
|
||||||
ifaces = [
|
|
||||||
['accounts-generated', 'org.freedesktop.', 'Accounts'],
|
|
||||||
['accounts-user-generated', act_namespace + '.', 'User'],
|
|
||||||
['realmd-generated', 'org.freedesktop.', 'realmd'],
|
|
||||||
]
|
|
||||||
|
|
||||||
foreach iface: ifaces
|
|
||||||
gdbus_sources = gnome.gdbus_codegen(
|
|
||||||
iface[0],
|
|
||||||
join_paths(data_dir, iface[1] + iface[2] + '.xml'),
|
|
||||||
interface_prefix: iface[1],
|
|
||||||
namespace: 'Accounts',
|
|
||||||
)
|
|
||||||
sources += gdbus_sources
|
|
||||||
gdbus_headers += gdbus_sources[1]
|
|
||||||
endforeach
|
|
||||||
|
|
||||||
deps = [
|
|
||||||
gio_dep,
|
|
||||||
gio_unix_dep,
|
|
||||||
]
|
|
||||||
|
|
||||||
cflags = [
|
|
||||||
'-DLOCALSTATEDIR="@0@"'.format(act_localstatedir),
|
|
||||||
'-DDATADIR="@0@"'.format(act_datadir),
|
|
||||||
+ '-DSYSCONFDIR="@0@"'.format(act_sysconfdir),
|
|
||||||
'-DICONDIR="@0@"'.format(join_paths(act_localstatedir, 'lib', 'AccountsService', 'icons')),
|
|
||||||
'-DUSERDIR="@0@"'.format(join_paths(act_localstatedir, 'lib', 'AccountsService', 'users')),
|
|
||||||
]
|
|
||||||
|
|
||||||
libaccounts_generated = static_library(
|
|
||||||
'accounts-generated',
|
|
||||||
sources: sources,
|
|
||||||
include_directories: top_inc,
|
|
||||||
dependencies: deps,
|
|
||||||
c_args: cflags,
|
|
||||||
)
|
|
||||||
|
|
||||||
libaccounts_generated_dep = declare_dependency(
|
|
||||||
sources: gdbus_headers,
|
|
||||||
include_directories: include_directories('.'),
|
|
||||||
dependencies: gio_dep,
|
|
||||||
link_with: libaccounts_generated,
|
|
||||||
)
|
|
||||||
|
|
||||||
sources = files(
|
|
||||||
'daemon.c',
|
|
||||||
'extensions.c',
|
|
||||||
'main.c',
|
|
||||||
'user.c',
|
|
||||||
'user-classify.c',
|
|
||||||
'util.c',
|
|
||||||
'wtmp-helper.c',
|
|
||||||
)
|
|
||||||
|
|
||||||
deps = [
|
|
||||||
diff --git a/src/user.c b/src/user.c
|
|
||||||
index 9f57af5..16c7721 100644
|
|
||||||
--- a/src/user.c
|
|
||||||
+++ b/src/user.c
|
|
||||||
@@ -43,127 +43,384 @@
|
|
||||||
#include <polkit/polkit.h>
|
|
||||||
|
|
||||||
#include "user-classify.h"
|
|
||||||
#include "daemon.h"
|
|
||||||
#include "user.h"
|
|
||||||
#include "accounts-user-generated.h"
|
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
struct User {
|
|
||||||
AccountsUserSkeleton parent;
|
|
||||||
|
|
||||||
GDBusConnection *system_bus_connection;
|
|
||||||
gchar *object_path;
|
|
||||||
|
|
||||||
Daemon *daemon;
|
|
||||||
|
|
||||||
GKeyFile *keyfile;
|
|
||||||
|
|
||||||
gid_t gid;
|
|
||||||
gint64 expiration_time;
|
|
||||||
gint64 last_change_time;
|
|
||||||
gint64 min_days_between_changes;
|
|
||||||
gint64 max_days_between_changes;
|
|
||||||
gint64 days_to_warn;
|
|
||||||
gint64 days_after_expiration_until_lock;
|
|
||||||
GVariant *login_history;
|
|
||||||
gchar *icon_file;
|
|
||||||
gchar *default_icon_file;
|
|
||||||
gboolean account_expiration_policy_known;
|
|
||||||
gboolean cached;
|
|
||||||
+ gboolean template_loaded;
|
|
||||||
|
|
||||||
guint *extension_ids;
|
|
||||||
guint n_extension_ids;
|
|
||||||
|
|
||||||
guint changed_timeout_id;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct UserClass
|
|
||||||
{
|
|
||||||
AccountsUserSkeletonClass parent_class;
|
|
||||||
} UserClass;
|
|
||||||
|
|
||||||
static void user_accounts_user_iface_init (AccountsUserIface *iface);
|
|
||||||
+static void user_update_from_keyfile (User *user, GKeyFile *keyfile);
|
|
||||||
|
|
||||||
G_DEFINE_TYPE_WITH_CODE (User, user, ACCOUNTS_TYPE_USER_SKELETON, G_IMPLEMENT_INTERFACE (ACCOUNTS_TYPE_USER, user_accounts_user_iface_init));
|
|
||||||
|
|
||||||
static gint
|
|
||||||
account_type_from_pwent (struct passwd *pwent)
|
|
||||||
{
|
|
||||||
struct group *grp;
|
|
||||||
gint i;
|
|
||||||
|
|
||||||
if (pwent->pw_uid == 0) {
|
|
||||||
g_debug ("user is root so account type is administrator");
|
|
||||||
return ACCOUNT_TYPE_ADMINISTRATOR;
|
|
||||||
}
|
|
||||||
|
|
||||||
grp = getgrnam (ADMIN_GROUP);
|
|
||||||
if (grp == NULL) {
|
|
||||||
g_debug (ADMIN_GROUP " group not found");
|
|
||||||
return ACCOUNT_TYPE_STANDARD;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; grp->gr_mem[i] != NULL; i++) {
|
|
||||||
if (g_strcmp0 (grp->gr_mem[i], pwent->pw_name) == 0) {
|
|
||||||
return ACCOUNT_TYPE_ADMINISTRATOR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ACCOUNT_TYPE_STANDARD;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
user_reset_icon_file (User *user)
|
|
||||||
{
|
|
||||||
const char *icon_file;
|
|
||||||
gboolean icon_is_default;
|
|
||||||
const char *home_dir;
|
|
||||||
|
|
||||||
icon_file = accounts_user_get_icon_file (ACCOUNTS_USER (user));
|
|
||||||
|
|
||||||
if (icon_file == NULL || g_strcmp0 (icon_file, user->default_icon_file) == 0) {
|
|
||||||
icon_is_default = TRUE;
|
|
||||||
} else {
|
|
||||||
icon_is_default = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_free (user->default_icon_file);
|
|
||||||
home_dir = accounts_user_get_home_directory (ACCOUNTS_USER (user));
|
|
||||||
|
|
||||||
user->default_icon_file = g_build_filename (home_dir, ".face", NULL);
|
|
||||||
|
|
||||||
if (icon_is_default) {
|
|
||||||
accounts_user_set_icon_file (ACCOUNTS_USER (user), user->default_icon_file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+static gboolean
|
|
||||||
+user_has_cache_file (User *user)
|
|
||||||
+{
|
|
||||||
+ g_autofree char *filename = NULL;
|
|
||||||
+
|
|
||||||
+ filename = g_build_filename (USERDIR, user_get_user_name (user), NULL);
|
|
||||||
+
|
|
||||||
+ return g_file_test (filename, G_FILE_TEST_EXISTS);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static gboolean
|
|
||||||
+is_valid_shell_identifier_character (char c,
|
|
||||||
+ gboolean first)
|
|
||||||
+{
|
|
||||||
+ return (!first && g_ascii_isdigit (c)) ||
|
|
||||||
+ c == '_' ||
|
|
||||||
+ g_ascii_isalpha (c);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static char *
|
|
||||||
+expand_template_variables (User *user,
|
|
||||||
+ GHashTable *template_variables,
|
|
||||||
+ const char *str)
|
|
||||||
+{
|
|
||||||
+ GString *s = g_string_new ("");
|
|
||||||
+ const char *p, *start;
|
|
||||||
+ char c;
|
|
||||||
+
|
|
||||||
+ p = str;
|
|
||||||
+ while (*p) {
|
|
||||||
+ c = *p;
|
|
||||||
+ if (c == '\\') {
|
|
||||||
+ p++;
|
|
||||||
+ c = *p;
|
|
||||||
+ if (c != '\0') {
|
|
||||||
+ p++;
|
|
||||||
+ switch (c) {
|
|
||||||
+ case '\\':
|
|
||||||
+ g_string_append_c (s, '\\');
|
|
||||||
+ break;
|
|
||||||
+ case '$':
|
|
||||||
+ g_string_append_c (s, '$');
|
|
||||||
+ break;
|
|
||||||
+ default:
|
|
||||||
+ g_string_append_c (s, '\\');
|
|
||||||
+ g_string_append_c (s, c);
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ } else if (c == '$') {
|
|
||||||
+ gboolean brackets = FALSE;
|
|
||||||
+ p++;
|
|
||||||
+ if (*p == '{') {
|
|
||||||
+ brackets = TRUE;
|
|
||||||
+ p++;
|
|
||||||
+ }
|
|
||||||
+ start = p;
|
|
||||||
+ while (*p != '\0' &&
|
|
||||||
+ is_valid_shell_identifier_character (*p, p == start))
|
|
||||||
+ p++;
|
|
||||||
+ if (p == start || (brackets && *p != '}')) {
|
|
||||||
+ g_string_append_c (s, '$');
|
|
||||||
+ if (brackets)
|
|
||||||
+ g_string_append_c (s, '{');
|
|
||||||
+ g_string_append_len (s, start, p - start);
|
|
||||||
+ } else {
|
|
||||||
+ g_autofree char *variable = NULL;
|
|
||||||
+ const char *value;
|
|
||||||
+
|
|
||||||
+ if (brackets && *p == '}')
|
|
||||||
+ p++;
|
|
||||||
+
|
|
||||||
+ variable = g_strndup (start, p - start - 1);
|
|
||||||
+
|
|
||||||
+ value = g_hash_table_lookup (template_variables, variable);
|
|
||||||
+ if (value) {
|
|
||||||
+ g_string_append (s, value);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ } else {
|
|
||||||
+ p++;
|
|
||||||
+ g_string_append_c (s, c);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ return g_string_free (s, FALSE);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+load_template_environment_file (User *user,
|
|
||||||
+ GHashTable *variables,
|
|
||||||
+ const char *file)
|
|
||||||
+{
|
|
||||||
+ g_autofree char *contents = NULL;
|
|
||||||
+ g_auto (GStrv) lines = NULL;
|
|
||||||
+ g_autoptr (GError) error = NULL;
|
|
||||||
+ gboolean file_loaded;
|
|
||||||
+ size_t i;
|
|
||||||
+
|
|
||||||
+ file_loaded = g_file_get_contents (file, &contents, NULL, &error);
|
|
||||||
+
|
|
||||||
+ if (!file_loaded) {
|
|
||||||
+ g_debug ("Couldn't load template environment file %s: %s",
|
|
||||||
+ file, error->message);
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ lines = g_strsplit (contents, "\n", -1);
|
|
||||||
+
|
|
||||||
+ for (i = 0; lines[i] != NULL; i++) {
|
|
||||||
+ char *p;
|
|
||||||
+ char *variable_end;
|
|
||||||
+ const char *variable;
|
|
||||||
+ const char *value;
|
|
||||||
+
|
|
||||||
+ p = lines[i];
|
|
||||||
+ while (g_ascii_isspace (*p))
|
|
||||||
+ p++;
|
|
||||||
+ if (*p == '#' || *p == '\0')
|
|
||||||
+ continue;
|
|
||||||
+ variable = p;
|
|
||||||
+ while (is_valid_shell_identifier_character (*p, p == variable))
|
|
||||||
+ p++;
|
|
||||||
+ variable_end = p;
|
|
||||||
+ while (g_ascii_isspace (*p))
|
|
||||||
+ p++;
|
|
||||||
+ if (variable_end == variable || *p != '=') {
|
|
||||||
+ g_debug ("template environment file %s has invalid line '%s'\n", file, lines[i]);
|
|
||||||
+ continue;
|
|
||||||
+ }
|
|
||||||
+ *variable_end = '\0';
|
|
||||||
+ p++;
|
|
||||||
+ while (g_ascii_isspace (*p))
|
|
||||||
+ p++;
|
|
||||||
+ value = p;
|
|
||||||
+
|
|
||||||
+ if (g_hash_table_lookup (variables, variable) == NULL) {
|
|
||||||
+ g_hash_table_insert (variables,
|
|
||||||
+ g_strdup (variable),
|
|
||||||
+ g_strdup (value));
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+initialize_template_environment (User *user,
|
|
||||||
+ GHashTable *variables,
|
|
||||||
+ const char * const *files)
|
|
||||||
+{
|
|
||||||
+ size_t i;
|
|
||||||
+
|
|
||||||
+ g_hash_table_insert (variables, g_strdup ("HOME"), g_strdup (accounts_user_get_home_directory (ACCOUNTS_USER (user))));
|
|
||||||
+ g_hash_table_insert (variables, g_strdup ("USER"), g_strdup (user_get_user_name (user)));
|
|
||||||
+
|
|
||||||
+ if (files == NULL)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ for (i = 0; files[i] != NULL; i++) {
|
|
||||||
+ load_template_environment_file (user, variables, files[i]);
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+user_update_from_template (User *user)
|
|
||||||
+{
|
|
||||||
+ g_autofree char *filename = NULL;
|
|
||||||
+ g_autoptr (GKeyFile) key_file = NULL;
|
|
||||||
+ g_autoptr (GError) error = NULL;
|
|
||||||
+ g_autoptr (GHashTable) template_variables = NULL;
|
|
||||||
+ g_auto (GStrv) template_environment_files = NULL;
|
|
||||||
+ gboolean key_file_loaded = FALSE;
|
|
||||||
+ const char * const *system_dirs[] = {
|
|
||||||
+ (const char *[]) { "/run", SYSCONFDIR, NULL },
|
|
||||||
+ g_get_system_data_dirs (),
|
|
||||||
+ NULL
|
|
||||||
+ };
|
|
||||||
+ g_autoptr (GPtrArray) dirs = NULL;
|
|
||||||
+ AccountType account_type;
|
|
||||||
+ const char *account_type_string;
|
|
||||||
+ size_t i, j;
|
|
||||||
+ g_autofree char *contents = NULL;
|
|
||||||
+ g_autofree char *expanded = NULL;
|
|
||||||
+ g_auto (GStrv) lines = NULL;
|
|
||||||
+
|
|
||||||
+ if (user->template_loaded)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ filename = g_build_filename (USERDIR,
|
|
||||||
+ accounts_user_get_user_name (ACCOUNTS_USER (user)),
|
|
||||||
+ NULL);
|
|
||||||
+
|
|
||||||
+ account_type = accounts_user_get_account_type (ACCOUNTS_USER (user));
|
|
||||||
+ if (account_type == ACCOUNT_TYPE_ADMINISTRATOR)
|
|
||||||
+ account_type_string = "administrator";
|
|
||||||
+ else
|
|
||||||
+ account_type_string = "standard";
|
|
||||||
+
|
|
||||||
+ dirs = g_ptr_array_new ();
|
|
||||||
+ for (i = 0; system_dirs[i] != NULL; i++) {
|
|
||||||
+ for (j = 0; system_dirs[i][j] != NULL; j++) {
|
|
||||||
+ char *dir;
|
|
||||||
+
|
|
||||||
+ dir = g_build_filename (system_dirs[i][j],
|
|
||||||
+ "accountsservice",
|
|
||||||
+ "user-templates",
|
|
||||||
+ NULL);
|
|
||||||
+ g_ptr_array_add (dirs, dir);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ g_ptr_array_add (dirs, NULL);
|
|
||||||
+
|
|
||||||
+ key_file = g_key_file_new ();
|
|
||||||
+ key_file_loaded = g_key_file_load_from_dirs (key_file,
|
|
||||||
+ account_type_string,
|
|
||||||
+ (const char **) dirs->pdata,
|
|
||||||
+ NULL,
|
|
||||||
+ G_KEY_FILE_KEEP_COMMENTS,
|
|
||||||
+ &error);
|
|
||||||
+
|
|
||||||
+ if (!key_file_loaded) {
|
|
||||||
+ g_debug ("failed to load user template: %s", error->message);
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ template_variables = g_hash_table_new_full (g_str_hash,
|
|
||||||
+ g_str_equal,
|
|
||||||
+ g_free,
|
|
||||||
+ g_free);
|
|
||||||
+
|
|
||||||
+ template_environment_files = g_key_file_get_string_list (key_file,
|
|
||||||
+ "Template",
|
|
||||||
+ "EnvironmentFiles",
|
|
||||||
+ NULL,
|
|
||||||
+ NULL);
|
|
||||||
+
|
|
||||||
+ initialize_template_environment (user, template_variables, (const char * const *) template_environment_files);
|
|
||||||
+
|
|
||||||
+ g_key_file_remove_group (key_file, "Template", NULL);
|
|
||||||
+ contents = g_key_file_to_data (key_file, NULL, NULL);
|
|
||||||
+ lines = g_strsplit (contents, "\n", -1);
|
|
||||||
+
|
|
||||||
+ expanded = expand_template_variables (user, template_variables, contents);
|
|
||||||
+
|
|
||||||
+ key_file_loaded = g_key_file_load_from_data (key_file,
|
|
||||||
+ expanded,
|
|
||||||
+ strlen (expanded),
|
|
||||||
+ G_KEY_FILE_KEEP_COMMENTS,
|
|
||||||
+ &error);
|
|
||||||
+
|
|
||||||
+ if (key_file_loaded)
|
|
||||||
+ user_update_from_keyfile (user, key_file);
|
|
||||||
+
|
|
||||||
+ user->template_loaded = key_file_loaded;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
void
|
|
||||||
user_update_from_pwent (User *user,
|
|
||||||
struct passwd *pwent,
|
|
||||||
struct spwd *spent)
|
|
||||||
{
|
|
||||||
g_autofree gchar *real_name = NULL;
|
|
||||||
gboolean is_system_account;
|
|
||||||
const gchar *passwd;
|
|
||||||
gboolean locked;
|
|
||||||
PasswordMode mode;
|
|
||||||
AccountType account_type;
|
|
||||||
|
|
||||||
g_object_freeze_notify (G_OBJECT (user));
|
|
||||||
|
|
||||||
if (pwent->pw_gecos && pwent->pw_gecos[0] != '\0') {
|
|
||||||
gchar *first_comma = NULL;
|
|
||||||
gchar *valid_utf8_name = NULL;
|
|
||||||
|
|
||||||
if (g_utf8_validate (pwent->pw_gecos, -1, NULL)) {
|
|
||||||
valid_utf8_name = pwent->pw_gecos;
|
|
||||||
first_comma = g_utf8_strchr (valid_utf8_name, -1, ',');
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
g_warning ("User %s has invalid UTF-8 in GECOS field. "
|
|
||||||
"It would be a good thing to check /etc/passwd.",
|
|
||||||
pwent->pw_name ? pwent->pw_name : "");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (first_comma) {
|
|
||||||
real_name = g_strndup (valid_utf8_name,
|
|
||||||
@@ -212,134 +469,150 @@ user_update_from_pwent (User *user,
|
|
||||||
accounts_user_set_locked (ACCOUNTS_USER (user), locked);
|
|
||||||
|
|
||||||
if (passwd == NULL || passwd[0] != 0) {
|
|
||||||
mode = PASSWORD_MODE_REGULAR;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
mode = PASSWORD_MODE_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (spent) {
|
|
||||||
if (spent->sp_lstchg == 0) {
|
|
||||||
mode = PASSWORD_MODE_SET_AT_LOGIN;
|
|
||||||
}
|
|
||||||
|
|
||||||
user->expiration_time = spent->sp_expire;
|
|
||||||
user->last_change_time = spent->sp_lstchg;
|
|
||||||
user->min_days_between_changes = spent->sp_min;
|
|
||||||
user->max_days_between_changes = spent->sp_max;
|
|
||||||
user->days_to_warn = spent->sp_warn;
|
|
||||||
user->days_after_expiration_until_lock = spent->sp_inact;
|
|
||||||
user->account_expiration_policy_known = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
accounts_user_set_password_mode (ACCOUNTS_USER (user), mode);
|
|
||||||
is_system_account = !user_classify_is_human (accounts_user_get_uid (ACCOUNTS_USER (user)),
|
|
||||||
accounts_user_get_user_name (ACCOUNTS_USER (user)),
|
|
||||||
accounts_user_get_shell (ACCOUNTS_USER (user)),
|
|
||||||
passwd);
|
|
||||||
accounts_user_set_system_account (ACCOUNTS_USER (user), is_system_account);
|
|
||||||
|
|
||||||
+ if (!user_has_cache_file (user))
|
|
||||||
+ user_update_from_template (user);
|
|
||||||
g_object_thaw_notify (G_OBJECT (user));
|
|
||||||
}
|
|
||||||
|
|
||||||
-void
|
|
||||||
+static void
|
|
||||||
user_update_from_keyfile (User *user,
|
|
||||||
GKeyFile *keyfile)
|
|
||||||
{
|
|
||||||
gchar *s;
|
|
||||||
|
|
||||||
- g_object_freeze_notify (G_OBJECT (user));
|
|
||||||
-
|
|
||||||
s = g_key_file_get_string (keyfile, "User", "Language", NULL);
|
|
||||||
if (s != NULL) {
|
|
||||||
accounts_user_set_language (ACCOUNTS_USER (user), s);
|
|
||||||
g_clear_pointer (&s, g_free);
|
|
||||||
}
|
|
||||||
|
|
||||||
s = g_key_file_get_string (keyfile, "User", "XSession", NULL);
|
|
||||||
if (s != NULL) {
|
|
||||||
accounts_user_set_xsession (ACCOUNTS_USER (user), s);
|
|
||||||
|
|
||||||
/* for backward compat */
|
|
||||||
accounts_user_set_session (ACCOUNTS_USER (user), s);
|
|
||||||
g_clear_pointer (&s, g_free);
|
|
||||||
}
|
|
||||||
|
|
||||||
s = g_key_file_get_string (keyfile, "User", "Session", NULL);
|
|
||||||
if (s != NULL) {
|
|
||||||
accounts_user_set_session (ACCOUNTS_USER (user), s);
|
|
||||||
g_clear_pointer (&s, g_free);
|
|
||||||
}
|
|
||||||
|
|
||||||
s = g_key_file_get_string (keyfile, "User", "SessionType", NULL);
|
|
||||||
if (s != NULL) {
|
|
||||||
accounts_user_set_session_type (ACCOUNTS_USER (user), s);
|
|
||||||
g_clear_pointer (&s, g_free);
|
|
||||||
}
|
|
||||||
|
|
||||||
s = g_key_file_get_string (keyfile, "User", "Email", NULL);
|
|
||||||
if (s != NULL) {
|
|
||||||
accounts_user_set_email (ACCOUNTS_USER (user), s);
|
|
||||||
g_clear_pointer (&s, g_free);
|
|
||||||
}
|
|
||||||
|
|
||||||
s = g_key_file_get_string (keyfile, "User", "Location", NULL);
|
|
||||||
if (s != NULL) {
|
|
||||||
accounts_user_set_location (ACCOUNTS_USER (user), s);
|
|
||||||
g_clear_pointer (&s, g_free);
|
|
||||||
}
|
|
||||||
|
|
||||||
s = g_key_file_get_string (keyfile, "User", "PasswordHint", NULL);
|
|
||||||
if (s != NULL) {
|
|
||||||
accounts_user_set_password_hint (ACCOUNTS_USER (user), s);
|
|
||||||
g_clear_pointer (&s, g_free);
|
|
||||||
}
|
|
||||||
|
|
||||||
s = g_key_file_get_string (keyfile, "User", "Icon", NULL);
|
|
||||||
if (s != NULL) {
|
|
||||||
accounts_user_set_icon_file (ACCOUNTS_USER (user), s);
|
|
||||||
g_clear_pointer (&s, g_free);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (g_key_file_has_key (keyfile, "User", "SystemAccount", NULL)) {
|
|
||||||
gboolean system_account;
|
|
||||||
|
|
||||||
system_account = g_key_file_get_boolean (keyfile, "User", "SystemAccount", NULL);
|
|
||||||
accounts_user_set_system_account (ACCOUNTS_USER (user), system_account);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_clear_pointer (&user->keyfile, g_key_file_unref);
|
|
||||||
user->keyfile = g_key_file_ref (keyfile);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+user_update_from_cache (User *user)
|
|
||||||
+{
|
|
||||||
+ g_autofree gchar *filename = NULL;
|
|
||||||
+ g_autoptr(GKeyFile) key_file = NULL;
|
|
||||||
+
|
|
||||||
+ filename = g_build_filename (USERDIR, accounts_user_get_user_name (ACCOUNTS_USER (user)), NULL);
|
|
||||||
+
|
|
||||||
+ key_file = g_key_file_new ();
|
|
||||||
+
|
|
||||||
+ if (!g_key_file_load_from_file (key_file, filename, 0, NULL))
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ g_object_freeze_notify (G_OBJECT (user));
|
|
||||||
+ user_update_from_keyfile (user, key_file);
|
|
||||||
user_set_cached (user, TRUE);
|
|
||||||
user_set_saved (user, TRUE);
|
|
||||||
-
|
|
||||||
g_object_thaw_notify (G_OBJECT (user));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
user_update_local_account_property (User *user,
|
|
||||||
gboolean local)
|
|
||||||
{
|
|
||||||
accounts_user_set_local_account (ACCOUNTS_USER (user), local);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
user_update_system_account_property (User *user,
|
|
||||||
gboolean system)
|
|
||||||
{
|
|
||||||
accounts_user_set_system_account (ACCOUNTS_USER (user), system);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
user_save_to_keyfile (User *user,
|
|
||||||
GKeyFile *keyfile)
|
|
||||||
{
|
|
||||||
g_key_file_remove_group (keyfile, "User", NULL);
|
|
||||||
|
|
||||||
if (accounts_user_get_email (ACCOUNTS_USER (user)))
|
|
||||||
g_key_file_set_string (keyfile, "User", "Email", accounts_user_get_email (ACCOUNTS_USER (user)));
|
|
||||||
|
|
||||||
if (accounts_user_get_language (ACCOUNTS_USER (user)))
|
|
||||||
g_key_file_set_string (keyfile, "User", "Language", accounts_user_get_language (ACCOUNTS_USER (user)));
|
|
||||||
|
|
||||||
if (accounts_user_get_session (ACCOUNTS_USER (user)))
|
|
||||||
@@ -509,60 +782,63 @@ user_extension_set_property (User *user,
|
|
||||||
if (!prev || !g_str_equal (printed, prev)) {
|
|
||||||
g_key_file_set_value (user->keyfile, interface->name, property->name, printed);
|
|
||||||
|
|
||||||
/* Emit a change signal. Use invalidation
|
|
||||||
* because the data may not be world-readable.
|
|
||||||
*/
|
|
||||||
g_dbus_connection_emit_signal (g_dbus_method_invocation_get_connection (invocation),
|
|
||||||
NULL, /* destination_bus_name */
|
|
||||||
g_dbus_method_invocation_get_object_path (invocation),
|
|
||||||
"org.freedesktop.DBus.Properties", "PropertiesChanged",
|
|
||||||
g_variant_new_parsed ("( %s, %a{sv}, [ %s ] )",
|
|
||||||
interface->name, NULL, property->name),
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
accounts_user_emit_changed (ACCOUNTS_USER (user));
|
|
||||||
save_extra_data (user);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
user_extension_authentication_done (Daemon *daemon,
|
|
||||||
User *user,
|
|
||||||
GDBusMethodInvocation *invocation,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
GDBusInterfaceInfo *interface = user_data;
|
|
||||||
const gchar *method_name;
|
|
||||||
|
|
||||||
+ if (!user_has_cache_file (user))
|
|
||||||
+ user_update_from_template (user);
|
|
||||||
+
|
|
||||||
method_name = g_dbus_method_invocation_get_method_name (invocation);
|
|
||||||
|
|
||||||
if (g_str_equal (method_name, "Get"))
|
|
||||||
user_extension_get_property (user, daemon, interface, invocation);
|
|
||||||
else if (g_str_equal (method_name, "GetAll"))
|
|
||||||
user_extension_get_all_properties (user, daemon, interface, invocation);
|
|
||||||
else if (g_str_equal (method_name, "Set"))
|
|
||||||
user_extension_set_property (user, daemon, interface, invocation);
|
|
||||||
else
|
|
||||||
g_assert_not_reached ();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
user_extension_method_call (GDBusConnection *connection,
|
|
||||||
const gchar *sender,
|
|
||||||
const gchar *object_path,
|
|
||||||
const gchar *interface_name,
|
|
||||||
const gchar *method_name,
|
|
||||||
GVariant *parameters,
|
|
||||||
GDBusMethodInvocation *invocation,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
User *user = user_data;
|
|
||||||
GDBusInterfaceInfo *iface_info;
|
|
||||||
const gchar *annotation_name;
|
|
||||||
const gchar *action_id;
|
|
||||||
gint uid;
|
|
||||||
gint i;
|
|
||||||
|
|
||||||
/* We don't allow method calls on extension interfaces, so we
|
|
||||||
diff --git a/src/user.h b/src/user.h
|
|
||||||
index b3b3380..eb81918 100644
|
|
||||||
--- a/src/user.h
|
|
||||||
+++ b/src/user.h
|
|
||||||
@@ -30,58 +30,57 @@
|
|
||||||
#include "types.h"
|
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
|
||||||
|
|
||||||
#define TYPE_USER (user_get_type ())
|
|
||||||
#define USER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), TYPE_USER, User))
|
|
||||||
#define IS_USER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), TYPE_USER))
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
ACCOUNT_TYPE_STANDARD,
|
|
||||||
ACCOUNT_TYPE_ADMINISTRATOR,
|
|
||||||
#define ACCOUNT_TYPE_LAST ACCOUNT_TYPE_ADMINISTRATOR
|
|
||||||
} AccountType;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
PASSWORD_MODE_REGULAR,
|
|
||||||
PASSWORD_MODE_SET_AT_LOGIN,
|
|
||||||
PASSWORD_MODE_NONE,
|
|
||||||
#define PASSWORD_MODE_LAST PASSWORD_MODE_NONE
|
|
||||||
} PasswordMode;
|
|
||||||
|
|
||||||
/* local methods */
|
|
||||||
|
|
||||||
GType user_get_type (void) G_GNUC_CONST;
|
|
||||||
User * user_new (Daemon *daemon,
|
|
||||||
uid_t uid);
|
|
||||||
|
|
||||||
void user_update_from_pwent (User *user,
|
|
||||||
struct passwd *pwent,
|
|
||||||
struct spwd *spent);
|
|
||||||
-void user_update_from_keyfile (User *user,
|
|
||||||
- GKeyFile *keyfile);
|
|
||||||
+void user_update_from_cache (User *user);
|
|
||||||
void user_update_local_account_property (User *user,
|
|
||||||
gboolean local);
|
|
||||||
void user_update_system_account_property (User *user,
|
|
||||||
gboolean system);
|
|
||||||
gboolean user_get_cached (User *user);
|
|
||||||
void user_set_cached (User *user,
|
|
||||||
gboolean cached);
|
|
||||||
void user_set_saved (User *user,
|
|
||||||
gboolean saved);
|
|
||||||
|
|
||||||
void user_register (User *user);
|
|
||||||
void user_unregister (User *user);
|
|
||||||
void user_changed (User *user);
|
|
||||||
|
|
||||||
void user_save (User *user);
|
|
||||||
|
|
||||||
const gchar * user_get_user_name (User *user);
|
|
||||||
gboolean user_get_system_account (User *user);
|
|
||||||
gboolean user_get_local_account (User *user);
|
|
||||||
const gchar * user_get_object_path (User *user);
|
|
||||||
uid_t user_get_uid (User *user);
|
|
||||||
const gchar * user_get_shell (User *user);
|
|
||||||
|
|
||||||
G_END_DECLS
|
|
||||||
|
|
||||||
#endif
|
|
||||||
--
|
|
||||||
2.27.0
|
|
||||||
|
|
@ -1,195 +0,0 @@
|
|||||||
From 12127d9c04e8151c51bd14114dce424ff8448345 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Ray Strode <rstrode@redhat.com>
|
|
||||||
Date: Thu, 9 Sep 2021 09:40:49 -0400
|
|
||||||
Subject: [PATCH 2/2] main: Allow cache files to be marked immutable
|
|
||||||
|
|
||||||
At the moment, at start up we unconditionally reset permission of all
|
|
||||||
cache files in /var/lib/AccountsService/users. If the mode of the files
|
|
||||||
can't be reset, accountsservice fails to start.
|
|
||||||
|
|
||||||
But there's a situation where we should proceed anyway: If the
|
|
||||||
mode is already correct, and the file is read-only, there is no reason
|
|
||||||
to refuse to proceed.
|
|
||||||
|
|
||||||
This commit changes the code to explicitly validate the permissions of
|
|
||||||
the file before failing.
|
|
||||||
---
|
|
||||||
src/main.c | 29 +++++++++++++++++++++++++----
|
|
||||||
1 file changed, 25 insertions(+), 4 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/src/main.c b/src/main.c
|
|
||||||
index 01cb617..36a2d7e 100644
|
|
||||||
--- a/src/main.c
|
|
||||||
+++ b/src/main.c
|
|
||||||
@@ -16,143 +16,164 @@
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*
|
|
||||||
* Written by: Matthias Clasen <mclasen@redhat.com>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <locale.h>
|
|
||||||
#include <libintl.h>
|
|
||||||
#include <syslog.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include <glib.h>
|
|
||||||
#include <glib/gi18n.h>
|
|
||||||
#include <glib/gstdio.h>
|
|
||||||
#include <glib-unix.h>
|
|
||||||
|
|
||||||
#include "daemon.h"
|
|
||||||
|
|
||||||
#define NAME_TO_CLAIM "org.freedesktop.Accounts"
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
ensure_directory (const char *path,
|
|
||||||
gint mode,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
+ GStatBuf stat_buffer = { 0 };
|
|
||||||
+
|
|
||||||
if (g_mkdir_with_parents (path, mode) < 0) {
|
|
||||||
g_set_error (error,
|
|
||||||
G_FILE_ERROR,
|
|
||||||
g_file_error_from_errno (errno),
|
|
||||||
"Failed to create directory %s: %m",
|
|
||||||
path);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
- if (g_chmod (path, mode) < 0) {
|
|
||||||
+ g_chmod (path, mode);
|
|
||||||
+
|
|
||||||
+ if (g_stat (path, &stat_buffer) < 0) {
|
|
||||||
+ g_clear_error (error);
|
|
||||||
+
|
|
||||||
g_set_error (error,
|
|
||||||
G_FILE_ERROR,
|
|
||||||
g_file_error_from_errno (errno),
|
|
||||||
- "Failed to change permissions of directory %s: %m",
|
|
||||||
+ "Failed to validate permissions of directory %s: %m",
|
|
||||||
path);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ if ((stat_buffer.st_mode & ~S_IFMT) != mode) {
|
|
||||||
+ g_set_error (error,
|
|
||||||
+ G_FILE_ERROR,
|
|
||||||
+ g_file_error_from_errno (errno),
|
|
||||||
+ "Directory %s has wrong mode %o; it should be %o",
|
|
||||||
+ path, stat_buffer.st_mode, mode);
|
|
||||||
+ return FALSE;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
ensure_file_permissions (const char *dir_path,
|
|
||||||
gint file_mode,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
GDir *dir = NULL;
|
|
||||||
const gchar *filename;
|
|
||||||
gint errsv = 0;
|
|
||||||
|
|
||||||
dir = g_dir_open (dir_path, 0, error);
|
|
||||||
if (dir == NULL)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
while ((filename = g_dir_read_name (dir)) != NULL) {
|
|
||||||
+ GStatBuf stat_buffer = { 0 };
|
|
||||||
+
|
|
||||||
gchar *file_path = g_build_filename (dir_path, filename, NULL);
|
|
||||||
|
|
||||||
g_debug ("Changing permission of %s to %04o", file_path, file_mode);
|
|
||||||
- if (g_chmod (file_path, file_mode) < 0)
|
|
||||||
+ g_chmod (file_path, file_mode);
|
|
||||||
+
|
|
||||||
+ if (g_stat (file_path, &stat_buffer) < 0)
|
|
||||||
errsv = errno;
|
|
||||||
|
|
||||||
+ if ((stat_buffer.st_mode & ~S_IFMT) != file_mode)
|
|
||||||
+ errsv = EACCES;
|
|
||||||
+
|
|
||||||
g_free (file_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_dir_close (dir);
|
|
||||||
|
|
||||||
/* Report any errors after all chmod()s have been attempted. */
|
|
||||||
if (errsv != 0) {
|
|
||||||
g_set_error (error,
|
|
||||||
G_FILE_ERROR,
|
|
||||||
g_file_error_from_errno (errsv),
|
|
||||||
"Failed to change permissions of files in directory %s: %m",
|
|
||||||
dir_path);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
on_bus_acquired (GDBusConnection *connection,
|
|
||||||
const gchar *name,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
GMainLoop *loop = user_data;
|
|
||||||
Daemon *daemon;
|
|
||||||
g_autoptr(GError) error = NULL;
|
|
||||||
|
|
||||||
if (!ensure_directory (ICONDIR, 0775, &error) ||
|
|
||||||
!ensure_directory (USERDIR, 0700, &error) ||
|
|
||||||
!ensure_file_permissions (USERDIR, 0600, &error)) {
|
|
||||||
g_printerr ("%s\n", error->message);
|
|
||||||
g_main_loop_quit (loop);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
daemon = daemon_new ();
|
|
||||||
if (daemon == NULL) {
|
|
||||||
g_printerr ("Failed to initialize daemon\n");
|
|
||||||
g_main_loop_quit (loop);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
-
|
|
||||||
openlog ("accounts-daemon", LOG_PID, LOG_DAEMON);
|
|
||||||
syslog (LOG_INFO, "started daemon version %s", VERSION);
|
|
||||||
closelog ();
|
|
||||||
openlog ("accounts-daemon", 0, LOG_AUTHPRIV);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
on_name_lost (GDBusConnection *connection,
|
|
||||||
const gchar *name,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
GMainLoop *loop = user_data;
|
|
||||||
|
|
||||||
g_debug ("got NameLost, exiting");
|
|
||||||
g_main_loop_quit (loop);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean debug;
|
|
||||||
|
|
||||||
static void
|
|
||||||
on_log_debug (const gchar *log_domain,
|
|
||||||
GLogLevelFlags log_level,
|
|
||||||
const gchar *message,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
g_autoptr(GString) string = NULL;
|
|
||||||
const gchar *progname;
|
|
||||||
int ret G_GNUC_UNUSED;
|
|
||||||
|
|
||||||
string = g_string_new (NULL);
|
|
||||||
--
|
|
||||||
2.31.1
|
|
||||||
|
|
@ -0,0 +1,145 @@
|
|||||||
|
From 99aa57bfa59e2578c4ef47e84338f7de85c6f61b Mon Sep 17 00:00:00 2001
|
||||||
|
From: Ray Strode <rstrode@redhat.com>
|
||||||
|
Date: Tue, 11 Apr 2023 10:11:05 -0400
|
||||||
|
Subject: [PATCH 2/2] user-manager: Fix another compiler warning
|
||||||
|
|
||||||
|
-Wswitch-enum apparently complains about missing entries even if there
|
||||||
|
is a default:.
|
||||||
|
|
||||||
|
This commit ensures ACT_USER_MANAGER_SEAT_STATE_UNLOADED is added to the
|
||||||
|
default case to fix that warning.
|
||||||
|
---
|
||||||
|
src/libaccountsservice/act-user-manager.c | 2 ++
|
||||||
|
1 file changed, 2 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/src/libaccountsservice/act-user-manager.c b/src/libaccountsservice/act-user-manager.c
|
||||||
|
index 61b4da5..3bbd480 100644
|
||||||
|
--- a/src/libaccountsservice/act-user-manager.c
|
||||||
|
+++ b/src/libaccountsservice/act-user-manager.c
|
||||||
|
@@ -1727,60 +1727,61 @@ unload_seat (ActUserManager *manager)
|
||||||
|
{
|
||||||
|
ActUserManagerPrivate *priv = act_user_manager_get_instance_private (manager);
|
||||||
|
|
||||||
|
priv->seat.state = ACT_USER_MANAGER_SEAT_STATE_UNLOADED;
|
||||||
|
|
||||||
|
g_free (priv->seat.id);
|
||||||
|
priv->seat.id = NULL;
|
||||||
|
|
||||||
|
g_free (priv->seat.session_id);
|
||||||
|
priv->seat.session_id = NULL;
|
||||||
|
|
||||||
|
g_debug ("ActUserManager: seat unloaded, so trying to set loaded property");
|
||||||
|
maybe_set_is_loaded (manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
load_new_session_incrementally (ActUserManagerNewSession *new_session)
|
||||||
|
{
|
||||||
|
switch (new_session->state) {
|
||||||
|
case ACT_USER_MANAGER_NEW_SESSION_STATE_GET_UID:
|
||||||
|
get_uid_for_new_session (new_session);
|
||||||
|
break;
|
||||||
|
case ACT_USER_MANAGER_NEW_SESSION_STATE_GET_X11_DISPLAY:
|
||||||
|
get_x11_display_for_new_session (new_session);
|
||||||
|
break;
|
||||||
|
case ACT_USER_MANAGER_NEW_SESSION_STATE_MAYBE_ADD:
|
||||||
|
maybe_add_new_session (new_session);
|
||||||
|
break;
|
||||||
|
case ACT_USER_MANAGER_NEW_SESSION_STATE_LOADED:
|
||||||
|
break;
|
||||||
|
+ case ACT_USER_MANAGER_NEW_SESSION_STATE_UNLOADED:
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
free_fetch_user_request (ActUserManagerFetchUserRequest *request)
|
||||||
|
{
|
||||||
|
ActUserManager *manager = request->manager;
|
||||||
|
ActUserManagerPrivate *priv = act_user_manager_get_instance_private (manager);
|
||||||
|
|
||||||
|
if (request->user != NULL) {
|
||||||
|
g_object_set_data (G_OBJECT (request->user), "fetch-user-request", NULL);
|
||||||
|
g_object_weak_unref (G_OBJECT (request->user), (GWeakNotify) on_user_destroyed, manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->fetch_user_requests = g_slist_remove (priv->fetch_user_requests, request);
|
||||||
|
if (request->type == ACT_USER_MANAGER_FETCH_USER_FROM_USERNAME_REQUEST) {
|
||||||
|
g_free (request->username);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (request->object_path);
|
||||||
|
g_free (request->description);
|
||||||
|
|
||||||
|
g_cancellable_cancel (request->cancellable);
|
||||||
|
g_object_unref (request->cancellable);
|
||||||
|
|
||||||
|
|
||||||
|
g_debug ("ActUserManager: unrefing manager owned by fetch user request");
|
||||||
|
g_object_unref (manager);
|
||||||
|
@@ -2243,60 +2244,61 @@ load_users (ActUserManager *manager)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
load_user_paths (manager, (const char * const *) user_paths);
|
||||||
|
|
||||||
|
load_included_usernames (manager);
|
||||||
|
|
||||||
|
priv->list_cached_users_done = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
load_seat_incrementally (ActUserManager *manager)
|
||||||
|
{
|
||||||
|
ActUserManagerPrivate *priv = act_user_manager_get_instance_private (manager);
|
||||||
|
|
||||||
|
priv->seat.load_idle_id = 0;
|
||||||
|
|
||||||
|
switch (priv->seat.state) {
|
||||||
|
case ACT_USER_MANAGER_SEAT_STATE_GET_SESSION_ID:
|
||||||
|
get_current_session_id (manager);
|
||||||
|
break;
|
||||||
|
case ACT_USER_MANAGER_SEAT_STATE_GET_ID:
|
||||||
|
get_seat_id_for_current_session (manager);
|
||||||
|
break;
|
||||||
|
case ACT_USER_MANAGER_SEAT_STATE_GET_SEAT_PROXY:
|
||||||
|
get_seat_proxy (manager);
|
||||||
|
break;
|
||||||
|
case ACT_USER_MANAGER_SEAT_STATE_LOADED:
|
||||||
|
g_debug ("ActUserManager: Seat loading sequence complete");
|
||||||
|
break;
|
||||||
|
+ case ACT_USER_MANAGER_NEW_SESSION_STATE_UNLOADED:
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (priv->seat.state == ACT_USER_MANAGER_SEAT_STATE_LOADED) {
|
||||||
|
load_sessions (manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
maybe_set_is_loaded (manager);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
load_idle (ActUserManager *manager)
|
||||||
|
{
|
||||||
|
ActUserManagerPrivate *priv = act_user_manager_get_instance_private (manager);
|
||||||
|
|
||||||
|
priv->seat.state = ACT_USER_MANAGER_SEAT_STATE_UNLOADED + 1;
|
||||||
|
load_seat_incrementally (manager);
|
||||||
|
priv->load_id = 0;
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
queue_load_seat (ActUserManager *manager)
|
||||||
|
{
|
||||||
|
ActUserManagerPrivate *priv = act_user_manager_get_instance_private (manager);
|
||||||
|
|
||||||
|
--
|
||||||
|
2.39.2
|
||||||
|
|
@ -1,13 +0,0 @@
|
|||||||
# This file contains defaults for new users. To edit, first
|
|
||||||
# copy it to /etc/accountsservice/user-templates and make changes
|
|
||||||
# there
|
|
||||||
[Template]
|
|
||||||
EnvironmentFiles=/etc/os-release;
|
|
||||||
|
|
||||||
[com.redhat.AccountsServiceUser.System]
|
|
||||||
id='${ID}'
|
|
||||||
version-id='${VERSION_ID}'
|
|
||||||
|
|
||||||
[User]
|
|
||||||
Session=gnome
|
|
||||||
Icon=${HOME}/.face
|
|
Loading…
Reference in new issue