]> git.proxmox.com Git - systemd.git/blame - src/login/logind-seat-dbus.c
Imported Upstream version 226
[systemd.git] / src / login / logind-seat-dbus.c
CommitLineData
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
33static 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
56static 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
74static 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
92static 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
110static 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
151static 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
169static 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 196int 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 224static 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 251static 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 273static 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 287static 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
301const 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
323int 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 379char *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
391int 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 441int 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 458int 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}