summaryrefslogtreecommitdiff
path: root/src/login
diff options
context:
space:
mode:
authorThorsten Kukuk <kukuk@suse.com>2023-04-19 16:11:55 +0200
committerLennart Poettering <lennart@poettering.net>2023-04-25 14:33:09 +0200
commit092e6cd19adf1ff6bc979034cbe287d92ca2efd7 (patch)
treefb8a9dd07a7cac3eca66d463962892d6f2640eac /src/login
parent4d26b2277a9a982b8c061d7da2300b266161b716 (diff)
downloadsystemd-092e6cd19adf1ff6bc979034cbe287d92ca2efd7.tar.gz
sd-login: add SetTTY session object #26611
Diffstat (limited to 'src/login')
-rw-r--r--src/login/logind-session-dbus.c41
-rw-r--r--src/login/logind-session.c20
-rw-r--r--src/login/logind-session.h1
-rw-r--r--src/login/org.freedesktop.login1.conf4
-rw-r--r--src/login/test-session-properties.c32
5 files changed, 98 insertions, 0 deletions
diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c
index e3bebc9188..00a0e8fd58 100644
--- a/src/login/logind-session-dbus.c
+++ b/src/login/logind-session-dbus.c
@@ -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),
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
index e7c917cdee..92d588b276 100644
--- a/src/login/logind-session.c
+++ b/src/login/logind-session.c
@@ -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;
diff --git a/src/login/logind-session.h b/src/login/logind-session.h
index 4c28607986..bf45301705 100644
--- a/src/login/logind-session.h
+++ b/src/login/logind-session.h
@@ -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);
diff --git a/src/login/org.freedesktop.login1.conf b/src/login/org.freedesktop.login1.conf
index bf905e3b0f..8ba094bcff 100644
--- a/src/login/org.freedesktop.login1.conf
+++ b/src/login/org.freedesktop.login1.conf
@@ -350,6 +350,10 @@
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>
diff --git a/src/login/test-session-properties.c b/src/login/test-session-properties.c
index 44d54811c3..0bfde42213 100644
--- a/src/login/test-session-properties.c
+++ b/src/login/test-session-properties.c
@@ -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;