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=\"ControlGroupPath\" 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=\"Controllers\" type=\"as\" access=\"read\"/>\n" \
63 " <property name=\"ResetControllers\" type=\"as\" access=\"read\"/>\n" \
64 " <property name=\"KillProcesses\" type=\"b\" access=\"read\"/>\n" \
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" \
70 #define INTROSPECTION \
71 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
73 BUS_SESSION_INTERFACE \
74 BUS_PROPERTIES_INTERFACE \
76 BUS_INTROSPECTABLE_INTERFACE \
79 #define INTERFACES_LIST \
80 BUS_GENERIC_INTERFACES_LIST \
81 "org.freedesktop.login1.Session\0"
83 static int bus_session_append_seat(DBusMessageIter *i, const char *property, void *data) {
86 const char *id, *path;
93 if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
98 path = p = seat_bus_path(s->seat);
107 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &id) ||
108 !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &path)) {
115 if (!dbus_message_iter_close_container(i, &sub))
121 static int bus_session_append_user(DBusMessageIter *i, const char *property, void *data) {
130 if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
133 p = user_bus_path(u);
137 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT32, &u->uid) ||
138 !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p)) {
145 if (!dbus_message_iter_close_container(i, &sub))
151 static int bus_session_append_active(DBusMessageIter *i, const char *property, void *data) {
159 b = session_is_active(s);
160 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
166 static int bus_session_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
174 b = session_get_idle_hint(s, NULL) > 0;
175 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
181 static int bus_session_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
190 session_get_idle_hint(s, &t);
191 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
193 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
199 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_session_append_type, session_type, SessionType);
200 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_session_append_class, session_class, SessionClass);
202 static int get_session_for_path(Manager *m, const char *path, Session **_s) {
210 if (!startswith(path, "/org/freedesktop/login1/session/"))
213 id = bus_path_unescape(path + 32);
217 s = hashmap_get(m->sessions, id);
227 static const BusProperty bus_login_session_properties[] = {
228 { "Id", bus_property_append_string, "s", offsetof(Session, id), true },
229 { "Timestamp", bus_property_append_usec, "t", offsetof(Session, timestamp.realtime) },
230 { "TimestampMonotonic", bus_property_append_usec, "t", offsetof(Session, timestamp.monotonic) },
231 { "ControlGroupPath", bus_property_append_string, "s", offsetof(Session, cgroup_path), true },
232 { "VTNr", bus_property_append_uint32, "u", offsetof(Session, vtnr) },
233 { "Seat", bus_session_append_seat, "(so)", 0 },
234 { "TTY", bus_property_append_string, "s", offsetof(Session, tty), true },
235 { "Display", bus_property_append_string, "s", offsetof(Session, display), true },
236 { "Remote", bus_property_append_bool, "b", offsetof(Session, remote) },
237 { "RemoteUser", bus_property_append_string, "s", offsetof(Session, remote_user), true },
238 { "RemoteHost", bus_property_append_string, "s", offsetof(Session, remote_host), true },
239 { "Service", bus_property_append_string, "s", offsetof(Session, service), true },
240 { "Leader", bus_property_append_pid, "u", offsetof(Session, leader) },
241 { "Audit", bus_property_append_uint32, "u", offsetof(Session, audit_id) },
242 { "Type", bus_session_append_type, "s", offsetof(Session, type) },
243 { "Class", bus_session_append_class, "s", offsetof(Session, class) },
244 { "Active", bus_session_append_active, "b", 0 },
245 { "Controllers", bus_property_append_strv, "as", offsetof(Session, controllers), true },
246 { "ResetControllers", bus_property_append_strv, "as", offsetof(Session, reset_controllers), true },
247 { "KillProcesses", bus_property_append_bool, "b", offsetof(Session, kill_processes) },
248 { "IdleHint", bus_session_append_idle_hint, "b", 0 },
249 { "IdleSinceHint", bus_session_append_idle_hint_since, "t", 0 },
250 { "IdleSinceHintMonotonic", bus_session_append_idle_hint_since, "t", 0 },
254 static const BusProperty bus_login_session_user_properties[] = {
255 { "User", bus_session_append_user, "(uo)", 0 },
256 { "Name", bus_property_append_string, "s", offsetof(User, name), true },
260 static DBusHandlerResult session_message_dispatch(
262 DBusConnection *connection,
263 DBusMessage *message) {
266 DBusMessage *reply = NULL;
273 dbus_error_init(&error);
275 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Terminate")) {
279 return bus_send_error_reply(connection, message, NULL, r);
281 reply = dbus_message_new_method_return(message);
285 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Activate")) {
287 r = session_activate(s);
289 return bus_send_error_reply(connection, message, NULL, r);
291 reply = dbus_message_new_method_return(message);
295 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Lock") ||
296 dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Unlock")) {
298 if (session_send_lock(s, streq(dbus_message_get_member(message), "Lock")) < 0)
301 reply = dbus_message_new_method_return(message);
305 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "SetIdleHint")) {
309 if (!dbus_message_get_args(
312 DBUS_TYPE_BOOLEAN, &b,
314 return bus_send_error_reply(connection, message, &error, -EINVAL);
316 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), &error);
317 if (ul == (unsigned long) -1)
318 return bus_send_error_reply(connection, message, &error, -EIO);
320 if (ul != 0 && ul != s->user->uid)
321 return bus_send_error_reply(connection, message, NULL, -EPERM);
323 session_set_idle_hint(s, b);
325 reply = dbus_message_new_method_return(message);
329 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Session", "Kill")) {
334 if (!dbus_message_get_args(
337 DBUS_TYPE_STRING, &swho,
338 DBUS_TYPE_INT32, &signo,
340 return bus_send_error_reply(connection, message, &error, -EINVAL);
345 who = kill_who_from_string(swho);
347 return bus_send_error_reply(connection, message, &error, -EINVAL);
350 if (signo <= 0 || signo >= _NSIG)
351 return bus_send_error_reply(connection, message, &error, -EINVAL);
353 r = session_kill(s, who, signo);
355 return bus_send_error_reply(connection, message, NULL, r);
357 reply = dbus_message_new_method_return(message);
362 const BusBoundProperties bps[] = {
363 { "org.freedesktop.login1.Session", bus_login_session_properties, s },
364 { "org.freedesktop.login1.Session", bus_login_session_user_properties, s->user },
367 return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, bps);
371 if (!dbus_connection_send(connection, reply, NULL))
374 dbus_message_unref(reply);
377 return DBUS_HANDLER_RESULT_HANDLED;
381 dbus_message_unref(reply);
383 dbus_error_free(&error);
385 return DBUS_HANDLER_RESULT_NEED_MEMORY;
388 static DBusHandlerResult session_message_handler(
389 DBusConnection *connection,
390 DBusMessage *message,
393 Manager *m = userdata;
397 r = get_session_for_path(m, dbus_message_get_path(message), &s);
401 return DBUS_HANDLER_RESULT_NEED_MEMORY;
407 dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown session");
408 return bus_send_error_reply(connection, message, &e, r);
411 return bus_send_error_reply(connection, message, NULL, r);
414 return session_message_dispatch(s, connection, message);
417 const DBusObjectPathVTable bus_session_vtable = {
418 .message_function = session_message_handler
421 char *session_bus_path(Session *s) {
426 t = bus_path_escape(s->id);
430 r = strappend("/org/freedesktop/login1/session/", t);
436 int session_send_signal(Session *s, bool new_session) {
443 m = dbus_message_new_signal("/org/freedesktop/login1",
444 "org.freedesktop.login1.Manager",
445 new_session ? "SessionNew" : "SessionRemoved");
450 p = session_bus_path(s);
454 if (!dbus_message_append_args(
456 DBUS_TYPE_STRING, &s->id,
457 DBUS_TYPE_OBJECT_PATH, &p,
461 if (!dbus_connection_send(s->manager->bus, m, NULL))
467 dbus_message_unref(m);
473 int session_send_changed(Session *s, const char *properties) {
483 p = session_bus_path(s);
487 m = bus_properties_changed_new(p, "org.freedesktop.login1.Session", properties);
491 if (!dbus_connection_send(s->manager->bus, m, NULL))
498 dbus_message_unref(m);
504 int session_send_lock(Session *s, bool lock) {
511 p = session_bus_path(s);
515 m = dbus_message_new_signal(p, "org.freedesktop.login1.Session", lock ? "Lock" : "Unlock");
521 b = dbus_connection_send(s->manager->bus, m, NULL);
522 dbus_message_unref(m);