]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-session-dbus.c
systemctl: show main and control PID explicitly in cgroup-show
[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" \
e3e9cc80 43 " <property name=\"Id\" type=\"s\" access=\"read\"/>\n" \
3f49d45a
LP
44 " <property name=\"User\" type=\"(uo)\" access=\"read\"/>\n" \
45 " <property name=\"Name\" type=\"s\" access=\"read\"/>\n" \
f401e48c
LP
46 " <property name=\"Timestamp\" type=\"t\" access=\"read\"/>\n" \
47 " <property name=\"TimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
b69d29ce 48 " <property name=\"DefaultControlGroup\" type=\"s\" access=\"read\"/>\n" \
3f49d45a
LP
49 " <property name=\"VTNr\" type=\"u\" access=\"read\"/>\n" \
50 " <property name=\"Seat\" type=\"(so)\" access=\"read\"/>\n" \
51 " <property name=\"TTY\" type=\"s\" access=\"read\"/>\n" \
52 " <property name=\"Display\" type=\"s\" access=\"read\"/>\n" \
53 " <property name=\"Remote\" type=\"b\" access=\"read\"/>\n" \
54 " <property name=\"RemoteHost\" type=\"s\" access=\"read\"/>\n" \
55 " <property name=\"RemoteUser\" type=\"s\" access=\"read\"/>\n" \
98a28fef 56 " <property name=\"Service\" type=\"s\" access=\"read\"/>\n" \
3f49d45a
LP
57 " <property name=\"Leader\" type=\"u\" access=\"read\"/>\n" \
58 " <property name=\"Audit\" type=\"u\" access=\"read\"/>\n" \
59 " <property name=\"Type\" type=\"s\" access=\"read\"/>\n" \
55efac6c 60 " <property name=\"Class\" type=\"s\" access=\"read\"/>\n" \
3f49d45a
LP
61 " <property name=\"Active\" type=\"b\" access=\"read\"/>\n" \
62 " <property name=\"Controllers\" type=\"as\" access=\"read\"/>\n" \
63 " <property name=\"ResetControllers\" type=\"as\" access=\"read\"/>\n" \
64 " <property name=\"KillProcesses\" type=\"b\" access=\"read\"/>\n" \
f401e48c
LP
65 " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
66 " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
67 " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
3f49d45a
LP
68 " </interface>\n"
69
70#define INTROSPECTION \
71 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
72 "<node>\n" \
73 BUS_SESSION_INTERFACE \
74 BUS_PROPERTIES_INTERFACE \
75 BUS_PEER_INTERFACE \
76 BUS_INTROSPECTABLE_INTERFACE \
77 "</node>\n"
78
79#define INTERFACES_LIST \
80 BUS_GENERIC_INTERFACES_LIST \
81 "org.freedesktop.login1.Session\0"
82
83static int bus_session_append_seat(DBusMessageIter *i, const char *property, void *data) {
84 DBusMessageIter sub;
85 Session *s = data;
86 const char *id, *path;
87 char *p = NULL;
88
89 assert(i);
90 assert(property);
91 assert(s);
92
93 if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
94 return -ENOMEM;
95
96 if (s->seat) {
97 id = s->seat->id;
98 path = p = seat_bus_path(s->seat);
99
100 if (!p)
101 return -ENOMEM;
102 } else {
103 id = "";
104 path = "/";
105 }
106
107 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &id) ||
108 !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &path)) {
109 free(p);
110 return -ENOMEM;
111 }
112
113 free(p);
114
115 if (!dbus_message_iter_close_container(i, &sub))
116 return -ENOMEM;
117
118 return 0;
119}
120
121static int bus_session_append_user(DBusMessageIter *i, const char *property, void *data) {
122 DBusMessageIter sub;
d200735e 123 User *u = data;
3f49d45a
LP
124 char *p = NULL;
125
126 assert(i);
127 assert(property);
d200735e 128 assert(u);
3f49d45a
LP
129
130 if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
131 return -ENOMEM;
132
d200735e 133 p = user_bus_path(u);
3f49d45a
LP
134 if (!p)
135 return -ENOMEM;
136
d200735e 137 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT32, &u->uid) ||
3f49d45a
LP
138 !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p)) {
139 free(p);
140 return -ENOMEM;
141 }
142
143 free(p);
144
145 if (!dbus_message_iter_close_container(i, &sub))
146 return -ENOMEM;
147
148 return 0;
149}
150
151static int bus_session_append_active(DBusMessageIter *i, const char *property, void *data) {
152 Session *s = data;
77527da0 153 dbus_bool_t b;
3f49d45a
LP
154
155 assert(i);
156 assert(property);
157 assert(s);
158
159 b = session_is_active(s);
160 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
161 return -ENOMEM;
162
163 return 0;
164}
165
a185c5aa
LP
166static int bus_session_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
167 Session *s = data;
77527da0 168 int b;
a185c5aa
LP
169
170 assert(i);
171 assert(property);
172 assert(s);
173
77527da0 174 b = session_get_idle_hint(s, NULL) > 0;
a185c5aa
LP
175 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
176 return -ENOMEM;
177
178 return 0;
179}
180
181static int bus_session_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
182 Session *s = data;
183 dual_timestamp t;
184 uint64_t u;
185
186 assert(i);
187 assert(property);
188 assert(s);
189
190 session_get_idle_hint(s, &t);
191 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
192
193 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
194 return -ENOMEM;
195
196 return 0;
197}
198
b69d29ce
LP
199static int bus_session_append_default_cgroup(DBusMessageIter *i, const char *property, void *data) {
200 Session *s = data;
201 char *t;
202 int r;
203 bool success;
204
205 assert(i);
206 assert(property);
207 assert(s);
208
209 r = cg_join_spec(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, &t);
210 if (r < 0)
211 return r;
212
213 success = dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t);
214 free(t);
215
216 return success ? 0 : -ENOMEM;
217}
218
3f49d45a 219static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_session_append_type, session_type, SessionType);
55efac6c 220static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_session_append_class, session_class, SessionClass);
3f49d45a
LP
221
222static int get_session_for_path(Manager *m, const char *path, Session **_s) {
223 Session *s;
224 char *id;
225
226 assert(m);
227 assert(path);
228 assert(_s);
229
230 if (!startswith(path, "/org/freedesktop/login1/session/"))
231 return -EINVAL;
232
233 id = bus_path_unescape(path + 32);
234 if (!id)
235 return -ENOMEM;
236
237 s = hashmap_get(m->sessions, id);
238 free(id);
239
240 if (!s)
241 return -ENOENT;
242
243 *_s = s;
244 return 0;
245}
246
d200735e
MS
247static const BusProperty bus_login_session_properties[] = {
248 { "Id", bus_property_append_string, "s", offsetof(Session, id), true },
249 { "Timestamp", bus_property_append_usec, "t", offsetof(Session, timestamp.realtime) },
250 { "TimestampMonotonic", bus_property_append_usec, "t", offsetof(Session, timestamp.monotonic) },
b69d29ce 251 { "DefaultControlGroup", bus_session_append_default_cgroup, "s", 0, },
d200735e
MS
252 { "VTNr", bus_property_append_uint32, "u", offsetof(Session, vtnr) },
253 { "Seat", bus_session_append_seat, "(so)", 0 },
254 { "TTY", bus_property_append_string, "s", offsetof(Session, tty), true },
255 { "Display", bus_property_append_string, "s", offsetof(Session, display), true },
256 { "Remote", bus_property_append_bool, "b", offsetof(Session, remote) },
257 { "RemoteUser", bus_property_append_string, "s", offsetof(Session, remote_user), true },
258 { "RemoteHost", bus_property_append_string, "s", offsetof(Session, remote_host), true },
259 { "Service", bus_property_append_string, "s", offsetof(Session, service), true },
260 { "Leader", bus_property_append_pid, "u", offsetof(Session, leader) },
261 { "Audit", bus_property_append_uint32, "u", offsetof(Session, audit_id) },
262 { "Type", bus_session_append_type, "s", offsetof(Session, type) },
55efac6c 263 { "Class", bus_session_append_class, "s", offsetof(Session, class) },
d200735e
MS
264 { "Active", bus_session_append_active, "b", 0 },
265 { "Controllers", bus_property_append_strv, "as", offsetof(Session, controllers), true },
266 { "ResetControllers", bus_property_append_strv, "as", offsetof(Session, reset_controllers), true },
267 { "KillProcesses", bus_property_append_bool, "b", offsetof(Session, kill_processes) },
268 { "IdleHint", bus_session_append_idle_hint, "b", 0 },
269 { "IdleSinceHint", bus_session_append_idle_hint_since, "t", 0 },
270 { "IdleSinceHintMonotonic", bus_session_append_idle_hint_since, "t", 0 },
271 { NULL, }
272};
273
274static const BusProperty bus_login_session_user_properties[] = {
275 { "User", bus_session_append_user, "(uo)", 0 },
276 { "Name", bus_property_append_string, "s", offsetof(User, name), true },
1d4ec315 277 { NULL, }
d200735e
MS
278};
279
3f49d45a
LP
280static DBusHandlerResult session_message_dispatch(
281 Session *s,
282 DBusConnection *connection,
283 DBusMessage *message) {
284
bef422ae
LP
285 DBusError error;
286 DBusMessage *reply = NULL;
287 int r;
288
3f49d45a
LP
289 assert(s);
290 assert(connection);
291 assert(message);
292
bef422ae
LP
293 dbus_error_init(&error);
294
295 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Terminate")) {
296
297 r = session_stop(s);
298 if (r < 0)
299 return bus_send_error_reply(connection, message, NULL, r);
300
301 reply = dbus_message_new_method_return(message);
302 if (!reply)
303 goto oom;
304
305 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Activate")) {
306
307 r = session_activate(s);
308 if (r < 0)
309 return bus_send_error_reply(connection, message, NULL, r);
310
311 reply = dbus_message_new_method_return(message);
312 if (!reply)
313 goto oom;
314
315 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Lock") ||
316 dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Unlock")) {
bef422ae 317
bda06175 318 if (session_send_lock(s, streq(dbus_message_get_member(message), "Lock")) < 0)
bef422ae
LP
319 goto oom;
320
321 reply = dbus_message_new_method_return(message);
322 if (!reply)
323 goto oom;
324
325 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "SetIdleHint")) {
326 dbus_bool_t b;
5bc849fd 327 unsigned long ul;
bef422ae
LP
328
329 if (!dbus_message_get_args(
330 message,
331 &error,
332 DBUS_TYPE_BOOLEAN, &b,
333 DBUS_TYPE_INVALID))
334 return bus_send_error_reply(connection, message, &error, -EINVAL);
335
5bc849fd
LP
336 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), &error);
337 if (ul == (unsigned long) -1)
338 return bus_send_error_reply(connection, message, &error, -EIO);
339
340 if (ul != 0 && ul != s->user->uid)
341 return bus_send_error_reply(connection, message, NULL, -EPERM);
342
bef422ae
LP
343 session_set_idle_hint(s, b);
344
345 reply = dbus_message_new_method_return(message);
346 if (!reply)
347 goto oom;
348
de07ab16
LP
349 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Kill")) {
350 const char *swho;
351 int32_t signo;
352 KillWho who;
353
354 if (!dbus_message_get_args(
355 message,
356 &error,
357 DBUS_TYPE_STRING, &swho,
358 DBUS_TYPE_INT32, &signo,
359 DBUS_TYPE_INVALID))
360 return bus_send_error_reply(connection, message, &error, -EINVAL);
361
362 if (isempty(swho))
363 who = KILL_ALL;
364 else {
365 who = kill_who_from_string(swho);
366 if (who < 0)
367 return bus_send_error_reply(connection, message, &error, -EINVAL);
368 }
369
370 if (signo <= 0 || signo >= _NSIG)
371 return bus_send_error_reply(connection, message, &error, -EINVAL);
372
373 r = session_kill(s, who, signo);
374 if (r < 0)
375 return bus_send_error_reply(connection, message, NULL, r);
376
377 reply = dbus_message_new_method_return(message);
378 if (!reply)
379 goto oom;
380
d200735e
MS
381 } else {
382 const BusBoundProperties bps[] = {
383 { "org.freedesktop.login1.Session", bus_login_session_properties, s },
384 { "org.freedesktop.login1.Session", bus_login_session_user_properties, s->user },
385 { NULL, }
386 };
387 return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, bps);
388 }
bef422ae
LP
389
390 if (reply) {
391 if (!dbus_connection_send(connection, reply, NULL))
392 goto oom;
393
394 dbus_message_unref(reply);
395 }
396
397 return DBUS_HANDLER_RESULT_HANDLED;
398
399oom:
400 if (reply)
401 dbus_message_unref(reply);
402
403 dbus_error_free(&error);
404
405 return DBUS_HANDLER_RESULT_NEED_MEMORY;
3f49d45a
LP
406}
407
408static DBusHandlerResult session_message_handler(
409 DBusConnection *connection,
410 DBusMessage *message,
411 void *userdata) {
412
413 Manager *m = userdata;
414 Session *s;
415 int r;
416
417 r = get_session_for_path(m, dbus_message_get_path(message), &s);
418 if (r < 0) {
419
420 if (r == -ENOMEM)
421 return DBUS_HANDLER_RESULT_NEED_MEMORY;
422
423 if (r == -ENOENT) {
424 DBusError e;
425
426 dbus_error_init(&e);
427 dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown session");
428 return bus_send_error_reply(connection, message, &e, r);
429 }
430
431 return bus_send_error_reply(connection, message, NULL, r);
432 }
433
434 return session_message_dispatch(s, connection, message);
435}
436
437const DBusObjectPathVTable bus_session_vtable = {
438 .message_function = session_message_handler
439};
440
441char *session_bus_path(Session *s) {
442 char *t, *r;
443
444 assert(s);
445
446 t = bus_path_escape(s->id);
447 if (!t)
448 return NULL;
449
450 r = strappend("/org/freedesktop/login1/session/", t);
451 free(t);
452
453 return r;
454}
da119395
LP
455
456int session_send_signal(Session *s, bool new_session) {
457 DBusMessage *m;
458 int r = -ENOMEM;
459 char *p = NULL;
460
461 assert(s);
462
463 m = dbus_message_new_signal("/org/freedesktop/login1",
464 "org.freedesktop.login1.Manager",
465 new_session ? "SessionNew" : "SessionRemoved");
466
467 if (!m)
468 return -ENOMEM;
469
470 p = session_bus_path(s);
471 if (!p)
472 goto finish;
473
474 if (!dbus_message_append_args(
475 m,
476 DBUS_TYPE_STRING, &s->id,
477 DBUS_TYPE_OBJECT_PATH, &p,
478 DBUS_TYPE_INVALID))
479 goto finish;
480
481 if (!dbus_connection_send(s->manager->bus, m, NULL))
482 goto finish;
483
484 r = 0;
485
486finish:
487 dbus_message_unref(m);
488 free(p);
489
490 return r;
491}
9418f147
LP
492
493int session_send_changed(Session *s, const char *properties) {
494 DBusMessage *m;
495 int r = -ENOMEM;
496 char *p = NULL;
497
498 assert(s);
499
ed18b08b
LP
500 if (!s->started)
501 return 0;
502
9418f147
LP
503 p = session_bus_path(s);
504 if (!p)
505 return -ENOMEM;
506
507 m = bus_properties_changed_new(p, "org.freedesktop.login1.Session", properties);
508 if (!m)
509 goto finish;
510
511 if (!dbus_connection_send(s->manager->bus, m, NULL))
512 goto finish;
513
514 r = 0;
515
516finish:
517 if (m)
518 dbus_message_unref(m);
519 free(p);
520
521 return r;
522}
88e3dc90
LP
523
524int session_send_lock(Session *s, bool lock) {
525 DBusMessage *m;
526 bool b;
527 char *p;
528
529 assert(s);
530
531 p = session_bus_path(s);
532 if (!p)
533 return -ENOMEM;
534
535 m = dbus_message_new_signal(p, "org.freedesktop.login1.Session", lock ? "Lock" : "Unlock");
536 free(p);
537
538 if (!m)
539 return -ENOMEM;
540
541 b = dbus_connection_send(s->manager->bus, m, NULL);
542 dbus_message_unref(m);
543
544 if (!b)
545 return -ENOMEM;
546
547 return 0;
548}