|
|
c90517 |
From 67c08ab2df5f86626b6e13f3318e41187bde0737 Mon Sep 17 00:00:00 2001
|
|
|
c90517 |
From: Ray Strode <rstrode@redhat.com>
|
|
|
c90517 |
Date: Thu, 2 Aug 2018 15:06:09 -0400
|
|
|
c90517 |
Subject: [PATCH 14/48] daemon: kill and restart greeter on demand under
|
|
|
c90517 |
wayland
|
|
|
c90517 |
|
|
|
c90517 |
Right now we leave the greeter alive after the user logs in.
|
|
|
c90517 |
This is for two reasons:
|
|
|
c90517 |
|
|
|
c90517 |
1) When the greeter is running Xorg, there's no way to kill
|
|
|
c90517 |
it when it's running on an inactive VT (X jumps to the foreground
|
|
|
c90517 |
when being killed)
|
|
|
c90517 |
|
|
|
c90517 |
2) The greeter, in a way, provides a securepath for unlock.
|
|
|
c90517 |
Users in theory could know that by hitting ctrl-alt-f1 to secure
|
|
|
c90517 |
attention, the login screen presented is not spoofed.
|
|
|
c90517 |
|
|
|
c90517 |
Since we use wayland by default, 1 isn't that much of a concern,
|
|
|
c90517 |
and 2 is a bit of niche feature that most users probably haven't
|
|
|
c90517 |
considered.
|
|
|
c90517 |
|
|
|
c90517 |
And there's a huge downside to keeping the greeter alive: it uses
|
|
|
c90517 |
a very large amount of memory.
|
|
|
c90517 |
|
|
|
c90517 |
This commit changes GDM to kill the login screen when switching
|
|
|
c90517 |
away from the login screen's VT and restarting it when switching
|
|
|
c90517 |
back.
|
|
|
c90517 |
|
|
|
c90517 |
Based heavily on work by Hans de Goede <hdegoede@redhat.com>
|
|
|
c90517 |
|
|
|
c90517 |
Closes: https://gitlab.gnome.org/GNOME/gdm/issues/222
|
|
|
c90517 |
---
|
|
|
c90517 |
daemon/gdm-local-display-factory.c | 167 +++++++++++++++++++++++++++++
|
|
|
c90517 |
1 file changed, 167 insertions(+)
|
|
|
c90517 |
|
|
|
c90517 |
diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c
|
|
|
c90517 |
index 7f7735ca1..4ae656ab3 100644
|
|
|
c90517 |
--- a/daemon/gdm-local-display-factory.c
|
|
|
c90517 |
+++ b/daemon/gdm-local-display-factory.c
|
|
|
c90517 |
@@ -34,60 +34,65 @@
|
|
|
c90517 |
#include "gdm-manager.h"
|
|
|
c90517 |
#include "gdm-display-factory.h"
|
|
|
c90517 |
#include "gdm-local-display-factory.h"
|
|
|
c90517 |
#include "gdm-local-display-factory-glue.h"
|
|
|
c90517 |
|
|
|
c90517 |
#include "gdm-settings-keys.h"
|
|
|
c90517 |
#include "gdm-settings-direct.h"
|
|
|
c90517 |
#include "gdm-display-store.h"
|
|
|
c90517 |
#include "gdm-local-display.h"
|
|
|
c90517 |
#include "gdm-legacy-display.h"
|
|
|
c90517 |
|
|
|
c90517 |
#define GDM_LOCAL_DISPLAY_FACTORY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_LOCAL_DISPLAY_FACTORY, GdmLocalDisplayFactoryPrivate))
|
|
|
c90517 |
|
|
|
c90517 |
#define GDM_DBUS_PATH "/org/gnome/DisplayManager"
|
|
|
c90517 |
#define GDM_LOCAL_DISPLAY_FACTORY_DBUS_PATH GDM_DBUS_PATH "/LocalDisplayFactory"
|
|
|
c90517 |
#define GDM_MANAGER_DBUS_NAME "org.gnome.DisplayManager.LocalDisplayFactory"
|
|
|
c90517 |
|
|
|
c90517 |
#define MAX_DISPLAY_FAILURES 5
|
|
|
c90517 |
|
|
|
c90517 |
struct GdmLocalDisplayFactoryPrivate
|
|
|
c90517 |
{
|
|
|
c90517 |
GdmDBusLocalDisplayFactory *skeleton;
|
|
|
c90517 |
GDBusConnection *connection;
|
|
|
c90517 |
GHashTable *used_display_numbers;
|
|
|
c90517 |
|
|
|
c90517 |
/* FIXME: this needs to be per seat? */
|
|
|
c90517 |
guint num_failures;
|
|
|
c90517 |
|
|
|
c90517 |
guint seat_new_id;
|
|
|
c90517 |
guint seat_removed_id;
|
|
|
c90517 |
+
|
|
|
c90517 |
+#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
|
|
|
c90517 |
+ char *tty_of_active_vt;
|
|
|
c90517 |
+ guint active_vt_watch_id;
|
|
|
c90517 |
+#endif
|
|
|
c90517 |
};
|
|
|
c90517 |
|
|
|
c90517 |
enum {
|
|
|
c90517 |
PROP_0,
|
|
|
c90517 |
};
|
|
|
c90517 |
|
|
|
c90517 |
static void gdm_local_display_factory_class_init (GdmLocalDisplayFactoryClass *klass);
|
|
|
c90517 |
static void gdm_local_display_factory_init (GdmLocalDisplayFactory *factory);
|
|
|
c90517 |
static void gdm_local_display_factory_finalize (GObject *object);
|
|
|
c90517 |
|
|
|
c90517 |
static GdmDisplay *create_display (GdmLocalDisplayFactory *factory,
|
|
|
c90517 |
const char *seat_id,
|
|
|
c90517 |
const char *session_type,
|
|
|
c90517 |
gboolean initial_display);
|
|
|
c90517 |
|
|
|
c90517 |
static void on_display_status_changed (GdmDisplay *display,
|
|
|
c90517 |
GParamSpec *arg1,
|
|
|
c90517 |
GdmLocalDisplayFactory *factory);
|
|
|
c90517 |
|
|
|
c90517 |
static gboolean gdm_local_display_factory_sync_seats (GdmLocalDisplayFactory *factory);
|
|
|
c90517 |
static gpointer local_display_factory_object = NULL;
|
|
|
c90517 |
|
|
|
c90517 |
G_DEFINE_TYPE (GdmLocalDisplayFactory, gdm_local_display_factory, GDM_TYPE_DISPLAY_FACTORY)
|
|
|
c90517 |
|
|
|
c90517 |
GQuark
|
|
|
c90517 |
gdm_local_display_factory_error_quark (void)
|
|
|
c90517 |
{
|
|
|
c90517 |
static GQuark ret = 0;
|
|
|
c90517 |
if (ret == 0) {
|
|
|
c90517 |
ret = g_quark_from_static_string ("gdm_local_display_factory_error");
|
|
|
c90517 |
@@ -507,98 +512,260 @@ gdm_local_display_factory_sync_seats (GdmLocalDisplayFactory *factory)
|
|
|
c90517 |
static void
|
|
|
c90517 |
on_seat_new (GDBusConnection *connection,
|
|
|
c90517 |
const gchar *sender_name,
|
|
|
c90517 |
const gchar *object_path,
|
|
|
c90517 |
const gchar *interface_name,
|
|
|
c90517 |
const gchar *signal_name,
|
|
|
c90517 |
GVariant *parameters,
|
|
|
c90517 |
gpointer user_data)
|
|
|
c90517 |
{
|
|
|
c90517 |
const char *seat;
|
|
|
c90517 |
|
|
|
c90517 |
g_variant_get (parameters, "(&s&o)", &seat, NULL);
|
|
|
c90517 |
create_display (GDM_LOCAL_DISPLAY_FACTORY (user_data), seat, NULL, FALSE);
|
|
|
c90517 |
}
|
|
|
c90517 |
|
|
|
c90517 |
static void
|
|
|
c90517 |
on_seat_removed (GDBusConnection *connection,
|
|
|
c90517 |
const gchar *sender_name,
|
|
|
c90517 |
const gchar *object_path,
|
|
|
c90517 |
const gchar *interface_name,
|
|
|
c90517 |
const gchar *signal_name,
|
|
|
c90517 |
GVariant *parameters,
|
|
|
c90517 |
gpointer user_data)
|
|
|
c90517 |
{
|
|
|
c90517 |
const char *seat;
|
|
|
c90517 |
|
|
|
c90517 |
g_variant_get (parameters, "(&s&o)", &seat, NULL);
|
|
|
c90517 |
delete_display (GDM_LOCAL_DISPLAY_FACTORY (user_data), seat);
|
|
|
c90517 |
}
|
|
|
c90517 |
|
|
|
c90517 |
+#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
|
|
|
c90517 |
+static gboolean
|
|
|
c90517 |
+lookup_by_session_id (const char *id,
|
|
|
c90517 |
+ GdmDisplay *display,
|
|
|
c90517 |
+ gpointer user_data)
|
|
|
c90517 |
+{
|
|
|
c90517 |
+ const char *looking_for = user_data;
|
|
|
c90517 |
+ const char *current;
|
|
|
c90517 |
+
|
|
|
c90517 |
+ current = gdm_display_get_session_id (display);
|
|
|
c90517 |
+ return g_strcmp0 (current, looking_for) == 0;
|
|
|
c90517 |
+}
|
|
|
c90517 |
+
|
|
|
c90517 |
+static void
|
|
|
c90517 |
+maybe_stop_greeter_display (GdmDisplay *display)
|
|
|
c90517 |
+{
|
|
|
c90517 |
+ g_autofree char *display_session_type = NULL;
|
|
|
c90517 |
+
|
|
|
c90517 |
+ if (gdm_display_get_status (display) != GDM_DISPLAY_MANAGED)
|
|
|
c90517 |
+ return;
|
|
|
c90517 |
+
|
|
|
c90517 |
+ g_object_get (G_OBJECT (display),
|
|
|
c90517 |
+ "session-type", &display_session_type,
|
|
|
c90517 |
+ NULL);
|
|
|
c90517 |
+
|
|
|
c90517 |
+ /* we can only stop greeter for wayland sessions, since
|
|
|
c90517 |
+ * X server would jump back on exit */
|
|
|
c90517 |
+ if (g_strcmp0 (display_session_type, "wayland") != 0)
|
|
|
c90517 |
+ return;
|
|
|
c90517 |
+
|
|
|
c90517 |
+ gdm_display_stop_greeter_session (display);
|
|
|
c90517 |
+ gdm_display_unmanage (display);
|
|
|
c90517 |
+ gdm_display_finish (display);
|
|
|
c90517 |
+}
|
|
|
c90517 |
+
|
|
|
c90517 |
+static gboolean
|
|
|
c90517 |
+on_vt_changed (GIOChannel *source,
|
|
|
c90517 |
+ GIOCondition condition,
|
|
|
c90517 |
+ GdmLocalDisplayFactory *factory)
|
|
|
c90517 |
+{
|
|
|
c90517 |
+ GIOStatus status;
|
|
|
c90517 |
+ static const char *tty_of_initial_vt = "tty" GDM_INITIAL_VT;
|
|
|
c90517 |
+ g_autofree char *tty_of_previous_vt = NULL;
|
|
|
c90517 |
+ g_autofree char *tty_of_active_vt = NULL;
|
|
|
c90517 |
+ g_autofree char *login_session_id = NULL;
|
|
|
c90517 |
+ g_autofree char *active_session_id = NULL;
|
|
|
c90517 |
+ const char *session_type = NULL;
|
|
|
c90517 |
+ int ret;
|
|
|
c90517 |
+
|
|
|
c90517 |
+ g_io_channel_seek_position (source, 0, G_SEEK_SET, NULL);
|
|
|
c90517 |
+
|
|
|
c90517 |
+ if (condition & G_IO_PRI) {
|
|
|
c90517 |
+ g_autoptr (GError) error = NULL;
|
|
|
c90517 |
+ status = g_io_channel_read_line (source, &tty_of_active_vt, NULL, NULL, &error);
|
|
|
c90517 |
+
|
|
|
c90517 |
+ if (error != NULL) {
|
|
|
c90517 |
+ g_warning ("could not read active VT from kernel: %s", error->message);
|
|
|
c90517 |
+ }
|
|
|
c90517 |
+ switch (status) {
|
|
|
c90517 |
+ case G_IO_STATUS_ERROR:
|
|
|
c90517 |
+ return G_SOURCE_REMOVE;
|
|
|
c90517 |
+ case G_IO_STATUS_EOF:
|
|
|
c90517 |
+ return G_SOURCE_REMOVE;
|
|
|
c90517 |
+ case G_IO_STATUS_AGAIN:
|
|
|
c90517 |
+ return G_SOURCE_CONTINUE;
|
|
|
c90517 |
+ case G_IO_STATUS_NORMAL:
|
|
|
c90517 |
+ break;
|
|
|
c90517 |
+ }
|
|
|
c90517 |
+ }
|
|
|
c90517 |
+
|
|
|
c90517 |
+ if ((condition & G_IO_ERR) || (condition & G_IO_HUP))
|
|
|
c90517 |
+ return G_SOURCE_REMOVE;
|
|
|
c90517 |
+
|
|
|
c90517 |
+ if (tty_of_active_vt == NULL)
|
|
|
c90517 |
+ return G_SOURCE_CONTINUE;
|
|
|
c90517 |
+
|
|
|
c90517 |
+ g_strchomp (tty_of_active_vt);
|
|
|
c90517 |
+
|
|
|
c90517 |
+ /* don't do anything if we're on the same VT we were before */
|
|
|
c90517 |
+ if (g_strcmp0 (tty_of_active_vt, factory->priv->tty_of_active_vt) == 0)
|
|
|
c90517 |
+ return G_SOURCE_CONTINUE;
|
|
|
c90517 |
+
|
|
|
c90517 |
+ tty_of_previous_vt = g_steal_pointer (&factory->priv->tty_of_active_vt);
|
|
|
c90517 |
+ factory->priv->tty_of_active_vt = g_steal_pointer (&tty_of_active_vt);
|
|
|
c90517 |
+
|
|
|
c90517 |
+ /* if the old VT was running a wayland login screen kill it
|
|
|
c90517 |
+ */
|
|
|
c90517 |
+ if (gdm_get_login_window_session_id ("seat0", &login_session_id)) {
|
|
|
c90517 |
+ unsigned int vt;
|
|
|
c90517 |
+
|
|
|
c90517 |
+ ret = sd_session_get_vt (login_session_id, &vt;;
|
|
|
c90517 |
+ if (ret == 0 && vt != 0) {
|
|
|
c90517 |
+ g_autofree char *tty_of_login_window_vt = NULL;
|
|
|
c90517 |
+
|
|
|
c90517 |
+ tty_of_login_window_vt = g_strdup_printf ("tty%u", vt);
|
|
|
c90517 |
+
|
|
|
c90517 |
+ if (g_strcmp0 (tty_of_login_window_vt, tty_of_previous_vt) == 0) {
|
|
|
c90517 |
+ GdmDisplayStore *store;
|
|
|
c90517 |
+ GdmDisplay *display;
|
|
|
c90517 |
+
|
|
|
c90517 |
+ store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
|
|
|
c90517 |
+ display = gdm_display_store_find (store,
|
|
|
c90517 |
+ lookup_by_session_id,
|
|
|
c90517 |
+ (gpointer) login_session_id);
|
|
|
c90517 |
+
|
|
|
c90517 |
+ if (display != NULL)
|
|
|
c90517 |
+ maybe_stop_greeter_display (display);
|
|
|
c90517 |
+ }
|
|
|
c90517 |
+ }
|
|
|
c90517 |
+ }
|
|
|
c90517 |
+
|
|
|
c90517 |
+ /* if user jumped back to initial vt and it's empty put a login screen
|
|
|
c90517 |
+ * on it (unless a login screen is already running elsewhere, then
|
|
|
c90517 |
+ * jump to that login screen)
|
|
|
c90517 |
+ */
|
|
|
c90517 |
+ if (strcmp (factory->priv->tty_of_active_vt, tty_of_initial_vt) != 0) {
|
|
|
c90517 |
+ return G_SOURCE_CONTINUE;
|
|
|
c90517 |
+ }
|
|
|
c90517 |
+
|
|
|
c90517 |
+ ret = sd_seat_get_active ("seat0", &active_session_id, NULL);
|
|
|
c90517 |
+
|
|
|
c90517 |
+ if (ret == 0) {
|
|
|
c90517 |
+ g_autofree char *state = NULL;
|
|
|
c90517 |
+ ret = sd_session_get_state (active_session_id, &state);
|
|
|
c90517 |
+
|
|
|
c90517 |
+ /* if there's something already running on the active VT then bail */
|
|
|
c90517 |
+ if (ret == 0 && g_strcmp0 (state, "closing") != 0)
|
|
|
c90517 |
+ return G_SOURCE_CONTINUE;
|
|
|
c90517 |
+ }
|
|
|
c90517 |
+
|
|
|
c90517 |
+ if (gdm_local_display_factory_use_wayland ())
|
|
|
c90517 |
+ session_type = "wayland";
|
|
|
c90517 |
+
|
|
|
c90517 |
+ create_display (factory, "seat0", session_type, TRUE);
|
|
|
c90517 |
+
|
|
|
c90517 |
+ return G_SOURCE_CONTINUE;
|
|
|
c90517 |
+}
|
|
|
c90517 |
+#endif
|
|
|
c90517 |
+
|
|
|
c90517 |
static void
|
|
|
c90517 |
gdm_local_display_factory_start_monitor (GdmLocalDisplayFactory *factory)
|
|
|
c90517 |
{
|
|
|
c90517 |
+ g_autoptr (GIOChannel) io_channel = NULL;
|
|
|
c90517 |
+
|
|
|
c90517 |
factory->priv->seat_new_id = g_dbus_connection_signal_subscribe (factory->priv->connection,
|
|
|
c90517 |
"org.freedesktop.login1",
|
|
|
c90517 |
"org.freedesktop.login1.Manager",
|
|
|
c90517 |
"SeatNew",
|
|
|
c90517 |
"/org/freedesktop/login1",
|
|
|
c90517 |
NULL,
|
|
|
c90517 |
G_DBUS_SIGNAL_FLAGS_NONE,
|
|
|
c90517 |
on_seat_new,
|
|
|
c90517 |
g_object_ref (factory),
|
|
|
c90517 |
g_object_unref);
|
|
|
c90517 |
factory->priv->seat_removed_id = g_dbus_connection_signal_subscribe (factory->priv->connection,
|
|
|
c90517 |
"org.freedesktop.login1",
|
|
|
c90517 |
"org.freedesktop.login1.Manager",
|
|
|
c90517 |
"SeatRemoved",
|
|
|
c90517 |
"/org/freedesktop/login1",
|
|
|
c90517 |
NULL,
|
|
|
c90517 |
G_DBUS_SIGNAL_FLAGS_NONE,
|
|
|
c90517 |
on_seat_removed,
|
|
|
c90517 |
g_object_ref (factory),
|
|
|
c90517 |
g_object_unref);
|
|
|
c90517 |
+
|
|
|
c90517 |
+#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
|
|
|
c90517 |
+ io_channel = g_io_channel_new_file ("/sys/class/tty/tty0/active", "r", NULL);
|
|
|
c90517 |
+
|
|
|
c90517 |
+ if (io_channel != NULL) {
|
|
|
c90517 |
+ factory->priv->active_vt_watch_id =
|
|
|
c90517 |
+ g_io_add_watch (io_channel,
|
|
|
c90517 |
+ G_IO_PRI,
|
|
|
c90517 |
+ (GIOFunc)
|
|
|
c90517 |
+ on_vt_changed,
|
|
|
c90517 |
+ factory);
|
|
|
c90517 |
+ }
|
|
|
c90517 |
+#endif
|
|
|
c90517 |
}
|
|
|
c90517 |
|
|
|
c90517 |
static void
|
|
|
c90517 |
gdm_local_display_factory_stop_monitor (GdmLocalDisplayFactory *factory)
|
|
|
c90517 |
{
|
|
|
c90517 |
if (factory->priv->seat_new_id) {
|
|
|
c90517 |
g_dbus_connection_signal_unsubscribe (factory->priv->connection,
|
|
|
c90517 |
factory->priv->seat_new_id);
|
|
|
c90517 |
factory->priv->seat_new_id = 0;
|
|
|
c90517 |
}
|
|
|
c90517 |
if (factory->priv->seat_removed_id) {
|
|
|
c90517 |
g_dbus_connection_signal_unsubscribe (factory->priv->connection,
|
|
|
c90517 |
factory->priv->seat_removed_id);
|
|
|
c90517 |
factory->priv->seat_removed_id = 0;
|
|
|
c90517 |
}
|
|
|
c90517 |
+#if defined(ENABLE_WAYLAND_SUPPORT) && defined(ENABLE_USER_DISPLAY_SERVER)
|
|
|
c90517 |
+ if (factory->priv->active_vt_watch_id) {
|
|
|
c90517 |
+ g_source_remove (factory->priv->active_vt_watch_id);
|
|
|
c90517 |
+ factory->priv->active_vt_watch_id = 0;
|
|
|
c90517 |
+ }
|
|
|
c90517 |
+
|
|
|
c90517 |
+ g_clear_pointer (&factory->priv->tty_of_active_vt, g_free);
|
|
|
c90517 |
+#endif
|
|
|
c90517 |
}
|
|
|
c90517 |
|
|
|
c90517 |
static void
|
|
|
c90517 |
on_display_added (GdmDisplayStore *display_store,
|
|
|
c90517 |
const char *id,
|
|
|
c90517 |
GdmLocalDisplayFactory *factory)
|
|
|
c90517 |
{
|
|
|
c90517 |
GdmDisplay *display;
|
|
|
c90517 |
|
|
|
c90517 |
display = gdm_display_store_lookup (display_store, id);
|
|
|
c90517 |
|
|
|
c90517 |
if (display != NULL) {
|
|
|
c90517 |
g_signal_connect_object (display, "notify::status",
|
|
|
c90517 |
G_CALLBACK (on_display_status_changed),
|
|
|
c90517 |
factory,
|
|
|
c90517 |
0);
|
|
|
c90517 |
|
|
|
c90517 |
g_object_weak_ref (G_OBJECT (display), (GWeakNotify)on_display_disposed, factory);
|
|
|
c90517 |
}
|
|
|
c90517 |
}
|
|
|
c90517 |
|
|
|
c90517 |
static void
|
|
|
c90517 |
on_display_removed (GdmDisplayStore *display_store,
|
|
|
c90517 |
GdmDisplay *display,
|
|
|
c90517 |
GdmLocalDisplayFactory *factory)
|
|
|
c90517 |
{
|
|
|
c90517 |
g_signal_handlers_disconnect_by_func (display, G_CALLBACK (on_display_status_changed), factory);
|
|
|
c90517 |
g_object_weak_unref (G_OBJECT (display), (GWeakNotify)on_display_disposed, factory);
|
|
|
c90517 |
}
|
|
|
c90517 |
|
|
|
c90517 |
--
|
|
|
c90517 |
2.26.0
|
|
|
c90517 |
|