| 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 |
| |
| |
| @@ -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 |
| |
| |
| @@ -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 |
| |
| |
| @@ -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 |
| |
| |
| @@ -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 |
| |
| |
| @@ -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 |
| |
| |
| @@ -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 |
| |