import accountsservice-0.6.50-7.el8

This commit is contained in:
CentOS Sources 2019-08-01 13:29:16 -04:00 committed by Stepan Oksanichenko
commit 3c5b0febb0
9 changed files with 3269 additions and 0 deletions

View File

@ -0,0 +1 @@
8d59b9cdc4121b34748442ee653b92d60607f2cb SOURCES/accountsservice-0.6.50.tar.xz

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
SOURCES/accountsservice-0.6.50.tar.xz

View File

@ -0,0 +1,349 @@
From dee5f443807fee3b5b279d0488df617eeed52230 Mon Sep 17 00:00:00 2001
From: Robert Ancell <robert.ancell@canonical.com>
Date: Thu, 6 Sep 2018 14:37:39 +1200
Subject: [PATCH] daemon: Fix warnings about type-punning
---
src/daemon.c | 26 +++++++++++++++-----------
1 file changed, 15 insertions(+), 11 deletions(-)
diff --git a/src/daemon.c b/src/daemon.c
index 2587b8a..00dff51 100644
--- a/src/daemon.c
+++ b/src/daemon.c
@@ -232,117 +232,118 @@ entry_generator_fgetpwent (Daemon *daemon,
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;
}
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;
- const gchar *name;
- User *user;
+ gpointer key, value;
GDir *dir;
/* First iteration */
if (*state == NULL) {
*state = g_dir_open (USERDIR, 0, &error);
if (error != NULL) {
if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
g_warning ("couldn't list user cache directory: %s", USERDIR);
return NULL;
}
}
/* Every iteration */
/*
* Use names of files of regular type to lookup information
* about each user. Loop until we find something valid.
*/
dir = *state;
while (TRUE) {
const gchar *name;
g_autofree gchar *filename = NULL;
name = g_dir_read_name (dir);
if (name == NULL)
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, (gpointer *)&name, (gpointer *)&user)) {
+ 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);
}
*state = NULL;
return NULL;
}
static struct passwd *
entry_generator_requested_users (Daemon *daemon,
GHashTable *users,
gpointer *state,
struct spwd **shadow_entry)
{
struct passwd *pwent;
GList *node;
/* First iteration */
if (*state == NULL) {
*state = daemon->priv->explicitly_requested_users;
}
/* Every iteration */
if (g_hash_table_size (users) < MAX_LOCAL_USERS) {
@@ -423,129 +424,131 @@ load_entries (Daemon *daemon,
}
if (!explicitly_requested) {
user_set_cached (user, TRUE);
}
}
/* Generator should have cleaned up */
g_assert (generator_state == NULL);
}
static GHashTable *
create_users_hash_table (void)
{
return g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
g_object_unref);
}
static void
reload_users (Daemon *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;
- User *user;
+ 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);
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, (gpointer *)&user)) {
+ 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 (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 */
old_users = daemon->priv->users;
daemon->priv->users = users;
/* Remove all the old users */
g_hash_table_iter_init (&iter, old_users);
- while (g_hash_table_iter_next (&iter, &name, (gpointer *)&user)) {
+ while (g_hash_table_iter_next (&iter, &name, &value)) {
+ User *user = value;
User *refreshed_user;
refreshed_user = g_hash_table_lookup (users, name);
if (!refreshed_user || (user_get_cached (user) && !user_get_cached (refreshed_user))) {
accounts_accounts_emit_user_deleted (ACCOUNTS_ACCOUNTS (daemon),
user_get_object_path (user));
user_unregister (user);
}
}
/* Register all the new users */
g_hash_table_iter_init (&iter, users);
- while (g_hash_table_iter_next (&iter, &name, (gpointer *)&user)) {
+ while (g_hash_table_iter_next (&iter, &name, &value)) {
+ User *user = value;
User *stale_user;
stale_user = g_hash_table_lookup (old_users, name);
if (!stale_user || (!user_get_cached (stale_user) && user_get_cached (user))) {
user_register (user);
accounts_accounts_emit_user_added (ACCOUNTS_ACCOUNTS (daemon),
user_get_object_path (user));
}
g_object_thaw_notify (G_OBJECT (user));
}
g_hash_table_destroy (old_users);
}
static gboolean
reload_users_timeout (Daemon *daemon)
{
reload_users (daemon);
daemon->priv->reload_id = 0;
return FALSE;
}
static gboolean load_autologin (Daemon *daemon,
gchar **name,
gboolean *enabled,
GError **error);
static gboolean
@@ -932,69 +935,70 @@ typedef struct {
} ListUserData;
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 gboolean
finish_list_cached_users (gpointer user_data)
{
ListUserData *data = user_data;
g_autoptr(GPtrArray) object_paths = NULL;
GHashTableIter iter;
- const gchar *name;
- User *user;
+ gpointer key, value;
uid_t uid;
const gchar *shell;
object_paths = g_ptr_array_new ();
g_hash_table_iter_init (&iter, data->daemon->priv->users);
- while (g_hash_table_iter_next (&iter, (gpointer *)&name, (gpointer *)&user)) {
+ 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)) {
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);
return FALSE;
}
static gboolean
daemon_list_cached_users (AccountsAccounts *accounts,
GDBusMethodInvocation *context)
{
Daemon *daemon = (Daemon*)accounts;
--
2.17.1

View File

@ -0,0 +1,88 @@
From b4f85d66280affcb52e998661f782c2ab4f806a7 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.21.0

View File

@ -0,0 +1,90 @@
From c7fa612023a163e8b2352e1170c6df3fceb19b27 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Thu, 19 Jul 2018 13:14:09 -0400
Subject: [PATCH] lib: don't set loaded state until seat is fetched
At the moment we set is-loaded on the user-manager
object as soon as we start fetching the seat, but
we should waiting until the seat is fetched, so
that can_switch() will return the correct value
if the caller waited until the loaded signal
to use it.
This commit changes the >= to > which I believe
was the original intention anyway.
https://bugs.freedesktop.org/show_bug.cgi?id=107298
---
src/libaccountsservice/act-user-manager.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/libaccountsservice/act-user-manager.c b/src/libaccountsservice/act-user-manager.c
index 325421b..e7e26b1 100644
--- a/src/libaccountsservice/act-user-manager.c
+++ b/src/libaccountsservice/act-user-manager.c
@@ -2355,61 +2355,61 @@ act_user_manager_list_users (ActUserManager *manager)
queue_load_seat_incrementally (manager);
}
retval = NULL;
g_hash_table_foreach (manager->priv->normal_users_by_name, listify_hash_values_hfunc, &retval);
return g_slist_sort (retval, (GCompareFunc) act_user_collate);
}
static void
maybe_set_is_loaded (ActUserManager *manager)
{
if (manager->priv->is_loaded) {
g_debug ("ActUserManager: already loaded, so not setting loaded property");
return;
}
if (manager->priv->getting_sessions) {
g_debug ("ActUserManager: GetSessions call pending, so not setting loaded property");
return;
}
if (manager->priv->new_users_inhibiting_load != NULL) {
g_debug ("ActUserManager: Loading new users, so not setting loaded property");
return;
}
/* Don't set is_loaded yet unless the seat is already loaded enough
* or failed to load.
*/
- if (manager->priv->seat.state >= ACT_USER_MANAGER_SEAT_STATE_GET_ID) {
+ if (manager->priv->seat.state > ACT_USER_MANAGER_SEAT_STATE_GET_ID) {
g_debug ("ActUserManager: Seat loaded, so now setting loaded property");
} else if (manager->priv->seat.state == ACT_USER_MANAGER_SEAT_STATE_UNLOADED) {
g_debug ("ActUserManager: Seat wouldn't load, so giving up on it and setting loaded property");
} else {
g_debug ("ActUserManager: Seat still actively loading, so not setting loaded property");
return;
}
set_is_loaded (manager, TRUE);
}
static GSList *
slist_deep_copy (const GSList *list)
{
GSList *retval;
GSList *l;
if (list == NULL)
return NULL;
retval = g_slist_copy ((GSList *) list);
for (l = retval; l != NULL; l = l->next) {
l->data = g_strdup (l->data);
}
return retval;
}
static void
--
2.17.1

View File

@ -0,0 +1,844 @@
From 4ff9bc526fec4be51f42739b4258529d7e4695a1 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 12 Oct 2018 15:53:52 -0400
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.
---
data/Makefile.am | 14 +-
.../com.redhat.AccountsServiceUser.System.xml | 10 ++
src/libaccountsservice/Makefile.am | 12 +-
src/libaccountsservice/act-user-manager.c | 123 ++++++++++++++++++
4 files changed, 157 insertions(+), 2 deletions(-)
create mode 100644 data/com.redhat.AccountsServiceUser.System.xml
diff --git a/data/Makefile.am b/data/Makefile.am
index 521c6c2..a441452 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -1,44 +1,56 @@
dbusifdir = $(datadir)/dbus-1/interfaces
dbusif_DATA = \
org.freedesktop.Accounts.xml \
- org.freedesktop.Accounts.User.xml
+ org.freedesktop.Accounts.User.xml \
+ com.redhat.AccountsServiceUser.System.xml
dbusconfdir = $(sysconfdir)/dbus-1/system.d
dbusconf_DATA = org.freedesktop.Accounts.conf
+accountsserviceifdir = $(datadir)/accountsservice/interfaces
+
servicedir = $(datadir)/dbus-1/system-services
service_in_files = org.freedesktop.Accounts.service.in
service_DATA = $(service_in_files:.service.in=.service)
$(service_DATA): $(service_in_files) Makefile
@sed -e "s|\@libexecdir\@|$(libexecdir)|" $< >$@
policydir = $(datadir)/polkit-1/actions
policy_in_files = org.freedesktop.accounts.policy.in
policy_DATA = $(policy_in_files:.policy.in=.policy)
@INTLTOOL_POLICY_RULE@
if HAVE_SYSTEMD
systemdsystemunit_DATA = \
accounts-daemon.service
accounts-daemon.service: accounts-daemon.service.in
@sed -e "s|\@libexecdir\@|$(libexecdir)|" $< >$@
endif
EXTRA_DIST = \
$(dbusif_DATA) \
$(dbusconf_DATA) \
$(service_in_files) \
$(policy_in_files) \
accounts-daemon.service.in
DISTCLEANFILES = \
$(service_DATA) \
$(policy_DATA)
CLEANFILES = \
accounts-daemon.service
+
+install-data-hook: com.redhat.AccountsServiceUser.System.xml
+ if test '!' -d $(DESTDIR)$(accountsserviceifdir); then \
+ $(mkinstalldirs) $(DESTDIR)$(accountsserviceifdir); \
+ chmod 755 $(DESTDIR)$(accountsserviceifdir); \
+ fi
+ if test '!' -L $(DESTDIR)$(accountsserviceifdir)/com.redhat.AccountsServiceUser.System.xml; then \
+ (cd $(DESTDIR)$(accountsserviceifdir); $(LN_S) ../../dbus-1/interfaces/com.redhat.AccountsServiceUser.System.xml) \
+ fi
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/src/libaccountsservice/Makefile.am b/src/libaccountsservice/Makefile.am
index 408d91f..d711d65 100644
--- a/src/libaccountsservice/Makefile.am
+++ b/src/libaccountsservice/Makefile.am
@@ -20,69 +20,79 @@ act-user-enum-types.h: act-user.h act-user-manager.h
$(AM_V_GEN) (cd $(srcdir) && \
glib-mkenums \
--fhead "#ifndef __ACT_USER_ENUM_TYPES_H__\n#define __ACT_USER_ENUM_TYPES_H__\n\n#include <glib-object.h>\n\nG_BEGIN_DECLS\n" \
--fprod "/* enumerations from \"@filename@\" */\n" \
--vhead "GType @enum_name@_get_type (void);\n#define ACT_USER_TYPE_@ENUMSHORT@ (@enum_name@_get_type())\n" \
--ftail "G_END_DECLS\n\n#endif /* __ACT_USER_ENUM_TYPES_H__ */" \
$(^F) ) > $@
act-user-enum-types.c: act-user.h act-user-manager.h act-user-enum-types.h
$(AM_V_GEN) (cd $(srcdir) && \
glib-mkenums \
--fhead "#include \"act-user.h\"\n" \
--fhead "#include \"act-user-manager.h\"\n" \
--fhead "#include \"act-user-enum-types.h\"\n" \
--fhead "#include <glib-object.h>" \
--fprod "\n/* enumerations from \"@filename@\" */" \
--vhead "GType\n@enum_name@_get_type (void)\n{\n static GType etype = 0;\n if (etype == 0) {\n static const G@Type@Value values[] = {" \
--vprod " { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" }," \
--vtail " { 0, NULL, NULL }\n };\n etype = g_@type@_register_static (\"@EnumName@\", values);\n }\n return etype;\n}\n" \
$(^F) ) > $@
ck-manager-generated.c ck-manager-generated.h: org.freedesktop.ConsoleKit.Manager.xml Makefile
$(AM_V_GEN) gdbus-codegen --generate-c-code ck-manager-generated --c-namespace ConsoleKit --interface-prefix=org.freedesktop.ConsoleKit $(srcdir)/org.freedesktop.ConsoleKit.Manager.xml
ck-seat-generated.c ck-seat-generated.h: org.freedesktop.ConsoleKit.Seat.xml Makefile
$(AM_V_GEN) gdbus-codegen --generate-c-code ck-seat-generated --c-namespace ConsoleKit --interface-prefix=org.freedesktop.ConsoleKit $(srcdir)/org.freedesktop.ConsoleKit.Seat.xml
ck-session-generated.c ck-session-generated.h: org.freedesktop.ConsoleKit.Session.xml Makefile
$(AM_V_GEN) gdbus-codegen --generate-c-code ck-session-generated --c-namespace ConsoleKit --interface-prefix=org.freedesktop.ConsoleKit $(srcdir)/org.freedesktop.ConsoleKit.Session.xml
+com.redhat.AccountsServiceUser.System.c com.redhat.AccountsServiceUser.System.h: $(top_srcdir)/data/com.redhat.AccountsServiceUser.System.xml Makefile
+ $(AM_V_GEN)gdbus-codegen \
+ --c-namespace=Act \
+ --interface-prefix=com.redhat.AccountsService \
+ --generate-c-code=com.redhat.AccountsServiceUser.System \
+ $(top_srcdir)/data/com.redhat.AccountsServiceUser.System.xml
+
+
BUILT_SOURCES += \
act-user-enum-types.c \
act-user-enum-types.h \
ck-manager-generated.c \
ck-manager-generated.h \
ck-seat-generated.c \
ck-seat-generated.h \
ck-session-generated.c \
- ck-session-generated.h
+ ck-session-generated.h \
+ com.redhat.AccountsServiceUser.System.h \
+ com.redhat.AccountsServiceUser.System.c
CLEANFILES += $(BUILT_SOURCES)
libaccountsservicedir = $(includedir)/accountsservice-1.0/act
libaccountsservice_headers = \
act-user.h \
act-user-manager.h \
act-user-enum-types.h \
$(END_OF_LIST)
libaccountsservice_HEADERS = \
act.h \
$(libaccountsservice_headers) \
$(END_OF_LIST)
libaccountsservice_la_CFLAGS = $(LIBACCOUNTSSERVICE_CFLAGS)
libaccountsservice_la_LDFLAGS = \
-export-symbols-regex '^[^_].*' \
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
-no-undefined \
$(END_OF_LIST)
libaccountsservice_la_LIBADD = \
../libaccounts-generated.la \
$(LIBACCOUNTSSERVICE_LIBS) \
-lcrypt \
$(END_OF_LIST)
libaccountsservice_la_sources = \
diff --git a/src/libaccountsservice/act-user-manager.c b/src/libaccountsservice/act-user-manager.c
index 325421b..091b46a 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
@@ -167,60 +168,63 @@ typedef struct
ActUser *user;
ActUserManagerFetchUserRequestType type;
union {
char *username;
uid_t uid;
};
char *object_path;
char *description;
} ActUserManagerFetchUserRequest;
struct ActUserManagerPrivate
{
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;
};
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);
@@ -2763,101 +2767,174 @@ 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 (manager->priv->accounts_proxy), G_MAXINT);
g_object_bind_property (G_OBJECT (manager->priv->accounts_proxy),
"has-multiple-users",
G_OBJECT (manager),
"has-multiple-users",
G_BINDING_SYNC_CREATE);
g_signal_connect (manager->priv->accounts_proxy,
"user-added",
G_CALLBACK (on_new_user_in_accounts_service),
manager);
g_signal_connect (manager->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 = manager->priv;
+ 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)
{
g_autoptr(GError) error = NULL;
manager->priv = ACT_USER_MANAGER_GET_PRIVATE (manager);
act_user_manager_error_quark (); /* register dbus errors */
/* sessions */
manager->priv->sessions = g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
g_object_unref);
/* users */
manager->priv->normal_users_by_name = g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
g_object_unref);
manager->priv->system_users_by_name = g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
g_object_unref);
manager->priv->users_by_object_path = g_hash_table_new_full (g_str_hash,
g_str_equal,
NULL,
g_object_unref);
manager->priv->connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
if (manager->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);
+
manager->priv->seat.state = ACT_USER_MANAGER_SEAT_STATE_UNLOADED;
}
static void
act_user_manager_finalize (GObject *object)
{
ActUserManager *manager;
GSList *node;
g_debug ("ActUserManager: finalizing user manager");
g_return_if_fail (object != NULL);
g_return_if_fail (ACT_IS_USER_MANAGER (object));
manager = ACT_USER_MANAGER (object);
g_return_if_fail (manager->priv != NULL);
g_slist_foreach (manager->priv->new_sessions,
(GFunc) unload_new_session, NULL);
g_slist_free (manager->priv->new_sessions);
g_slist_foreach (manager->priv->fetch_user_requests,
(GFunc) free_fetch_user_request, NULL);
g_slist_free (manager->priv->fetch_user_requests);
g_slist_free (manager->priv->new_users_inhibiting_load);
node = manager->priv->new_users;
while (node != NULL) {
@@ -2899,141 +2976,179 @@ act_user_manager_finalize (GObject *object)
#ifdef WITH_SYSTEMD
if (manager->priv->seat.session_monitor != NULL) {
sd_login_monitor_unref (manager->priv->seat.session_monitor);
}
if (manager->priv->seat.session_monitor_stream != NULL) {
g_object_unref (manager->priv->seat.session_monitor_stream);
}
if (manager->priv->seat.session_monitor_source_id != 0) {
g_source_remove (manager->priv->seat.session_monitor_source_id);
}
#endif
if (manager->priv->accounts_proxy != NULL) {
g_object_unref (manager->priv->accounts_proxy);
}
if (manager->priv->load_id > 0) {
g_source_remove (manager->priv->load_id);
manager->priv->load_id = 0;
}
g_hash_table_destroy (manager->priv->sessions);
g_hash_table_destroy (manager->priv->normal_users_by_name);
g_hash_table_destroy (manager->priv->system_users_by_name);
g_hash_table_destroy (manager->priv->users_by_object_path);
+ g_free (manager->priv->os_id);
+ g_free (manager->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)
{
return manager->priv->accounts_proxy == NULL;
}
+static void
+save_system_info (ActUserManager *manager,
+ const char *user_path)
+{
+ ActUserManagerPrivate *priv = manager->priv;
+ 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)
{
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 (manager->priv->accounts_proxy != NULL);
res = accounts_accounts_call_create_user_sync (manager->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.
*
@@ -3077,105 +3192,110 @@ act_user_manager_create_user_async (ActUserManager *manager,
* act_user_manager_create_user_finish:
* @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)
{
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 (manager->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)
{
GError *local_error = NULL;
gboolean res;
g_autofree gchar *path = NULL;
g_debug ("ActUserManager: Caching user '%s'",
username);
g_assert (manager->priv->accounts_proxy != NULL);
res = accounts_accounts_call_cache_user_sync (manager->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)
{
GTask *task;
@@ -3199,60 +3319,63 @@ act_user_manager_cache_user_async (ActUserManager *manager,
* act_user_manager_cache_user_finish:
* @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)
{
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 (manager->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)
{
GError *local_error = NULL;
--
2.17.1

View File

@ -0,0 +1,910 @@
From c66cee942242a731082f0fac649f3f9569ae99a3 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 8 Aug 2018 16:11:56 -0400
Subject: [PATCH 1/2] user: add new Session/SessionType properties to replace
XSession
Having a property called XSession in the API makes little
sense when wayland has taken the world by storm.
This commit adds new "Session" property without the "X" in the name,
and an additional property "SessionType" that can be either
"wayland" or "x11".
---
data/org.freedesktop.Accounts.User.xml | 103 +++++++++++++++++++++
src/libaccountsservice/act-user.c | 93 +++++++++++++++++++
src/libaccountsservice/act-user.h | 6 ++
src/user.c | 121 +++++++++++++++++++++++++
4 files changed, 323 insertions(+)
diff --git a/data/org.freedesktop.Accounts.User.xml b/data/org.freedesktop.Accounts.User.xml
index 4ab989a..7fc3c61 100644
--- a/data/org.freedesktop.Accounts.User.xml
+++ b/data/org.freedesktop.Accounts.User.xml
@@ -141,60 +141,143 @@
<doc:term>org.freedesktop.accounts.user-administration</doc:term>
<doc:definition>To change the language of another user</doc:definition>
</doc:item>
</doc:list>
</doc:permission>
<doc:errors>
<doc:error name="org.freedesktop.Accounts.Error.PermissionDenied">if the caller lacks the appropriate PolicyKit authorization</doc:error>
<doc:error name="org.freedesktop.Accounts.Error.Failed">if the operation failed</doc:error>
</doc:errors>
</doc:doc>
</method>
<method name="SetXSession">
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="user_set_x_session"/>
<arg name="x_session" direction="in" type="s">
<doc:doc>
<doc:summary>
The new xsession to start (e.g. "gnome")
</doc:summary>
</doc:doc>
</arg>
<doc:doc>
<doc:description>
<doc:para>
Sets the users x session.
</doc:para>
<doc:para>
The expectation is that display managers will log the user in to this
specified session, if available.
+
+ Note this call is deprecated and has been superceded by SetSession since
+ not all graphical sessions use X as the display server.
+ </doc:para>
+ </doc:description>
+ <doc:permission>
+ The caller needs one of the following PolicyKit authorizations:
+ <doc:list>
+ <doc:item>
+ <doc:term>org.freedesktop.accounts.change-own-user-data</doc:term>
+ <doc:definition>To change his own language</doc:definition>
+ </doc:item>
+ <doc:item>
+ <doc:term>org.freedesktop.accounts.user-administration</doc:term>
+ <doc:definition>To change the language of another user</doc:definition>
+ </doc:item>
+ </doc:list>
+ </doc:permission>
+ <doc:errors>
+ <doc:error name="org.freedesktop.Accounts.Error.PermissionDenied">if the caller lacks the appropriate PolicyKit authorization</doc:error>
+ <doc:error name="org.freedesktop.Accounts.Error.Failed">if the operation failed</doc:error>
+ </doc:errors>
+ </doc:doc>
+ </method>
+
+ <method name="SetSession">
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="user_set_session"/>
+ <arg name="session" direction="in" type="s">
+ <doc:doc>
+ <doc:summary>
+ The new session to start (e.g. "gnome-xorg")
+ </doc:summary>
+ </doc:doc>
+ </arg>
+ <doc:doc>
+ <doc:description>
+ <doc:para>
+ Sets the users wayland or x session.
+ </doc:para>
+ <doc:para>
+ The expectation is that display managers will log the user in to this
+ specified session, if available.
+ </doc:para>
+ </doc:description>
+ <doc:permission>
+ The caller needs one of the following PolicyKit authorizations:
+ <doc:list>
+ <doc:item>
+ <doc:term>org.freedesktop.accounts.change-own-user-data</doc:term>
+ <doc:definition>To change his own language</doc:definition>
+ </doc:item>
+ <doc:item>
+ <doc:term>org.freedesktop.accounts.user-administration</doc:term>
+ <doc:definition>To change the language of another user</doc:definition>
+ </doc:item>
+ </doc:list>
+ </doc:permission>
+ <doc:errors>
+ <doc:error name="org.freedesktop.Accounts.Error.PermissionDenied">if the caller lacks the appropriate PolicyKit authorization</doc:error>
+ <doc:error name="org.freedesktop.Accounts.Error.Failed">if the operation failed</doc:error>
+ </doc:errors>
+ </doc:doc>
+ </method>
+
+ <method name="SetSessionType">
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="user_set_session_type"/>
+ <arg name="session_type" direction="in" type="s">
+ <doc:doc>
+ <doc:summary>
+ The type of the new session to start (e.g. "wayland" or "x11")
+ </doc:summary>
+ </doc:doc>
+ </arg>
+ <doc:doc>
+ <doc:description>
+ <doc:para>
+ Sets the session type of the users session.
+ </doc:para>
+ <doc:para>
+ Display managers may use this property to decide what type of display server to use when
+ loading the session
</doc:para>
</doc:description>
<doc:permission>
The caller needs one of the following PolicyKit authorizations:
<doc:list>
<doc:item>
<doc:term>org.freedesktop.accounts.change-own-user-data</doc:term>
<doc:definition>To change his own language</doc:definition>
</doc:item>
<doc:item>
<doc:term>org.freedesktop.accounts.user-administration</doc:term>
<doc:definition>To change the language of another user</doc:definition>
</doc:item>
</doc:list>
</doc:permission>
<doc:errors>
<doc:error name="org.freedesktop.Accounts.Error.PermissionDenied">if the caller lacks the appropriate PolicyKit authorization</doc:error>
<doc:error name="org.freedesktop.Accounts.Error.Failed">if the operation failed</doc:error>
</doc:errors>
</doc:doc>
</method>
<method name="SetLocation">
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<arg name="location" direction="in" type="s">
<doc:doc>
<doc:summary>
The new location as a freeform string.
</doc:summary>
</doc:doc>
@@ -641,60 +724,80 @@
<property name="Shell" type="s" access="read">
<doc:doc>
<doc:description>
<doc:para>
The users shell.
</doc:para>
</doc:description>
</doc:doc>
</property>
<property name="Email" type="s" access="read">
<doc:doc>
<doc:description>
<doc:para>
The email address.
</doc:para>
</doc:description>
</doc:doc>
</property>
<property name="Language" type="s" access="read">
<doc:doc>
<doc:description>
<doc:para>
The users language, as a locale specification like "de_DE.UTF-8".
</doc:para>
</doc:description>
</doc:doc>
</property>
+ <property name="Session" type="s" access="read">
+ <doc:doc>
+ <doc:description>
+ <doc:para>
+ The users Wayland or X session.
+ </doc:para>
+ </doc:description>
+ </doc:doc>
+ </property>
+
+ <property name="SessionType" type="s" access="read">
+ <doc:doc>
+ <doc:description>
+ <doc:para>
+ The type of session the user should use (e.g. "wayland" or "x11")
+ </doc:para>
+ </doc:description>
+ </doc:doc>
+ </property>
+
<property name="XSession" type="s" access="read">
<doc:doc>
<doc:description>
<doc:para>
The users x session.
</doc:para>
</doc:description>
</doc:doc>
</property>
<property name="Location" type="s" access="read">
<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>
diff --git a/src/libaccountsservice/act-user.c b/src/libaccountsservice/act-user.c
index 7162221..dd8f81b 100644
--- a/src/libaccountsservice/act-user.c
+++ b/src/libaccountsservice/act-user.c
@@ -999,60 +999,98 @@ act_user_get_icon_file (ActUser *user)
const char *
act_user_get_language (ActUser *user)
{
g_return_val_if_fail (ACT_IS_USER (user), NULL);
if (user->accounts_proxy == NULL)
return NULL;
return accounts_user_get_language (user->accounts_proxy);
}
/**
* act_user_get_x_session:
* @user: a #ActUser
*
* Returns the path to the configured X session for @user.
*
* Returns: (transfer none): a path to an icon
*/
const char *
act_user_get_x_session (ActUser *user)
{
g_return_val_if_fail (ACT_IS_USER (user), NULL);
if (user->accounts_proxy == NULL)
return NULL;
return accounts_user_get_xsession (user->accounts_proxy);
}
+/**
+ * act_user_get_session:
+ * @user: a #ActUser
+ *
+ * Returns the path to the configured session for @user.
+ *
+ * Returns: (transfer none): a path to an icon
+ */
+const char *
+act_user_get_session (ActUser *user)
+{
+ g_return_val_if_fail (ACT_IS_USER (user), NULL);
+
+ if (user->accounts_proxy == NULL)
+ return NULL;
+
+ return accounts_user_get_session (user->accounts_proxy);
+}
+
+/**
+ * act_user_get_session_type:
+ * @user: a #ActUser
+ *
+ * Returns the type of the configured session for @user.
+ *
+ * Returns: (transfer none): a path to an icon
+ */
+const char *
+act_user_get_session_type (ActUser *user)
+{
+ g_return_val_if_fail (ACT_IS_USER (user), NULL);
+
+ if (user->accounts_proxy == NULL)
+ return NULL;
+
+ return accounts_user_get_session_type (user->accounts_proxy);
+}
+
/**
* act_user_get_object_path:
* @user: a #ActUser
*
* Returns the user accounts service object path of @user,
* or %NULL if @user doesn't have an object path associated
* with it.
*
* Returns: (transfer none): the object path of the user
*/
const char *
act_user_get_object_path (ActUser *user)
{
g_return_val_if_fail (ACT_IS_USER (user), NULL);
if (user->accounts_proxy == NULL)
return NULL;
return g_dbus_proxy_get_object_path (G_DBUS_PROXY (user->accounts_proxy));
}
/**
* act_user_get_primary_session_id:
* @user: a #ActUser
*
* Returns the id of the primary session of @user, or %NULL if @user
* has no primary session. The primary session will always be
* graphical and will be chosen from the sessions on the same seat as
* the seat of the session of the calling process.
*
@@ -1310,60 +1348,115 @@ act_user_set_language (ActUser *user,
}
/**
* act_user_set_x_session:
* @user: the user object to alter.
* @x_session: an x session (e.g. gnome)
*
* Assigns a new x session for @user.
*
* Note this function is synchronous and ignores errors.
**/
void
act_user_set_x_session (ActUser *user,
const char *x_session)
{
g_autoptr(GError) error = NULL;
g_return_if_fail (ACT_IS_USER (user));
g_return_if_fail (x_session != NULL);
g_return_if_fail (ACCOUNTS_IS_USER (user->accounts_proxy));
if (!accounts_user_call_set_xsession_sync (user->accounts_proxy,
x_session,
NULL,
&error)) {
g_warning ("SetXSession call failed: %s", error->message);
return;
}
}
+/**
+ * act_user_set_session:
+ * @user: the user object to alter.
+ * @session: a session (e.g. gnome)
+ *
+ * Assigns a new session for @user.
+ *
+ * Note this function is synchronous and ignores errors.
+ **/
+void
+act_user_set_session (ActUser *user,
+ const char *session)
+{
+ g_autoptr(GError) error = NULL;
+
+ g_return_if_fail (ACT_IS_USER (user));
+ g_return_if_fail (session != NULL);
+ g_return_if_fail (ACCOUNTS_IS_USER (user->accounts_proxy));
+
+ if (!accounts_user_call_set_session_sync (user->accounts_proxy,
+ session,
+ NULL,
+ &error)) {
+ g_warning ("SetSession call failed: %s", error->message);
+ return;
+ }
+}
+
+/**
+ * act_user_set_session_type:
+ * @user: the user object to alter.
+ * @session_type: a type of session (e.g. "wayland" or "x11")
+ *
+ * Assigns a type to the session for @user.
+ *
+ * Note this function is synchronous and ignores errors.
+ **/
+void
+act_user_set_session_type (ActUser *user,
+ const char *session_type)
+{
+ g_autoptr(GError) error = NULL;
+
+ g_return_if_fail (ACT_IS_USER (user));
+ g_return_if_fail (session_type != NULL);
+ g_return_if_fail (ACCOUNTS_IS_USER (user->accounts_proxy));
+
+ if (!accounts_user_call_set_session_type_sync (user->accounts_proxy,
+ session_type,
+ NULL,
+ &error)) {
+ g_warning ("SetSessionType call failed: %s", error->message);
+ return;
+ }
+}
/**
* act_user_set_location:
* @user: the user object to alter.
* @location: a location
*
* Assigns a new location for @user.
*
* Note this function is synchronous and ignores errors.
**/
void
act_user_set_location (ActUser *user,
const char *location)
{
g_autoptr(GError) error = NULL;
g_return_if_fail (ACT_IS_USER (user));
g_return_if_fail (location != NULL);
g_return_if_fail (ACCOUNTS_IS_USER (user->accounts_proxy));
if (!accounts_user_call_set_location_sync (user->accounts_proxy,
location,
NULL,
&error)) {
g_warning ("SetLocation call failed: %s", error->message);
return;
}
}
/**
diff --git a/src/libaccountsservice/act-user.h b/src/libaccountsservice/act-user.h
index c685fcc..2ef13b1 100644
--- a/src/libaccountsservice/act-user.h
+++ b/src/libaccountsservice/act-user.h
@@ -51,79 +51,85 @@ typedef struct _ActUserClass ActUserClass;
GType act_user_get_type (void) G_GNUC_CONST;
const char *act_user_get_object_path (ActUser *user);
uid_t act_user_get_uid (ActUser *user);
const char *act_user_get_user_name (ActUser *user);
const char *act_user_get_real_name (ActUser *user);
ActUserAccountType act_user_get_account_type (ActUser *user);
ActUserPasswordMode act_user_get_password_mode (ActUser *user);
const char *act_user_get_password_hint (ActUser *user);
const char *act_user_get_home_dir (ActUser *user);
const char *act_user_get_shell (ActUser *user);
const char *act_user_get_email (ActUser *user);
const char *act_user_get_location (ActUser *user);
guint act_user_get_num_sessions (ActUser *user);
guint act_user_get_num_sessions_anywhere (ActUser *user);
gboolean act_user_is_logged_in (ActUser *user);
gboolean act_user_is_logged_in_anywhere (ActUser *user);
int act_user_get_login_frequency (ActUser *user);
gint64 act_user_get_login_time (ActUser *user);
const GVariant*act_user_get_login_history (ActUser *user);
gboolean act_user_get_locked (ActUser *user);
gboolean act_user_get_automatic_login (ActUser *user);
gboolean act_user_is_system_account (ActUser *user);
gboolean act_user_is_local_account (ActUser *user);
gboolean act_user_is_nonexistent (ActUser *user);
const char *act_user_get_icon_file (ActUser *user);
const char *act_user_get_language (ActUser *user);
const char *act_user_get_x_session (ActUser *user);
+const char *act_user_get_session (ActUser *user);
+const char *act_user_get_session_type (ActUser *user);
const char *act_user_get_primary_session_id (ActUser *user);
gint act_user_collate (ActUser *user1,
ActUser *user2);
gboolean act_user_is_loaded (ActUser *user);
void act_user_get_password_expiration_policy (ActUser *user,
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);
void act_user_set_email (ActUser *user,
const char *email);
void act_user_set_language (ActUser *user,
const char *language);
void act_user_set_x_session (ActUser *user,
const char *x_session);
+void act_user_set_session (ActUser *user,
+ const char *session);
+void act_user_set_session_type (ActUser *user,
+ const char *session_type);
void act_user_set_location (ActUser *user,
const char *location);
void act_user_set_user_name (ActUser *user,
const char *user_name);
void act_user_set_real_name (ActUser *user,
const char *real_name);
void act_user_set_icon_file (ActUser *user,
const char *icon_file);
void act_user_set_account_type (ActUser *user,
ActUserAccountType account_type);
void act_user_set_password (ActUser *user,
const gchar *password,
const gchar *hint);
void act_user_set_password_hint (ActUser *user,
const gchar *hint);
void act_user_set_password_mode (ActUser *user,
ActUserPasswordMode password_mode);
void act_user_set_locked (ActUser *user,
gboolean locked);
void act_user_set_automatic_login (ActUser *user,
gboolean enabled);
#if GLIB_CHECK_VERSION(2, 44, 0)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ActUser, g_object_unref)
#endif
G_END_DECLS
#endif /* __ACT_USER_H__ */
diff --git a/src/user.c b/src/user.c
index 174530f..94c0244 100644
--- a/src/user.c
+++ b/src/user.c
@@ -232,60 +232,75 @@ user_update_from_pwent (User *user,
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);
g_object_thaw_notify (G_OBJECT (user));
}
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;
@@ -299,60 +314,66 @@ user_update_from_keyfile (User *user,
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)))
+ g_key_file_set_string (keyfile, "User", "Session", accounts_user_get_session (ACCOUNTS_USER (user)));
+
+ if (accounts_user_get_session_type (ACCOUNTS_USER (user)))
+ g_key_file_set_string (keyfile, "User", "SessionType", accounts_user_get_session_type (ACCOUNTS_USER (user)));
+
if (accounts_user_get_xsession (ACCOUNTS_USER (user)))
g_key_file_set_string (keyfile, "User", "XSession", accounts_user_get_xsession (ACCOUNTS_USER (user)));
if (accounts_user_get_location (ACCOUNTS_USER (user)))
g_key_file_set_string (keyfile, "User", "Location", accounts_user_get_location (ACCOUNTS_USER (user)));
if (accounts_user_get_password_hint (ACCOUNTS_USER (user)))
g_key_file_set_string (keyfile, "User", "PasswordHint", accounts_user_get_password_hint (ACCOUNTS_USER (user)));
if (accounts_user_get_icon_file (ACCOUNTS_USER (user)))
g_key_file_set_string (keyfile, "User", "Icon", accounts_user_get_icon_file (ACCOUNTS_USER (user)));
g_key_file_set_boolean (keyfile, "User", "SystemAccount", accounts_user_get_system_account (ACCOUNTS_USER (user)));
user_set_cached (user, TRUE);
}
static void
save_extra_data (User *user)
{
g_autofree gchar *data = NULL;
g_autofree gchar *filename = NULL;
g_autoptr(GError) error = NULL;
user_save_to_keyfile (user, user->keyfile);
data = g_key_file_to_data (user->keyfile, NULL, &error);
if (data == NULL) {
g_warning ("Saving data for user %s failed: %s",
accounts_user_get_user_name (ACCOUNTS_USER (user)), error->message);
@@ -996,60 +1017,158 @@ static gboolean
user_set_language (AccountsUser *auser,
GDBusMethodInvocation *context,
const gchar *language)
{
User *user = (User*)auser;
int uid;
const gchar *action_id;
if (!get_caller_uid (context, &uid)) {
throw_error (context, ERROR_FAILED, "identifying caller failed");
return FALSE;
}
if (accounts_user_get_uid (ACCOUNTS_USER (user)) == (uid_t) uid)
action_id = "org.freedesktop.accounts.change-own-user-data";
else
action_id = "org.freedesktop.accounts.user-administration";
daemon_local_check_auth (user->daemon,
user,
action_id,
TRUE,
user_change_language_authorized_cb,
context,
g_strdup (language),
(GDestroyNotify)g_free);
return TRUE;
}
+static void
+user_change_session_authorized_cb (Daemon *daemon,
+ User *user,
+ GDBusMethodInvocation *context,
+ gpointer user_data)
+
+{
+ const gchar *session = user_data;
+
+ if (g_strcmp0 (accounts_user_get_session (ACCOUNTS_USER (user)), session) != 0) {
+ accounts_user_set_session (ACCOUNTS_USER (user), session);
+
+ save_extra_data (user);
+ }
+
+ accounts_user_complete_set_session (ACCOUNTS_USER (user), context);
+}
+
+static gboolean
+user_set_session (AccountsUser *auser,
+ GDBusMethodInvocation *context,
+ const gchar *session)
+{
+ User *user = (User*)auser;
+ int uid;
+ const gchar *action_id;
+
+ if (!get_caller_uid (context, &uid)) {
+ throw_error (context, ERROR_FAILED, "identifying caller failed");
+ return FALSE;
+ }
+
+ if (accounts_user_get_uid (ACCOUNTS_USER (user)) == (uid_t) uid)
+ action_id = "org.freedesktop.accounts.change-own-user-data";
+ else
+ action_id = "org.freedesktop.accounts.user-administration";
+
+ daemon_local_check_auth (user->daemon,
+ user,
+ action_id,
+ TRUE,
+ user_change_session_authorized_cb,
+ context,
+ g_strdup (session),
+ (GDestroyNotify) g_free);
+
+ return TRUE;
+}
+
+static void
+user_change_session_type_authorized_cb (Daemon *daemon,
+ User *user,
+ GDBusMethodInvocation *context,
+ gpointer user_data)
+
+{
+ const gchar *session_type = user_data;
+
+ if (g_strcmp0 (accounts_user_get_session_type (ACCOUNTS_USER (user)), session_type) != 0) {
+ accounts_user_set_session_type (ACCOUNTS_USER (user), session_type);
+
+ save_extra_data (user);
+ }
+
+ accounts_user_complete_set_session_type (ACCOUNTS_USER (user), context);
+}
+
+static gboolean
+user_set_session_type (AccountsUser *auser,
+ GDBusMethodInvocation *context,
+ const gchar *session_type)
+{
+ User *user = (User*)auser;
+ int uid;
+ const gchar *action_id;
+
+ if (!get_caller_uid (context, &uid)) {
+ throw_error (context, ERROR_FAILED, "identifying caller failed");
+ return FALSE;
+ }
+
+ if (accounts_user_get_uid (ACCOUNTS_USER (user)) == (uid_t) uid)
+ action_id = "org.freedesktop.accounts.change-own-user-data";
+ else
+ action_id = "org.freedesktop.accounts.user-administration";
+
+ daemon_local_check_auth (user->daemon,
+ user,
+ action_id,
+ TRUE,
+ user_change_session_type_authorized_cb,
+ context,
+ g_strdup (session_type),
+ (GDestroyNotify) g_free);
+
+ return TRUE;
+}
+
static void
user_change_x_session_authorized_cb (Daemon *daemon,
User *user,
GDBusMethodInvocation *context,
gpointer data)
{
gchar *x_session = data;
if (g_strcmp0 (accounts_user_get_xsession (ACCOUNTS_USER (user)), x_session) != 0) {
accounts_user_set_xsession (ACCOUNTS_USER (user), x_session);
save_extra_data (user);
}
accounts_user_complete_set_xsession (ACCOUNTS_USER (user), context);
}
static gboolean
user_set_x_session (AccountsUser *auser,
GDBusMethodInvocation *context,
const gchar *x_session)
{
User *user = (User*)auser;
int uid;
const gchar *action_id;
if (!get_caller_uid (context, &uid)) {
throw_error (context, ERROR_FAILED, "identifying caller failed");
return FALSE;
@@ -1966,41 +2085,43 @@ user_finalize (GObject *object)
}
static void
user_class_init (UserClass *class)
{
GObjectClass *gobject_class;
gobject_class = G_OBJECT_CLASS (class);
gobject_class->finalize = user_finalize;
}
static void
user_accounts_user_iface_init (AccountsUserIface *iface)
{
iface->handle_set_account_type = user_set_account_type;
iface->handle_set_automatic_login = user_set_automatic_login;
iface->handle_set_email = user_set_email;
iface->handle_set_home_directory = user_set_home_directory;
iface->handle_set_icon_file = user_set_icon_file;
iface->handle_set_language = user_set_language;
iface->handle_set_location = user_set_location;
iface->handle_set_locked = user_set_locked;
iface->handle_set_password = user_set_password;
iface->handle_set_password_mode = user_set_password_mode;
iface->handle_set_password_hint = user_set_password_hint;
iface->handle_set_real_name = user_set_real_name;
iface->handle_set_shell = user_set_shell;
iface->handle_set_user_name = user_set_user_name;
iface->handle_set_xsession = user_set_x_session;
+ iface->handle_set_session = user_set_session;
+ iface->handle_set_session_type = user_set_session_type;
iface->handle_get_password_expiration_policy = user_get_password_expiration_policy;
}
static void
user_init (User *user)
{
user->system_bus_connection = NULL;
user->default_icon_file = NULL;
user->login_history = NULL;
user->keyfile = g_key_file_new ();
}
--
2.17.1

View File

@ -0,0 +1,629 @@
From 14bb1237f71e38749558c74963032a0387eecec0 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 15 Aug 2018 16:04:42 -0400
Subject: [PATCH 2/2] user: export new Saved property
accountsservice maintains a state file for some users, if those users
have selected a specific session or language.
There's no good way, at the moment, for an application to check if a
specific user has saved state.
This commit exports the Saved property on the User object.
---
data/org.freedesktop.Accounts.User.xml | 10 ++++++++++
src/daemon.c | 3 +++
src/libaccountsservice/act-user.c | 19 +++++++++++++++++++
src/libaccountsservice/act-user.h | 1 +
src/user.c | 10 ++++++++++
src/user.h | 2 ++
6 files changed, 45 insertions(+)
diff --git a/data/org.freedesktop.Accounts.User.xml b/data/org.freedesktop.Accounts.User.xml
index 7fc3c61..8d3fe1c 100644
--- a/data/org.freedesktop.Accounts.User.xml
+++ b/data/org.freedesktop.Accounts.User.xml
@@ -811,60 +811,70 @@
</doc:doc>
</property>
<property name="LoginHistory" type="a(xxa{sv})" access="read">
<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>
+ Whether the users account has retained state
+ </doc:para>
+ </doc:description>
+ </doc:doc>
+ </property>
+
<property name="Locked" type="b" access="read">
<doc:doc>
<doc:description>
<doc:para>
Whether the users account is locked.
</doc:para>
</doc:description>
</doc:doc>
</property>
<property name="PasswordMode" type="i" access="read">
<doc:doc>
<doc:description>
<doc:para>
The password mode for the user account, encoded as an integer:
<doc:list>
<doc:item>
<doc:term>0</doc:term>
<doc:definition>Regular password</doc:definition>
</doc:item>
<doc:item>
<doc:term>1</doc:term>
<doc:definition>Password must be set at next login</doc:definition>
</doc:item>
<doc:item>
<doc:term>2</doc:term>
<doc:definition>No password</doc:definition>
</doc:item>
</doc:list>
</doc:para>
diff --git a/src/daemon.c b/src/daemon.c
index 2851ed6..2587b8a 100644
--- a/src/daemon.c
+++ b/src/daemon.c
@@ -1187,60 +1187,61 @@ daemon_cache_user (AccountsAccounts *accounts,
context,
g_strdup (user_name),
g_free);
return TRUE;
}
static void
daemon_uncache_user_authorized_cb (Daemon *daemon,
User *dummy,
GDBusMethodInvocation *context,
gpointer data)
{
const gchar *user_name = data;
User *user;
sys_log (context, "uncache user '%s'", user_name);
user = daemon_local_find_user_by_name (daemon, user_name);
if (user == NULL) {
throw_error (context, ERROR_USER_DOES_NOT_EXIST,
"No user with the name %s found", user_name);
return;
}
/* Always use the canonical user name looked up */
user_name = user_get_user_name (user);
remove_cache_files (user_name);
+ user_set_saved (user, FALSE);
user_set_cached (user, FALSE);
accounts_accounts_complete_uncache_user (NULL, context);
queue_reload_users (daemon);
}
static gboolean
daemon_uncache_user (AccountsAccounts *accounts,
GDBusMethodInvocation *context,
const gchar *user_name)
{
Daemon *daemon = (Daemon*)accounts;
daemon_local_check_auth (daemon,
NULL,
"org.freedesktop.accounts.user-administration",
TRUE,
daemon_uncache_user_authorized_cb,
context,
g_strdup (user_name),
g_free);
return TRUE;
}
typedef struct {
uid_t uid;
gboolean remove_files;
} DeleteUserData;
@@ -1252,60 +1253,62 @@ daemon_delete_user_authorized_cb (Daemon *daemon,
gpointer data)
{
DeleteUserData *ud = data;
g_autoptr(GError) error = NULL;
struct passwd *pwent;
const gchar *argv[6];
User *user;
pwent = getpwuid (ud->uid);
if (pwent == NULL) {
throw_error (context, ERROR_USER_DOES_NOT_EXIST, "No user with uid %d found", ud->uid);
return;
}
sys_log (context, "delete user '%s' (%d)", pwent->pw_name, ud->uid);
user = daemon_local_find_user_by_id (daemon, ud->uid);
if (user != NULL) {
user_set_cached (user, FALSE);
if (daemon->priv->autologin == user) {
daemon_local_set_automatic_login (daemon, user, FALSE, NULL);
}
}
remove_cache_files (pwent->pw_name);
+ user_set_saved (user, FALSE);
+
argv[0] = "/usr/sbin/userdel";
if (ud->remove_files) {
argv[1] = "-f";
argv[2] = "-r";
argv[3] = "--";
argv[4] = pwent->pw_name;
argv[5] = NULL;
}
else {
argv[1] = "-f";
argv[2] = "--";
argv[3] = pwent->pw_name;
argv[4] = NULL;
}
if (!spawn_with_login_uid (context, argv, &error)) {
throw_error (context, ERROR_FAILED, "running '%s' failed: %s", argv[0], error->message);
return;
}
accounts_accounts_complete_delete_user (NULL, context);
}
static gboolean
daemon_delete_user (AccountsAccounts *accounts,
GDBusMethodInvocation *context,
gint64 uid,
gboolean remove_files)
{
diff --git a/src/libaccountsservice/act-user.c b/src/libaccountsservice/act-user.c
index dd8f81b..540ffe7 100644
--- a/src/libaccountsservice/act-user.c
+++ b/src/libaccountsservice/act-user.c
@@ -849,60 +849,79 @@ act_user_collate (ActUser *user1,
*
* Returns whether or not #ActUser is currently graphically logged in
* on the same seat as the seat of the session of the calling process.
*
* Returns: %TRUE or %FALSE
*/
gboolean
act_user_is_logged_in (ActUser *user)
{
return user->our_sessions != NULL;
}
/**
* act_user_is_logged_in_anywhere:
* @user: a #ActUser
*
* Returns whether or not #ActUser is currently logged in in any way
* whatsoever. See also act_user_is_logged_in().
*
* (Currently, this function is only implemented for systemd-logind.
* For ConsoleKit, it is equivalent to act_user_is_logged_in.)
*
* Returns: %TRUE or %FALSE
*/
gboolean
act_user_is_logged_in_anywhere (ActUser *user)
{
return user->our_sessions != NULL || user->other_sessions != NULL;
}
+/**
+ * act_user_get_saved:
+ * @user: a #ActUser
+ *
+ * Returns whether or not the #ActUser account has retained state in accountsservice.
+ *
+ * Returns: %TRUE or %FALSE
+ */
+gboolean
+act_user_get_saved (ActUser *user)
+{
+ g_return_val_if_fail (ACT_IS_USER (user), TRUE);
+
+ if (user->accounts_proxy == NULL)
+ return FALSE;
+
+ return accounts_user_get_saved (user->accounts_proxy);
+}
+
/**
* act_user_get_locked:
* @user: a #ActUser
*
* Returns whether or not the #ActUser account is locked.
*
* Returns: %TRUE or %FALSE
*/
gboolean
act_user_get_locked (ActUser *user)
{
g_return_val_if_fail (ACT_IS_USER (user), TRUE);
if (user->accounts_proxy == NULL)
return TRUE;
return accounts_user_get_locked (user->accounts_proxy);
}
/**
* act_user_get_automatic_login:
* @user: a #ActUser
*
* Returns whether or not #ActUser is automatically logged in at boot time.
*
* Returns: %TRUE or %FALSE
*/
gboolean
act_user_get_automatic_login (ActUser *user)
{
diff --git a/src/libaccountsservice/act-user.h b/src/libaccountsservice/act-user.h
index 2ef13b1..34d7fe3 100644
--- a/src/libaccountsservice/act-user.h
+++ b/src/libaccountsservice/act-user.h
@@ -43,60 +43,61 @@ typedef enum {
typedef enum {
ACT_USER_PASSWORD_MODE_REGULAR,
ACT_USER_PASSWORD_MODE_SET_AT_LOGIN,
ACT_USER_PASSWORD_MODE_NONE,
} ActUserPasswordMode;
typedef struct _ActUser ActUser;
typedef struct _ActUserClass ActUserClass;
GType act_user_get_type (void) G_GNUC_CONST;
const char *act_user_get_object_path (ActUser *user);
uid_t act_user_get_uid (ActUser *user);
const char *act_user_get_user_name (ActUser *user);
const char *act_user_get_real_name (ActUser *user);
ActUserAccountType act_user_get_account_type (ActUser *user);
ActUserPasswordMode act_user_get_password_mode (ActUser *user);
const char *act_user_get_password_hint (ActUser *user);
const char *act_user_get_home_dir (ActUser *user);
const char *act_user_get_shell (ActUser *user);
const char *act_user_get_email (ActUser *user);
const char *act_user_get_location (ActUser *user);
guint act_user_get_num_sessions (ActUser *user);
guint act_user_get_num_sessions_anywhere (ActUser *user);
gboolean act_user_is_logged_in (ActUser *user);
gboolean act_user_is_logged_in_anywhere (ActUser *user);
int act_user_get_login_frequency (ActUser *user);
gint64 act_user_get_login_time (ActUser *user);
const GVariant*act_user_get_login_history (ActUser *user);
+gboolean act_user_get_saved (ActUser *user);
gboolean act_user_get_locked (ActUser *user);
gboolean act_user_get_automatic_login (ActUser *user);
gboolean act_user_is_system_account (ActUser *user);
gboolean act_user_is_local_account (ActUser *user);
gboolean act_user_is_nonexistent (ActUser *user);
const char *act_user_get_icon_file (ActUser *user);
const char *act_user_get_language (ActUser *user);
const char *act_user_get_x_session (ActUser *user);
const char *act_user_get_session (ActUser *user);
const char *act_user_get_session_type (ActUser *user);
const char *act_user_get_primary_session_id (ActUser *user);
gint act_user_collate (ActUser *user1,
ActUser *user2);
gboolean act_user_is_loaded (ActUser *user);
void act_user_get_password_expiration_policy (ActUser *user,
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);
void act_user_set_email (ActUser *user,
const char *email);
void act_user_set_language (ActUser *user,
const char *language);
void act_user_set_x_session (ActUser *user,
const char *x_session);
diff --git a/src/user.c b/src/user.c
index 94c0244..93afadc 100644
--- a/src/user.c
+++ b/src/user.c
@@ -284,60 +284,61 @@ user_update_from_keyfile (User *user,
}
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);
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)));
@@ -357,60 +358,62 @@ user_save_to_keyfile (User *user,
g_key_file_set_string (keyfile, "User", "PasswordHint", accounts_user_get_password_hint (ACCOUNTS_USER (user)));
if (accounts_user_get_icon_file (ACCOUNTS_USER (user)))
g_key_file_set_string (keyfile, "User", "Icon", accounts_user_get_icon_file (ACCOUNTS_USER (user)));
g_key_file_set_boolean (keyfile, "User", "SystemAccount", accounts_user_get_system_account (ACCOUNTS_USER (user)));
user_set_cached (user, TRUE);
}
static void
save_extra_data (User *user)
{
g_autofree gchar *data = NULL;
g_autofree gchar *filename = NULL;
g_autoptr(GError) error = NULL;
user_save_to_keyfile (user, user->keyfile);
data = g_key_file_to_data (user->keyfile, NULL, &error);
if (data == NULL) {
g_warning ("Saving data for user %s failed: %s",
accounts_user_get_user_name (ACCOUNTS_USER (user)), error->message);
return;
}
filename = g_build_filename (USERDIR,
accounts_user_get_user_name (ACCOUNTS_USER (user)),
NULL);
g_file_set_contents (filename, data, -1, &error);
+
+ user_set_saved (user, TRUE);
}
static void
move_extra_data (const gchar *old_name,
const gchar *new_name)
{
g_autofree gchar *old_filename = NULL;
g_autofree gchar *new_filename = NULL;
old_filename = g_build_filename (USERDIR,
old_name, NULL);
new_filename = g_build_filename (USERDIR,
new_name, NULL);
g_rename (old_filename, new_filename);
}
static GVariant *
user_extension_get_value (User *user,
GDBusInterfaceInfo *interface,
const GDBusPropertyInfo *property)
{
const GVariantType *type = G_VARIANT_TYPE (property->signature);
GVariant *value;
g_autofree gchar *printed = NULL;
gint i;
/* First, try to get the value from the keyfile */
printed = g_key_file_get_value (user->keyfile, interface->name, property->name, NULL);
if (printed) {
@@ -773,60 +776,67 @@ const gchar *
user_get_object_path (User *user)
{
return g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON (user));
}
uid_t
user_get_uid (User *user)
{
return accounts_user_get_uid (ACCOUNTS_USER (user));
}
const gchar *
user_get_shell(User *user)
{
return accounts_user_get_shell (ACCOUNTS_USER (user));
}
gboolean
user_get_cached (User *user)
{
return user->cached;
}
void
user_set_cached (User *user,
gboolean cached)
{
user->cached = cached;
}
+void
+user_set_saved (User *user,
+ gboolean saved)
+{
+ accounts_user_set_saved (ACCOUNTS_USER (user), saved);
+}
+
static void
throw_error (GDBusMethodInvocation *context,
gint error_code,
const gchar *format,
...)
{
va_list args;
g_autofree gchar *message = NULL;
va_start (args, format);
message = g_strdup_vprintf (format, args);
va_end (args);
g_dbus_method_invocation_return_error (context, ERROR, error_code, "%s", message);
}
static void
user_change_real_name_authorized_cb (Daemon *daemon,
User *user,
GDBusMethodInvocation *context,
gpointer data)
{
gchar *name = data;
g_autoptr(GError) error = NULL;
const gchar *argv[6];
if (g_strcmp0 (accounts_user_get_real_name (ACCOUNTS_USER (user)), name) != 0) {
sys_log (context,
"change real name of user '%s' (%d) to '%s'",
diff --git a/src/user.h b/src/user.h
index 39c6f13..b3b3380 100644
--- a/src/user.h
+++ b/src/user.h
@@ -39,47 +39,49 @@ 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_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.17.1

357
SPECS/accountsservice.spec Normal file
View File

@ -0,0 +1,357 @@
%global _hardened_build 1
Name: accountsservice
Version: 0.6.50
Release: 7%{?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
BuildRequires: glib2-devel
BuildRequires: polkit-devel
BuildRequires: libtool, automake, autoconf, gettext-devel, intltool
BuildRequires: systemd
BuildRequires: systemd-devel
BuildRequires: gobject-introspection-devel
BuildRequires: gtk-doc
BuildRequires: git
Patch01: 0001-user-add-new-Session-SessionType-properties-to-repla.patch
Patch02: 0002-user-export-new-Saved-property.patch
Patch10: 0001-daemon-Fix-warnings-about-type-punning.patch
Patch20: 0001-lib-don-t-set-loaded-state-until-seat-is-fetched.patch
Patch30: 0001-data-don-t-send-change-updates-for-login-history.patch
Patch90: 0001-lib-save-os-when-creating-user.patch
Requires: polkit
Requires: shadow-utils
%{?systemd_requires}
%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
autoreconf -f -i
%build
export CFLAGS="$RPM_OPT_FLAGS -fno-strict-aliasing"
%configure --enable-user-heuristics
make %{?_smp_mflags}
%install
make install DESTDIR=$RPM_BUILD_ROOT
rm $RPM_BUILD_ROOT%{_libdir}/*.la
rm $RPM_BUILD_ROOT%{_libdir}/*.a
%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 AUTHORS
%{_sysconfdir}/dbus-1/system.d/org.freedesktop.Accounts.conf
%{_libexecdir}/accounts-daemon
%{_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}/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 Jun 17 2019 Ray Strode <rstrode@redhat.com> - 0.6.50-7
- Don't send change updates for login history changes
Resolves: #1713080
* Mon Nov 26 2018 Ray Strode <rstrode@redhat.com> - 0.6.50-6
- Fix user switching before screen lock
Resolves: #1653263
* Mon Oct 15 2018 Ray Strode <rstrode@redhat.com> - 0.6.50-5
- Turn off aliasing optimizations until glib codegen is fixed
Related: #1628060 1639428
* Fri Oct 12 2018 Ray Strode <rstrode@redhat.com> - 0.6.50-4
Correct rpmdiff complaints
Related: #1628060
* Fri Oct 12 2018 Ray Strode <rstrode@redhat.com> - 0.6.50-3
- Record OS in user data when creating new users
Related: #1628060
* Mon Aug 20 2018 Ray Strode <rstrode@redhat.com> - 0.6.50-2
- add new api needed for handling upgrades from RHEL 7
Related: #1612915 1595825
* Fri Jul 13 2018 Ray Strode <rstrode@redhat.com> - 0.6.50-1
- Update to 0.6.50
Related: #1597499
* 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
- Initial packaging, based on work by Richard Hughes