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 " <signal name=\"Lock\"/>\n" \
44 " <signal name=\"Unlock\"/>\n" \
45 " <property name=\"Id\" type=\"s\" access=\"read\"/>\n" \
46 " <property name=\"User\" type=\"(uo)\" access=\"read\"/>\n" \
47 " <property name=\"Name\" type=\"s\" access=\"read\"/>\n" \
48 " <property name=\"Timestamp\" type=\"t\" access=\"read\"/>\n" \
49 " <property name=\"TimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
50 " <property name=\"DefaultControlGroup\" type=\"s\" access=\"read\"/>\n" \
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" \
58 " <property name=\"Service\" type=\"s\" access=\"read\"/>\n" \
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" \
62 " <property name=\"Class\" type=\"s\" access=\"read\"/>\n" \
63 " <property name=\"Active\" type=\"b\" access=\"read\"/>\n" \
64 " <property name=\"State\" type=\"s\" access=\"read\"/>\n" \
65 " <property name=\"Controllers\" type=\"as\" access=\"read\"/>\n" \
66 " <property name=\"ResetControllers\" type=\"as\" access=\"read\"/>\n" \
67 " <property name=\"KillProcesses\" type=\"b\" access=\"read\"/>\n" \
68 " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
69 " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
70 " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
73 #define INTROSPECTION \
74 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
76 BUS_SESSION_INTERFACE \
77 BUS_PROPERTIES_INTERFACE \
79 BUS_INTROSPECTABLE_INTERFACE \
82 #define INTERFACES_LIST \
83 BUS_GENERIC_INTERFACES_LIST \
84 "org.freedesktop.login1.Session\0"
86 static int bus_session_append_seat(DBusMessageIter *i, const char *property, void *data) {
89 const char *id, *path;
96 if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
101 path = p = seat_bus_path(s->seat);
110 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &id) ||
111 !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &path)) {
118 if (!dbus_message_iter_close_container(i, &sub))
124 static int bus_session_append_user(DBusMessageIter *i, const char *property, void *data) {
133 if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
136 p = user_bus_path(u);
140 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT32, &u->uid) ||
141 !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p)) {
148 if (!dbus_message_iter_close_container(i, &sub))
154 static int bus_session_append_active(DBusMessageIter *i, const char *property, void *data) {
162 b = session_is_active(s);
163 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
169 static int bus_session_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
177 b = session_get_idle_hint(s, NULL) > 0;
178 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
184 static int bus_session_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
194 r = session_get_idle_hint(s, &t);
198 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
200 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
206 static int bus_session_append_default_cgroup(DBusMessageIter *i, const char *property, void *data) {
216 r = cg_join_spec(SYSTEMD_CGROUP_CONTROLLER, s->cgroup_path, &t);
220 success = dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t);
223 return success ? 0 : -ENOMEM;
226 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_session_append_type, session_type, SessionType);
227 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_session_append_class, session_class, SessionClass);
229 static int bus_session_append_state(DBusMessageIter *i, const char *property, void *data) {
237 state = session_state_to_string(session_get_state(s));
239 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state))
245 static int get_session_for_path(Manager *m, const char *path, Session **_s) {
253 if (!startswith(path, "/org/freedesktop/login1/session/"))
256 id = bus_path_unescape(path + 32);
260 s = hashmap_get(m->sessions, id);
270 static const BusProperty bus_login_session_properties[] = {
271 { "Id", bus_property_append_string, "s", offsetof(Session, id), true },
272 { "Timestamp", bus_property_append_usec, "t", offsetof(Session, timestamp.realtime) },
273 { "TimestampMonotonic", bus_property_append_usec, "t", offsetof(Session, timestamp.monotonic) },
274 { "DefaultControlGroup", bus_session_append_default_cgroup, "s", 0, },
275 { "VTNr", bus_property_append_uint32, "u", offsetof(Session, vtnr) },
276 { "Seat", bus_session_append_seat, "(so)", 0 },
277 { "TTY", bus_property_append_string, "s", offsetof(Session, tty), true },
278 { "Display", bus_property_append_string, "s", offsetof(Session, display), true },
279 { "Remote", bus_property_append_bool, "b", offsetof(Session, remote) },
280 { "RemoteUser", bus_property_append_string, "s", offsetof(Session, remote_user), true },
281 { "RemoteHost", bus_property_append_string, "s", offsetof(Session, remote_host), true },
282 { "Service", bus_property_append_string, "s", offsetof(Session, service), true },
283 { "Leader", bus_property_append_pid, "u", offsetof(Session, leader) },
284 { "Audit", bus_property_append_uint32, "u", offsetof(Session, audit_id) },
285 { "Type", bus_session_append_type, "s", offsetof(Session, type) },
286 { "Class", bus_session_append_class, "s", offsetof(Session, class) },
287 { "Active", bus_session_append_active, "b", 0 },
288 { "State", bus_session_append_state, "s", 0 },
289 { "Controllers", bus_property_append_strv, "as", offsetof(Session, controllers), true },
290 { "ResetControllers", bus_property_append_strv, "as", offsetof(Session, reset_controllers), true },
291 { "KillProcesses", bus_property_append_bool, "b", offsetof(Session, kill_processes) },
292 { "IdleHint", bus_session_append_idle_hint, "b", 0 },
293 { "IdleSinceHint", bus_session_append_idle_hint_since, "t", 0 },
294 { "IdleSinceHintMonotonic", bus_session_append_idle_hint_since, "t", 0 },
298 static const BusProperty bus_login_session_user_properties[] = {
299 { "User", bus_session_append_user, "(uo)", 0 },
300 { "Name", bus_property_append_string, "s", offsetof(User, name), true },
304 static DBusHandlerResult session_message_dispatch(
306 DBusConnection *connection,
307 DBusMessage *message) {
310 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
317 dbus_error_init(&error);
319 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Terminate")) {
323 return bus_send_error_reply(connection, message, NULL, r);
325 reply = dbus_message_new_method_return(message);
329 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Activate")) {
331 r = session_activate(s);
333 return bus_send_error_reply(connection, message, NULL, r);
335 reply = dbus_message_new_method_return(message);
339 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Lock") ||
340 dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Unlock")) {
342 if (session_send_lock(s, streq(dbus_message_get_member(message), "Lock")) < 0)
345 reply = dbus_message_new_method_return(message);
349 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "SetIdleHint")) {
353 if (!dbus_message_get_args(
356 DBUS_TYPE_BOOLEAN, &b,
358 return bus_send_error_reply(connection, message, &error, -EINVAL);
360 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), &error);
361 if (ul == (unsigned long) -1)
362 return bus_send_error_reply(connection, message, &error, -EIO);
364 if (ul != 0 && ul != s->user->uid)
365 return bus_send_error_reply(connection, message, NULL, -EPERM);
367 session_set_idle_hint(s, b);
369 reply = dbus_message_new_method_return(message);
373 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Kill")) {
378 if (!dbus_message_get_args(
381 DBUS_TYPE_STRING, &swho,
382 DBUS_TYPE_INT32, &signo,
384 return bus_send_error_reply(connection, message, &error, -EINVAL);
389 who = kill_who_from_string(swho);
391 return bus_send_error_reply(connection, message, &error, -EINVAL);
394 if (signo <= 0 || signo >= _NSIG)
395 return bus_send_error_reply(connection, message, &error, -EINVAL);
397 r = session_kill(s, who, signo);
399 return bus_send_error_reply(connection, message, NULL, r);
401 reply = dbus_message_new_method_return(message);
406 const BusBoundProperties bps[] = {
407 { "org.freedesktop.login1.Session", bus_login_session_properties, s },
408 { "org.freedesktop.login1.Session", bus_login_session_user_properties, s->user },
411 return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, bps);
415 if (!bus_maybe_send_reply(connection, message, reply))
419 return DBUS_HANDLER_RESULT_HANDLED;
422 dbus_error_free(&error);
424 return DBUS_HANDLER_RESULT_NEED_MEMORY;
427 static DBusHandlerResult session_message_handler(
428 DBusConnection *connection,
429 DBusMessage *message,
432 Manager *m = userdata;
436 r = get_session_for_path(m, dbus_message_get_path(message), &s);
440 return DBUS_HANDLER_RESULT_NEED_MEMORY;
446 dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown session");
447 return bus_send_error_reply(connection, message, &e, r);
450 return bus_send_error_reply(connection, message, NULL, r);
453 return session_message_dispatch(s, connection, message);
456 const DBusObjectPathVTable bus_session_vtable = {
457 .message_function = session_message_handler
460 char *session_bus_path(Session *s) {
465 t = bus_path_escape(s->id);
469 r = strappend("/org/freedesktop/login1/session/", t);
475 int session_send_signal(Session *s, bool new_session) {
476 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
478 _cleanup_free_ char *p = NULL;
482 m = dbus_message_new_signal("/org/freedesktop/login1",
483 "org.freedesktop.login1.Manager",
484 new_session ? "SessionNew" : "SessionRemoved");
489 p = session_bus_path(s);
493 if (!dbus_message_append_args(
495 DBUS_TYPE_STRING, &s->id,
496 DBUS_TYPE_OBJECT_PATH, &p,
500 if (!dbus_connection_send(s->manager->bus, m, NULL))
509 int session_send_changed(Session *s, const char *properties) {
510 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
512 _cleanup_free_ char *p = NULL;
519 p = session_bus_path(s);
523 m = bus_properties_changed_new(p, "org.freedesktop.login1.Session", properties);
527 if (!dbus_connection_send(s->manager->bus, m, NULL))
536 int session_send_lock(Session *s, bool lock) {
537 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
539 _cleanup_free_ char *p = NULL;
543 p = session_bus_path(s);
547 m = dbus_message_new_signal(p, "org.freedesktop.login1.Session", lock ? "Lock" : "Unlock");
552 b = dbus_connection_send(s->manager->bus, m, NULL);
559 int session_send_lock_all(Manager *m, bool lock) {
566 HASHMAP_FOREACH(session, m->sessions, i) {
569 k = session_send_lock(session, lock);