From 54a8d932442d02f5a7dbf6038c8f557ce41f468b Mon Sep 17 00:00:00 2001
From: David Tardon <dtardon@redhat.com>
Date: Fri, 10 Jun 2022 15:07:01 +0200
Subject: [PATCH] logind-session-dbus: allow to set display name via dbus

Currently, the only way to set display name of a graphical session is to
pass it to CreateSession(). But modern display managers like gdm start
the display server as part of the user session, which means that the
display name isn't known yet when the session is being created. Hence,
let's make it possible to set it later.

(cherry picked from commit 4885d7490b23e08d8444e5a68927ce9ce8727e5a)

Resolves: #1857969
---
 src/login/logind-session-dbus.c       | 26 ++++++++++++++++++++++++++
 src/login/logind-session.c            | 20 ++++++++++++++++++++
 src/login/logind-session.h            |  1 +
 src/login/org.freedesktop.login1.conf |  4 ++++
 4 files changed, 51 insertions(+)

diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c
index 03585b7f8e..c935959e02 100644
--- a/src/login/logind-session-dbus.c
+++ b/src/login/logind-session-dbus.c
@@ -381,6 +381,31 @@ static int method_release_control(sd_bus_message *message, void *userdata, sd_bu
         return sd_bus_reply_method_return(message, NULL);
 }
 
+static int method_set_display(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        Session *s = userdata;
+        const char *display;
+        int r;
+
+        assert(message);
+        assert(s);
+
+        r = sd_bus_message_read(message, "s", &display);
+        if (r < 0)
+                return r;
+
+        if (!session_is_controller(s, sd_bus_message_get_sender(message)))
+                return sd_bus_error_set(error, BUS_ERROR_NOT_IN_CONTROL, "You must be in control of this session to set display");
+
+        if (!SESSION_TYPE_IS_GRAPHICAL(s->type))
+                return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Setting display is only supported for graphical sessions");
+
+        r = session_set_display(s, display);
+        if (r < 0)
+                return r;
+
+        return sd_bus_reply_method_return(message, NULL);
+}
+
 static int method_take_device(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Session *s = userdata;
         uint32_t major, minor;
@@ -523,6 +548,7 @@ const sd_bus_vtable session_vtable[] = {
         SD_BUS_METHOD("TakeDevice", "uu", "hb", method_take_device, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("ReleaseDevice", "uu", NULL, method_release_device, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("PauseDeviceComplete", "uu", NULL, method_pause_device_complete, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("SetDisplay", "s", NULL, method_set_display, SD_BUS_VTABLE_UNPRIVILEGED),
 
         SD_BUS_SIGNAL("PauseDevice", "uus", 0),
         SD_BUS_SIGNAL("ResumeDevice", "uuh", 0),
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
index e4c8bb36f6..1143a834a4 100644
--- a/src/login/logind-session.c
+++ b/src/login/logind-session.c
@@ -953,6 +953,26 @@ void session_set_locked_hint(Session *s, bool b) {
         session_send_changed(s, "LockedHint", NULL);
 }
 
+int session_set_display(Session *s, const char *display) {
+        int r;
+
+        assert(s);
+        assert(display);
+
+        if (streq(s->display, display))
+                return 0;
+
+        r = free_and_strdup(&s->display, display);
+        if (r < 0)
+                return r;
+
+        session_save(s);
+
+        session_send_changed(s, "Display", NULL);
+
+        return 1;
+}
+
 static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
         Session *s = userdata;
 
diff --git a/src/login/logind-session.h b/src/login/logind-session.h
index 7d17d9a25f..9bd0c96a03 100644
--- a/src/login/logind-session.h
+++ b/src/login/logind-session.h
@@ -123,6 +123,7 @@ int session_get_idle_hint(Session *s, dual_timestamp *t);
 void session_set_idle_hint(Session *s, bool b);
 int session_get_locked_hint(Session *s);
 void session_set_locked_hint(Session *s, bool b);
+int session_set_display(Session *s, const char *display);
 int session_create_fifo(Session *s);
 int session_start(Session *s, sd_bus_message *properties, sd_bus_error *error);
 int session_stop(Session *s, bool force);
diff --git a/src/login/org.freedesktop.login1.conf b/src/login/org.freedesktop.login1.conf
index dcde0c22c6..b780ae08cf 100644
--- a/src/login/org.freedesktop.login1.conf
+++ b/src/login/org.freedesktop.login1.conf
@@ -314,6 +314,10 @@
                        send_interface="org.freedesktop.login1.User"
                        send_member="Kill"/>
 
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Session"
+                       send_member="SetDisplay"/>
+
                 <allow receive_sender="org.freedesktop.login1"/>
         </policy>
 
