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/>.
28 #include "dbus-common.h"
31 #include "path-util.h"
34 #include "systemd/sd-id128.h"
35 #include "systemd/sd-messages.h"
36 #include "fileio-label.h"
39 #define BUS_MANAGER_INTERFACE \
40 " <interface name=\"org.freedesktop.login1.Manager\">\n" \
41 " <method name=\"GetSession\">\n" \
42 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
43 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
45 " <method name=\"GetSessionByPID\">\n" \
46 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
47 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
49 " <method name=\"GetUser\">\n" \
50 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
51 " <arg name=\"user\" type=\"o\" direction=\"out\"/>\n" \
53 " <method name=\"GetSeat\">\n" \
54 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
55 " <arg name=\"seat\" type=\"o\" direction=\"out\"/>\n" \
57 " <method name=\"ListSessions\">\n" \
58 " <arg name=\"sessions\" type=\"a(susso)\" direction=\"out\"/>\n" \
60 " <method name=\"ListUsers\">\n" \
61 " <arg name=\"users\" type=\"a(uso)\" direction=\"out\"/>\n" \
63 " <method name=\"ListSeats\">\n" \
64 " <arg name=\"seats\" type=\"a(so)\" direction=\"out\"/>\n" \
66 " <method name=\"CreateSession\">\n" \
67 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
68 " <arg name=\"leader\" type=\"u\" direction=\"in\"/>\n" \
69 " <arg name=\"sevice\" type=\"s\" direction=\"in\"/>\n" \
70 " <arg name=\"type\" type=\"s\" direction=\"in\"/>\n" \
71 " <arg name=\"class\" type=\"s\" direction=\"in\"/>\n" \
72 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
73 " <arg name=\"vtnr\" type=\"u\" direction=\"in\"/>\n" \
74 " <arg name=\"tty\" type=\"s\" direction=\"in\"/>\n" \
75 " <arg name=\"display\" type=\"s\" direction=\"in\"/>\n" \
76 " <arg name=\"remote\" type=\"b\" direction=\"in\"/>\n" \
77 " <arg name=\"remote_user\" type=\"s\" direction=\"in\"/>\n" \
78 " <arg name=\"remote_host\" type=\"s\" direction=\"in\"/>\n" \
79 " <arg name=\"controllers\" type=\"as\" direction=\"in\"/>\n" \
80 " <arg name=\"reset_controllers\" type=\"as\" direction=\"in\"/>\n" \
81 " <arg name=\"kill_processes\" type=\"b\" direction=\"in\"/>\n" \
82 " <arg name=\"id\" type=\"s\" direction=\"out\"/>\n" \
83 " <arg name=\"path\" type=\"o\" direction=\"out\"/>\n" \
84 " <arg name=\"runtime_path\" type=\"o\" direction=\"out\"/>\n" \
85 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
86 " <arg name=\"seat\" type=\"s\" direction=\"out\"/>\n" \
87 " <arg name=\"vtnr\" type=\"u\" direction=\"out\"/>\n" \
88 " <arg name=\"existing\" type=\"b\" direction=\"out\"/>\n" \
90 " <method name=\"ReleaseSession\">\n" \
91 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
93 " <method name=\"ActivateSession\">\n" \
94 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
96 " <method name=\"ActivateSessionOnSeat\">\n" \
97 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
98 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
100 " <method name=\"LockSession\">\n" \
101 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
103 " <method name=\"UnlockSession\">\n" \
104 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
106 " <method name=\"LockSessions\"/>\n" \
107 " <method name=\"UnlockSessions\"/>\n" \
108 " <method name=\"KillSession\">\n" \
109 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
110 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
111 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
113 " <method name=\"KillUser\">\n" \
114 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
115 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
117 " <method name=\"TerminateSession\">\n" \
118 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
120 " <method name=\"TerminateUser\">\n" \
121 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
123 " <method name=\"TerminateSeat\">\n" \
124 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
126 " <method name=\"SetUserLinger\">\n" \
127 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
128 " <arg name=\"b\" type=\"b\" direction=\"in\"/>\n" \
129 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
131 " <method name=\"AttachDevice\">\n" \
132 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
133 " <arg name=\"sysfs\" type=\"s\" direction=\"in\"/>\n" \
134 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
136 " <method name=\"FlushDevices\">\n" \
137 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
139 " <method name=\"PowerOff\">\n" \
140 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
142 " <method name=\"Reboot\">\n" \
143 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
145 " <method name=\"Suspend\">\n" \
146 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
148 " <method name=\"Hibernate\">\n" \
149 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
151 " <method name=\"HybridSleep\">\n" \
152 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
154 " <method name=\"CanPowerOff\">\n" \
155 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
157 " <method name=\"CanReboot\">\n" \
158 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
160 " <method name=\"CanSuspend\">\n" \
161 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
163 " <method name=\"CanHibernate\">\n" \
164 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
166 " <method name=\"CanHybridSleep\">\n" \
167 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
169 " <method name=\"Inhibit\">\n" \
170 " <arg name=\"what\" type=\"s\" direction=\"in\"/>\n" \
171 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
172 " <arg name=\"why\" type=\"s\" direction=\"in\"/>\n" \
173 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
174 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
176 " <method name=\"ListInhibitors\">\n" \
177 " <arg name=\"inhibitors\" type=\"a(ssssuu)\" direction=\"out\"/>\n" \
179 " <signal name=\"SessionNew\">\n" \
180 " <arg name=\"id\" type=\"s\"/>\n" \
181 " <arg name=\"path\" type=\"o\"/>\n" \
183 " <signal name=\"SessionRemoved\">\n" \
184 " <arg name=\"id\" type=\"s\"/>\n" \
185 " <arg name=\"path\" type=\"o\"/>\n" \
187 " <signal name=\"UserNew\">\n" \
188 " <arg name=\"uid\" type=\"u\"/>\n" \
189 " <arg name=\"path\" type=\"o\"/>\n" \
191 " <signal name=\"UserRemoved\">\n" \
192 " <arg name=\"uid\" type=\"u\"/>\n" \
193 " <arg name=\"path\" type=\"o\"/>\n" \
195 " <signal name=\"SeatNew\">\n" \
196 " <arg name=\"id\" type=\"s\"/>\n" \
197 " <arg name=\"path\" type=\"o\"/>\n" \
199 " <signal name=\"SeatRemoved\">\n" \
200 " <arg name=\"id\" type=\"s\"/>\n" \
201 " <arg name=\"path\" type=\"o\"/>\n" \
203 " <signal name=\"PrepareForShutdown\">\n" \
204 " <arg name=\"active\" type=\"b\"/>\n" \
206 " <signal name=\"PrepareForSleep\">\n" \
207 " <arg name=\"active\" type=\"b\"/>\n" \
209 " <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
210 " <property name=\"Controllers\" type=\"as\" access=\"read\"/>\n" \
211 " <property name=\"ResetControllers\" type=\"as\" access=\"read\"/>\n" \
212 " <property name=\"NAutoVTs\" type=\"u\" access=\"read\"/>\n" \
213 " <property name=\"KillOnlyUsers\" type=\"as\" access=\"read\"/>\n" \
214 " <property name=\"KillExcludeUsers\" type=\"as\" access=\"read\"/>\n" \
215 " <property name=\"KillUserProcesses\" type=\"b\" access=\"read\"/>\n" \
216 " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
217 " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
218 " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
219 " <property name=\"BlockInhibited\" type=\"s\" access=\"read\"/>\n" \
220 " <property name=\"DelayInhibited\" type=\"s\" access=\"read\"/>\n" \
221 " <property name=\"InhibitDelayMaxUSec\" type=\"t\" access=\"read\"/>\n" \
222 " <property name=\"HandlePowerKey\" type=\"s\" access=\"read\"/>\n" \
223 " <property name=\"HandleSuspendKey\" type=\"s\" access=\"read\"/>\n" \
224 " <property name=\"HandleHibernateKey\" type=\"s\" access=\"read\"/>\n" \
225 " <property name=\"HandleLidSwitch\" type=\"s\" access=\"read\"/>\n" \
226 " <property name=\"IdleAction\" type=\"s\" access=\"read\"/>\n" \
227 " <property name=\"IdleActionUSec\" type=\"t\" access=\"read\"/>\n" \
228 " <property name=\"PreparingForShutdown\" type=\"b\" access=\"read\"/>\n" \
229 " <property name=\"PreparingForSleep\" type=\"b\" access=\"read\"/>\n" \
232 #define INTROSPECTION_BEGIN \
233 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
235 BUS_MANAGER_INTERFACE \
236 BUS_PROPERTIES_INTERFACE \
238 BUS_INTROSPECTABLE_INTERFACE
240 #define INTROSPECTION_END \
243 #define INTERFACES_LIST \
244 BUS_GENERIC_INTERFACES_LIST \
245 "org.freedesktop.login1.Manager\0"
247 static int bus_manager_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
255 b = manager_get_idle_hint(m, NULL) > 0;
256 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
262 static int bus_manager_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
271 manager_get_idle_hint(m, &t);
272 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
274 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
280 static int bus_manager_append_inhibited(DBusMessageIter *i, const char *property, void *data) {
285 w = manager_inhibit_what(m, streq(property, "BlockInhibited") ? INHIBIT_BLOCK : INHIBIT_DELAY);
286 p = inhibit_what_to_string(w);
288 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &p))
294 static int bus_manager_append_preparing(DBusMessageIter *i, const char *property, void *data) {
301 if (streq(property, "PreparingForShutdown"))
302 b = !!(m->action_what & INHIBIT_SHUTDOWN);
304 b = !!(m->action_what & INHIBIT_SLEEP);
306 dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b);
310 static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMessage **_reply) {
311 const char *type, *class, *cseat, *tty, *display, *remote_user, *remote_host, *service;
312 uint32_t uid, leader, audit_id = 0;
313 dbus_bool_t remote, kill_processes, exists;
314 _cleanup_strv_free_ char **controllers = NULL, **reset_controllers = NULL;
315 _cleanup_free_ char *cgroup = NULL, *id = NULL, *p = NULL;
318 DBusMessageIter iter;
321 _cleanup_close_ int fifo_fd = -1;
322 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
323 Session *session = NULL;
332 if (!dbus_message_iter_init(message, &iter) ||
333 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
336 dbus_message_iter_get_basic(&iter, &uid);
338 if (!dbus_message_iter_next(&iter) ||
339 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
342 dbus_message_iter_get_basic(&iter, &leader);
345 !dbus_message_iter_next(&iter) ||
346 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
349 dbus_message_iter_get_basic(&iter, &service);
351 if (!dbus_message_iter_next(&iter) ||
352 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
355 dbus_message_iter_get_basic(&iter, &type);
356 t = session_type_from_string(type);
359 !dbus_message_iter_next(&iter) ||
360 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
363 dbus_message_iter_get_basic(&iter, &class);
367 c = session_class_from_string(class);
370 !dbus_message_iter_next(&iter) ||
371 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
374 dbus_message_iter_get_basic(&iter, &cseat);
379 seat = hashmap_get(m->seats, cseat);
384 if (!dbus_message_iter_next(&iter) ||
385 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
388 dbus_message_iter_get_basic(&iter, &vtnr);
390 if (!dbus_message_iter_next(&iter) ||
391 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
394 dbus_message_iter_get_basic(&iter, &tty);
396 if (tty_is_vc(tty)) {
401 else if (seat != m->vtconsole)
404 v = vtnr_from_tty(tty);
407 return v < 0 ? v : -EINVAL;
411 else if (vtnr != (uint32_t) v)
413 } else if (tty_is_console(tty)) {
417 else if (seat != m->vtconsole)
425 if (seat_can_multi_session(seat)) {
434 if (!dbus_message_iter_next(&iter) ||
435 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
438 dbus_message_iter_get_basic(&iter, &display);
440 if (!dbus_message_iter_next(&iter) ||
441 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
444 dbus_message_iter_get_basic(&iter, &remote);
446 if (!dbus_message_iter_next(&iter) ||
447 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
450 dbus_message_iter_get_basic(&iter, &remote_user);
452 if (!dbus_message_iter_next(&iter) ||
453 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
456 dbus_message_iter_get_basic(&iter, &remote_host);
458 if (!dbus_message_iter_next(&iter) ||
459 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
460 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
463 r = bus_parse_strv_iter(&iter, &controllers);
467 if (strv_contains(controllers, "systemd") ||
468 !dbus_message_iter_next(&iter) ||
469 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
470 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) {
475 r = bus_parse_strv_iter(&iter, &reset_controllers);
479 if (strv_contains(reset_controllers, "systemd") ||
480 !dbus_message_iter_next(&iter) ||
481 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) {
486 dbus_message_iter_get_basic(&iter, &kill_processes);
488 r = cg_pid_get_cgroup(leader, NULL, &cgroup);
492 r = manager_get_session_by_cgroup(m, cgroup, &session);
497 fifo_fd = session_create_fifo(session);
503 /* Session already exists, client is probably
504 * something like "su" which changes uid but
505 * is still the same audit session */
507 reply = dbus_message_new_method_return(message);
513 p = session_bus_path(session);
519 cseat = session->seat ? session->seat->id : "";
520 vtnr = session->vtnr;
523 b = dbus_message_append_args(
525 DBUS_TYPE_STRING, &session->id,
526 DBUS_TYPE_OBJECT_PATH, &p,
527 DBUS_TYPE_STRING, &session->user->runtime_path,
528 DBUS_TYPE_UNIX_FD, &fifo_fd,
529 DBUS_TYPE_STRING, &cseat,
530 DBUS_TYPE_UINT32, &vtnr,
531 DBUS_TYPE_BOOLEAN, &exists,
544 audit_session_from_pid(leader, &audit_id);
546 /* Keep our session IDs and the audit session IDs in sync */
548 if (asprintf(&id, "%lu", (unsigned long) audit_id) < 0) {
553 /* Wut? There's already a session by this name and we
554 * didn't find it above? Weird, then let's not trust
555 * the audit data and let's better register a new
557 if (hashmap_get(m->sessions, id)) {
570 if (asprintf(&id, "c%lu", ++m->session_counter) < 0) {
575 } while (hashmap_get(m->sessions, id));
578 r = manager_add_user_by_uid(m, uid, &user);
582 r = manager_add_session(m, user, id, &session);
586 session->leader = leader;
587 session->audit_id = audit_id;
590 session->remote = remote;
591 session->controllers = controllers;
592 session->reset_controllers = reset_controllers;
593 session->kill_processes = kill_processes;
594 session->vtnr = vtnr;
596 controllers = reset_controllers = NULL;
599 session->tty = strdup(tty);
606 if (!isempty(display)) {
607 session->display = strdup(display);
608 if (!session->display) {
614 if (!isempty(remote_user)) {
615 session->remote_user = strdup(remote_user);
616 if (!session->remote_user) {
622 if (!isempty(remote_host)) {
623 session->remote_host = strdup(remote_host);
624 if (!session->remote_host) {
630 if (!isempty(service)) {
631 session->service = strdup(service);
632 if (!session->service) {
638 fifo_fd = session_create_fifo(session);
645 r = seat_attach_session(seat, session);
650 r = session_start(session);
654 reply = dbus_message_new_method_return(message);
660 p = session_bus_path(session);
666 cseat = seat ? seat->id : "";
668 b = dbus_message_append_args(
670 DBUS_TYPE_STRING, &session->id,
671 DBUS_TYPE_OBJECT_PATH, &p,
672 DBUS_TYPE_STRING, &session->user->runtime_path,
673 DBUS_TYPE_UNIX_FD, &fifo_fd,
674 DBUS_TYPE_STRING, &cseat,
675 DBUS_TYPE_UINT32, &vtnr,
676 DBUS_TYPE_BOOLEAN, &exists,
691 session_add_to_gc_queue(session);
694 user_add_to_gc_queue(user);
699 static int bus_manager_inhibit(
701 DBusConnection *connection,
702 DBusMessage *message,
704 DBusMessage **_reply) {
708 const char *who, *why, *what, *mode;
714 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
722 if (!dbus_message_get_args(
725 DBUS_TYPE_STRING, &what,
726 DBUS_TYPE_STRING, &who,
727 DBUS_TYPE_STRING, &why,
728 DBUS_TYPE_STRING, &mode,
729 DBUS_TYPE_INVALID)) {
734 w = inhibit_what_from_string(what);
740 mm = inhibit_mode_from_string(mode);
746 /* Delay is only supported for shutdown/sleep */
747 if (mm == INHIBIT_DELAY && (w & ~(INHIBIT_SHUTDOWN|INHIBIT_SLEEP))) {
752 /* Don't allow taking delay locks while we are already
753 * executing the operation. We shouldn't create the impression
754 * that the lock was successful if the machine is about to go
755 * down/suspend any moment. */
756 if (m->action_what & w) {
761 r = verify_polkit(connection, message,
762 w == INHIBIT_SHUTDOWN ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
763 w == INHIBIT_SLEEP ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep" : "org.freedesktop.login1.inhibit-delay-sleep") :
764 w == INHIBIT_IDLE ? "org.freedesktop.login1.inhibit-block-idle" :
765 w == INHIBIT_HANDLE_POWER_KEY ? "org.freedesktop.login1.inhibit-handle-power-key" :
766 w == INHIBIT_HANDLE_SUSPEND_KEY ? "org.freedesktop.login1.inhibit-handle-suspend-key" :
767 w == INHIBIT_HANDLE_HIBERNATE_KEY ? "org.freedesktop.login1.inhibit-handle-hibernate-key" :
768 "org.freedesktop.login1.inhibit-handle-lid-switch",
773 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
774 if (ul == (unsigned long) -1) {
779 pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
789 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
793 } while (hashmap_get(m->inhibitors, id));
795 r = manager_add_inhibitor(m, id, &i);
805 i->why = strdup(why);
806 i->who = strdup(who);
808 if (!i->why || !i->who) {
813 fifo_fd = inhibitor_create_fifo(i);
819 reply = dbus_message_new_method_return(message);
825 if (!dbus_message_append_args(
827 DBUS_TYPE_UNIX_FD, &fifo_fd,
828 DBUS_TYPE_INVALID)) {
833 close_nointr_nofail(fifo_fd);
846 close_nointr_nofail(fifo_fd);
851 static int trigger_device(Manager *m, struct udev_device *d) {
852 struct udev_enumerate *e;
853 struct udev_list_entry *first, *item;
858 e = udev_enumerate_new(m->udev);
865 if (udev_enumerate_add_match_parent(e, d) < 0) {
871 if (udev_enumerate_scan_devices(e) < 0) {
876 first = udev_enumerate_get_list_entry(e);
877 udev_list_entry_foreach(item, first) {
881 p = udev_list_entry_get_name(item);
883 t = strappend(p, "/uevent");
889 write_one_line_file(t, "change");
897 udev_enumerate_unref(e);
902 static int attach_device(Manager *m, const char *seat, const char *sysfs) {
903 struct udev_device *d;
904 char *rule = NULL, *file = NULL;
905 const char *id_for_seat;
912 d = udev_device_new_from_syspath(m->udev, sysfs);
916 if (!udev_device_has_tag(d, "seat")) {
921 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
927 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
932 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
937 mkdir_p_label("/etc/udev/rules.d", 0755);
939 r = write_one_line_file_atomic_label(file, rule);
943 r = trigger_device(m, d);
950 udev_device_unref(d);
955 static int flush_devices(Manager *m) {
960 d = opendir("/etc/udev/rules.d");
963 log_warning("Failed to open /etc/udev/rules.d: %m");
967 while ((de = readdir(d))) {
969 if (!dirent_is_file(de))
972 if (!startswith(de->d_name, "72-seat-"))
975 if (!endswith(de->d_name, ".rules"))
978 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
979 log_warning("Failed to unlink %s: %m", de->d_name);
985 return trigger_device(m, NULL);
988 static int have_multiple_sessions(
997 /* Check for other users' sessions. Greeter sessions do not
998 * count, and non-login sessions do not count either. */
999 HASHMAP_FOREACH(session, m->sessions, i)
1000 if (session->class == SESSION_USER &&
1001 (session->type == SESSION_TTY || session->type == SESSION_X11) &&
1002 session->user->uid != uid)
1008 static int bus_manager_log_shutdown(
1011 const char *unit_name) {
1018 if (w != INHIBIT_SHUTDOWN)
1021 if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
1022 p = "MESSAGE=System is powering down.";
1023 q = "SHUTDOWN=power-off";
1024 } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
1025 p = "MESSAGE=System is halting.";
1026 q = "SHUTDOWN=halt";
1027 } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
1028 p = "MESSAGE=System is rebooting.";
1029 q = "SHUTDOWN=reboot";
1030 } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
1031 p = "MESSAGE=System is rebooting with kexec.";
1032 q = "SHUTDOWN=kexec";
1034 p = "MESSAGE=System is shutting down.";
1038 return log_struct(LOG_NOTICE, MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
1043 static int execute_shutdown_or_sleep(
1046 const char *unit_name,
1049 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1050 const char *mode = "replace-irreversibly", *p;
1056 assert(w < _INHIBIT_WHAT_MAX);
1059 bus_manager_log_shutdown(m, w, unit_name);
1061 r = bus_method_call_with_reply(
1063 "org.freedesktop.systemd1",
1064 "/org/freedesktop/systemd1",
1065 "org.freedesktop.systemd1.Manager",
1069 DBUS_TYPE_STRING, &unit_name,
1070 DBUS_TYPE_STRING, &mode,
1075 if (!dbus_message_get_args(
1078 DBUS_TYPE_OBJECT_PATH, &p,
1086 m->action_unit = unit_name;
1087 free(m->action_job);
1094 static int delay_shutdown_or_sleep(
1097 const char *unit_name) {
1101 assert(w < _INHIBIT_WHAT_MAX);
1104 m->action_timestamp = now(CLOCK_MONOTONIC);
1105 m->action_unit = unit_name;
1111 static int bus_manager_can_shutdown_or_sleep(
1113 DBusConnection *connection,
1114 DBusMessage *message,
1117 const char *action_multiple_sessions,
1118 const char *action_ignore_inhibit,
1119 const char *sleep_type,
1120 const char *sleep_disk_type,
1122 DBusMessage **_reply) {
1124 bool multiple_sessions, challenge, blocked, b;
1126 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1134 assert(w <= _INHIBIT_WHAT_MAX);
1136 assert(action_multiple_sessions);
1137 assert(action_ignore_inhibit);
1142 r = can_sleep(sleep_type);
1152 if (sleep_disk_type) {
1153 r = can_sleep_disk(sleep_disk_type);
1163 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1164 if (ul == (unsigned long) -1)
1167 r = have_multiple_sessions(m, (uid_t) ul);
1171 multiple_sessions = r > 0;
1172 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1174 if (multiple_sessions) {
1175 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1182 result = "challenge";
1188 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1192 if (r > 0 && !result)
1194 else if (challenge && (!result || streq(result, "yes")))
1195 result = "challenge";
1200 if (!multiple_sessions && !blocked) {
1201 /* If neither inhibit nor multiple sessions
1202 * apply then just check the normal policy */
1204 r = verify_polkit(connection, message, action, false, &challenge, error);
1211 result = "challenge";
1217 reply = dbus_message_new_method_return(message);
1221 b = dbus_message_append_args(
1223 DBUS_TYPE_STRING, &result,
1234 static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
1235 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
1236 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
1237 [INHIBIT_SLEEP] = "PrepareForSleep"
1240 dbus_bool_t active = _active;
1241 _cleanup_dbus_message_unref_ DBusMessage *message = NULL;
1245 assert(w < _INHIBIT_WHAT_MAX);
1246 assert(signal_name[w]);
1248 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1252 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1253 !dbus_connection_send(m->bus, message, NULL))
1259 int bus_manager_shutdown_or_sleep_now_or_later(
1261 const char *unit_name,
1271 assert(w <= _INHIBIT_WHAT_MAX);
1272 assert(!m->action_job);
1274 /* Tell everybody to prepare for shutdown/sleep */
1275 send_prepare_for(m, w, true);
1278 m->inhibit_delay_max > 0 &&
1279 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0);
1282 /* Shutdown is delayed, keep in mind what we
1283 * want to do, and start a timeout */
1284 r = delay_shutdown_or_sleep(m, w, unit_name);
1286 /* Shutdown is not delayed, execute it
1288 r = execute_shutdown_or_sleep(m, w, unit_name, error);
1293 static int bus_manager_do_shutdown_or_sleep(
1295 DBusConnection *connection,
1296 DBusMessage *message,
1297 const char *unit_name,
1300 const char *action_multiple_sessions,
1301 const char *action_ignore_inhibit,
1302 const char *sleep_type,
1303 const char *sleep_disk_type,
1305 DBusMessage **_reply) {
1307 dbus_bool_t interactive;
1308 bool multiple_sessions, blocked;
1309 DBusMessage *reply = NULL;
1318 assert(w <= _INHIBIT_WHAT_MAX);
1320 assert(action_multiple_sessions);
1321 assert(action_ignore_inhibit);
1325 /* Don't allow multiple jobs being executed at the same time */
1329 if (!dbus_message_get_args(
1332 DBUS_TYPE_BOOLEAN, &interactive,
1337 r = can_sleep(sleep_type);
1345 if (sleep_disk_type) {
1346 r = can_sleep_disk(sleep_disk_type);
1354 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1355 if (ul == (unsigned long) -1)
1358 r = have_multiple_sessions(m, (uid_t) ul);
1362 multiple_sessions = r > 0;
1363 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1365 if (multiple_sessions) {
1366 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1372 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1377 if (!multiple_sessions && !blocked) {
1378 r = verify_polkit(connection, message, action, interactive, NULL, error);
1383 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
1387 reply = dbus_message_new_method_return(message);
1395 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_action, handle_action, HandleAction);
1397 static const BusProperty bus_login_manager_properties[] = {
1398 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_path), true },
1399 { "Controllers", bus_property_append_strv, "as", offsetof(Manager, controllers), true },
1400 { "ResetControllers", bus_property_append_strv, "as", offsetof(Manager, reset_controllers), true },
1401 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1402 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1403 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1404 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1405 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1406 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1407 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
1408 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1409 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1410 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
1411 { "HandlePowerKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_power_key) },
1412 { "HandleSuspendKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_suspend_key) },
1413 { "HandleHibernateKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_hibernate_key)},
1414 { "HandleLidSwitch", bus_manager_append_handle_action, "s", offsetof(Manager, handle_lid_switch) },
1415 { "IdleAction", bus_manager_append_handle_action, "s", offsetof(Manager, idle_action) },
1416 { "IdleActionUSec", bus_property_append_usec, "t", offsetof(Manager, idle_action_usec) },
1417 { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
1418 { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
1422 static DBusHandlerResult manager_message_handler(
1423 DBusConnection *connection,
1424 DBusMessage *message,
1427 Manager *m = userdata;
1430 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1437 dbus_error_init(&error);
1439 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1445 if (!dbus_message_get_args(
1448 DBUS_TYPE_STRING, &name,
1450 return bus_send_error_reply(connection, message, &error, -EINVAL);
1452 session = hashmap_get(m->sessions, name);
1454 return bus_send_error_reply(connection, message, &error, -ENOENT);
1456 reply = dbus_message_new_method_return(message);
1460 p = session_bus_path(session);
1464 b = dbus_message_append_args(
1466 DBUS_TYPE_OBJECT_PATH, &p,
1473 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1479 if (!dbus_message_get_args(
1482 DBUS_TYPE_UINT32, &pid,
1484 return bus_send_error_reply(connection, message, &error, -EINVAL);
1486 r = manager_get_session_by_pid(m, pid, &session);
1488 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1490 reply = dbus_message_new_method_return(message);
1494 p = session_bus_path(session);
1498 b = dbus_message_append_args(
1500 DBUS_TYPE_OBJECT_PATH, &p,
1507 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1513 if (!dbus_message_get_args(
1516 DBUS_TYPE_UINT32, &uid,
1518 return bus_send_error_reply(connection, message, &error, -EINVAL);
1520 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1522 return bus_send_error_reply(connection, message, &error, -ENOENT);
1524 reply = dbus_message_new_method_return(message);
1528 p = user_bus_path(user);
1532 b = dbus_message_append_args(
1534 DBUS_TYPE_OBJECT_PATH, &p,
1541 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1547 if (!dbus_message_get_args(
1550 DBUS_TYPE_STRING, &name,
1552 return bus_send_error_reply(connection, message, &error, -EINVAL);
1554 seat = hashmap_get(m->seats, name);
1556 return bus_send_error_reply(connection, message, &error, -ENOENT);
1558 reply = dbus_message_new_method_return(message);
1562 p = seat_bus_path(seat);
1566 b = dbus_message_append_args(
1568 DBUS_TYPE_OBJECT_PATH, &p,
1575 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1579 DBusMessageIter iter, sub;
1580 const char *empty = "";
1582 reply = dbus_message_new_method_return(message);
1586 dbus_message_iter_init_append(reply, &iter);
1588 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1591 HASHMAP_FOREACH(session, m->sessions, i) {
1592 DBusMessageIter sub2;
1595 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1598 uid = session->user->uid;
1600 p = session_bus_path(session);
1604 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1605 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1606 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1607 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1608 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1615 if (!dbus_message_iter_close_container(&sub, &sub2))
1619 if (!dbus_message_iter_close_container(&iter, &sub))
1622 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1626 DBusMessageIter iter, sub;
1628 reply = dbus_message_new_method_return(message);
1632 dbus_message_iter_init_append(reply, &iter);
1634 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1637 HASHMAP_FOREACH(user, m->users, i) {
1638 DBusMessageIter sub2;
1641 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1646 p = user_bus_path(user);
1650 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1651 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1652 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1659 if (!dbus_message_iter_close_container(&sub, &sub2))
1663 if (!dbus_message_iter_close_container(&iter, &sub))
1666 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1670 DBusMessageIter iter, sub;
1672 reply = dbus_message_new_method_return(message);
1676 dbus_message_iter_init_append(reply, &iter);
1678 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1681 HASHMAP_FOREACH(seat, m->seats, i) {
1682 DBusMessageIter sub2;
1684 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1687 p = seat_bus_path(seat);
1691 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1692 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1699 if (!dbus_message_iter_close_container(&sub, &sub2))
1703 if (!dbus_message_iter_close_container(&iter, &sub))
1706 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1707 Inhibitor *inhibitor;
1709 DBusMessageIter iter, sub;
1711 reply = dbus_message_new_method_return(message);
1715 dbus_message_iter_init_append(reply, &iter);
1717 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1720 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1721 DBusMessageIter sub2;
1722 dbus_uint32_t uid, pid;
1723 const char *what, *who, *why, *mode;
1725 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1728 what = strempty(inhibit_what_to_string(inhibitor->what));
1729 who = strempty(inhibitor->who);
1730 why = strempty(inhibitor->why);
1731 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
1732 uid = (dbus_uint32_t) inhibitor->uid;
1733 pid = (dbus_uint32_t) inhibitor->pid;
1735 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1736 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1737 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1738 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
1739 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1740 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1743 if (!dbus_message_iter_close_container(&sub, &sub2))
1747 if (!dbus_message_iter_close_container(&iter, &sub))
1750 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1752 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1755 return bus_send_error_reply(connection, message, &error, r);
1758 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1760 r = bus_manager_create_session(m, message, &reply);
1762 /* Don't delay the work on OOM here, since it might be
1763 * triggered by a low RLIMIT_NOFILE here (since we
1764 * send a dupped fd to the client), and we'd rather
1765 * see this fail quickly then be retried later */
1768 return bus_send_error_reply(connection, message, NULL, r);
1770 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1774 if (!dbus_message_get_args(
1777 DBUS_TYPE_STRING, &name,
1779 return bus_send_error_reply(connection, message, &error, -EINVAL);
1781 session = hashmap_get(m->sessions, name);
1783 return bus_send_error_reply(connection, message, &error, -ENOENT);
1785 /* We use the FIFO to detect stray sessions where the
1786 process invoking PAM dies abnormally. We need to make
1787 sure that that process is not killed if at the clean
1788 end of the session it closes the FIFO. Hence, with
1789 this call explicitly turn off the FIFO logic, so that
1790 the PAM code can finish clean up on its own */
1791 session_remove_fifo(session);
1793 reply = dbus_message_new_method_return(message);
1797 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1801 if (!dbus_message_get_args(
1804 DBUS_TYPE_STRING, &name,
1806 return bus_send_error_reply(connection, message, &error, -EINVAL);
1808 session = hashmap_get(m->sessions, name);
1810 return bus_send_error_reply(connection, message, &error, -ENOENT);
1812 r = session_activate(session);
1814 return bus_send_error_reply(connection, message, NULL, r);
1816 reply = dbus_message_new_method_return(message);
1820 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1821 const char *session_name, *seat_name;
1825 /* Same as ActivateSession() but refuses to work if
1826 * the seat doesn't match */
1828 if (!dbus_message_get_args(
1831 DBUS_TYPE_STRING, &session_name,
1832 DBUS_TYPE_STRING, &seat_name,
1834 return bus_send_error_reply(connection, message, &error, -EINVAL);
1836 session = hashmap_get(m->sessions, session_name);
1838 return bus_send_error_reply(connection, message, &error, -ENOENT);
1840 seat = hashmap_get(m->seats, seat_name);
1842 return bus_send_error_reply(connection, message, &error, -ENOENT);
1844 if (session->seat != seat)
1845 return bus_send_error_reply(connection, message, &error, -EINVAL);
1847 r = session_activate(session);
1849 return bus_send_error_reply(connection, message, NULL, r);
1851 reply = dbus_message_new_method_return(message);
1855 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1856 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1860 if (!dbus_message_get_args(
1863 DBUS_TYPE_STRING, &name,
1865 return bus_send_error_reply(connection, message, &error, -EINVAL);
1867 session = hashmap_get(m->sessions, name);
1869 return bus_send_error_reply(connection, message, NULL, -ENOENT);
1871 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1874 reply = dbus_message_new_method_return(message);
1878 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions") ||
1879 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSessions")) {
1881 r = session_send_lock_all(m, streq(dbus_message_get_member(message), "LockSessions"));
1883 bus_send_error_reply(connection, message, NULL, r);
1885 reply = dbus_message_new_method_return(message);
1889 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1896 if (!dbus_message_get_args(
1899 DBUS_TYPE_STRING, &name,
1900 DBUS_TYPE_STRING, &swho,
1901 DBUS_TYPE_INT32, &signo,
1903 return bus_send_error_reply(connection, message, &error, -EINVAL);
1908 who = kill_who_from_string(swho);
1910 return bus_send_error_reply(connection, message, &error, -EINVAL);
1913 if (signo <= 0 || signo >= _NSIG)
1914 return bus_send_error_reply(connection, message, &error, -EINVAL);
1916 session = hashmap_get(m->sessions, name);
1918 return bus_send_error_reply(connection, message, &error, -ENOENT);
1920 r = session_kill(session, who, signo);
1922 return bus_send_error_reply(connection, message, NULL, r);
1924 reply = dbus_message_new_method_return(message);
1928 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1933 if (!dbus_message_get_args(
1936 DBUS_TYPE_UINT32, &uid,
1937 DBUS_TYPE_INT32, &signo,
1939 return bus_send_error_reply(connection, message, &error, -EINVAL);
1941 if (signo <= 0 || signo >= _NSIG)
1942 return bus_send_error_reply(connection, message, &error, -EINVAL);
1944 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1946 return bus_send_error_reply(connection, message, &error, -ENOENT);
1948 r = user_kill(user, signo);
1950 return bus_send_error_reply(connection, message, NULL, r);
1952 reply = dbus_message_new_method_return(message);
1956 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1960 if (!dbus_message_get_args(
1963 DBUS_TYPE_STRING, &name,
1965 return bus_send_error_reply(connection, message, &error, -EINVAL);
1967 session = hashmap_get(m->sessions, name);
1969 return bus_send_error_reply(connection, message, &error, -ENOENT);
1971 r = session_stop(session);
1973 return bus_send_error_reply(connection, message, NULL, r);
1975 reply = dbus_message_new_method_return(message);
1979 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1983 if (!dbus_message_get_args(
1986 DBUS_TYPE_UINT32, &uid,
1988 return bus_send_error_reply(connection, message, &error, -EINVAL);
1990 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1992 return bus_send_error_reply(connection, message, &error, -ENOENT);
1994 r = user_stop(user);
1996 return bus_send_error_reply(connection, message, NULL, r);
1998 reply = dbus_message_new_method_return(message);
2002 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
2006 if (!dbus_message_get_args(
2009 DBUS_TYPE_STRING, &name,
2011 return bus_send_error_reply(connection, message, &error, -EINVAL);
2013 seat = hashmap_get(m->seats, name);
2015 return bus_send_error_reply(connection, message, &error, -ENOENT);
2017 r = seat_stop_sessions(seat);
2019 return bus_send_error_reply(connection, message, NULL, r);
2021 reply = dbus_message_new_method_return(message);
2025 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
2028 dbus_bool_t b, interactive;
2031 if (!dbus_message_get_args(
2034 DBUS_TYPE_UINT32, &uid,
2035 DBUS_TYPE_BOOLEAN, &b,
2036 DBUS_TYPE_BOOLEAN, &interactive,
2038 return bus_send_error_reply(connection, message, &error, -EINVAL);
2043 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
2045 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
2047 return bus_send_error_reply(connection, message, &error, r);
2049 mkdir_p_label("/var/lib/systemd", 0755);
2051 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
2053 return bus_send_error_reply(connection, message, &error, r);
2055 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
2066 return bus_send_error_reply(connection, message, &error, r);
2068 if (manager_add_user_by_uid(m, uid, &u) >= 0)
2077 if (r < 0 && errno != ENOENT)
2078 return bus_send_error_reply(connection, message, &error, -errno);
2080 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
2082 user_add_to_gc_queue(u);
2085 reply = dbus_message_new_method_return(message);
2089 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
2090 const char *sysfs, *seat;
2091 dbus_bool_t interactive;
2093 if (!dbus_message_get_args(
2096 DBUS_TYPE_STRING, &seat,
2097 DBUS_TYPE_STRING, &sysfs,
2098 DBUS_TYPE_BOOLEAN, &interactive,
2100 return bus_send_error_reply(connection, message, &error, -EINVAL);
2102 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
2103 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2105 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
2107 return bus_send_error_reply(connection, message, &error, r);
2109 r = attach_device(m, seat, sysfs);
2111 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2113 reply = dbus_message_new_method_return(message);
2118 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
2119 dbus_bool_t interactive;
2121 if (!dbus_message_get_args(
2124 DBUS_TYPE_BOOLEAN, &interactive,
2126 return bus_send_error_reply(connection, message, &error, -EINVAL);
2128 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
2130 return bus_send_error_reply(connection, message, &error, r);
2132 r = flush_devices(m);
2134 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2136 reply = dbus_message_new_method_return(message);
2140 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
2142 r = bus_manager_do_shutdown_or_sleep(
2143 m, connection, message,
2144 SPECIAL_POWEROFF_TARGET,
2146 "org.freedesktop.login1.power-off",
2147 "org.freedesktop.login1.power-off-multiple-sessions",
2148 "org.freedesktop.login1.power-off-ignore-inhibit",
2152 return bus_send_error_reply(connection, message, &error, r);
2153 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
2154 r = bus_manager_do_shutdown_or_sleep(
2155 m, connection, message,
2156 SPECIAL_REBOOT_TARGET,
2158 "org.freedesktop.login1.reboot",
2159 "org.freedesktop.login1.reboot-multiple-sessions",
2160 "org.freedesktop.login1.reboot-ignore-inhibit",
2164 return bus_send_error_reply(connection, message, &error, r);
2166 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2167 r = bus_manager_do_shutdown_or_sleep(
2168 m, connection, message,
2169 SPECIAL_SUSPEND_TARGET,
2171 "org.freedesktop.login1.suspend",
2172 "org.freedesktop.login1.suspend-multiple-sessions",
2173 "org.freedesktop.login1.suspend-ignore-inhibit",
2177 return bus_send_error_reply(connection, message, &error, r);
2178 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2179 r = bus_manager_do_shutdown_or_sleep(
2180 m, connection, message,
2181 SPECIAL_HIBERNATE_TARGET,
2183 "org.freedesktop.login1.hibernate",
2184 "org.freedesktop.login1.hibernate-multiple-sessions",
2185 "org.freedesktop.login1.hibernate-ignore-inhibit",
2189 return bus_send_error_reply(connection, message, &error, r);
2191 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "HybridSleep")) {
2192 r = bus_manager_do_shutdown_or_sleep(
2193 m, connection, message,
2194 SPECIAL_HYBRID_SLEEP_TARGET,
2196 "org.freedesktop.login1.hibernate",
2197 "org.freedesktop.login1.hibernate-multiple-sessions",
2198 "org.freedesktop.login1.hibernate-ignore-inhibit",
2202 return bus_send_error_reply(connection, message, &error, r);
2204 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2206 r = bus_manager_can_shutdown_or_sleep(
2207 m, connection, message,
2209 "org.freedesktop.login1.power-off",
2210 "org.freedesktop.login1.power-off-multiple-sessions",
2211 "org.freedesktop.login1.power-off-ignore-inhibit",
2215 return bus_send_error_reply(connection, message, &error, r);
2216 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2217 r = bus_manager_can_shutdown_or_sleep(
2218 m, connection, message,
2220 "org.freedesktop.login1.reboot",
2221 "org.freedesktop.login1.reboot-multiple-sessions",
2222 "org.freedesktop.login1.reboot-ignore-inhibit",
2226 return bus_send_error_reply(connection, message, &error, r);
2228 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2229 r = bus_manager_can_shutdown_or_sleep(
2230 m, connection, message,
2232 "org.freedesktop.login1.suspend",
2233 "org.freedesktop.login1.suspend-multiple-sessions",
2234 "org.freedesktop.login1.suspend-ignore-inhibit",
2238 return bus_send_error_reply(connection, message, &error, r);
2240 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2241 r = bus_manager_can_shutdown_or_sleep(
2242 m, connection, message,
2244 "org.freedesktop.login1.hibernate",
2245 "org.freedesktop.login1.hibernate-multiple-sessions",
2246 "org.freedesktop.login1.hibernate-ignore-inhibit",
2250 return bus_send_error_reply(connection, message, &error, r);
2252 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHybridSleep")) {
2253 r = bus_manager_can_shutdown_or_sleep(
2254 m, connection, message,
2256 "org.freedesktop.login1.hibernate",
2257 "org.freedesktop.login1.hibernate-multiple-sessions",
2258 "org.freedesktop.login1.hibernate-ignore-inhibit",
2262 return bus_send_error_reply(connection, message, &error, r);
2264 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2265 char *introspection = NULL;
2274 if (!(reply = dbus_message_new_method_return(message)))
2277 /* We roll our own introspection code here, instead of
2278 * relying on bus_default_message_handler() because we
2279 * need to generate our introspection string
2282 if (!(f = open_memstream(&introspection, &size)))
2285 fputs(INTROSPECTION_BEGIN, f);
2287 HASHMAP_FOREACH(seat, m->seats, i) {
2288 p = bus_path_escape(seat->id);
2291 fprintf(f, "<node name=\"seat/%s\"/>", p);
2296 HASHMAP_FOREACH(user, m->users, i)
2297 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2299 HASHMAP_FOREACH(session, m->sessions, i) {
2300 p = bus_path_escape(session->id);
2303 fprintf(f, "<node name=\"session/%s\"/>", p);
2308 fputs(INTROSPECTION_END, f);
2312 free(introspection);
2321 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2322 free(introspection);
2326 free(introspection);
2328 const BusBoundProperties bps[] = {
2329 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2332 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2336 if (!bus_maybe_send_reply(connection, message, reply))
2340 return DBUS_HANDLER_RESULT_HANDLED;
2343 dbus_error_free(&error);
2345 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2348 const DBusObjectPathVTable bus_manager_vtable = {
2349 .message_function = manager_message_handler
2352 DBusHandlerResult bus_message_filter(
2353 DBusConnection *connection,
2354 DBusMessage *message,
2357 Manager *m = userdata;
2364 dbus_error_init(&error);
2366 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
2369 if (!dbus_message_get_args(message, &error,
2370 DBUS_TYPE_STRING, &cgroup,
2372 log_error("Failed to parse Released message: %s", bus_error_message(&error));
2374 manager_cgroup_notify_empty(m, cgroup);
2376 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
2378 const char *path, *result, *unit;
2380 if (!dbus_message_get_args(message, &error,
2381 DBUS_TYPE_UINT32, &id,
2382 DBUS_TYPE_OBJECT_PATH, &path,
2383 DBUS_TYPE_STRING, &unit,
2384 DBUS_TYPE_STRING, &result,
2386 log_error("Failed to parse JobRemoved message: %s", bus_error_message(&error));
2388 else if (m->action_job && streq(m->action_job, path)) {
2390 log_info("Operation finished.");
2392 /* Tell people that they now may take a lock again */
2393 send_prepare_for(m, m->action_what, false);
2395 free(m->action_job);
2396 m->action_job = NULL;
2397 m->action_unit = NULL;
2402 dbus_error_free(&error);
2404 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2407 int manager_send_changed(Manager *manager, const char *properties) {
2408 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
2413 m = bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties);
2417 if (!dbus_connection_send(manager->bus, m, NULL))
2426 int manager_dispatch_delayed(Manager *manager) {
2432 if (!manager->action_unit || manager->action_job)
2435 /* Continue delay? */
2436 if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0)) {
2438 if (manager->action_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC))
2441 log_info("Delay lock is active but inhibitor timeout is reached.");
2444 /* Actually do the operation */
2445 dbus_error_init(&error);
2446 r = execute_shutdown_or_sleep(manager, manager->action_what, manager->action_unit, &error);
2448 log_warning("Failed to send delayed message: %s", bus_error_message_or_strerror(&error, -r));
2449 dbus_error_free(&error);
2451 manager->action_unit = NULL;
2452 manager->action_what = 0;