Package: gdm3 Version: 43.0-3 Severity: normal Tags: patch upstream Dear Maintainer,
in multiseat setups, gdm3 is limited to only support Wayland sessions on seat0. There are patches for gdm3 and gnome-shell to enable Wayland sessions for all seats in a multiseat environment. I use these patches on top of the current Debian sid packages for some months now without any glitches. I also tested fast user-switching as requested by the author of these patches. The original source of the patches is here: https://gitlab.gnome.org/GNOME/gdm/-/merge_requests/174/commits I'll open a separate bug for the gnome-shell part of this issue. Regards, Tino -- System Information: Debian Release: bookworm/sid APT prefers unstable APT policy: (500, 'unstable'), (1, 'experimental') Architecture: amd64 (x86_64) Foreign Architectures: i386 Kernel: Linux 6.1.7 (SMP w/12 CPU threads; PREEMPT) Kernel taint flags: TAINT_UNSIGNED_MODULE Locale: LANG=de_DE.UTF-8, LC_CTYPE=de_DE.UTF-8 (charmap=UTF-8), LANGUAGE not set Shell: /bin/sh linked to /usr/bin/dash Init: systemd (via /run/systemd/system) Versions of packages gdm3 depends on: ii accountsservice 22.08.8-5 ii adduser 3.131 ii dbus [default-dbus-system-bus] 1.14.6-1 ii dbus-bin 1.14.6-1 ii dbus-daemon 1.14.6-1 ii dconf-cli 0.40.0-4 ii dconf-gsettings-backend 0.40.0-4 ii debconf [debconf-2.0] 1.5.82 ii fluxbox [x-window-manager] 1.3.5-2.1 ii gir1.2-gdm-1.0 43.0-1.1 ii gnome-session [x-session-manager] 43.0-1 ii gnome-session-bin 43.0-1 ii gnome-session-common 43.0-1 ii gnome-settings-daemon 43.0-4 hi gnome-shell 43.2-1.1 ii gnome-terminal [x-terminal-emulator] 3.46.7-1 ii gsettings-desktop-schemas 43.0-1 ii libaccountsservice0 22.08.8-5 ii libaudit1 1:3.0.9-1 ii libc6 2.36-8 ii libcanberra-gtk3-0 0.30-10 ii libcanberra0 0.30-10 ii libgdk-pixbuf-2.0-0 2.42.10+dfsg-1+b1 ii libgdm1 43.0-1.1 ii libglib2.0-0 2.74.5-1 ii libglib2.0-bin 2.74.5-1 ii libgtk-3-0 3.24.36-3 ii libgudev-1.0-0 237-2 ii libkeyutils1 1.6.3-2 ii libpam-modules 1.5.2-6 ii libpam-runtime 1.5.2-6 ii libpam-systemd [logind] 252.5-2 ii libpam0g 1.5.2-6 ii librsvg2-common 2.54.5+dfsg-1 ii libselinux1 3.4-1+b5 ii libsystemd0 252.5-2 ii libx11-6 2:1.8.3-3 ii libxau6 1:1.0.9-1 ii libxcb1 1.15-1 ii libxdmcp6 1:1.1.2-3 ii lsb-base 11.6 ii mutter [x-window-manager] 43.2-6 ii polkitd 122-3 ii procps 2:4.0.2-3 ii systemd-sysv 252.5-2 ii sysvinit-utils [lsb-base] 3.06-2 ii ucf 3.0043+nmu1 ii x11-common 1:7.7+23 ii x11-xserver-utils 7.7+9+b1 ii xterm [x-terminal-emulator] 378-1 Versions of packages gdm3 recommends: ii at-spi2-core 2.46.0-5 ii desktop-base 12.0.2 ii gnome-session [x-session-manager] 43.0-1 ii x11-xkb-utils 7.7+7 pn xserver-xephyr <none> ii xserver-xorg 1:7.7+23 ii zenity 3.44.0-1 Versions of packages gdm3 suggests: pn libpam-fprintd <none> ii libpam-gnome-keyring 42.1-1+b1 pn libpam-pkcs11 <none> pn libpam-sss <none> pn orca <none> -- Configuration Files: /etc/gdm3/daemon.conf changed: [daemon] WaylandEnable=true [security] [xdmcp] [chooser] [debug] Enable=true -- debconf information: gdm3/daemon_name: /usr/sbin/gdm3 * shared/default-x-display-manager: gdm3
>From 4135ba952ecb75bd53dac14ef10e6bfe1e5c1952 Mon Sep 17 00:00:00 2001 From: msizanoen1 <[email protected]> Date: Mon, 7 Mar 2022 11:34:18 +0700 Subject: [PATCH 1/7] local-display-factory: Acquire seat name properly systemd-logind escapes the seat name prior to exposing as a DBus object. As a result, seat names like "seat-name" may be escaped to "seat_x2dname" when exposed as a DBus object. Use DBus to acquire the seat name instead of using the last component of the object path. --- daemon/gdm-local-display-factory.c | 32 ++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c index 8c912cc6..8d4be1be 100644 --- a/daemon/gdm-local-display-factory.c +++ b/daemon/gdm-local-display-factory.c @@ -1026,19 +1026,39 @@ on_seat_properties_changed (GDBusConnection *connection, const gchar *seat = NULL; g_autoptr(GVariant) changed_props = NULL; g_autoptr(GVariant) changed_prop = NULL; + g_autoptr(GVariant) reply = NULL; + g_autoptr(GVariant) reply_value = NULL; + g_autoptr(GError) error = NULL; g_autofree const gchar **invalidated_props = NULL; gboolean changed = FALSE; int ret; - /* Extract seat id, i.e. the last element of the object path. */ - seat = strrchr (object_path, '/'); - if (seat == NULL) + /* Acquire seat name */ + reply = g_dbus_connection_call_sync (connection, + sender_name, + object_path, + "org.freedesktop.DBus.Properties", + "Get", + g_variant_new ("(ss)", + "org.freedesktop.login1.Seat", + "Id"), + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, &error); + + if (reply == NULL) { + g_debug ("could not acquire seat name: %s", error->message); return; - seat += 1; + } + + g_variant_get (reply, "(v)", &reply_value); - /* Valid seat IDs must start with seat, i.e. ignore "auto" */ - if (!g_str_has_prefix (seat, "seat")) + seat = g_variant_get_string (reply_value, NULL); + + if (seat == NULL) { + g_debug ("seat name is not string"); return; + } g_variant_get (parameters, "(s@a{sv}^a&s)", NULL, &changed_props, &invalidated_props);
>From 43491f85100ef7f76f1557164d92b1321cf4db97 Mon Sep 17 00:00:00 2001 From: msizanoen1 <[email protected]> Date: Mon, 7 Mar 2022 12:03:15 +0700 Subject: [PATCH 2/7] daemon: Allow Wayland sessions on non-primary seats --- daemon/gdm-local-display-factory.c | 38 ++++++++++++------------------ daemon/gdm-manager.c | 3 +-- daemon/gdm-session.c | 5 +--- 3 files changed, 17 insertions(+), 29 deletions(-) diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c index 8d4be1be..369ad4ef 100644 --- a/daemon/gdm-local-display-factory.c +++ b/daemon/gdm-local-display-factory.c @@ -785,26 +785,20 @@ ensure_display_for_seat (GdmLocalDisplayFactory *factory, seat_supports_graphics = FALSE; } - if (g_strcmp0 (seat_id, "seat0") == 0) { + if (g_strcmp0 (seat_id, "seat0") == 0) is_seat0 = TRUE; + else + is_seat0 = FALSE; - falling_back = factory->num_failures > 0; - session_types = gdm_local_display_factory_get_session_types (factory, falling_back); + falling_back = factory->num_failures > 0; + session_types = gdm_local_display_factory_get_session_types (factory, falling_back); - if (session_types == NULL) { - g_debug ("GdmLocalDisplayFactory: Both Wayland and Xorg are unavailable"); - seat_supports_graphics = FALSE; - } else { - g_debug ("GdmLocalDisplayFactory: New displays on seat0 will use %s%s", - session_types[0], falling_back? " fallback" : ""); - } + if (session_types == NULL) { + g_debug ("GdmLocalDisplayFactory: Both Wayland and Xorg are unavailable"); + seat_supports_graphics = FALSE; } else { - is_seat0 = FALSE; - - g_debug ("GdmLocalDisplayFactory: New displays on seat %s will use X11 fallback", seat_id); - /* Force legacy X11 for all auxiliary seats */ - seat_supports_graphics = TRUE; - session_types = g_strdupv ((char **) legacy_session_types); + g_debug ("GdmLocalDisplayFactory: New displays on seat0 will use %s%s", + session_types[0], falling_back? " fallback" : ""); } /* For seat0, we have a fallback logic to still try starting it after @@ -896,13 +890,11 @@ ensure_display_for_seat (GdmLocalDisplayFactory *factory, #ifdef ENABLE_USER_DISPLAY_SERVER if (g_strcmp0 (preferred_display_server, "wayland") == 0 || g_strcmp0 (preferred_display_server, "xorg") == 0) { - if (is_seat0) { - display = gdm_local_display_new (); - g_object_set (G_OBJECT (display), - "session-type", session_types[0], - "supported-session-types", session_types, - NULL); - } + display = gdm_local_display_new (); + g_object_set (G_OBJECT (display), + "session-type", session_types[0], + "supported-session-types", session_types, + NULL); } #endif diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c index cc61efc9..7e4b0274 100644 --- a/daemon/gdm-manager.c +++ b/daemon/gdm-manager.c @@ -1640,8 +1640,7 @@ create_display_for_user_session (GdmManager *self, const char *session_id) { GdmDisplay *display; - /* at the moment we only create GdmLocalDisplay objects on seat0 */ - const char *seat_id = "seat0"; + g_autofree const char *seat_id = gdm_session_get_display_seat_id (session); display = gdm_local_display_new (); diff --git a/daemon/gdm-session.c b/daemon/gdm-session.c index 4b709731..0b6f9e91 100644 --- a/daemon/gdm-session.c +++ b/daemon/gdm-session.c @@ -3336,11 +3336,8 @@ gdm_session_get_display_mode (GdmSession *self) self->is_program_session? "yes" : "no", self->display_seat_id); - /* Non-seat0 sessions share their X server with their login screen - * for now. - */ if (g_strcmp0 (self->display_seat_id, "seat0") != 0) { - return GDM_SESSION_DISPLAY_MODE_REUSE_VT; + return GDM_SESSION_DISPLAY_MODE_LOGIND_MANAGED; } #ifdef ENABLE_USER_DISPLAY_SERVER
>From 20f0a6ff9e02c952792519ffc694b864b5bee11a Mon Sep 17 00:00:00 2001 From: msizanoen1 <[email protected]> Date: Mon, 7 Mar 2022 12:05:07 +0700 Subject: [PATCH 3/7] gdm-session-worker: Do not set PAM_TTY on non-primary seats pam_systemd complains and refuse to create the login session when PAM_TTY or XDG_VTNR is configured on non-primary seats. --- daemon/gdm-session-worker.c | 43 +++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c index a264ea1d..c3b8374a 100644 --- a/daemon/gdm-session-worker.c +++ b/daemon/gdm-session-worker.c @@ -1237,10 +1237,13 @@ gdm_session_worker_initialize_pam (GdmSessionWorker *worker, g_debug ("GdmSessionWorker: state SETUP_COMPLETE"); gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_SETUP_COMPLETE); - /* Temporarily set PAM_TTY with the login VT, - PAM_TTY will be reset with the users VT right before the user session is opened */ - g_snprintf (tty_string, 256, "/dev/tty%d", GDM_INITIAL_VT); - pam_set_item (worker->priv->pam_handle, PAM_TTY, tty_string); + if (strcmp (seat_id, "seat0") == 0) { + /* Temporarily set PAM_TTY with the login VT, + PAM_TTY will be reset with the users VT right before the user session is opened */ + g_snprintf (tty_string, 256, "/dev/tty%d", GDM_INITIAL_VT); + pam_set_item (worker->priv->pam_handle, PAM_TTY, tty_string); + } + if (!display_is_local) worker->priv->password_is_required = TRUE; @@ -2376,22 +2379,24 @@ gdm_session_worker_open_session (GdmSessionWorker *worker, g_assert (worker->priv->state == GDM_SESSION_WORKER_STATE_ACCOUNT_DETAILS_SAVED); g_assert (geteuid () == 0); - switch (worker->priv->display_mode) { - case GDM_SESSION_DISPLAY_MODE_REUSE_VT: - if (!set_up_for_current_vt (worker, error)) { - return FALSE; - } - break; - case GDM_SESSION_DISPLAY_MODE_NEW_VT: - case GDM_SESSION_DISPLAY_MODE_LOGIND_MANAGED: - if (!set_up_for_new_vt (worker)) { - g_set_error (error, - GDM_SESSION_WORKER_ERROR, - GDM_SESSION_WORKER_ERROR_OPENING_SESSION, - "Unable to open VT"); - return FALSE; + if (g_strcmp0 (worker->priv->display_seat_id, "seat0") == 0) { + switch (worker->priv->display_mode) { + case GDM_SESSION_DISPLAY_MODE_REUSE_VT: + if (!set_up_for_current_vt (worker, error)) { + return FALSE; + } + break; + case GDM_SESSION_DISPLAY_MODE_NEW_VT: + case GDM_SESSION_DISPLAY_MODE_LOGIND_MANAGED: + if (!set_up_for_new_vt (worker)) { + g_set_error (error, + GDM_SESSION_WORKER_ERROR, + GDM_SESSION_WORKER_ERROR_OPENING_SESSION, + "Unable to open VT"); + return FALSE; + } + break; } - break; } flags = 0;
>From 0403c5288e14349b735c8e9c97efe80478782c35 Mon Sep 17 00:00:00 2001 From: msizanoen1 <[email protected]> Date: Mon, 7 Mar 2022 12:24:51 +0700 Subject: [PATCH 4/7] local-display-factory: Search for greeter sessions from logind before looking up the display from display store On non-primary seats, GDM will look up the display from display store and abort ensuring a display for seat. This causes the seat to have no active session when a user logs out, instead of the login screen. Fix this by searching for greeter sessions from logind before looking up the display from display store. --- daemon/gdm-local-display-factory.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c index 369ad4ef..5407c682 100644 --- a/daemon/gdm-local-display-factory.c +++ b/daemon/gdm-local-display-factory.c @@ -856,17 +856,6 @@ ensure_display_for_seat (GdmLocalDisplayFactory *factory, store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory)); - if (is_seat0) - display = gdm_display_store_find (store, lookup_prepared_display_by_seat_id, (gpointer) seat_id); - else - display = gdm_display_store_find (store, lookup_by_seat_id, (gpointer) seat_id); - - /* Ensure we don't create the same display more than once */ - if (display != NULL) { - g_debug ("GdmLocalDisplayFactory: display already created"); - return; - } - /* If we already have a login window, switch to it */ if (gdm_get_login_window_session_id (seat_id, &login_session_id)) { GdmDisplay *display; @@ -885,6 +874,17 @@ ensure_display_for_seat (GdmLocalDisplayFactory *factory, } } + if (is_seat0) + display = gdm_display_store_find (store, lookup_prepared_display_by_seat_id, (gpointer) seat_id); + else + display = gdm_display_store_find (store, lookup_by_seat_id, (gpointer) seat_id); + + /* Ensure we don't create the same display more than once */ + if (display != NULL) { + g_debug ("GdmLocalDisplayFactory: display already created"); + return; + } + g_debug ("GdmLocalDisplayFactory: Adding display on seat %s", seat_id); #ifdef ENABLE_USER_DISPLAY_SERVER
>From 64d5d6c3124e96ca5b12fd9cb7a16c1f841a97f5 Mon Sep 17 00:00:00 2001 From: msizanoen1 <[email protected]> Date: Mon, 7 Mar 2022 12:29:57 +0700 Subject: [PATCH 5/7] local-display-factory: Only ensure display for the session's seat on logout instead of all seats An user logging out from another seat shouldn't affect other users on other seats. Limit ensuring a greeter session to the seat that have just been logged out. --- daemon/gdm-local-display-factory.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c index 5407c682..6e0e7701 100644 --- a/daemon/gdm-local-display-factory.c +++ b/daemon/gdm-local-display-factory.c @@ -546,17 +546,15 @@ on_display_status_changed (GdmDisplay *display, } gdm_display_factory_queue_purge_displays (GDM_DISPLAY_FACTORY (factory)); - /* if this is a local display, do a full resync. Only - * seats without displays will get created anyway. This - * ensures we get a new login screen when the user logs out, - * if there isn't one. + /* if this is a local display, ensure that we get a login + * screen when the user logs out. */ if (is_local && (g_strcmp0 (session_class, "greeter") != 0 || factory->active_vt == GDM_INITIAL_VT)) { /* reset num failures */ factory->num_failures = 0; - gdm_local_display_factory_sync_seats (factory); + ensure_display_for_seat (factory, seat_id); } break; case GDM_DISPLAY_FAILED:
>From 073f58051db50a169bb5f25ecbff66d20c40fd2c Mon Sep 17 00:00:00 2001 From: msizanoen1 <[email protected]> Date: Mon, 7 Mar 2022 12:35:20 +0700 Subject: [PATCH 6/7] local-display-factory: Ensure greeter sessions on non-primary seats are respawned on termination Trigger ensuring a greeter session for a non-primary seat when it terminates and only looking for displays with state of GDM_DISPLAY_MANAGED when checking for duplicates in ensure_display_for_seat on non-primary seats. --- daemon/gdm-local-display-factory.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c index 6e0e7701..b9522e5a 100644 --- a/daemon/gdm-local-display-factory.c +++ b/daemon/gdm-local-display-factory.c @@ -550,7 +550,8 @@ on_display_status_changed (GdmDisplay *display, * screen when the user logs out. */ if (is_local && - (g_strcmp0 (session_class, "greeter") != 0 || factory->active_vt == GDM_INITIAL_VT)) { + (g_strcmp0 (session_class, "greeter") != 0 || factory->active_vt == GDM_INITIAL_VT || + g_strcmp0 (seat_id, "seat0") != 0)) { /* reset num failures */ factory->num_failures = 0; @@ -632,6 +633,21 @@ lookup_prepared_display_by_seat_id (const char *id, return lookup_by_seat_id (id, display, user_data); } +static gboolean +lookup_managed_display_by_seat_id (const char *id, + GdmDisplay *display, + gpointer user_data) +{ + int status; + + status = gdm_display_get_status (display); + + if (status != GDM_DISPLAY_MANAGED) + return FALSE; + + return lookup_by_seat_id (id, display, user_data); +} + #ifdef HAVE_UDEV static gboolean udev_is_settled (GdmLocalDisplayFactory *factory) @@ -875,7 +891,7 @@ ensure_display_for_seat (GdmLocalDisplayFactory *factory, if (is_seat0) display = gdm_display_store_find (store, lookup_prepared_display_by_seat_id, (gpointer) seat_id); else - display = gdm_display_store_find (store, lookup_by_seat_id, (gpointer) seat_id); + display = gdm_display_store_find (store, lookup_managed_display_by_seat_id, (gpointer) seat_id); /* Ensure we don't create the same display more than once */ if (display != NULL) {
>From 23a936d1471f091193814e89b8fdca849f48d498 Mon Sep 17 00:00:00 2001 From: msizanoen1 <[email protected]> Date: Sat, 30 Apr 2022 10:08:16 +0700 Subject: [PATCH 7/7] local-display-factory: Do not ensure login screen when a background user session terminates --- daemon/gdm-local-display-factory.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/daemon/gdm-local-display-factory.c b/daemon/gdm-local-display-factory.c index b9522e5a..cf6c0bbd 100644 --- a/daemon/gdm-local-display-factory.c +++ b/daemon/gdm-local-display-factory.c @@ -514,8 +514,10 @@ on_display_status_changed (GdmDisplay *display, int status; int num; char *seat_id = NULL; + char *seat_active_session = NULL; char *session_type = NULL; char *session_class = NULL; + char *session_id = NULL; gboolean is_initial = TRUE; gboolean is_local = TRUE; @@ -532,8 +534,11 @@ on_display_status_changed (GdmDisplay *display, "is-local", &is_local, "session-type", &session_type, "session-class", &session_class, + "session-id", &session_id, NULL); + sd_seat_get_active(seat_id, &seat_active_session, NULL); + status = gdm_display_get_status (display); g_debug ("GdmLocalDisplayFactory: display status changed: %d", status); @@ -550,7 +555,9 @@ on_display_status_changed (GdmDisplay *display, * screen when the user logs out. */ if (is_local && - (g_strcmp0 (session_class, "greeter") != 0 || factory->active_vt == GDM_INITIAL_VT || + ((g_strcmp0 (session_class, "greeter") != 0 && + (!seat_active_session || g_strcmp0(session_id, seat_active_session) == 0)) || + factory->active_vt == GDM_INITIAL_VT || g_strcmp0 (seat_id, "seat0") != 0)) { /* reset num failures */ factory->num_failures = 0; @@ -596,8 +603,10 @@ on_display_status_changed (GdmDisplay *display, } g_free (seat_id); + g_free (seat_active_session); g_free (session_type); g_free (session_class); + g_free (session_id); } static gboolean

