Blob Blame History Raw
From 0b466395de112bb247ec586e9ef9770c31e74657 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Thu, 4 Feb 2016 13:36:06 -0500
Subject: [PATCH 1/4] daemon: support dbus user buses with X sessions

If the dbus user bus was started when the user first
logged in, before the session was started, then that
dbus daemon won't have DISPLAY and XAUTHORITY in its
activation environment.

This means programs activated from that dbus daemon
also won't have DISPLAY and XAUTHORITY in their
activation environments.

This commit changes GDM to explicitly put the two
variables in the activation environment via D-Bus,
rather than sending them into the bus environment
process when launching the bus (since in the case
of the user bus, we don't launch it).

https://bugzilla.gnome.org/show_bug.cgi?id=761568
---
 daemon/gdm-x-session.c | 42 +++++++++++++++++++++++++++++++++++++++---
 1 file changed, 39 insertions(+), 3 deletions(-)

diff --git a/daemon/gdm-x-session.c b/daemon/gdm-x-session.c
index 624f67c..c01cc5e 100644
--- a/daemon/gdm-x-session.c
+++ b/daemon/gdm-x-session.c
@@ -351,144 +351,180 @@ on_bus_finished (GSubprocess  *subprocess,
                 goto out;
         }
 
         if (g_subprocess_get_if_exited (subprocess)) {
                 int exit_status;
 
                 exit_status = g_subprocess_get_exit_status (subprocess);
 
                 g_debug ("message bus exited with status %d", exit_status);
         } else {
                 int signal_number;
 
                 signal_number = g_subprocess_get_term_sig (subprocess);
                 g_debug ("message bus was killed with status %d", signal_number);
         }
 
         g_clear_object (&state->bus_subprocess);
 out:
         g_main_loop_quit (state->main_loop);
 }
 
 static gboolean
 spawn_bus (State        *state,
            GCancellable *cancellable)
 {
         GPtrArray           *arguments = NULL;
         GSubprocessLauncher *launcher = NULL;
         GSubprocess         *subprocess = NULL;
         GInputStream        *input_stream = NULL;
         GDataInputStream    *data_stream = NULL;
+        GDBusConnection     *connection = NULL;
+        GVariantBuilder     *builder = NULL;
+        GVariant            *reply = NULL;
         GError              *error = NULL;
         const char          *bus_env = NULL;
         char                *bus_address_fd_string;
         char                *bus_address = NULL;
         gsize                bus_address_size;
 
         gboolean  is_running = FALSE;
         int       ret;
         int       pipe_fds[2];
 
         g_debug ("Running session message bus");
 
         bus_env = g_getenv ("DBUS_SESSION_BUS_ADDRESS");
         if (bus_env != NULL) {
                 g_debug ("session message bus already running, not starting another one");
                 state->bus_address = g_strdup (bus_env);
                 return TRUE;
         }
 
         ret = g_unix_open_pipe (pipe_fds, FD_CLOEXEC, &error);
 
         if (!ret) {
                 g_debug ("could not open pipe: %s", error->message);
                 goto out;
         }
 
         arguments = g_ptr_array_new ();
         launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_NONE);
 
-        g_subprocess_launcher_setenv (launcher, "DISPLAY", state->display_name, TRUE);
-        g_subprocess_launcher_setenv (launcher, "XAUTHORITY", state->auth_file, TRUE);
-
         g_subprocess_launcher_take_fd (launcher, pipe_fds[1], BUS_ADDRESS_FILENO);
 
         bus_address_fd_string = g_strdup_printf ("%d", BUS_ADDRESS_FILENO);
 
         g_ptr_array_add (arguments, "dbus-daemon");
 
         g_ptr_array_add (arguments, "--print-address");
         g_ptr_array_add (arguments, bus_address_fd_string);
         g_ptr_array_add (arguments, "--session");
         g_ptr_array_add (arguments, NULL);
 
         subprocess = g_subprocess_launcher_spawnv (launcher,
                                                    (const char * const *) arguments->pdata,
                                                    &error);
         g_free (bus_address_fd_string);
         g_clear_object (&launcher);
         g_ptr_array_free (arguments, TRUE);
 
         if (subprocess == NULL) {
                 g_debug ("could not start dbus-daemon: %s", error->message);
                 goto out;
         }
 
         input_stream = g_unix_input_stream_new (pipe_fds[0], TRUE);
         data_stream = g_data_input_stream_new (input_stream);
         g_clear_object (&input_stream);
 
         bus_address = g_data_input_stream_read_line (data_stream,
                                                      &bus_address_size,
                                                      cancellable,
                                                      &error);
 
         if (error != NULL) {
                 g_debug ("could not read address from session message bus: %s", error->message);
                 goto out;
         }
 
         if (bus_address == NULL) {
                 g_debug ("session message bus did not write address");
                 goto out;
         }
 
         state->bus_address = bus_address;
 
         state->bus_subprocess = g_object_ref (subprocess);
 
         g_subprocess_wait_async (state->bus_subprocess,
                                  cancellable,
                                  (GAsyncReadyCallback)
                                  on_bus_finished,
                                  state);
 
+        connection = g_dbus_connection_new_for_address_sync (state->bus_address,
+                                                             G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
+                                                             G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION,
+                                                             NULL,
+                                                             cancellable,
+                                                             &error);
+
+        if (connection == NULL) {
+                g_debug ("could not open connection to session bus: %s",
+                         error->message);
+                goto out;
+        }
+
+        g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}"));
+        g_variant_builder_add (&builder, "{ss}", "DISPLAY", state->display_name);
+        g_variant_builder_add (&builder, "{ss}", "XAUTHORITY", state->auth_file);
+
+        reply = g_dbus_connection_call_sync (connection,
+                                             "org.freedesktop.DBus",
+                                             "/org/freedesktop/DBus",
+                                             "org.freedesktop.DBus",
+                                             "UpdateActivationEnvironment",
+                                             g_variant_new ("(@a{ss})",
+                                                            g_variant_builder_end (&builder)),
+                                             NULL,
+                                             G_DBUS_CALL_FLAGS_NONE,
+                                             -1, NULL, &error);
+
+        if (reply == NULL) {
+                g_debug ("could not update activation environment: %s", error->message);
+                goto out;
+        }
+
+        g_variant_unref (reply);
+        g_clear_object (&connection);
+
         is_running = TRUE;
 out:
         g_clear_object (&data_stream);
         g_clear_object (&subprocess);
         g_clear_object (&launcher);
         g_clear_error (&error);
 
         return is_running;
 }
 
 
 static void
 on_session_finished (GSubprocess  *subprocess,
                      GAsyncResult *result,
                      State        *state)
 {
         gboolean cancelled;
 
         cancelled = !g_subprocess_wait_finish (subprocess, result, NULL);
 
         if (cancelled) {
                 goto out;
         }
 
         if (g_subprocess_get_if_exited (subprocess)) {
                 int exit_status;
 
                 exit_status = g_subprocess_get_exit_status (subprocess);
 
                 g_debug ("session exited with status %d", exit_status);
-- 
2.7.0


From ee14ddb28e0df3f6726b10d1b7fffb898b058738 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 5 Feb 2016 10:42:20 -0500
Subject: [PATCH 2/4] gdm-x-session: fix tiny leak in error path

I wasn't cleaning up the dbus connection in out: so
it leaked in an error path.

Spotted by Michael Catanzaro
---
 daemon/gdm-x-session.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/daemon/gdm-x-session.c b/daemon/gdm-x-session.c
index c01cc5e..41e4118 100644
--- a/daemon/gdm-x-session.c
+++ b/daemon/gdm-x-session.c
@@ -469,64 +469,64 @@ spawn_bus (State        *state,
                                                              cancellable,
                                                              &error);
 
         if (connection == NULL) {
                 g_debug ("could not open connection to session bus: %s",
                          error->message);
                 goto out;
         }
 
         g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}"));
         g_variant_builder_add (&builder, "{ss}", "DISPLAY", state->display_name);
         g_variant_builder_add (&builder, "{ss}", "XAUTHORITY", state->auth_file);
 
         reply = g_dbus_connection_call_sync (connection,
                                              "org.freedesktop.DBus",
                                              "/org/freedesktop/DBus",
                                              "org.freedesktop.DBus",
                                              "UpdateActivationEnvironment",
                                              g_variant_new ("(@a{ss})",
                                                             g_variant_builder_end (&builder)),
                                              NULL,
                                              G_DBUS_CALL_FLAGS_NONE,
                                              -1, NULL, &error);
 
         if (reply == NULL) {
                 g_debug ("could not update activation environment: %s", error->message);
                 goto out;
         }
 
         g_variant_unref (reply);
-        g_clear_object (&connection);
 
         is_running = TRUE;
 out:
+        g_clear_object (&connection);
         g_clear_object (&data_stream);
         g_clear_object (&subprocess);
         g_clear_object (&launcher);
         g_clear_error (&error);
 
         return is_running;
 }
 
 
 static void
 on_session_finished (GSubprocess  *subprocess,
                      GAsyncResult *result,
                      State        *state)
 {
         gboolean cancelled;
 
         cancelled = !g_subprocess_wait_finish (subprocess, result, NULL);
 
         if (cancelled) {
                 goto out;
         }
 
         if (g_subprocess_get_if_exited (subprocess)) {
                 int exit_status;
 
                 exit_status = g_subprocess_get_exit_status (subprocess);
 
                 g_debug ("session exited with status %d", exit_status);
 
                 state->session_exit_status = exit_status;
-- 
2.7.0


From a8982d70e65d13f5c0a65a144d659c65382b04f3 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 9 Feb 2016 11:34:30 -0500
Subject: [PATCH 3/4] gdm-x-session: fix pointer confusion in
 UpdateActivationEnv call

commit 99eeae91c1f11997521ad3bc016a7b2d23ec7942 introduced a
call to UpdateActivationEnvironment but mucked up the GVariantBuilder
declaration.  This commit fixes that.
---
 daemon/gdm-x-session.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/daemon/gdm-x-session.c b/daemon/gdm-x-session.c
index 41e4118..6957c83 100644
--- a/daemon/gdm-x-session.c
+++ b/daemon/gdm-x-session.c
@@ -352,61 +352,61 @@ on_bus_finished (GSubprocess  *subprocess,
         }
 
         if (g_subprocess_get_if_exited (subprocess)) {
                 int exit_status;
 
                 exit_status = g_subprocess_get_exit_status (subprocess);
 
                 g_debug ("message bus exited with status %d", exit_status);
         } else {
                 int signal_number;
 
                 signal_number = g_subprocess_get_term_sig (subprocess);
                 g_debug ("message bus was killed with status %d", signal_number);
         }
 
         g_clear_object (&state->bus_subprocess);
 out:
         g_main_loop_quit (state->main_loop);
 }
 
 static gboolean
 spawn_bus (State        *state,
            GCancellable *cancellable)
 {
         GPtrArray           *arguments = NULL;
         GSubprocessLauncher *launcher = NULL;
         GSubprocess         *subprocess = NULL;
         GInputStream        *input_stream = NULL;
         GDataInputStream    *data_stream = NULL;
         GDBusConnection     *connection = NULL;
-        GVariantBuilder     *builder = NULL;
+        GVariantBuilder      builder;
         GVariant            *reply = NULL;
         GError              *error = NULL;
         const char          *bus_env = NULL;
         char                *bus_address_fd_string;
         char                *bus_address = NULL;
         gsize                bus_address_size;
 
         gboolean  is_running = FALSE;
         int       ret;
         int       pipe_fds[2];
 
         g_debug ("Running session message bus");
 
         bus_env = g_getenv ("DBUS_SESSION_BUS_ADDRESS");
         if (bus_env != NULL) {
                 g_debug ("session message bus already running, not starting another one");
                 state->bus_address = g_strdup (bus_env);
                 return TRUE;
         }
 
         ret = g_unix_open_pipe (pipe_fds, FD_CLOEXEC, &error);
 
         if (!ret) {
                 g_debug ("could not open pipe: %s", error->message);
                 goto out;
         }
 
         arguments = g_ptr_array_new ();
         launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_NONE);
 
-- 
2.7.0


From 1c7fdfad3b47b9e7c27862c5926120235151bd57 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 9 Feb 2016 11:49:02 -0500
Subject: [PATCH 4/4] gdm-session: update session type when the session
 defaults change

If a user has never logged in before and they login using autologin,
then we don't select the correct session type if they end up
with a wayland session.  This is because we fail to initialize
the session type based on the default session type.

This commit changes the code to update the session type anytime the
session defaults are reset.

https://bugzilla.gnome.org/show_bug.cgi?id=761785
---
 daemon/gdm-session.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/daemon/gdm-session.c b/daemon/gdm-session.c
index c230dae..b839fea 100644
--- a/daemon/gdm-session.c
+++ b/daemon/gdm-session.c
@@ -581,60 +581,62 @@ get_fallback_session_name (GdmSession *self)
                                          strlen (".desktop"));
 
                        break;
                }
                session = g_sequence_iter_next (session);
         } while (!g_sequence_iter_is_end (session));
 
         g_free (self->priv->fallback_session_name);
         self->priv->fallback_session_name = name;
 
         g_sequence_free (sessions);
 
  out:
         return self->priv->fallback_session_name;
 }
 
 static const char *
 get_default_session_name (GdmSession *self)
 {
         if (self->priv->saved_session != NULL) {
                 return self->priv->saved_session;
         }
 
         return get_fallback_session_name (self);
 }
 
 static void
 gdm_session_defaults_changed (GdmSession *self)
 {
 
+        update_session_type (self);
+
         if (self->priv->greeter_interface != NULL) {
                 gdm_dbus_greeter_emit_default_language_name_changed (self->priv->greeter_interface,
                                                                      get_default_language_name (self));
                 gdm_dbus_greeter_emit_default_session_name_changed (self->priv->greeter_interface,
                                                                     get_default_session_name (self));
         }
 }
 
 void
 gdm_session_select_user (GdmSession *self,
                          const char *text)
 {
 
         g_debug ("GdmSession: Setting user: '%s'", text);
 
         g_free (self->priv->selected_user);
         self->priv->selected_user = g_strdup (text);
 
         g_free (self->priv->saved_session);
         self->priv->saved_session = NULL;
 
         g_free (self->priv->saved_language);
         self->priv->saved_language = NULL;
 }
 
 static void
 cancel_pending_query (GdmSessionConversation *conversation)
 {
         if (conversation->pending_invocation == NULL) {
                 return;
@@ -893,62 +895,60 @@ worker_on_saved_language_name_read (GdmDBusWorker          *worker,
 {
         GdmSession *self = conversation->session;
 
         if (strlen (language_name) > 0 &&
             strcmp (language_name, get_default_language_name (self)) != 0) {
                 g_free (self->priv->saved_language);
                 self->priv->saved_language = g_strdup (language_name);
 
                 if (self->priv->greeter_interface != NULL) {
                         gdm_dbus_greeter_emit_default_language_name_changed (self->priv->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)) {
                 /* ignore sessions that don't exist */
                 g_debug ("GdmSession: not using invalid .dmrc session: %s", session_name);
                 g_free (self->priv->saved_session);
                 self->priv->saved_session = NULL;
                 return;
         }
 
-        update_session_type (self);
-
         if (strcmp (session_name,
                     get_default_session_name (self)) != 0) {
                 g_free (self->priv->saved_session);
                 self->priv->saved_session = g_strdup (session_name);
 
                 if (self->priv->greeter_interface != NULL) {
                         gdm_dbus_greeter_emit_default_session_name_changed (self->priv->greeter_interface,
                                                                             session_name);
                 }
         }
 }
 
 static GdmSessionConversation *
 find_conversation_by_pid (GdmSession *self,
                           GPid        pid)
 {
         GHashTableIter iter;
         gpointer key, value;
 
         g_hash_table_iter_init (&iter, self->priv->conversations);
         while (g_hash_table_iter_next (&iter, &key, &value)) {
                 GdmSessionConversation *conversation;
 
                 conversation = (GdmSessionConversation *) value;
 
                 if (conversation->worker_pid == pid) {
                         return conversation;
                 }
         }
 
-- 
2.7.0