sd-login: add SetTTY session object #26611

This commit is contained in:
Thorsten Kukuk 2023-04-19 16:11:55 +02:00 committed by Lennart Poettering
parent 4d26b2277a
commit 092e6cd19a
6 changed files with 106 additions and 0 deletions

View 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

View 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),

View 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;

View 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);

View File

@ -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>

View 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;