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=\"KillSession\">\n" \
106 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
107 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
108 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
110 " <method name=\"KillUser\">\n" \
111 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
112 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
114 " <method name=\"TerminateSession\">\n" \
115 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
117 " <method name=\"TerminateUser\">\n" \
118 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
120 " <method name=\"TerminateSeat\">\n" \
121 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
123 " <method name=\"SetUserLinger\">\n" \
124 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
125 " <arg name=\"b\" type=\"b\" direction=\"in\"/>\n" \
126 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
128 " <method name=\"AttachDevice\">\n" \
129 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
130 " <arg name=\"sysfs\" type=\"s\" direction=\"in\"/>\n" \
131 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
133 " <method name=\"FlushDevices\">\n" \
134 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
136 " <method name=\"PowerOff\">\n" \
137 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
139 " <method name=\"Reboot\">\n" \
140 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
142 " <method name=\"Suspend\">\n" \
143 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
145 " <method name=\"Hibernate\">\n" \
146 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
148 " <method name=\"HybridSleep\">\n" \
149 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
151 " <method name=\"CanPowerOff\">\n" \
152 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
154 " <method name=\"CanReboot\">\n" \
155 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
157 " <method name=\"CanSuspend\">\n" \
158 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
160 " <method name=\"CanHibernate\">\n" \
161 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
163 " <method name=\"CanHybridSleep\">\n" \
164 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
166 " <method name=\"Inhibit\">\n" \
167 " <arg name=\"what\" type=\"s\" direction=\"in\"/>\n" \
168 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
169 " <arg name=\"why\" type=\"s\" direction=\"in\"/>\n" \
170 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
171 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
173 " <method name=\"ListInhibitors\">\n" \
174 " <arg name=\"inhibitors\" type=\"a(ssssuu)\" direction=\"out\"/>\n" \
176 " <signal name=\"SessionNew\">\n" \
177 " <arg name=\"id\" type=\"s\"/>\n" \
178 " <arg name=\"path\" type=\"o\"/>\n" \
180 " <signal name=\"SessionRemoved\">\n" \
181 " <arg name=\"id\" type=\"s\"/>\n" \
182 " <arg name=\"path\" type=\"o\"/>\n" \
184 " <signal name=\"UserNew\">\n" \
185 " <arg name=\"uid\" type=\"u\"/>\n" \
186 " <arg name=\"path\" type=\"o\"/>\n" \
188 " <signal name=\"UserRemoved\">\n" \
189 " <arg name=\"uid\" type=\"u\"/>\n" \
190 " <arg name=\"path\" type=\"o\"/>\n" \
192 " <signal name=\"SeatNew\">\n" \
193 " <arg name=\"id\" type=\"s\"/>\n" \
194 " <arg name=\"path\" type=\"o\"/>\n" \
196 " <signal name=\"SeatRemoved\">\n" \
197 " <arg name=\"id\" type=\"s\"/>\n" \
198 " <arg name=\"path\" type=\"o\"/>\n" \
200 " <signal name=\"Resumed\"/>\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->delayed_what & INHIBIT_SHUTDOWN);
302 b = !!(m->delayed_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(Manager *m, DBusConnection *connection, DBusMessage *message, DBusError *error, DBusMessage **_reply) {
702 const char *who, *why, *what, *mode;
708 DBusMessage *reply = NULL;
716 if (!dbus_message_get_args(
719 DBUS_TYPE_STRING, &what,
720 DBUS_TYPE_STRING, &who,
721 DBUS_TYPE_STRING, &why,
722 DBUS_TYPE_STRING, &mode,
723 DBUS_TYPE_INVALID)) {
728 w = inhibit_what_from_string(what);
734 mm = inhibit_mode_from_string(mode);
740 /* Delay is only supported for shutdown/sleep */
741 if (mm == INHIBIT_DELAY && (w & ~(INHIBIT_SHUTDOWN|INHIBIT_SLEEP))) {
746 r = verify_polkit(connection, message,
747 w == INHIBIT_SHUTDOWN ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
748 w == INHIBIT_SLEEP ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep" : "org.freedesktop.login1.inhibit-delay-sleep") :
749 w == INHIBIT_IDLE ? "org.freedesktop.login1.inhibit-block-idle" :
750 w == INHIBIT_HANDLE_POWER_KEY ? "org.freedesktop.login1.inhibit-handle-power-key" :
751 w == INHIBIT_HANDLE_SUSPEND_KEY ? "org.freedesktop.login1.inhibit-handle-suspend-key" :
752 w == INHIBIT_HANDLE_HIBERNATE_KEY ? "org.freedesktop.login1.inhibit-handle-hibernate-key" :
753 "org.freedesktop.login1.inhibit-handle-lid-switch",
758 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
759 if (ul == (unsigned long) -1) {
764 pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
774 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
778 } while (hashmap_get(m->inhibitors, id));
780 r = manager_add_inhibitor(m, id, &i);
790 i->why = strdup(why);
791 i->who = strdup(who);
793 if (!i->why || !i->who) {
798 fifo_fd = inhibitor_create_fifo(i);
804 reply = dbus_message_new_method_return(message);
810 if (!dbus_message_append_args(
812 DBUS_TYPE_UNIX_FD, &fifo_fd,
813 DBUS_TYPE_INVALID)) {
818 close_nointr_nofail(fifo_fd);
830 close_nointr_nofail(fifo_fd);
833 dbus_message_unref(reply);
838 static int trigger_device(Manager *m, struct udev_device *d) {
839 struct udev_enumerate *e;
840 struct udev_list_entry *first, *item;
845 e = udev_enumerate_new(m->udev);
852 if (udev_enumerate_add_match_parent(e, d) < 0) {
858 if (udev_enumerate_scan_devices(e) < 0) {
863 first = udev_enumerate_get_list_entry(e);
864 udev_list_entry_foreach(item, first) {
868 p = udev_list_entry_get_name(item);
870 t = strappend(p, "/uevent");
876 write_one_line_file(t, "change");
884 udev_enumerate_unref(e);
889 static int attach_device(Manager *m, const char *seat, const char *sysfs) {
890 struct udev_device *d;
891 char *rule = NULL, *file = NULL;
892 const char *id_for_seat;
899 d = udev_device_new_from_syspath(m->udev, sysfs);
903 if (!udev_device_has_tag(d, "seat")) {
908 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
914 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
919 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
924 mkdir_p_label("/etc/udev/rules.d", 0755);
925 r = write_one_line_file_atomic(file, rule);
929 r = trigger_device(m, d);
936 udev_device_unref(d);
941 static int flush_devices(Manager *m) {
946 d = opendir("/etc/udev/rules.d");
949 log_warning("Failed to open /etc/udev/rules.d: %m");
953 while ((de = readdir(d))) {
955 if (!dirent_is_file(de))
958 if (!startswith(de->d_name, "72-seat-"))
961 if (!endswith(de->d_name, ".rules"))
964 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
965 log_warning("Failed to unlink %s: %m", de->d_name);
971 return trigger_device(m, NULL);
974 static int have_multiple_sessions(
983 /* Check for other users' sessions. Greeter sessions do not
984 * count, and non-login sessions do not count either. */
985 HASHMAP_FOREACH(session, m->sessions, i)
986 if (session->class == SESSION_USER &&
987 (session->type == SESSION_TTY || session->type == SESSION_X11) &&
988 session->user->uid != uid)
994 static int send_start_unit(Manager *m, const char *unit_name, bool send_resumed, DBusError *error) {
995 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
996 const char *mode = "replace", *p;
1003 r = bus_method_call_with_reply(
1005 "org.freedesktop.systemd1",
1006 "/org/freedesktop/systemd1",
1007 "org.freedesktop.systemd1.Manager",
1011 DBUS_TYPE_STRING, &unit_name,
1012 DBUS_TYPE_STRING, &mode,
1017 if (!dbus_message_get_args(
1020 DBUS_TYPE_OBJECT_PATH, &p,
1028 free(m->action_job);
1030 m->send_resumed_after_action_job = send_resumed;
1035 static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
1036 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
1037 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
1038 [INHIBIT_SLEEP] = "PrepareForSleep"
1041 dbus_bool_t active = _active;
1042 _cleanup_dbus_message_unref_ DBusMessage *message = NULL;
1046 assert(w < _INHIBIT_WHAT_MAX);
1047 assert(signal_name[w]);
1049 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1053 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1054 !dbus_connection_send(m->bus, message, NULL))
1060 static int delay_shutdown_or_sleep(Manager *m, InhibitWhat w, const char *unit_name) {
1063 assert(w < _INHIBIT_WHAT_MAX);
1065 /* Tell everybody to prepare for shutdown/sleep */
1066 send_prepare_for(m, w, true);
1068 /* Update timestamp for timeout */
1069 if (!m->delayed_unit)
1070 m->delayed_timestamp = now(CLOCK_MONOTONIC);
1072 /* Remember what we want to do, possibly overriding what kind
1073 * of unit we previously queued. */
1074 m->delayed_unit = unit_name;
1075 m->delayed_what = w;
1080 static int bus_manager_can_shutdown_or_sleep(
1082 DBusConnection *connection,
1083 DBusMessage *message,
1086 const char *action_multiple_sessions,
1087 const char *action_ignore_inhibit,
1088 const char *sleep_type,
1089 const char *sleep_disk_type,
1091 DBusMessage **_reply) {
1093 bool multiple_sessions, challenge, blocked, b;
1095 DBusMessage *reply = NULL;
1103 assert(w <= _INHIBIT_WHAT_MAX);
1105 assert(action_multiple_sessions);
1106 assert(action_ignore_inhibit);
1111 r = can_sleep(sleep_type);
1121 if (sleep_disk_type) {
1122 r = can_sleep_disk(sleep_disk_type);
1132 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1133 if (ul == (unsigned long) -1)
1136 r = have_multiple_sessions(m, (uid_t) ul);
1140 multiple_sessions = r > 0;
1141 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1143 if (multiple_sessions) {
1144 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1151 result = "challenge";
1157 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1161 if (r > 0 && !result)
1163 else if (challenge && (!result || streq(result, "yes")))
1164 result = "challenge";
1169 if (!multiple_sessions && !blocked) {
1170 /* If neither inhibit nor multiple sessions
1171 * apply then just check the normal policy */
1173 r = verify_polkit(connection, message, action, false, &challenge, error);
1180 result = "challenge";
1186 reply = dbus_message_new_method_return(message);
1190 b = dbus_message_append_args(
1192 DBUS_TYPE_STRING, &result,
1195 dbus_message_unref(reply);
1203 static int bus_manager_log_shutdown(
1206 const char *unit_name) {
1213 if (w != INHIBIT_SHUTDOWN)
1216 if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
1217 p = "MESSAGE=System is powering down.";
1218 q = "SHUTDOWN=power-off";
1219 } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
1220 p = "MESSAGE=System is halting.";
1221 q = "SHUTDOWN=halt";
1222 } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
1223 p = "MESSAGE=System is rebooting.";
1224 q = "SHUTDOWN=reboot";
1225 } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
1226 p = "MESSAGE=System is rebooting with kexec.";
1227 q = "SHUTDOWN=kexec";
1229 p = "MESSAGE=System is shutting down.";
1233 return log_struct(LOG_NOTICE, MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
1238 int bus_manager_shutdown_or_sleep_now_or_later(
1240 const char *unit_name,
1250 assert(w <= _INHIBIT_WHAT_MAX);
1251 assert(!m->action_job);
1254 m->inhibit_delay_max > 0 &&
1255 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0);
1258 /* Shutdown is delayed, keep in mind what we
1259 * want to do, and start a timeout */
1260 r = delay_shutdown_or_sleep(m, w, unit_name);
1262 bus_manager_log_shutdown(m, w, unit_name);
1264 /* Shutdown is not delayed, execute it
1266 r = send_start_unit(m, unit_name, w & INHIBIT_SLEEP, error);
1272 static int bus_manager_do_shutdown_or_sleep(
1274 DBusConnection *connection,
1275 DBusMessage *message,
1276 const char *unit_name,
1279 const char *action_multiple_sessions,
1280 const char *action_ignore_inhibit,
1281 const char *sleep_type,
1282 const char *sleep_disk_type,
1284 DBusMessage **_reply) {
1286 dbus_bool_t interactive;
1287 bool multiple_sessions, blocked;
1288 DBusMessage *reply = NULL;
1297 assert(w <= _INHIBIT_WHAT_MAX);
1299 assert(action_multiple_sessions);
1300 assert(action_ignore_inhibit);
1304 if (m->action_job || m->delayed_unit)
1307 if (!dbus_message_get_args(
1310 DBUS_TYPE_BOOLEAN, &interactive,
1315 r = can_sleep(sleep_type);
1323 if (sleep_disk_type) {
1324 r = can_sleep_disk(sleep_disk_type);
1332 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1333 if (ul == (unsigned long) -1)
1336 r = have_multiple_sessions(m, (uid_t) ul);
1340 multiple_sessions = r > 0;
1341 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1343 if (multiple_sessions) {
1344 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1350 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1355 if (!multiple_sessions && !blocked) {
1356 r = verify_polkit(connection, message, action, interactive, NULL, error);
1361 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
1365 reply = dbus_message_new_method_return(message);
1373 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_action, handle_action, HandleAction);
1375 static const BusProperty bus_login_manager_properties[] = {
1376 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_path), true },
1377 { "Controllers", bus_property_append_strv, "as", offsetof(Manager, controllers), true },
1378 { "ResetControllers", bus_property_append_strv, "as", offsetof(Manager, reset_controllers), true },
1379 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1380 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1381 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1382 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1383 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1384 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1385 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
1386 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1387 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1388 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
1389 { "HandlePowerKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_power_key) },
1390 { "HandleSuspendKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_suspend_key) },
1391 { "HandleHibernateKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_hibernate_key)},
1392 { "HandleLidSwitch", bus_manager_append_handle_action, "s", offsetof(Manager, handle_lid_switch) },
1393 { "IdleAction", bus_manager_append_handle_action, "s", offsetof(Manager, idle_action) },
1394 { "IdleActionUSec", bus_property_append_usec, "t", offsetof(Manager, idle_action_usec) },
1395 { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
1396 { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
1400 static DBusHandlerResult manager_message_handler(
1401 DBusConnection *connection,
1402 DBusMessage *message,
1405 Manager *m = userdata;
1408 DBusMessage *reply = NULL;
1415 dbus_error_init(&error);
1417 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1423 if (!dbus_message_get_args(
1426 DBUS_TYPE_STRING, &name,
1428 return bus_send_error_reply(connection, message, &error, -EINVAL);
1430 session = hashmap_get(m->sessions, name);
1432 return bus_send_error_reply(connection, message, &error, -ENOENT);
1434 reply = dbus_message_new_method_return(message);
1438 p = session_bus_path(session);
1442 b = dbus_message_append_args(
1444 DBUS_TYPE_OBJECT_PATH, &p,
1451 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1457 if (!dbus_message_get_args(
1460 DBUS_TYPE_UINT32, &pid,
1462 return bus_send_error_reply(connection, message, &error, -EINVAL);
1464 r = manager_get_session_by_pid(m, pid, &session);
1466 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1468 reply = dbus_message_new_method_return(message);
1472 p = session_bus_path(session);
1476 b = dbus_message_append_args(
1478 DBUS_TYPE_OBJECT_PATH, &p,
1485 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1491 if (!dbus_message_get_args(
1494 DBUS_TYPE_UINT32, &uid,
1496 return bus_send_error_reply(connection, message, &error, -EINVAL);
1498 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1500 return bus_send_error_reply(connection, message, &error, -ENOENT);
1502 reply = dbus_message_new_method_return(message);
1506 p = user_bus_path(user);
1510 b = dbus_message_append_args(
1512 DBUS_TYPE_OBJECT_PATH, &p,
1519 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1525 if (!dbus_message_get_args(
1528 DBUS_TYPE_STRING, &name,
1530 return bus_send_error_reply(connection, message, &error, -EINVAL);
1532 seat = hashmap_get(m->seats, name);
1534 return bus_send_error_reply(connection, message, &error, -ENOENT);
1536 reply = dbus_message_new_method_return(message);
1540 p = seat_bus_path(seat);
1544 b = dbus_message_append_args(
1546 DBUS_TYPE_OBJECT_PATH, &p,
1553 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1557 DBusMessageIter iter, sub;
1558 const char *empty = "";
1560 reply = dbus_message_new_method_return(message);
1564 dbus_message_iter_init_append(reply, &iter);
1566 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1569 HASHMAP_FOREACH(session, m->sessions, i) {
1570 DBusMessageIter sub2;
1573 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1576 uid = session->user->uid;
1578 p = session_bus_path(session);
1582 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1583 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1584 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1585 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1586 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1593 if (!dbus_message_iter_close_container(&sub, &sub2))
1597 if (!dbus_message_iter_close_container(&iter, &sub))
1600 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1604 DBusMessageIter iter, sub;
1606 reply = dbus_message_new_method_return(message);
1610 dbus_message_iter_init_append(reply, &iter);
1612 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1615 HASHMAP_FOREACH(user, m->users, i) {
1616 DBusMessageIter sub2;
1619 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1624 p = user_bus_path(user);
1628 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1629 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1630 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1637 if (!dbus_message_iter_close_container(&sub, &sub2))
1641 if (!dbus_message_iter_close_container(&iter, &sub))
1644 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1648 DBusMessageIter iter, sub;
1650 reply = dbus_message_new_method_return(message);
1654 dbus_message_iter_init_append(reply, &iter);
1656 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1659 HASHMAP_FOREACH(seat, m->seats, i) {
1660 DBusMessageIter sub2;
1662 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1665 p = seat_bus_path(seat);
1669 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1670 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1677 if (!dbus_message_iter_close_container(&sub, &sub2))
1681 if (!dbus_message_iter_close_container(&iter, &sub))
1684 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1685 Inhibitor *inhibitor;
1687 DBusMessageIter iter, sub;
1689 reply = dbus_message_new_method_return(message);
1693 dbus_message_iter_init_append(reply, &iter);
1695 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1698 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1699 DBusMessageIter sub2;
1700 dbus_uint32_t uid, pid;
1701 const char *what, *who, *why, *mode;
1703 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1706 what = strempty(inhibit_what_to_string(inhibitor->what));
1707 who = strempty(inhibitor->who);
1708 why = strempty(inhibitor->why);
1709 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
1710 uid = (dbus_uint32_t) inhibitor->uid;
1711 pid = (dbus_uint32_t) inhibitor->pid;
1713 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1714 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1715 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1716 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
1717 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1718 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1721 if (!dbus_message_iter_close_container(&sub, &sub2))
1725 if (!dbus_message_iter_close_container(&iter, &sub))
1728 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1730 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1733 return bus_send_error_reply(connection, message, &error, r);
1736 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1738 r = bus_manager_create_session(m, message, &reply);
1740 /* Don't delay the work on OOM here, since it might be
1741 * triggered by a low RLIMIT_NOFILE here (since we
1742 * send a dupped fd to the client), and we'd rather
1743 * see this fail quickly then be retried later */
1746 return bus_send_error_reply(connection, message, NULL, r);
1748 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1752 if (!dbus_message_get_args(
1755 DBUS_TYPE_STRING, &name,
1757 return bus_send_error_reply(connection, message, &error, -EINVAL);
1759 session = hashmap_get(m->sessions, name);
1761 return bus_send_error_reply(connection, message, &error, -ENOENT);
1763 /* We use the FIFO to detect stray sessions where the
1764 process invoking PAM dies abnormally. We need to make
1765 sure that that process is not killed if at the clean
1766 end of the session it closes the FIFO. Hence, with
1767 this call explicitly turn off the FIFO logic, so that
1768 the PAM code can finish clean up on its own */
1769 session_remove_fifo(session);
1771 reply = dbus_message_new_method_return(message);
1775 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1779 if (!dbus_message_get_args(
1782 DBUS_TYPE_STRING, &name,
1784 return bus_send_error_reply(connection, message, &error, -EINVAL);
1786 session = hashmap_get(m->sessions, name);
1788 return bus_send_error_reply(connection, message, &error, -ENOENT);
1790 r = session_activate(session);
1792 return bus_send_error_reply(connection, message, NULL, r);
1794 reply = dbus_message_new_method_return(message);
1798 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1799 const char *session_name, *seat_name;
1803 /* Same as ActivateSession() but refuses to work if
1804 * the seat doesn't match */
1806 if (!dbus_message_get_args(
1809 DBUS_TYPE_STRING, &session_name,
1810 DBUS_TYPE_STRING, &seat_name,
1812 return bus_send_error_reply(connection, message, &error, -EINVAL);
1814 session = hashmap_get(m->sessions, session_name);
1816 return bus_send_error_reply(connection, message, &error, -ENOENT);
1818 seat = hashmap_get(m->seats, seat_name);
1820 return bus_send_error_reply(connection, message, &error, -ENOENT);
1822 if (session->seat != seat)
1823 return bus_send_error_reply(connection, message, &error, -EINVAL);
1825 r = session_activate(session);
1827 return bus_send_error_reply(connection, message, NULL, r);
1829 reply = dbus_message_new_method_return(message);
1833 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1834 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1838 if (!dbus_message_get_args(
1841 DBUS_TYPE_STRING, &name,
1843 return bus_send_error_reply(connection, message, &error, -EINVAL);
1845 session = hashmap_get(m->sessions, name);
1847 return bus_send_error_reply(connection, message, NULL, -ENOENT);
1849 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1852 reply = dbus_message_new_method_return(message);
1856 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions")) {
1857 r = session_send_lock_all(m, true);
1859 bus_send_error_reply(connection, message, NULL, r);
1861 reply = dbus_message_new_method_return(message);
1865 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1872 if (!dbus_message_get_args(
1875 DBUS_TYPE_STRING, &name,
1876 DBUS_TYPE_STRING, &swho,
1877 DBUS_TYPE_INT32, &signo,
1879 return bus_send_error_reply(connection, message, &error, -EINVAL);
1884 who = kill_who_from_string(swho);
1886 return bus_send_error_reply(connection, message, &error, -EINVAL);
1889 if (signo <= 0 || signo >= _NSIG)
1890 return bus_send_error_reply(connection, message, &error, -EINVAL);
1892 session = hashmap_get(m->sessions, name);
1894 return bus_send_error_reply(connection, message, &error, -ENOENT);
1896 r = session_kill(session, who, signo);
1898 return bus_send_error_reply(connection, message, NULL, r);
1900 reply = dbus_message_new_method_return(message);
1904 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1909 if (!dbus_message_get_args(
1912 DBUS_TYPE_UINT32, &uid,
1913 DBUS_TYPE_INT32, &signo,
1915 return bus_send_error_reply(connection, message, &error, -EINVAL);
1917 if (signo <= 0 || signo >= _NSIG)
1918 return bus_send_error_reply(connection, message, &error, -EINVAL);
1920 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1922 return bus_send_error_reply(connection, message, &error, -ENOENT);
1924 r = user_kill(user, signo);
1926 return bus_send_error_reply(connection, message, NULL, r);
1928 reply = dbus_message_new_method_return(message);
1932 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1936 if (!dbus_message_get_args(
1939 DBUS_TYPE_STRING, &name,
1941 return bus_send_error_reply(connection, message, &error, -EINVAL);
1943 session = hashmap_get(m->sessions, name);
1945 return bus_send_error_reply(connection, message, &error, -ENOENT);
1947 r = session_stop(session);
1949 return bus_send_error_reply(connection, message, NULL, r);
1951 reply = dbus_message_new_method_return(message);
1955 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1959 if (!dbus_message_get_args(
1962 DBUS_TYPE_UINT32, &uid,
1964 return bus_send_error_reply(connection, message, &error, -EINVAL);
1966 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1968 return bus_send_error_reply(connection, message, &error, -ENOENT);
1970 r = user_stop(user);
1972 return bus_send_error_reply(connection, message, NULL, r);
1974 reply = dbus_message_new_method_return(message);
1978 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1982 if (!dbus_message_get_args(
1985 DBUS_TYPE_STRING, &name,
1987 return bus_send_error_reply(connection, message, &error, -EINVAL);
1989 seat = hashmap_get(m->seats, name);
1991 return bus_send_error_reply(connection, message, &error, -ENOENT);
1993 r = seat_stop_sessions(seat);
1995 return bus_send_error_reply(connection, message, NULL, r);
1997 reply = dbus_message_new_method_return(message);
2001 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
2004 dbus_bool_t b, interactive;
2007 if (!dbus_message_get_args(
2010 DBUS_TYPE_UINT32, &uid,
2011 DBUS_TYPE_BOOLEAN, &b,
2012 DBUS_TYPE_BOOLEAN, &interactive,
2014 return bus_send_error_reply(connection, message, &error, -EINVAL);
2019 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
2021 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
2023 return bus_send_error_reply(connection, message, &error, r);
2025 mkdir_p_label("/var/lib/systemd", 0755);
2027 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
2029 return bus_send_error_reply(connection, message, &error, r);
2031 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
2042 return bus_send_error_reply(connection, message, &error, r);
2044 if (manager_add_user_by_uid(m, uid, &u) >= 0)
2053 if (r < 0 && errno != ENOENT)
2054 return bus_send_error_reply(connection, message, &error, -errno);
2056 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
2058 user_add_to_gc_queue(u);
2061 reply = dbus_message_new_method_return(message);
2065 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
2066 const char *sysfs, *seat;
2067 dbus_bool_t interactive;
2069 if (!dbus_message_get_args(
2072 DBUS_TYPE_STRING, &seat,
2073 DBUS_TYPE_STRING, &sysfs,
2074 DBUS_TYPE_BOOLEAN, &interactive,
2076 return bus_send_error_reply(connection, message, &error, -EINVAL);
2078 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
2079 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2081 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
2083 return bus_send_error_reply(connection, message, &error, r);
2085 r = attach_device(m, seat, sysfs);
2087 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2089 reply = dbus_message_new_method_return(message);
2094 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
2095 dbus_bool_t interactive;
2097 if (!dbus_message_get_args(
2100 DBUS_TYPE_BOOLEAN, &interactive,
2102 return bus_send_error_reply(connection, message, &error, -EINVAL);
2104 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
2106 return bus_send_error_reply(connection, message, &error, r);
2108 r = flush_devices(m);
2110 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2112 reply = dbus_message_new_method_return(message);
2116 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
2118 r = bus_manager_do_shutdown_or_sleep(
2119 m, connection, message,
2120 SPECIAL_POWEROFF_TARGET,
2122 "org.freedesktop.login1.power-off",
2123 "org.freedesktop.login1.power-off-multiple-sessions",
2124 "org.freedesktop.login1.power-off-ignore-inhibit",
2128 return bus_send_error_reply(connection, message, &error, r);
2129 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
2130 r = bus_manager_do_shutdown_or_sleep(
2131 m, connection, message,
2132 SPECIAL_REBOOT_TARGET,
2134 "org.freedesktop.login1.reboot",
2135 "org.freedesktop.login1.reboot-multiple-sessions",
2136 "org.freedesktop.login1.reboot-ignore-inhibit",
2140 return bus_send_error_reply(connection, message, &error, r);
2142 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2143 r = bus_manager_do_shutdown_or_sleep(
2144 m, connection, message,
2145 SPECIAL_SUSPEND_TARGET,
2147 "org.freedesktop.login1.suspend",
2148 "org.freedesktop.login1.suspend-multiple-sessions",
2149 "org.freedesktop.login1.suspend-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", "Hibernate")) {
2155 r = bus_manager_do_shutdown_or_sleep(
2156 m, connection, message,
2157 SPECIAL_HIBERNATE_TARGET,
2159 "org.freedesktop.login1.hibernate",
2160 "org.freedesktop.login1.hibernate-multiple-sessions",
2161 "org.freedesktop.login1.hibernate-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", "HybridSleep")) {
2168 r = bus_manager_do_shutdown_or_sleep(
2169 m, connection, message,
2170 SPECIAL_HYBRID_SLEEP_TARGET,
2172 "org.freedesktop.login1.hibernate",
2173 "org.freedesktop.login1.hibernate-multiple-sessions",
2174 "org.freedesktop.login1.hibernate-ignore-inhibit",
2178 return bus_send_error_reply(connection, message, &error, r);
2180 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2182 r = bus_manager_can_shutdown_or_sleep(
2183 m, connection, message,
2185 "org.freedesktop.login1.power-off",
2186 "org.freedesktop.login1.power-off-multiple-sessions",
2187 "org.freedesktop.login1.power-off-ignore-inhibit",
2191 return bus_send_error_reply(connection, message, &error, r);
2192 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2193 r = bus_manager_can_shutdown_or_sleep(
2194 m, connection, message,
2196 "org.freedesktop.login1.reboot",
2197 "org.freedesktop.login1.reboot-multiple-sessions",
2198 "org.freedesktop.login1.reboot-ignore-inhibit",
2202 return bus_send_error_reply(connection, message, &error, r);
2204 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2205 r = bus_manager_can_shutdown_or_sleep(
2206 m, connection, message,
2208 "org.freedesktop.login1.suspend",
2209 "org.freedesktop.login1.suspend-multiple-sessions",
2210 "org.freedesktop.login1.suspend-ignore-inhibit",
2214 return bus_send_error_reply(connection, message, &error, r);
2216 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2217 r = bus_manager_can_shutdown_or_sleep(
2218 m, connection, message,
2220 "org.freedesktop.login1.hibernate",
2221 "org.freedesktop.login1.hibernate-multiple-sessions",
2222 "org.freedesktop.login1.hibernate-ignore-inhibit",
2226 return bus_send_error_reply(connection, message, &error, r);
2228 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHybridSleep")) {
2229 r = bus_manager_can_shutdown_or_sleep(
2230 m, connection, message,
2232 "org.freedesktop.login1.hibernate",
2233 "org.freedesktop.login1.hibernate-multiple-sessions",
2234 "org.freedesktop.login1.hibernate-ignore-inhibit",
2238 return bus_send_error_reply(connection, message, &error, r);
2240 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2241 char *introspection = NULL;
2250 if (!(reply = dbus_message_new_method_return(message)))
2253 /* We roll our own introspection code here, instead of
2254 * relying on bus_default_message_handler() because we
2255 * need to generate our introspection string
2258 if (!(f = open_memstream(&introspection, &size)))
2261 fputs(INTROSPECTION_BEGIN, f);
2263 HASHMAP_FOREACH(seat, m->seats, i) {
2264 p = bus_path_escape(seat->id);
2267 fprintf(f, "<node name=\"seat/%s\"/>", p);
2272 HASHMAP_FOREACH(user, m->users, i)
2273 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2275 HASHMAP_FOREACH(session, m->sessions, i) {
2276 p = bus_path_escape(session->id);
2279 fprintf(f, "<node name=\"session/%s\"/>", p);
2284 fputs(INTROSPECTION_END, f);
2288 free(introspection);
2297 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2298 free(introspection);
2302 free(introspection);
2304 const BusBoundProperties bps[] = {
2305 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2308 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2312 if (!bus_maybe_send_reply(connection, message, reply))
2315 dbus_message_unref(reply);
2318 return DBUS_HANDLER_RESULT_HANDLED;
2322 dbus_message_unref(reply);
2324 dbus_error_free(&error);
2326 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2329 const DBusObjectPathVTable bus_manager_vtable = {
2330 .message_function = manager_message_handler
2333 DBusHandlerResult bus_message_filter(
2334 DBusConnection *connection,
2335 DBusMessage *message,
2338 Manager *m = userdata;
2345 dbus_error_init(&error);
2347 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
2350 if (!dbus_message_get_args(message, &error,
2351 DBUS_TYPE_STRING, &cgroup,
2353 log_error("Failed to parse Released message: %s", bus_error_message(&error));
2355 manager_cgroup_notify_empty(m, cgroup);
2357 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
2359 const char *path, *result, *unit;
2361 if (!dbus_message_get_args(message, &error,
2362 DBUS_TYPE_UINT32, &id,
2363 DBUS_TYPE_OBJECT_PATH, &path,
2364 DBUS_TYPE_STRING, &unit,
2365 DBUS_TYPE_STRING, &result,
2367 log_error("Failed to parse JobRemoved message: %s", bus_error_message(&error));
2368 else if (m->action_job && streq(m->action_job, path)) {
2369 log_info("Action is complete, result is '%s'.", result);
2370 free(m->action_job);
2371 m->action_job = NULL;
2373 if (m->send_resumed_after_action_job) {
2374 _cleanup_dbus_message_unref_ DBusMessage *s = NULL;
2376 s = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", "Resumed");
2378 dbus_connection_send(m->bus, s, NULL);
2383 dbus_error_free(&error);
2385 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2388 int manager_send_changed(Manager *manager, const char *properties) {
2394 m = bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties);
2398 if (!dbus_connection_send(manager->bus, m, NULL))
2405 dbus_message_unref(m);
2410 int manager_dispatch_delayed(Manager *manager) {
2411 const char *unit_name;
2418 if (!manager->delayed_unit)
2421 /* Continue delay? */
2423 manager->delayed_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC) &&
2424 manager_is_inhibited(manager, manager->delayed_what, INHIBIT_DELAY, NULL, false, false, 0);
2428 bus_manager_log_shutdown(manager, manager->delayed_what, manager->delayed_unit);
2430 /* Tell people about it */
2431 send_prepare_for(manager, manager->delayed_what, false);
2433 /* Reset delay data */
2434 unit_name = manager->delayed_unit;
2435 manager->delayed_unit = NULL;
2437 /* Actually do the shutdown */
2438 dbus_error_init(&error);
2439 r = send_start_unit(manager, unit_name, manager->delayed_what & INHIBIT_SLEEP, &error);
2441 log_warning("Failed to send delayed message: %s", bus_error_message_or_strerror(&error, -r));
2442 dbus_error_free(&error);