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