Toshaan Bharvani
3 years ago
commit
0edf99b17f
8 changed files with 4670 additions and 0 deletions
@ -0,0 +1,304 @@ |
|||||||
|
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
@ -0,0 +1,88 @@ |
|||||||
|
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 |
||||||
|
|
@ -0,0 +1,894 @@ |
|||||||
|
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,925 @@ |
|||||||
|
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 |
||||||
|
|
@ -0,0 +1,195 @@ |
|||||||
|
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,13 @@ |
|||||||
|
# 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 |
@ -0,0 +1,412 @@ |
|||||||
|
%global _hardened_build 1 |
||||||
|
|
||||||
|
Name: accountsservice |
||||||
|
Version: 0.6.55 |
||||||
|
Release: 9%{?dist} |
||||||
|
Summary: D-Bus interfaces for querying and manipulating user account information |
||||||
|
License: GPLv3+ |
||||||
|
URL: https://www.freedesktop.org/wiki/Software/AccountsService/ |
||||||
|
|
||||||
|
#VCS: git:git://git.freedesktop.org/accountsservice |
||||||
|
Source0: http://www.freedesktop.org/software/accountsservice/accountsservice-%{version}.tar.xz |
||||||
|
Source1: user-template |
||||||
|
|
||||||
|
BuildRequires: gettext-devel |
||||||
|
BuildRequires: pkgconfig(dbus-1) |
||||||
|
BuildRequires: glib2-devel |
||||||
|
BuildRequires: polkit-devel |
||||||
|
BuildRequires: systemd |
||||||
|
BuildRequires: systemd-devel |
||||||
|
BuildRequires: gobject-introspection-devel |
||||||
|
BuildRequires: gtk-doc |
||||||
|
BuildRequires: git |
||||||
|
BuildRequires: meson |
||||||
|
|
||||||
|
Requires: polkit |
||||||
|
Requires: shadow-utils |
||||||
|
%{?systemd_requires} |
||||||
|
|
||||||
|
Patch10001: 0001-data-don-t-send-change-updates-for-login-history.patch |
||||||
|
|
||||||
|
Patch20001: 0001-daemon-if-no-local-users-check-if-machine-is-enrolle.patch |
||||||
|
|
||||||
|
Patch30001: 0001-lib-save-os-when-creating-user.patch |
||||||
|
|
||||||
|
Patch40001: 0001-user-Introduce-user-templates-for-setting-default-se.patch |
||||||
|
|
||||||
|
Patch50001: 0001-daemon-Allow-SystemAccount-false-to-be-set-in-cache-.patch |
||||||
|
Patch50002: 0002-main-Allow-cache-files-to-be-marked-immutable.patch |
||||||
|
|
||||||
|
%description |
||||||
|
The accountsservice project provides a set of D-Bus interfaces for |
||||||
|
querying and manipulating user account information and an implementation |
||||||
|
of these interfaces, based on the useradd, usermod and userdel commands. |
||||||
|
|
||||||
|
%package libs |
||||||
|
Summary: Client-side library to talk to accountsservice |
||||||
|
Requires: %{name} = %{version}-%{release} |
||||||
|
|
||||||
|
%description libs |
||||||
|
The accountsservice-libs package contains a library that can |
||||||
|
be used by applications that want to interact with the accountsservice |
||||||
|
daemon. |
||||||
|
|
||||||
|
%package devel |
||||||
|
Summary: Development files for accountsservice-libs |
||||||
|
Requires: %{name}-libs = %{version}-%{release} |
||||||
|
|
||||||
|
%description devel |
||||||
|
The accountsservice-devel package contains headers and other |
||||||
|
files needed to build applications that use accountsservice-libs. |
||||||
|
|
||||||
|
|
||||||
|
%prep |
||||||
|
%autosetup -S git |
||||||
|
|
||||||
|
%build |
||||||
|
%meson -Dgtk_doc=true -Dsystemd=true -Duser_heuristics=true |
||||||
|
%meson_build |
||||||
|
|
||||||
|
%install |
||||||
|
%meson_install |
||||||
|
|
||||||
|
mkdir -p $RPM_BUILD_ROOT%{_datadir}/accountsservice/interfaces/ |
||||||
|
mkdir -p $RPM_BUILD_ROOT%{_datadir}/accountsservice/user-templates $RPM_BUILD_ROOT%{_sysconfdir}/accountsservice/user-templates |
||||||
|
cp $RPM_SOURCE_DIR/user-template $RPM_BUILD_ROOT%{_datadir}/accountsservice/user-templates/standard |
||||||
|
cp $RPM_SOURCE_DIR/user-template $RPM_BUILD_ROOT%{_datadir}/accountsservice/user-templates/administrator |
||||||
|
|
||||||
|
|
||||||
|
%find_lang accounts-service |
||||||
|
|
||||||
|
%ldconfig_scriptlets libs |
||||||
|
|
||||||
|
%post |
||||||
|
%systemd_post accounts-daemon.service |
||||||
|
|
||||||
|
%preun |
||||||
|
%systemd_preun accounts-daemon.service |
||||||
|
|
||||||
|
%postun |
||||||
|
%systemd_postun accounts-daemon.service |
||||||
|
|
||||||
|
%files -f accounts-service.lang |
||||||
|
%license COPYING |
||||||
|
%doc README.md AUTHORS |
||||||
|
%dir %{_sysconfdir}/accountsservice/user-templates |
||||||
|
%dir %{_sysconfdir}/accountsservice |
||||||
|
%{_sysconfdir}/dbus-1/system.d/org.freedesktop.Accounts.conf |
||||||
|
%{_libexecdir}/accounts-daemon |
||||||
|
%dir %{_datadir}/accountsservice/ |
||||||
|
%dir %{_datadir}/accountsservice/interfaces/ |
||||||
|
%{_datadir}/dbus-1/interfaces/org.freedesktop.Accounts.xml |
||||||
|
%{_datadir}/dbus-1/interfaces/org.freedesktop.Accounts.User.xml |
||||||
|
%{_datadir}/dbus-1/system-services/org.freedesktop.Accounts.service |
||||||
|
%{_datadir}/polkit-1/actions/org.freedesktop.accounts.policy |
||||||
|
%{_datadir}/accountsservice/interfaces/com.redhat.AccountsServiceUser.System.xml |
||||||
|
%{_datadir}/accountsservice/user-templates/administrator |
||||||
|
%{_datadir}/accountsservice/user-templates/standard |
||||||
|
%{_datadir}/dbus-1/interfaces/com.redhat.AccountsServiceUser.System.xml |
||||||
|
%dir %{_localstatedir}/lib/AccountsService/ |
||||||
|
%dir %{_localstatedir}/lib/AccountsService/users |
||||||
|
%dir %{_localstatedir}/lib/AccountsService/icons |
||||||
|
%{_unitdir}/accounts-daemon.service |
||||||
|
|
||||||
|
%files libs |
||||||
|
%{_libdir}/libaccountsservice.so.* |
||||||
|
%{_libdir}/girepository-1.0/AccountsService-1.0.typelib |
||||||
|
|
||||||
|
%files devel |
||||||
|
%{_includedir}/accountsservice-1.0 |
||||||
|
%{_libdir}/libaccountsservice.so |
||||||
|
%{_libdir}/pkgconfig/accountsservice.pc |
||||||
|
%{_datadir}/gir-1.0/AccountsService-1.0.gir |
||||||
|
%dir %{_datadir}/gtk-doc/html/libaccountsservice |
||||||
|
%{_datadir}/gtk-doc/html/libaccountsservice/* |
||||||
|
|
||||||
|
%changelog |
||||||
|
* Mon Oct 25 2021 Ray Strode <rstrode@redhat.com> - 0.6.55-9 |
||||||
|
- Bring in RHEL-8 patches |
||||||
|
Resolves: #2014692 |
||||||
|
|
||||||
|
* Mon Aug 09 2021 Mohan Boddu <mboddu@redhat.com> - 0.6.55-8 |
||||||
|
- Rebuilt for IMA sigs, glibc 2.34, aarch64 flags |
||||||
|
Related: rhbz#1991688 |
||||||
|
|
||||||
|
* Thu Apr 15 2021 Mohan Boddu <mboddu@redhat.com> - 0.6.55-7 |
||||||
|
- Rebuilt for RHEL 9 BETA on Apr 15th 2021. Related: rhbz#1947937 |
||||||
|
|
||||||
|
* Mon Jan 25 2021 Fedora Release Engineering <releng@fedoraproject.org> - 0.6.55-6 |
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild |
||||||
|
|
||||||
|
* Fri Sep 04 2020 Bastien Nocera <bnocera@redhat.com> - 0.6.55-5 |
||||||
|
+ accountsservice-0.6.55-5 |
||||||
|
- Own /usr/share/accountsservice |
||||||
|
|
||||||
|
* Fri Jul 31 2020 Fedora Release Engineering <releng@fedoraproject.org> - 0.6.55-4 |
||||||
|
- Second attempt - Rebuilt for |
||||||
|
https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild |
||||||
|
|
||||||
|
* Mon Jul 27 2020 Fedora Release Engineering <releng@fedoraproject.org> - 0.6.55-3 |
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild |
||||||
|
|
||||||
|
* Tue Jan 28 2020 Fedora Release Engineering <releng@fedoraproject.org> - 0.6.55-2 |
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild |
||||||
|
|
||||||
|
* Thu Sep 26 2019 Benjamin Berg <bberg@redhat.com> - 0.6.55-1 |
||||||
|
- Update to 0.6.55 |
||||||
|
Resolves: #1755838 |
||||||
|
|
||||||
|
* Wed Jul 24 2019 Fedora Release Engineering <releng@fedoraproject.org> - 0.6.54-6 |
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild |
||||||
|
|
||||||
|
* Thu Jan 31 2019 Fedora Release Engineering <releng@fedoraproject.org> - 0.6.54-5 |
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild |
||||||
|
|
||||||
|
* Mon Jan 21 2019 Alexandru-Sever Horin <alex.sever.h@gmail.com> - 0.6.54-4 |
||||||
|
- Add patch from upstream to fix UID detection |
||||||
|
Resolves: #1646418 |
||||||
|
|
||||||
|
* Thu Jan 17 2019 Adam Williamson <awilliam@redhat.com> - 0.6.54-3 |
||||||
|
- Explicitly enable systemd support (#1576903) (Elliott Sales de Andrade) |
||||||
|
|
||||||
|
* Mon Jan 14 2019 Björn Esser <besser82@fedoraproject.org> - 0.6.54-2 |
||||||
|
- Rebuilt for libcrypt.so.2 (#1666033) |
||||||
|
|
||||||
|
* Sat Sep 29 2018 Ray Strode <rstrode@redhat.com> - 0.6.54-1 |
||||||
|
- Update to 0.6.54 |
||||||
|
|
||||||
|
* Thu Sep 27 2018 Ray Strode <rstrode@redhat.com> - 0.6.53-1 |
||||||
|
- Update to 0.6.53 |
||||||
|
|
||||||
|
* Mon Sep 24 2018 Adam Williamson <awilliam@redhat.com> - 0.6.50-1 |
||||||
|
- Update to 0.6.50, plus a couple of backported patches |
||||||
|
Resolves: #1576903 |
||||||
|
|
||||||
|
* Thu Jul 12 2018 Fedora Release Engineering <releng@fedoraproject.org> - 0.6.49-2 |
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild |
||||||
|
|
||||||
|
* Thu May 10 2018 Ray Strode <rstrode@redhat.com> - 0.6.49-1 |
||||||
|
- Update to 0.6.49 (brown bag release) |
||||||
|
|
||||||
|
* Thu May 10 2018 Ray Strode <rstrode@redhat.com> - 0.6.48-1 |
||||||
|
- Update to 0.6.48 |
||||||
|
Resolves: #1575780 |
||||||
|
|
||||||
|
* Fri May 04 2018 Ray Strode <rstrode@redhat.com> - 0.6.47-2 |
||||||
|
- fix crash on user deletion |
||||||
|
Resolves: #1573550 |
||||||
|
|
||||||
|
* Tue Apr 24 2018 Ray Strode <rstrode@redhat.com> - 0.6.47-1 |
||||||
|
- Update to 0.6.47 |
||||||
|
|
||||||
|
* Sat Apr 21 2018 Peter Robinson <pbrobinson@fedoraproject.org> 0.4.46-1 |
||||||
|
- Update to 0.6.46 |
||||||
|
- Spec cleanup, use %%license |
||||||
|
|
||||||
|
* Wed Feb 07 2018 Fedora Release Engineering <releng@fedoraproject.org> - 0.6.42-9 |
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild |
||||||
|
|
||||||
|
* Sun Feb 04 2018 Igor Gnatenko <ignatenkobrain@fedoraproject.org> - 0.6.42-8 |
||||||
|
- Switch to %%ldconfig_scriptlets |
||||||
|
|
||||||
|
* Thu Jan 25 2018 Igor Gnatenko <ignatenkobrain@fedoraproject.org> - 0.6.42-7 |
||||||
|
- Fix systemd executions/requirements |
||||||
|
|
||||||
|
* Wed Jan 24 2018 Ray Strode <rstrode@redhat.com> - 0.6.42-6 |
||||||
|
- Fix crash introduced by glibc/libxcrypt change |
||||||
|
https://fedoraproject.org/wiki/Changes/Replace_glibc_libcrypt_with_libxcrypt |
||||||
|
Resolves: #1538181 |
||||||
|
|
||||||
|
* Sat Jan 20 2018 Björn Esser <besser82@fedoraproject.org> - 0.6.42-5 |
||||||
|
- Rebuilt for switch to libxcrypt |
||||||
|
|
||||||
|
* Wed Aug 02 2017 Fedora Release Engineering <releng@fedoraproject.org> - 0.6.42-4 |
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild |
||||||
|
|
||||||
|
* Wed Jul 26 2017 Fedora Release Engineering <releng@fedoraproject.org> - 0.6.42-3 |
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild |
||||||
|
|
||||||
|
* Fri Feb 10 2017 Fedora Release Engineering <releng@fedoraproject.org> - 0.6.42-2 |
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild |
||||||
|
|
||||||
|
* Thu Jun 09 2016 Ray Strode <rstrode@redhat.com> - 0.6.42-1 |
||||||
|
- Update to 0.6.42 |
||||||
|
- Fixes systemd incompatibility |
||||||
|
|
||||||
|
* Tue May 31 2016 Ray Strode <rstrode@redhat.com> - 0.6.40-4 |
||||||
|
- Don't create /root/.cache at startup |
||||||
|
Resolves: #1331926 |
||||||
|
|
||||||
|
* Wed Feb 03 2016 Fedora Release Engineering <releng@fedoraproject.org> - 0.6.40-3 |
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild |
||||||
|
|
||||||
|
* Tue Jun 16 2015 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.6.40-2 |
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild |
||||||
|
|
||||||
|
* Fri Jan 23 2015 Ray Strode <rstrode@redhat.com> 0.6.40-1 |
||||||
|
- Update to 0.6.40 |
||||||
|
|
||||||
|
* Fri Oct 17 2014 Ray Strode <rstrode@redhat.com> 0.6.39-2 |
||||||
|
- More ListCachedUsers race fixes (this time with SSSD) |
||||||
|
Related: #1147504 |
||||||
|
|
||||||
|
* Thu Oct 16 2014 Ray Strode <rstrode@redhat.com> 0.6.39-1 |
||||||
|
- Update to 0.6.39 |
||||||
|
- Fixes ListCachedUsers race at startup |
||||||
|
|
||||||
|
* Thu Sep 18 2014 Stef Walter <stefw@redhat.com> - 0.6.38-1 |
||||||
|
- Update to 0.6.38 |
||||||
|
- Fixes polkit policy rhbz#1094138 |
||||||
|
- Remove dbus-glib-devel dependency, accountsservice uses gdbus now |
||||||
|
|
||||||
|
* Fri Aug 15 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.6.37-3 |
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild |
||||||
|
|
||||||
|
* Tue Jul 22 2014 Kalev Lember <kalevlember@gmail.com> - 0.6.37-2 |
||||||
|
- Rebuilt for gobject-introspection 1.41.4 |
||||||
|
|
||||||
|
* Sat Jun 07 2014 Kalev Lember <kalevlember@gmail.com> - 0.6.37-1 |
||||||
|
- Update to 0.6.37, drop upstreamed patches |
||||||
|
|
||||||
|
* Sat Jun 07 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.6.35-5 |
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild |
||||||
|
|
||||||
|
* Fri Jan 10 2014 Matthias Clasen <mclasen@redhat.com> - 0.6.35-4 |
||||||
|
- Consistently call userdel with -f |
||||||
|
|
||||||
|
* Wed Nov 20 2013 Ray Strode <rstrode@redhat.com> 0.6.35-3 |
||||||
|
- Only treat users < 1000 as system users |
||||||
|
- only use user heuristics on the range 500-1000 |
||||||
|
|
||||||
|
* Mon Nov 11 2013 Ray Strode <rstrode@redhat.com> 0.6.35-2 |
||||||
|
- pass --enable-user-heuristics which fedora needs so users |
||||||
|
with UIDs less than 1000 show up in the user list. |
||||||
|
|
||||||
|
* Mon Oct 28 2013 Ray Strode <rstrode@redhat.com> 0.6.35-1 |
||||||
|
- Update to 0.6.35 |
||||||
|
Related: #1013721 |
||||||
|
|
||||||
|
* Sat Aug 03 2013 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.6.34-2 |
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild |
||||||
|
|
||||||
|
* Tue Jun 11 2013 Ray Strode <rstrode@redhat.com> 0.6.34-1 |
||||||
|
- Update to 0.6.34 |
||||||
|
|
||||||
|
* Tue Jun 11 2013 Matthias Clasen <mclasen@redhat.com> - 0.6.33-1 |
||||||
|
- Update to 0.6.33 |
||||||
|
|
||||||
|
* Tue May 14 2013 Matthias Clasen <mclasen@redhat.com> - 0.6.32-1 |
||||||
|
- Update to 0.6.32 |
||||||
|
|
||||||
|
* Thu Apr 18 2013 Matthias Clasen <mclasen@redhat.com> - 0.6.31-2 |
||||||
|
- Hardened build |
||||||
|
|
||||||
|
* Tue Apr 16 2013 Matthias Clasen <mclasen@redhat.com> - 0.6.31-1 |
||||||
|
- Update to 0.6.31 |
||||||
|
|
||||||
|
* Wed Feb 13 2013 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.6.30-2 |
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild |
||||||
|
|
||||||
|
* Wed Jan 16 2013 Richard Hughes <rhughes@redhat.com> - 0.6.30-1 |
||||||
|
- Update to 0.6.30 |
||||||
|
|
||||||
|
* Fri Nov 16 2012 Matthias Clasen <mclasen@redhat.com> - 0.6.26-1 |
||||||
|
- Update to 0.6.26 |
||||||
|
|
||||||
|
* Tue Oct 2 2012 Matthias Clasen <mclasen@redhat.com> - 0.6.25-2 |
||||||
|
- Update to 0.6.25 |
||||||
|
- Use systemd scriptlets (#856649) |
||||||
|
|
||||||
|
* Wed Jul 18 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.6.22-3 |
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild |
||||||
|
|
||||||
|
* Sat Jul 14 2012 Ville Skyttä <ville.skytta@iki.fi> - 0.6.22-2 |
||||||
|
- Add ldconfig scriptlets to -libs. |
||||||
|
|
||||||
|
* Thu Jun 28 2012 Ray Strode <rstrode@redhat.com> 0.6.22-1 |
||||||
|
- Update to 0.6.22. |
||||||
|
- Fixes CVE-2012-2737 - local file disclosure |
||||||
|
Related: #832532 |
||||||
|
|
||||||
|
* Thu May 30 2012 Matthias Clasen <mclasen@redhatcom> 0.6.21-1 |
||||||
|
- Update to 0.6.21 |
||||||
|
|
||||||
|
* Fri May 04 2012 Ray Strode <rstrode@redhat.com> 0.6.20-1 |
||||||
|
- Update to 0.6.20. Should fix user list. |
||||||
|
Related: #814690 |
||||||
|
|
||||||
|
* Thu May 03 2012 Ray Strode <rstrode@redhat.com> 0.6.19-1 |
||||||
|
- Update to 0.6.19 |
||||||
|
Allows user deletion of logged in users |
||||||
|
Related: #814690 |
||||||
|
|
||||||
|
* Wed Apr 11 2012 Matthias Clasen <mclsaen@redhat.com> - 0.6.18-1 |
||||||
|
- Update to 0.6.18 |
||||||
|
|
||||||
|
* Tue Mar 27 2012 Ray Strode <rstrode@redhat.com> 0.6.17-1 |
||||||
|
- Update to latest release |
||||||
|
|
||||||
|
* Sun Mar 4 2012 Peter Robinson <pbrobinson@fedoraproject.org> - 0.6.15-4 |
||||||
|
- Fix unitdir with usrmove |
||||||
|
|
||||||
|
* Thu Jan 12 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.6.15-3 |
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild |
||||||
|
|
||||||
|
* Tue Nov 29 2011 Matthias Clasen <mclasen@redhat.com> 0.6.15-2 |
||||||
|
- Make resetting user icons work |
||||||
|
- Update to 0.6.15 |
||||||
|
- Fixes session chooser at login screen when logged into vt |
||||||
|
|
||||||
|
* Wed Sep 21 2011 Ray Strode <rstrode@redhat.com> 0.6.14-2 |
||||||
|
- Fix wtmp loading so users coming from the network are |
||||||
|
remembered in the user list in subsequent boots |
||||||
|
|
||||||
|
* Wed Sep 21 2011 Ray Strode <rstrode@redhat.com> 0.6.14-1 |
||||||
|
- Update to 0.6.14 |
||||||
|
|
||||||
|
* Sun Sep 4 2011 Matthias Clasen <mclasen@redhat.com> - 0.6.13-3 |
||||||
|
- Fix fast user switching |
||||||
|
|
||||||
|
* Mon Aug 15 2011 Kalev Lember <kalevlember@gmail.com> - 0.6.13-2 |
||||||
|
- Rebuilt for rpm bug #728707 |
||||||
|
|
||||||
|
* Tue Jul 19 2011 Matthias Clasen <mclasen@redhat.com> - 0.6.13-1 |
||||||
|
- Update to 0.6.13 |
||||||
|
- Drop ConsoleKit dependency |
||||||
|
|
||||||
|
* Mon Jun 06 2011 Ray Strode <rstrode@redhat.com> 0.6.12-1 |
||||||
|
- Update to latest release |
||||||
|
|
||||||
|
* Wed May 18 2011 Matthias Clasen <mclasen@redhat.com> 0.6.11-1 |
||||||
|
- Update to 0.6.11 |
||||||
|
|
||||||
|
* Mon Feb 07 2011 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.6.3-2 |
||||||
|
- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild |
||||||
|
|
||||||
|
* Wed Feb 02 2011 Ray Strode <rstrode@redhat.com> 0.6.3-1 |
||||||
|
- Update to 0.6.3 |
||||||
|
|
||||||
|
* Thu Jan 27 2011 Matthias Clasen <mclasen@redhat.com> 0.6.2-1 |
||||||
|
- Update to 0.6.2 |
||||||
|
|
||||||
|
* Wed Jul 21 2010 Matthias Clasen <mclasen@redhat.com> 0.6.1-1 |
||||||
|
- Update to 0.6.1 |
||||||
|
- Install systemd unit file |
||||||
|
|
||||||
|
* Mon Apr 5 2010 Matthias Clasen <mclasen@redhat.com> 0.6-2 |
||||||
|
- Always emit changed signal on icon change |
||||||
|
|
||||||
|
* Tue Mar 30 2010 Matthias Clasen <mclasen@redhat.com> 0.6-1 |
||||||
|
- Update to 0.6 |
||||||
|
|
||||||
|
* Mon Mar 22 2010 Matthias Clasen <mclasen@redhat.com> 0.5-1 |
||||||
|
- Update to 0.5 |
||||||
|
|
||||||
|
* Mon Feb 22 2010 Bastien Nocera <bnocera@redhat.com> 0.4-3 |
||||||
|
- Fix directory ownership |
||||||
|
|
||||||
|
* Mon Feb 22 2010 Bastien Nocera <bnocera@redhat.com> 0.4-2 |
||||||
|
- Add missing directories to the filelist |
||||||
|
|
||||||
|
* Fri Jan 29 2010 Matthias Clasen <mclasen@redhat.com> 0.4-1 |
||||||
|
- |
Loading…
Reference in new issue