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