]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-seat-dbus.c
logind: process session/inhibitor fds at higher priority
[thirdparty/systemd.git] / src / login / logind-seat-dbus.c
CommitLineData
3f49d45a
LP
1/***
2 This file is part of systemd.
3
4 Copyright 2011 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
3f49d45a
LP
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 14 Lesser General Public License for more details.
3f49d45a 15
5430f7f2 16 You should have received a copy of the GNU Lesser General Public License
3f49d45a
LP
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
20#include <errno.h>
a185c5aa 21#include <string.h>
3f49d45a 22
b5efdb8a 23#include "alloc-util.h"
96aad8d1 24#include "bus-common-errors.h"
a6278b88 25#include "bus-label.h"
ee104e11 26#include "bus-util.h"
3f49d45a 27#include "logind-seat.h"
ee104e11
LP
28#include "logind.h"
29#include "strv.h"
30#include "user-util.h"
31#include "util.h"
3f49d45a 32
cc377381
LP
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,
ebcf1f97
LP
39 void *userdata,
40 sd_bus_error *error) {
cc377381 41
7fd1b19b 42 _cleanup_free_ char *p = NULL;
cc377381 43 Seat *s = userdata;
3f49d45a 44
cc377381
LP
45 assert(bus);
46 assert(reply);
3f49d45a
LP
47 assert(s);
48
cc377381
LP
49 p = s->active ? session_bus_path(s->active) : strdup("/");
50 if (!p)
3f49d45a
LP
51 return -ENOMEM;
52
cc377381
LP
53 return sd_bus_message_append(reply, "(so)", s->active ? s->active->id : "", p);
54}
3f49d45a 55
cc377381
LP
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,
ebcf1f97
LP
62 void *userdata,
63 sd_bus_error *error) {
3f49d45a 64
cc377381 65 Seat *s = userdata;
3f49d45a 66
cc377381
LP
67 assert(bus);
68 assert(reply);
69 assert(s);
3f49d45a 70
cc377381 71 return sd_bus_message_append(reply, "b", seat_can_multi_session(s));
3f49d45a
LP
72}
73
cc377381
LP
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,
ebcf1f97
LP
80 void *userdata,
81 sd_bus_error *error) {
cc377381
LP
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
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,
ebcf1f97
LP
98 void *userdata,
99 sd_bus_error *error) {
cc377381
LP
100
101 Seat *s = userdata;
102
103 assert(bus);
104 assert(reply);
105 assert(s);
106
a0a6be9f 107 return sd_bus_message_append(reply, "b", seat_can_graphical(s));
cc377381
LP
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,
ebcf1f97
LP
116 void *userdata,
117 sd_bus_error *error) {
cc377381
LP
118
119 Seat *s = userdata;
3f49d45a 120 Session *session;
cc377381 121 int r;
3f49d45a 122
cc377381
LP
123 assert(bus);
124 assert(reply);
3f49d45a
LP
125 assert(s);
126
cc377381
LP
127 r = sd_bus_message_open_container(reply, 'a', "(so)");
128 if (r < 0)
129 return r;
3f49d45a
LP
130
131 LIST_FOREACH(sessions_by_seat, session, s->sessions) {
7fd1b19b 132 _cleanup_free_ char *p = NULL;
3f49d45a 133
3f49d45a
LP
134 p = session_bus_path(session);
135 if (!p)
136 return -ENOMEM;
137
cc377381
LP
138 r = sd_bus_message_append(reply, "(so)", session->id, p);
139 if (r < 0)
140 return r;
3f49d45a 141
3f49d45a
LP
142 }
143
cc377381
LP
144 r = sd_bus_message_close_container(reply);
145 if (r < 0)
146 return r;
3f49d45a 147
cc377381 148 return 1;
3f49d45a
LP
149}
150
cc377381
LP
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,
ebcf1f97
LP
157 void *userdata,
158 sd_bus_error *error) {
f401e48c 159
cc377381 160 Seat *s = userdata;
f1a8e221 161
cc377381
LP
162 assert(bus);
163 assert(reply);
f1a8e221
LP
164 assert(s);
165
cc377381 166 return sd_bus_message_append(reply, "b", seat_get_idle_hint(s, NULL) > 0);
f1a8e221
LP
167}
168
cc377381
LP
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,
ebcf1f97
LP
175 void *userdata,
176 sd_bus_error *error) {
cc377381
LP
177
178 Seat *s = userdata;
179 dual_timestamp t;
180 uint64_t u;
181 int r;
f1a8e221 182
cc377381
LP
183 assert(bus);
184 assert(reply);
f1a8e221
LP
185 assert(s);
186
cc377381
LP
187 r = seat_get_idle_hint(s, &t);
188 if (r < 0)
189 return r;
f1a8e221 190
cc377381 191 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
f1a8e221 192
cc377381 193 return sd_bus_message_append(reply, "t", u);
f1a8e221
LP
194}
195
19070062 196int bus_seat_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
197 Seat *s = userdata;
198 int r;
a185c5aa 199
cc377381 200 assert(message);
a185c5aa
LP
201 assert(s);
202
c529695e
LP
203 r = bus_verify_polkit_async(
204 message,
205 CAP_KILL,
206 "org.freedesktop.login1.manage",
403ed0e5 207 NULL,
c529695e
LP
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
9bb69af4 217 r = seat_stop_sessions(s, true);
cc377381 218 if (r < 0)
ebcf1f97 219 return r;
a185c5aa 220
df2d202e 221 return sd_bus_reply_method_return(message, NULL);
a185c5aa
LP
222}
223
19070062 224static int method_activate_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
225 Seat *s = userdata;
226 const char *name;
227 Session *session;
228 int r;
a185c5aa 229
cc377381 230 assert(message);
a185c5aa
LP
231 assert(s);
232
cc377381
LP
233 r = sd_bus_message_read(message, "s", &name);
234 if (r < 0)
ebcf1f97 235 return r;
a185c5aa 236
cc377381
LP
237 session = hashmap_get(s->manager->sessions, name);
238 if (!session)
ebcf1f97 239 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
a185c5aa 240
cc377381 241 if (session->seat != s)
ebcf1f97 242 return sd_bus_error_setf(error, BUS_ERROR_SESSION_NOT_ON_SEAT, "Session %s not on seat %s", name, s->id);
a185c5aa 243
cc377381
LP
244 r = session_activate(session);
245 if (r < 0)
ebcf1f97 246 return r;
3f49d45a 247
df2d202e 248 return sd_bus_reply_method_return(message, NULL);
3f49d45a
LP
249}
250
19070062 251static int method_switch_to(sd_bus_message *message, void *userdata, sd_bus_error *error) {
49e6fdbf
DH
252 Seat *s = userdata;
253 unsigned int to;
254 int r;
255
49e6fdbf
DH
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
19070062 273static int method_switch_to_next(sd_bus_message *message, void *userdata, sd_bus_error *error) {
49e6fdbf
DH
274 Seat *s = userdata;
275 int r;
276
49e6fdbf
DH
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
19070062 287static int method_switch_to_previous(sd_bus_message *message, void *userdata, sd_bus_error *error) {
49e6fdbf
DH
288 Seat *s = userdata;
289 int r;
290
49e6fdbf
DH
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
cc377381
LP
301const sd_bus_vtable seat_vtable[] = {
302 SD_BUS_VTABLE_START(0),
a185c5aa 303
556089dc 304 SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Seat, id), SD_BUS_VTABLE_PROPERTY_CONST),
cc377381 305 SD_BUS_PROPERTY("ActiveSession", "(so)", property_get_active_session, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
556089dc
LP
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),
cc377381
LP
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),
3f49d45a 313
c529695e 314 SD_BUS_METHOD("Terminate", NULL, NULL, bus_seat_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED),
adacb957 315 SD_BUS_METHOD("ActivateSession", "s", NULL, method_activate_session, SD_BUS_VTABLE_UNPRIVILEGED),
49e6fdbf
DH
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),
a185c5aa 319
cc377381
LP
320 SD_BUS_VTABLE_END
321};
a185c5aa 322
f00c3121 323int seat_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
cc377381
LP
324 Manager *m = userdata;
325 Seat *seat;
927b1649 326 int r;
a185c5aa 327
cc377381
LP
328 assert(bus);
329 assert(path);
330 assert(interface);
331 assert(found);
332 assert(m);
a185c5aa 333
927b1649 334 if (streq(path, "/org/freedesktop/login1/seat/self")) {
4afd3348 335 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
927b1649
LP
336 sd_bus_message *message;
337 Session *session;
309a29df 338 const char *name;
a185c5aa 339
19befb2d 340 message = sd_bus_get_current_message(bus);
927b1649
LP
341 if (!message)
342 return 0;
343
309a29df 344 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds);
927b1649 345 if (r < 0)
5b12334d
LP
346 return r;
347
309a29df 348 r = sd_bus_creds_get_session(creds, &name);
5b12334d
LP
349 if (r < 0)
350 return r;
927b1649 351
309a29df
LP
352 session = hashmap_get(m->sessions, name);
353 if (!session)
927b1649 354 return 0;
a185c5aa 355
927b1649
LP
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
a6278b88 365 e = bus_label_unescape(p);
927b1649
LP
366 if (!e)
367 return -ENOMEM;
368
369 seat = hashmap_get(m->seats, e);
927b1649 370 }
a185c5aa 371
309a29df
LP
372 if (!seat)
373 return 0;
374
cc377381
LP
375 *found = seat;
376 return 1;
377}
a185c5aa 378
cc377381
LP
379char *seat_bus_path(Seat *s) {
380 _cleanup_free_ char *t = NULL;
a185c5aa 381
cc377381 382 assert(s);
a185c5aa 383
a6278b88 384 t = bus_label_escape(s->id);
cc377381
LP
385 if (!t)
386 return NULL;
a185c5aa 387
cc377381 388 return strappend("/org/freedesktop/login1/seat/", t);
3f49d45a
LP
389}
390
f00c3121 391int seat_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
cc377381 392 _cleanup_strv_free_ char **l = NULL;
ca56b0a6 393 sd_bus_message *message;
3f49d45a 394 Manager *m = userdata;
cc377381
LP
395 Seat *seat;
396 Iterator i;
3f49d45a
LP
397 int r;
398
cc377381
LP
399 assert(bus);
400 assert(path);
401 assert(nodes);
3f49d45a 402
cc377381
LP
403 HASHMAP_FOREACH(seat, m->seats, i) {
404 char *p;
3f49d45a 405
cc377381
LP
406 p = seat_bus_path(seat);
407 if (!p)
408 return -ENOMEM;
3f49d45a 409
6e18964d
ZJS
410 r = strv_consume(&l, p);
411 if (r < 0)
cc377381 412 return r;
3f49d45a
LP
413 }
414
ca56b0a6
DH
415 message = sd_bus_get_current_message(bus);
416 if (message) {
4afd3348 417 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
ca56b0a6
DH
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 }
b298e984 434
cc377381
LP
435 *nodes = l;
436 l = NULL;
3f49d45a 437
cc377381 438 return 1;
3f49d45a 439}
da119395
LP
440
441int seat_send_signal(Seat *s, bool new_seat) {
ce0fc5f5 442 _cleanup_free_ char *p = NULL;
da119395
LP
443
444 assert(s);
445
da119395
LP
446 p = seat_bus_path(s);
447 if (!p)
4654e558 448 return -ENOMEM;
da119395 449
cc377381
LP
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);
da119395 456}
9418f147 457
cc377381 458int seat_send_changed(Seat *s, const char *properties, ...) {
ce0fc5f5 459 _cleanup_free_ char *p = NULL;
cc377381 460 char **l;
9418f147
LP
461
462 assert(s);
463
ed18b08b
LP
464 if (!s->started)
465 return 0;
466
9418f147
LP
467 p = seat_bus_path(s);
468 if (!p)
469 return -ENOMEM;
470
cc377381 471 l = strv_from_stdarg_alloca(properties);
9418f147 472
cc377381 473 return sd_bus_emit_properties_changed_strv(s->manager->bus, p, "org.freedesktop.login1.Seat", l);
9418f147 474}