From 22b08727980cefd665b8805376710e9244523fe3 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Tue, 14 Aug 2018 14:52:41 -0400 Subject: [PATCH 2/4] session: support new accountsservice Session and SessionType props At the moment the user's session is stored in a property called "XSession". This is pretty weird if the user is using wayland. AccountService now supports a more generic property "Session" and a related "SessionType" property to replace "XSession". This commit switches GDM over to use the new properties. --- daemon/gdm-session-settings.c | 61 ++++++++++++++++++++++-- daemon/gdm-session-settings.h | 3 ++ daemon/gdm-session-worker.c | 28 +++++++++++ daemon/gdm-session-worker.xml | 3 ++ daemon/gdm-session.c | 87 +++++++++++++++++++++++++---------- 5 files changed, 153 insertions(+), 29 deletions(-) diff --git a/daemon/gdm-session-settings.c b/daemon/gdm-session-settings.c index 484a3b5b..f2b1addd 100644 --- a/daemon/gdm-session-settings.c +++ b/daemon/gdm-session-settings.c @@ -12,114 +12,121 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. * * Written by: Ray Strode */ #include "config.h" #include "gdm-session-settings.h" #include #include #include #include #include #include #include #include #include struct _GdmSessionSettingsPrivate { ActUserManager *user_manager; ActUser *user; char *session_name; + char *session_type; char *language_name; }; static void gdm_session_settings_finalize (GObject *object); static void gdm_session_settings_class_install_properties (GdmSessionSettingsClass * settings_class); static void gdm_session_settings_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void gdm_session_settings_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); enum { PROP_0 = 0, PROP_SESSION_NAME, + PROP_SESSION_TYPE, PROP_LANGUAGE_NAME, PROP_IS_LOADED }; G_DEFINE_TYPE_WITH_PRIVATE (GdmSessionSettings, gdm_session_settings, G_TYPE_OBJECT) static void gdm_session_settings_class_init (GdmSessionSettingsClass *settings_class) { GObjectClass *object_class; object_class = G_OBJECT_CLASS (settings_class); object_class->finalize = gdm_session_settings_finalize; gdm_session_settings_class_install_properties (settings_class); } static void gdm_session_settings_class_install_properties (GdmSessionSettingsClass *settings_class) { GObjectClass *object_class; GParamSpec *param_spec; object_class = G_OBJECT_CLASS (settings_class); object_class->set_property = gdm_session_settings_set_property; object_class->get_property = gdm_session_settings_get_property; param_spec = g_param_spec_string ("session-name", "Session Name", "The name of the session", NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_SESSION_NAME, param_spec); + param_spec = g_param_spec_string ("session-type", "Session Type", + "The type of the session", + NULL, G_PARAM_READWRITE); + g_object_class_install_property (object_class, PROP_SESSION_TYPE, param_spec); + param_spec = g_param_spec_string ("language-name", "Language Name", "The name of the language", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_LANGUAGE_NAME, param_spec); param_spec = g_param_spec_boolean ("is-loaded", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_IS_LOADED, param_spec); } static void gdm_session_settings_init (GdmSessionSettings *settings) { settings->priv = G_TYPE_INSTANCE_GET_PRIVATE (settings, GDM_TYPE_SESSION_SETTINGS, GdmSessionSettingsPrivate); settings->priv->user_manager = act_user_manager_get_default (); } static void gdm_session_settings_finalize (GObject *object) { GdmSessionSettings *settings; GObjectClass *parent_class; settings = GDM_SESSION_SETTINGS (object); @@ -136,172 +143,212 @@ gdm_session_settings_finalize (GObject *object) parent_class->finalize (object); } } void gdm_session_settings_set_language_name (GdmSessionSettings *settings, const char *language_name) { g_return_if_fail (GDM_IS_SESSION_SETTINGS (settings)); if (settings->priv->language_name == NULL || strcmp (settings->priv->language_name, language_name) != 0) { settings->priv->language_name = g_strdup (language_name); g_object_notify (G_OBJECT (settings), "language-name"); } } void gdm_session_settings_set_session_name (GdmSessionSettings *settings, const char *session_name) { g_return_if_fail (GDM_IS_SESSION_SETTINGS (settings)); if (settings->priv->session_name == NULL || strcmp (settings->priv->session_name, session_name) != 0) { settings->priv->session_name = g_strdup (session_name); g_object_notify (G_OBJECT (settings), "session-name"); } } +void +gdm_session_settings_set_session_type (GdmSessionSettings *settings, + const char *session_type) +{ + g_return_if_fail (GDM_IS_SESSION_SETTINGS (settings)); + + if (settings->priv->session_type == NULL || + g_strcmp0 (settings->priv->session_type, session_type) != 0) { + settings->priv->session_type = g_strdup (session_type); + g_object_notify (G_OBJECT (settings), "session-type"); + } +} + char * gdm_session_settings_get_language_name (GdmSessionSettings *settings) { g_return_val_if_fail (GDM_IS_SESSION_SETTINGS (settings), NULL); return g_strdup (settings->priv->language_name); } char * gdm_session_settings_get_session_name (GdmSessionSettings *settings) { g_return_val_if_fail (GDM_IS_SESSION_SETTINGS (settings), NULL); return g_strdup (settings->priv->session_name); } +char * +gdm_session_settings_get_session_type (GdmSessionSettings *settings) +{ + g_return_val_if_fail (GDM_IS_SESSION_SETTINGS (settings), NULL); + return g_strdup (settings->priv->session_type); +} + static void gdm_session_settings_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GdmSessionSettings *settings; settings = GDM_SESSION_SETTINGS (object); switch (prop_id) { case PROP_LANGUAGE_NAME: gdm_session_settings_set_language_name (settings, g_value_get_string (value)); break; case PROP_SESSION_NAME: gdm_session_settings_set_session_name (settings, g_value_get_string (value)); break; + case PROP_SESSION_TYPE: + gdm_session_settings_set_session_type (settings, g_value_get_string (value)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void gdm_session_settings_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GdmSessionSettings *settings; settings = GDM_SESSION_SETTINGS (object); switch (prop_id) { case PROP_SESSION_NAME: g_value_set_string (value, settings->priv->session_name); break; + case PROP_SESSION_TYPE: + g_value_set_string (value, settings->priv->session_type); + break; + case PROP_LANGUAGE_NAME: g_value_set_string (value, settings->priv->language_name); break; case PROP_IS_LOADED: g_value_set_boolean (value, gdm_session_settings_is_loaded (settings)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } GdmSessionSettings * gdm_session_settings_new (void) { GdmSessionSettings *settings; settings = g_object_new (GDM_TYPE_SESSION_SETTINGS, NULL); return settings; } gboolean gdm_session_settings_is_loaded (GdmSessionSettings *settings) { if (settings->priv->user == NULL) { return FALSE; } return act_user_is_loaded (settings->priv->user); } static void load_settings_from_user (GdmSessionSettings *settings) { const char *session_name; + const char *session_type; const char *language_name; if (!act_user_is_loaded (settings->priv->user)) { g_warning ("GdmSessionSettings: trying to load user settings from unloaded user"); return; } - session_name = act_user_get_x_session (settings->priv->user); - g_debug ("GdmSessionSettings: saved session is %s", session_name); - if (session_name != NULL) { + + + + session_type = act_user_get_session_type (settings->priv->user); + session_name = act_user_get_session (settings->priv->user); + + g_debug ("GdmSessionSettings: saved session is %s (type %s)", session_name, session_type); + + if (session_type != NULL && session_type[0] != '\0') { + gdm_session_settings_set_session_type (settings, session_type); + } + + if (session_name != NULL && session_name[0] != '\0') { gdm_session_settings_set_session_name (settings, session_name); } language_name = act_user_get_language (settings->priv->user); g_debug ("GdmSessionSettings: saved language is %s", language_name); - if (language_name != NULL) { + if (language_name != NULL && language_name[0] != '\0') { gdm_session_settings_set_language_name (settings, language_name); } +out: g_object_notify (G_OBJECT (settings), "is-loaded"); } static void on_user_is_loaded_changed (ActUser *user, GParamSpec *pspec, GdmSessionSettings *settings) { if (act_user_is_loaded (settings->priv->user)) { load_settings_from_user (settings); g_signal_handlers_disconnect_by_func (G_OBJECT (settings->priv->user), G_CALLBACK (on_user_is_loaded_changed), settings); } } gboolean gdm_session_settings_load (GdmSessionSettings *settings, const char *username) { ActUser *old_user; g_return_val_if_fail (settings != NULL, FALSE); g_return_val_if_fail (username != NULL, FALSE); g_return_val_if_fail (!gdm_session_settings_is_loaded (settings), FALSE); if (settings->priv->user != NULL) { old_user = settings->priv->user; g_signal_handlers_disconnect_by_func (G_OBJECT (settings->priv->user), @@ -322,40 +369,44 @@ gdm_session_settings_load (GdmSessionSettings *settings, G_CALLBACK (on_user_is_loaded_changed), settings); return FALSE; } load_settings_from_user (settings); return TRUE; } gboolean gdm_session_settings_save (GdmSessionSettings *settings, const char *username) { ActUser *user; g_return_val_if_fail (GDM_IS_SESSION_SETTINGS (settings), FALSE); g_return_val_if_fail (username != NULL, FALSE); g_return_val_if_fail (gdm_session_settings_is_loaded (settings), FALSE); user = act_user_manager_get_user (settings->priv->user_manager, username); if (!act_user_is_loaded (user)) { g_object_unref (user); return FALSE; } if (settings->priv->session_name != NULL) { - act_user_set_x_session (user, settings->priv->session_name); + act_user_set_session (user, settings->priv->session_name); + } + + if (settings->priv->session_type != NULL) { + act_user_set_session_type (user, settings->priv->session_type); } if (settings->priv->language_name != NULL) { act_user_set_language (user, settings->priv->language_name); } g_object_unref (user); return TRUE; } diff --git a/daemon/gdm-session-settings.h b/daemon/gdm-session-settings.h index 20946bff..db38ffc7 100644 --- a/daemon/gdm-session-settings.h +++ b/daemon/gdm-session-settings.h @@ -33,37 +33,40 @@ G_BEGIN_DECLS #define GDM_IS_SESSION_SETTINGS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDM_TYPE_SESSION_SETTINGS)) #define GDM_SESSION_SETTINGS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GDM_TYPE_SESSION_SETTINGS, GdmSessionSettingsClass)) #define GDM_SESSION_SETTINGS_ERROR (gdm_session_settings_error_quark ()) typedef struct _GdmSessionSettings GdmSessionSettings; typedef struct _GdmSessionSettingsClass GdmSessionSettingsClass; typedef struct _GdmSessionSettingsPrivate GdmSessionSettingsPrivate; struct _GdmSessionSettings { GObject parent; /*< private > */ GdmSessionSettingsPrivate *priv; }; struct _GdmSessionSettingsClass { GObjectClass parent_class; }; GType gdm_session_settings_get_type (void); GdmSessionSettings *gdm_session_settings_new (void); gboolean gdm_session_settings_load (GdmSessionSettings *settings, const char *username); gboolean gdm_session_settings_save (GdmSessionSettings *settings, const char *username); gboolean gdm_session_settings_is_loaded (GdmSessionSettings *settings); char *gdm_session_settings_get_language_name (GdmSessionSettings *settings); char *gdm_session_settings_get_session_name (GdmSessionSettings *settings); +char *gdm_session_settings_get_session_type (GdmSessionSettings *settings); void gdm_session_settings_set_language_name (GdmSessionSettings *settings, const char *language_name); void gdm_session_settings_set_session_name (GdmSessionSettings *settings, const char *session_name); +void gdm_session_settings_set_session_type (GdmSessionSettings *settings, + const char *session_type); G_END_DECLS #endif /* GDM_SESSION_SETTINGS_H */ diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c index 438348df..9cff53a5 100644 --- a/daemon/gdm-session-worker.c +++ b/daemon/gdm-session-worker.c @@ -2662,60 +2662,74 @@ gdm_session_worker_handle_set_language_name (GdmDBusWorker *object, gdm_dbus_worker_complete_set_language_name (object, invocation); return TRUE; } static void on_saved_language_name_read (GdmSessionWorker *worker) { char *language_name; language_name = gdm_session_settings_get_language_name (worker->priv->user_settings); g_debug ("GdmSessionWorker: Saved language is %s", language_name); gdm_dbus_worker_emit_saved_language_name_read (GDM_DBUS_WORKER (worker), language_name); g_free (language_name); } static void on_saved_session_name_read (GdmSessionWorker *worker) { char *session_name; session_name = gdm_session_settings_get_session_name (worker->priv->user_settings); g_debug ("GdmSessionWorker: Saved session is %s", session_name); gdm_dbus_worker_emit_saved_session_name_read (GDM_DBUS_WORKER (worker), session_name); g_free (session_name); } +static void +on_saved_session_type_read (GdmSessionWorker *worker) +{ + char *session_type; + + session_type = gdm_session_settings_get_session_type (worker->priv->user_settings); + + g_debug ("GdmSessionWorker: Saved session type is %s", session_type); + gdm_dbus_worker_emit_saved_session_type_read (GDM_DBUS_WORKER (worker), + session_type); + g_free (session_type); +} + + static void do_setup (GdmSessionWorker *worker) { GError *error; gboolean res; error = NULL; res = gdm_session_worker_initialize_pam (worker, worker->priv->service, (const char **) worker->priv->extensions, worker->priv->username, worker->priv->hostname, worker->priv->display_is_local, worker->priv->x11_display_name, worker->priv->x11_authority_file, worker->priv->display_device, worker->priv->display_seat_id, &error); if (res) { g_dbus_method_invocation_return_value (worker->priv->pending_invocation, NULL); } else { g_dbus_method_invocation_take_error (worker->priv->pending_invocation, error); } worker->priv->pending_invocation = NULL; } static void do_authenticate (GdmSessionWorker *worker) { @@ -3125,158 +3139,172 @@ gdm_session_worker_handle_initialize (GdmDBusWorker *object, } else if (g_strcmp0 (key, "x11-authority-file") == 0) { worker->priv->x11_authority_file = g_variant_dup_string (value, NULL); } else if (g_strcmp0 (key, "console") == 0) { worker->priv->display_device = g_variant_dup_string (value, NULL); } else if (g_strcmp0 (key, "seat-id") == 0) { worker->priv->display_seat_id = g_variant_dup_string (value, NULL); } else if (g_strcmp0 (key, "hostname") == 0) { worker->priv->hostname = g_variant_dup_string (value, NULL); } else if (g_strcmp0 (key, "display-is-local") == 0) { worker->priv->display_is_local = g_variant_get_boolean (value); } else if (g_strcmp0 (key, "display-is-initial") == 0) { worker->priv->display_is_initial = g_variant_get_boolean (value); } } worker->priv->pending_invocation = invocation; if (!worker->priv->is_program_session) { worker->priv->user_settings = gdm_session_settings_new (); g_signal_connect_swapped (worker->priv->user_settings, "notify::language-name", G_CALLBACK (on_saved_language_name_read), worker); g_signal_connect_swapped (worker->priv->user_settings, "notify::session-name", G_CALLBACK (on_saved_session_name_read), worker); + g_signal_connect_swapped (worker->priv->user_settings, + "notify::session-type", + G_CALLBACK (on_saved_session_type_read), + worker); + if (worker->priv->username) { wait_for_settings = !gdm_session_settings_load (worker->priv->user_settings, worker->priv->username); } } if (wait_for_settings) { /* Load settings from accounts daemon before continuing */ g_signal_connect (G_OBJECT (worker->priv->user_settings), "notify::is-loaded", G_CALLBACK (on_settings_is_loaded_changed), worker); } else { queue_state_change (worker); } return TRUE; } static gboolean gdm_session_worker_handle_setup (GdmDBusWorker *object, GDBusMethodInvocation *invocation, const char *service, const char *x11_display_name, const char *x11_authority_file, const char *console, const char *seat_id, const char *hostname, gboolean display_is_local, gboolean display_is_initial) { GdmSessionWorker *worker = GDM_SESSION_WORKER (object); validate_and_queue_state_change (worker, invocation, GDM_SESSION_WORKER_STATE_SETUP_COMPLETE); worker->priv->service = g_strdup (service); worker->priv->x11_display_name = g_strdup (x11_display_name); worker->priv->x11_authority_file = g_strdup (x11_authority_file); worker->priv->display_device = g_strdup (console); worker->priv->display_seat_id = g_strdup (seat_id); worker->priv->hostname = g_strdup (hostname); worker->priv->display_is_local = display_is_local; worker->priv->display_is_initial = display_is_initial; worker->priv->username = NULL; worker->priv->user_settings = gdm_session_settings_new (); g_signal_connect_swapped (worker->priv->user_settings, "notify::language-name", G_CALLBACK (on_saved_language_name_read), worker); g_signal_connect_swapped (worker->priv->user_settings, "notify::session-name", G_CALLBACK (on_saved_session_name_read), worker); + g_signal_connect_swapped (worker->priv->user_settings, + "notify::session-type", + G_CALLBACK (on_saved_session_type_read), + worker); + return TRUE; } static gboolean gdm_session_worker_handle_setup_for_user (GdmDBusWorker *object, GDBusMethodInvocation *invocation, const char *service, const char *username, const char *x11_display_name, const char *x11_authority_file, const char *console, const char *seat_id, const char *hostname, gboolean display_is_local, gboolean display_is_initial) { GdmSessionWorker *worker = GDM_SESSION_WORKER (object); if (!validate_state_change (worker, invocation, GDM_SESSION_WORKER_STATE_SETUP_COMPLETE)) return TRUE; worker->priv->service = g_strdup (service); worker->priv->x11_display_name = g_strdup (x11_display_name); worker->priv->x11_authority_file = g_strdup (x11_authority_file); worker->priv->display_device = g_strdup (console); worker->priv->display_seat_id = g_strdup (seat_id); worker->priv->hostname = g_strdup (hostname); worker->priv->display_is_local = display_is_local; worker->priv->display_is_initial = display_is_initial; worker->priv->username = g_strdup (username); worker->priv->user_settings = gdm_session_settings_new (); g_signal_connect_swapped (worker->priv->user_settings, "notify::language-name", G_CALLBACK (on_saved_language_name_read), worker); g_signal_connect_swapped (worker->priv->user_settings, "notify::session-name", G_CALLBACK (on_saved_session_name_read), worker); + g_signal_connect_swapped (worker->priv->user_settings, + "notify::session-type", + G_CALLBACK (on_saved_session_type_read), + worker); /* Load settings from accounts daemon before continuing */ worker->priv->pending_invocation = invocation; if (gdm_session_settings_load (worker->priv->user_settings, username)) { queue_state_change (worker); } else { g_signal_connect (G_OBJECT (worker->priv->user_settings), "notify::is-loaded", G_CALLBACK (on_settings_is_loaded_changed), worker); } return TRUE; } static gboolean gdm_session_worker_handle_setup_for_program (GdmDBusWorker *object, GDBusMethodInvocation *invocation, const char *service, const char *username, const char *x11_display_name, const char *x11_authority_file, const char *console, const char *seat_id, const char *hostname, gboolean display_is_local, gboolean display_is_initial, const char *log_file) { diff --git a/daemon/gdm-session-worker.xml b/daemon/gdm-session-worker.xml index 4280fe09..a215779c 100644 --- a/daemon/gdm-session-worker.xml +++ b/daemon/gdm-session-worker.xml @@ -51,40 +51,43 @@ + + + diff --git a/daemon/gdm-session.c b/daemon/gdm-session.c index 72afe7b2..f4d0bef9 100644 --- a/daemon/gdm-session.c +++ b/daemon/gdm-session.c @@ -61,60 +61,61 @@ #define GDM_SESSION_DBUS_OBJECT_PATH "/org/gnome/DisplayManager/Session" #define GDM_WORKER_DBUS_PATH "/org/gnome/DisplayManager/Worker" typedef struct { GdmSession *session; GdmSessionWorkerJob *job; GPid worker_pid; char *service_name; GDBusMethodInvocation *starting_invocation; char *starting_username; GDBusMethodInvocation *pending_invocation; GdmDBusWorkerManager *worker_manager_interface; GdmDBusWorker *worker_proxy; GCancellable *worker_cancellable; char *session_id; guint32 is_stopping : 1; GPid reauth_pid_of_caller; } GdmSessionConversation; struct _GdmSession { GObject parent; /* per open scope */ char *selected_program; char *selected_session; char *saved_session; + char *saved_session_type; char *saved_language; char *selected_user; char *user_x11_authority_file; char *timed_login_username; int timed_login_delay; GList *pending_timed_login_invocations; GHashTable *conversations; GdmSessionConversation *session_conversation; char **conversation_environment; GdmDBusUserVerifier *user_verifier_interface; GHashTable *user_verifier_extensions; GdmDBusGreeter *greeter_interface; GdmDBusRemoteGreeter *remote_greeter_interface; GdmDBusChooser *chooser_interface; GList *pending_worker_connections; GList *outside_connections; GPid session_pid; /* object lifetime scope */ char *session_type; char *display_name; char *display_hostname; char *display_device; @@ -328,309 +329,325 @@ on_establish_credentials_cb (GdmDBusWorker *proxy, case GDM_SESSION_VERIFICATION_MODE_REAUTHENTICATE: if (self->user_verifier_interface != NULL) { gdm_dbus_user_verifier_emit_verification_complete (self->user_verifier_interface, service_name); g_signal_emit (self, signals[VERIFICATION_COMPLETE], 0, service_name); } break; default: break; } } else { report_and_stop_conversation (self, service_name, error); } g_free (service_name); g_object_unref (self); } static gboolean supports_session_type (GdmSession *self, const char *session_type) { if (session_type == NULL) return TRUE; return g_strv_contains ((const char * const *) self->supported_session_types, session_type); } static char ** -get_system_session_dirs (GdmSession *self) +get_system_session_dirs (GdmSession *self, + const char *type) { GArray *search_array = NULL; char **search_dirs; int i, j; const gchar * const *system_data_dirs = g_get_system_data_dirs (); static const char *x_search_dirs[] = { "/etc/X11/sessions/", DMCONFDIR "/Sessions/", DATADIR "/gdm/BuiltInSessions/", DATADIR "/xsessions/", }; static const char *wayland_search_dir = DATADIR "/wayland-sessions/"; search_array = g_array_new (TRUE, TRUE, sizeof (char *)); for (j = 0; self->supported_session_types[j] != NULL; j++) { const char *supported_type = self->supported_session_types[j]; - if (g_str_equal (supported_type, "x11")) { + if (g_str_equal (supported_type, "x11") || + (type == NULL || g_str_equal (type, supported_type))) { for (i = 0; system_data_dirs[i]; i++) { gchar *dir = g_build_filename (system_data_dirs[i], "xsessions", NULL); g_array_append_val (search_array, dir); } g_array_append_vals (search_array, x_search_dirs, G_N_ELEMENTS (x_search_dirs)); } #ifdef ENABLE_WAYLAND_SUPPORT - if (g_str_equal (supported_type, "wayland")) { + if (g_str_equal (supported_type, "wayland") || + (type == NULL || g_str_equal (type, supported_type))) { for (i = 0; system_data_dirs[i]; i++) { gchar *dir = g_build_filename (system_data_dirs[i], "wayland-sessions", NULL); g_array_append_val (search_array, dir); } g_array_append_val (search_array, wayland_search_dir); } #endif } search_dirs = g_strdupv ((char **) search_array->data); g_array_free (search_array, TRUE); return search_dirs; } static gboolean is_prog_in_path (const char *prog) { char *f; gboolean ret; f = g_find_program_in_path (prog); ret = (f != NULL); g_free (f); return ret; } static GKeyFile * load_key_file_for_file (GdmSession *self, const char *file, + const char *type, char **full_path) { GKeyFile *key_file; - GError *error; + GError *error = NULL; gboolean res; char **search_dirs; key_file = g_key_file_new (); - search_dirs = get_system_session_dirs (self), + search_dirs = get_system_session_dirs (self, type); + error = NULL; res = g_key_file_load_from_dirs (key_file, file, (const char **) search_dirs, full_path, G_KEY_FILE_NONE, &error); if (! res) { - g_debug ("GdmSession: File '%s' not found: %s", file, error->message); - g_error_free (error); + g_debug ("GdmSession: File '%s' not found in search dirs", file); + if (error != NULL) { + g_debug ("GdmSession: %s", error->message); + g_error_free (error); + } g_key_file_free (key_file); key_file = NULL; } g_strfreev (search_dirs); return key_file; } static gboolean get_session_command_for_file (GdmSession *self, const char *file, + const char *type, char **command) { GKeyFile *key_file; GError *error; char *exec; gboolean ret; gboolean res; exec = NULL; ret = FALSE; if (command != NULL) { *command = NULL; } + if (!supports_session_type (self, type)) { + g_debug ("GdmSession: ignoring %s session command request for file '%s'", + type, file); + goto out; + } + g_debug ("GdmSession: getting session command for file '%s'", file); - key_file = load_key_file_for_file (self, file, NULL); + key_file = load_key_file_for_file (self, file, type, NULL); if (key_file == NULL) { goto out; } error = NULL; res = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_HIDDEN, &error); if (error == NULL && res) { g_debug ("GdmSession: Session %s is marked as hidden", file); goto out; } exec = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_TRY_EXEC, NULL); if (exec != NULL) { res = is_prog_in_path (exec); g_free (exec); exec = NULL; if (! res) { g_debug ("GdmSession: Command not found: %s", G_KEY_FILE_DESKTOP_KEY_TRY_EXEC); goto out; } } error = NULL; exec = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_EXEC, &error); if (error != NULL) { g_debug ("GdmSession: %s key not found: %s", G_KEY_FILE_DESKTOP_KEY_EXEC, error->message); g_error_free (error); goto out; } if (command != NULL) { *command = g_strdup (exec); } ret = TRUE; out: g_free (exec); return ret; } static gboolean get_session_command_for_name (GdmSession *self, const char *name, + const char *type, char **command) { gboolean res; char *filename; filename = g_strdup_printf ("%s.desktop", name); - res = get_session_command_for_file (self, filename, command); + res = get_session_command_for_file (self, filename, type, command); g_free (filename); return res; } static const char * get_default_language_name (GdmSession *self) { const char *default_language; if (self->saved_language != NULL) { return self->saved_language; } default_language = g_hash_table_lookup (self->environment, "LANG"); if (default_language != NULL) { return default_language; } return setlocale (LC_MESSAGES, NULL); } static const char * get_fallback_session_name (GdmSession *self) { char **search_dirs; int i; char *name; GSequence *sessions; GSequenceIter *session; if (self->fallback_session_name != NULL) { /* verify that the cached version still exists */ - if (get_session_command_for_name (self, self->fallback_session_name, NULL)) { + if (get_session_command_for_name (self, self->fallback_session_name, NULL, NULL)) { goto out; } } name = g_strdup ("gnome"); - if (get_session_command_for_name (self, name, NULL)) { + if (get_session_command_for_name (self, name, NULL, NULL)) { g_free (self->fallback_session_name); self->fallback_session_name = name; goto out; } g_free (name); sessions = g_sequence_new (g_free); - search_dirs = get_system_session_dirs (self); + search_dirs = get_system_session_dirs (self, NULL); for (i = 0; search_dirs[i] != NULL; i++) { GDir *dir; const char *base_name; dir = g_dir_open (search_dirs[i], 0, NULL); if (dir == NULL) { continue; } do { base_name = g_dir_read_name (dir); if (base_name == NULL) { break; } if (!g_str_has_suffix (base_name, ".desktop")) { continue; } - if (get_session_command_for_file (self, base_name, NULL)) { + if (get_session_command_for_file (self, base_name, NULL, NULL)) { name = g_strndup (base_name, strlen (base_name) - strlen (".desktop")); g_sequence_insert_sorted (sessions, name, (GCompareDataFunc) g_strcmp0, NULL); } } while (base_name != NULL); g_dir_close (dir); } g_strfreev (search_dirs); name = NULL; session = g_sequence_get_begin_iter (sessions); if (g_sequence_iter_is_end (session)) g_error ("GdmSession: no session desktop files installed, aborting..."); do { name = g_sequence_get (session); if (name) { break; } session = g_sequence_iter_next (session); } while (!g_sequence_iter_is_end (session)); g_free (self->fallback_session_name); self->fallback_session_name = g_strdup (name); g_sequence_free (sessions); out: return self->fallback_session_name; @@ -649,60 +666,63 @@ get_default_session_name (GdmSession *self) static void gdm_session_defaults_changed (GdmSession *self) { update_session_type (self); if (self->greeter_interface != NULL) { gdm_dbus_greeter_emit_default_language_name_changed (self->greeter_interface, get_default_language_name (self)); gdm_dbus_greeter_emit_default_session_name_changed (self->greeter_interface, get_default_session_name (self)); } } void gdm_session_select_user (GdmSession *self, const char *text) { g_debug ("GdmSession: selecting user '%s' for session '%s' (%p)", text, gdm_session_get_session_id (self), self); g_free (self->selected_user); self->selected_user = g_strdup (text); g_free (self->saved_session); self->saved_session = NULL; + g_free (self->saved_session_type); + self->saved_session_type = NULL; + g_free (self->saved_language); self->saved_language = NULL; } static void cancel_pending_query (GdmSessionConversation *conversation) { if (conversation->pending_invocation == NULL) { return; } g_debug ("GdmSession: Cancelling pending query"); g_dbus_method_invocation_return_dbus_error (conversation->pending_invocation, GDM_SESSION_DBUS_ERROR_CANCEL, "Operation cancelled"); conversation->pending_invocation = NULL; } static void answer_pending_query (GdmSessionConversation *conversation, const char *answer) { g_dbus_method_invocation_return_value (conversation->pending_invocation, g_variant_new ("(s)", answer)); conversation->pending_invocation = NULL; } static void set_pending_query (GdmSessionConversation *conversation, @@ -969,85 +989,96 @@ worker_on_reauthenticated (GdmDBusWorker *worker, GdmSession *self = conversation->session; g_debug ("GdmSession: Emitting 'reauthenticated' signal "); g_signal_emit (self, signals[REAUTHENTICATED], 0, service_name); } static void worker_on_saved_language_name_read (GdmDBusWorker *worker, const char *language_name, GdmSessionConversation *conversation) { GdmSession *self = conversation->session; if (strlen (language_name) > 0) { g_free (self->saved_language); self->saved_language = g_strdup (language_name); if (self->greeter_interface != NULL) { gdm_dbus_greeter_emit_default_language_name_changed (self->greeter_interface, language_name); } } } static void worker_on_saved_session_name_read (GdmDBusWorker *worker, const char *session_name, GdmSessionConversation *conversation) { GdmSession *self = conversation->session; - if (! get_session_command_for_name (self, session_name, NULL)) { + if (! get_session_command_for_name (self, session_name, self->saved_session_type, NULL)) { /* ignore sessions that don't exist */ g_debug ("GdmSession: not using invalid .dmrc session: %s", session_name); g_free (self->saved_session); self->saved_session = NULL; update_session_type (self); } else { if (strcmp (session_name, get_default_session_name (self)) != 0) { g_free (self->saved_session); self->saved_session = g_strdup (session_name); if (self->greeter_interface != NULL) { gdm_dbus_greeter_emit_default_session_name_changed (self->greeter_interface, session_name); } } if (self->saved_session_type != NULL) set_session_type (self, self->saved_session_type); else update_session_type (self); } } +static void +worker_on_saved_session_type_read (GdmDBusWorker *worker, + const char *session_type, + GdmSessionConversation *conversation) +{ + GdmSession *self = conversation->session; + + g_free (self->saved_session_type); + self->saved_session_type = g_strdup (session_type); +} + static GdmSessionConversation * find_conversation_by_pid (GdmSession *self, GPid pid) { GHashTableIter iter; gpointer key, value; g_hash_table_iter_init (&iter, self->conversations); while (g_hash_table_iter_next (&iter, &key, &value)) { GdmSessionConversation *conversation; conversation = (GdmSessionConversation *) value; if (conversation->worker_pid == pid) { return conversation; } } return NULL; } static gboolean allow_worker_function (GDBusAuthObserver *observer, GIOStream *stream, GCredentials *credentials, GdmSession *self) { uid_t connecting_user; connecting_user = g_credentials_get_unix_user (credentials, NULL); @@ -1127,60 +1158,63 @@ register_worker (GdmDBusWorkerManager *worker_manager_interface, g_dbus_method_invocation_return_value (invocation, NULL); conversation->worker_proxy = gdm_dbus_worker_proxy_new_sync (connection, G_DBUS_PROXY_FLAGS_NONE, NULL, GDM_WORKER_DBUS_PATH, NULL, NULL); /* drop the reference we stole from the pending connections list * since the proxy owns the connection now */ g_object_unref (connection); g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (conversation->worker_proxy), G_MAXINT); conversation->worker_cancellable = g_cancellable_new (); g_signal_connect (conversation->worker_proxy, "username-changed", G_CALLBACK (worker_on_username_changed), conversation); g_signal_connect (conversation->worker_proxy, "session-exited", G_CALLBACK (worker_on_session_exited), conversation); g_signal_connect (conversation->worker_proxy, "reauthenticated", G_CALLBACK (worker_on_reauthenticated), conversation); g_signal_connect (conversation->worker_proxy, "saved-language-name-read", G_CALLBACK (worker_on_saved_language_name_read), conversation); g_signal_connect (conversation->worker_proxy, "saved-session-name-read", G_CALLBACK (worker_on_saved_session_name_read), conversation); + g_signal_connect (conversation->worker_proxy, + "saved-session-type-read", + G_CALLBACK (worker_on_saved_session_type_read), conversation); g_signal_connect (conversation->worker_proxy, "cancel-pending-query", G_CALLBACK (worker_on_cancel_pending_query), conversation); conversation->worker_manager_interface = g_object_ref (worker_manager_interface); g_debug ("GdmSession: worker connection is %p", connection); g_debug ("GdmSession: Emitting conversation-started signal"); g_signal_emit (self, signals[CONVERSATION_STARTED], 0, conversation->service_name); if (self->user_verifier_interface != NULL) { gdm_dbus_user_verifier_emit_conversation_started (self->user_verifier_interface, conversation->service_name); } if (conversation->starting_invocation != NULL) { if (conversation->starting_username != NULL) { gdm_session_setup_for_user (self, conversation->service_name, conversation->starting_username); g_clear_pointer (&conversation->starting_username, (GDestroyNotify) g_free); } else { gdm_session_setup (self, conversation->service_name); } } g_debug ("GdmSession: Conversation started"); return TRUE; @@ -1923,60 +1957,63 @@ free_conversation (GdmSessionConversation *conversation) close_conversation (conversation); if (conversation->job != NULL) { g_warning ("Freeing conversation '%s' with active job", conversation->service_name); } g_free (conversation->service_name); g_free (conversation->starting_username); g_free (conversation->session_id); g_clear_object (&conversation->worker_manager_interface); g_cancellable_cancel (conversation->worker_cancellable); g_clear_object (&conversation->worker_cancellable); if (conversation->worker_proxy != NULL) { g_signal_handlers_disconnect_by_func (conversation->worker_proxy, G_CALLBACK (worker_on_username_changed), conversation); g_signal_handlers_disconnect_by_func (conversation->worker_proxy, G_CALLBACK (worker_on_session_exited), conversation); g_signal_handlers_disconnect_by_func (conversation->worker_proxy, G_CALLBACK (worker_on_reauthenticated), conversation); g_signal_handlers_disconnect_by_func (conversation->worker_proxy, G_CALLBACK (worker_on_saved_language_name_read), conversation); g_signal_handlers_disconnect_by_func (conversation->worker_proxy, G_CALLBACK (worker_on_saved_session_name_read), conversation); + g_signal_handlers_disconnect_by_func (conversation->worker_proxy, + G_CALLBACK (worker_on_saved_session_type_read), + conversation); g_signal_handlers_disconnect_by_func (conversation->worker_proxy, G_CALLBACK (worker_on_cancel_pending_query), conversation); g_clear_object (&conversation->worker_proxy); } g_clear_object (&conversation->session); g_free (conversation); } static void load_lang_config_file (GdmSession *self) { static const char *config_file = LANG_CONFIG_FILE; gchar *contents = NULL; gchar *p; gchar *key; gchar *value; gsize length; GError *error; GString *line; GRegex *re; if (!g_file_test (config_file, G_FILE_TEST_EXISTS)) { g_debug ("Cannot access '%s'", config_file); return; } error = NULL; if (!g_file_get_contents (config_file, &contents, &length, &error)) { g_debug ("Failed to parse '%s': %s", @@ -2535,83 +2572,83 @@ gdm_session_send_environment (GdmSession *self, g_return_if_fail (GDM_IS_SESSION (self)); conversation = find_conversation_by_name (self, service_name); if (conversation != NULL) { send_environment (self, conversation); } } static const char * get_session_name (GdmSession *self) { /* FIXME: test the session names before we use them? */ if (self->selected_session != NULL) { return self->selected_session; } return get_default_session_name (self); } static char * get_session_command (GdmSession *self) { gboolean res; char *command; const char *session_name; session_name = get_session_name (self); command = NULL; - res = get_session_command_for_name (self, session_name, &command); + res = get_session_command_for_name (self, session_name, NULL, &command); if (! res) { g_critical ("Cannot find a command for specified session: %s", session_name); exit (EXIT_FAILURE); } return command; } static gchar * get_session_desktop_names (GdmSession *self) { gchar *filename; GKeyFile *keyfile; gchar *desktop_names = NULL; if (self->selected_program != NULL) { return g_strdup ("GNOME-Greeter:GNOME"); } filename = g_strdup_printf ("%s.desktop", get_session_name (self)); g_debug ("GdmSession: getting desktop names for file '%s'", filename); - keyfile = load_key_file_for_file (self, filename, NULL); + keyfile = load_key_file_for_file (self, filename, NULL, NULL); if (keyfile != NULL) { gchar **names; names = g_key_file_get_string_list (keyfile, G_KEY_FILE_DESKTOP_GROUP, "DesktopNames", NULL, NULL); if (names != NULL) { desktop_names = g_strjoinv (":", names); g_strfreev (names); } } g_key_file_free (keyfile); g_free (filename); return desktop_names; } void gdm_session_set_environment_variable (GdmSession *self, const char *key, const char *value) { g_return_if_fail (key != NULL); g_return_if_fail (value != NULL); g_hash_table_replace (self->environment, g_strdup (key), g_strdup (value)); } @@ -3181,148 +3218,150 @@ gdm_session_get_conversation_session_id (GdmSession *self, conversation = find_conversation_by_name (self, service_name); if (conversation == NULL) { return NULL; } return conversation->session_id; } static char * get_session_filename (GdmSession *self) { return g_strdup_printf ("%s.desktop", get_session_name (self)); } #ifdef ENABLE_WAYLAND_SUPPORT static gboolean gdm_session_is_wayland_session (GdmSession *self) { GKeyFile *key_file; gboolean is_wayland_session = FALSE; char *filename; char *full_path = NULL; g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (GDM_IS_SESSION (self), FALSE); filename = get_session_filename (self); if (supports_session_type (self, "wayland")) { - key_file = load_key_file_for_file (self, filename, &full_path); + key_file = load_key_file_for_file (self, filename, NULL, &full_path); - if (key_file == NULL) { - goto out; - } + if (key_file == NULL) { + goto out; + } } if (full_path != NULL && strstr (full_path, "/wayland-sessions/") != NULL) { is_wayland_session = TRUE; } g_debug ("GdmSession: checking if file '%s' is wayland session: %s", filename, is_wayland_session? "yes" : "no"); out: g_clear_pointer (&key_file, g_key_file_free); g_free (filename); return is_wayland_session; } #endif static void update_session_type (GdmSession *self) { #ifdef ENABLE_WAYLAND_SUPPORT - gboolean is_wayland_session; + gboolean is_wayland_session = FALSE; + + if (supports_session_type (self, "wayland")) + is_wayland_session = gdm_session_is_wayland_session (self); - is_wayland_session = gdm_session_is_wayland_session (self); if (is_wayland_session) { set_session_type (self, "wayland"); } else { set_session_type (self, NULL); } #endif } gboolean gdm_session_session_registers (GdmSession *self) { g_autoptr(GError) error = NULL; g_autoptr(GKeyFile) key_file = NULL; gboolean session_registers = FALSE; g_autofree char *filename = NULL; g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (GDM_IS_SESSION (self), FALSE); filename = get_session_filename (self); - key_file = load_key_file_for_file (self, filename, NULL); + key_file = load_key_file_for_file (self, filename, NULL, NULL); session_registers = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, "X-GDM-SessionRegisters", &error); if (!session_registers && error != NULL && !g_error_matches (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_KEY_NOT_FOUND)) { g_warning ("GdmSession: Couldn't read session file '%s'", filename); return FALSE; } g_debug ("GdmSession: '%s' %s self", filename, session_registers ? "registers" : "does not register"); return session_registers; } gboolean gdm_session_bypasses_xsession (GdmSession *self) { GError *error; GKeyFile *key_file; gboolean res; gboolean bypasses_xsession = FALSE; char *filename = NULL; g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (GDM_IS_SESSION (self), FALSE); #ifdef ENABLE_WAYLAND_SUPPORT if (gdm_session_is_wayland_session (self)) { bypasses_xsession = TRUE; goto out; } #endif filename = get_session_filename (self); - key_file = load_key_file_for_file (self, filename, NULL); + key_file = load_key_file_for_file (self, filename, "x11", NULL); error = NULL; res = g_key_file_has_key (key_file, G_KEY_FILE_DESKTOP_GROUP, "X-GDM-BypassXsession", NULL); if (!res) { goto out; } else { bypasses_xsession = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, "X-GDM-BypassXsession", &error); if (error) { bypasses_xsession = FALSE; g_error_free (error); goto out; } } out: if (bypasses_xsession) { g_debug ("GdmSession: Session %s bypasses Xsession wrapper script", filename); } g_free (filename); return bypasses_xsession; } GdmSessionDisplayMode gdm_session_get_display_mode (GdmSession *self) { g_debug ("GdmSession: type %s, program? %s, seat %s", self->session_type, self->is_program_session? "yes" : "no", self->display_seat_id); -- 2.33.1