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