Skip to content
This repository was archived by the owner on Nov 15, 2025. It is now read-only.

Commit 3b92c08

Browse files
committed
logind: make "self" and "auto" magic strings when operating on seats + sessions
Most of the operations one can do on sessions so far accepted an empty session name as a shortcut for the caller's session. This is quite useful traditionally, but much less useful than it used to be, since most user code now (rightfully) runs in --user context, not in a session. With this change we tweak the logic a bit: we introduce the two special session and seat names "self" and "auto". The former refers to the session/seat the client is in, and is hence mostly equivalent to te empty string "" as before. However, the latter refers to the session/seat the client is in if that exists, with a fallback of the user's display session if not. Clients can hence reference "auto" instead of the empty string if they really don't want to think much about sessions. Why "self" btw? Previously, we'd already expose a special dbus object with the path /org/freedesktop/login1/session/self (and similar for the seat), matching what the empty string did for bus calls that took a session name. With this scheme we reuse this identifier and introduce "auto" in a similar way. Of course this means real-life seats and sessions can never be named "self" or "auto", but they aren't anyway: valid seat names have to start with "seat" anyway, and sessions are generated server-side as either a numeric value or "c" suffixed with a counter ID. Fixes: systemd#12399
1 parent 469df51 commit 3b92c08

File tree

5 files changed

+179
-87
lines changed

5 files changed

+179
-87
lines changed

src/login/logind-dbus.c

Lines changed: 75 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -46,47 +46,78 @@
4646
#include "utmp-wtmp.h"
4747
#include "virt.h"
4848

49-
static int get_sender_session(Manager *m, sd_bus_message *message, sd_bus_error *error, Session **ret) {
49+
static int get_sender_session(
50+
Manager *m,
51+
sd_bus_message *message,
52+
bool consult_display,
53+
sd_bus_error *error,
54+
Session **ret) {
5055

5156
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
57+
Session *session = NULL;
5258
const char *name;
53-
Session *session;
5459
int r;
5560

56-
/* Get client login session. This is not what you are looking for these days,
57-
* as apps may instead belong to a user service unit. This includes terminal
58-
* emulators and hence command-line apps. */
59-
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds);
61+
/* Acquire the sender's session. This first checks if the sending process is inside a session itself,
62+
* and returns that. If not and 'consult_display' is true, this returns the display session of the
63+
* owning user of the caller. */
64+
65+
r = sd_bus_query_sender_creds(message,
66+
SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT|
67+
(consult_display ? SD_BUS_CREDS_OWNER_UID : 0), &creds);
6068
if (r < 0)
6169
return r;
6270

6371
r = sd_bus_creds_get_session(creds, &name);
64-
if (r == -ENXIO)
65-
goto err_no_session;
66-
if (r < 0)
67-
return r;
72+
if (r < 0) {
73+
if (r != -ENXIO)
74+
return r;
75+
76+
if (consult_display) {
77+
uid_t uid;
78+
79+
r = sd_bus_creds_get_owner_uid(creds, &uid);
80+
if (r < 0) {
81+
if (r != -ENXIO)
82+
return r;
83+
} else {
84+
User *user;
85+
86+
user = hashmap_get(m->users, UID_TO_PTR(uid));
87+
if (user)
88+
session = user->display;
89+
}
90+
}
91+
} else
92+
session = hashmap_get(m->sessions, name);
6893

69-
session = hashmap_get(m->sessions, name);
7094
if (!session)
71-
goto err_no_session;
95+
return sd_bus_error_setf(error, BUS_ERROR_NO_SESSION_FOR_PID,
96+
consult_display ?
97+
"Caller does not belong to any known session and doesn't own any suitable session." :
98+
"Caller does not belong to any known session.");
7299

73100
*ret = session;
74101
return 0;
75-
76-
err_no_session:
77-
return sd_bus_error_setf(error, BUS_ERROR_NO_SESSION_FOR_PID,
78-
"Caller does not belong to any known session");
79102
}
80103

81-
int manager_get_session_from_creds(Manager *m, sd_bus_message *message, const char *name, sd_bus_error *error, Session **ret) {
104+
int manager_get_session_from_creds(
105+
Manager *m,
106+
sd_bus_message *message,
107+
const char *name,
108+
sd_bus_error *error,
109+
Session **ret) {
110+
82111
Session *session;
83112

84113
assert(m);
85114
assert(message);
86115
assert(ret);
87116

88-
if (isempty(name))
89-
return get_sender_session(m, message, error, ret);
117+
if (SEAT_IS_SELF(name)) /* the caller's own session */
118+
return get_sender_session(m, message, false, error, ret);
119+
if (SEAT_IS_AUTO(name)) /* The caller's own session if they have one, otherwise their user's display session */
120+
return get_sender_session(m, message, true, error, ret);
90121

91122
session = hashmap_get(m->sessions, name);
92123
if (!session)
@@ -97,7 +128,6 @@ int manager_get_session_from_creds(Manager *m, sd_bus_message *message, const ch
97128
}
98129

99130
static int get_sender_user(Manager *m, sd_bus_message *message, sd_bus_error *error, User **ret) {
100-
101131
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
102132
uid_t uid;
103133
User *user;
@@ -109,21 +139,20 @@ static int get_sender_user(Manager *m, sd_bus_message *message, sd_bus_error *er
109139
return r;
110140

111141
r = sd_bus_creds_get_owner_uid(creds, &uid);
112-
if (r == -ENXIO)
113-
goto err_no_user;
114-
if (r < 0)
115-
return r;
142+
if (r < 0) {
143+
if (r != -ENXIO)
144+
return r;
145+
146+
user = NULL;
147+
} else
148+
user = hashmap_get(m->users, UID_TO_PTR(uid));
116149

117-
user = hashmap_get(m->users, UID_TO_PTR(uid));
118150
if (!user)
119-
goto err_no_user;
151+
return sd_bus_error_setf(error, BUS_ERROR_NO_USER_FOR_PID,
152+
"Caller does not belong to any logged in or lingering user");
120153

121154
*ret = user;
122155
return 0;
123-
124-
err_no_user:
125-
return sd_bus_error_setf(error, BUS_ERROR_NO_USER_FOR_PID,
126-
"Caller does not belong to any logged in user or lingering user");
127156
}
128157

129158
int manager_get_user_from_creds(Manager *m, sd_bus_message *message, uid_t uid, sd_bus_error *error, User **ret) {
@@ -145,24 +174,31 @@ int manager_get_user_from_creds(Manager *m, sd_bus_message *message, uid_t uid,
145174
return 0;
146175
}
147176

148-
int manager_get_seat_from_creds(Manager *m, sd_bus_message *message, const char *name, sd_bus_error *error, Seat **ret) {
177+
int manager_get_seat_from_creds(
178+
Manager *m,
179+
sd_bus_message *message,
180+
const char *name,
181+
sd_bus_error *error,
182+
Seat **ret) {
183+
149184
Seat *seat;
150185
int r;
151186

152187
assert(m);
153188
assert(message);
154189
assert(ret);
155190

156-
if (isempty(name)) {
191+
if (SEAT_IS_SELF(name) || SEAT_IS_AUTO(name)) {
157192
Session *session;
158193

159-
r = manager_get_session_from_creds(m, message, NULL, error, &session);
194+
/* Use these special seat names as session names */
195+
r = manager_get_session_from_creds(m, message, name, error, &session);
160196
if (r < 0)
161197
return r;
162198

163199
seat = session->seat;
164200
if (!seat)
165-
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SEAT, "Session has no seat.");
201+
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SEAT, "Session '%s' has no seat.", session->id);
166202
} else {
167203
seat = hashmap_get(m->seats, name);
168204
if (!seat)
@@ -830,6 +866,10 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
830866
} while (hashmap_get(m->sessions, id));
831867
}
832868

869+
/* The generated names should not clash with 'auto' or 'self' */
870+
assert(!SESSION_IS_SELF(id));
871+
assert(!SESSION_IS_AUTO(id));
872+
833873
/* If we are not watching utmp already, try again */
834874
manager_reconnect_utmp(m);
835875

@@ -990,8 +1030,7 @@ static int method_activate_session_on_seat(sd_bus_message *message, void *userda
9901030
assert(message);
9911031
assert(m);
9921032

993-
/* Same as ActivateSession() but refuses to work if
994-
* the seat doesn't match */
1033+
/* Same as ActivateSession() but refuses to work if the seat doesn't match */
9951034

9961035
r = sd_bus_message_read(message, "ss", &session_name, &seat_name);
9971036
if (r < 0)

src/login/logind-seat-dbus.c

Lines changed: 44 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,10 @@ const sd_bus_vtable seat_vtable[] = {
255255
};
256256

257257
int seat_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
258+
_cleanup_free_ char *e = NULL;
259+
sd_bus_message *message;
258260
Manager *m = userdata;
261+
const char *p;
259262
Seat *seat;
260263
int r;
261264

@@ -265,32 +268,25 @@ int seat_object_find(sd_bus *bus, const char *path, const char *interface, void
265268
assert(found);
266269
assert(m);
267270

268-
if (streq(path, "/org/freedesktop/login1/seat/self")) {
269-
sd_bus_message *message;
270-
271-
message = sd_bus_get_current_message(bus);
272-
if (!message)
273-
return 0;
274-
275-
r = manager_get_seat_from_creds(m, message, NULL, error, &seat);
276-
if (r < 0)
277-
return r;
278-
} else {
279-
_cleanup_free_ char *e = NULL;
280-
const char *p;
271+
p = startswith(path, "/org/freedesktop/login1/seat/");
272+
if (!p)
273+
return 0;
281274

282-
p = startswith(path, "/org/freedesktop/login1/seat/");
283-
if (!p)
284-
return 0;
275+
e = bus_label_unescape(p);
276+
if (!e)
277+
return -ENOMEM;
285278

286-
e = bus_label_unescape(p);
287-
if (!e)
288-
return -ENOMEM;
279+
message = sd_bus_get_current_message(bus);
280+
if (!message)
281+
return 0;
289282

290-
seat = hashmap_get(m->seats, e);
291-
if (!seat)
292-
return 0;
283+
r = manager_get_seat_from_creds(m, message, e, error, &seat);
284+
if (r == -ENXIO) {
285+
sd_bus_error_free(error);
286+
return 0;
293287
}
288+
if (r < 0)
289+
return r;
294290

295291
*found = seat;
296292
return 1;
@@ -335,25 +331,47 @@ int seat_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***
335331
message = sd_bus_get_current_message(bus);
336332
if (message) {
337333
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
338-
const char *name;
339-
Session *session;
340334

341-
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds);
335+
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID|SD_BUS_CREDS_AUGMENT, &creds);
342336
if (r >= 0) {
337+
bool may_auto = false;
338+
const char *name;
339+
343340
r = sd_bus_creds_get_session(creds, &name);
344341
if (r >= 0) {
342+
Session *session;
343+
345344
session = hashmap_get(m->sessions, name);
346345
if (session && session->seat) {
347346
r = strv_extend(&l, "/org/freedesktop/login1/seat/self");
348347
if (r < 0)
349348
return r;
349+
350+
may_auto = true;
350351
}
351352
}
353+
354+
if (!may_auto) {
355+
uid_t uid;
356+
357+
r = sd_bus_creds_get_owner_uid(creds, &uid);
358+
if (r >= 0) {
359+
User *user;
360+
361+
user = hashmap_get(m->users, UID_TO_PTR(uid));
362+
may_auto = user && user->display && user->display->seat;
363+
}
364+
}
365+
366+
if (may_auto) {
367+
r = strv_extend(&l, "/org/freedesktop/login1/seat/auto");
368+
if (r < 0)
369+
return r;
370+
}
352371
}
353372
}
354373

355374
*nodes = TAKE_PTR(l);
356-
357375
return 1;
358376
}
359377

src/login/logind-seat.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,11 @@ int seat_send_signal(Seat *s, bool new_seat);
7777
int seat_send_changed(Seat *s, const char *properties, ...) _sentinel_;
7878

7979
int bus_seat_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error);
80+
81+
static inline bool SEAT_IS_SELF(const char *name) {
82+
return isempty(name) || streq(name, "self");
83+
}
84+
85+
static inline bool SEAT_IS_AUTO(const char *name) {
86+
return streq_ptr(name, "auto");
87+
}

0 commit comments

Comments
 (0)