]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-login: add SetTTY session object #26611
authorThorsten Kukuk <kukuk@suse.com>
Wed, 19 Apr 2023 14:11:55 +0000 (16:11 +0200)
committerLennart Poettering <lennart@poettering.net>
Tue, 25 Apr 2023 12:33:09 +0000 (14:33 +0200)
man/org.freedesktop.login1.xml
src/login/logind-session-dbus.c
src/login/logind-session.c
src/login/logind-session.h
src/login/org.freedesktop.login1.conf
src/login/test-session-properties.c

index 6781e1dcaaec50e59a5e8615d6a9a869a20e8c30..034fd1078fb894242468be0b808f9ce5344e4d1d 100644 (file)
@@ -1083,6 +1083,7 @@ node /org/freedesktop/login1/session/1 {
       ReleaseControl();
       SetType(in  s type);
       SetDisplay(in  s display);
+      SetTTY(in  h tty_fd);
       TakeDevice(in  u major,
                  in  u minor,
                  out h fd,
@@ -1182,6 +1183,8 @@ node /org/freedesktop/login1/session/1 {
 
     <variablelist class="dbus-method" generated="True" extra-ref="SetDisplay()"/>
 
+    <variablelist class="dbus-method" generated="True" extra-ref="SetTTY()"/>
+
     <variablelist class="dbus-method" generated="True" extra-ref="TakeDevice()"/>
 
     <variablelist class="dbus-method" generated="True" extra-ref="ReleaseDevice()"/>
@@ -1283,6 +1286,11 @@ node /org/freedesktop/login1/session/1 {
       controller. If <function>TakeControl()</function> has not been called, this method will fail. The only argument
       <varname>display</varname> is the new display name.</para>
 
+      <para><function>SetTTY()</function> allows the device name of the session to be changed. This is
+      useful if the tty device is only known after authentication. It can only be called by session's
+      current controller. If <function>TakeControl()</function> has not been called, this method will fail.
+      The only argument <varname>tty_fd</varname> is a file handle to the new tty device.</para>
+
       <para><function>TakeDevice()</function> allows a session controller to get a file descriptor for a
       specific device. Pass in the major and minor numbers of the character device and
       <filename>systemd-logind</filename> will return a file descriptor for the device. Only a limited set of
index e3bebc9188be9d5e818149f51b78a5d6f39583de..00a0e8fd5896d63d127a19651ba652eba96f2e56 100644 (file)
@@ -23,6 +23,7 @@
 #include "path-util.h"
 #include "signal-util.h"
 #include "strv.h"
+#include "terminal-util.h"
 #include "user-util.h"
 
 static int property_get_user(
@@ -421,6 +422,41 @@ static int method_set_display(sd_bus_message *message, void *userdata, sd_bus_er
         return sd_bus_reply_method_return(message, NULL);
 }
 
+static int method_set_tty(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        Session *s = ASSERT_PTR(userdata);
+        int fd, r, flags;
+        _cleanup_free_ char *q = NULL;
+
+        assert(message);
+
+        r = sd_bus_message_read(message, "h", &fd);
+        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 tty");
+
+        assert(fd >= 0);
+
+        flags = fcntl(fd, F_GETFL, 0);
+        if (flags < 0)
+                return -errno;
+        if ((flags & O_ACCMODE) != O_RDWR)
+                return -EACCES;
+        if (FLAGS_SET(flags, O_PATH))
+                return -ENOTTY;
+
+        r = getttyname_malloc(fd, &q);
+        if (r < 0)
+                return r;
+
+        r = session_set_tty(s, q);
+        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 = ASSERT_PTR(userdata);
         uint32_t major, minor;
@@ -909,6 +945,11 @@ static const sd_bus_vtable session_vtable[] = {
                                 SD_BUS_NO_RESULT,
                                 method_set_display,
                                 SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("SetTTY",
+                                SD_BUS_ARGS("h", tty_fd),
+                                SD_BUS_NO_RESULT,
+                                method_set_tty,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD_WITH_ARGS("TakeDevice",
                                 SD_BUS_ARGS("u", major, "u", minor),
                                 SD_BUS_RESULT("h", fd, "b", inactive),
index e7c917cdeef4e9b231831063aa0d7d483f831b30..92d588b2764730d8a0318be3acc9eb403dccd8bf 100644 (file)
@@ -1132,6 +1132,23 @@ int session_set_display(Session *s, const char *display) {
         return 1;
 }
 
+int session_set_tty(Session *s, const char *tty) {
+        int r;
+
+        assert(s);
+        assert(tty);
+
+        r = free_and_strdup(&s->tty, tty);
+        if (r <= 0)  /* 0 means the strings were equal */
+                return r;
+
+        session_save(s);
+
+        session_send_changed(s, "TTY", NULL);
+
+        return 1;
+}
+
 static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
         Session *s = ASSERT_PTR(userdata);
 
@@ -1349,6 +1366,9 @@ error:
 static void session_restore_vt(Session *s) {
         int r;
 
+        if (s->vtfd < 0)
+                return;
+
         r = vt_restore(s->vtfd);
         if (r == -EIO) {
                 int vt, old_fd;
index 4c286079866a78ef7ed1ceca3f500a69db946ad8..bf45301705ac13c435cae09e4ae56f55f7ad365b 100644 (file)
@@ -140,6 +140,7 @@ int session_get_locked_hint(Session *s);
 void session_set_locked_hint(Session *s, bool b);
 void session_set_type(Session *s, SessionType t);
 int session_set_display(Session *s, const char *display);
+int session_set_tty(Session *s, const char *tty);
 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);
index bf905e3b0f9771ae9e25e77b397f24cb859a1a30..8ba094bcff18ce8e505b740582464c27ebeb9c32 100644 (file)
                        send_interface="org.freedesktop.login1.Session"
                        send_member="SetDisplay"/>
 
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Session"
+                       send_member="SetTTY"/>
+
                 <allow receive_sender="org.freedesktop.login1"/>
         </policy>
 
index 44d54811c3e75e78cc8e784608370a2e9d3c948f..0bfde422138ce42b24684d66edbeebf9b43dd76e 100644 (file)
@@ -6,10 +6,16 @@
  * ./test-session-properties /org/freedesktop/login1/session/_32
  */
 
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
 #include "alloc-util.h"
 #include "bus-common-errors.h"
 #include "bus-locator.h"
+#include "path-util.h"
 #include "string-util.h"
+#include "terminal-util.h"
 #include "tests.h"
 
 static BusLocator session;
@@ -94,6 +100,32 @@ TEST(set_display) {
         assert_se(isempty(display));
 }
 
+/* Tests org.freedesktop.logind.Session SetTTY */
+TEST(set_tty) {
+        _cleanup_(sd_bus_flush_close_unrefp) sd_bus* bus = NULL;
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_free_ char *tty = NULL;
+        const char *path = "/dev/tty2"; /* testsuite uses tty2 */
+        int fd;
+
+        fd = open(path, O_RDWR|O_CLOEXEC|O_NOCTTY);
+        assert_se(fd >= 0);
+
+        assert_se(sd_bus_open_system(&bus) >= 0);
+
+        /* tty can only be set by the session controller (which we're not ATM) */
+        assert_se(bus_call_method(bus, &session, "SetTTY", &error, NULL, "h", fd) < 0);
+        assert_se(sd_bus_error_has_name(&error, BUS_ERROR_NOT_IN_CONTROL));
+
+        assert_se(bus_call_method(bus, &session, "TakeControl", NULL, NULL, "b", true) >= 0);
+
+        /* tty can be set */
+        assert_se(bus_call_method(bus, &session, "SetTTY", NULL, NULL, "h", fd) >= 0);
+        tty = mfree(tty);
+        assert_se(bus_get_property_string(bus, &session, "TTY", NULL, &tty) >= 0);
+        assert_se(streq(tty, "tty2"));
+}
+
 static int intro(void) {
         if (saved_argc <= 1)
                 return EXIT_FAILURE;