]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/logind-seat-dbus.c
Merge pull request #1659 from vcaputo/journal_verify_envalid
[thirdparty/systemd.git] / src / login / logind-seat-dbus.c
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 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 _cleanup_free_ char *p = NULL;
43 Seat *s = userdata;
44
45 assert(bus);
46 assert(reply);
47 assert(s);
48
49 p = s->active ? session_bus_path(s->active) : strdup("/");
50 if (!p)
51 return -ENOMEM;
52
53 return sd_bus_message_append(reply, "(so)", s->active ? s->active->id : "", p);
54 }
55
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) {
64
65 Seat *s = userdata;
66
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) {
82
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));
90 }
91
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;
120 Session *session;
121 int r;
122
123 assert(bus);
124 assert(reply);
125 assert(s);
126
127 r = sd_bus_message_open_container(reply, 'a', "(so)");
128 if (r < 0)
129 return r;
130
131 LIST_FOREACH(sessions_by_seat, session, s->sessions) {
132 _cleanup_free_ char *p = NULL;
133
134 p = session_bus_path(session);
135 if (!p)
136 return -ENOMEM;
137
138 r = sd_bus_message_append(reply, "(so)", session->id, p);
139 if (r < 0)
140 return r;
141
142 }
143
144 r = sd_bus_message_close_container(reply);
145 if (r < 0)
146 return r;
147
148 return 1;
149 }
150
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) {
159
160 Seat *s = userdata;
161
162 assert(bus);
163 assert(reply);
164 assert(s);
165
166 return sd_bus_message_append(reply, "b", seat_get_idle_hint(s, NULL) > 0);
167 }
168
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) {
177
178 Seat *s = userdata;
179 dual_timestamp t;
180 uint64_t u;
181 int r;
182
183 assert(bus);
184 assert(reply);
185 assert(s);
186
187 r = seat_get_idle_hint(s, &t);
188 if (r < 0)
189 return r;
190
191 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
192
193 return sd_bus_message_append(reply, "t", u);
194 }
195
196 int bus_seat_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
197 Seat *s = userdata;
198 int r;
199
200 assert(message);
201 assert(s);
202
203 r = bus_verify_polkit_async(
204 message,
205 CAP_KILL,
206 "org.freedesktop.login1.manage",
207 NULL,
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
217 r = seat_stop_sessions(s, true);
218 if (r < 0)
219 return r;
220
221 return sd_bus_reply_method_return(message, NULL);
222 }
223
224 static int method_activate_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
225 Seat *s = userdata;
226 const char *name;
227 Session *session;
228 int r;
229
230 assert(message);
231 assert(s);
232
233 r = sd_bus_message_read(message, "s", &name);
234 if (r < 0)
235 return r;
236
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);
240
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);
243
244 r = session_activate(session);
245 if (r < 0)
246 return r;
247
248 return sd_bus_reply_method_return(message, NULL);
249 }
250
251 static int method_switch_to(sd_bus_message *message, void *userdata, sd_bus_error *error) {
252 Seat *s = userdata;
253 unsigned int to;
254 int r;
255
256 assert(message);
257 assert(s);
258
259 r = sd_bus_message_read(message, "u", &to);
260 if (r < 0)
261 return r;
262
263 if (to <= 0)
264 return -EINVAL;
265
266 r = seat_switch_to(s, to);
267 if (r < 0)
268 return r;
269
270 return sd_bus_reply_method_return(message, NULL);
271 }
272
273 static int method_switch_to_next(sd_bus_message *message, void *userdata, sd_bus_error *error) {
274 Seat *s = userdata;
275 int r;
276
277 assert(message);
278 assert(s);
279
280 r = seat_switch_to_next(s);
281 if (r < 0)
282 return r;
283
284 return sd_bus_reply_method_return(message, NULL);
285 }
286
287 static int method_switch_to_previous(sd_bus_message *message, void *userdata, sd_bus_error *error) {
288 Seat *s = userdata;
289 int r;
290
291 assert(message);
292 assert(s);
293
294 r = seat_switch_to_previous(s);
295 if (r < 0)
296 return r;
297
298 return sd_bus_reply_method_return(message, NULL);
299 }
300
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
314 SD_BUS_METHOD("Terminate", NULL, NULL, bus_seat_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED),
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 };
322
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;
327
328 assert(bus);
329 assert(path);
330 assert(interface);
331 assert(found);
332 assert(m);
333
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;
338 const char *name;
339
340 message = sd_bus_get_current_message(bus);
341 if (!message)
342 return 0;
343
344 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds);
345 if (r < 0)
346 return r;
347
348 r = sd_bus_creds_get_session(creds, &name);
349 if (r < 0)
350 return r;
351
352 session = hashmap_get(m->sessions, name);
353 if (!session)
354 return 0;
355
356 seat = session->seat;
357 } else {
358 _cleanup_free_ char *e = NULL;
359 const char *p;
360
361 p = startswith(path, "/org/freedesktop/login1/seat/");
362 if (!p)
363 return 0;
364
365 e = bus_label_unescape(p);
366 if (!e)
367 return -ENOMEM;
368
369 seat = hashmap_get(m->seats, e);
370 }
371
372 if (!seat)
373 return 0;
374
375 *found = seat;
376 return 1;
377 }
378
379 char *seat_bus_path(Seat *s) {
380 _cleanup_free_ char *t = NULL;
381
382 assert(s);
383
384 t = bus_label_escape(s->id);
385 if (!t)
386 return NULL;
387
388 return strappend("/org/freedesktop/login1/seat/", t);
389 }
390
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;
393 sd_bus_message *message;
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
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
435 *nodes = l;
436 l = NULL;
437
438 return 1;
439 }
440
441 int seat_send_signal(Seat *s, bool new_seat) {
442 _cleanup_free_ char *p = NULL;
443
444 assert(s);
445
446 p = seat_bus_path(s);
447 if (!p)
448 return -ENOMEM;
449
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);
456 }
457
458 int seat_send_changed(Seat *s, const char *properties, ...) {
459 _cleanup_free_ char *p = NULL;
460 char **l;
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
471 l = strv_from_stdarg_alloca(properties);
472
473 return sd_bus_emit_properties_changed_strv(s->manager->bus, p, "org.freedesktop.login1.Seat", l);
474 }