Line data Source code
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 :
25 : #include "util.h"
26 : #include "bus-util.h"
27 : #include "strv.h"
28 : #include "bus-common-errors.h"
29 : #include "bus-label.h"
30 : #include "logind.h"
31 : #include "logind-seat.h"
32 :
33 0 : 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 :
42 0 : _cleanup_free_ char *p = NULL;
43 0 : Seat *s = userdata;
44 :
45 0 : assert(bus);
46 0 : assert(reply);
47 0 : assert(s);
48 :
49 0 : p = s->active ? session_bus_path(s->active) : strdup("/");
50 0 : if (!p)
51 0 : return -ENOMEM;
52 :
53 0 : return sd_bus_message_append(reply, "(so)", s->active ? s->active->id : "", p);
54 : }
55 :
56 0 : 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) {
64 :
65 0 : Seat *s = userdata;
66 :
67 0 : assert(bus);
68 0 : assert(reply);
69 0 : assert(s);
70 :
71 0 : return sd_bus_message_append(reply, "b", seat_can_multi_session(s));
72 : }
73 :
74 0 : 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) {
82 :
83 0 : Seat *s = userdata;
84 :
85 0 : assert(bus);
86 0 : assert(reply);
87 0 : assert(s);
88 :
89 0 : return sd_bus_message_append(reply, "b", seat_can_tty(s));
90 : }
91 :
92 0 : 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 0 : Seat *s = userdata;
102 :
103 0 : assert(bus);
104 0 : assert(reply);
105 0 : assert(s);
106 :
107 0 : return sd_bus_message_append(reply, "b", seat_can_graphical(s));
108 : }
109 :
110 0 : 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 0 : Seat *s = userdata;
120 : Session *session;
121 : int r;
122 :
123 0 : assert(bus);
124 0 : assert(reply);
125 0 : assert(s);
126 :
127 0 : r = sd_bus_message_open_container(reply, 'a', "(so)");
128 0 : if (r < 0)
129 0 : return r;
130 :
131 0 : LIST_FOREACH(sessions_by_seat, session, s->sessions) {
132 0 : _cleanup_free_ char *p = NULL;
133 :
134 0 : p = session_bus_path(session);
135 0 : if (!p)
136 0 : return -ENOMEM;
137 :
138 0 : r = sd_bus_message_append(reply, "(so)", session->id, p);
139 0 : if (r < 0)
140 0 : return r;
141 :
142 : }
143 :
144 0 : r = sd_bus_message_close_container(reply);
145 0 : if (r < 0)
146 0 : return r;
147 :
148 0 : return 1;
149 : }
150 :
151 0 : 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) {
159 :
160 0 : Seat *s = userdata;
161 :
162 0 : assert(bus);
163 0 : assert(reply);
164 0 : assert(s);
165 :
166 0 : return sd_bus_message_append(reply, "b", seat_get_idle_hint(s, NULL) > 0);
167 : }
168 :
169 0 : 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) {
177 :
178 0 : Seat *s = userdata;
179 : dual_timestamp t;
180 : uint64_t u;
181 : int r;
182 :
183 0 : assert(bus);
184 0 : assert(reply);
185 0 : assert(s);
186 :
187 0 : r = seat_get_idle_hint(s, &t);
188 0 : if (r < 0)
189 0 : return r;
190 :
191 0 : u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
192 :
193 0 : return sd_bus_message_append(reply, "t", u);
194 : }
195 :
196 0 : int bus_seat_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
197 0 : Seat *s = userdata;
198 : int r;
199 :
200 0 : assert(message);
201 0 : assert(s);
202 :
203 0 : r = bus_verify_polkit_async(
204 : message,
205 : CAP_KILL,
206 : "org.freedesktop.login1.manage",
207 : false,
208 : UID_INVALID,
209 0 : &s->manager->polkit_registry,
210 : error);
211 0 : if (r < 0)
212 0 : return r;
213 0 : if (r == 0)
214 0 : return 1; /* Will call us back */
215 :
216 0 : r = seat_stop_sessions(s, true);
217 0 : if (r < 0)
218 0 : return r;
219 :
220 0 : return sd_bus_reply_method_return(message, NULL);
221 : }
222 :
223 0 : static int method_activate_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
224 0 : Seat *s = userdata;
225 : const char *name;
226 : Session *session;
227 : int r;
228 :
229 0 : assert(message);
230 0 : assert(s);
231 :
232 0 : r = sd_bus_message_read(message, "s", &name);
233 0 : if (r < 0)
234 0 : return r;
235 :
236 0 : session = hashmap_get(s->manager->sessions, name);
237 0 : if (!session)
238 0 : return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
239 :
240 0 : if (session->seat != s)
241 0 : return sd_bus_error_setf(error, BUS_ERROR_SESSION_NOT_ON_SEAT, "Session %s not on seat %s", name, s->id);
242 :
243 0 : r = session_activate(session);
244 0 : if (r < 0)
245 0 : return r;
246 :
247 0 : return sd_bus_reply_method_return(message, NULL);
248 : }
249 :
250 0 : static int method_switch_to(sd_bus_message *message, void *userdata, sd_bus_error *error) {
251 0 : Seat *s = userdata;
252 : unsigned int to;
253 : int r;
254 :
255 0 : assert(message);
256 0 : assert(s);
257 :
258 0 : r = sd_bus_message_read(message, "u", &to);
259 0 : if (r < 0)
260 0 : return r;
261 :
262 0 : if (to <= 0)
263 0 : return -EINVAL;
264 :
265 0 : r = seat_switch_to(s, to);
266 0 : if (r < 0)
267 0 : return r;
268 :
269 0 : return sd_bus_reply_method_return(message, NULL);
270 : }
271 :
272 0 : static int method_switch_to_next(sd_bus_message *message, void *userdata, sd_bus_error *error) {
273 0 : Seat *s = userdata;
274 : int r;
275 :
276 0 : assert(message);
277 0 : assert(s);
278 :
279 0 : r = seat_switch_to_next(s);
280 0 : if (r < 0)
281 0 : return r;
282 :
283 0 : return sd_bus_reply_method_return(message, NULL);
284 : }
285 :
286 0 : static int method_switch_to_previous(sd_bus_message *message, void *userdata, sd_bus_error *error) {
287 0 : Seat *s = userdata;
288 : int r;
289 :
290 0 : assert(message);
291 0 : assert(s);
292 :
293 0 : r = seat_switch_to_previous(s);
294 0 : if (r < 0)
295 0 : return r;
296 :
297 0 : return sd_bus_reply_method_return(message, NULL);
298 : }
299 :
300 : const sd_bus_vtable seat_vtable[] = {
301 : SD_BUS_VTABLE_START(0),
302 :
303 : SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Seat, id), SD_BUS_VTABLE_PROPERTY_CONST),
304 : SD_BUS_PROPERTY("ActiveSession", "(so)", property_get_active_session, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
305 : SD_BUS_PROPERTY("CanMultiSession", "b", property_get_can_multi_session, 0, SD_BUS_VTABLE_PROPERTY_CONST),
306 : SD_BUS_PROPERTY("CanTTY", "b", property_get_can_tty, 0, SD_BUS_VTABLE_PROPERTY_CONST),
307 : SD_BUS_PROPERTY("CanGraphical", "b", property_get_can_graphical, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
308 : SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
309 : SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
310 : SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
311 : SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
312 :
313 : SD_BUS_METHOD("Terminate", NULL, NULL, bus_seat_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED),
314 : SD_BUS_METHOD("ActivateSession", "s", NULL, method_activate_session, SD_BUS_VTABLE_UNPRIVILEGED),
315 : SD_BUS_METHOD("SwitchTo", "u", NULL, method_switch_to, SD_BUS_VTABLE_UNPRIVILEGED),
316 : SD_BUS_METHOD("SwitchToNext", NULL, NULL, method_switch_to_next, SD_BUS_VTABLE_UNPRIVILEGED),
317 : SD_BUS_METHOD("SwitchToPrevious", NULL, NULL, method_switch_to_previous, SD_BUS_VTABLE_UNPRIVILEGED),
318 :
319 : SD_BUS_VTABLE_END
320 : };
321 :
322 0 : int seat_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
323 0 : Manager *m = userdata;
324 : Seat *seat;
325 : int r;
326 :
327 0 : assert(bus);
328 0 : assert(path);
329 0 : assert(interface);
330 0 : assert(found);
331 0 : assert(m);
332 :
333 0 : if (streq(path, "/org/freedesktop/login1/seat/self")) {
334 0 : _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
335 : sd_bus_message *message;
336 : Session *session;
337 : const char *name;
338 :
339 0 : message = sd_bus_get_current_message(bus);
340 0 : if (!message)
341 0 : return 0;
342 :
343 0 : r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds);
344 0 : if (r < 0)
345 0 : return r;
346 :
347 0 : r = sd_bus_creds_get_session(creds, &name);
348 0 : if (r < 0)
349 0 : return r;
350 :
351 0 : session = hashmap_get(m->sessions, name);
352 0 : if (!session)
353 0 : return 0;
354 :
355 0 : seat = session->seat;
356 : } else {
357 0 : _cleanup_free_ char *e = NULL;
358 : const char *p;
359 :
360 0 : p = startswith(path, "/org/freedesktop/login1/seat/");
361 0 : if (!p)
362 0 : return 0;
363 :
364 0 : e = bus_label_unescape(p);
365 0 : if (!e)
366 0 : return -ENOMEM;
367 :
368 0 : seat = hashmap_get(m->seats, e);
369 : }
370 :
371 0 : if (!seat)
372 0 : return 0;
373 :
374 0 : *found = seat;
375 0 : return 1;
376 : }
377 :
378 0 : char *seat_bus_path(Seat *s) {
379 0 : _cleanup_free_ char *t = NULL;
380 :
381 0 : assert(s);
382 :
383 0 : t = bus_label_escape(s->id);
384 0 : if (!t)
385 0 : return NULL;
386 :
387 0 : return strappend("/org/freedesktop/login1/seat/", t);
388 : }
389 :
390 0 : int seat_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
391 0 : _cleanup_strv_free_ char **l = NULL;
392 : sd_bus_message *message;
393 0 : Manager *m = userdata;
394 : Seat *seat;
395 : Iterator i;
396 : int r;
397 :
398 0 : assert(bus);
399 0 : assert(path);
400 0 : assert(nodes);
401 :
402 0 : HASHMAP_FOREACH(seat, m->seats, i) {
403 : char *p;
404 :
405 0 : p = seat_bus_path(seat);
406 0 : if (!p)
407 0 : return -ENOMEM;
408 :
409 0 : r = strv_consume(&l, p);
410 0 : if (r < 0)
411 0 : return r;
412 : }
413 :
414 0 : message = sd_bus_get_current_message(bus);
415 0 : if (message) {
416 0 : _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
417 : const char *name;
418 : Session *session;
419 :
420 0 : r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds);
421 0 : if (r >= 0) {
422 0 : r = sd_bus_creds_get_session(creds, &name);
423 0 : if (r >= 0) {
424 0 : session = hashmap_get(m->sessions, name);
425 0 : if (session && session->seat) {
426 0 : r = strv_extend(&l, "/org/freedesktop/login1/seat/self");
427 0 : if (r < 0)
428 0 : return r;
429 : }
430 : }
431 : }
432 : }
433 :
434 0 : *nodes = l;
435 0 : l = NULL;
436 :
437 0 : return 1;
438 : }
439 :
440 0 : int seat_send_signal(Seat *s, bool new_seat) {
441 0 : _cleanup_free_ char *p = NULL;
442 :
443 0 : assert(s);
444 :
445 0 : p = seat_bus_path(s);
446 0 : if (!p)
447 0 : return -ENOMEM;
448 :
449 0 : return sd_bus_emit_signal(
450 0 : s->manager->bus,
451 : "/org/freedesktop/login1",
452 : "org.freedesktop.login1.Manager",
453 : new_seat ? "SeatNew" : "SeatRemoved",
454 : "so", s->id, p);
455 : }
456 :
457 0 : int seat_send_changed(Seat *s, const char *properties, ...) {
458 0 : _cleanup_free_ char *p = NULL;
459 : char **l;
460 :
461 0 : assert(s);
462 :
463 0 : if (!s->started)
464 0 : return 0;
465 :
466 0 : p = seat_bus_path(s);
467 0 : if (!p)
468 0 : return -ENOMEM;
469 :
470 0 : l = strv_from_stdarg_alloca(properties);
471 :
472 0 : return sd_bus_emit_properties_changed_strv(s->manager->bus, p, "org.freedesktop.login1.Seat", l);
473 : }
|