From 1a810024da1d3d5910b286205b6a645cde7e679e Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Fri, 27 Oct 2023 09:49:24 -0400
Subject: [PATCH 1/9] manager: Use sd_session_is_remote instead of looking at
 seat id

A very long time ago logind gained an API for detecting if a session
is remote. GDM has a FIXME to actually use the API rather than
perform heuristics based on seat id.

This commit fixes the FIXME.
---
 daemon/gdm-manager.c | 28 +++++++++-------------------
 1 file changed, 9 insertions(+), 19 deletions(-)

diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index 0e0f30cfb..22ae1195b 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -377,29 +377,19 @@ is_remote_session (GdmManager  *self,
                    const char  *session_id,
                    GError     **error)
 {
-        char *seat;
         int ret;
-        gboolean is_remote;
 
-        /* FIXME: The next release of logind is going to have explicit api for
-         * checking remoteness.
-         */
-        seat = NULL;
-        ret = sd_session_get_seat (session_id, &seat);
+        ret = sd_session_is_remote (session_id);
 
         if (ret < 0 && ret != -ENXIO) {
-                g_debug ("GdmManager: Error while retrieving seat for session %s: %s",
-                         session_id, strerror (-ret));
-        }
-
-        if (seat != NULL) {
-                is_remote = FALSE;
-                free (seat);
-        } else {
-                is_remote = TRUE;
+                g_set_error (error,
+                             GDM_DISPLAY_ERROR,
+                             GDM_DISPLAY_ERROR_GETTING_SESSION_INFO,
+                             "%s", g_strerror (-ret));
+                return FALSE;
         }
 
-        return is_remote;
+        return ret != FALSE;
 }
 
 static char *
@@ -554,8 +544,8 @@ get_display_and_details_for_bus_sender (GdmManager       *self,
                 *out_is_remote = is_remote_session (self, session_id, &error);
 
                 if (error != NULL) {
-                        g_debug ("GdmManager: Error while retrieving remoteness for session: %s",
-                                 error->message);
+                        g_debug ("GdmManager: Error while retrieving remoteness for session %s: %s",
+                                 session_id, error->message);
                         g_clear_error (&error);
                 }
         }
-- 
GitLab


From 583f7b5206d404c5dbb02d7bc9036516ef15978a Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 1 Nov 2023 18:10:43 -0400
Subject: [PATCH 2/9] gdm-session-worker: Always set PAM_RHOST if
 !display_is_local

Sometimes a session could be remote, but the connected client
is dynamic. In that case we don't know the remote hostname up
front but we need to put *something* so that logind marks the
session as remote.

This commit identifies that case and sets the hostname to
0.0.0.0 which is better than nothing I guess.
---
 daemon/gdm-session-worker.c | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c
index 32f4572ec..3c8ab47aa 100644
--- a/daemon/gdm-session-worker.c
+++ b/daemon/gdm-session-worker.c
@@ -1199,11 +1199,19 @@ gdm_session_worker_initialize_pam (GdmSessionWorker   *worker,
         }
 
         /* set RHOST */
-        if (hostname != NULL && hostname[0] != '\0') {
-                error_code = pam_set_item (worker->pam_handle, PAM_RHOST, hostname);
-                g_debug ("error informing authentication system of user's hostname %s: %s",
-                         hostname,
-                         pam_strerror (worker->pam_handle, error_code));
+        if (!display_is_local) {
+                if (hostname != NULL && hostname[0] != '\0') {
+                        error_code = pam_set_item (worker->pam_handle, PAM_RHOST, hostname);
+
+                        g_debug ("error informing authentication system of user's hostname %s: %s",
+                                 hostname,
+                                 pam_strerror (worker->pam_handle, error_code));
+                } else {
+                        error_code = pam_set_item (worker->pam_handle, PAM_RHOST, "0.0.0.0");
+
+                        g_debug ("error informing authentication system user is remote but has indeterminate hostname: %s",
+                                 pam_strerror (worker->pam_handle, error_code));
+                }
 
                 if (error_code != PAM_SUCCESS) {
                         g_set_error_literal (error,
-- 
GitLab


From 937eddc1d3ea64cde422e63489e55e25bfe51745 Mon Sep 17 00:00:00 2001
From: Joan Torres <joan.torres@suse.com>
Date: Wed, 13 Jul 2022 17:42:21 +0200
Subject: [PATCH 3/9] settings: Add RemoteLoginEnable option

As a first step toward getting remote login support in GDM, this
commit adds a new RemoteLoginEnable option.

This is a big switch to just turn the feature on or off. The
switch is on by default, because it doesn't actually
enable remote login by itself. It still requires gnome-remote-desktop
(or whatever) to be running as a system service to manage the remote
login requests.
---
 common/gdm-settings-keys.h | 1 +
 data/gdm.schemas.in        | 5 +++++
 2 files changed, 6 insertions(+)

diff --git a/common/gdm-settings-keys.h b/common/gdm-settings-keys.h
index 87685d3cd..631a30cea 100644
--- a/common/gdm-settings-keys.h
+++ b/common/gdm-settings-keys.h
@@ -36,6 +36,7 @@ G_BEGIN_DECLS
 #define GDM_KEY_PREFERRED_DISPLAY_SERVER "daemon/PreferredDisplayServer"
 #define GDM_KEY_WAYLAND_ENABLE "daemon/WaylandEnable"
 #define GDM_KEY_XORG_ENABLE "daemon/XorgEnable"
+#define GDM_KEY_REMOTE_LOGIN_ENABLE "daemon/RemoteLoginEnable"
 
 #define GDM_KEY_DEBUG "debug/Enable"
 
diff --git a/data/gdm.schemas.in b/data/gdm.schemas.in
index a1035f95e..621bfca04 100644
--- a/data/gdm.schemas.in
+++ b/data/gdm.schemas.in
@@ -67,6 +67,11 @@
       <signature>b</signature>
       <default>true</default>
     </schema>
+    <schema>
+      <key>daemon/RemoteLoginEnable</key>
+      <signature>b</signature>
+      <default>true</default>
+    </schema>
     <schema>
       <key>security/AllowRemoteAutoLogin</key>
       <signature>b</signature>
-- 
GitLab


From 7503d3dd939daf46709e72055ebc23b663c255ac Mon Sep 17 00:00:00 2001
From: Joan Torres <joan.torres@suse.com>
Date: Fri, 22 Jul 2022 09:10:49 +0200
Subject: [PATCH 4/9] Introduce Remote Display

New class that is used to define wayland headless remote displays.

These displays expose a dbus interface RemoteDisplay with RemoteId property
which represents the id of the RemoteClient from grd daemon-system.
This means this display will be used by that RemoteClient.

Bind the session_id property from the display parent and expose it on
the RemoteDisplay interface too.
---
 daemon/gdm-display.c          |   2 +-
 daemon/gdm-remote-display.c   | 116 ++++++++++++++++++++++++++++++++++
 daemon/gdm-remote-display.h   |  40 ++++++++++++
 daemon/gdm-remote-display.xml |   7 ++
 daemon/meson.build            |   8 +++
 data/gdm.conf.in              |   6 ++
 6 files changed, 178 insertions(+), 1 deletion(-)
 create mode 100644 daemon/gdm-remote-display.c
 create mode 100644 daemon/gdm-remote-display.h
 create mode 100644 daemon/gdm-remote-display.xml

diff --git a/daemon/gdm-display.c b/daemon/gdm-display.c
index 39430a5bf..eb450a692 100644
--- a/daemon/gdm-display.c
+++ b/daemon/gdm-display.c
@@ -1475,7 +1475,7 @@ on_launch_environment_session_opened (GdmLaunchEnvironment *launch_environment,
 
         g_debug ("GdmDisplay: Greeter session opened");
         session_id = gdm_launch_environment_get_session_id (launch_environment);
-        _gdm_display_set_session_id (self, session_id);
+        g_object_set (G_OBJECT (self), "session-id", session_id, NULL);
 }
 
 static void
diff --git a/daemon/gdm-remote-display.c b/daemon/gdm-remote-display.c
new file mode 100644
index 000000000..a7cc8548b
--- /dev/null
+++ b/daemon/gdm-remote-display.c
@@ -0,0 +1,116 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2022 Joan Torres <joan.torres@suse.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * 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.
+ *
+ */
+
+#include "config.h"
+
+#include <glib-object.h>
+
+#include "gdm-display.h"
+#include "gdm-remote-display.h"
+#include "gdm-remote-display-glue.h"
+
+struct _GdmRemoteDisplay
+{
+        GdmDisplay            parent;
+
+        GdmDBusRemoteDisplay *skeleton;
+};
+
+static void     gdm_remote_display_class_init   (GdmRemoteDisplayClass *klass);
+static void     gdm_remote_display_init         (GdmRemoteDisplay      *remote_display);
+
+G_DEFINE_TYPE (GdmRemoteDisplay, gdm_remote_display, GDM_TYPE_DISPLAY)
+
+static GObject *
+gdm_remote_display_constructor (GType                  type,
+                                guint                  n_construct_properties,
+                                GObjectConstructParam *construct_properties)
+{
+        GdmRemoteDisplay *display;
+
+        display = GDM_REMOTE_DISPLAY (G_OBJECT_CLASS (gdm_remote_display_parent_class)->constructor (type,
+                                                                                                     n_construct_properties,
+                                                                                                     construct_properties));
+
+        display->skeleton = GDM_DBUS_REMOTE_DISPLAY (gdm_dbus_remote_display_skeleton_new ());
+
+        g_dbus_object_skeleton_add_interface (gdm_display_get_object_skeleton (GDM_DISPLAY (display)),
+                                              G_DBUS_INTERFACE_SKELETON (display->skeleton));
+
+        g_object_bind_property (display, "session-id", display->skeleton, "session-id", G_BINDING_SYNC_CREATE);
+
+        return G_OBJECT (display);
+}
+
+static void
+gdm_remote_display_finalize (GObject *object)
+{
+        GdmRemoteDisplay *display = GDM_REMOTE_DISPLAY (object);
+
+        g_clear_object (&display->skeleton);
+
+        G_OBJECT_CLASS (gdm_remote_display_parent_class)->finalize (object);
+}
+
+static gboolean
+gdm_remote_display_prepare (GdmDisplay *display)
+{
+        /* TODO: create a headless greeter launch environment */
+
+        return GDM_DISPLAY_CLASS (gdm_remote_display_parent_class)->prepare (display);
+}
+
+static void
+gdm_remote_display_class_init (GdmRemoteDisplayClass *klass)
+{
+        GObjectClass *object_class = G_OBJECT_CLASS (klass);
+        GdmDisplayClass *display_class = GDM_DISPLAY_CLASS (klass);
+
+        object_class->constructor = gdm_remote_display_constructor;
+        object_class->finalize = gdm_remote_display_finalize;
+
+        display_class->prepare = gdm_remote_display_prepare;
+}
+
+static void
+gdm_remote_display_init (GdmRemoteDisplay *remote_display)
+{
+}
+
+GdmDisplay *
+gdm_remote_display_new (const char *remote_id)
+{
+        GObject *object;
+        GdmRemoteDisplay *self;
+
+        const char *session_types[] = { "wayland", NULL };
+
+        object = g_object_new (GDM_TYPE_REMOTE_DISPLAY,
+                               "is-local", FALSE,
+                               "session-type", session_types[0],
+                               "supported-session-types", session_types,
+                               NULL);
+
+        self = GDM_REMOTE_DISPLAY (object);
+        g_object_set (G_OBJECT (self->skeleton), "remote-id", remote_id, NULL);
+
+        return GDM_DISPLAY (object);
+}
+
diff --git a/daemon/gdm-remote-display.h b/daemon/gdm-remote-display.h
new file mode 100644
index 000000000..2d2c0eb42
--- /dev/null
+++ b/daemon/gdm-remote-display.h
@@ -0,0 +1,40 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2022 Joan Torres <joan.torres@suse.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * 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.
+ *
+ */
+
+
+#ifndef __GDM_REMOTE_DISPLAY_H
+#define __GDM_REMOTE_DISPLAY_H
+
+#include <glib-object.h>
+#include <stdint.h>
+
+#include "gdm-display.h"
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_REMOTE_DISPLAY         (gdm_remote_display_get_type ())
+G_DECLARE_FINAL_TYPE (GdmRemoteDisplay, gdm_remote_display, GDM, REMOTE_DISPLAY, GdmDisplay)
+
+GdmDisplay *        gdm_remote_display_new                     (const char *remote_id);
+
+G_END_DECLS
+
+#endif /* __GDM_REMOTE_DISPLAY_H */
+
diff --git a/daemon/gdm-remote-display.xml b/daemon/gdm-remote-display.xml
new file mode 100644
index 000000000..2fdf9ad7f
--- /dev/null
+++ b/daemon/gdm-remote-display.xml
@@ -0,0 +1,7 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+  <interface name="org.gnome.DisplayManager.RemoteDisplay">
+    <property name="RemoteId" type="o" access="read"/>
+    <property name="SessionId" type="s" access="read"/>
+  </interface>
+</node>
diff --git a/daemon/meson.build b/daemon/meson.build
index 41f30abef..3842aff38 100644
--- a/daemon/meson.build
+++ b/daemon/meson.build
@@ -23,6 +23,12 @@ local_display_factory_dbus_gen = gnome.gdbus_codegen('gdm-local-display-factory-
   interface_prefix: 'org.gnome.DisplayManager',
   autocleanup: 'all',
 )
+remote_display_dbus_gen = gnome.gdbus_codegen('gdm-remote-display-glue',
+  'gdm-remote-display.xml',
+  namespace: 'GdmDBus',
+  interface_prefix: 'org.gnome.DisplayManager',
+  autocleanup: 'all',
+)
 manager_dbus_gen = gnome.gdbus_codegen('gdm-manager-glue',
   'gdm-manager.xml',
   namespace: 'GdmDBus',
@@ -172,6 +178,7 @@ gdm_daemon_sources = files(
   'gdm-legacy-display.c',
   'gdm-local-display-factory.c',
   'gdm-local-display.c',
+  'gdm-remote-display.c',
   'gdm-manager.c',
   'gdm-server.c',
   'gdm-session-record.c',
@@ -186,6 +193,7 @@ gdm_daemon_gen_sources = [
   local_display_factory_dbus_gen,
   manager_dbus_gen,
   local_display_dbus_gen,
+  remote_display_dbus_gen,
   session_dbus_gen,
   session_worker_dbus_gen,
   gdm_session_enums,
diff --git a/data/gdm.conf.in b/data/gdm.conf.in
index 2d8897d39..3b9148fc8 100644
--- a/data/gdm.conf.in
+++ b/data/gdm.conf.in
@@ -11,6 +11,8 @@
            send_interface="org.gnome.DisplayManager.Manager"/>
     <allow send_destination="org.gnome.DisplayManager"
            send_interface="org.gnome.DisplayManager.Display"/>
+    <allow send_destination="org.gnome.DisplayManager"
+           send_interface="org.gnome.DisplayManager.RemoteDisplay"/>
     <allow send_destination="org.gnome.DisplayManager"
            send_interface="org.gnome.DisplayManager.LocalDisplayFactory"/>
     <allow send_destination="org.gnome.DisplayManager"
@@ -25,6 +27,8 @@
   <policy context="default">
     <deny send_destination="org.gnome.DisplayManager"
           send_interface="org.gnome.DisplayManager.Display"/>
+    <deny send_destination="org.gnome.DisplayManager"
+          send_interface="org.gnome.DisplayManager.RemoteDisplay"/>
     <deny send_destination="org.gnome.DisplayManager"
           send_interface="org.gnome.DisplayManager.LocalDisplayFactory"/>
     <deny send_destination="org.gnome.DisplayManager"
@@ -68,6 +72,8 @@
            send_interface="org.gnome.DisplayManager.Manager"/>
     <allow send_destination="org.gnome.DisplayManager"
            send_interface="org.gnome.DisplayManager.Display"/>
+    <allow send_destination="org.gnome.DisplayManager"
+           send_interface="org.gnome.DisplayManager.RemoteDisplay"/>
     <allow send_destination="org.gnome.DisplayManager"
            send_interface="org.gnome.DisplayManager.LocalDisplayFactory"/>
     <allow send_destination="org.gnome.DisplayManager"
-- 
GitLab


From 19bc765b00ddde060072d349f55545e28b4012c8 Mon Sep 17 00:00:00 2001
From: Joan Torres <joan.torres@suse.com>
Date: Fri, 22 Jul 2022 09:31:15 +0200
Subject: [PATCH 5/9] remote-display: Start login screen when display is
 prepared

This commit ensures a login screen gets created on remote
displays at the time they are prepared.
---
 daemon/gdm-remote-display.c | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/daemon/gdm-remote-display.c b/daemon/gdm-remote-display.c
index a7cc8548b..9b7c8a8db 100644
--- a/daemon/gdm-remote-display.c
+++ b/daemon/gdm-remote-display.c
@@ -23,6 +23,7 @@
 #include <glib-object.h>
 
 #include "gdm-display.h"
+#include "gdm-launch-environment.h"
 #include "gdm-remote-display.h"
 #include "gdm-remote-display-glue.h"
 
@@ -72,7 +73,21 @@ gdm_remote_display_finalize (GObject *object)
 static gboolean
 gdm_remote_display_prepare (GdmDisplay *display)
 {
-        /* TODO: create a headless greeter launch environment */
+        GdmRemoteDisplay *self = GDM_REMOTE_DISPLAY (display);
+        g_autoptr (GdmLaunchEnvironment) launch_environment = NULL;
+        g_autofree char *session_type = NULL;
+
+        g_object_get (self,
+                      "session-type", &session_type,
+                      NULL);
+
+        launch_environment = gdm_create_greeter_launch_environment (NULL,
+                                                                    NULL,
+                                                                    session_type,
+                                                                    NULL,
+                                                                    FALSE);
+
+        g_object_set (self, "launch-environment", launch_environment, NULL);
 
         return GDM_DISPLAY_CLASS (gdm_remote_display_parent_class)->prepare (display);
 }
-- 
GitLab


From 942227209f19dd15649d0fbf052e0ceaf6826e10 Mon Sep 17 00:00:00 2001
From: Joan Torres <joan.torres@suse.com>
Date: Wed, 13 Jul 2022 17:35:21 +0200
Subject: [PATCH 6/9] Introduce Remote Display Factory

This commit adds a new class used to create remote displays.

It exposes a RemoteDisplayFactory interface over the bus to create remote displays
with a CreateRemoteDisplay method. This method sets the received remote_id to
on the created RemoteDisplay.

When it creates a remote display, it stores it in the display store and
prepares it (which makes the remote display create a headless login screen)
---
 daemon/gdm-remote-display-factory.c   | 219 ++++++++++++++++++++++++++
 daemon/gdm-remote-display-factory.h   |  39 +++++
 daemon/gdm-remote-display-factory.xml |   8 +
 daemon/meson.build                    |   8 +
 data/gdm.conf.in                      |  11 ++
 data/meson.build                      |   2 +-
 6 files changed, 286 insertions(+), 1 deletion(-)
 create mode 100644 daemon/gdm-remote-display-factory.c
 create mode 100644 daemon/gdm-remote-display-factory.h
 create mode 100644 daemon/gdm-remote-display-factory.xml

diff --git a/daemon/gdm-remote-display-factory.c b/daemon/gdm-remote-display-factory.c
new file mode 100644
index 000000000..26d0302f1
--- /dev/null
+++ b/daemon/gdm-remote-display-factory.c
@@ -0,0 +1,219 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2022 Joan Torres <joan.torres@suse.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * 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.
+ *
+ */
+
+#include "config.h"
+
+#include "gdm-remote-display.h"
+#include "gdm-remote-display-factory.h"
+#include "gdm-remote-display-factory-glue.h"
+
+#define GDM_REMOTE_DISPLAY_FACTORY_DBUS_PATH "/org/gnome/DisplayManager/RemoteDisplayFactory"
+
+struct _GdmRemoteDisplayFactory
+{
+        GdmDisplayFactory            parent;
+
+        GdmDBusRemoteDisplayFactory *skeleton;
+        GDBusConnection             *connection;
+};
+
+static void     gdm_remote_display_factory_class_init    (GdmRemoteDisplayFactoryClass *klass);
+static void     gdm_remote_display_factory_init          (GdmRemoteDisplayFactory      *factory);
+static void     gdm_remote_display_factory_finalize      (GObject                     *object);
+
+static gpointer remote_display_factory_object = NULL;
+
+G_DEFINE_TYPE (GdmRemoteDisplayFactory, gdm_remote_display_factory, GDM_TYPE_DISPLAY_FACTORY)
+
+static void
+on_display_status_changed (GdmDisplay              *display,
+                           GParamSpec              *arg1,
+                           GdmRemoteDisplayFactory *factory)
+{
+        g_debug ("GdmRemoteDisplayFactory: remote display status changed: %d",
+                 gdm_display_get_status (display));
+}
+
+static gboolean
+gdm_remote_display_factory_create_remote_display (GdmRemoteDisplayFactory *factory,
+                                                  const char              *remote_id)
+{
+        GdmDisplay      *display  = NULL;
+        GdmDisplayStore *store;
+
+        g_debug ("GdmRemoteDisplayFactory: Creating remote display");
+
+        display = gdm_remote_display_new (remote_id);
+
+        store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
+        gdm_display_store_add (store, display);
+
+        if (!gdm_display_prepare (display)) {
+                gdm_display_unmanage (display);
+                g_object_unref (display);
+                return FALSE;
+        }
+
+        g_signal_connect_after (display,
+                                "notify::status",
+                                G_CALLBACK (on_display_status_changed),
+                                factory);
+
+        g_object_unref (display);
+
+        return TRUE;
+}
+
+static gboolean
+handle_create_remote_display (GdmDBusRemoteDisplayFactory *skeleton,
+                              GDBusMethodInvocation       *invocation,
+                              const char                  *remote_id,
+                              GdmRemoteDisplayFactory     *factory)
+{
+        if (!gdm_remote_display_factory_create_remote_display (factory, remote_id))
+                g_dbus_method_invocation_return_error_literal (invocation,
+                                                               G_DBUS_ERROR,
+                                                               G_DBUS_ERROR_FAILED,
+                                                               "Error creating remote display");
+        else
+                gdm_dbus_remote_display_factory_complete_create_remote_display (factory->skeleton,
+                                                                                invocation);
+
+        return TRUE;
+}
+
+static gboolean
+register_factory (GdmRemoteDisplayFactory *factory)
+{
+        GError *error = NULL;
+
+        factory->connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
+        if (factory->connection == NULL) {
+                g_critical ("Error getting system bus: %s", error->message);
+                g_error_free (error);
+                exit (EXIT_FAILURE);
+        }
+
+        factory->skeleton = GDM_DBUS_REMOTE_DISPLAY_FACTORY (gdm_dbus_remote_display_factory_skeleton_new ());
+
+        g_signal_connect (factory->skeleton,
+                          "handle-create-remote-display",
+                          G_CALLBACK (handle_create_remote_display),
+                          factory);
+
+        if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (factory->skeleton),
+                                               factory->connection,
+                                               GDM_REMOTE_DISPLAY_FACTORY_DBUS_PATH,
+                                               &error)) {
+                g_critical ("Error exporting RemoteDisplayFactory object: %s", error->message);
+                g_error_free (error);
+                exit (EXIT_FAILURE);
+        }
+
+        return TRUE;
+}
+
+static void
+gdm_remote_display_factory_finalize (GObject *object)
+{
+        GdmRemoteDisplayFactory *factory;
+
+        g_return_if_fail (object != NULL);
+        g_return_if_fail (GDM_IS_REMOTE_DISPLAY_FACTORY (object));
+
+        factory = GDM_REMOTE_DISPLAY_FACTORY (object);
+
+        g_return_if_fail (factory != NULL);
+
+        g_clear_object (&factory->connection);
+        g_clear_object (&factory->skeleton);
+
+        G_OBJECT_CLASS (gdm_remote_display_factory_parent_class)->finalize (object);
+}
+
+static GObject *
+gdm_remote_display_factory_constructor (GType                  type,
+                                        guint                  n_construct_properties,
+                                        GObjectConstructParam *construct_properties)
+{
+        GdmRemoteDisplayFactory *factory;
+        gboolean                 res;
+
+        factory = GDM_REMOTE_DISPLAY_FACTORY (G_OBJECT_CLASS (gdm_remote_display_factory_parent_class)->constructor (type,
+                                                                                                                     n_construct_properties,
+                                                                                                                     construct_properties));
+
+        res = register_factory (factory);
+        if (!res) {
+                g_warning ("Unable to register remote display factory with system bus");
+        }
+
+        return G_OBJECT (factory);
+}
+
+static gboolean
+gdm_remote_display_factory_start (GdmDisplayFactory *base_factory)
+{
+        GdmRemoteDisplayFactory *factory = GDM_REMOTE_DISPLAY_FACTORY (base_factory);
+        g_return_val_if_fail (GDM_IS_REMOTE_DISPLAY_FACTORY (factory), FALSE);
+        return TRUE;
+}
+
+static gboolean
+gdm_remote_display_factory_stop (GdmDisplayFactory *base_factory)
+{
+        GdmRemoteDisplayFactory *factory = GDM_REMOTE_DISPLAY_FACTORY (base_factory);
+        g_return_val_if_fail (GDM_IS_REMOTE_DISPLAY_FACTORY (factory), FALSE);
+        return TRUE;
+}
+
+static void
+gdm_remote_display_factory_class_init (GdmRemoteDisplayFactoryClass *klass)
+{
+        GObjectClass *object_class = G_OBJECT_CLASS (klass);
+        GdmDisplayFactoryClass *factory_class = GDM_DISPLAY_FACTORY_CLASS (klass);
+
+        object_class->finalize = gdm_remote_display_factory_finalize;
+        object_class->constructor = gdm_remote_display_factory_constructor;
+
+        factory_class->start = gdm_remote_display_factory_start;
+        factory_class->stop = gdm_remote_display_factory_stop;
+}
+
+static void
+gdm_remote_display_factory_init (GdmRemoteDisplayFactory *factory)
+{
+}
+
+GdmRemoteDisplayFactory *
+gdm_remote_display_factory_new (GdmDisplayStore *store)
+{
+        if (remote_display_factory_object != NULL) {
+                g_object_ref (remote_display_factory_object);
+        } else {
+                remote_display_factory_object = g_object_new (GDM_TYPE_REMOTE_DISPLAY_FACTORY,
+                                                              "display-store", store,
+                                                              NULL);
+                g_object_add_weak_pointer (remote_display_factory_object,
+                                           (gpointer *) &remote_display_factory_object);
+        }
+
+        return GDM_REMOTE_DISPLAY_FACTORY (remote_display_factory_object);
+}
diff --git a/daemon/gdm-remote-display-factory.h b/daemon/gdm-remote-display-factory.h
new file mode 100644
index 000000000..99defbad6
--- /dev/null
+++ b/daemon/gdm-remote-display-factory.h
@@ -0,0 +1,39 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2022 Joan Torres <joan.torres@suse.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * 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.
+ *
+ */
+
+
+#ifndef __GDM_REMOTE_DISPLAY_FACTORY_H
+#define __GDM_REMOTE_DISPLAY_FACTORY_H
+
+#include <glib-object.h>
+
+#include "gdm-display-factory.h"
+#include "gdm-display-store.h"
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_REMOTE_DISPLAY_FACTORY (gdm_remote_display_factory_get_type ())
+G_DECLARE_FINAL_TYPE (GdmRemoteDisplayFactory, gdm_remote_display_factory, GDM, REMOTE_DISPLAY_FACTORY, GdmDisplayFactory)
+
+GdmRemoteDisplayFactory *    gdm_remote_display_factory_new                      (GdmDisplayStore         *display_store);
+
+G_END_DECLS
+
+#endif /* __GDM_REMOTE_DISPLAY_FACTORY_H */
diff --git a/daemon/gdm-remote-display-factory.xml b/daemon/gdm-remote-display-factory.xml
new file mode 100644
index 000000000..84ce4770d
--- /dev/null
+++ b/daemon/gdm-remote-display-factory.xml
@@ -0,0 +1,8 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node name="/org/gnome/DisplayManager/RemoteDisplayFactory">
+  <interface name="org.gnome.DisplayManager.RemoteDisplayFactory">
+    <method name="CreateRemoteDisplay">
+      <arg name="remote_id" direction="in" type="o"/>
+    </method>
+  </interface>
+</node>
diff --git a/daemon/meson.build b/daemon/meson.build
index 3842aff38..90e837441 100644
--- a/daemon/meson.build
+++ b/daemon/meson.build
@@ -29,6 +29,12 @@ remote_display_dbus_gen = gnome.gdbus_codegen('gdm-remote-display-glue',
   interface_prefix: 'org.gnome.DisplayManager',
   autocleanup: 'all',
 )
+remote_display_factory_dbus_gen = gnome.gdbus_codegen('gdm-remote-display-factory-glue',
+  'gdm-remote-display-factory.xml',
+  namespace: 'GdmDBus',
+  interface_prefix: 'org.gnome.DisplayManager',
+  autocleanup: 'all',
+)
 manager_dbus_gen = gnome.gdbus_codegen('gdm-manager-glue',
   'gdm-manager.xml',
   namespace: 'GdmDBus',
@@ -179,6 +185,7 @@ gdm_daemon_sources = files(
   'gdm-local-display-factory.c',
   'gdm-local-display.c',
   'gdm-remote-display.c',
+  'gdm-remote-display-factory.c',
   'gdm-manager.c',
   'gdm-server.c',
   'gdm-session-record.c',
@@ -194,6 +201,7 @@ gdm_daemon_gen_sources = [
   manager_dbus_gen,
   local_display_dbus_gen,
   remote_display_dbus_gen,
+  remote_display_factory_dbus_gen,
   session_dbus_gen,
   session_worker_dbus_gen,
   gdm_session_enums,
diff --git a/data/gdm.conf.in b/data/gdm.conf.in
index 3b9148fc8..cbaa356d9 100644
--- a/data/gdm.conf.in
+++ b/data/gdm.conf.in
@@ -15,6 +15,8 @@
            send_interface="org.gnome.DisplayManager.RemoteDisplay"/>
     <allow send_destination="org.gnome.DisplayManager"
            send_interface="org.gnome.DisplayManager.LocalDisplayFactory"/>
+    <allow send_destination="org.gnome.DisplayManager"
+           send_interface="org.gnome.DisplayManager.RemoteDisplayFactory"/>
     <allow send_destination="org.gnome.DisplayManager"
            send_interface="org.gnome.DisplayManager.Settings"/>
     <allow send_destination="org.gnome.DisplayManager"
@@ -24,6 +26,11 @@
 
   </policy>
 
+  <policy user="gnome-remote-desktop">
+    <allow send_destination="org.gnome.DisplayManager"
+           send_interface="org.gnome.DisplayManager.RemoteDisplayFactory"/>
+  </policy>
+
   <policy context="default">
     <deny send_destination="org.gnome.DisplayManager"
           send_interface="org.gnome.DisplayManager.Display"/>
@@ -31,6 +38,8 @@
           send_interface="org.gnome.DisplayManager.RemoteDisplay"/>
     <deny send_destination="org.gnome.DisplayManager"
           send_interface="org.gnome.DisplayManager.LocalDisplayFactory"/>
+    <deny send_destination="org.gnome.DisplayManager"
+          send_interface="org.gnome.DisplayManager.RemoteDisplayFactory"/>
     <deny send_destination="org.gnome.DisplayManager"
           send_interface="org.gnome.DisplayManager.Settings"/>
     <deny send_destination="org.gnome.DisplayManager"
@@ -76,6 +85,8 @@
            send_interface="org.gnome.DisplayManager.RemoteDisplay"/>
     <allow send_destination="org.gnome.DisplayManager"
            send_interface="org.gnome.DisplayManager.LocalDisplayFactory"/>
+    <allow send_destination="org.gnome.DisplayManager"
+           send_interface="org.gnome.DisplayManager.RemoteDisplayFactory"/>
     <allow send_destination="org.gnome.DisplayManager"
            send_interface="org.gnome.DisplayManager.Settings"/>
     <allow send_destination="org.gnome.DisplayManager"
diff --git a/data/meson.build b/data/meson.build
index 164183f13..2cfe46918 100644
--- a/data/meson.build
+++ b/data/meson.build
@@ -28,7 +28,7 @@ configure_file(
   input: 'gdm.conf.in',
   output: '@BASENAME@',
   configuration: {
-    'GDM_USERNAME': get_option('user')
+    'GDM_USERNAME': get_option('user'),
   },
   install_dir: dbus_sys_dir,
 )
-- 
GitLab


From 6f44a2eab9634a29745e6311a2c49a13c8014164 Mon Sep 17 00:00:00 2001
From: Joan Torres <joan.torres@suse.com>
Date: Wed, 13 Jul 2022 17:46:44 +0200
Subject: [PATCH 7/9] manager: Add a remote display factory

Manager has a new display factory to create remote displays.

To enable it, it uses the RemoteLoginEnable key from gdm settings.

Also, when a session is opened and the display is remote-display, it will
be emitted the SessionOpened signal on its interface.
---
 daemon/gdm-display.c |  1 +
 daemon/gdm-manager.c | 55 ++++++++++++++++++++++++++++++++++++++++++--
 daemon/gdm-manager.h |  2 ++
 daemon/main.c        |  5 ++++
 4 files changed, 61 insertions(+), 2 deletions(-)

diff --git a/daemon/gdm-display.c b/daemon/gdm-display.c
index eb450a692..a8f6c14cb 100644
--- a/daemon/gdm-display.c
+++ b/daemon/gdm-display.c
@@ -42,6 +42,7 @@
 #include "gdm-display-glue.h"
 #include "gdm-display-access-file.h"
 #include "gdm-launch-environment.h"
+#include "gdm-remote-display.h"
 
 #include "gdm-settings-direct.h"
 #include "gdm-settings-keys.h"
diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index 22ae1195b..ec07303e1 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -48,6 +48,8 @@
 #include "gdm-launch-environment.h"
 #include "gdm-local-display.h"
 #include "gdm-local-display-factory.h"
+#include "gdm-remote-display.h"
+#include "gdm-remote-display-factory.h"
 #include "gdm-session.h"
 #include "gdm-session-record.h"
 #include "gdm-settings-direct.h"
@@ -78,11 +80,13 @@ struct _GdmManager
 #ifdef HAVE_LIBXDMCP
         GdmXdmcpDisplayFactory *xdmcp_factory;
 #endif
+        GdmRemoteDisplayFactory *remote_factory;
         GdmDisplay             *automatic_login_display;
         GList                  *user_sessions;
         GHashTable             *transient_sessions;
         GHashTable             *open_reauthentication_requests;
         gboolean                xdmcp_enabled;
+        gboolean                remote_login_enabled;
 
         gboolean                started;
         gboolean                show_local_greeter;
@@ -99,7 +103,8 @@ struct _GdmManager
 enum {
         PROP_0,
         PROP_XDMCP_ENABLED,
-        PROP_SHOW_LOCAL_GREETER
+        PROP_SHOW_LOCAL_GREETER,
+        PROP_REMOTE_LOGIN_ENABLED
 };
 
 enum {
@@ -2502,8 +2507,19 @@ gdm_manager_start (GdmManager *manager)
                 gdm_display_factory_start (GDM_DISPLAY_FACTORY (manager->local_factory));
         }
 
-#ifdef HAVE_LIBXDMCP
         /* Accept remote connections */
+        if (manager->remote_login_enabled) {
+#ifdef WITH_PLYMOUTH
+                /* Quit plymouth if remote is the only display */
+                if (!manager->show_local_greeter && manager->plymouth_is_running) {
+                        plymouth_quit_without_transition ();
+                        manager->plymouth_is_running = FALSE;
+                }
+#endif
+        }
+
+#ifdef HAVE_LIBXDMCP
+        /* Accept xdmcp connections */
         if (manager->xdmcp_enabled) {
 #ifdef WITH_PLYMOUTH
                 /* Quit plymouth if xdmcp is the only display */
@@ -2592,6 +2608,22 @@ gdm_manager_set_show_local_greeter (GdmManager *manager,
         manager->show_local_greeter = show_local_greeter;
 }
 
+void
+gdm_manager_set_remote_login_enabled (GdmManager *manager,
+                                      gboolean    enabled)
+{
+        g_return_if_fail (GDM_IS_MANAGER (manager));
+
+        if (manager->remote_login_enabled != enabled) {
+                manager->remote_login_enabled = enabled;
+                if (manager->remote_login_enabled) {
+                        manager->remote_factory = gdm_remote_display_factory_new (manager->display_store);
+                } else {
+                        g_clear_object (&manager->remote_factory);
+                }
+        }
+}
+
 static void
 gdm_manager_set_property (GObject      *object,
                           guint         prop_id,
@@ -2609,6 +2641,9 @@ gdm_manager_set_property (GObject      *object,
         case PROP_SHOW_LOCAL_GREETER:
                 gdm_manager_set_show_local_greeter (self, g_value_get_boolean (value));
                 break;
+        case PROP_REMOTE_LOGIN_ENABLED:
+                gdm_manager_set_remote_login_enabled (self, g_value_get_boolean (value));
+                break;
         default:
                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                 break;
@@ -2632,6 +2667,9 @@ gdm_manager_get_property (GObject    *object,
         case PROP_SHOW_LOCAL_GREETER:
                 g_value_set_boolean (value, self->show_local_greeter);
                 break;
+        case PROP_REMOTE_LOGIN_ENABLED:
+                g_value_set_boolean (value, self->remote_login_enabled);
+                break;
         default:
                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                 break;
@@ -2653,6 +2691,10 @@ gdm_manager_constructor (GType                  type,
 
         manager->local_factory = gdm_local_display_factory_new (manager->display_store);
 
+        if (manager->remote_login_enabled) {
+                manager->remote_factory = gdm_remote_display_factory_new (manager->display_store);
+        }
+
 #ifdef HAVE_LIBXDMCP
         if (manager->xdmcp_enabled) {
                 manager->xdmcp_factory = gdm_xdmcp_display_factory_new (manager->display_store);
@@ -2700,6 +2742,14 @@ gdm_manager_class_init (GdmManagerClass *klass)
                                                                NULL,
                                                                FALSE,
                                                                G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+        g_object_class_install_property (object_class,
+                                         PROP_REMOTE_LOGIN_ENABLED,
+                                         g_param_spec_boolean ("remote-login-enabled",
+                                                               NULL,
+                                                               NULL,
+                                                               FALSE,
+                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
 }
 
 static void
@@ -2770,6 +2820,7 @@ gdm_manager_dispose (GObject *object)
         g_clear_object (&manager->xdmcp_factory);
 #endif
         g_clear_object (&manager->local_factory);
+        g_clear_object (&manager->remote_factory);
         g_clear_pointer (&manager->open_reauthentication_requests,
                          g_hash_table_unref);
         g_clear_pointer (&manager->transient_sessions,
diff --git a/daemon/gdm-manager.h b/daemon/gdm-manager.h
index cc06197d7..ad736df77 100644
--- a/daemon/gdm-manager.h
+++ b/daemon/gdm-manager.h
@@ -49,6 +49,8 @@ void                gdm_manager_set_xdmcp_enabled              (GdmManager *mana
                                                                 gboolean    enabled);
 void                gdm_manager_set_show_local_greeter         (GdmManager *manager,
                                                                 gboolean    show_local_greeter);
+void                gdm_manager_set_remote_login_enabled       (GdmManager *manager,
+                                                                gboolean    enabled);
 gboolean            gdm_manager_get_displays                   (GdmManager *manager,
                                                                 GPtrArray **displays,
                                                                 GError    **error);
diff --git a/daemon/main.c b/daemon/main.c
index 539b853f6..673a03103 100644
--- a/daemon/main.c
+++ b/daemon/main.c
@@ -406,6 +406,7 @@ on_name_acquired (GDBusConnection *bus,
 {
         gboolean xdmcp_enabled;
         gboolean show_local_greeter;
+        gboolean remote_login_enabled;
 
         manager = gdm_manager_new ();
         if (manager == NULL) {
@@ -423,6 +424,10 @@ on_name_acquired (GDBusConnection *bus,
         gdm_settings_direct_get_boolean (GDM_KEY_XDMCP_ENABLE, &xdmcp_enabled);
         gdm_manager_set_xdmcp_enabled (manager, xdmcp_enabled);
 
+        remote_login_enabled = FALSE;
+        gdm_settings_direct_get_boolean (GDM_KEY_REMOTE_LOGIN_ENABLE, &remote_login_enabled);
+        gdm_manager_set_remote_login_enabled (manager, remote_login_enabled);
+
         gdm_manager_start (manager);
 }
 
-- 
GitLab


From f9f706967533c4c255a09866c27bd308d98958c7 Mon Sep 17 00:00:00 2001
From: Joan Torres <joan.torres@suse.com>
Date: Thu, 10 Nov 2022 17:13:43 +0100
Subject: [PATCH 8/9] sessions: Filter out non-headless capable sessions from
 headless environments

Now that GDM can start a headless login screen for remote access, we
need to make the login screen only lets the user select sessions that
don't require a local seat.

This commit checks a new property in the session definition,
X-GDM-CanRunHeadless to filter out non-capabable sessions.
---
 daemon/gdm-session.c  | 20 +++++++++++++++
 libgdm/gdm-sessions.c | 60 +++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 78 insertions(+), 2 deletions(-)

diff --git a/daemon/gdm-session.c b/daemon/gdm-session.c
index be19a049c..e4e5d1d08 100644
--- a/daemon/gdm-session.c
+++ b/daemon/gdm-session.c
@@ -458,6 +458,13 @@ load_key_file_for_file (GdmSession   *self,
         return key_file;
 }
 
+static gboolean
+is_wayland_headless (GdmSession *self)
+{
+        return g_strcmp0 (self->session_type, "wayland") == 0 &&
+                          !self->display_is_local;
+}
+
 static gboolean
 get_session_command_for_file (GdmSession  *self,
                               const char  *file,
@@ -498,6 +505,19 @@ get_session_command_for_file (GdmSession  *self,
                 goto out;
         }
 
+        if (is_wayland_headless (self)) {
+                gboolean can_run_headless;
+
+                can_run_headless = g_key_file_get_boolean (key_file,
+                                                           G_KEY_FILE_DESKTOP_GROUP,
+                                                           "X-GDM-CanRunHeadless",
+                                                           NULL);
+                if (!can_run_headless && is_wayland_headless (self)) {
+                        g_debug ("GdmSession: Session %s is not headless capable", file);
+                        goto out;
+                }
+        }
+
         exec = g_key_file_get_string (key_file,
                                       G_KEY_FILE_DESKTOP_GROUP,
                                       G_KEY_FILE_DESKTOP_KEY_TRY_EXEC,
diff --git a/libgdm/gdm-sessions.c b/libgdm/gdm-sessions.c
index c3aeafddf..b0258d84d 100644
--- a/libgdm/gdm-sessions.c
+++ b/libgdm/gdm-sessions.c
@@ -35,6 +35,8 @@
 #include <glib/gi18n.h>
 #include <glib/gstdio.h>
 
+#include <systemd/sd-login.h>
+
 #include "gdm-sessions.h"
 
 typedef struct _GdmSessionFile {
@@ -58,14 +60,59 @@ gdm_session_file_free (GdmSessionFile *session)
   g_free (session);
 }
 
+static char *
+get_systemd_session (void)
+{
+        int ret;
+        g_autofree char *systemd_unit = NULL;
+        g_autofree char *session_id = NULL;
+        pid_t pid;
+        uid_t uid;
+
+        pid = getpid ();
+        uid = getuid ();
+
+        ret = sd_pid_get_user_unit (pid, &systemd_unit);
+
+        if (ret == 0)
+                ret = sd_uid_get_display (uid, &session_id);
+        else
+                ret = sd_pid_get_session (pid, &session_id);
+
+        return g_steal_pointer (&session_id);
+}
+
+static char *
+get_systemd_seat (void)
+{
+        g_autofree char *session_id = NULL;
+        g_autofree char *seat = NULL;
+        int ret;
+
+        session_id = get_systemd_session ();
+
+        if (session_id == NULL)
+                return NULL;
+
+        ret = sd_session_get_seat (session_id, &seat);
+
+        if (ret != 0)
+                return NULL;
+
+        return g_steal_pointer (&seat);
+}
+
 /* adapted from gnome-menus desktop-entries.c */
 static gboolean
 key_file_is_relevant (GKeyFile     *key_file)
 {
         GError    *error;
+        g_autofree char *seat = NULL;
         gboolean   no_display;
         gboolean   hidden;
         gboolean   tryexec_failed;
+        gboolean   can_run_headless;
+        gboolean   only_headless_allowed;
         char      *tryexec;
 
         error = NULL;
@@ -88,6 +135,15 @@ key_file_is_relevant (GKeyFile     *key_file)
                 g_error_free (error);
         }
 
+        seat = get_systemd_seat ();
+
+        only_headless_allowed = seat == NULL;
+
+        can_run_headless = g_key_file_get_boolean (key_file,
+                                                   G_KEY_FILE_DESKTOP_GROUP,
+                                                   "X-GDM-CanRunHeadless",
+                                                   NULL);
+
         tryexec_failed = FALSE;
         tryexec = g_key_file_get_string (key_file,
                                          G_KEY_FILE_DESKTOP_GROUP,
@@ -104,7 +160,7 @@ key_file_is_relevant (GKeyFile     *key_file)
                 g_free (tryexec);
         }
 
-        if (no_display || hidden || tryexec_failed) {
+        if (no_display || hidden || tryexec_failed || (only_headless_allowed && !can_run_headless)) {
                 return FALSE;
         }
 
@@ -142,7 +198,7 @@ load_session_file (const char              *id,
         }
 
         if (!key_file_is_relevant (key_file)) {
-                g_debug ("\"%s\" is hidden or contains non-executable TryExec program\n", path);
+                g_debug ("\"%s\" is hidden, contains non-executable TryExec program, or is otherwise not capable of being used\n", path);
                 g_hash_table_remove (gdm_available_sessions_map, id);
                 goto out;
         }
-- 
GitLab


From 0541d62d1f3ee4f75d77a3e15092d22af4dee1ed Mon Sep 17 00:00:00 2001
From: Joan Torres <joan.torres@suse.com>
Date: Fri, 1 Sep 2023 19:10:12 +0200
Subject: [PATCH 9/9] manager: Create remote displays for user sessions started
 from remote login screens

If a login screen is running on a remote display, the session that gets
started from that login screen should have a remote display associated
with it as well, instead of a local display object.

Furthermore, the two remote displays should have a comment remote_id so
there's a clear trail from one to the other.

This commit does that.
---
 daemon/gdm-manager.c        | 26 +++++++++++++++++++++++---
 daemon/gdm-remote-display.c | 14 ++++++++++++++
 daemon/gdm-remote-display.h |  2 ++
 daemon/gdm-session.c        | 25 +++++++++++++++++++++++++
 4 files changed, 64 insertions(+), 3 deletions(-)

diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c
index ec07303e1..5e85ae467 100644
--- a/daemon/gdm-manager.c
+++ b/daemon/gdm-manager.c
@@ -1638,10 +1638,24 @@ create_display_for_user_session (GdmManager *self,
                                  GdmSession *session,
                                  const char *session_id)
 {
-        GdmDisplay *display;
+        GdmDisplay *display = NULL;
         const char *seat_id = gdm_session_get_display_seat_id (session);
+        gboolean display_is_local;
+
+        g_object_get (G_OBJECT (session), "display-is-local", &display_is_local, NULL);
+
+        if (!display_is_local) {
+                g_autofree char *remote_id = NULL;
+
+                g_object_get (G_OBJECT (session),
+                              "remote-id", &remote_id,
+                              NULL);
+
+                display = gdm_remote_display_new (remote_id);
+        }
 
-        display = gdm_local_display_new ();
+        if (display == NULL)
+                display = gdm_local_display_new ();
 
         g_object_set (G_OBJECT (display),
                       "session-class", "user",
@@ -1861,7 +1875,6 @@ on_start_user_session (StartUserSessionOperation *operation)
                                                  operation->session,
                                                  session_id);
 
-
                 if (g_strcmp0 (operation->service_name, "gdm-autologin") == 0 &&
 	            !gdm_session_client_is_connected (operation->session)) {
                         /* remove the unused prepared greeter display since we're not going
@@ -2326,6 +2339,13 @@ create_user_session_for_display (GdmManager *manager,
                                    display_auth_file,
                                    display_is_local,
                                    NULL);
+
+        if (GDM_IS_REMOTE_DISPLAY (display)) {
+                g_autofree char *remote_id = gdm_remote_display_get_remote_id (GDM_REMOTE_DISPLAY (display));
+
+                g_object_set (G_OBJECT (session), "remote-id", remote_id, NULL);
+        }
+
         g_object_set (G_OBJECT (session),
                       "supported-session-types", supported_session_types,
                       NULL);
diff --git a/daemon/gdm-remote-display.c b/daemon/gdm-remote-display.c
index 9b7c8a8db..6074eddcd 100644
--- a/daemon/gdm-remote-display.c
+++ b/daemon/gdm-remote-display.c
@@ -39,6 +39,20 @@ static void     gdm_remote_display_init         (GdmRemoteDisplay      *remote_d
 
 G_DEFINE_TYPE (GdmRemoteDisplay, gdm_remote_display, GDM_TYPE_DISPLAY)
 
+char *
+gdm_remote_display_get_remote_id (GdmRemoteDisplay *display)
+{
+        g_autofree char *remote_id = NULL;
+
+        g_return_val_if_fail (GDM_IS_REMOTE_DISPLAY (display), NULL);
+
+        g_object_get (G_OBJECT (display->skeleton),
+                      "remote-id", &remote_id,
+                      NULL);
+
+        return g_steal_pointer (&remote_id);
+}
+
 static GObject *
 gdm_remote_display_constructor (GType                  type,
                                 guint                  n_construct_properties,
diff --git a/daemon/gdm-remote-display.h b/daemon/gdm-remote-display.h
index 2d2c0eb42..bbe962705 100644
--- a/daemon/gdm-remote-display.h
+++ b/daemon/gdm-remote-display.h
@@ -34,6 +34,8 @@ G_DECLARE_FINAL_TYPE (GdmRemoteDisplay, gdm_remote_display, GDM, REMOTE_DISPLAY,
 
 GdmDisplay *        gdm_remote_display_new                     (const char *remote_id);
 
+char *              gdm_remote_display_get_remote_id           (GdmRemoteDisplay *self);
+
 G_END_DECLS
 
 #endif /* __GDM_REMOTE_DISPLAY_H */
diff --git a/daemon/gdm-session.c b/daemon/gdm-session.c
index e4e5d1d08..85dea36be 100644
--- a/daemon/gdm-session.c
+++ b/daemon/gdm-session.c
@@ -135,6 +135,8 @@ struct _GdmSession
 
         GStrv                supported_session_types;
 
+        char                *remote_id;
+
         guint32              is_program_session : 1;
         guint32              display_is_initial : 1;
 };
@@ -154,6 +156,7 @@ enum {
         PROP_USER_X11_AUTHORITY_FILE,
         PROP_CONVERSATION_ENVIRONMENT,
         PROP_SUPPORTED_SESSION_TYPES,
+        PROP_REMOTE_ID,
 };
 
 enum {
@@ -3612,6 +3615,14 @@ set_session_type (GdmSession *self,
         }
 }
 
+static void
+set_remote_id (GdmSession *self,
+               const char *remote_id)
+{
+        g_free (self->remote_id);
+        self->remote_id = g_strdup (remote_id);
+}
+
 static void
 gdm_session_set_property (GObject      *object,
                           guint         prop_id,
@@ -3662,6 +3673,9 @@ gdm_session_set_property (GObject      *object,
         case PROP_SUPPORTED_SESSION_TYPES:
                 gdm_session_set_supported_session_types (self, g_value_get_boxed (value));
                 break;
+        case PROP_REMOTE_ID:
+                set_remote_id (self, g_value_get_string (value));
+                break;
         default:
                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                 break;
@@ -3718,6 +3732,9 @@ gdm_session_get_property (GObject    *object,
         case PROP_SUPPORTED_SESSION_TYPES:
                 g_value_set_boxed (value, self->supported_session_types);
                 break;
+        case PROP_REMOTE_ID:
+                g_value_set_string (value, self->remote_id);
+                break;
         default:
                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                 break;
@@ -4159,6 +4176,14 @@ gdm_session_class_init (GdmSessionClass *session_class)
                                                              G_TYPE_STRV,
                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
 
+        g_object_class_install_property (object_class,
+                                         PROP_REMOTE_ID,
+                                         g_param_spec_string ("remote-id",
+                                                              "remote id",
+                                                              "remote id",
+                                                              NULL,
+                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
         /* Ensure we can resolve errors */
         gdm_dbus_error_ensure (GDM_SESSION_WORKER_ERROR);
 }
