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) {
191 session_get_idle_hint(s, &t);
192 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
194 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
200 static int bus_session_append_default_cgroup(DBusMessageIter *i, const char *property, void *data) {
210 r = cg_join_spec(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, &t);
214 success = dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t);
217 return success ? 0 : -ENOMEM;
220 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_session_append_type, session_type, SessionType);
221 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_session_append_class, session_class, SessionClass);
223 static int bus_session_append_state(DBusMessageIter *i, const char *property, void *data) {
231 state = session_state_to_string(session_get_state(s));
233 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state))
239 static int get_session_for_path(Manager *m, const char *path, Session **_s) {
247 if (!startswith(path, "/org/freedesktop/login1/session/"))
250 id = bus_path_unescape(path + 32);
254 s = hashmap_get(m->sessions, id);
264 static const BusProperty bus_login_session_properties[] = {
265 { "Id", bus_property_append_string, "s", offsetof(Session, id), true },
266 { "Timestamp", bus_property_append_usec, "t", offsetof(Session, timestamp.realtime) },
267 { "TimestampMonotonic", bus_property_append_usec, "t", offsetof(Session, timestamp.monotonic) },
268 { "DefaultControlGroup", bus_session_append_default_cgroup, "s", 0, },
269 { "VTNr", bus_property_append_uint32, "u", offsetof(Session, vtnr) },
270 { "Seat", bus_session_append_seat, "(so)", 0 },
271 { "TTY", bus_property_append_string, "s", offsetof(Session, tty), true },
272 { "Display", bus_property_append_string, "s", offsetof(Session, display), true },
273 { "Remote", bus_property_append_bool, "b", offsetof(Session, remote) },
274 { "RemoteUser", bus_property_append_string, "s", offsetof(Session, remote_user), true },
275 { "RemoteHost", bus_property_append_string, "s", offsetof(Session, remote_host), true },
276 { "Service", bus_property_append_string, "s", offsetof(Session, service), true },
277 { "Leader", bus_property_append_pid, "u", offsetof(Session, leader) },
278 { "Audit", bus_property_append_uint32, "u", offsetof(Session, audit_id) },
279 { "Type", bus_session_append_type, "s", offsetof(Session, type) },
280 { "Class", bus_session_append_class, "s", offsetof(Session, class) },
281 { "Active", bus_session_append_active, "b", 0 },
282 { "State", bus_session_append_state, "s", 0 },
283 { "Controllers", bus_property_append_strv, "as", offsetof(Session, controllers), true },
284 { "ResetControllers", bus_property_append_strv, "as", offsetof(Session, reset_controllers), true },
285 { "KillProcesses", bus_property_append_bool, "b", offsetof(Session, kill_processes) },
286 { "IdleHint", bus_session_append_idle_hint, "b", 0 },
287 { "IdleSinceHint", bus_session_append_idle_hint_since, "t", 0 },
288 { "IdleSinceHintMonotonic", bus_session_append_idle_hint_since, "t", 0 },
292 static const BusProperty bus_login_session_user_properties[] = {
293 { "User", bus_session_append_user, "(uo)", 0 },
294 { "Name", bus_property_append_string, "s", offsetof(User, name), true },
298 static DBusHandlerResult session_message_dispatch(
300 DBusConnection *connection,
301 DBusMessage *message) {
304 DBusMessage *reply = NULL;
311 dbus_error_init(&error);
313 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Terminate")) {
317 return bus_send_error_reply(connection, message, NULL, r);
319 reply = dbus_message_new_method_return(message);
323 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Activate")) {
325 r = session_activate(s);
327 return bus_send_error_reply(connection, message, NULL, r);
329 reply = dbus_message_new_method_return(message);
333 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Lock") ||
334 dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Unlock")) {
336 if (session_send_lock(s, streq(dbus_message_get_member(message), "Lock")) < 0)
339 reply = dbus_message_new_method_return(message);
343 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "SetIdleHint")) {
347 if (!dbus_message_get_args(
350 DBUS_TYPE_BOOLEAN, &b,
352 return bus_send_error_reply(connection, message, &error, -EINVAL);
354 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), &error);
355 if (ul == (unsigned long) -1)
356 return bus_send_error_reply(connection, message, &error, -EIO);
358 if (ul != 0 && ul != s->user->uid)
359 return bus_send_error_reply(connection, message, NULL, -EPERM);
361 session_set_idle_hint(s, b);
363 reply = dbus_message_new_method_return(message);
367 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Kill")) {
372 if (!dbus_message_get_args(
375 DBUS_TYPE_STRING, &swho,
376 DBUS_TYPE_INT32, &signo,
378 return bus_send_error_reply(connection, message, &error, -EINVAL);
383 who = kill_who_from_string(swho);
385 return bus_send_error_reply(connection, message, &error, -EINVAL);
388 if (signo <= 0 || signo >= _NSIG)
389 return bus_send_error_reply(connection, message, &error, -EINVAL);
391 r = session_kill(s, who, signo);
393 return bus_send_error_reply(connection, message, NULL, r);
395 reply = dbus_message_new_method_return(message);
400 const BusBoundProperties bps[] = {
401 { "org.freedesktop.login1.Session", bus_login_session_properties, s },
402 { "org.freedesktop.login1.Session", bus_login_session_user_properties, s->user },
405 return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, bps);
409 if (!dbus_connection_send(connection, reply, NULL))
412 dbus_message_unref(reply);
415 return DBUS_HANDLER_RESULT_HANDLED;
419 dbus_message_unref(reply);
421 dbus_error_free(&error);
423 return DBUS_HANDLER_RESULT_NEED_MEMORY;
426 static DBusHandlerResult session_message_handler(
427 DBusConnection *connection,
428 DBusMessage *message,
431 Manager *m = userdata;
435 r = get_session_for_path(m, dbus_message_get_path(message), &s);
439 return DBUS_HANDLER_RESULT_NEED_MEMORY;
445 dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown session");
446 return bus_send_error_reply(connection, message, &e, r);
449 return bus_send_error_reply(connection, message, NULL, r);
452 return session_message_dispatch(s, connection, message);
455 const DBusObjectPathVTable bus_session_vtable = {
456 .message_function = session_message_handler
459 char *session_bus_path(Session *s) {
464 t = bus_path_escape(s->id);
468 r = strappend("/org/freedesktop/login1/session/", t);
474 int session_send_signal(Session *s, bool new_session) {
481 m = dbus_message_new_signal("/org/freedesktop/login1",
482 "org.freedesktop.login1.Manager",
483 new_session ? "SessionNew" : "SessionRemoved");
488 p = session_bus_path(s);
492 if (!dbus_message_append_args(
494 DBUS_TYPE_STRING, &s->id,
495 DBUS_TYPE_OBJECT_PATH, &p,
499 if (!dbus_connection_send(s->manager->bus, m, NULL))
505 dbus_message_unref(m);
511 int session_send_changed(Session *s, const char *properties) {
521 p = session_bus_path(s);
525 m = bus_properties_changed_new(p, "org.freedesktop.login1.Session", properties);
529 if (!dbus_connection_send(s->manager->bus, m, NULL))
536 dbus_message_unref(m);
542 int session_send_lock(Session *s, bool lock) {
549 p = session_bus_path(s);
553 m = dbus_message_new_signal(p, "org.freedesktop.login1.Session", lock ? "Lock" : "Unlock");
559 b = dbus_connection_send(s->manager->bus, m, NULL);
560 dbus_message_unref(m);