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"
37 #define BUS_MANAGER_INTERFACE \
38 " <interface name=\"org.freedesktop.login1.Manager\">\n" \
39 " <method name=\"GetSession\">\n" \
40 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
41 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
43 " <method name=\"GetSessionByPID\">\n" \
44 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
45 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
47 " <method name=\"GetUser\">\n" \
48 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
49 " <arg name=\"user\" type=\"o\" direction=\"out\"/>\n" \
51 " <method name=\"GetSeat\">\n" \
52 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
53 " <arg name=\"seat\" type=\"o\" direction=\"out\"/>\n" \
55 " <method name=\"ListSessions\">\n" \
56 " <arg name=\"sessions\" type=\"a(susso)\" direction=\"out\"/>\n" \
58 " <method name=\"ListUsers\">\n" \
59 " <arg name=\"users\" type=\"a(uso)\" direction=\"out\"/>\n" \
61 " <method name=\"ListSeats\">\n" \
62 " <arg name=\"seats\" type=\"a(so)\" direction=\"out\"/>\n" \
64 " <method name=\"CreateSession\">\n" \
65 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
66 " <arg name=\"leader\" type=\"u\" direction=\"in\"/>\n" \
67 " <arg name=\"sevice\" type=\"s\" direction=\"in\"/>\n" \
68 " <arg name=\"type\" type=\"s\" direction=\"in\"/>\n" \
69 " <arg name=\"class\" type=\"s\" direction=\"in\"/>\n" \
70 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
71 " <arg name=\"vtnr\" type=\"u\" direction=\"in\"/>\n" \
72 " <arg name=\"tty\" type=\"s\" direction=\"in\"/>\n" \
73 " <arg name=\"display\" type=\"s\" direction=\"in\"/>\n" \
74 " <arg name=\"remote\" type=\"b\" direction=\"in\"/>\n" \
75 " <arg name=\"remote_user\" type=\"s\" direction=\"in\"/>\n" \
76 " <arg name=\"remote_host\" type=\"s\" direction=\"in\"/>\n" \
77 " <arg name=\"controllers\" type=\"as\" direction=\"in\"/>\n" \
78 " <arg name=\"reset_controllers\" type=\"as\" direction=\"in\"/>\n" \
79 " <arg name=\"kill_processes\" type=\"b\" direction=\"in\"/>\n" \
80 " <arg name=\"id\" type=\"s\" direction=\"out\"/>\n" \
81 " <arg name=\"path\" type=\"o\" direction=\"out\"/>\n" \
82 " <arg name=\"runtime_path\" type=\"o\" direction=\"out\"/>\n" \
83 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
84 " <arg name=\"seat\" type=\"s\" direction=\"out\"/>\n" \
85 " <arg name=\"vtnr\" type=\"u\" direction=\"out\"/>\n" \
86 " <arg name=\"existing\" type=\"b\" direction=\"out\"/>\n" \
88 " <method name=\"ReleaseSession\">\n" \
89 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
91 " <method name=\"ActivateSession\">\n" \
92 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
94 " <method name=\"ActivateSessionOnSeat\">\n" \
95 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
96 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
98 " <method name=\"LockSession\">\n" \
99 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
101 " <method name=\"UnlockSession\">\n" \
102 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
104 " <method name=\"LockSessions\"/>\n" \
105 " <method name=\"UnlockSessions\"/>\n" \
106 " <method name=\"KillSession\">\n" \
107 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
108 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
109 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
111 " <method name=\"KillUser\">\n" \
112 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
113 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
115 " <method name=\"TerminateSession\">\n" \
116 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
118 " <method name=\"TerminateUser\">\n" \
119 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
121 " <method name=\"TerminateSeat\">\n" \
122 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
124 " <method name=\"SetUserLinger\">\n" \
125 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
126 " <arg name=\"b\" type=\"b\" direction=\"in\"/>\n" \
127 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
129 " <method name=\"AttachDevice\">\n" \
130 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
131 " <arg name=\"sysfs\" type=\"s\" direction=\"in\"/>\n" \
132 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
134 " <method name=\"FlushDevices\">\n" \
135 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
137 " <method name=\"PowerOff\">\n" \
138 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
140 " <method name=\"Reboot\">\n" \
141 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
143 " <method name=\"Suspend\">\n" \
144 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
146 " <method name=\"Hibernate\">\n" \
147 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
149 " <method name=\"HybridSleep\">\n" \
150 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
152 " <method name=\"CanPowerOff\">\n" \
153 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
155 " <method name=\"CanReboot\">\n" \
156 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
158 " <method name=\"CanSuspend\">\n" \
159 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
161 " <method name=\"CanHibernate\">\n" \
162 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
164 " <method name=\"CanHybridSleep\">\n" \
165 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
167 " <method name=\"Inhibit\">\n" \
168 " <arg name=\"what\" type=\"s\" direction=\"in\"/>\n" \
169 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
170 " <arg name=\"why\" type=\"s\" direction=\"in\"/>\n" \
171 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
172 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
174 " <method name=\"ListInhibitors\">\n" \
175 " <arg name=\"inhibitors\" type=\"a(ssssuu)\" direction=\"out\"/>\n" \
177 " <signal name=\"SessionNew\">\n" \
178 " <arg name=\"id\" type=\"s\"/>\n" \
179 " <arg name=\"path\" type=\"o\"/>\n" \
181 " <signal name=\"SessionRemoved\">\n" \
182 " <arg name=\"id\" type=\"s\"/>\n" \
183 " <arg name=\"path\" type=\"o\"/>\n" \
185 " <signal name=\"UserNew\">\n" \
186 " <arg name=\"uid\" type=\"u\"/>\n" \
187 " <arg name=\"path\" type=\"o\"/>\n" \
189 " <signal name=\"UserRemoved\">\n" \
190 " <arg name=\"uid\" type=\"u\"/>\n" \
191 " <arg name=\"path\" type=\"o\"/>\n" \
193 " <signal name=\"SeatNew\">\n" \
194 " <arg name=\"id\" type=\"s\"/>\n" \
195 " <arg name=\"path\" type=\"o\"/>\n" \
197 " <signal name=\"SeatRemoved\">\n" \
198 " <arg name=\"id\" type=\"s\"/>\n" \
199 " <arg name=\"path\" type=\"o\"/>\n" \
201 " <signal name=\"PrepareForShutdown\">\n" \
202 " <arg name=\"active\" type=\"b\"/>\n" \
204 " <signal name=\"PrepareForSleep\">\n" \
205 " <arg name=\"active\" type=\"b\"/>\n" \
207 " <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
208 " <property name=\"Controllers\" type=\"as\" access=\"read\"/>\n" \
209 " <property name=\"ResetControllers\" type=\"as\" access=\"read\"/>\n" \
210 " <property name=\"NAutoVTs\" type=\"u\" access=\"read\"/>\n" \
211 " <property name=\"KillOnlyUsers\" type=\"as\" access=\"read\"/>\n" \
212 " <property name=\"KillExcludeUsers\" type=\"as\" access=\"read\"/>\n" \
213 " <property name=\"KillUserProcesses\" type=\"b\" access=\"read\"/>\n" \
214 " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
215 " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
216 " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
217 " <property name=\"BlockInhibited\" type=\"s\" access=\"read\"/>\n" \
218 " <property name=\"DelayInhibited\" type=\"s\" access=\"read\"/>\n" \
219 " <property name=\"InhibitDelayMaxUSec\" type=\"t\" access=\"read\"/>\n" \
220 " <property name=\"HandlePowerKey\" type=\"s\" access=\"read\"/>\n" \
221 " <property name=\"HandleSuspendKey\" type=\"s\" access=\"read\"/>\n" \
222 " <property name=\"HandleHibernateKey\" type=\"s\" access=\"read\"/>\n" \
223 " <property name=\"HandleLidSwitch\" type=\"s\" access=\"read\"/>\n" \
224 " <property name=\"IdleAction\" type=\"s\" access=\"read\"/>\n" \
225 " <property name=\"IdleActionUSec\" type=\"t\" access=\"read\"/>\n" \
226 " <property name=\"PreparingForShutdown\" type=\"b\" access=\"read\"/>\n" \
227 " <property name=\"PreparingForSleep\" type=\"b\" access=\"read\"/>\n" \
230 #define INTROSPECTION_BEGIN \
231 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
233 BUS_MANAGER_INTERFACE \
234 BUS_PROPERTIES_INTERFACE \
236 BUS_INTROSPECTABLE_INTERFACE
238 #define INTROSPECTION_END \
241 #define INTERFACES_LIST \
242 BUS_GENERIC_INTERFACES_LIST \
243 "org.freedesktop.login1.Manager\0"
245 static int bus_manager_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
253 b = manager_get_idle_hint(m, NULL) > 0;
254 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
260 static int bus_manager_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
269 manager_get_idle_hint(m, &t);
270 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
272 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
278 static int bus_manager_append_inhibited(DBusMessageIter *i, const char *property, void *data) {
283 w = manager_inhibit_what(m, streq(property, "BlockInhibited") ? INHIBIT_BLOCK : INHIBIT_DELAY);
284 p = inhibit_what_to_string(w);
286 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &p))
292 static int bus_manager_append_preparing(DBusMessageIter *i, const char *property, void *data) {
299 if (streq(property, "PreparingForShutdown"))
300 b = !!(m->action_what & INHIBIT_SHUTDOWN);
302 b = !!(m->action_what & INHIBIT_SLEEP);
304 dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b);
308 static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMessage **_reply) {
309 Session *session = NULL;
311 const char *type, *class, *seat, *tty, *display, *remote_user, *remote_host, *service;
312 uint32_t uid, leader, audit_id = 0;
313 dbus_bool_t remote, kill_processes, exists;
314 char **controllers = NULL, **reset_controllers = NULL;
318 DBusMessageIter iter;
323 DBusMessage *reply = NULL;
330 if (!dbus_message_iter_init(message, &iter) ||
331 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
334 dbus_message_iter_get_basic(&iter, &uid);
336 if (!dbus_message_iter_next(&iter) ||
337 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
340 dbus_message_iter_get_basic(&iter, &leader);
343 !dbus_message_iter_next(&iter) ||
344 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
347 dbus_message_iter_get_basic(&iter, &service);
349 if (!dbus_message_iter_next(&iter) ||
350 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
353 dbus_message_iter_get_basic(&iter, &type);
354 t = session_type_from_string(type);
357 !dbus_message_iter_next(&iter) ||
358 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
361 dbus_message_iter_get_basic(&iter, &class);
365 c = session_class_from_string(class);
368 !dbus_message_iter_next(&iter) ||
369 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
372 dbus_message_iter_get_basic(&iter, &seat);
377 s = hashmap_get(m->seats, seat);
382 if (!dbus_message_iter_next(&iter) ||
383 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
386 dbus_message_iter_get_basic(&iter, &vtnr);
388 if (!dbus_message_iter_next(&iter) ||
389 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
392 dbus_message_iter_get_basic(&iter, &tty);
394 if (tty_is_vc(tty)) {
399 else if (s != m->vtconsole)
402 v = vtnr_from_tty(tty);
405 return v < 0 ? v : -EINVAL;
409 else if (vtnr != (uint32_t) v)
411 } else if (tty_is_console(tty)) {
415 else if (s != m->vtconsole)
424 if (seat_can_multi_session(s)) {
433 if (!dbus_message_iter_next(&iter) ||
434 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
437 dbus_message_iter_get_basic(&iter, &display);
439 if (!dbus_message_iter_next(&iter) ||
440 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
443 dbus_message_iter_get_basic(&iter, &remote);
445 if (!dbus_message_iter_next(&iter) ||
446 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
449 dbus_message_iter_get_basic(&iter, &remote_user);
451 if (!dbus_message_iter_next(&iter) ||
452 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
455 dbus_message_iter_get_basic(&iter, &remote_host);
457 if (!dbus_message_iter_next(&iter) ||
458 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
459 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
462 r = bus_parse_strv_iter(&iter, &controllers);
466 if (strv_contains(controllers, "systemd") ||
467 !dbus_message_iter_next(&iter) ||
468 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
469 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) {
474 r = bus_parse_strv_iter(&iter, &reset_controllers);
478 if (strv_contains(reset_controllers, "systemd") ||
479 !dbus_message_iter_next(&iter) ||
480 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) {
485 dbus_message_iter_get_basic(&iter, &kill_processes);
487 r = manager_add_user_by_uid(m, uid, &user);
491 audit_session_from_pid(leader, &audit_id);
494 asprintf(&id, "%lu", (unsigned long) audit_id);
501 session = hashmap_get(m->sessions, id);
506 fifo_fd = session_create_fifo(session);
512 /* Session already exists, client is probably
513 * something like "su" which changes uid but
514 * is still the same audit session */
516 reply = dbus_message_new_method_return(message);
522 p = session_bus_path(session);
528 seat = session->seat ? session->seat->id : "";
529 vtnr = session->vtnr;
532 b = dbus_message_append_args(
534 DBUS_TYPE_STRING, &session->id,
535 DBUS_TYPE_OBJECT_PATH, &p,
536 DBUS_TYPE_STRING, &session->user->runtime_path,
537 DBUS_TYPE_UNIX_FD, &fifo_fd,
538 DBUS_TYPE_STRING, &seat,
539 DBUS_TYPE_UINT32, &vtnr,
540 DBUS_TYPE_BOOLEAN, &exists,
549 close_nointr_nofail(fifo_fd);
552 strv_free(controllers);
553 strv_free(reset_controllers);
563 if (asprintf(&id, "c%lu", ++m->session_counter) < 0) {
568 } while (hashmap_get(m->sessions, id));
571 r = manager_add_session(m, user, id, &session);
576 session->leader = leader;
577 session->audit_id = audit_id;
580 session->remote = remote;
581 session->controllers = controllers;
582 session->reset_controllers = reset_controllers;
583 session->kill_processes = kill_processes;
584 session->vtnr = vtnr;
586 controllers = reset_controllers = NULL;
589 session->tty = strdup(tty);
596 if (!isempty(display)) {
597 session->display = strdup(display);
598 if (!session->display) {
604 if (!isempty(remote_user)) {
605 session->remote_user = strdup(remote_user);
606 if (!session->remote_user) {
612 if (!isempty(remote_host)) {
613 session->remote_host = strdup(remote_host);
614 if (!session->remote_host) {
620 if (!isempty(service)) {
621 session->service = strdup(service);
622 if (!session->service) {
628 fifo_fd = session_create_fifo(session);
635 r = seat_attach_session(s, session);
640 r = session_start(session);
644 reply = dbus_message_new_method_return(message);
650 p = session_bus_path(session);
656 seat = s ? s->id : "";
658 b = dbus_message_append_args(
660 DBUS_TYPE_STRING, &session->id,
661 DBUS_TYPE_OBJECT_PATH, &p,
662 DBUS_TYPE_STRING, &session->user->runtime_path,
663 DBUS_TYPE_UNIX_FD, &fifo_fd,
664 DBUS_TYPE_STRING, &seat,
665 DBUS_TYPE_UINT32, &vtnr,
666 DBUS_TYPE_BOOLEAN, &exists,
675 close_nointr_nofail(fifo_fd);
681 strv_free(controllers);
682 strv_free(reset_controllers);
685 session_add_to_gc_queue(session);
688 user_add_to_gc_queue(user);
691 close_nointr_nofail(fifo_fd);
694 dbus_message_unref(reply);
699 static int bus_manager_inhibit(
701 DBusConnection *connection,
702 DBusMessage *message,
704 DBusMessage **_reply) {
708 const char *who, *why, *what, *mode;
714 DBusMessage *reply = NULL;
722 if (!dbus_message_get_args(
725 DBUS_TYPE_STRING, &what,
726 DBUS_TYPE_STRING, &who,
727 DBUS_TYPE_STRING, &why,
728 DBUS_TYPE_STRING, &mode,
729 DBUS_TYPE_INVALID)) {
734 w = inhibit_what_from_string(what);
740 mm = inhibit_mode_from_string(mode);
746 /* Delay is only supported for shutdown/sleep */
747 if (mm == INHIBIT_DELAY && (w & ~(INHIBIT_SHUTDOWN|INHIBIT_SLEEP))) {
752 /* Don't allow taking delay locks while we are already
753 * executing the operation. We shouldn't create the impression
754 * that the lock was successful if the machine is about to go
755 * down/suspend any moment. */
756 if (m->action_what & w) {
761 r = verify_polkit(connection, message,
762 w == INHIBIT_SHUTDOWN ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
763 w == INHIBIT_SLEEP ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep" : "org.freedesktop.login1.inhibit-delay-sleep") :
764 w == INHIBIT_IDLE ? "org.freedesktop.login1.inhibit-block-idle" :
765 w == INHIBIT_HANDLE_POWER_KEY ? "org.freedesktop.login1.inhibit-handle-power-key" :
766 w == INHIBIT_HANDLE_SUSPEND_KEY ? "org.freedesktop.login1.inhibit-handle-suspend-key" :
767 w == INHIBIT_HANDLE_HIBERNATE_KEY ? "org.freedesktop.login1.inhibit-handle-hibernate-key" :
768 "org.freedesktop.login1.inhibit-handle-lid-switch",
773 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
774 if (ul == (unsigned long) -1) {
779 pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
789 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
793 } while (hashmap_get(m->inhibitors, id));
795 r = manager_add_inhibitor(m, id, &i);
805 i->why = strdup(why);
806 i->who = strdup(who);
808 if (!i->why || !i->who) {
813 fifo_fd = inhibitor_create_fifo(i);
819 reply = dbus_message_new_method_return(message);
825 if (!dbus_message_append_args(
827 DBUS_TYPE_UNIX_FD, &fifo_fd,
828 DBUS_TYPE_INVALID)) {
833 close_nointr_nofail(fifo_fd);
845 close_nointr_nofail(fifo_fd);
848 dbus_message_unref(reply);
853 static int trigger_device(Manager *m, struct udev_device *d) {
854 struct udev_enumerate *e;
855 struct udev_list_entry *first, *item;
860 e = udev_enumerate_new(m->udev);
867 if (udev_enumerate_add_match_parent(e, d) < 0) {
873 if (udev_enumerate_scan_devices(e) < 0) {
878 first = udev_enumerate_get_list_entry(e);
879 udev_list_entry_foreach(item, first) {
883 p = udev_list_entry_get_name(item);
885 t = strappend(p, "/uevent");
891 write_one_line_file(t, "change");
899 udev_enumerate_unref(e);
904 static int attach_device(Manager *m, const char *seat, const char *sysfs) {
905 struct udev_device *d;
906 char *rule = NULL, *file = NULL;
907 const char *id_for_seat;
914 d = udev_device_new_from_syspath(m->udev, sysfs);
918 if (!udev_device_has_tag(d, "seat")) {
923 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
929 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
934 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
939 mkdir_p_label("/etc/udev/rules.d", 0755);
940 r = write_one_line_file_atomic(file, rule);
944 r = trigger_device(m, d);
951 udev_device_unref(d);
956 static int flush_devices(Manager *m) {
961 d = opendir("/etc/udev/rules.d");
964 log_warning("Failed to open /etc/udev/rules.d: %m");
968 while ((de = readdir(d))) {
970 if (!dirent_is_file(de))
973 if (!startswith(de->d_name, "72-seat-"))
976 if (!endswith(de->d_name, ".rules"))
979 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
980 log_warning("Failed to unlink %s: %m", de->d_name);
986 return trigger_device(m, NULL);
989 static int have_multiple_sessions(
998 /* Check for other users' sessions. Greeter sessions do not
999 * count, and non-login sessions do not count either. */
1000 HASHMAP_FOREACH(session, m->sessions, i)
1001 if (session->class == SESSION_USER &&
1002 (session->type == SESSION_TTY || session->type == SESSION_X11) &&
1003 session->user->uid != uid)
1009 static int bus_manager_log_shutdown(
1012 const char *unit_name) {
1019 if (w != INHIBIT_SHUTDOWN)
1022 if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
1023 p = "MESSAGE=System is powering down.";
1024 q = "SHUTDOWN=power-off";
1025 } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
1026 p = "MESSAGE=System is halting.";
1027 q = "SHUTDOWN=halt";
1028 } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
1029 p = "MESSAGE=System is rebooting.";
1030 q = "SHUTDOWN=reboot";
1031 } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
1032 p = "MESSAGE=System is rebooting with kexec.";
1033 q = "SHUTDOWN=kexec";
1035 p = "MESSAGE=System is shutting down.";
1039 return log_struct(LOG_NOTICE, MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
1044 static int execute_shutdown_or_sleep(
1047 const char *unit_name,
1050 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1051 const char *mode = "replace", *p;
1057 assert(w < _INHIBIT_WHAT_MAX);
1060 bus_manager_log_shutdown(m, w, unit_name);
1062 r = bus_method_call_with_reply(
1064 "org.freedesktop.systemd1",
1065 "/org/freedesktop/systemd1",
1066 "org.freedesktop.systemd1.Manager",
1070 DBUS_TYPE_STRING, &unit_name,
1071 DBUS_TYPE_STRING, &mode,
1076 if (!dbus_message_get_args(
1079 DBUS_TYPE_OBJECT_PATH, &p,
1087 m->action_unit = unit_name;
1088 free(m->action_job);
1095 static int delay_shutdown_or_sleep(
1098 const char *unit_name) {
1102 assert(w < _INHIBIT_WHAT_MAX);
1105 m->action_timestamp = now(CLOCK_MONOTONIC);
1106 m->action_unit = unit_name;
1112 static int bus_manager_can_shutdown_or_sleep(
1114 DBusConnection *connection,
1115 DBusMessage *message,
1118 const char *action_multiple_sessions,
1119 const char *action_ignore_inhibit,
1120 const char *sleep_type,
1121 const char *sleep_disk_type,
1123 DBusMessage **_reply) {
1125 bool multiple_sessions, challenge, blocked, b;
1127 DBusMessage *reply = NULL;
1135 assert(w <= _INHIBIT_WHAT_MAX);
1137 assert(action_multiple_sessions);
1138 assert(action_ignore_inhibit);
1143 r = can_sleep(sleep_type);
1153 if (sleep_disk_type) {
1154 r = can_sleep_disk(sleep_disk_type);
1164 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1165 if (ul == (unsigned long) -1)
1168 r = have_multiple_sessions(m, (uid_t) ul);
1172 multiple_sessions = r > 0;
1173 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1175 if (multiple_sessions) {
1176 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1183 result = "challenge";
1189 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1193 if (r > 0 && !result)
1195 else if (challenge && (!result || streq(result, "yes")))
1196 result = "challenge";
1201 if (!multiple_sessions && !blocked) {
1202 /* If neither inhibit nor multiple sessions
1203 * apply then just check the normal policy */
1205 r = verify_polkit(connection, message, action, false, &challenge, error);
1212 result = "challenge";
1218 reply = dbus_message_new_method_return(message);
1222 b = dbus_message_append_args(
1224 DBUS_TYPE_STRING, &result,
1227 dbus_message_unref(reply);
1235 static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
1236 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
1237 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
1238 [INHIBIT_SLEEP] = "PrepareForSleep"
1241 dbus_bool_t active = _active;
1242 _cleanup_dbus_message_unref_ DBusMessage *message = NULL;
1246 assert(w < _INHIBIT_WHAT_MAX);
1247 assert(signal_name[w]);
1249 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1253 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1254 !dbus_connection_send(m->bus, message, NULL))
1260 int bus_manager_shutdown_or_sleep_now_or_later(
1262 const char *unit_name,
1272 assert(w <= _INHIBIT_WHAT_MAX);
1273 assert(!m->action_job);
1275 /* Tell everybody to prepare for shutdown/sleep */
1276 send_prepare_for(m, w, true);
1279 m->inhibit_delay_max > 0 &&
1280 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0);
1283 /* Shutdown is delayed, keep in mind what we
1284 * want to do, and start a timeout */
1285 r = delay_shutdown_or_sleep(m, w, unit_name);
1287 /* Shutdown is not delayed, execute it
1289 r = execute_shutdown_or_sleep(m, w, unit_name, error);
1294 static int bus_manager_do_shutdown_or_sleep(
1296 DBusConnection *connection,
1297 DBusMessage *message,
1298 const char *unit_name,
1301 const char *action_multiple_sessions,
1302 const char *action_ignore_inhibit,
1303 const char *sleep_type,
1304 const char *sleep_disk_type,
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_type);
1346 if (sleep_disk_type) {
1347 r = can_sleep_disk(sleep_disk_type);
1355 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1356 if (ul == (unsigned long) -1)
1359 r = have_multiple_sessions(m, (uid_t) ul);
1363 multiple_sessions = r > 0;
1364 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1366 if (multiple_sessions) {
1367 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1373 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1378 if (!multiple_sessions && !blocked) {
1379 r = verify_polkit(connection, message, action, interactive, NULL, error);
1384 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
1388 reply = dbus_message_new_method_return(message);
1396 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_action, handle_action, HandleAction);
1398 static const BusProperty bus_login_manager_properties[] = {
1399 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_path), true },
1400 { "Controllers", bus_property_append_strv, "as", offsetof(Manager, controllers), true },
1401 { "ResetControllers", bus_property_append_strv, "as", offsetof(Manager, reset_controllers), true },
1402 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1403 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1404 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1405 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1406 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1407 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1408 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
1409 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1410 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1411 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
1412 { "HandlePowerKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_power_key) },
1413 { "HandleSuspendKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_suspend_key) },
1414 { "HandleHibernateKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_hibernate_key)},
1415 { "HandleLidSwitch", bus_manager_append_handle_action, "s", offsetof(Manager, handle_lid_switch) },
1416 { "IdleAction", bus_manager_append_handle_action, "s", offsetof(Manager, idle_action) },
1417 { "IdleActionUSec", bus_property_append_usec, "t", offsetof(Manager, idle_action_usec) },
1418 { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
1419 { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
1423 static DBusHandlerResult manager_message_handler(
1424 DBusConnection *connection,
1425 DBusMessage *message,
1428 Manager *m = userdata;
1431 DBusMessage *reply = NULL;
1438 dbus_error_init(&error);
1440 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1446 if (!dbus_message_get_args(
1449 DBUS_TYPE_STRING, &name,
1451 return bus_send_error_reply(connection, message, &error, -EINVAL);
1453 session = hashmap_get(m->sessions, name);
1455 return bus_send_error_reply(connection, message, &error, -ENOENT);
1457 reply = dbus_message_new_method_return(message);
1461 p = session_bus_path(session);
1465 b = dbus_message_append_args(
1467 DBUS_TYPE_OBJECT_PATH, &p,
1474 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1480 if (!dbus_message_get_args(
1483 DBUS_TYPE_UINT32, &pid,
1485 return bus_send_error_reply(connection, message, &error, -EINVAL);
1487 r = manager_get_session_by_pid(m, pid, &session);
1489 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1491 reply = dbus_message_new_method_return(message);
1495 p = session_bus_path(session);
1499 b = dbus_message_append_args(
1501 DBUS_TYPE_OBJECT_PATH, &p,
1508 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1514 if (!dbus_message_get_args(
1517 DBUS_TYPE_UINT32, &uid,
1519 return bus_send_error_reply(connection, message, &error, -EINVAL);
1521 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1523 return bus_send_error_reply(connection, message, &error, -ENOENT);
1525 reply = dbus_message_new_method_return(message);
1529 p = user_bus_path(user);
1533 b = dbus_message_append_args(
1535 DBUS_TYPE_OBJECT_PATH, &p,
1542 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1548 if (!dbus_message_get_args(
1551 DBUS_TYPE_STRING, &name,
1553 return bus_send_error_reply(connection, message, &error, -EINVAL);
1555 seat = hashmap_get(m->seats, name);
1557 return bus_send_error_reply(connection, message, &error, -ENOENT);
1559 reply = dbus_message_new_method_return(message);
1563 p = seat_bus_path(seat);
1567 b = dbus_message_append_args(
1569 DBUS_TYPE_OBJECT_PATH, &p,
1576 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1580 DBusMessageIter iter, sub;
1581 const char *empty = "";
1583 reply = dbus_message_new_method_return(message);
1587 dbus_message_iter_init_append(reply, &iter);
1589 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1592 HASHMAP_FOREACH(session, m->sessions, i) {
1593 DBusMessageIter sub2;
1596 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1599 uid = session->user->uid;
1601 p = session_bus_path(session);
1605 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1606 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1607 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1608 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1609 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1616 if (!dbus_message_iter_close_container(&sub, &sub2))
1620 if (!dbus_message_iter_close_container(&iter, &sub))
1623 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1627 DBusMessageIter iter, sub;
1629 reply = dbus_message_new_method_return(message);
1633 dbus_message_iter_init_append(reply, &iter);
1635 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1638 HASHMAP_FOREACH(user, m->users, i) {
1639 DBusMessageIter sub2;
1642 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1647 p = user_bus_path(user);
1651 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1652 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1653 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1660 if (!dbus_message_iter_close_container(&sub, &sub2))
1664 if (!dbus_message_iter_close_container(&iter, &sub))
1667 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1671 DBusMessageIter iter, sub;
1673 reply = dbus_message_new_method_return(message);
1677 dbus_message_iter_init_append(reply, &iter);
1679 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1682 HASHMAP_FOREACH(seat, m->seats, i) {
1683 DBusMessageIter sub2;
1685 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1688 p = seat_bus_path(seat);
1692 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1693 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1700 if (!dbus_message_iter_close_container(&sub, &sub2))
1704 if (!dbus_message_iter_close_container(&iter, &sub))
1707 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1708 Inhibitor *inhibitor;
1710 DBusMessageIter iter, sub;
1712 reply = dbus_message_new_method_return(message);
1716 dbus_message_iter_init_append(reply, &iter);
1718 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1721 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1722 DBusMessageIter sub2;
1723 dbus_uint32_t uid, pid;
1724 const char *what, *who, *why, *mode;
1726 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1729 what = strempty(inhibit_what_to_string(inhibitor->what));
1730 who = strempty(inhibitor->who);
1731 why = strempty(inhibitor->why);
1732 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
1733 uid = (dbus_uint32_t) inhibitor->uid;
1734 pid = (dbus_uint32_t) inhibitor->pid;
1736 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1737 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1738 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1739 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
1740 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1741 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1744 if (!dbus_message_iter_close_container(&sub, &sub2))
1748 if (!dbus_message_iter_close_container(&iter, &sub))
1751 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1753 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1756 return bus_send_error_reply(connection, message, &error, r);
1759 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1761 r = bus_manager_create_session(m, message, &reply);
1763 /* Don't delay the work on OOM here, since it might be
1764 * triggered by a low RLIMIT_NOFILE here (since we
1765 * send a dupped fd to the client), and we'd rather
1766 * see this fail quickly then be retried later */
1769 return bus_send_error_reply(connection, message, NULL, r);
1771 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1775 if (!dbus_message_get_args(
1778 DBUS_TYPE_STRING, &name,
1780 return bus_send_error_reply(connection, message, &error, -EINVAL);
1782 session = hashmap_get(m->sessions, name);
1784 return bus_send_error_reply(connection, message, &error, -ENOENT);
1786 /* We use the FIFO to detect stray sessions where the
1787 process invoking PAM dies abnormally. We need to make
1788 sure that that process is not killed if at the clean
1789 end of the session it closes the FIFO. Hence, with
1790 this call explicitly turn off the FIFO logic, so that
1791 the PAM code can finish clean up on its own */
1792 session_remove_fifo(session);
1794 reply = dbus_message_new_method_return(message);
1798 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1802 if (!dbus_message_get_args(
1805 DBUS_TYPE_STRING, &name,
1807 return bus_send_error_reply(connection, message, &error, -EINVAL);
1809 session = hashmap_get(m->sessions, name);
1811 return bus_send_error_reply(connection, message, &error, -ENOENT);
1813 r = session_activate(session);
1815 return bus_send_error_reply(connection, message, NULL, r);
1817 reply = dbus_message_new_method_return(message);
1821 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1822 const char *session_name, *seat_name;
1826 /* Same as ActivateSession() but refuses to work if
1827 * the seat doesn't match */
1829 if (!dbus_message_get_args(
1832 DBUS_TYPE_STRING, &session_name,
1833 DBUS_TYPE_STRING, &seat_name,
1835 return bus_send_error_reply(connection, message, &error, -EINVAL);
1837 session = hashmap_get(m->sessions, session_name);
1839 return bus_send_error_reply(connection, message, &error, -ENOENT);
1841 seat = hashmap_get(m->seats, seat_name);
1843 return bus_send_error_reply(connection, message, &error, -ENOENT);
1845 if (session->seat != seat)
1846 return bus_send_error_reply(connection, message, &error, -EINVAL);
1848 r = session_activate(session);
1850 return bus_send_error_reply(connection, message, NULL, r);
1852 reply = dbus_message_new_method_return(message);
1856 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1857 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1861 if (!dbus_message_get_args(
1864 DBUS_TYPE_STRING, &name,
1866 return bus_send_error_reply(connection, message, &error, -EINVAL);
1868 session = hashmap_get(m->sessions, name);
1870 return bus_send_error_reply(connection, message, NULL, -ENOENT);
1872 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1875 reply = dbus_message_new_method_return(message);
1879 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions") ||
1880 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSessions")) {
1882 r = session_send_lock_all(m, streq(dbus_message_get_member(message), "LockSessions"));
1884 bus_send_error_reply(connection, message, NULL, r);
1886 reply = dbus_message_new_method_return(message);
1890 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1897 if (!dbus_message_get_args(
1900 DBUS_TYPE_STRING, &name,
1901 DBUS_TYPE_STRING, &swho,
1902 DBUS_TYPE_INT32, &signo,
1904 return bus_send_error_reply(connection, message, &error, -EINVAL);
1909 who = kill_who_from_string(swho);
1911 return bus_send_error_reply(connection, message, &error, -EINVAL);
1914 if (signo <= 0 || signo >= _NSIG)
1915 return bus_send_error_reply(connection, message, &error, -EINVAL);
1917 session = hashmap_get(m->sessions, name);
1919 return bus_send_error_reply(connection, message, &error, -ENOENT);
1921 r = session_kill(session, who, signo);
1923 return bus_send_error_reply(connection, message, NULL, r);
1925 reply = dbus_message_new_method_return(message);
1929 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1934 if (!dbus_message_get_args(
1937 DBUS_TYPE_UINT32, &uid,
1938 DBUS_TYPE_INT32, &signo,
1940 return bus_send_error_reply(connection, message, &error, -EINVAL);
1942 if (signo <= 0 || signo >= _NSIG)
1943 return bus_send_error_reply(connection, message, &error, -EINVAL);
1945 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1947 return bus_send_error_reply(connection, message, &error, -ENOENT);
1949 r = user_kill(user, signo);
1951 return bus_send_error_reply(connection, message, NULL, r);
1953 reply = dbus_message_new_method_return(message);
1957 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1961 if (!dbus_message_get_args(
1964 DBUS_TYPE_STRING, &name,
1966 return bus_send_error_reply(connection, message, &error, -EINVAL);
1968 session = hashmap_get(m->sessions, name);
1970 return bus_send_error_reply(connection, message, &error, -ENOENT);
1972 r = session_stop(session);
1974 return bus_send_error_reply(connection, message, NULL, r);
1976 reply = dbus_message_new_method_return(message);
1980 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1984 if (!dbus_message_get_args(
1987 DBUS_TYPE_UINT32, &uid,
1989 return bus_send_error_reply(connection, message, &error, -EINVAL);
1991 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1993 return bus_send_error_reply(connection, message, &error, -ENOENT);
1995 r = user_stop(user);
1997 return bus_send_error_reply(connection, message, NULL, r);
1999 reply = dbus_message_new_method_return(message);
2003 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
2007 if (!dbus_message_get_args(
2010 DBUS_TYPE_STRING, &name,
2012 return bus_send_error_reply(connection, message, &error, -EINVAL);
2014 seat = hashmap_get(m->seats, name);
2016 return bus_send_error_reply(connection, message, &error, -ENOENT);
2018 r = seat_stop_sessions(seat);
2020 return bus_send_error_reply(connection, message, NULL, r);
2022 reply = dbus_message_new_method_return(message);
2026 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
2029 dbus_bool_t b, interactive;
2032 if (!dbus_message_get_args(
2035 DBUS_TYPE_UINT32, &uid,
2036 DBUS_TYPE_BOOLEAN, &b,
2037 DBUS_TYPE_BOOLEAN, &interactive,
2039 return bus_send_error_reply(connection, message, &error, -EINVAL);
2044 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
2046 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
2048 return bus_send_error_reply(connection, message, &error, r);
2050 mkdir_p_label("/var/lib/systemd", 0755);
2052 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
2054 return bus_send_error_reply(connection, message, &error, r);
2056 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
2067 return bus_send_error_reply(connection, message, &error, r);
2069 if (manager_add_user_by_uid(m, uid, &u) >= 0)
2078 if (r < 0 && errno != ENOENT)
2079 return bus_send_error_reply(connection, message, &error, -errno);
2081 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
2083 user_add_to_gc_queue(u);
2086 reply = dbus_message_new_method_return(message);
2090 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
2091 const char *sysfs, *seat;
2092 dbus_bool_t interactive;
2094 if (!dbus_message_get_args(
2097 DBUS_TYPE_STRING, &seat,
2098 DBUS_TYPE_STRING, &sysfs,
2099 DBUS_TYPE_BOOLEAN, &interactive,
2101 return bus_send_error_reply(connection, message, &error, -EINVAL);
2103 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
2104 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2106 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
2108 return bus_send_error_reply(connection, message, &error, r);
2110 r = attach_device(m, seat, sysfs);
2112 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2114 reply = dbus_message_new_method_return(message);
2119 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
2120 dbus_bool_t interactive;
2122 if (!dbus_message_get_args(
2125 DBUS_TYPE_BOOLEAN, &interactive,
2127 return bus_send_error_reply(connection, message, &error, -EINVAL);
2129 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
2131 return bus_send_error_reply(connection, message, &error, r);
2133 r = flush_devices(m);
2135 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2137 reply = dbus_message_new_method_return(message);
2141 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
2143 r = bus_manager_do_shutdown_or_sleep(
2144 m, connection, message,
2145 SPECIAL_POWEROFF_TARGET,
2147 "org.freedesktop.login1.power-off",
2148 "org.freedesktop.login1.power-off-multiple-sessions",
2149 "org.freedesktop.login1.power-off-ignore-inhibit",
2153 return bus_send_error_reply(connection, message, &error, r);
2154 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
2155 r = bus_manager_do_shutdown_or_sleep(
2156 m, connection, message,
2157 SPECIAL_REBOOT_TARGET,
2159 "org.freedesktop.login1.reboot",
2160 "org.freedesktop.login1.reboot-multiple-sessions",
2161 "org.freedesktop.login1.reboot-ignore-inhibit",
2165 return bus_send_error_reply(connection, message, &error, r);
2167 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2168 r = bus_manager_do_shutdown_or_sleep(
2169 m, connection, message,
2170 SPECIAL_SUSPEND_TARGET,
2172 "org.freedesktop.login1.suspend",
2173 "org.freedesktop.login1.suspend-multiple-sessions",
2174 "org.freedesktop.login1.suspend-ignore-inhibit",
2178 return bus_send_error_reply(connection, message, &error, r);
2179 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2180 r = bus_manager_do_shutdown_or_sleep(
2181 m, connection, message,
2182 SPECIAL_HIBERNATE_TARGET,
2184 "org.freedesktop.login1.hibernate",
2185 "org.freedesktop.login1.hibernate-multiple-sessions",
2186 "org.freedesktop.login1.hibernate-ignore-inhibit",
2190 return bus_send_error_reply(connection, message, &error, r);
2192 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "HybridSleep")) {
2193 r = bus_manager_do_shutdown_or_sleep(
2194 m, connection, message,
2195 SPECIAL_HYBRID_SLEEP_TARGET,
2197 "org.freedesktop.login1.hibernate",
2198 "org.freedesktop.login1.hibernate-multiple-sessions",
2199 "org.freedesktop.login1.hibernate-ignore-inhibit",
2203 return bus_send_error_reply(connection, message, &error, r);
2205 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2207 r = bus_manager_can_shutdown_or_sleep(
2208 m, connection, message,
2210 "org.freedesktop.login1.power-off",
2211 "org.freedesktop.login1.power-off-multiple-sessions",
2212 "org.freedesktop.login1.power-off-ignore-inhibit",
2216 return bus_send_error_reply(connection, message, &error, r);
2217 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2218 r = bus_manager_can_shutdown_or_sleep(
2219 m, connection, message,
2221 "org.freedesktop.login1.reboot",
2222 "org.freedesktop.login1.reboot-multiple-sessions",
2223 "org.freedesktop.login1.reboot-ignore-inhibit",
2227 return bus_send_error_reply(connection, message, &error, r);
2229 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2230 r = bus_manager_can_shutdown_or_sleep(
2231 m, connection, message,
2233 "org.freedesktop.login1.suspend",
2234 "org.freedesktop.login1.suspend-multiple-sessions",
2235 "org.freedesktop.login1.suspend-ignore-inhibit",
2239 return bus_send_error_reply(connection, message, &error, r);
2241 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2242 r = bus_manager_can_shutdown_or_sleep(
2243 m, connection, message,
2245 "org.freedesktop.login1.hibernate",
2246 "org.freedesktop.login1.hibernate-multiple-sessions",
2247 "org.freedesktop.login1.hibernate-ignore-inhibit",
2251 return bus_send_error_reply(connection, message, &error, r);
2253 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHybridSleep")) {
2254 r = bus_manager_can_shutdown_or_sleep(
2255 m, connection, message,
2257 "org.freedesktop.login1.hibernate",
2258 "org.freedesktop.login1.hibernate-multiple-sessions",
2259 "org.freedesktop.login1.hibernate-ignore-inhibit",
2263 return bus_send_error_reply(connection, message, &error, r);
2265 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2266 char *introspection = NULL;
2275 if (!(reply = dbus_message_new_method_return(message)))
2278 /* We roll our own introspection code here, instead of
2279 * relying on bus_default_message_handler() because we
2280 * need to generate our introspection string
2283 if (!(f = open_memstream(&introspection, &size)))
2286 fputs(INTROSPECTION_BEGIN, f);
2288 HASHMAP_FOREACH(seat, m->seats, i) {
2289 p = bus_path_escape(seat->id);
2292 fprintf(f, "<node name=\"seat/%s\"/>", p);
2297 HASHMAP_FOREACH(user, m->users, i)
2298 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2300 HASHMAP_FOREACH(session, m->sessions, i) {
2301 p = bus_path_escape(session->id);
2304 fprintf(f, "<node name=\"session/%s\"/>", p);
2309 fputs(INTROSPECTION_END, f);
2313 free(introspection);
2322 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2323 free(introspection);
2327 free(introspection);
2329 const BusBoundProperties bps[] = {
2330 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2333 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2337 if (!bus_maybe_send_reply(connection, message, reply))
2340 dbus_message_unref(reply);
2343 return DBUS_HANDLER_RESULT_HANDLED;
2347 dbus_message_unref(reply);
2349 dbus_error_free(&error);
2351 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2354 const DBusObjectPathVTable bus_manager_vtable = {
2355 .message_function = manager_message_handler
2358 DBusHandlerResult bus_message_filter(
2359 DBusConnection *connection,
2360 DBusMessage *message,
2363 Manager *m = userdata;
2370 dbus_error_init(&error);
2372 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
2375 if (!dbus_message_get_args(message, &error,
2376 DBUS_TYPE_STRING, &cgroup,
2378 log_error("Failed to parse Released message: %s", bus_error_message(&error));
2380 manager_cgroup_notify_empty(m, cgroup);
2382 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
2384 const char *path, *result, *unit;
2386 if (!dbus_message_get_args(message, &error,
2387 DBUS_TYPE_UINT32, &id,
2388 DBUS_TYPE_OBJECT_PATH, &path,
2389 DBUS_TYPE_STRING, &unit,
2390 DBUS_TYPE_STRING, &result,
2392 log_error("Failed to parse JobRemoved message: %s", bus_error_message(&error));
2394 else if (m->action_job && streq(m->action_job, path)) {
2396 log_info("Operation finished.");
2398 /* Tell people that they now may take a lock again */
2399 send_prepare_for(m, m->action_what, false);
2401 free(m->action_job);
2402 m->action_job = NULL;
2403 m->action_unit = NULL;
2408 dbus_error_free(&error);
2410 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2413 int manager_send_changed(Manager *manager, const char *properties) {
2419 m = bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties);
2423 if (!dbus_connection_send(manager->bus, m, NULL))
2430 dbus_message_unref(m);
2435 int manager_dispatch_delayed(Manager *manager) {
2441 if (!manager->action_unit || manager->action_job)
2444 /* Continue delay? */
2445 if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0)) {
2447 if (manager->action_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC))
2450 log_info("Delay lock is active but inhibitor timeout is reached.");
2453 /* Actually do the operation */
2454 dbus_error_init(&error);
2455 r = execute_shutdown_or_sleep(manager, manager->action_what, manager->action_unit, &error);
2457 log_warning("Failed to send delayed message: %s", bus_error_message_or_strerror(&error, -r));
2458 dbus_error_free(&error);
2460 manager->action_unit = NULL;
2461 manager->action_what = 0;