]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-session-dbus.c
logind: port over to use scopes+slices for all cgroup stuff
[thirdparty/systemd.git] / src / login / logind-session-dbus.c
CommitLineData
3f49d45a
LP
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
5430f7f2
LP
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
3f49d45a
LP
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
5430f7f2 16 Lesser General Public License for more details.
3f49d45a 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
3f49d45a
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <errno.h>
a185c5aa 23#include <string.h>
3f49d45a
LP
24
25#include "logind.h"
26#include "logind-session.h"
27#include "dbus-common.h"
28#include "util.h"
29
30#define BUS_SESSION_INTERFACE \
31 " <interface name=\"org.freedesktop.login1.Session\">\n" \
32 " <method name=\"Terminate\"/>\n" \
33 " <method name=\"Activate\"/>\n" \
f401e48c
LP
34 " <method name=\"Lock\"/>\n" \
35 " <method name=\"Unlock\"/>\n" \
36 " <method name=\"SetIdleHint\">\n" \
37 " <arg name=\"b\" type=\"b\"/>\n" \
38 " </method>\n" \
de07ab16
LP
39 " <method name=\"Kill\">\n" \
40 " <arg name=\"who\" type=\"s\"/>\n" \
41 " <arg name=\"signal\" type=\"s\"/>\n" \
42 " </method>\n" \
083f4da2
LP
43 " <signal name=\"Lock\"/>\n" \
44 " <signal name=\"Unlock\"/>\n" \
e3e9cc80 45 " <property name=\"Id\" type=\"s\" access=\"read\"/>\n" \
3f49d45a
LP
46 " <property name=\"User\" type=\"(uo)\" access=\"read\"/>\n" \
47 " <property name=\"Name\" type=\"s\" access=\"read\"/>\n" \
f401e48c
LP
48 " <property name=\"Timestamp\" type=\"t\" access=\"read\"/>\n" \
49 " <property name=\"TimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
3f49d45a
LP
50 " <property name=\"VTNr\" type=\"u\" access=\"read\"/>\n" \
51 " <property name=\"Seat\" type=\"(so)\" access=\"read\"/>\n" \
52 " <property name=\"TTY\" type=\"s\" access=\"read\"/>\n" \
53 " <property name=\"Display\" type=\"s\" access=\"read\"/>\n" \
54 " <property name=\"Remote\" type=\"b\" access=\"read\"/>\n" \
55 " <property name=\"RemoteHost\" type=\"s\" access=\"read\"/>\n" \
56 " <property name=\"RemoteUser\" type=\"s\" access=\"read\"/>\n" \
0604381b 57 " <property name=\"Service\" type=\"s\" access=\"read\"/>\n" \
fb6becb4 58 " <property name=\"Scope\" type=\"s\" access=\"read\"/>\n" \
3f49d45a
LP
59 " <property name=\"Leader\" type=\"u\" access=\"read\"/>\n" \
60 " <property name=\"Audit\" type=\"u\" access=\"read\"/>\n" \
61 " <property name=\"Type\" type=\"s\" access=\"read\"/>\n" \
0604381b 62 " <property name=\"Class\" type=\"s\" access=\"read\"/>\n" \
3f49d45a 63 " <property name=\"Active\" type=\"b\" access=\"read\"/>\n" \
0604381b 64 " <property name=\"State\" type=\"s\" access=\"read\"/>\n" \
3f49d45a 65 " <property name=\"KillProcesses\" type=\"b\" access=\"read\"/>\n" \
f401e48c
LP
66 " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
67 " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
68 " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
3f49d45a
LP
69 " </interface>\n"
70
71#define INTROSPECTION \
72 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
73 "<node>\n" \
74 BUS_SESSION_INTERFACE \
75 BUS_PROPERTIES_INTERFACE \
76 BUS_PEER_INTERFACE \
77 BUS_INTROSPECTABLE_INTERFACE \
78 "</node>\n"
79
80#define INTERFACES_LIST \
81 BUS_GENERIC_INTERFACES_LIST \
82 "org.freedesktop.login1.Session\0"
83
84static int bus_session_append_seat(DBusMessageIter *i, const char *property, void *data) {
85 DBusMessageIter sub;
86 Session *s = data;
87 const char *id, *path;
88 char *p = NULL;
89
90 assert(i);
91 assert(property);
92 assert(s);
93
94 if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
95 return -ENOMEM;
96
97 if (s->seat) {
98 id = s->seat->id;
99 path = p = seat_bus_path(s->seat);
100
101 if (!p)
102 return -ENOMEM;
103 } else {
104 id = "";
105 path = "/";
106 }
107
108 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &id) ||
4654e558 109 !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &path))
3f49d45a 110 return -ENOMEM;
3f49d45a
LP
111
112 if (!dbus_message_iter_close_container(i, &sub))
113 return -ENOMEM;
114
115 return 0;
116}
117
118static int bus_session_append_user(DBusMessageIter *i, const char *property, void *data) {
119 DBusMessageIter sub;
d200735e 120 User *u = data;
7fd1b19b 121 _cleanup_free_ char *p = NULL;
3f49d45a
LP
122
123 assert(i);
124 assert(property);
d200735e 125 assert(u);
3f49d45a
LP
126
127 if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
128 return -ENOMEM;
129
d200735e 130 p = user_bus_path(u);
3f49d45a
LP
131 if (!p)
132 return -ENOMEM;
133
d200735e 134 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT32, &u->uid) ||
4654e558 135 !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p))
3f49d45a 136 return -ENOMEM;
3f49d45a
LP
137
138 if (!dbus_message_iter_close_container(i, &sub))
139 return -ENOMEM;
140
141 return 0;
142}
143
144static int bus_session_append_active(DBusMessageIter *i, const char *property, void *data) {
145 Session *s = data;
77527da0 146 dbus_bool_t b;
3f49d45a
LP
147
148 assert(i);
149 assert(property);
150 assert(s);
151
152 b = session_is_active(s);
153 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
154 return -ENOMEM;
155
156 return 0;
157}
158
a185c5aa
LP
159static int bus_session_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
160 Session *s = data;
77527da0 161 int b;
a185c5aa
LP
162
163 assert(i);
164 assert(property);
165 assert(s);
166
77527da0 167 b = session_get_idle_hint(s, NULL) > 0;
a185c5aa
LP
168 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
169 return -ENOMEM;
170
171 return 0;
172}
173
174static int bus_session_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
175 Session *s = data;
176 dual_timestamp t;
177 uint64_t u;
ca4f2b6d 178 int r;
a185c5aa
LP
179
180 assert(i);
181 assert(property);
182 assert(s);
183
ca4f2b6d
VP
184 r = session_get_idle_hint(s, &t);
185 if (r < 0)
186 return r;
187
a185c5aa
LP
188 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
189
190 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
191 return -ENOMEM;
192
193 return 0;
194}
195
3f49d45a 196static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_session_append_type, session_type, SessionType);
55efac6c 197static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_session_append_class, session_class, SessionClass);
3f49d45a 198
0604381b
LP
199static int bus_session_append_state(DBusMessageIter *i, const char *property, void *data) {
200 Session *s = data;
201 const char *state;
202
203 assert(i);
204 assert(property);
205 assert(s);
206
207 state = session_state_to_string(session_get_state(s));
208
209 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state))
210 return -ENOMEM;
211
212 return 0;
213}
214
3f49d45a 215static int get_session_for_path(Manager *m, const char *path, Session **_s) {
9444b1f2 216 _cleanup_free_ char *id = NULL;
3f49d45a 217 Session *s;
3f49d45a
LP
218
219 assert(m);
220 assert(path);
221 assert(_s);
222
223 if (!startswith(path, "/org/freedesktop/login1/session/"))
224 return -EINVAL;
225
226 id = bus_path_unescape(path + 32);
227 if (!id)
228 return -ENOMEM;
229
230 s = hashmap_get(m->sessions, id);
3f49d45a
LP
231 if (!s)
232 return -ENOENT;
233
234 *_s = s;
235 return 0;
236}
237
d200735e
MS
238static const BusProperty bus_login_session_properties[] = {
239 { "Id", bus_property_append_string, "s", offsetof(Session, id), true },
240 { "Timestamp", bus_property_append_usec, "t", offsetof(Session, timestamp.realtime) },
241 { "TimestampMonotonic", bus_property_append_usec, "t", offsetof(Session, timestamp.monotonic) },
d200735e
MS
242 { "VTNr", bus_property_append_uint32, "u", offsetof(Session, vtnr) },
243 { "Seat", bus_session_append_seat, "(so)", 0 },
244 { "TTY", bus_property_append_string, "s", offsetof(Session, tty), true },
245 { "Display", bus_property_append_string, "s", offsetof(Session, display), true },
246 { "Remote", bus_property_append_bool, "b", offsetof(Session, remote) },
247 { "RemoteUser", bus_property_append_string, "s", offsetof(Session, remote_user), true },
248 { "RemoteHost", bus_property_append_string, "s", offsetof(Session, remote_host), true },
249 { "Service", bus_property_append_string, "s", offsetof(Session, service), true },
fb6becb4 250 { "Scope", bus_property_append_string, "s", offsetof(Session, scope), true },
d200735e
MS
251 { "Leader", bus_property_append_pid, "u", offsetof(Session, leader) },
252 { "Audit", bus_property_append_uint32, "u", offsetof(Session, audit_id) },
253 { "Type", bus_session_append_type, "s", offsetof(Session, type) },
55efac6c 254 { "Class", bus_session_append_class, "s", offsetof(Session, class) },
d200735e 255 { "Active", bus_session_append_active, "b", 0 },
0604381b 256 { "State", bus_session_append_state, "s", 0 },
d200735e
MS
257 { "IdleHint", bus_session_append_idle_hint, "b", 0 },
258 { "IdleSinceHint", bus_session_append_idle_hint_since, "t", 0 },
259 { "IdleSinceHintMonotonic", bus_session_append_idle_hint_since, "t", 0 },
260 { NULL, }
261};
262
263static const BusProperty bus_login_session_user_properties[] = {
264 { "User", bus_session_append_user, "(uo)", 0 },
265 { "Name", bus_property_append_string, "s", offsetof(User, name), true },
1d4ec315 266 { NULL, }
d200735e
MS
267};
268
3f49d45a
LP
269static DBusHandlerResult session_message_dispatch(
270 Session *s,
271 DBusConnection *connection,
272 DBusMessage *message) {
273
bef422ae 274 DBusError error;
ce0fc5f5 275 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
bef422ae
LP
276 int r;
277
3f49d45a
LP
278 assert(s);
279 assert(connection);
280 assert(message);
281
bef422ae
LP
282 dbus_error_init(&error);
283
284 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Terminate")) {
285
286 r = session_stop(s);
287 if (r < 0)
288 return bus_send_error_reply(connection, message, NULL, r);
289
290 reply = dbus_message_new_method_return(message);
291 if (!reply)
292 goto oom;
293
294 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Activate")) {
295
296 r = session_activate(s);
297 if (r < 0)
298 return bus_send_error_reply(connection, message, NULL, r);
299
300 reply = dbus_message_new_method_return(message);
301 if (!reply)
302 goto oom;
303
304 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Lock") ||
305 dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Unlock")) {
bef422ae 306
bda06175 307 if (session_send_lock(s, streq(dbus_message_get_member(message), "Lock")) < 0)
bef422ae
LP
308 goto oom;
309
310 reply = dbus_message_new_method_return(message);
311 if (!reply)
312 goto oom;
313
314 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "SetIdleHint")) {
315 dbus_bool_t b;
5bc849fd 316 unsigned long ul;
bef422ae
LP
317
318 if (!dbus_message_get_args(
319 message,
320 &error,
321 DBUS_TYPE_BOOLEAN, &b,
322 DBUS_TYPE_INVALID))
323 return bus_send_error_reply(connection, message, &error, -EINVAL);
324
5bc849fd
LP
325 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), &error);
326 if (ul == (unsigned long) -1)
327 return bus_send_error_reply(connection, message, &error, -EIO);
328
329 if (ul != 0 && ul != s->user->uid)
330 return bus_send_error_reply(connection, message, NULL, -EPERM);
331
bef422ae
LP
332 session_set_idle_hint(s, b);
333
334 reply = dbus_message_new_method_return(message);
335 if (!reply)
336 goto oom;
337
de07ab16
LP
338 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Kill")) {
339 const char *swho;
340 int32_t signo;
341 KillWho who;
342
343 if (!dbus_message_get_args(
344 message,
345 &error,
346 DBUS_TYPE_STRING, &swho,
347 DBUS_TYPE_INT32, &signo,
348 DBUS_TYPE_INVALID))
349 return bus_send_error_reply(connection, message, &error, -EINVAL);
350
351 if (isempty(swho))
352 who = KILL_ALL;
353 else {
354 who = kill_who_from_string(swho);
355 if (who < 0)
356 return bus_send_error_reply(connection, message, &error, -EINVAL);
357 }
358
359 if (signo <= 0 || signo >= _NSIG)
360 return bus_send_error_reply(connection, message, &error, -EINVAL);
361
362 r = session_kill(s, who, signo);
363 if (r < 0)
364 return bus_send_error_reply(connection, message, NULL, r);
365
366 reply = dbus_message_new_method_return(message);
367 if (!reply)
368 goto oom;
369
d200735e
MS
370 } else {
371 const BusBoundProperties bps[] = {
372 { "org.freedesktop.login1.Session", bus_login_session_properties, s },
373 { "org.freedesktop.login1.Session", bus_login_session_user_properties, s->user },
374 { NULL, }
375 };
376 return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, bps);
377 }
bef422ae
LP
378
379 if (reply) {
c6a818c8 380 if (!bus_maybe_send_reply(connection, message, reply))
bef422ae 381 goto oom;
bef422ae
LP
382 }
383
384 return DBUS_HANDLER_RESULT_HANDLED;
385
386oom:
bef422ae
LP
387 dbus_error_free(&error);
388
389 return DBUS_HANDLER_RESULT_NEED_MEMORY;
3f49d45a
LP
390}
391
392static DBusHandlerResult session_message_handler(
393 DBusConnection *connection,
394 DBusMessage *message,
395 void *userdata) {
396
397 Manager *m = userdata;
398 Session *s;
399 int r;
400
401 r = get_session_for_path(m, dbus_message_get_path(message), &s);
402 if (r < 0) {
403
404 if (r == -ENOMEM)
405 return DBUS_HANDLER_RESULT_NEED_MEMORY;
406
407 if (r == -ENOENT) {
408 DBusError e;
409
410 dbus_error_init(&e);
411 dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown session");
412 return bus_send_error_reply(connection, message, &e, r);
413 }
414
415 return bus_send_error_reply(connection, message, NULL, r);
416 }
417
418 return session_message_dispatch(s, connection, message);
419}
420
421const DBusObjectPathVTable bus_session_vtable = {
422 .message_function = session_message_handler
423};
424
425char *session_bus_path(Session *s) {
9444b1f2 426 _cleanup_free_ char *t = NULL;
3f49d45a
LP
427
428 assert(s);
429
430 t = bus_path_escape(s->id);
431 if (!t)
432 return NULL;
433
4654e558 434 return strappend("/org/freedesktop/login1/session/", t);
3f49d45a 435}
da119395
LP
436
437int session_send_signal(Session *s, bool new_session) {
ce0fc5f5 438 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
ce0fc5f5 439 _cleanup_free_ char *p = NULL;
da119395
LP
440
441 assert(s);
442
443 m = dbus_message_new_signal("/org/freedesktop/login1",
444 "org.freedesktop.login1.Manager",
445 new_session ? "SessionNew" : "SessionRemoved");
446
447 if (!m)
448 return -ENOMEM;
449
450 p = session_bus_path(s);
451 if (!p)
4654e558 452 return -ENOMEM;
da119395
LP
453
454 if (!dbus_message_append_args(
455 m,
456 DBUS_TYPE_STRING, &s->id,
457 DBUS_TYPE_OBJECT_PATH, &p,
458 DBUS_TYPE_INVALID))
4654e558 459 return -ENOMEM;
da119395
LP
460
461 if (!dbus_connection_send(s->manager->bus, m, NULL))
4654e558 462 return -ENOMEM;
da119395 463
4654e558 464 return 0;
da119395 465}
9418f147
LP
466
467int session_send_changed(Session *s, const char *properties) {
ce0fc5f5 468 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
ce0fc5f5 469 _cleanup_free_ char *p = NULL;
9418f147
LP
470
471 assert(s);
472
ed18b08b
LP
473 if (!s->started)
474 return 0;
475
9418f147
LP
476 p = session_bus_path(s);
477 if (!p)
478 return -ENOMEM;
479
480 m = bus_properties_changed_new(p, "org.freedesktop.login1.Session", properties);
481 if (!m)
4654e558 482 return -ENOMEM;
9418f147
LP
483
484 if (!dbus_connection_send(s->manager->bus, m, NULL))
4654e558 485 return -ENOMEM;
9418f147 486
4654e558 487 return 0;
9418f147 488}
88e3dc90
LP
489
490int session_send_lock(Session *s, bool lock) {
ce0fc5f5 491 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
88e3dc90 492 bool b;
ce0fc5f5 493 _cleanup_free_ char *p = NULL;
88e3dc90
LP
494
495 assert(s);
496
497 p = session_bus_path(s);
498 if (!p)
499 return -ENOMEM;
500
501 m = dbus_message_new_signal(p, "org.freedesktop.login1.Session", lock ? "Lock" : "Unlock");
88e3dc90
LP
502
503 if (!m)
504 return -ENOMEM;
505
506 b = dbus_connection_send(s->manager->bus, m, NULL);
88e3dc90
LP
507 if (!b)
508 return -ENOMEM;
509
510 return 0;
511}
7ba64386
LP
512
513int session_send_lock_all(Manager *m, bool lock) {
514 Session *session;
515 Iterator i;
516 int r = 0;
517
518 assert(m);
519
520 HASHMAP_FOREACH(session, m->sessions, i) {
521 int k;
522
523 k = session_send_lock(session, lock);
524 if (k < 0)
525 r = k;
526 }
527
528 return r;
529}
fb6becb4
LP
530
531int session_send_create_reply(Session *s, DBusError *error) {
532 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
533
534 assert(s);
535
536 if (!s->create_message)
537 return 0;
538
539 if (error) {
540 DBusError buffer;
541
542 dbus_error_init(&buffer);
543
544 if (!dbus_error_is_set(error)) {
545 dbus_set_error_const(&buffer, DBUS_ERROR_INVALID_ARGS, "Invalid Arguments");
546 error = &buffer;
547 }
548
549 reply = dbus_message_new_error(s->create_message, error->name, error->message);
550 dbus_error_free(&buffer);
551
552 if (!reply)
553 return log_oom();
554 } else {
555 _cleanup_close_ int fifo_fd = -1;
556 _cleanup_free_ char *path = NULL;
557 const char *cseat;
558 uint32_t vtnr;
559 dbus_bool_t exists;
560
561 fifo_fd = session_create_fifo(s);
562 if (fifo_fd < 0) {
563 log_error("Failed to create fifo: %s", strerror(-fifo_fd));
564 return fifo_fd;
565 }
566
567 path = session_bus_path(s);
568 if (!path)
569 return log_oom();
570
571 reply = dbus_message_new_method_return(s->create_message);
572 if (!reply)
573 return log_oom();
574
575 cseat = s->seat ? s->seat->id : "";
576 vtnr = s->vtnr;
577 exists = false;
578
579 if (!dbus_message_append_args(
580 reply,
581 DBUS_TYPE_STRING, &s->id,
582 DBUS_TYPE_OBJECT_PATH, &path,
583 DBUS_TYPE_STRING, &s->user->runtime_path,
584 DBUS_TYPE_UNIX_FD, &fifo_fd,
585 DBUS_TYPE_STRING, &cseat,
586 DBUS_TYPE_UINT32, &vtnr,
587 DBUS_TYPE_BOOLEAN, &exists,
588 DBUS_TYPE_INVALID))
589 return log_oom();
590 }
591
592 if (!dbus_connection_send(s->manager->bus, reply, NULL))
593 return log_oom();
594
595 dbus_message_unref(s->create_message);
596 s->create_message = NULL;
597
598 return 0;
599}