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 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,
543 audit_session_from_pid(leader, &audit_id);
545 /* Keep our session IDs and the audit session IDs in sync */
547 if (asprintf(&id, "%lu", (unsigned long) audit_id) < 0) {
552 /* Wut? There's already a session by this name and we
553 * didn't find it above? Weird, then let's not trust
554 * the audit data and let's better register a new
556 if (hashmap_get(m->sessions, id)) {
569 if (asprintf(&id, "c%lu", ++m->session_counter) < 0) {
574 } while (hashmap_get(m->sessions, id));
577 r = manager_add_user_by_uid(m, uid, &user);
581 r = manager_add_session(m, user, id, &session);
585 session->leader = leader;
586 session->audit_id = audit_id;
589 session->remote = remote;
590 session->controllers = controllers;
591 session->reset_controllers = reset_controllers;
592 session->kill_processes = kill_processes;
593 session->vtnr = vtnr;
595 controllers = reset_controllers = NULL;
598 session->tty = strdup(tty);
605 if (!isempty(display)) {
606 session->display = strdup(display);
607 if (!session->display) {
613 if (!isempty(remote_user)) {
614 session->remote_user = strdup(remote_user);
615 if (!session->remote_user) {
621 if (!isempty(remote_host)) {
622 session->remote_host = strdup(remote_host);
623 if (!session->remote_host) {
629 if (!isempty(service)) {
630 session->service = strdup(service);
631 if (!session->service) {
637 fifo_fd = session_create_fifo(session);
644 r = seat_attach_session(seat, session);
649 r = session_start(session);
653 reply = dbus_message_new_method_return(message);
659 p = session_bus_path(session);
665 cseat = seat ? seat->id : "";
667 b = dbus_message_append_args(
669 DBUS_TYPE_STRING, &session->id,
670 DBUS_TYPE_OBJECT_PATH, &p,
671 DBUS_TYPE_STRING, &session->user->runtime_path,
672 DBUS_TYPE_UNIX_FD, &fifo_fd,
673 DBUS_TYPE_STRING, &cseat,
674 DBUS_TYPE_UINT32, &vtnr,
675 DBUS_TYPE_BOOLEAN, &exists,
689 session_add_to_gc_queue(session);
692 user_add_to_gc_queue(user);
695 dbus_message_unref(reply);
700 static int bus_manager_inhibit(
702 DBusConnection *connection,
703 DBusMessage *message,
705 DBusMessage **_reply) {
709 const char *who, *why, *what, *mode;
715 DBusMessage *reply = NULL;
723 if (!dbus_message_get_args(
726 DBUS_TYPE_STRING, &what,
727 DBUS_TYPE_STRING, &who,
728 DBUS_TYPE_STRING, &why,
729 DBUS_TYPE_STRING, &mode,
730 DBUS_TYPE_INVALID)) {
735 w = inhibit_what_from_string(what);
741 mm = inhibit_mode_from_string(mode);
747 /* Delay is only supported for shutdown/sleep */
748 if (mm == INHIBIT_DELAY && (w & ~(INHIBIT_SHUTDOWN|INHIBIT_SLEEP))) {
753 /* Don't allow taking delay locks while we are already
754 * executing the operation. We shouldn't create the impression
755 * that the lock was successful if the machine is about to go
756 * down/suspend any moment. */
757 if (m->action_what & w) {
762 r = verify_polkit(connection, message,
763 w == INHIBIT_SHUTDOWN ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
764 w == INHIBIT_SLEEP ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep" : "org.freedesktop.login1.inhibit-delay-sleep") :
765 w == INHIBIT_IDLE ? "org.freedesktop.login1.inhibit-block-idle" :
766 w == INHIBIT_HANDLE_POWER_KEY ? "org.freedesktop.login1.inhibit-handle-power-key" :
767 w == INHIBIT_HANDLE_SUSPEND_KEY ? "org.freedesktop.login1.inhibit-handle-suspend-key" :
768 w == INHIBIT_HANDLE_HIBERNATE_KEY ? "org.freedesktop.login1.inhibit-handle-hibernate-key" :
769 "org.freedesktop.login1.inhibit-handle-lid-switch",
774 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
775 if (ul == (unsigned long) -1) {
780 pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
790 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
794 } while (hashmap_get(m->inhibitors, id));
796 r = manager_add_inhibitor(m, id, &i);
806 i->why = strdup(why);
807 i->who = strdup(who);
809 if (!i->why || !i->who) {
814 fifo_fd = inhibitor_create_fifo(i);
820 reply = dbus_message_new_method_return(message);
826 if (!dbus_message_append_args(
828 DBUS_TYPE_UNIX_FD, &fifo_fd,
829 DBUS_TYPE_INVALID)) {
834 close_nointr_nofail(fifo_fd);
846 close_nointr_nofail(fifo_fd);
849 dbus_message_unref(reply);
854 static int trigger_device(Manager *m, struct udev_device *d) {
855 struct udev_enumerate *e;
856 struct udev_list_entry *first, *item;
861 e = udev_enumerate_new(m->udev);
868 if (udev_enumerate_add_match_parent(e, d) < 0) {
874 if (udev_enumerate_scan_devices(e) < 0) {
879 first = udev_enumerate_get_list_entry(e);
880 udev_list_entry_foreach(item, first) {
884 p = udev_list_entry_get_name(item);
886 t = strappend(p, "/uevent");
892 write_one_line_file(t, "change");
900 udev_enumerate_unref(e);
905 static int attach_device(Manager *m, const char *seat, const char *sysfs) {
906 struct udev_device *d;
907 char *rule = NULL, *file = NULL;
908 const char *id_for_seat;
915 d = udev_device_new_from_syspath(m->udev, sysfs);
919 if (!udev_device_has_tag(d, "seat")) {
924 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
930 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
935 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
940 mkdir_p_label("/etc/udev/rules.d", 0755);
942 r = write_one_line_file_atomic_label(file, rule);
946 r = trigger_device(m, d);
953 udev_device_unref(d);
958 static int flush_devices(Manager *m) {
963 d = opendir("/etc/udev/rules.d");
966 log_warning("Failed to open /etc/udev/rules.d: %m");
970 while ((de = readdir(d))) {
972 if (!dirent_is_file(de))
975 if (!startswith(de->d_name, "72-seat-"))
978 if (!endswith(de->d_name, ".rules"))
981 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
982 log_warning("Failed to unlink %s: %m", de->d_name);
988 return trigger_device(m, NULL);
991 static int have_multiple_sessions(
1000 /* Check for other users' sessions. Greeter sessions do not
1001 * count, and non-login sessions do not count either. */
1002 HASHMAP_FOREACH(session, m->sessions, i)
1003 if (session->class == SESSION_USER &&
1004 (session->type == SESSION_TTY || session->type == SESSION_X11) &&
1005 session->user->uid != uid)
1011 static int bus_manager_log_shutdown(
1014 const char *unit_name) {
1021 if (w != INHIBIT_SHUTDOWN)
1024 if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
1025 p = "MESSAGE=System is powering down.";
1026 q = "SHUTDOWN=power-off";
1027 } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
1028 p = "MESSAGE=System is halting.";
1029 q = "SHUTDOWN=halt";
1030 } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
1031 p = "MESSAGE=System is rebooting.";
1032 q = "SHUTDOWN=reboot";
1033 } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
1034 p = "MESSAGE=System is rebooting with kexec.";
1035 q = "SHUTDOWN=kexec";
1037 p = "MESSAGE=System is shutting down.";
1041 return log_struct(LOG_NOTICE, MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
1046 static int execute_shutdown_or_sleep(
1049 const char *unit_name,
1052 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1053 const char *mode = "replace-irreversibly", *p;
1059 assert(w < _INHIBIT_WHAT_MAX);
1062 bus_manager_log_shutdown(m, w, unit_name);
1064 r = bus_method_call_with_reply(
1066 "org.freedesktop.systemd1",
1067 "/org/freedesktop/systemd1",
1068 "org.freedesktop.systemd1.Manager",
1072 DBUS_TYPE_STRING, &unit_name,
1073 DBUS_TYPE_STRING, &mode,
1078 if (!dbus_message_get_args(
1081 DBUS_TYPE_OBJECT_PATH, &p,
1089 m->action_unit = unit_name;
1090 free(m->action_job);
1097 static int delay_shutdown_or_sleep(
1100 const char *unit_name) {
1104 assert(w < _INHIBIT_WHAT_MAX);
1107 m->action_timestamp = now(CLOCK_MONOTONIC);
1108 m->action_unit = unit_name;
1114 static int bus_manager_can_shutdown_or_sleep(
1116 DBusConnection *connection,
1117 DBusMessage *message,
1120 const char *action_multiple_sessions,
1121 const char *action_ignore_inhibit,
1122 const char *sleep_type,
1123 const char *sleep_disk_type,
1125 DBusMessage **_reply) {
1127 bool multiple_sessions, challenge, blocked, b;
1129 DBusMessage *reply = NULL;
1137 assert(w <= _INHIBIT_WHAT_MAX);
1139 assert(action_multiple_sessions);
1140 assert(action_ignore_inhibit);
1145 r = can_sleep(sleep_type);
1155 if (sleep_disk_type) {
1156 r = can_sleep_disk(sleep_disk_type);
1166 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1167 if (ul == (unsigned long) -1)
1170 r = have_multiple_sessions(m, (uid_t) ul);
1174 multiple_sessions = r > 0;
1175 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1177 if (multiple_sessions) {
1178 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1185 result = "challenge";
1191 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1195 if (r > 0 && !result)
1197 else if (challenge && (!result || streq(result, "yes")))
1198 result = "challenge";
1203 if (!multiple_sessions && !blocked) {
1204 /* If neither inhibit nor multiple sessions
1205 * apply then just check the normal policy */
1207 r = verify_polkit(connection, message, action, false, &challenge, error);
1214 result = "challenge";
1220 reply = dbus_message_new_method_return(message);
1224 b = dbus_message_append_args(
1226 DBUS_TYPE_STRING, &result,
1229 dbus_message_unref(reply);
1237 static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
1238 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
1239 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
1240 [INHIBIT_SLEEP] = "PrepareForSleep"
1243 dbus_bool_t active = _active;
1244 _cleanup_dbus_message_unref_ DBusMessage *message = NULL;
1248 assert(w < _INHIBIT_WHAT_MAX);
1249 assert(signal_name[w]);
1251 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1255 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1256 !dbus_connection_send(m->bus, message, NULL))
1262 int bus_manager_shutdown_or_sleep_now_or_later(
1264 const char *unit_name,
1274 assert(w <= _INHIBIT_WHAT_MAX);
1275 assert(!m->action_job);
1277 /* Tell everybody to prepare for shutdown/sleep */
1278 send_prepare_for(m, w, true);
1281 m->inhibit_delay_max > 0 &&
1282 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0);
1285 /* Shutdown is delayed, keep in mind what we
1286 * want to do, and start a timeout */
1287 r = delay_shutdown_or_sleep(m, w, unit_name);
1289 /* Shutdown is not delayed, execute it
1291 r = execute_shutdown_or_sleep(m, w, unit_name, error);
1296 static int bus_manager_do_shutdown_or_sleep(
1298 DBusConnection *connection,
1299 DBusMessage *message,
1300 const char *unit_name,
1303 const char *action_multiple_sessions,
1304 const char *action_ignore_inhibit,
1305 const char *sleep_type,
1306 const char *sleep_disk_type,
1308 DBusMessage **_reply) {
1310 dbus_bool_t interactive;
1311 bool multiple_sessions, blocked;
1312 DBusMessage *reply = NULL;
1321 assert(w <= _INHIBIT_WHAT_MAX);
1323 assert(action_multiple_sessions);
1324 assert(action_ignore_inhibit);
1328 /* Don't allow multiple jobs being executed at the same time */
1332 if (!dbus_message_get_args(
1335 DBUS_TYPE_BOOLEAN, &interactive,
1340 r = can_sleep(sleep_type);
1348 if (sleep_disk_type) {
1349 r = can_sleep_disk(sleep_disk_type);
1357 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1358 if (ul == (unsigned long) -1)
1361 r = have_multiple_sessions(m, (uid_t) ul);
1365 multiple_sessions = r > 0;
1366 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1368 if (multiple_sessions) {
1369 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1375 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1380 if (!multiple_sessions && !blocked) {
1381 r = verify_polkit(connection, message, action, interactive, NULL, error);
1386 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
1390 reply = dbus_message_new_method_return(message);
1398 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_action, handle_action, HandleAction);
1400 static const BusProperty bus_login_manager_properties[] = {
1401 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_path), true },
1402 { "Controllers", bus_property_append_strv, "as", offsetof(Manager, controllers), true },
1403 { "ResetControllers", bus_property_append_strv, "as", offsetof(Manager, reset_controllers), true },
1404 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1405 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1406 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1407 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1408 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1409 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1410 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
1411 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1412 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1413 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
1414 { "HandlePowerKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_power_key) },
1415 { "HandleSuspendKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_suspend_key) },
1416 { "HandleHibernateKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_hibernate_key)},
1417 { "HandleLidSwitch", bus_manager_append_handle_action, "s", offsetof(Manager, handle_lid_switch) },
1418 { "IdleAction", bus_manager_append_handle_action, "s", offsetof(Manager, idle_action) },
1419 { "IdleActionUSec", bus_property_append_usec, "t", offsetof(Manager, idle_action_usec) },
1420 { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
1421 { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
1425 static DBusHandlerResult manager_message_handler(
1426 DBusConnection *connection,
1427 DBusMessage *message,
1430 Manager *m = userdata;
1433 DBusMessage *reply = NULL;
1440 dbus_error_init(&error);
1442 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1448 if (!dbus_message_get_args(
1451 DBUS_TYPE_STRING, &name,
1453 return bus_send_error_reply(connection, message, &error, -EINVAL);
1455 session = hashmap_get(m->sessions, name);
1457 return bus_send_error_reply(connection, message, &error, -ENOENT);
1459 reply = dbus_message_new_method_return(message);
1463 p = session_bus_path(session);
1467 b = dbus_message_append_args(
1469 DBUS_TYPE_OBJECT_PATH, &p,
1476 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1482 if (!dbus_message_get_args(
1485 DBUS_TYPE_UINT32, &pid,
1487 return bus_send_error_reply(connection, message, &error, -EINVAL);
1489 r = manager_get_session_by_pid(m, pid, &session);
1491 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1493 reply = dbus_message_new_method_return(message);
1497 p = session_bus_path(session);
1501 b = dbus_message_append_args(
1503 DBUS_TYPE_OBJECT_PATH, &p,
1510 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1516 if (!dbus_message_get_args(
1519 DBUS_TYPE_UINT32, &uid,
1521 return bus_send_error_reply(connection, message, &error, -EINVAL);
1523 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1525 return bus_send_error_reply(connection, message, &error, -ENOENT);
1527 reply = dbus_message_new_method_return(message);
1531 p = user_bus_path(user);
1535 b = dbus_message_append_args(
1537 DBUS_TYPE_OBJECT_PATH, &p,
1544 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1550 if (!dbus_message_get_args(
1553 DBUS_TYPE_STRING, &name,
1555 return bus_send_error_reply(connection, message, &error, -EINVAL);
1557 seat = hashmap_get(m->seats, name);
1559 return bus_send_error_reply(connection, message, &error, -ENOENT);
1561 reply = dbus_message_new_method_return(message);
1565 p = seat_bus_path(seat);
1569 b = dbus_message_append_args(
1571 DBUS_TYPE_OBJECT_PATH, &p,
1578 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1582 DBusMessageIter iter, sub;
1583 const char *empty = "";
1585 reply = dbus_message_new_method_return(message);
1589 dbus_message_iter_init_append(reply, &iter);
1591 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1594 HASHMAP_FOREACH(session, m->sessions, i) {
1595 DBusMessageIter sub2;
1598 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1601 uid = session->user->uid;
1603 p = session_bus_path(session);
1607 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1608 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1609 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1610 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1611 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1618 if (!dbus_message_iter_close_container(&sub, &sub2))
1622 if (!dbus_message_iter_close_container(&iter, &sub))
1625 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1629 DBusMessageIter iter, sub;
1631 reply = dbus_message_new_method_return(message);
1635 dbus_message_iter_init_append(reply, &iter);
1637 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1640 HASHMAP_FOREACH(user, m->users, i) {
1641 DBusMessageIter sub2;
1644 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1649 p = user_bus_path(user);
1653 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1654 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1655 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1662 if (!dbus_message_iter_close_container(&sub, &sub2))
1666 if (!dbus_message_iter_close_container(&iter, &sub))
1669 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1673 DBusMessageIter iter, sub;
1675 reply = dbus_message_new_method_return(message);
1679 dbus_message_iter_init_append(reply, &iter);
1681 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1684 HASHMAP_FOREACH(seat, m->seats, i) {
1685 DBusMessageIter sub2;
1687 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1690 p = seat_bus_path(seat);
1694 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1695 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1702 if (!dbus_message_iter_close_container(&sub, &sub2))
1706 if (!dbus_message_iter_close_container(&iter, &sub))
1709 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1710 Inhibitor *inhibitor;
1712 DBusMessageIter iter, sub;
1714 reply = dbus_message_new_method_return(message);
1718 dbus_message_iter_init_append(reply, &iter);
1720 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1723 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1724 DBusMessageIter sub2;
1725 dbus_uint32_t uid, pid;
1726 const char *what, *who, *why, *mode;
1728 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1731 what = strempty(inhibit_what_to_string(inhibitor->what));
1732 who = strempty(inhibitor->who);
1733 why = strempty(inhibitor->why);
1734 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
1735 uid = (dbus_uint32_t) inhibitor->uid;
1736 pid = (dbus_uint32_t) inhibitor->pid;
1738 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1739 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1740 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1741 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
1742 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1743 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1746 if (!dbus_message_iter_close_container(&sub, &sub2))
1750 if (!dbus_message_iter_close_container(&iter, &sub))
1753 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1755 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1758 return bus_send_error_reply(connection, message, &error, r);
1761 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1763 r = bus_manager_create_session(m, message, &reply);
1765 /* Don't delay the work on OOM here, since it might be
1766 * triggered by a low RLIMIT_NOFILE here (since we
1767 * send a dupped fd to the client), and we'd rather
1768 * see this fail quickly then be retried later */
1771 return bus_send_error_reply(connection, message, NULL, r);
1773 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1777 if (!dbus_message_get_args(
1780 DBUS_TYPE_STRING, &name,
1782 return bus_send_error_reply(connection, message, &error, -EINVAL);
1784 session = hashmap_get(m->sessions, name);
1786 return bus_send_error_reply(connection, message, &error, -ENOENT);
1788 /* We use the FIFO to detect stray sessions where the
1789 process invoking PAM dies abnormally. We need to make
1790 sure that that process is not killed if at the clean
1791 end of the session it closes the FIFO. Hence, with
1792 this call explicitly turn off the FIFO logic, so that
1793 the PAM code can finish clean up on its own */
1794 session_remove_fifo(session);
1796 reply = dbus_message_new_method_return(message);
1800 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1804 if (!dbus_message_get_args(
1807 DBUS_TYPE_STRING, &name,
1809 return bus_send_error_reply(connection, message, &error, -EINVAL);
1811 session = hashmap_get(m->sessions, name);
1813 return bus_send_error_reply(connection, message, &error, -ENOENT);
1815 r = session_activate(session);
1817 return bus_send_error_reply(connection, message, NULL, r);
1819 reply = dbus_message_new_method_return(message);
1823 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1824 const char *session_name, *seat_name;
1828 /* Same as ActivateSession() but refuses to work if
1829 * the seat doesn't match */
1831 if (!dbus_message_get_args(
1834 DBUS_TYPE_STRING, &session_name,
1835 DBUS_TYPE_STRING, &seat_name,
1837 return bus_send_error_reply(connection, message, &error, -EINVAL);
1839 session = hashmap_get(m->sessions, session_name);
1841 return bus_send_error_reply(connection, message, &error, -ENOENT);
1843 seat = hashmap_get(m->seats, seat_name);
1845 return bus_send_error_reply(connection, message, &error, -ENOENT);
1847 if (session->seat != seat)
1848 return bus_send_error_reply(connection, message, &error, -EINVAL);
1850 r = session_activate(session);
1852 return bus_send_error_reply(connection, message, NULL, r);
1854 reply = dbus_message_new_method_return(message);
1858 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1859 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1863 if (!dbus_message_get_args(
1866 DBUS_TYPE_STRING, &name,
1868 return bus_send_error_reply(connection, message, &error, -EINVAL);
1870 session = hashmap_get(m->sessions, name);
1872 return bus_send_error_reply(connection, message, NULL, -ENOENT);
1874 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1877 reply = dbus_message_new_method_return(message);
1881 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions") ||
1882 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSessions")) {
1884 r = session_send_lock_all(m, streq(dbus_message_get_member(message), "LockSessions"));
1886 bus_send_error_reply(connection, message, NULL, r);
1888 reply = dbus_message_new_method_return(message);
1892 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1899 if (!dbus_message_get_args(
1902 DBUS_TYPE_STRING, &name,
1903 DBUS_TYPE_STRING, &swho,
1904 DBUS_TYPE_INT32, &signo,
1906 return bus_send_error_reply(connection, message, &error, -EINVAL);
1911 who = kill_who_from_string(swho);
1913 return bus_send_error_reply(connection, message, &error, -EINVAL);
1916 if (signo <= 0 || signo >= _NSIG)
1917 return bus_send_error_reply(connection, message, &error, -EINVAL);
1919 session = hashmap_get(m->sessions, name);
1921 return bus_send_error_reply(connection, message, &error, -ENOENT);
1923 r = session_kill(session, who, signo);
1925 return bus_send_error_reply(connection, message, NULL, r);
1927 reply = dbus_message_new_method_return(message);
1931 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1936 if (!dbus_message_get_args(
1939 DBUS_TYPE_UINT32, &uid,
1940 DBUS_TYPE_INT32, &signo,
1942 return bus_send_error_reply(connection, message, &error, -EINVAL);
1944 if (signo <= 0 || signo >= _NSIG)
1945 return bus_send_error_reply(connection, message, &error, -EINVAL);
1947 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1949 return bus_send_error_reply(connection, message, &error, -ENOENT);
1951 r = user_kill(user, signo);
1953 return bus_send_error_reply(connection, message, NULL, r);
1955 reply = dbus_message_new_method_return(message);
1959 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1963 if (!dbus_message_get_args(
1966 DBUS_TYPE_STRING, &name,
1968 return bus_send_error_reply(connection, message, &error, -EINVAL);
1970 session = hashmap_get(m->sessions, name);
1972 return bus_send_error_reply(connection, message, &error, -ENOENT);
1974 r = session_stop(session);
1976 return bus_send_error_reply(connection, message, NULL, r);
1978 reply = dbus_message_new_method_return(message);
1982 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1986 if (!dbus_message_get_args(
1989 DBUS_TYPE_UINT32, &uid,
1991 return bus_send_error_reply(connection, message, &error, -EINVAL);
1993 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1995 return bus_send_error_reply(connection, message, &error, -ENOENT);
1997 r = user_stop(user);
1999 return bus_send_error_reply(connection, message, NULL, r);
2001 reply = dbus_message_new_method_return(message);
2005 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
2009 if (!dbus_message_get_args(
2012 DBUS_TYPE_STRING, &name,
2014 return bus_send_error_reply(connection, message, &error, -EINVAL);
2016 seat = hashmap_get(m->seats, name);
2018 return bus_send_error_reply(connection, message, &error, -ENOENT);
2020 r = seat_stop_sessions(seat);
2022 return bus_send_error_reply(connection, message, NULL, r);
2024 reply = dbus_message_new_method_return(message);
2028 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
2031 dbus_bool_t b, interactive;
2034 if (!dbus_message_get_args(
2037 DBUS_TYPE_UINT32, &uid,
2038 DBUS_TYPE_BOOLEAN, &b,
2039 DBUS_TYPE_BOOLEAN, &interactive,
2041 return bus_send_error_reply(connection, message, &error, -EINVAL);
2046 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
2048 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
2050 return bus_send_error_reply(connection, message, &error, r);
2052 mkdir_p_label("/var/lib/systemd", 0755);
2054 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
2056 return bus_send_error_reply(connection, message, &error, r);
2058 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
2069 return bus_send_error_reply(connection, message, &error, r);
2071 if (manager_add_user_by_uid(m, uid, &u) >= 0)
2080 if (r < 0 && errno != ENOENT)
2081 return bus_send_error_reply(connection, message, &error, -errno);
2083 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
2085 user_add_to_gc_queue(u);
2088 reply = dbus_message_new_method_return(message);
2092 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
2093 const char *sysfs, *seat;
2094 dbus_bool_t interactive;
2096 if (!dbus_message_get_args(
2099 DBUS_TYPE_STRING, &seat,
2100 DBUS_TYPE_STRING, &sysfs,
2101 DBUS_TYPE_BOOLEAN, &interactive,
2103 return bus_send_error_reply(connection, message, &error, -EINVAL);
2105 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
2106 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2108 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
2110 return bus_send_error_reply(connection, message, &error, r);
2112 r = attach_device(m, seat, sysfs);
2114 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2116 reply = dbus_message_new_method_return(message);
2121 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
2122 dbus_bool_t interactive;
2124 if (!dbus_message_get_args(
2127 DBUS_TYPE_BOOLEAN, &interactive,
2129 return bus_send_error_reply(connection, message, &error, -EINVAL);
2131 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
2133 return bus_send_error_reply(connection, message, &error, r);
2135 r = flush_devices(m);
2137 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2139 reply = dbus_message_new_method_return(message);
2143 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
2145 r = bus_manager_do_shutdown_or_sleep(
2146 m, connection, message,
2147 SPECIAL_POWEROFF_TARGET,
2149 "org.freedesktop.login1.power-off",
2150 "org.freedesktop.login1.power-off-multiple-sessions",
2151 "org.freedesktop.login1.power-off-ignore-inhibit",
2155 return bus_send_error_reply(connection, message, &error, r);
2156 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
2157 r = bus_manager_do_shutdown_or_sleep(
2158 m, connection, message,
2159 SPECIAL_REBOOT_TARGET,
2161 "org.freedesktop.login1.reboot",
2162 "org.freedesktop.login1.reboot-multiple-sessions",
2163 "org.freedesktop.login1.reboot-ignore-inhibit",
2167 return bus_send_error_reply(connection, message, &error, r);
2169 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2170 r = bus_manager_do_shutdown_or_sleep(
2171 m, connection, message,
2172 SPECIAL_SUSPEND_TARGET,
2174 "org.freedesktop.login1.suspend",
2175 "org.freedesktop.login1.suspend-multiple-sessions",
2176 "org.freedesktop.login1.suspend-ignore-inhibit",
2180 return bus_send_error_reply(connection, message, &error, r);
2181 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2182 r = bus_manager_do_shutdown_or_sleep(
2183 m, connection, message,
2184 SPECIAL_HIBERNATE_TARGET,
2186 "org.freedesktop.login1.hibernate",
2187 "org.freedesktop.login1.hibernate-multiple-sessions",
2188 "org.freedesktop.login1.hibernate-ignore-inhibit",
2192 return bus_send_error_reply(connection, message, &error, r);
2194 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "HybridSleep")) {
2195 r = bus_manager_do_shutdown_or_sleep(
2196 m, connection, message,
2197 SPECIAL_HYBRID_SLEEP_TARGET,
2199 "org.freedesktop.login1.hibernate",
2200 "org.freedesktop.login1.hibernate-multiple-sessions",
2201 "org.freedesktop.login1.hibernate-ignore-inhibit",
2205 return bus_send_error_reply(connection, message, &error, r);
2207 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2209 r = bus_manager_can_shutdown_or_sleep(
2210 m, connection, message,
2212 "org.freedesktop.login1.power-off",
2213 "org.freedesktop.login1.power-off-multiple-sessions",
2214 "org.freedesktop.login1.power-off-ignore-inhibit",
2218 return bus_send_error_reply(connection, message, &error, r);
2219 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2220 r = bus_manager_can_shutdown_or_sleep(
2221 m, connection, message,
2223 "org.freedesktop.login1.reboot",
2224 "org.freedesktop.login1.reboot-multiple-sessions",
2225 "org.freedesktop.login1.reboot-ignore-inhibit",
2229 return bus_send_error_reply(connection, message, &error, r);
2231 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2232 r = bus_manager_can_shutdown_or_sleep(
2233 m, connection, message,
2235 "org.freedesktop.login1.suspend",
2236 "org.freedesktop.login1.suspend-multiple-sessions",
2237 "org.freedesktop.login1.suspend-ignore-inhibit",
2241 return bus_send_error_reply(connection, message, &error, r);
2243 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2244 r = bus_manager_can_shutdown_or_sleep(
2245 m, connection, message,
2247 "org.freedesktop.login1.hibernate",
2248 "org.freedesktop.login1.hibernate-multiple-sessions",
2249 "org.freedesktop.login1.hibernate-ignore-inhibit",
2253 return bus_send_error_reply(connection, message, &error, r);
2255 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHybridSleep")) {
2256 r = bus_manager_can_shutdown_or_sleep(
2257 m, connection, message,
2259 "org.freedesktop.login1.hibernate",
2260 "org.freedesktop.login1.hibernate-multiple-sessions",
2261 "org.freedesktop.login1.hibernate-ignore-inhibit",
2265 return bus_send_error_reply(connection, message, &error, r);
2267 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2268 char *introspection = NULL;
2277 if (!(reply = dbus_message_new_method_return(message)))
2280 /* We roll our own introspection code here, instead of
2281 * relying on bus_default_message_handler() because we
2282 * need to generate our introspection string
2285 if (!(f = open_memstream(&introspection, &size)))
2288 fputs(INTROSPECTION_BEGIN, f);
2290 HASHMAP_FOREACH(seat, m->seats, i) {
2291 p = bus_path_escape(seat->id);
2294 fprintf(f, "<node name=\"seat/%s\"/>", p);
2299 HASHMAP_FOREACH(user, m->users, i)
2300 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2302 HASHMAP_FOREACH(session, m->sessions, i) {
2303 p = bus_path_escape(session->id);
2306 fprintf(f, "<node name=\"session/%s\"/>", p);
2311 fputs(INTROSPECTION_END, f);
2315 free(introspection);
2324 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2325 free(introspection);
2329 free(introspection);
2331 const BusBoundProperties bps[] = {
2332 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2335 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2339 if (!bus_maybe_send_reply(connection, message, reply))
2342 dbus_message_unref(reply);
2345 return DBUS_HANDLER_RESULT_HANDLED;
2349 dbus_message_unref(reply);
2351 dbus_error_free(&error);
2353 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2356 const DBusObjectPathVTable bus_manager_vtable = {
2357 .message_function = manager_message_handler
2360 DBusHandlerResult bus_message_filter(
2361 DBusConnection *connection,
2362 DBusMessage *message,
2365 Manager *m = userdata;
2372 dbus_error_init(&error);
2374 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
2377 if (!dbus_message_get_args(message, &error,
2378 DBUS_TYPE_STRING, &cgroup,
2380 log_error("Failed to parse Released message: %s", bus_error_message(&error));
2382 manager_cgroup_notify_empty(m, cgroup);
2384 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
2386 const char *path, *result, *unit;
2388 if (!dbus_message_get_args(message, &error,
2389 DBUS_TYPE_UINT32, &id,
2390 DBUS_TYPE_OBJECT_PATH, &path,
2391 DBUS_TYPE_STRING, &unit,
2392 DBUS_TYPE_STRING, &result,
2394 log_error("Failed to parse JobRemoved message: %s", bus_error_message(&error));
2396 else if (m->action_job && streq(m->action_job, path)) {
2398 log_info("Operation finished.");
2400 /* Tell people that they now may take a lock again */
2401 send_prepare_for(m, m->action_what, false);
2403 free(m->action_job);
2404 m->action_job = NULL;
2405 m->action_unit = NULL;
2410 dbus_error_free(&error);
2412 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2415 int manager_send_changed(Manager *manager, const char *properties) {
2421 m = bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties);
2425 if (!dbus_connection_send(manager->bus, m, NULL))
2432 dbus_message_unref(m);
2437 int manager_dispatch_delayed(Manager *manager) {
2443 if (!manager->action_unit || manager->action_job)
2446 /* Continue delay? */
2447 if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0)) {
2449 if (manager->action_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC))
2452 log_info("Delay lock is active but inhibitor timeout is reached.");
2455 /* Actually do the operation */
2456 dbus_error_init(&error);
2457 r = execute_shutdown_or_sleep(manager, manager->action_what, manager->action_unit, &error);
2459 log_warning("Failed to send delayed message: %s", bus_error_message_or_strerror(&error, -r));
2460 dbus_error_free(&error);
2462 manager->action_unit = NULL;
2463 manager->action_what = 0;