1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
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.
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.
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/>.
26 #include "logind-session.h"
27 #include "dbus-common.h"
30 #define BUS_SESSION_INTERFACE \
31 " <interface name=\"org.freedesktop.login1.Session\">\n" \
32 " <method name=\"Terminate\"/>\n" \
33 " <method name=\"Activate\"/>\n" \
34 " <method name=\"Lock\"/>\n" \
35 " <method name=\"Unlock\"/>\n" \
36 " <method name=\"SetIdleHint\">\n" \
37 " <arg name=\"b\" type=\"b\"/>\n" \
39 " <method name=\"Kill\">\n" \
40 " <arg name=\"who\" type=\"s\"/>\n" \
41 " <arg name=\"signal\" type=\"s\"/>\n" \
43 " <property name=\"Id\" type=\"s\" access=\"read\"/>\n" \
44 " <property name=\"User\" type=\"(uo)\" access=\"read\"/>\n" \
45 " <property name=\"Name\" type=\"s\" access=\"read\"/>\n" \
46 " <property name=\"Timestamp\" type=\"t\" access=\"read\"/>\n" \
47 " <property name=\"TimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
48 " <property name=\"DefaultControlGroup\" type=\"s\" access=\"read\"/>\n" \
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" \
56 " <property name=\"Service\" type=\"s\" access=\"read\"/>\n" \
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" \
60 " <property name=\"Class\" type=\"s\" access=\"read\"/>\n" \
61 " <property name=\"Active\" type=\"b\" access=\"read\"/>\n" \
62 " <property name=\"State\" type=\"s\" access=\"read\"/>\n" \
63 " <property name=\"Controllers\" type=\"as\" access=\"read\"/>\n" \
64 " <property name=\"ResetControllers\" type=\"as\" access=\"read\"/>\n" \
65 " <property name=\"KillProcesses\" type=\"b\" access=\"read\"/>\n" \
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" \
71 #define INTROSPECTION \
72 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
74 BUS_SESSION_INTERFACE \
75 BUS_PROPERTIES_INTERFACE \
77 BUS_INTROSPECTABLE_INTERFACE \
80 #define INTERFACES_LIST \
81 BUS_GENERIC_INTERFACES_LIST \
82 "org.freedesktop.login1.Session\0"
84 static int bus_session_append_seat(DBusMessageIter *i, const char *property, void *data) {
87 const char *id, *path;
94 if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
99 path = p = seat_bus_path(s->seat);
108 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &id) ||
109 !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &path)) {
116 if (!dbus_message_iter_close_container(i, &sub))
122 static int bus_session_append_user(DBusMessageIter *i, const char *property, void *data) {
131 if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
134 p = user_bus_path(u);
138 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT32, &u->uid) ||
139 !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p)) {
146 if (!dbus_message_iter_close_container(i, &sub))
152 static int bus_session_append_active(DBusMessageIter *i, const char *property, void *data) {
160 b = session_is_active(s);
161 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
167 static int bus_session_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
175 b = session_get_idle_hint(s, NULL) > 0;
176 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
182 static int bus_session_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
192 r = session_get_idle_hint(s, &t);
196 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
198 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
204 static int bus_session_append_default_cgroup(DBusMessageIter *i, const char *property, void *data) {
214 r = cg_join_spec(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, &t);
218 success = dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t);
221 return success ? 0 : -ENOMEM;
224 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_session_append_type, session_type, SessionType);
225 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_session_append_class, session_class, SessionClass);
227 static int bus_session_append_state(DBusMessageIter *i, const char *property, void *data) {
235 state = session_state_to_string(session_get_state(s));
237 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state))
243 static int get_session_for_path(Manager *m, const char *path, Session **_s) {
251 if (!startswith(path, "/org/freedesktop/login1/session/"))
254 id = bus_path_unescape(path + 32);
258 s = hashmap_get(m->sessions, id);
268 static const BusProperty bus_login_session_properties[] = {
269 { "Id", bus_property_append_string, "s", offsetof(Session, id), true },
270 { "Timestamp", bus_property_append_usec, "t", offsetof(Session, timestamp.realtime) },
271 { "TimestampMonotonic", bus_property_append_usec, "t", offsetof(Session, timestamp.monotonic) },
272 { "DefaultControlGroup", bus_session_append_default_cgroup, "s", 0, },
273 { "VTNr", bus_property_append_uint32, "u", offsetof(Session, vtnr) },
274 { "Seat", bus_session_append_seat, "(so)", 0 },
275 { "TTY", bus_property_append_string, "s", offsetof(Session, tty), true },
276 { "Display", bus_property_append_string, "s", offsetof(Session, display), true },
277 { "Remote", bus_property_append_bool, "b", offsetof(Session, remote) },
278 { "RemoteUser", bus_property_append_string, "s", offsetof(Session, remote_user), true },
279 { "RemoteHost", bus_property_append_string, "s", offsetof(Session, remote_host), true },
280 { "Service", bus_property_append_string, "s", offsetof(Session, service), true },
281 { "Leader", bus_property_append_pid, "u", offsetof(Session, leader) },
282 { "Audit", bus_property_append_uint32, "u", offsetof(Session, audit_id) },
283 { "Type", bus_session_append_type, "s", offsetof(Session, type) },
284 { "Class", bus_session_append_class, "s", offsetof(Session, class) },
285 { "Active", bus_session_append_active, "b", 0 },
286 { "State", bus_session_append_state, "s", 0 },
287 { "Controllers", bus_property_append_strv, "as", offsetof(Session, controllers), true },
288 { "ResetControllers", bus_property_append_strv, "as", offsetof(Session, reset_controllers), true },
289 { "KillProcesses", bus_property_append_bool, "b", offsetof(Session, kill_processes) },
290 { "IdleHint", bus_session_append_idle_hint, "b", 0 },
291 { "IdleSinceHint", bus_session_append_idle_hint_since, "t", 0 },
292 { "IdleSinceHintMonotonic", bus_session_append_idle_hint_since, "t", 0 },
296 static const BusProperty bus_login_session_user_properties[] = {
297 { "User", bus_session_append_user, "(uo)", 0 },
298 { "Name", bus_property_append_string, "s", offsetof(User, name), true },
302 static DBusHandlerResult session_message_dispatch(
304 DBusConnection *connection,
305 DBusMessage *message) {
308 DBusMessage *reply = NULL;
315 dbus_error_init(&error);
317 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Terminate")) {
321 return bus_send_error_reply(connection, message, NULL, r);
323 reply = dbus_message_new_method_return(message);
327 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Activate")) {
329 r = session_activate(s);
331 return bus_send_error_reply(connection, message, NULL, r);
333 reply = dbus_message_new_method_return(message);
337 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Lock") ||
338 dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Unlock")) {
340 if (session_send_lock(s, streq(dbus_message_get_member(message), "Lock")) < 0)
343 reply = dbus_message_new_method_return(message);
347 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "SetIdleHint")) {
351 if (!dbus_message_get_args(
354 DBUS_TYPE_BOOLEAN, &b,
356 return bus_send_error_reply(connection, message, &error, -EINVAL);
358 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), &error);
359 if (ul == (unsigned long) -1)
360 return bus_send_error_reply(connection, message, &error, -EIO);
362 if (ul != 0 && ul != s->user->uid)
363 return bus_send_error_reply(connection, message, NULL, -EPERM);
365 session_set_idle_hint(s, b);
367 reply = dbus_message_new_method_return(message);
371 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Kill")) {
376 if (!dbus_message_get_args(
379 DBUS_TYPE_STRING, &swho,
380 DBUS_TYPE_INT32, &signo,
382 return bus_send_error_reply(connection, message, &error, -EINVAL);
387 who = kill_who_from_string(swho);
389 return bus_send_error_reply(connection, message, &error, -EINVAL);
392 if (signo <= 0 || signo >= _NSIG)
393 return bus_send_error_reply(connection, message, &error, -EINVAL);
395 r = session_kill(s, who, signo);
397 return bus_send_error_reply(connection, message, NULL, r);
399 reply = dbus_message_new_method_return(message);
404 const BusBoundProperties bps[] = {
405 { "org.freedesktop.login1.Session", bus_login_session_properties, s },
406 { "org.freedesktop.login1.Session", bus_login_session_user_properties, s->user },
409 return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, bps);
413 if (!dbus_connection_send(connection, reply, NULL))
416 dbus_message_unref(reply);
419 return DBUS_HANDLER_RESULT_HANDLED;
423 dbus_message_unref(reply);
425 dbus_error_free(&error);
427 return DBUS_HANDLER_RESULT_NEED_MEMORY;
430 static DBusHandlerResult session_message_handler(
431 DBusConnection *connection,
432 DBusMessage *message,
435 Manager *m = userdata;
439 r = get_session_for_path(m, dbus_message_get_path(message), &s);
443 return DBUS_HANDLER_RESULT_NEED_MEMORY;
449 dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown session");
450 return bus_send_error_reply(connection, message, &e, r);
453 return bus_send_error_reply(connection, message, NULL, r);
456 return session_message_dispatch(s, connection, message);
459 const DBusObjectPathVTable bus_session_vtable = {
460 .message_function = session_message_handler
463 char *session_bus_path(Session *s) {
468 t = bus_path_escape(s->id);
472 r = strappend("/org/freedesktop/login1/session/", t);
478 int session_send_signal(Session *s, bool new_session) {
485 m = dbus_message_new_signal("/org/freedesktop/login1",
486 "org.freedesktop.login1.Manager",
487 new_session ? "SessionNew" : "SessionRemoved");
492 p = session_bus_path(s);
496 if (!dbus_message_append_args(
498 DBUS_TYPE_STRING, &s->id,
499 DBUS_TYPE_OBJECT_PATH, &p,
503 if (!dbus_connection_send(s->manager->bus, m, NULL))
509 dbus_message_unref(m);
515 int session_send_changed(Session *s, const char *properties) {
525 p = session_bus_path(s);
529 m = bus_properties_changed_new(p, "org.freedesktop.login1.Session", properties);
533 if (!dbus_connection_send(s->manager->bus, m, NULL))
540 dbus_message_unref(m);
546 int session_send_lock(Session *s, bool lock) {
553 p = session_bus_path(s);
557 m = dbus_message_new_signal(p, "org.freedesktop.login1.Session", lock ? "Lock" : "Unlock");
563 b = dbus_connection_send(s->manager->bus, m, NULL);
564 dbus_message_unref(m);