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