]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/logind-seat-dbus.c
logind: always kill session when termination is requested
[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 #include <sys/capability.h>
25
26 #include "util.h"
27 #include "bus-util.h"
28 #include "strv.h"
29 #include "bus-errors.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 static int method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
197 Seat *s = userdata;
198 int r;
199
200 assert(bus);
201 assert(message);
202 assert(s);
203
204 r = seat_stop_sessions(s, true);
205 if (r < 0)
206 return r;
207
208 return sd_bus_reply_method_return(message, NULL);
209 }
210
211 static int method_activate_session(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
212 Seat *s = userdata;
213 const char *name;
214 Session *session;
215 int r;
216
217 assert(bus);
218 assert(message);
219 assert(s);
220
221 r = sd_bus_message_read(message, "s", &name);
222 if (r < 0)
223 return r;
224
225 session = hashmap_get(s->manager->sessions, name);
226 if (!session)
227 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
228
229 if (session->seat != s)
230 return sd_bus_error_setf(error, BUS_ERROR_SESSION_NOT_ON_SEAT, "Session %s not on seat %s", name, s->id);
231
232 r = session_activate(session);
233 if (r < 0)
234 return r;
235
236 return sd_bus_reply_method_return(message, NULL);
237 }
238
239 static int method_switch_to(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
240 Seat *s = userdata;
241 unsigned int to;
242 int r;
243
244 assert(bus);
245 assert(message);
246 assert(s);
247
248 r = sd_bus_message_read(message, "u", &to);
249 if (r < 0)
250 return r;
251
252 if (to <= 0)
253 return -EINVAL;
254
255 r = seat_switch_to(s, to);
256 if (r < 0)
257 return r;
258
259 return sd_bus_reply_method_return(message, NULL);
260 }
261
262 static int method_switch_to_next(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
263 Seat *s = userdata;
264 int r;
265
266 assert(bus);
267 assert(message);
268 assert(s);
269
270 r = seat_switch_to_next(s);
271 if (r < 0)
272 return r;
273
274 return sd_bus_reply_method_return(message, NULL);
275 }
276
277 static int method_switch_to_previous(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
278 Seat *s = userdata;
279 int r;
280
281 assert(bus);
282 assert(message);
283 assert(s);
284
285 r = seat_switch_to_previous(s);
286 if (r < 0)
287 return r;
288
289 return sd_bus_reply_method_return(message, NULL);
290 }
291
292 const sd_bus_vtable seat_vtable[] = {
293 SD_BUS_VTABLE_START(0),
294
295 SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Seat, id), SD_BUS_VTABLE_PROPERTY_CONST),
296 SD_BUS_PROPERTY("ActiveSession", "(so)", property_get_active_session, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
297 SD_BUS_PROPERTY("CanMultiSession", "b", property_get_can_multi_session, 0, SD_BUS_VTABLE_PROPERTY_CONST),
298 SD_BUS_PROPERTY("CanTTY", "b", property_get_can_tty, 0, SD_BUS_VTABLE_PROPERTY_CONST),
299 SD_BUS_PROPERTY("CanGraphical", "b", property_get_can_graphical, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
300 SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
301 SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
302 SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
303 SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
304
305 SD_BUS_METHOD("Terminate", NULL, NULL, method_terminate, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
306 SD_BUS_METHOD("ActivateSession", "s", NULL, method_activate_session, SD_BUS_VTABLE_UNPRIVILEGED),
307 SD_BUS_METHOD("SwitchTo", "u", NULL, method_switch_to, SD_BUS_VTABLE_UNPRIVILEGED),
308 SD_BUS_METHOD("SwitchToNext", NULL, NULL, method_switch_to_next, SD_BUS_VTABLE_UNPRIVILEGED),
309 SD_BUS_METHOD("SwitchToPrevious", NULL, NULL, method_switch_to_previous, SD_BUS_VTABLE_UNPRIVILEGED),
310
311 SD_BUS_VTABLE_END
312 };
313
314 int seat_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
315 Manager *m = userdata;
316 Seat *seat;
317 int r;
318
319 assert(bus);
320 assert(path);
321 assert(interface);
322 assert(found);
323 assert(m);
324
325 if (streq(path, "/org/freedesktop/login1/seat/self")) {
326 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
327 sd_bus_message *message;
328 Session *session;
329 pid_t pid;
330
331 message = sd_bus_get_current(bus);
332 if (!message)
333 return 0;
334
335 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
336 if (r < 0)
337 return r;
338
339 r = sd_bus_creds_get_pid(creds, &pid);
340 if (r < 0)
341 return r;
342
343 r = manager_get_session_by_pid(m, pid, &session);
344 if (r <= 0)
345 return 0;
346
347 if (!session->seat)
348 return 0;
349
350 seat = session->seat;
351 } else {
352 _cleanup_free_ char *e = NULL;
353 const char *p;
354
355 p = startswith(path, "/org/freedesktop/login1/seat/");
356 if (!p)
357 return 0;
358
359 e = sd_bus_label_unescape(p);
360 if (!e)
361 return -ENOMEM;
362
363 seat = hashmap_get(m->seats, e);
364 if (!seat)
365 return 0;
366 }
367
368 *found = seat;
369 return 1;
370 }
371
372 char *seat_bus_path(Seat *s) {
373 _cleanup_free_ char *t = NULL;
374
375 assert(s);
376
377 t = sd_bus_label_escape(s->id);
378 if (!t)
379 return NULL;
380
381 return strappend("/org/freedesktop/login1/seat/", t);
382 }
383
384 int seat_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
385 _cleanup_strv_free_ char **l = NULL;
386 Manager *m = userdata;
387 Seat *seat;
388 Iterator i;
389 int r;
390
391 assert(bus);
392 assert(path);
393 assert(nodes);
394
395 HASHMAP_FOREACH(seat, m->seats, i) {
396 char *p;
397
398 p = seat_bus_path(seat);
399 if (!p)
400 return -ENOMEM;
401
402 r = strv_push(&l, p);
403 if (r < 0) {
404 free(p);
405 return r;
406 }
407 }
408
409 *nodes = l;
410 l = NULL;
411
412 return 1;
413 }
414
415 int seat_send_signal(Seat *s, bool new_seat) {
416 _cleanup_free_ char *p = NULL;
417
418 assert(s);
419
420 p = seat_bus_path(s);
421 if (!p)
422 return -ENOMEM;
423
424 return sd_bus_emit_signal(
425 s->manager->bus,
426 "/org/freedesktop/login1",
427 "org.freedesktop.login1.Manager",
428 new_seat ? "SeatNew" : "SeatRemoved",
429 "so", s->id, p);
430 }
431
432 int seat_send_changed(Seat *s, const char *properties, ...) {
433 _cleanup_free_ char *p = NULL;
434 char **l;
435
436 assert(s);
437
438 if (!s->started)
439 return 0;
440
441 p = seat_bus_path(s);
442 if (!p)
443 return -ENOMEM;
444
445 l = strv_from_stdarg_alloca(properties);
446
447 return sd_bus_emit_properties_changed_strv(s->manager->bus, p, "org.freedesktop.login1.Seat", l);
448 }