]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
3f49d45a LP |
2 | /*** |
3 | This file is part of systemd. | |
4 | ||
5 | Copyright 2011 Lennart Poettering | |
3f49d45a LP |
6 | ***/ |
7 | ||
8 | #include <errno.h> | |
a185c5aa | 9 | #include <string.h> |
3f49d45a | 10 | |
b5efdb8a | 11 | #include "alloc-util.h" |
96aad8d1 | 12 | #include "bus-common-errors.h" |
a6278b88 | 13 | #include "bus-label.h" |
ee104e11 | 14 | #include "bus-util.h" |
3f49d45a | 15 | #include "logind-seat.h" |
ee104e11 LP |
16 | #include "logind.h" |
17 | #include "strv.h" | |
18 | #include "user-util.h" | |
19 | #include "util.h" | |
3f49d45a | 20 | |
cc377381 LP |
21 | static int property_get_active_session( |
22 | sd_bus *bus, | |
23 | const char *path, | |
24 | const char *interface, | |
25 | const char *property, | |
26 | sd_bus_message *reply, | |
ebcf1f97 LP |
27 | void *userdata, |
28 | sd_bus_error *error) { | |
cc377381 | 29 | |
7fd1b19b | 30 | _cleanup_free_ char *p = NULL; |
cc377381 | 31 | Seat *s = userdata; |
3f49d45a | 32 | |
cc377381 LP |
33 | assert(bus); |
34 | assert(reply); | |
3f49d45a LP |
35 | assert(s); |
36 | ||
cc377381 LP |
37 | p = s->active ? session_bus_path(s->active) : strdup("/"); |
38 | if (!p) | |
3f49d45a LP |
39 | return -ENOMEM; |
40 | ||
cc377381 LP |
41 | return sd_bus_message_append(reply, "(so)", s->active ? s->active->id : "", p); |
42 | } | |
3f49d45a | 43 | |
cc377381 LP |
44 | static int property_get_can_multi_session( |
45 | sd_bus *bus, | |
46 | const char *path, | |
47 | const char *interface, | |
48 | const char *property, | |
49 | sd_bus_message *reply, | |
ebcf1f97 LP |
50 | void *userdata, |
51 | sd_bus_error *error) { | |
3f49d45a | 52 | |
cc377381 | 53 | Seat *s = userdata; |
3f49d45a | 54 | |
cc377381 LP |
55 | assert(bus); |
56 | assert(reply); | |
57 | assert(s); | |
3f49d45a | 58 | |
cc377381 | 59 | return sd_bus_message_append(reply, "b", seat_can_multi_session(s)); |
3f49d45a LP |
60 | } |
61 | ||
cc377381 LP |
62 | static int property_get_can_tty( |
63 | sd_bus *bus, | |
64 | const char *path, | |
65 | const char *interface, | |
66 | const char *property, | |
67 | sd_bus_message *reply, | |
ebcf1f97 LP |
68 | void *userdata, |
69 | sd_bus_error *error) { | |
cc377381 LP |
70 | |
71 | Seat *s = userdata; | |
72 | ||
73 | assert(bus); | |
74 | assert(reply); | |
75 | assert(s); | |
76 | ||
77 | return sd_bus_message_append(reply, "b", seat_can_tty(s)); | |
78 | } | |
79 | ||
80 | static int property_get_can_graphical( | |
81 | sd_bus *bus, | |
82 | const char *path, | |
83 | const char *interface, | |
84 | const char *property, | |
85 | sd_bus_message *reply, | |
ebcf1f97 LP |
86 | void *userdata, |
87 | sd_bus_error *error) { | |
cc377381 LP |
88 | |
89 | Seat *s = userdata; | |
90 | ||
91 | assert(bus); | |
92 | assert(reply); | |
93 | assert(s); | |
94 | ||
a0a6be9f | 95 | return sd_bus_message_append(reply, "b", seat_can_graphical(s)); |
cc377381 LP |
96 | } |
97 | ||
98 | static int property_get_sessions( | |
99 | sd_bus *bus, | |
100 | const char *path, | |
101 | const char *interface, | |
102 | const char *property, | |
103 | sd_bus_message *reply, | |
ebcf1f97 LP |
104 | void *userdata, |
105 | sd_bus_error *error) { | |
cc377381 LP |
106 | |
107 | Seat *s = userdata; | |
3f49d45a | 108 | Session *session; |
cc377381 | 109 | int r; |
3f49d45a | 110 | |
cc377381 LP |
111 | assert(bus); |
112 | assert(reply); | |
3f49d45a LP |
113 | assert(s); |
114 | ||
cc377381 LP |
115 | r = sd_bus_message_open_container(reply, 'a', "(so)"); |
116 | if (r < 0) | |
117 | return r; | |
3f49d45a LP |
118 | |
119 | LIST_FOREACH(sessions_by_seat, session, s->sessions) { | |
7fd1b19b | 120 | _cleanup_free_ char *p = NULL; |
3f49d45a | 121 | |
3f49d45a LP |
122 | p = session_bus_path(session); |
123 | if (!p) | |
124 | return -ENOMEM; | |
125 | ||
cc377381 LP |
126 | r = sd_bus_message_append(reply, "(so)", session->id, p); |
127 | if (r < 0) | |
128 | return r; | |
3f49d45a | 129 | |
3f49d45a LP |
130 | } |
131 | ||
cc377381 LP |
132 | r = sd_bus_message_close_container(reply); |
133 | if (r < 0) | |
134 | return r; | |
3f49d45a | 135 | |
cc377381 | 136 | return 1; |
3f49d45a LP |
137 | } |
138 | ||
cc377381 LP |
139 | static int property_get_idle_hint( |
140 | sd_bus *bus, | |
141 | const char *path, | |
142 | const char *interface, | |
143 | const char *property, | |
144 | sd_bus_message *reply, | |
ebcf1f97 LP |
145 | void *userdata, |
146 | sd_bus_error *error) { | |
f401e48c | 147 | |
cc377381 | 148 | Seat *s = userdata; |
f1a8e221 | 149 | |
cc377381 LP |
150 | assert(bus); |
151 | assert(reply); | |
f1a8e221 LP |
152 | assert(s); |
153 | ||
cc377381 | 154 | return sd_bus_message_append(reply, "b", seat_get_idle_hint(s, NULL) > 0); |
f1a8e221 LP |
155 | } |
156 | ||
cc377381 LP |
157 | static int property_get_idle_since_hint( |
158 | sd_bus *bus, | |
159 | const char *path, | |
160 | const char *interface, | |
161 | const char *property, | |
162 | sd_bus_message *reply, | |
ebcf1f97 LP |
163 | void *userdata, |
164 | sd_bus_error *error) { | |
cc377381 LP |
165 | |
166 | Seat *s = userdata; | |
167 | dual_timestamp t; | |
168 | uint64_t u; | |
169 | int r; | |
f1a8e221 | 170 | |
cc377381 LP |
171 | assert(bus); |
172 | assert(reply); | |
f1a8e221 LP |
173 | assert(s); |
174 | ||
cc377381 LP |
175 | r = seat_get_idle_hint(s, &t); |
176 | if (r < 0) | |
177 | return r; | |
f1a8e221 | 178 | |
cc377381 | 179 | u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic; |
f1a8e221 | 180 | |
cc377381 | 181 | return sd_bus_message_append(reply, "t", u); |
f1a8e221 LP |
182 | } |
183 | ||
19070062 | 184 | int bus_seat_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
cc377381 LP |
185 | Seat *s = userdata; |
186 | int r; | |
a185c5aa | 187 | |
cc377381 | 188 | assert(message); |
a185c5aa LP |
189 | assert(s); |
190 | ||
c529695e LP |
191 | r = bus_verify_polkit_async( |
192 | message, | |
193 | CAP_KILL, | |
194 | "org.freedesktop.login1.manage", | |
403ed0e5 | 195 | NULL, |
c529695e LP |
196 | false, |
197 | UID_INVALID, | |
198 | &s->manager->polkit_registry, | |
199 | error); | |
200 | if (r < 0) | |
201 | return r; | |
202 | if (r == 0) | |
203 | return 1; /* Will call us back */ | |
204 | ||
9bb69af4 | 205 | r = seat_stop_sessions(s, true); |
cc377381 | 206 | if (r < 0) |
ebcf1f97 | 207 | return r; |
a185c5aa | 208 | |
df2d202e | 209 | return sd_bus_reply_method_return(message, NULL); |
a185c5aa LP |
210 | } |
211 | ||
19070062 | 212 | static int method_activate_session(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
cc377381 LP |
213 | Seat *s = userdata; |
214 | const char *name; | |
215 | Session *session; | |
216 | int r; | |
a185c5aa | 217 | |
cc377381 | 218 | assert(message); |
a185c5aa LP |
219 | assert(s); |
220 | ||
cc377381 LP |
221 | r = sd_bus_message_read(message, "s", &name); |
222 | if (r < 0) | |
ebcf1f97 | 223 | return r; |
a185c5aa | 224 | |
cc377381 LP |
225 | session = hashmap_get(s->manager->sessions, name); |
226 | if (!session) | |
ebcf1f97 | 227 | return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name); |
a185c5aa | 228 | |
cc377381 | 229 | if (session->seat != s) |
ebcf1f97 | 230 | return sd_bus_error_setf(error, BUS_ERROR_SESSION_NOT_ON_SEAT, "Session %s not on seat %s", name, s->id); |
a185c5aa | 231 | |
cc377381 LP |
232 | r = session_activate(session); |
233 | if (r < 0) | |
ebcf1f97 | 234 | return r; |
3f49d45a | 235 | |
df2d202e | 236 | return sd_bus_reply_method_return(message, NULL); |
3f49d45a LP |
237 | } |
238 | ||
19070062 | 239 | static int method_switch_to(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
49e6fdbf DH |
240 | Seat *s = userdata; |
241 | unsigned int to; | |
242 | int r; | |
243 | ||
49e6fdbf DH |
244 | assert(message); |
245 | assert(s); | |
246 | ||
247 | r = sd_bus_message_read(message, "u", &to); | |
248 | if (r < 0) | |
249 | return r; | |
250 | ||
251 | if (to <= 0) | |
252 | return -EINVAL; | |
253 | ||
254 | r = seat_switch_to(s, to); | |
255 | if (r < 0) | |
256 | return r; | |
257 | ||
258 | return sd_bus_reply_method_return(message, NULL); | |
259 | } | |
260 | ||
19070062 | 261 | static int method_switch_to_next(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
49e6fdbf DH |
262 | Seat *s = userdata; |
263 | int r; | |
264 | ||
49e6fdbf DH |
265 | assert(message); |
266 | assert(s); | |
267 | ||
268 | r = seat_switch_to_next(s); | |
269 | if (r < 0) | |
270 | return r; | |
271 | ||
272 | return sd_bus_reply_method_return(message, NULL); | |
273 | } | |
274 | ||
19070062 | 275 | static int method_switch_to_previous(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
49e6fdbf DH |
276 | Seat *s = userdata; |
277 | int r; | |
278 | ||
49e6fdbf DH |
279 | assert(message); |
280 | assert(s); | |
281 | ||
282 | r = seat_switch_to_previous(s); | |
283 | if (r < 0) | |
284 | return r; | |
285 | ||
286 | return sd_bus_reply_method_return(message, NULL); | |
287 | } | |
288 | ||
cc377381 LP |
289 | const sd_bus_vtable seat_vtable[] = { |
290 | SD_BUS_VTABLE_START(0), | |
a185c5aa | 291 | |
556089dc | 292 | SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Seat, id), SD_BUS_VTABLE_PROPERTY_CONST), |
cc377381 | 293 | SD_BUS_PROPERTY("ActiveSession", "(so)", property_get_active_session, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), |
556089dc LP |
294 | SD_BUS_PROPERTY("CanMultiSession", "b", property_get_can_multi_session, 0, SD_BUS_VTABLE_PROPERTY_CONST), |
295 | SD_BUS_PROPERTY("CanTTY", "b", property_get_can_tty, 0, SD_BUS_VTABLE_PROPERTY_CONST), | |
cc377381 | 296 | SD_BUS_PROPERTY("CanGraphical", "b", property_get_can_graphical, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), |
91ab7b01 | 297 | SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, 0), |
cc377381 LP |
298 | SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), |
299 | SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), | |
300 | SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), | |
3f49d45a | 301 | |
c529695e | 302 | SD_BUS_METHOD("Terminate", NULL, NULL, bus_seat_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED), |
adacb957 | 303 | SD_BUS_METHOD("ActivateSession", "s", NULL, method_activate_session, SD_BUS_VTABLE_UNPRIVILEGED), |
49e6fdbf DH |
304 | SD_BUS_METHOD("SwitchTo", "u", NULL, method_switch_to, SD_BUS_VTABLE_UNPRIVILEGED), |
305 | SD_BUS_METHOD("SwitchToNext", NULL, NULL, method_switch_to_next, SD_BUS_VTABLE_UNPRIVILEGED), | |
306 | SD_BUS_METHOD("SwitchToPrevious", NULL, NULL, method_switch_to_previous, SD_BUS_VTABLE_UNPRIVILEGED), | |
a185c5aa | 307 | |
cc377381 LP |
308 | SD_BUS_VTABLE_END |
309 | }; | |
a185c5aa | 310 | |
f00c3121 | 311 | int seat_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) { |
cc377381 LP |
312 | Manager *m = userdata; |
313 | Seat *seat; | |
927b1649 | 314 | int r; |
a185c5aa | 315 | |
cc377381 LP |
316 | assert(bus); |
317 | assert(path); | |
318 | assert(interface); | |
319 | assert(found); | |
320 | assert(m); | |
a185c5aa | 321 | |
927b1649 LP |
322 | if (streq(path, "/org/freedesktop/login1/seat/self")) { |
323 | sd_bus_message *message; | |
a185c5aa | 324 | |
19befb2d | 325 | message = sd_bus_get_current_message(bus); |
927b1649 LP |
326 | if (!message) |
327 | return 0; | |
328 | ||
e4d2984b | 329 | r = manager_get_seat_from_creds(m, message, NULL, error, &seat); |
927b1649 | 330 | if (r < 0) |
5b12334d | 331 | return r; |
927b1649 LP |
332 | } else { |
333 | _cleanup_free_ char *e = NULL; | |
334 | const char *p; | |
335 | ||
336 | p = startswith(path, "/org/freedesktop/login1/seat/"); | |
337 | if (!p) | |
338 | return 0; | |
339 | ||
a6278b88 | 340 | e = bus_label_unescape(p); |
927b1649 LP |
341 | if (!e) |
342 | return -ENOMEM; | |
343 | ||
344 | seat = hashmap_get(m->seats, e); | |
e4d2984b AJ |
345 | if (!seat) |
346 | return 0; | |
927b1649 | 347 | } |
a185c5aa | 348 | |
cc377381 LP |
349 | *found = seat; |
350 | return 1; | |
351 | } | |
a185c5aa | 352 | |
cc377381 LP |
353 | char *seat_bus_path(Seat *s) { |
354 | _cleanup_free_ char *t = NULL; | |
a185c5aa | 355 | |
cc377381 | 356 | assert(s); |
a185c5aa | 357 | |
a6278b88 | 358 | t = bus_label_escape(s->id); |
cc377381 LP |
359 | if (!t) |
360 | return NULL; | |
a185c5aa | 361 | |
cc377381 | 362 | return strappend("/org/freedesktop/login1/seat/", t); |
3f49d45a LP |
363 | } |
364 | ||
f00c3121 | 365 | int seat_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) { |
cc377381 | 366 | _cleanup_strv_free_ char **l = NULL; |
ca56b0a6 | 367 | sd_bus_message *message; |
3f49d45a | 368 | Manager *m = userdata; |
cc377381 LP |
369 | Seat *seat; |
370 | Iterator i; | |
3f49d45a LP |
371 | int r; |
372 | ||
cc377381 LP |
373 | assert(bus); |
374 | assert(path); | |
375 | assert(nodes); | |
3f49d45a | 376 | |
cc377381 LP |
377 | HASHMAP_FOREACH(seat, m->seats, i) { |
378 | char *p; | |
3f49d45a | 379 | |
cc377381 LP |
380 | p = seat_bus_path(seat); |
381 | if (!p) | |
382 | return -ENOMEM; | |
3f49d45a | 383 | |
6e18964d ZJS |
384 | r = strv_consume(&l, p); |
385 | if (r < 0) | |
cc377381 | 386 | return r; |
3f49d45a LP |
387 | } |
388 | ||
ca56b0a6 DH |
389 | message = sd_bus_get_current_message(bus); |
390 | if (message) { | |
4afd3348 | 391 | _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; |
ca56b0a6 DH |
392 | const char *name; |
393 | Session *session; | |
394 | ||
395 | r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds); | |
396 | if (r >= 0) { | |
397 | r = sd_bus_creds_get_session(creds, &name); | |
398 | if (r >= 0) { | |
399 | session = hashmap_get(m->sessions, name); | |
400 | if (session && session->seat) { | |
401 | r = strv_extend(&l, "/org/freedesktop/login1/seat/self"); | |
402 | if (r < 0) | |
403 | return r; | |
404 | } | |
405 | } | |
406 | } | |
407 | } | |
b298e984 | 408 | |
1cc6c93a | 409 | *nodes = TAKE_PTR(l); |
3f49d45a | 410 | |
cc377381 | 411 | return 1; |
3f49d45a | 412 | } |
da119395 LP |
413 | |
414 | int seat_send_signal(Seat *s, bool new_seat) { | |
ce0fc5f5 | 415 | _cleanup_free_ char *p = NULL; |
da119395 LP |
416 | |
417 | assert(s); | |
418 | ||
da119395 LP |
419 | p = seat_bus_path(s); |
420 | if (!p) | |
4654e558 | 421 | return -ENOMEM; |
da119395 | 422 | |
cc377381 LP |
423 | return sd_bus_emit_signal( |
424 | s->manager->bus, | |
425 | "/org/freedesktop/login1", | |
426 | "org.freedesktop.login1.Manager", | |
427 | new_seat ? "SeatNew" : "SeatRemoved", | |
428 | "so", s->id, p); | |
da119395 | 429 | } |
9418f147 | 430 | |
cc377381 | 431 | int seat_send_changed(Seat *s, const char *properties, ...) { |
ce0fc5f5 | 432 | _cleanup_free_ char *p = NULL; |
cc377381 | 433 | char **l; |
9418f147 LP |
434 | |
435 | assert(s); | |
436 | ||
ed18b08b LP |
437 | if (!s->started) |
438 | return 0; | |
439 | ||
9418f147 LP |
440 | p = seat_bus_path(s); |
441 | if (!p) | |
442 | return -ENOMEM; | |
443 | ||
cc377381 | 444 | l = strv_from_stdarg_alloca(properties); |
9418f147 | 445 | |
cc377381 | 446 | return sd_bus_emit_properties_changed_strv(s->manager->bus, p, "org.freedesktop.login1.Seat", l); |
9418f147 | 447 | } |