]> git.proxmox.com Git - systemd.git/blame - src/login/logind-seat-dbus.c
Imported Upstream version 220
[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",
207 false,
208 UID_INVALID,
209 &s->manager->polkit_registry,
210 error);
211 if (r < 0)
212 return r;
213 if (r == 0)
214 return 1; /* Will call us back */
215
60f067b4
JS
216 r = seat_stop_sessions(s, true);
217 if (r < 0)
218 return r;
663996b3 219
60f067b4 220 return sd_bus_reply_method_return(message, NULL);
663996b3
MS
221}
222
e3bff60a 223static int method_activate_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
60f067b4
JS
224 Seat *s = userdata;
225 const char *name;
226 Session *session;
227 int r;
663996b3 228
60f067b4 229 assert(message);
663996b3
MS
230 assert(s);
231
60f067b4
JS
232 r = sd_bus_message_read(message, "s", &name);
233 if (r < 0)
234 return r;
663996b3 235
60f067b4
JS
236 session = hashmap_get(s->manager->sessions, name);
237 if (!session)
238 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
663996b3 239
60f067b4
JS
240 if (session->seat != s)
241 return sd_bus_error_setf(error, BUS_ERROR_SESSION_NOT_ON_SEAT, "Session %s not on seat %s", name, s->id);
663996b3 242
60f067b4
JS
243 r = session_activate(session);
244 if (r < 0)
245 return r;
663996b3 246
60f067b4 247 return sd_bus_reply_method_return(message, NULL);
663996b3
MS
248}
249
e3bff60a 250static int method_switch_to(sd_bus_message *message, void *userdata, sd_bus_error *error) {
60f067b4
JS
251 Seat *s = userdata;
252 unsigned int to;
253 int r;
663996b3 254
60f067b4
JS
255 assert(message);
256 assert(s);
663996b3 257
60f067b4
JS
258 r = sd_bus_message_read(message, "u", &to);
259 if (r < 0)
260 return r;
663996b3 261
60f067b4
JS
262 if (to <= 0)
263 return -EINVAL;
663996b3 264
60f067b4
JS
265 r = seat_switch_to(s, to);
266 if (r < 0)
267 return r;
663996b3 268
60f067b4 269 return sd_bus_reply_method_return(message, NULL);
663996b3
MS
270}
271
e3bff60a 272static int method_switch_to_next(sd_bus_message *message, void *userdata, sd_bus_error *error) {
60f067b4 273 Seat *s = userdata;
663996b3
MS
274 int r;
275
663996b3 276 assert(message);
60f067b4 277 assert(s);
663996b3 278
60f067b4
JS
279 r = seat_switch_to_next(s);
280 if (r < 0)
281 return r;
663996b3 282
60f067b4
JS
283 return sd_bus_reply_method_return(message, NULL);
284}
663996b3 285
e3bff60a 286static int method_switch_to_previous(sd_bus_message *message, void *userdata, sd_bus_error *error) {
60f067b4
JS
287 Seat *s = userdata;
288 int r;
663996b3 289
60f067b4
JS
290 assert(message);
291 assert(s);
663996b3 292
60f067b4
JS
293 r = seat_switch_to_previous(s);
294 if (r < 0)
295 return r;
663996b3 296
60f067b4
JS
297 return sd_bus_reply_method_return(message, NULL);
298}
663996b3 299
60f067b4
JS
300const 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
e3bff60a 313 SD_BUS_METHOD("Terminate", NULL, NULL, bus_seat_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED),
60f067b4
JS
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};
663996b3 321
60f067b4
JS
322int seat_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
323 Manager *m = userdata;
324 Seat *seat;
325 int r;
663996b3 326
60f067b4
JS
327 assert(bus);
328 assert(path);
329 assert(interface);
330 assert(found);
331 assert(m);
663996b3 332
60f067b4
JS
333 if (streq(path, "/org/freedesktop/login1/seat/self")) {
334 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
335 sd_bus_message *message;
336 Session *session;
e735f4d4 337 const char *name;
663996b3 338
60f067b4
JS
339 message = sd_bus_get_current_message(bus);
340 if (!message)
341 return 0;
663996b3 342
e735f4d4 343 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds);
60f067b4
JS
344 if (r < 0)
345 return r;
663996b3 346
e735f4d4 347 r = sd_bus_creds_get_session(creds, &name);
60f067b4
JS
348 if (r < 0)
349 return r;
663996b3 350
e735f4d4
MP
351 session = hashmap_get(m->sessions, name);
352 if (!session)
60f067b4 353 return 0;
663996b3 354
60f067b4
JS
355 seat = session->seat;
356 } else {
357 _cleanup_free_ char *e = NULL;
358 const char *p;
663996b3 359
60f067b4
JS
360 p = startswith(path, "/org/freedesktop/login1/seat/");
361 if (!p)
362 return 0;
663996b3 363
60f067b4
JS
364 e = bus_label_unescape(p);
365 if (!e)
366 return -ENOMEM;
663996b3 367
60f067b4 368 seat = hashmap_get(m->seats, e);
663996b3
MS
369 }
370
e735f4d4
MP
371 if (!seat)
372 return 0;
373
60f067b4
JS
374 *found = seat;
375 return 1;
663996b3
MS
376}
377
663996b3 378char *seat_bus_path(Seat *s) {
14228c0d 379 _cleanup_free_ char *t = NULL;
663996b3
MS
380
381 assert(s);
382
60f067b4 383 t = bus_label_escape(s->id);
663996b3
MS
384 if (!t)
385 return NULL;
386
387 return strappend("/org/freedesktop/login1/seat/", t);
388}
389
60f067b4
JS
390int seat_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
391 _cleanup_strv_free_ char **l = NULL;
e735f4d4 392 sd_bus_message *message;
60f067b4
JS
393 Manager *m = userdata;
394 Seat *seat;
395 Iterator i;
396 int r;
397
398 assert(bus);
399 assert(path);
400 assert(nodes);
401
402 HASHMAP_FOREACH(seat, m->seats, i) {
403 char *p;
404
405 p = seat_bus_path(seat);
406 if (!p)
407 return -ENOMEM;
408
409 r = strv_consume(&l, p);
410 if (r < 0)
411 return r;
412 }
413
e735f4d4
MP
414 message = sd_bus_get_current_message(bus);
415 if (message) {
416 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
417 const char *name;
418 Session *session;
419
420 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds);
421 if (r >= 0) {
422 r = sd_bus_creds_get_session(creds, &name);
423 if (r >= 0) {
424 session = hashmap_get(m->sessions, name);
425 if (session && session->seat) {
426 r = strv_extend(&l, "/org/freedesktop/login1/seat/self");
427 if (r < 0)
428 return r;
429 }
430 }
431 }
432 }
433
60f067b4
JS
434 *nodes = l;
435 l = NULL;
436
437 return 1;
438}
439
663996b3 440int seat_send_signal(Seat *s, bool new_seat) {
663996b3
MS
441 _cleanup_free_ char *p = NULL;
442
443 assert(s);
444
663996b3
MS
445 p = seat_bus_path(s);
446 if (!p)
447 return -ENOMEM;
448
60f067b4
JS
449 return sd_bus_emit_signal(
450 s->manager->bus,
451 "/org/freedesktop/login1",
452 "org.freedesktop.login1.Manager",
453 new_seat ? "SeatNew" : "SeatRemoved",
454 "so", s->id, p);
663996b3
MS
455}
456
60f067b4 457int seat_send_changed(Seat *s, const char *properties, ...) {
663996b3 458 _cleanup_free_ char *p = NULL;
60f067b4 459 char **l;
663996b3
MS
460
461 assert(s);
462
463 if (!s->started)
464 return 0;
465
466 p = seat_bus_path(s);
467 if (!p)
468 return -ENOMEM;
469
60f067b4 470 l = strv_from_stdarg_alloca(properties);
663996b3 471
60f067b4 472 return sd_bus_emit_properties_changed_strv(s->manager->bus, p, "org.freedesktop.login1.Seat", l);
663996b3 473}