From c66cee942242a731082f0fac649f3f9569ae99a3 Mon Sep 17 00:00:00 2001 From: Ray Strode 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 @@ org.freedesktop.accounts.user-administration To change the language of another user if the caller lacks the appropriate PolicyKit authorization if the operation failed The new xsession to start (e.g. "gnome") Sets the users x session. 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. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.change-own-user-data + To change his own language + + + org.freedesktop.accounts.user-administration + To change the language of another user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + + The new session to start (e.g. "gnome-xorg") + + + + + + + Sets the users wayland or x session. + + + The expectation is that display managers will log the user in to this + specified session, if available. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.change-own-user-data + To change his own language + + + org.freedesktop.accounts.user-administration + To change the language of another user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + + The type of the new session to start (e.g. "wayland" or "x11") + + + + + + + Sets the session type of the users session. + + + Display managers may use this property to decide what type of display server to use when + loading the session The caller needs one of the following PolicyKit authorizations: org.freedesktop.accounts.change-own-user-data To change his own language org.freedesktop.accounts.user-administration To change the language of another user if the caller lacks the appropriate PolicyKit authorization if the operation failed The new location as a freeform string. @@ -641,60 +724,80 @@ The users shell. The email address. The users language, as a locale specification like "de_DE.UTF-8". + + + + + The users Wayland or X session. + + + + + + + + + + The type of session the user should use (e.g. "wayland" or "x11") + + + + + The users x session. The users location. How often the user has logged in. 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