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 "sleep-config.h"
35 #include "systemd/sd-id128.h"
36 #include "systemd/sd-messages.h"
37 #include "fileio-label.h"
40 #define BUS_MANAGER_INTERFACE \
41 " <interface name=\"org.freedesktop.login1.Manager\">\n" \
42 " <method name=\"GetSession\">\n" \
43 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
44 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
46 " <method name=\"GetSessionByPID\">\n" \
47 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
48 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
50 " <method name=\"GetUser\">\n" \
51 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
52 " <arg name=\"user\" type=\"o\" direction=\"out\"/>\n" \
54 " <method name=\"GetSeat\">\n" \
55 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
56 " <arg name=\"seat\" type=\"o\" direction=\"out\"/>\n" \
58 " <method name=\"ListSessions\">\n" \
59 " <arg name=\"sessions\" type=\"a(susso)\" direction=\"out\"/>\n" \
61 " <method name=\"ListUsers\">\n" \
62 " <arg name=\"users\" type=\"a(uso)\" direction=\"out\"/>\n" \
64 " <method name=\"ListSeats\">\n" \
65 " <arg name=\"seats\" type=\"a(so)\" direction=\"out\"/>\n" \
67 " <method name=\"CreateSession\">\n" \
68 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
69 " <arg name=\"leader\" type=\"u\" direction=\"in\"/>\n" \
70 " <arg name=\"service\" type=\"s\" direction=\"in\"/>\n" \
71 " <arg name=\"type\" type=\"s\" direction=\"in\"/>\n" \
72 " <arg name=\"class\" type=\"s\" direction=\"in\"/>\n" \
73 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
74 " <arg name=\"vtnr\" type=\"u\" direction=\"in\"/>\n" \
75 " <arg name=\"tty\" type=\"s\" direction=\"in\"/>\n" \
76 " <arg name=\"display\" type=\"s\" direction=\"in\"/>\n" \
77 " <arg name=\"remote\" type=\"b\" direction=\"in\"/>\n" \
78 " <arg name=\"remote_user\" type=\"s\" direction=\"in\"/>\n" \
79 " <arg name=\"remote_host\" type=\"s\" direction=\"in\"/>\n" \
80 " <arg name=\"controllers\" type=\"as\" direction=\"in\"/>\n" \
81 " <arg name=\"reset_controllers\" type=\"as\" direction=\"in\"/>\n" \
82 " <arg name=\"kill_processes\" type=\"b\" direction=\"in\"/>\n" \
83 " <arg name=\"id\" type=\"s\" direction=\"out\"/>\n" \
84 " <arg name=\"path\" type=\"o\" direction=\"out\"/>\n" \
85 " <arg name=\"runtime_path\" type=\"o\" direction=\"out\"/>\n" \
86 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
87 " <arg name=\"seat\" type=\"s\" direction=\"out\"/>\n" \
88 " <arg name=\"vtnr\" type=\"u\" direction=\"out\"/>\n" \
89 " <arg name=\"existing\" type=\"b\" direction=\"out\"/>\n" \
91 " <method name=\"ReleaseSession\">\n" \
92 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
94 " <method name=\"ActivateSession\">\n" \
95 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
97 " <method name=\"ActivateSessionOnSeat\">\n" \
98 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
99 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
101 " <method name=\"LockSession\">\n" \
102 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
104 " <method name=\"UnlockSession\">\n" \
105 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
107 " <method name=\"LockSessions\"/>\n" \
108 " <method name=\"UnlockSessions\"/>\n" \
109 " <method name=\"KillSession\">\n" \
110 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
111 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
112 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
114 " <method name=\"KillUser\">\n" \
115 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
116 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
118 " <method name=\"TerminateSession\">\n" \
119 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
121 " <method name=\"TerminateUser\">\n" \
122 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
124 " <method name=\"TerminateSeat\">\n" \
125 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
127 " <method name=\"SetUserLinger\">\n" \
128 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
129 " <arg name=\"b\" type=\"b\" direction=\"in\"/>\n" \
130 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
132 " <method name=\"AttachDevice\">\n" \
133 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
134 " <arg name=\"sysfs\" type=\"s\" direction=\"in\"/>\n" \
135 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
137 " <method name=\"FlushDevices\">\n" \
138 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
140 " <method name=\"PowerOff\">\n" \
141 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
143 " <method name=\"Reboot\">\n" \
144 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
146 " <method name=\"Suspend\">\n" \
147 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
149 " <method name=\"Hibernate\">\n" \
150 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
152 " <method name=\"HybridSleep\">\n" \
153 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
155 " <method name=\"CanPowerOff\">\n" \
156 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
158 " <method name=\"CanReboot\">\n" \
159 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
161 " <method name=\"CanSuspend\">\n" \
162 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
164 " <method name=\"CanHibernate\">\n" \
165 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
167 " <method name=\"CanHybridSleep\">\n" \
168 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
170 " <method name=\"Inhibit\">\n" \
171 " <arg name=\"what\" type=\"s\" direction=\"in\"/>\n" \
172 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
173 " <arg name=\"why\" type=\"s\" direction=\"in\"/>\n" \
174 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
175 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
177 " <method name=\"ListInhibitors\">\n" \
178 " <arg name=\"inhibitors\" type=\"a(ssssuu)\" direction=\"out\"/>\n" \
180 " <signal name=\"SessionNew\">\n" \
181 " <arg name=\"id\" type=\"s\"/>\n" \
182 " <arg name=\"path\" type=\"o\"/>\n" \
184 " <signal name=\"SessionRemoved\">\n" \
185 " <arg name=\"id\" type=\"s\"/>\n" \
186 " <arg name=\"path\" type=\"o\"/>\n" \
188 " <signal name=\"UserNew\">\n" \
189 " <arg name=\"uid\" type=\"u\"/>\n" \
190 " <arg name=\"path\" type=\"o\"/>\n" \
192 " <signal name=\"UserRemoved\">\n" \
193 " <arg name=\"uid\" type=\"u\"/>\n" \
194 " <arg name=\"path\" type=\"o\"/>\n" \
196 " <signal name=\"SeatNew\">\n" \
197 " <arg name=\"id\" type=\"s\"/>\n" \
198 " <arg name=\"path\" type=\"o\"/>\n" \
200 " <signal name=\"SeatRemoved\">\n" \
201 " <arg name=\"id\" type=\"s\"/>\n" \
202 " <arg name=\"path\" type=\"o\"/>\n" \
204 " <signal name=\"PrepareForShutdown\">\n" \
205 " <arg name=\"active\" type=\"b\"/>\n" \
207 " <signal name=\"PrepareForSleep\">\n" \
208 " <arg name=\"active\" type=\"b\"/>\n" \
210 " <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
211 " <property name=\"Controllers\" type=\"as\" access=\"read\"/>\n" \
212 " <property name=\"ResetControllers\" type=\"as\" access=\"read\"/>\n" \
213 " <property name=\"NAutoVTs\" type=\"u\" access=\"read\"/>\n" \
214 " <property name=\"KillOnlyUsers\" type=\"as\" access=\"read\"/>\n" \
215 " <property name=\"KillExcludeUsers\" type=\"as\" access=\"read\"/>\n" \
216 " <property name=\"KillUserProcesses\" type=\"b\" access=\"read\"/>\n" \
217 " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
218 " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
219 " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
220 " <property name=\"BlockInhibited\" type=\"s\" access=\"read\"/>\n" \
221 " <property name=\"DelayInhibited\" type=\"s\" access=\"read\"/>\n" \
222 " <property name=\"InhibitDelayMaxUSec\" type=\"t\" access=\"read\"/>\n" \
223 " <property name=\"HandlePowerKey\" type=\"s\" access=\"read\"/>\n" \
224 " <property name=\"HandleSuspendKey\" type=\"s\" access=\"read\"/>\n" \
225 " <property name=\"HandleHibernateKey\" type=\"s\" access=\"read\"/>\n" \
226 " <property name=\"HandleLidSwitch\" type=\"s\" access=\"read\"/>\n" \
227 " <property name=\"IdleAction\" type=\"s\" access=\"read\"/>\n" \
228 " <property name=\"IdleActionUSec\" type=\"t\" access=\"read\"/>\n" \
229 " <property name=\"PreparingForShutdown\" type=\"b\" access=\"read\"/>\n" \
230 " <property name=\"PreparingForSleep\" type=\"b\" access=\"read\"/>\n" \
233 #define INTROSPECTION_BEGIN \
234 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
236 BUS_MANAGER_INTERFACE \
237 BUS_PROPERTIES_INTERFACE \
239 BUS_INTROSPECTABLE_INTERFACE
241 #define INTROSPECTION_END \
244 #define INTERFACES_LIST \
245 BUS_GENERIC_INTERFACES_LIST \
246 "org.freedesktop.login1.Manager\0"
248 static int bus_manager_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
256 b = manager_get_idle_hint(m, NULL) > 0;
257 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
263 static int bus_manager_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
272 manager_get_idle_hint(m, &t);
273 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
275 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
281 static int bus_manager_append_inhibited(DBusMessageIter *i, const char *property, void *data) {
286 w = manager_inhibit_what(m, streq(property, "BlockInhibited") ? INHIBIT_BLOCK : INHIBIT_DELAY);
287 p = inhibit_what_to_string(w);
289 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &p))
295 static int bus_manager_append_preparing(DBusMessageIter *i, const char *property, void *data) {
302 if (streq(property, "PreparingForShutdown"))
303 b = !!(m->action_what & INHIBIT_SHUTDOWN);
305 b = !!(m->action_what & INHIBIT_SLEEP);
307 dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b);
311 static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMessage **_reply) {
312 const char *type, *class, *cseat, *tty, *display, *remote_user, *remote_host, *service;
313 uint32_t uid, leader, audit_id = 0;
314 dbus_bool_t remote, kill_processes, exists;
315 _cleanup_strv_free_ char **controllers = NULL, **reset_controllers = NULL;
316 _cleanup_free_ char *cgroup = NULL, *id = NULL, *p = NULL;
319 DBusMessageIter iter;
322 _cleanup_close_ int fifo_fd = -1;
323 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
324 Session *session = NULL;
333 if (!dbus_message_iter_init(message, &iter) ||
334 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
337 dbus_message_iter_get_basic(&iter, &uid);
339 if (!dbus_message_iter_next(&iter) ||
340 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
343 dbus_message_iter_get_basic(&iter, &leader);
346 !dbus_message_iter_next(&iter) ||
347 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
350 dbus_message_iter_get_basic(&iter, &service);
352 if (!dbus_message_iter_next(&iter) ||
353 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
356 dbus_message_iter_get_basic(&iter, &type);
358 t = _SESSION_TYPE_INVALID;
360 t = session_type_from_string(type);
365 if (!dbus_message_iter_next(&iter) ||
366 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
369 dbus_message_iter_get_basic(&iter, &class);
371 c = _SESSION_CLASS_INVALID;
373 c = session_class_from_string(class);
378 if (!dbus_message_iter_next(&iter) ||
379 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
382 dbus_message_iter_get_basic(&iter, &cseat);
387 seat = hashmap_get(m->seats, cseat);
392 if (!dbus_message_iter_next(&iter) ||
393 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
396 dbus_message_iter_get_basic(&iter, &vtnr);
398 if (!dbus_message_iter_next(&iter) ||
399 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
402 dbus_message_iter_get_basic(&iter, &tty);
404 if (tty_is_vc(tty)) {
409 else if (seat != m->vtconsole)
412 v = vtnr_from_tty(tty);
415 return v < 0 ? v : -EINVAL;
419 else if (vtnr != (uint32_t) v)
421 } else if (tty_is_console(tty)) {
425 else if (seat != m->vtconsole)
433 if (seat_can_multi_session(seat)) {
442 if (!dbus_message_iter_next(&iter) ||
443 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
446 dbus_message_iter_get_basic(&iter, &display);
448 if (!dbus_message_iter_next(&iter) ||
449 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
452 if (t == _SESSION_TYPE_INVALID) {
453 if (!isempty(display))
455 else if (!isempty(tty))
458 t = SESSION_UNSPECIFIED;
461 if (c == _SESSION_CLASS_INVALID) {
462 if (!isempty(display) || !isempty(tty))
465 c = SESSION_BACKGROUND;
468 dbus_message_iter_get_basic(&iter, &remote);
470 if (!dbus_message_iter_next(&iter) ||
471 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
474 dbus_message_iter_get_basic(&iter, &remote_user);
476 if (!dbus_message_iter_next(&iter) ||
477 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
480 dbus_message_iter_get_basic(&iter, &remote_host);
482 if (!dbus_message_iter_next(&iter) ||
483 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
484 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
487 r = bus_parse_strv_iter(&iter, &controllers);
491 if (!dbus_message_iter_next(&iter) ||
492 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
493 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) {
498 r = bus_parse_strv_iter(&iter, &reset_controllers);
502 if (!dbus_message_iter_next(&iter) ||
503 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) {
508 dbus_message_iter_get_basic(&iter, &kill_processes);
510 r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, leader, &cgroup);
514 r = manager_get_session_by_cgroup(m, cgroup, &session);
519 fifo_fd = session_create_fifo(session);
525 /* Session already exists, client is probably
526 * something like "su" which changes uid but
527 * is still the same audit session */
529 reply = dbus_message_new_method_return(message);
535 p = session_bus_path(session);
541 cseat = session->seat ? session->seat->id : "";
542 vtnr = session->vtnr;
545 b = dbus_message_append_args(
547 DBUS_TYPE_STRING, &session->id,
548 DBUS_TYPE_OBJECT_PATH, &p,
549 DBUS_TYPE_STRING, &session->user->runtime_path,
550 DBUS_TYPE_UNIX_FD, &fifo_fd,
551 DBUS_TYPE_STRING, &cseat,
552 DBUS_TYPE_UINT32, &vtnr,
553 DBUS_TYPE_BOOLEAN, &exists,
566 audit_session_from_pid(leader, &audit_id);
568 /* Keep our session IDs and the audit session IDs in sync */
570 if (asprintf(&id, "%lu", (unsigned long) audit_id) < 0) {
575 /* Wut? There's already a session by this name and we
576 * didn't find it above? Weird, then let's not trust
577 * the audit data and let's better register a new
579 if (hashmap_get(m->sessions, id)) {
592 if (asprintf(&id, "c%lu", ++m->session_counter) < 0) {
597 } while (hashmap_get(m->sessions, id));
600 r = manager_add_user_by_uid(m, uid, &user);
604 r = manager_add_session(m, user, id, &session);
608 session->leader = leader;
609 session->audit_id = audit_id;
612 session->remote = remote;
613 session->kill_processes = kill_processes;
614 session->vtnr = vtnr;
616 session->controllers = cg_shorten_controllers(controllers);
617 session->reset_controllers = cg_shorten_controllers(reset_controllers);
618 controllers = reset_controllers = NULL;
621 session->tty = strdup(tty);
628 if (!isempty(display)) {
629 session->display = strdup(display);
630 if (!session->display) {
636 if (!isempty(remote_user)) {
637 session->remote_user = strdup(remote_user);
638 if (!session->remote_user) {
644 if (!isempty(remote_host)) {
645 session->remote_host = strdup(remote_host);
646 if (!session->remote_host) {
652 if (!isempty(service)) {
653 session->service = strdup(service);
654 if (!session->service) {
660 fifo_fd = session_create_fifo(session);
667 r = seat_attach_session(seat, session);
672 r = session_start(session);
676 reply = dbus_message_new_method_return(message);
682 p = session_bus_path(session);
688 cseat = seat ? seat->id : "";
690 b = dbus_message_append_args(
692 DBUS_TYPE_STRING, &session->id,
693 DBUS_TYPE_OBJECT_PATH, &p,
694 DBUS_TYPE_STRING, &session->user->runtime_path,
695 DBUS_TYPE_UNIX_FD, &fifo_fd,
696 DBUS_TYPE_STRING, &cseat,
697 DBUS_TYPE_UINT32, &vtnr,
698 DBUS_TYPE_BOOLEAN, &exists,
713 session_add_to_gc_queue(session);
716 user_add_to_gc_queue(user);
721 static int bus_manager_inhibit(
723 DBusConnection *connection,
724 DBusMessage *message,
726 DBusMessage **_reply) {
730 const char *who, *why, *what, *mode;
736 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
744 if (!dbus_message_get_args(
747 DBUS_TYPE_STRING, &what,
748 DBUS_TYPE_STRING, &who,
749 DBUS_TYPE_STRING, &why,
750 DBUS_TYPE_STRING, &mode,
751 DBUS_TYPE_INVALID)) {
756 w = inhibit_what_from_string(what);
762 mm = inhibit_mode_from_string(mode);
768 /* Delay is only supported for shutdown/sleep */
769 if (mm == INHIBIT_DELAY && (w & ~(INHIBIT_SHUTDOWN|INHIBIT_SLEEP))) {
774 /* Don't allow taking delay locks while we are already
775 * executing the operation. We shouldn't create the impression
776 * that the lock was successful if the machine is about to go
777 * down/suspend any moment. */
778 if (m->action_what & w) {
783 r = verify_polkit(connection, message,
784 w == INHIBIT_SHUTDOWN ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
785 w == INHIBIT_SLEEP ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep" : "org.freedesktop.login1.inhibit-delay-sleep") :
786 w == INHIBIT_IDLE ? "org.freedesktop.login1.inhibit-block-idle" :
787 w == INHIBIT_HANDLE_POWER_KEY ? "org.freedesktop.login1.inhibit-handle-power-key" :
788 w == INHIBIT_HANDLE_SUSPEND_KEY ? "org.freedesktop.login1.inhibit-handle-suspend-key" :
789 w == INHIBIT_HANDLE_HIBERNATE_KEY ? "org.freedesktop.login1.inhibit-handle-hibernate-key" :
790 "org.freedesktop.login1.inhibit-handle-lid-switch",
795 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
796 if (ul == (unsigned long) -1) {
801 pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
811 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
815 } while (hashmap_get(m->inhibitors, id));
817 r = manager_add_inhibitor(m, id, &i);
827 i->why = strdup(why);
828 i->who = strdup(who);
830 if (!i->why || !i->who) {
835 fifo_fd = inhibitor_create_fifo(i);
841 reply = dbus_message_new_method_return(message);
847 if (!dbus_message_append_args(
849 DBUS_TYPE_UNIX_FD, &fifo_fd,
850 DBUS_TYPE_INVALID)) {
855 close_nointr_nofail(fifo_fd);
868 close_nointr_nofail(fifo_fd);
873 static int trigger_device(Manager *m, struct udev_device *d) {
874 struct udev_enumerate *e;
875 struct udev_list_entry *first, *item;
880 e = udev_enumerate_new(m->udev);
887 if (udev_enumerate_add_match_parent(e, d) < 0) {
893 if (udev_enumerate_scan_devices(e) < 0) {
898 first = udev_enumerate_get_list_entry(e);
899 udev_list_entry_foreach(item, first) {
903 p = udev_list_entry_get_name(item);
905 t = strappend(p, "/uevent");
911 write_string_file(t, "change");
919 udev_enumerate_unref(e);
924 static int attach_device(Manager *m, const char *seat, const char *sysfs) {
925 struct udev_device *d;
926 _cleanup_free_ char *rule = NULL, *file = NULL;
927 const char *id_for_seat;
934 d = udev_device_new_from_syspath(m->udev, sysfs);
938 if (!udev_device_has_tag(d, "seat")) {
943 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
949 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
954 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
959 mkdir_p_label("/etc/udev/rules.d", 0755);
961 r = write_string_file_atomic_label(file, rule);
965 r = trigger_device(m, d);
969 udev_device_unref(d);
974 static int flush_devices(Manager *m) {
975 _cleanup_closedir_ DIR *d;
979 d = opendir("/etc/udev/rules.d");
982 log_warning("Failed to open /etc/udev/rules.d: %m");
986 while ((de = readdir(d))) {
988 if (!dirent_is_file(de))
991 if (!startswith(de->d_name, "72-seat-"))
994 if (!endswith(de->d_name, ".rules"))
997 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
998 log_warning("Failed to unlink %s: %m", de->d_name);
1002 return trigger_device(m, NULL);
1005 static int have_multiple_sessions(
1014 /* Check for other users' sessions. Greeter sessions do not
1015 * count, and non-login sessions do not count either. */
1016 HASHMAP_FOREACH(session, m->sessions, i)
1017 if (session->class == SESSION_USER &&
1018 session->user->uid != uid)
1024 static int bus_manager_log_shutdown(
1027 const char *unit_name) {
1034 if (w != INHIBIT_SHUTDOWN)
1037 if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
1038 p = "MESSAGE=System is powering down.";
1039 q = "SHUTDOWN=power-off";
1040 } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
1041 p = "MESSAGE=System is halting.";
1042 q = "SHUTDOWN=halt";
1043 } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
1044 p = "MESSAGE=System is rebooting.";
1045 q = "SHUTDOWN=reboot";
1046 } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
1047 p = "MESSAGE=System is rebooting with kexec.";
1048 q = "SHUTDOWN=kexec";
1050 p = "MESSAGE=System is shutting down.";
1054 return log_struct(LOG_NOTICE, MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
1059 static int execute_shutdown_or_sleep(
1062 const char *unit_name,
1065 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1066 const char *mode = "replace-irreversibly", *p;
1072 assert(w < _INHIBIT_WHAT_MAX);
1075 bus_manager_log_shutdown(m, w, unit_name);
1077 r = bus_method_call_with_reply(
1079 "org.freedesktop.systemd1",
1080 "/org/freedesktop/systemd1",
1081 "org.freedesktop.systemd1.Manager",
1085 DBUS_TYPE_STRING, &unit_name,
1086 DBUS_TYPE_STRING, &mode,
1091 if (!dbus_message_get_args(
1094 DBUS_TYPE_OBJECT_PATH, &p,
1102 m->action_unit = unit_name;
1103 free(m->action_job);
1110 static int delay_shutdown_or_sleep(
1113 const char *unit_name) {
1117 assert(w < _INHIBIT_WHAT_MAX);
1120 m->action_timestamp = now(CLOCK_MONOTONIC);
1121 m->action_unit = unit_name;
1127 static int bus_manager_can_shutdown_or_sleep(
1129 DBusConnection *connection,
1130 DBusMessage *message,
1133 const char *action_multiple_sessions,
1134 const char *action_ignore_inhibit,
1135 const char *sleep_verb,
1137 DBusMessage **_reply) {
1139 bool multiple_sessions, challenge, blocked, b;
1140 const char *result = NULL;
1141 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1149 assert(w <= _INHIBIT_WHAT_MAX);
1151 assert(action_multiple_sessions);
1152 assert(action_ignore_inhibit);
1157 r = can_sleep(sleep_verb);
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,
1236 static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
1237 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
1238 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
1239 [INHIBIT_SLEEP] = "PrepareForSleep"
1242 dbus_bool_t active = _active;
1243 _cleanup_dbus_message_unref_ DBusMessage *message = NULL;
1247 assert(w < _INHIBIT_WHAT_MAX);
1248 assert(signal_name[w]);
1250 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1254 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1255 !dbus_connection_send(m->bus, message, NULL))
1261 int bus_manager_shutdown_or_sleep_now_or_later(
1263 const char *unit_name,
1273 assert(w <= _INHIBIT_WHAT_MAX);
1274 assert(!m->action_job);
1276 /* Tell everybody to prepare for shutdown/sleep */
1277 send_prepare_for(m, w, true);
1280 m->inhibit_delay_max > 0 &&
1281 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0);
1284 /* Shutdown is delayed, keep in mind what we
1285 * want to do, and start a timeout */
1286 r = delay_shutdown_or_sleep(m, w, unit_name);
1288 /* Shutdown is not delayed, execute it
1290 r = execute_shutdown_or_sleep(m, w, unit_name, error);
1295 static int bus_manager_do_shutdown_or_sleep(
1297 DBusConnection *connection,
1298 DBusMessage *message,
1299 const char *unit_name,
1302 const char *action_multiple_sessions,
1303 const char *action_ignore_inhibit,
1304 const char *sleep_verb,
1306 DBusMessage **_reply) {
1308 dbus_bool_t interactive;
1309 bool multiple_sessions, blocked;
1310 DBusMessage *reply = NULL;
1319 assert(w <= _INHIBIT_WHAT_MAX);
1321 assert(action_multiple_sessions);
1322 assert(action_ignore_inhibit);
1326 /* Don't allow multiple jobs being executed at the same time */
1330 if (!dbus_message_get_args(
1333 DBUS_TYPE_BOOLEAN, &interactive,
1338 r = can_sleep(sleep_verb);
1346 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1347 if (ul == (unsigned long) -1)
1350 r = have_multiple_sessions(m, (uid_t) ul);
1354 multiple_sessions = r > 0;
1355 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1357 if (multiple_sessions) {
1358 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1364 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1369 if (!multiple_sessions && !blocked) {
1370 r = verify_polkit(connection, message, action, interactive, NULL, error);
1375 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
1379 reply = dbus_message_new_method_return(message);
1387 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_action, handle_action, HandleAction);
1389 static const BusProperty bus_login_manager_properties[] = {
1390 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_path), true },
1391 { "Controllers", bus_property_append_strv, "as", offsetof(Manager, controllers), true },
1392 { "ResetControllers", bus_property_append_strv, "as", offsetof(Manager, reset_controllers), true },
1393 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1394 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1395 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1396 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1397 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1398 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1399 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
1400 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1401 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1402 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
1403 { "HandlePowerKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_power_key) },
1404 { "HandleSuspendKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_suspend_key) },
1405 { "HandleHibernateKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_hibernate_key)},
1406 { "HandleLidSwitch", bus_manager_append_handle_action, "s", offsetof(Manager, handle_lid_switch) },
1407 { "IdleAction", bus_manager_append_handle_action, "s", offsetof(Manager, idle_action) },
1408 { "IdleActionUSec", bus_property_append_usec, "t", offsetof(Manager, idle_action_usec) },
1409 { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
1410 { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
1414 static DBusHandlerResult manager_message_handler(
1415 DBusConnection *connection,
1416 DBusMessage *message,
1419 Manager *m = userdata;
1422 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1429 dbus_error_init(&error);
1431 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1437 if (!dbus_message_get_args(
1440 DBUS_TYPE_STRING, &name,
1442 return bus_send_error_reply(connection, message, &error, -EINVAL);
1444 session = hashmap_get(m->sessions, name);
1446 return bus_send_error_reply(connection, message, &error, -ENOENT);
1448 reply = dbus_message_new_method_return(message);
1452 p = session_bus_path(session);
1456 b = dbus_message_append_args(
1458 DBUS_TYPE_OBJECT_PATH, &p,
1465 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1471 if (!dbus_message_get_args(
1474 DBUS_TYPE_UINT32, &pid,
1476 return bus_send_error_reply(connection, message, &error, -EINVAL);
1478 r = manager_get_session_by_pid(m, pid, &session);
1480 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1482 reply = dbus_message_new_method_return(message);
1486 p = session_bus_path(session);
1490 b = dbus_message_append_args(
1492 DBUS_TYPE_OBJECT_PATH, &p,
1499 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1505 if (!dbus_message_get_args(
1508 DBUS_TYPE_UINT32, &uid,
1510 return bus_send_error_reply(connection, message, &error, -EINVAL);
1512 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1514 return bus_send_error_reply(connection, message, &error, -ENOENT);
1516 reply = dbus_message_new_method_return(message);
1520 p = user_bus_path(user);
1524 b = dbus_message_append_args(
1526 DBUS_TYPE_OBJECT_PATH, &p,
1533 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1539 if (!dbus_message_get_args(
1542 DBUS_TYPE_STRING, &name,
1544 return bus_send_error_reply(connection, message, &error, -EINVAL);
1546 seat = hashmap_get(m->seats, name);
1548 return bus_send_error_reply(connection, message, &error, -ENOENT);
1550 reply = dbus_message_new_method_return(message);
1554 p = seat_bus_path(seat);
1558 b = dbus_message_append_args(
1560 DBUS_TYPE_OBJECT_PATH, &p,
1567 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1571 DBusMessageIter iter, sub;
1572 const char *empty = "";
1574 reply = dbus_message_new_method_return(message);
1578 dbus_message_iter_init_append(reply, &iter);
1580 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1583 HASHMAP_FOREACH(session, m->sessions, i) {
1584 DBusMessageIter sub2;
1587 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1590 uid = session->user->uid;
1592 p = session_bus_path(session);
1596 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1597 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1598 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1599 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1600 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1607 if (!dbus_message_iter_close_container(&sub, &sub2))
1611 if (!dbus_message_iter_close_container(&iter, &sub))
1614 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1618 DBusMessageIter iter, sub;
1620 reply = dbus_message_new_method_return(message);
1624 dbus_message_iter_init_append(reply, &iter);
1626 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1629 HASHMAP_FOREACH(user, m->users, i) {
1630 DBusMessageIter sub2;
1633 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1638 p = user_bus_path(user);
1642 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1643 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1644 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1651 if (!dbus_message_iter_close_container(&sub, &sub2))
1655 if (!dbus_message_iter_close_container(&iter, &sub))
1658 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1662 DBusMessageIter iter, sub;
1664 reply = dbus_message_new_method_return(message);
1668 dbus_message_iter_init_append(reply, &iter);
1670 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1673 HASHMAP_FOREACH(seat, m->seats, i) {
1674 DBusMessageIter sub2;
1676 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1679 p = seat_bus_path(seat);
1683 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1684 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1691 if (!dbus_message_iter_close_container(&sub, &sub2))
1695 if (!dbus_message_iter_close_container(&iter, &sub))
1698 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1699 Inhibitor *inhibitor;
1701 DBusMessageIter iter, sub;
1703 reply = dbus_message_new_method_return(message);
1707 dbus_message_iter_init_append(reply, &iter);
1709 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1712 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1713 DBusMessageIter sub2;
1714 dbus_uint32_t uid, pid;
1715 const char *what, *who, *why, *mode;
1717 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1720 what = strempty(inhibit_what_to_string(inhibitor->what));
1721 who = strempty(inhibitor->who);
1722 why = strempty(inhibitor->why);
1723 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
1724 uid = (dbus_uint32_t) inhibitor->uid;
1725 pid = (dbus_uint32_t) inhibitor->pid;
1727 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1728 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1729 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1730 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
1731 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1732 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1735 if (!dbus_message_iter_close_container(&sub, &sub2))
1739 if (!dbus_message_iter_close_container(&iter, &sub))
1742 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1744 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1747 return bus_send_error_reply(connection, message, &error, r);
1750 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1752 r = bus_manager_create_session(m, message, &reply);
1754 /* Don't delay the work on OOM here, since it might be
1755 * triggered by a low RLIMIT_NOFILE here (since we
1756 * send a dupped fd to the client), and we'd rather
1757 * see this fail quickly then be retried later */
1760 return bus_send_error_reply(connection, message, NULL, r);
1762 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1766 if (!dbus_message_get_args(
1769 DBUS_TYPE_STRING, &name,
1771 return bus_send_error_reply(connection, message, &error, -EINVAL);
1773 session = hashmap_get(m->sessions, name);
1775 return bus_send_error_reply(connection, message, &error, -ENOENT);
1777 /* We use the FIFO to detect stray sessions where the
1778 process invoking PAM dies abnormally. We need to make
1779 sure that that process is not killed if at the clean
1780 end of the session it closes the FIFO. Hence, with
1781 this call explicitly turn off the FIFO logic, so that
1782 the PAM code can finish clean up on its own */
1783 session_remove_fifo(session);
1785 reply = dbus_message_new_method_return(message);
1789 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1793 if (!dbus_message_get_args(
1796 DBUS_TYPE_STRING, &name,
1798 return bus_send_error_reply(connection, message, &error, -EINVAL);
1800 session = hashmap_get(m->sessions, name);
1802 return bus_send_error_reply(connection, message, &error, -ENOENT);
1804 r = session_activate(session);
1806 return bus_send_error_reply(connection, message, NULL, r);
1808 reply = dbus_message_new_method_return(message);
1812 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1813 const char *session_name, *seat_name;
1817 /* Same as ActivateSession() but refuses to work if
1818 * the seat doesn't match */
1820 if (!dbus_message_get_args(
1823 DBUS_TYPE_STRING, &session_name,
1824 DBUS_TYPE_STRING, &seat_name,
1826 return bus_send_error_reply(connection, message, &error, -EINVAL);
1828 session = hashmap_get(m->sessions, session_name);
1830 return bus_send_error_reply(connection, message, &error, -ENOENT);
1832 seat = hashmap_get(m->seats, seat_name);
1834 return bus_send_error_reply(connection, message, &error, -ENOENT);
1836 if (session->seat != seat)
1837 return bus_send_error_reply(connection, message, &error, -EINVAL);
1839 r = session_activate(session);
1841 return bus_send_error_reply(connection, message, NULL, r);
1843 reply = dbus_message_new_method_return(message);
1847 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1848 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1852 if (!dbus_message_get_args(
1855 DBUS_TYPE_STRING, &name,
1857 return bus_send_error_reply(connection, message, &error, -EINVAL);
1859 session = hashmap_get(m->sessions, name);
1861 return bus_send_error_reply(connection, message, NULL, -ENOENT);
1863 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1866 reply = dbus_message_new_method_return(message);
1870 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions") ||
1871 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSessions")) {
1873 r = session_send_lock_all(m, streq(dbus_message_get_member(message), "LockSessions"));
1875 bus_send_error_reply(connection, message, NULL, r);
1877 reply = dbus_message_new_method_return(message);
1881 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1888 if (!dbus_message_get_args(
1891 DBUS_TYPE_STRING, &name,
1892 DBUS_TYPE_STRING, &swho,
1893 DBUS_TYPE_INT32, &signo,
1895 return bus_send_error_reply(connection, message, &error, -EINVAL);
1900 who = kill_who_from_string(swho);
1902 return bus_send_error_reply(connection, message, &error, -EINVAL);
1905 if (signo <= 0 || signo >= _NSIG)
1906 return bus_send_error_reply(connection, message, &error, -EINVAL);
1908 session = hashmap_get(m->sessions, name);
1910 return bus_send_error_reply(connection, message, &error, -ENOENT);
1912 r = session_kill(session, who, signo);
1914 return bus_send_error_reply(connection, message, NULL, r);
1916 reply = dbus_message_new_method_return(message);
1920 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1925 if (!dbus_message_get_args(
1928 DBUS_TYPE_UINT32, &uid,
1929 DBUS_TYPE_INT32, &signo,
1931 return bus_send_error_reply(connection, message, &error, -EINVAL);
1933 if (signo <= 0 || signo >= _NSIG)
1934 return bus_send_error_reply(connection, message, &error, -EINVAL);
1936 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1938 return bus_send_error_reply(connection, message, &error, -ENOENT);
1940 r = user_kill(user, signo);
1942 return bus_send_error_reply(connection, message, NULL, r);
1944 reply = dbus_message_new_method_return(message);
1948 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1952 if (!dbus_message_get_args(
1955 DBUS_TYPE_STRING, &name,
1957 return bus_send_error_reply(connection, message, &error, -EINVAL);
1959 session = hashmap_get(m->sessions, name);
1961 return bus_send_error_reply(connection, message, &error, -ENOENT);
1963 r = session_stop(session);
1965 return bus_send_error_reply(connection, message, NULL, r);
1967 reply = dbus_message_new_method_return(message);
1971 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1975 if (!dbus_message_get_args(
1978 DBUS_TYPE_UINT32, &uid,
1980 return bus_send_error_reply(connection, message, &error, -EINVAL);
1982 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1984 return bus_send_error_reply(connection, message, &error, -ENOENT);
1986 r = user_stop(user);
1988 return bus_send_error_reply(connection, message, NULL, r);
1990 reply = dbus_message_new_method_return(message);
1994 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1998 if (!dbus_message_get_args(
2001 DBUS_TYPE_STRING, &name,
2003 return bus_send_error_reply(connection, message, &error, -EINVAL);
2005 seat = hashmap_get(m->seats, name);
2007 return bus_send_error_reply(connection, message, &error, -ENOENT);
2009 r = seat_stop_sessions(seat);
2011 return bus_send_error_reply(connection, message, NULL, r);
2013 reply = dbus_message_new_method_return(message);
2017 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
2020 dbus_bool_t b, interactive;
2023 if (!dbus_message_get_args(
2026 DBUS_TYPE_UINT32, &uid,
2027 DBUS_TYPE_BOOLEAN, &b,
2028 DBUS_TYPE_BOOLEAN, &interactive,
2030 return bus_send_error_reply(connection, message, &error, -EINVAL);
2035 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
2037 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
2039 return bus_send_error_reply(connection, message, &error, r);
2041 mkdir_p_label("/var/lib/systemd", 0755);
2043 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
2045 return bus_send_error_reply(connection, message, &error, r);
2047 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
2058 return bus_send_error_reply(connection, message, &error, r);
2060 if (manager_add_user_by_uid(m, uid, &u) >= 0)
2069 if (r < 0 && errno != ENOENT)
2070 return bus_send_error_reply(connection, message, &error, -errno);
2072 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
2074 user_add_to_gc_queue(u);
2077 reply = dbus_message_new_method_return(message);
2081 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
2082 const char *sysfs, *seat;
2083 dbus_bool_t interactive;
2085 if (!dbus_message_get_args(
2088 DBUS_TYPE_STRING, &seat,
2089 DBUS_TYPE_STRING, &sysfs,
2090 DBUS_TYPE_BOOLEAN, &interactive,
2092 return bus_send_error_reply(connection, message, &error, -EINVAL);
2094 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
2095 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2097 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
2099 return bus_send_error_reply(connection, message, &error, r);
2101 r = attach_device(m, seat, sysfs);
2103 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2105 reply = dbus_message_new_method_return(message);
2110 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
2111 dbus_bool_t interactive;
2113 if (!dbus_message_get_args(
2116 DBUS_TYPE_BOOLEAN, &interactive,
2118 return bus_send_error_reply(connection, message, &error, -EINVAL);
2120 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
2122 return bus_send_error_reply(connection, message, &error, r);
2124 r = flush_devices(m);
2126 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2128 reply = dbus_message_new_method_return(message);
2132 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
2134 r = bus_manager_do_shutdown_or_sleep(
2135 m, connection, message,
2136 SPECIAL_POWEROFF_TARGET,
2138 "org.freedesktop.login1.power-off",
2139 "org.freedesktop.login1.power-off-multiple-sessions",
2140 "org.freedesktop.login1.power-off-ignore-inhibit",
2144 return bus_send_error_reply(connection, message, &error, r);
2145 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
2146 r = bus_manager_do_shutdown_or_sleep(
2147 m, connection, message,
2148 SPECIAL_REBOOT_TARGET,
2150 "org.freedesktop.login1.reboot",
2151 "org.freedesktop.login1.reboot-multiple-sessions",
2152 "org.freedesktop.login1.reboot-ignore-inhibit",
2156 return bus_send_error_reply(connection, message, &error, r);
2158 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2159 r = bus_manager_do_shutdown_or_sleep(
2160 m, connection, message,
2161 SPECIAL_SUSPEND_TARGET,
2163 "org.freedesktop.login1.suspend",
2164 "org.freedesktop.login1.suspend-multiple-sessions",
2165 "org.freedesktop.login1.suspend-ignore-inhibit",
2169 return bus_send_error_reply(connection, message, &error, r);
2170 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2171 r = bus_manager_do_shutdown_or_sleep(
2172 m, connection, message,
2173 SPECIAL_HIBERNATE_TARGET,
2175 "org.freedesktop.login1.hibernate",
2176 "org.freedesktop.login1.hibernate-multiple-sessions",
2177 "org.freedesktop.login1.hibernate-ignore-inhibit",
2181 return bus_send_error_reply(connection, message, &error, r);
2183 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "HybridSleep")) {
2184 r = bus_manager_do_shutdown_or_sleep(
2185 m, connection, message,
2186 SPECIAL_HYBRID_SLEEP_TARGET,
2188 "org.freedesktop.login1.hibernate",
2189 "org.freedesktop.login1.hibernate-multiple-sessions",
2190 "org.freedesktop.login1.hibernate-ignore-inhibit",
2194 return bus_send_error_reply(connection, message, &error, r);
2196 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2198 r = bus_manager_can_shutdown_or_sleep(
2199 m, connection, message,
2201 "org.freedesktop.login1.power-off",
2202 "org.freedesktop.login1.power-off-multiple-sessions",
2203 "org.freedesktop.login1.power-off-ignore-inhibit",
2207 return bus_send_error_reply(connection, message, &error, r);
2208 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2209 r = bus_manager_can_shutdown_or_sleep(
2210 m, connection, message,
2212 "org.freedesktop.login1.reboot",
2213 "org.freedesktop.login1.reboot-multiple-sessions",
2214 "org.freedesktop.login1.reboot-ignore-inhibit",
2218 return bus_send_error_reply(connection, message, &error, r);
2220 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2221 r = bus_manager_can_shutdown_or_sleep(
2222 m, connection, message,
2224 "org.freedesktop.login1.suspend",
2225 "org.freedesktop.login1.suspend-multiple-sessions",
2226 "org.freedesktop.login1.suspend-ignore-inhibit",
2230 return bus_send_error_reply(connection, message, &error, r);
2232 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2233 r = bus_manager_can_shutdown_or_sleep(
2234 m, connection, message,
2236 "org.freedesktop.login1.hibernate",
2237 "org.freedesktop.login1.hibernate-multiple-sessions",
2238 "org.freedesktop.login1.hibernate-ignore-inhibit",
2242 return bus_send_error_reply(connection, message, &error, r);
2244 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHybridSleep")) {
2245 r = bus_manager_can_shutdown_or_sleep(
2246 m, connection, message,
2248 "org.freedesktop.login1.hibernate",
2249 "org.freedesktop.login1.hibernate-multiple-sessions",
2250 "org.freedesktop.login1.hibernate-ignore-inhibit",
2254 return bus_send_error_reply(connection, message, &error, r);
2256 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2257 char *introspection = NULL;
2266 if (!(reply = dbus_message_new_method_return(message)))
2269 /* We roll our own introspection code here, instead of
2270 * relying on bus_default_message_handler() because we
2271 * need to generate our introspection string
2274 if (!(f = open_memstream(&introspection, &size)))
2277 fputs(INTROSPECTION_BEGIN, f);
2279 HASHMAP_FOREACH(seat, m->seats, i) {
2280 p = bus_path_escape(seat->id);
2283 fprintf(f, "<node name=\"seat/%s\"/>", p);
2288 HASHMAP_FOREACH(user, m->users, i)
2289 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2291 HASHMAP_FOREACH(session, m->sessions, i) {
2292 p = bus_path_escape(session->id);
2295 fprintf(f, "<node name=\"session/%s\"/>", p);
2300 fputs(INTROSPECTION_END, f);
2304 free(introspection);
2313 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2314 free(introspection);
2318 free(introspection);
2320 const BusBoundProperties bps[] = {
2321 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2324 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2328 if (!bus_maybe_send_reply(connection, message, reply))
2332 return DBUS_HANDLER_RESULT_HANDLED;
2335 dbus_error_free(&error);
2337 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2340 const DBusObjectPathVTable bus_manager_vtable = {
2341 .message_function = manager_message_handler
2344 DBusHandlerResult bus_message_filter(
2345 DBusConnection *connection,
2346 DBusMessage *message,
2349 Manager *m = userdata;
2356 dbus_error_init(&error);
2358 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
2361 if (!dbus_message_get_args(message, &error,
2362 DBUS_TYPE_STRING, &cgroup,
2364 log_error("Failed to parse Released message: %s", bus_error_message(&error));
2366 manager_cgroup_notify_empty(m, cgroup);
2368 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
2370 const char *path, *result, *unit;
2372 if (!dbus_message_get_args(message, &error,
2373 DBUS_TYPE_UINT32, &id,
2374 DBUS_TYPE_OBJECT_PATH, &path,
2375 DBUS_TYPE_STRING, &unit,
2376 DBUS_TYPE_STRING, &result,
2378 log_error("Failed to parse JobRemoved message: %s", bus_error_message(&error));
2380 else if (m->action_job && streq(m->action_job, path)) {
2381 log_info("Operation finished.");
2383 /* Tell people that they now may take a lock again */
2384 send_prepare_for(m, m->action_what, false);
2386 free(m->action_job);
2387 m->action_job = NULL;
2388 m->action_unit = NULL;
2393 dbus_error_free(&error);
2395 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2398 int manager_send_changed(Manager *manager, const char *properties) {
2399 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
2403 m = bus_properties_changed_new("/org/freedesktop/login1",
2404 "org.freedesktop.login1.Manager",
2409 if (!dbus_connection_send(manager->bus, m, NULL))
2415 int manager_dispatch_delayed(Manager *manager) {
2421 if (manager->action_what == 0 || manager->action_job)
2424 /* Continue delay? */
2425 if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0)) {
2427 if (manager->action_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC))
2430 log_info("Delay lock is active but inhibitor timeout is reached.");
2433 /* Actually do the operation */
2434 dbus_error_init(&error);
2435 r = execute_shutdown_or_sleep(manager, manager->action_what, manager->action_unit, &error);
2437 log_warning("Failed to send delayed message: %s", bus_error(&error, r));
2438 dbus_error_free(&error);
2440 manager->action_unit = NULL;
2441 manager->action_what = 0;