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