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