]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-seat-dbus.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / login / logind-seat-dbus.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
3f49d45a
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2011 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
3f49d45a
LP
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 15 Lesser General Public License for more details.
3f49d45a 16
5430f7f2 17 You should have received a copy of the GNU Lesser General Public License
3f49d45a
LP
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
21#include <errno.h>
a185c5aa 22#include <string.h>
3f49d45a 23
b5efdb8a 24#include "alloc-util.h"
96aad8d1 25#include "bus-common-errors.h"
a6278b88 26#include "bus-label.h"
ee104e11 27#include "bus-util.h"
3f49d45a 28#include "logind-seat.h"
ee104e11
LP
29#include "logind.h"
30#include "strv.h"
31#include "user-util.h"
32#include "util.h"
3f49d45a 33
cc377381
LP
34static int property_get_active_session(
35 sd_bus *bus,
36 const char *path,
37 const char *interface,
38 const char *property,
39 sd_bus_message *reply,
ebcf1f97
LP
40 void *userdata,
41 sd_bus_error *error) {
cc377381 42
7fd1b19b 43 _cleanup_free_ char *p = NULL;
cc377381 44 Seat *s = userdata;
3f49d45a 45
cc377381
LP
46 assert(bus);
47 assert(reply);
3f49d45a
LP
48 assert(s);
49
cc377381
LP
50 p = s->active ? session_bus_path(s->active) : strdup("/");
51 if (!p)
3f49d45a
LP
52 return -ENOMEM;
53
cc377381
LP
54 return sd_bus_message_append(reply, "(so)", s->active ? s->active->id : "", p);
55}
3f49d45a 56
cc377381
LP
57static int property_get_can_multi_session(
58 sd_bus *bus,
59 const char *path,
60 const char *interface,
61 const char *property,
62 sd_bus_message *reply,
ebcf1f97
LP
63 void *userdata,
64 sd_bus_error *error) {
3f49d45a 65
cc377381 66 Seat *s = userdata;
3f49d45a 67
cc377381
LP
68 assert(bus);
69 assert(reply);
70 assert(s);
3f49d45a 71
cc377381 72 return sd_bus_message_append(reply, "b", seat_can_multi_session(s));
3f49d45a
LP
73}
74
cc377381
LP
75static int property_get_can_tty(
76 sd_bus *bus,
77 const char *path,
78 const char *interface,
79 const char *property,
80 sd_bus_message *reply,
ebcf1f97
LP
81 void *userdata,
82 sd_bus_error *error) {
cc377381
LP
83
84 Seat *s = userdata;
85
86 assert(bus);
87 assert(reply);
88 assert(s);
89
90 return sd_bus_message_append(reply, "b", seat_can_tty(s));
91}
92
93static int property_get_can_graphical(
94 sd_bus *bus,
95 const char *path,
96 const char *interface,
97 const char *property,
98 sd_bus_message *reply,
ebcf1f97
LP
99 void *userdata,
100 sd_bus_error *error) {
cc377381
LP
101
102 Seat *s = userdata;
103
104 assert(bus);
105 assert(reply);
106 assert(s);
107
a0a6be9f 108 return sd_bus_message_append(reply, "b", seat_can_graphical(s));
cc377381
LP
109}
110
111static int property_get_sessions(
112 sd_bus *bus,
113 const char *path,
114 const char *interface,
115 const char *property,
116 sd_bus_message *reply,
ebcf1f97
LP
117 void *userdata,
118 sd_bus_error *error) {
cc377381
LP
119
120 Seat *s = userdata;
3f49d45a 121 Session *session;
cc377381 122 int r;
3f49d45a 123
cc377381
LP
124 assert(bus);
125 assert(reply);
3f49d45a
LP
126 assert(s);
127
cc377381
LP
128 r = sd_bus_message_open_container(reply, 'a', "(so)");
129 if (r < 0)
130 return r;
3f49d45a
LP
131
132 LIST_FOREACH(sessions_by_seat, session, s->sessions) {
7fd1b19b 133 _cleanup_free_ char *p = NULL;
3f49d45a 134
3f49d45a
LP
135 p = session_bus_path(session);
136 if (!p)
137 return -ENOMEM;
138
cc377381
LP
139 r = sd_bus_message_append(reply, "(so)", session->id, p);
140 if (r < 0)
141 return r;
3f49d45a 142
3f49d45a
LP
143 }
144
cc377381
LP
145 r = sd_bus_message_close_container(reply);
146 if (r < 0)
147 return r;
3f49d45a 148
cc377381 149 return 1;
3f49d45a
LP
150}
151
cc377381
LP
152static int property_get_idle_hint(
153 sd_bus *bus,
154 const char *path,
155 const char *interface,
156 const char *property,
157 sd_bus_message *reply,
ebcf1f97
LP
158 void *userdata,
159 sd_bus_error *error) {
f401e48c 160
cc377381 161 Seat *s = userdata;
f1a8e221 162
cc377381
LP
163 assert(bus);
164 assert(reply);
f1a8e221
LP
165 assert(s);
166
cc377381 167 return sd_bus_message_append(reply, "b", seat_get_idle_hint(s, NULL) > 0);
f1a8e221
LP
168}
169
cc377381
LP
170static int property_get_idle_since_hint(
171 sd_bus *bus,
172 const char *path,
173 const char *interface,
174 const char *property,
175 sd_bus_message *reply,
ebcf1f97
LP
176 void *userdata,
177 sd_bus_error *error) {
cc377381
LP
178
179 Seat *s = userdata;
180 dual_timestamp t;
181 uint64_t u;
182 int r;
f1a8e221 183
cc377381
LP
184 assert(bus);
185 assert(reply);
f1a8e221
LP
186 assert(s);
187
cc377381
LP
188 r = seat_get_idle_hint(s, &t);
189 if (r < 0)
190 return r;
f1a8e221 191
cc377381 192 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
f1a8e221 193
cc377381 194 return sd_bus_message_append(reply, "t", u);
f1a8e221
LP
195}
196
19070062 197int bus_seat_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
198 Seat *s = userdata;
199 int r;
a185c5aa 200
cc377381 201 assert(message);
a185c5aa
LP
202 assert(s);
203
c529695e
LP
204 r = bus_verify_polkit_async(
205 message,
206 CAP_KILL,
207 "org.freedesktop.login1.manage",
403ed0e5 208 NULL,
c529695e
LP
209 false,
210 UID_INVALID,
211 &s->manager->polkit_registry,
212 error);
213 if (r < 0)
214 return r;
215 if (r == 0)
216 return 1; /* Will call us back */
217
9bb69af4 218 r = seat_stop_sessions(s, true);
cc377381 219 if (r < 0)
ebcf1f97 220 return r;
a185c5aa 221
df2d202e 222 return sd_bus_reply_method_return(message, NULL);
a185c5aa
LP
223}
224
19070062 225static int method_activate_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
226 Seat *s = userdata;
227 const char *name;
228 Session *session;
229 int r;
a185c5aa 230
cc377381 231 assert(message);
a185c5aa
LP
232 assert(s);
233
cc377381
LP
234 r = sd_bus_message_read(message, "s", &name);
235 if (r < 0)
ebcf1f97 236 return r;
a185c5aa 237
cc377381
LP
238 session = hashmap_get(s->manager->sessions, name);
239 if (!session)
ebcf1f97 240 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
a185c5aa 241
cc377381 242 if (session->seat != s)
ebcf1f97 243 return sd_bus_error_setf(error, BUS_ERROR_SESSION_NOT_ON_SEAT, "Session %s not on seat %s", name, s->id);
a185c5aa 244
cc377381
LP
245 r = session_activate(session);
246 if (r < 0)
ebcf1f97 247 return r;
3f49d45a 248
df2d202e 249 return sd_bus_reply_method_return(message, NULL);
3f49d45a
LP
250}
251
19070062 252static int method_switch_to(sd_bus_message *message, void *userdata, sd_bus_error *error) {
49e6fdbf
DH
253 Seat *s = userdata;
254 unsigned int to;
255 int r;
256
49e6fdbf
DH
257 assert(message);
258 assert(s);
259
260 r = sd_bus_message_read(message, "u", &to);
261 if (r < 0)
262 return r;
263
264 if (to <= 0)
265 return -EINVAL;
266
267 r = seat_switch_to(s, to);
268 if (r < 0)
269 return r;
270
271 return sd_bus_reply_method_return(message, NULL);
272}
273
19070062 274static int method_switch_to_next(sd_bus_message *message, void *userdata, sd_bus_error *error) {
49e6fdbf
DH
275 Seat *s = userdata;
276 int r;
277
49e6fdbf
DH
278 assert(message);
279 assert(s);
280
281 r = seat_switch_to_next(s);
282 if (r < 0)
283 return r;
284
285 return sd_bus_reply_method_return(message, NULL);
286}
287
19070062 288static int method_switch_to_previous(sd_bus_message *message, void *userdata, sd_bus_error *error) {
49e6fdbf
DH
289 Seat *s = userdata;
290 int r;
291
49e6fdbf
DH
292 assert(message);
293 assert(s);
294
295 r = seat_switch_to_previous(s);
296 if (r < 0)
297 return r;
298
299 return sd_bus_reply_method_return(message, NULL);
300}
301
cc377381
LP
302const sd_bus_vtable seat_vtable[] = {
303 SD_BUS_VTABLE_START(0),
a185c5aa 304
556089dc 305 SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Seat, id), SD_BUS_VTABLE_PROPERTY_CONST),
cc377381 306 SD_BUS_PROPERTY("ActiveSession", "(so)", property_get_active_session, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
556089dc
LP
307 SD_BUS_PROPERTY("CanMultiSession", "b", property_get_can_multi_session, 0, SD_BUS_VTABLE_PROPERTY_CONST),
308 SD_BUS_PROPERTY("CanTTY", "b", property_get_can_tty, 0, SD_BUS_VTABLE_PROPERTY_CONST),
cc377381 309 SD_BUS_PROPERTY("CanGraphical", "b", property_get_can_graphical, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
91ab7b01 310 SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, 0),
cc377381
LP
311 SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
312 SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
313 SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
3f49d45a 314
c529695e 315 SD_BUS_METHOD("Terminate", NULL, NULL, bus_seat_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED),
adacb957 316 SD_BUS_METHOD("ActivateSession", "s", NULL, method_activate_session, SD_BUS_VTABLE_UNPRIVILEGED),
49e6fdbf
DH
317 SD_BUS_METHOD("SwitchTo", "u", NULL, method_switch_to, SD_BUS_VTABLE_UNPRIVILEGED),
318 SD_BUS_METHOD("SwitchToNext", NULL, NULL, method_switch_to_next, SD_BUS_VTABLE_UNPRIVILEGED),
319 SD_BUS_METHOD("SwitchToPrevious", NULL, NULL, method_switch_to_previous, SD_BUS_VTABLE_UNPRIVILEGED),
a185c5aa 320
cc377381
LP
321 SD_BUS_VTABLE_END
322};
a185c5aa 323
f00c3121 324int seat_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
cc377381
LP
325 Manager *m = userdata;
326 Seat *seat;
927b1649 327 int r;
a185c5aa 328
cc377381
LP
329 assert(bus);
330 assert(path);
331 assert(interface);
332 assert(found);
333 assert(m);
a185c5aa 334
927b1649
LP
335 if (streq(path, "/org/freedesktop/login1/seat/self")) {
336 sd_bus_message *message;
a185c5aa 337
19befb2d 338 message = sd_bus_get_current_message(bus);
927b1649
LP
339 if (!message)
340 return 0;
341
e4d2984b 342 r = manager_get_seat_from_creds(m, message, NULL, error, &seat);
927b1649 343 if (r < 0)
5b12334d 344 return r;
927b1649
LP
345 } else {
346 _cleanup_free_ char *e = NULL;
347 const char *p;
348
349 p = startswith(path, "/org/freedesktop/login1/seat/");
350 if (!p)
351 return 0;
352
a6278b88 353 e = bus_label_unescape(p);
927b1649
LP
354 if (!e)
355 return -ENOMEM;
356
357 seat = hashmap_get(m->seats, e);
e4d2984b
AJ
358 if (!seat)
359 return 0;
927b1649 360 }
a185c5aa 361
cc377381
LP
362 *found = seat;
363 return 1;
364}
a185c5aa 365
cc377381
LP
366char *seat_bus_path(Seat *s) {
367 _cleanup_free_ char *t = NULL;
a185c5aa 368
cc377381 369 assert(s);
a185c5aa 370
a6278b88 371 t = bus_label_escape(s->id);
cc377381
LP
372 if (!t)
373 return NULL;
a185c5aa 374
cc377381 375 return strappend("/org/freedesktop/login1/seat/", t);
3f49d45a
LP
376}
377
f00c3121 378int seat_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
cc377381 379 _cleanup_strv_free_ char **l = NULL;
ca56b0a6 380 sd_bus_message *message;
3f49d45a 381 Manager *m = userdata;
cc377381
LP
382 Seat *seat;
383 Iterator i;
3f49d45a
LP
384 int r;
385
cc377381
LP
386 assert(bus);
387 assert(path);
388 assert(nodes);
3f49d45a 389
cc377381
LP
390 HASHMAP_FOREACH(seat, m->seats, i) {
391 char *p;
3f49d45a 392
cc377381
LP
393 p = seat_bus_path(seat);
394 if (!p)
395 return -ENOMEM;
3f49d45a 396
6e18964d
ZJS
397 r = strv_consume(&l, p);
398 if (r < 0)
cc377381 399 return r;
3f49d45a
LP
400 }
401
ca56b0a6
DH
402 message = sd_bus_get_current_message(bus);
403 if (message) {
4afd3348 404 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
ca56b0a6
DH
405 const char *name;
406 Session *session;
407
408 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds);
409 if (r >= 0) {
410 r = sd_bus_creds_get_session(creds, &name);
411 if (r >= 0) {
412 session = hashmap_get(m->sessions, name);
413 if (session && session->seat) {
414 r = strv_extend(&l, "/org/freedesktop/login1/seat/self");
415 if (r < 0)
416 return r;
417 }
418 }
419 }
420 }
b298e984 421
cc377381
LP
422 *nodes = l;
423 l = NULL;
3f49d45a 424
cc377381 425 return 1;
3f49d45a 426}
da119395
LP
427
428int seat_send_signal(Seat *s, bool new_seat) {
ce0fc5f5 429 _cleanup_free_ char *p = NULL;
da119395
LP
430
431 assert(s);
432
da119395
LP
433 p = seat_bus_path(s);
434 if (!p)
4654e558 435 return -ENOMEM;
da119395 436
cc377381
LP
437 return sd_bus_emit_signal(
438 s->manager->bus,
439 "/org/freedesktop/login1",
440 "org.freedesktop.login1.Manager",
441 new_seat ? "SeatNew" : "SeatRemoved",
442 "so", s->id, p);
da119395 443}
9418f147 444
cc377381 445int seat_send_changed(Seat *s, const char *properties, ...) {
ce0fc5f5 446 _cleanup_free_ char *p = NULL;
cc377381 447 char **l;
9418f147
LP
448
449 assert(s);
450
ed18b08b
LP
451 if (!s->started)
452 return 0;
453
9418f147
LP
454 p = seat_bus_path(s);
455 if (!p)
456 return -ENOMEM;
457
cc377381 458 l = strv_from_stdarg_alloca(properties);
9418f147 459
cc377381 460 return sd_bus_emit_properties_changed_strv(s->manager->bus, p, "org.freedesktop.login1.Seat", l);
9418f147 461}