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=\"Resumed\"/>\n" \
202 " <signal name=\"PrepareForShutdown\">\n" \
203 " <arg name=\"active\" type=\"b\"/>\n" \
205 " <signal name=\"PrepareForSleep\">\n" \
206 " <arg name=\"active\" type=\"b\"/>\n" \
208 " <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
209 " <property name=\"Controllers\" type=\"as\" access=\"read\"/>\n" \
210 " <property name=\"ResetControllers\" type=\"as\" access=\"read\"/>\n" \
211 " <property name=\"NAutoVTs\" type=\"u\" access=\"read\"/>\n" \
212 " <property name=\"KillOnlyUsers\" type=\"as\" access=\"read\"/>\n" \
213 " <property name=\"KillExcludeUsers\" type=\"as\" access=\"read\"/>\n" \
214 " <property name=\"KillUserProcesses\" type=\"b\" access=\"read\"/>\n" \
215 " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
216 " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
217 " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
218 " <property name=\"BlockInhibited\" type=\"s\" access=\"read\"/>\n" \
219 " <property name=\"DelayInhibited\" type=\"s\" access=\"read\"/>\n" \
220 " <property name=\"InhibitDelayMaxUSec\" type=\"t\" access=\"read\"/>\n" \
221 " <property name=\"HandlePowerKey\" type=\"s\" access=\"read\"/>\n" \
222 " <property name=\"HandleSuspendKey\" type=\"s\" access=\"read\"/>\n" \
223 " <property name=\"HandleHibernateKey\" type=\"s\" access=\"read\"/>\n" \
224 " <property name=\"HandleLidSwitch\" type=\"s\" access=\"read\"/>\n" \
225 " <property name=\"IdleAction\" type=\"s\" access=\"read\"/>\n" \
226 " <property name=\"IdleActionUSec\" type=\"t\" access=\"read\"/>\n" \
227 " <property name=\"PreparingForShutdown\" type=\"b\" access=\"read\"/>\n" \
228 " <property name=\"PreparingForSleep\" type=\"b\" access=\"read\"/>\n" \
231 #define INTROSPECTION_BEGIN \
232 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
234 BUS_MANAGER_INTERFACE \
235 BUS_PROPERTIES_INTERFACE \
237 BUS_INTROSPECTABLE_INTERFACE
239 #define INTROSPECTION_END \
242 #define INTERFACES_LIST \
243 BUS_GENERIC_INTERFACES_LIST \
244 "org.freedesktop.login1.Manager\0"
246 static int bus_manager_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
254 b = manager_get_idle_hint(m, NULL) > 0;
255 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
261 static int bus_manager_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
270 manager_get_idle_hint(m, &t);
271 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
273 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
279 static int bus_manager_append_inhibited(DBusMessageIter *i, const char *property, void *data) {
284 w = manager_inhibit_what(m, streq(property, "BlockInhibited") ? INHIBIT_BLOCK : INHIBIT_DELAY);
285 p = inhibit_what_to_string(w);
287 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &p))
293 static int bus_manager_append_preparing(DBusMessageIter *i, const char *property, void *data) {
300 if (streq(property, "PreparingForShutdown"))
301 b = !!(m->delayed_what & INHIBIT_SHUTDOWN);
303 b = !!(m->delayed_what & INHIBIT_SLEEP);
305 dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b);
309 static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMessage **_reply) {
310 Session *session = NULL;
312 const char *type, *class, *seat, *tty, *display, *remote_user, *remote_host, *service;
313 uint32_t uid, leader, audit_id = 0;
314 dbus_bool_t remote, kill_processes, exists;
315 char **controllers = NULL, **reset_controllers = NULL;
319 DBusMessageIter iter;
324 DBusMessage *reply = NULL;
331 if (!dbus_message_iter_init(message, &iter) ||
332 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
335 dbus_message_iter_get_basic(&iter, &uid);
337 if (!dbus_message_iter_next(&iter) ||
338 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
341 dbus_message_iter_get_basic(&iter, &leader);
344 !dbus_message_iter_next(&iter) ||
345 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
348 dbus_message_iter_get_basic(&iter, &service);
350 if (!dbus_message_iter_next(&iter) ||
351 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
354 dbus_message_iter_get_basic(&iter, &type);
355 t = session_type_from_string(type);
358 !dbus_message_iter_next(&iter) ||
359 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
362 dbus_message_iter_get_basic(&iter, &class);
366 c = session_class_from_string(class);
369 !dbus_message_iter_next(&iter) ||
370 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
373 dbus_message_iter_get_basic(&iter, &seat);
378 s = hashmap_get(m->seats, seat);
383 if (!dbus_message_iter_next(&iter) ||
384 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
387 dbus_message_iter_get_basic(&iter, &vtnr);
389 if (!dbus_message_iter_next(&iter) ||
390 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
393 dbus_message_iter_get_basic(&iter, &tty);
395 if (tty_is_vc(tty)) {
400 else if (s != m->vtconsole)
403 v = vtnr_from_tty(tty);
406 return v < 0 ? v : -EINVAL;
410 else if (vtnr != (uint32_t) v)
412 } else if (tty_is_console(tty)) {
416 else if (s != m->vtconsole)
425 if (seat_can_multi_session(s)) {
434 if (!dbus_message_iter_next(&iter) ||
435 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
438 dbus_message_iter_get_basic(&iter, &display);
440 if (!dbus_message_iter_next(&iter) ||
441 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
444 dbus_message_iter_get_basic(&iter, &remote);
446 if (!dbus_message_iter_next(&iter) ||
447 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
450 dbus_message_iter_get_basic(&iter, &remote_user);
452 if (!dbus_message_iter_next(&iter) ||
453 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
456 dbus_message_iter_get_basic(&iter, &remote_host);
458 if (!dbus_message_iter_next(&iter) ||
459 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
460 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
463 r = bus_parse_strv_iter(&iter, &controllers);
467 if (strv_contains(controllers, "systemd") ||
468 !dbus_message_iter_next(&iter) ||
469 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
470 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) {
475 r = bus_parse_strv_iter(&iter, &reset_controllers);
479 if (strv_contains(reset_controllers, "systemd") ||
480 !dbus_message_iter_next(&iter) ||
481 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) {
486 dbus_message_iter_get_basic(&iter, &kill_processes);
488 r = manager_add_user_by_uid(m, uid, &user);
492 audit_session_from_pid(leader, &audit_id);
495 asprintf(&id, "%lu", (unsigned long) audit_id);
502 session = hashmap_get(m->sessions, id);
507 fifo_fd = session_create_fifo(session);
513 /* Session already exists, client is probably
514 * something like "su" which changes uid but
515 * is still the same audit session */
517 reply = dbus_message_new_method_return(message);
523 p = session_bus_path(session);
529 seat = session->seat ? session->seat->id : "";
530 vtnr = session->vtnr;
533 b = dbus_message_append_args(
535 DBUS_TYPE_STRING, &session->id,
536 DBUS_TYPE_OBJECT_PATH, &p,
537 DBUS_TYPE_STRING, &session->user->runtime_path,
538 DBUS_TYPE_UNIX_FD, &fifo_fd,
539 DBUS_TYPE_STRING, &seat,
540 DBUS_TYPE_UINT32, &vtnr,
541 DBUS_TYPE_BOOLEAN, &exists,
550 close_nointr_nofail(fifo_fd);
553 strv_free(controllers);
554 strv_free(reset_controllers);
564 if (asprintf(&id, "c%lu", ++m->session_counter) < 0) {
569 } while (hashmap_get(m->sessions, id));
572 r = manager_add_session(m, user, id, &session);
577 session->leader = leader;
578 session->audit_id = audit_id;
581 session->remote = remote;
582 session->controllers = controllers;
583 session->reset_controllers = reset_controllers;
584 session->kill_processes = kill_processes;
585 session->vtnr = vtnr;
587 controllers = reset_controllers = NULL;
590 session->tty = strdup(tty);
597 if (!isempty(display)) {
598 session->display = strdup(display);
599 if (!session->display) {
605 if (!isempty(remote_user)) {
606 session->remote_user = strdup(remote_user);
607 if (!session->remote_user) {
613 if (!isempty(remote_host)) {
614 session->remote_host = strdup(remote_host);
615 if (!session->remote_host) {
621 if (!isempty(service)) {
622 session->service = strdup(service);
623 if (!session->service) {
629 fifo_fd = session_create_fifo(session);
636 r = seat_attach_session(s, session);
641 r = session_start(session);
645 reply = dbus_message_new_method_return(message);
651 p = session_bus_path(session);
657 seat = s ? s->id : "";
659 b = dbus_message_append_args(
661 DBUS_TYPE_STRING, &session->id,
662 DBUS_TYPE_OBJECT_PATH, &p,
663 DBUS_TYPE_STRING, &session->user->runtime_path,
664 DBUS_TYPE_UNIX_FD, &fifo_fd,
665 DBUS_TYPE_STRING, &seat,
666 DBUS_TYPE_UINT32, &vtnr,
667 DBUS_TYPE_BOOLEAN, &exists,
676 close_nointr_nofail(fifo_fd);
682 strv_free(controllers);
683 strv_free(reset_controllers);
686 session_add_to_gc_queue(session);
689 user_add_to_gc_queue(user);
692 close_nointr_nofail(fifo_fd);
695 dbus_message_unref(reply);
700 static int bus_manager_inhibit(Manager *m, DBusConnection *connection, DBusMessage *message, DBusError *error, DBusMessage **_reply) {
703 const char *who, *why, *what, *mode;
709 DBusMessage *reply = NULL;
717 if (!dbus_message_get_args(
720 DBUS_TYPE_STRING, &what,
721 DBUS_TYPE_STRING, &who,
722 DBUS_TYPE_STRING, &why,
723 DBUS_TYPE_STRING, &mode,
724 DBUS_TYPE_INVALID)) {
729 w = inhibit_what_from_string(what);
735 mm = inhibit_mode_from_string(mode);
741 /* Delay is only supported for shutdown/sleep */
742 if (mm == INHIBIT_DELAY && (w & ~(INHIBIT_SHUTDOWN|INHIBIT_SLEEP))) {
747 r = verify_polkit(connection, message,
748 w == INHIBIT_SHUTDOWN ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
749 w == INHIBIT_SLEEP ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep" : "org.freedesktop.login1.inhibit-delay-sleep") :
750 w == INHIBIT_IDLE ? "org.freedesktop.login1.inhibit-block-idle" :
751 w == INHIBIT_HANDLE_POWER_KEY ? "org.freedesktop.login1.inhibit-handle-power-key" :
752 w == INHIBIT_HANDLE_SUSPEND_KEY ? "org.freedesktop.login1.inhibit-handle-suspend-key" :
753 w == INHIBIT_HANDLE_HIBERNATE_KEY ? "org.freedesktop.login1.inhibit-handle-hibernate-key" :
754 "org.freedesktop.login1.inhibit-handle-lid-switch",
759 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
760 if (ul == (unsigned long) -1) {
765 pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
775 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
779 } while (hashmap_get(m->inhibitors, id));
781 r = manager_add_inhibitor(m, id, &i);
791 i->why = strdup(why);
792 i->who = strdup(who);
794 if (!i->why || !i->who) {
799 fifo_fd = inhibitor_create_fifo(i);
805 reply = dbus_message_new_method_return(message);
811 if (!dbus_message_append_args(
813 DBUS_TYPE_UNIX_FD, &fifo_fd,
814 DBUS_TYPE_INVALID)) {
819 close_nointr_nofail(fifo_fd);
831 close_nointr_nofail(fifo_fd);
834 dbus_message_unref(reply);
839 static int trigger_device(Manager *m, struct udev_device *d) {
840 struct udev_enumerate *e;
841 struct udev_list_entry *first, *item;
846 e = udev_enumerate_new(m->udev);
853 if (udev_enumerate_add_match_parent(e, d) < 0) {
859 if (udev_enumerate_scan_devices(e) < 0) {
864 first = udev_enumerate_get_list_entry(e);
865 udev_list_entry_foreach(item, first) {
869 p = udev_list_entry_get_name(item);
871 t = strappend(p, "/uevent");
877 write_one_line_file(t, "change");
885 udev_enumerate_unref(e);
890 static int attach_device(Manager *m, const char *seat, const char *sysfs) {
891 struct udev_device *d;
892 char *rule = NULL, *file = NULL;
893 const char *id_for_seat;
900 d = udev_device_new_from_syspath(m->udev, sysfs);
904 if (!udev_device_has_tag(d, "seat")) {
909 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
915 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
920 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
925 mkdir_p_label("/etc/udev/rules.d", 0755);
926 r = write_one_line_file_atomic(file, rule);
930 r = trigger_device(m, d);
937 udev_device_unref(d);
942 static int flush_devices(Manager *m) {
947 d = opendir("/etc/udev/rules.d");
950 log_warning("Failed to open /etc/udev/rules.d: %m");
954 while ((de = readdir(d))) {
956 if (!dirent_is_file(de))
959 if (!startswith(de->d_name, "72-seat-"))
962 if (!endswith(de->d_name, ".rules"))
965 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
966 log_warning("Failed to unlink %s: %m", de->d_name);
972 return trigger_device(m, NULL);
975 static int have_multiple_sessions(
984 /* Check for other users' sessions. Greeter sessions do not
985 * count, and non-login sessions do not count either. */
986 HASHMAP_FOREACH(session, m->sessions, i)
987 if (session->class == SESSION_USER &&
988 (session->type == SESSION_TTY || session->type == SESSION_X11) &&
989 session->user->uid != uid)
995 static int send_start_unit(Manager *m, const char *unit_name, bool send_resumed, DBusError *error) {
996 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
997 const char *mode = "replace", *p;
1004 r = bus_method_call_with_reply(
1006 "org.freedesktop.systemd1",
1007 "/org/freedesktop/systemd1",
1008 "org.freedesktop.systemd1.Manager",
1012 DBUS_TYPE_STRING, &unit_name,
1013 DBUS_TYPE_STRING, &mode,
1018 if (!dbus_message_get_args(
1021 DBUS_TYPE_OBJECT_PATH, &p,
1029 free(m->action_job);
1031 m->send_resumed_after_action_job = send_resumed;
1036 static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
1037 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
1038 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
1039 [INHIBIT_SLEEP] = "PrepareForSleep"
1042 dbus_bool_t active = _active;
1043 _cleanup_dbus_message_unref_ DBusMessage *message = NULL;
1047 assert(w < _INHIBIT_WHAT_MAX);
1048 assert(signal_name[w]);
1050 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1054 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1055 !dbus_connection_send(m->bus, message, NULL))
1061 static int delay_shutdown_or_sleep(Manager *m, InhibitWhat w, const char *unit_name) {
1064 assert(w < _INHIBIT_WHAT_MAX);
1066 /* Tell everybody to prepare for shutdown/sleep */
1067 send_prepare_for(m, w, true);
1069 /* Update timestamp for timeout */
1070 if (!m->delayed_unit)
1071 m->delayed_timestamp = now(CLOCK_MONOTONIC);
1073 /* Remember what we want to do, possibly overriding what kind
1074 * of unit we previously queued. */
1075 m->delayed_unit = unit_name;
1076 m->delayed_what = w;
1081 static int bus_manager_can_shutdown_or_sleep(
1083 DBusConnection *connection,
1084 DBusMessage *message,
1087 const char *action_multiple_sessions,
1088 const char *action_ignore_inhibit,
1089 const char *sleep_type,
1090 const char *sleep_disk_type,
1092 DBusMessage **_reply) {
1094 bool multiple_sessions, challenge, blocked, b;
1096 DBusMessage *reply = NULL;
1104 assert(w <= _INHIBIT_WHAT_MAX);
1106 assert(action_multiple_sessions);
1107 assert(action_ignore_inhibit);
1112 r = can_sleep(sleep_type);
1122 if (sleep_disk_type) {
1123 r = can_sleep_disk(sleep_disk_type);
1133 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1134 if (ul == (unsigned long) -1)
1137 r = have_multiple_sessions(m, (uid_t) ul);
1141 multiple_sessions = r > 0;
1142 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1144 if (multiple_sessions) {
1145 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1152 result = "challenge";
1158 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1162 if (r > 0 && !result)
1164 else if (challenge && (!result || streq(result, "yes")))
1165 result = "challenge";
1170 if (!multiple_sessions && !blocked) {
1171 /* If neither inhibit nor multiple sessions
1172 * apply then just check the normal policy */
1174 r = verify_polkit(connection, message, action, false, &challenge, error);
1181 result = "challenge";
1187 reply = dbus_message_new_method_return(message);
1191 b = dbus_message_append_args(
1193 DBUS_TYPE_STRING, &result,
1196 dbus_message_unref(reply);
1204 static int bus_manager_log_shutdown(
1207 const char *unit_name) {
1214 if (w != INHIBIT_SHUTDOWN)
1217 if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
1218 p = "MESSAGE=System is powering down.";
1219 q = "SHUTDOWN=power-off";
1220 } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
1221 p = "MESSAGE=System is halting.";
1222 q = "SHUTDOWN=halt";
1223 } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
1224 p = "MESSAGE=System is rebooting.";
1225 q = "SHUTDOWN=reboot";
1226 } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
1227 p = "MESSAGE=System is rebooting with kexec.";
1228 q = "SHUTDOWN=kexec";
1230 p = "MESSAGE=System is shutting down.";
1234 return log_struct(LOG_NOTICE, MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
1239 int bus_manager_shutdown_or_sleep_now_or_later(
1241 const char *unit_name,
1251 assert(w <= _INHIBIT_WHAT_MAX);
1252 assert(!m->action_job);
1255 m->inhibit_delay_max > 0 &&
1256 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0);
1259 /* Shutdown is delayed, keep in mind what we
1260 * want to do, and start a timeout */
1261 r = delay_shutdown_or_sleep(m, w, unit_name);
1263 bus_manager_log_shutdown(m, w, unit_name);
1265 /* Shutdown is not delayed, execute it
1267 r = send_start_unit(m, unit_name, w & INHIBIT_SLEEP, error);
1273 static int bus_manager_do_shutdown_or_sleep(
1275 DBusConnection *connection,
1276 DBusMessage *message,
1277 const char *unit_name,
1280 const char *action_multiple_sessions,
1281 const char *action_ignore_inhibit,
1282 const char *sleep_type,
1283 const char *sleep_disk_type,
1285 DBusMessage **_reply) {
1287 dbus_bool_t interactive;
1288 bool multiple_sessions, blocked;
1289 DBusMessage *reply = NULL;
1298 assert(w <= _INHIBIT_WHAT_MAX);
1300 assert(action_multiple_sessions);
1301 assert(action_ignore_inhibit);
1305 if (m->action_job || m->delayed_unit)
1308 if (!dbus_message_get_args(
1311 DBUS_TYPE_BOOLEAN, &interactive,
1316 r = can_sleep(sleep_type);
1324 if (sleep_disk_type) {
1325 r = can_sleep_disk(sleep_disk_type);
1333 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1334 if (ul == (unsigned long) -1)
1337 r = have_multiple_sessions(m, (uid_t) ul);
1341 multiple_sessions = r > 0;
1342 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1344 if (multiple_sessions) {
1345 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1351 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1356 if (!multiple_sessions && !blocked) {
1357 r = verify_polkit(connection, message, action, interactive, NULL, error);
1362 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
1366 reply = dbus_message_new_method_return(message);
1374 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_action, handle_action, HandleAction);
1376 static const BusProperty bus_login_manager_properties[] = {
1377 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_path), true },
1378 { "Controllers", bus_property_append_strv, "as", offsetof(Manager, controllers), true },
1379 { "ResetControllers", bus_property_append_strv, "as", offsetof(Manager, reset_controllers), true },
1380 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1381 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1382 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1383 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1384 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1385 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1386 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
1387 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1388 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1389 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
1390 { "HandlePowerKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_power_key) },
1391 { "HandleSuspendKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_suspend_key) },
1392 { "HandleHibernateKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_hibernate_key)},
1393 { "HandleLidSwitch", bus_manager_append_handle_action, "s", offsetof(Manager, handle_lid_switch) },
1394 { "IdleAction", bus_manager_append_handle_action, "s", offsetof(Manager, idle_action) },
1395 { "IdleActionUSec", bus_property_append_usec, "t", offsetof(Manager, idle_action_usec) },
1396 { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
1397 { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
1401 static DBusHandlerResult manager_message_handler(
1402 DBusConnection *connection,
1403 DBusMessage *message,
1406 Manager *m = userdata;
1409 DBusMessage *reply = NULL;
1416 dbus_error_init(&error);
1418 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1424 if (!dbus_message_get_args(
1427 DBUS_TYPE_STRING, &name,
1429 return bus_send_error_reply(connection, message, &error, -EINVAL);
1431 session = hashmap_get(m->sessions, name);
1433 return bus_send_error_reply(connection, message, &error, -ENOENT);
1435 reply = dbus_message_new_method_return(message);
1439 p = session_bus_path(session);
1443 b = dbus_message_append_args(
1445 DBUS_TYPE_OBJECT_PATH, &p,
1452 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1458 if (!dbus_message_get_args(
1461 DBUS_TYPE_UINT32, &pid,
1463 return bus_send_error_reply(connection, message, &error, -EINVAL);
1465 r = manager_get_session_by_pid(m, pid, &session);
1467 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1469 reply = dbus_message_new_method_return(message);
1473 p = session_bus_path(session);
1477 b = dbus_message_append_args(
1479 DBUS_TYPE_OBJECT_PATH, &p,
1486 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1492 if (!dbus_message_get_args(
1495 DBUS_TYPE_UINT32, &uid,
1497 return bus_send_error_reply(connection, message, &error, -EINVAL);
1499 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1501 return bus_send_error_reply(connection, message, &error, -ENOENT);
1503 reply = dbus_message_new_method_return(message);
1507 p = user_bus_path(user);
1511 b = dbus_message_append_args(
1513 DBUS_TYPE_OBJECT_PATH, &p,
1520 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1526 if (!dbus_message_get_args(
1529 DBUS_TYPE_STRING, &name,
1531 return bus_send_error_reply(connection, message, &error, -EINVAL);
1533 seat = hashmap_get(m->seats, name);
1535 return bus_send_error_reply(connection, message, &error, -ENOENT);
1537 reply = dbus_message_new_method_return(message);
1541 p = seat_bus_path(seat);
1545 b = dbus_message_append_args(
1547 DBUS_TYPE_OBJECT_PATH, &p,
1554 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1558 DBusMessageIter iter, sub;
1559 const char *empty = "";
1561 reply = dbus_message_new_method_return(message);
1565 dbus_message_iter_init_append(reply, &iter);
1567 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1570 HASHMAP_FOREACH(session, m->sessions, i) {
1571 DBusMessageIter sub2;
1574 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1577 uid = session->user->uid;
1579 p = session_bus_path(session);
1583 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1584 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1585 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1586 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1587 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1594 if (!dbus_message_iter_close_container(&sub, &sub2))
1598 if (!dbus_message_iter_close_container(&iter, &sub))
1601 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1605 DBusMessageIter iter, sub;
1607 reply = dbus_message_new_method_return(message);
1611 dbus_message_iter_init_append(reply, &iter);
1613 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1616 HASHMAP_FOREACH(user, m->users, i) {
1617 DBusMessageIter sub2;
1620 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1625 p = user_bus_path(user);
1629 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1630 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1631 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1638 if (!dbus_message_iter_close_container(&sub, &sub2))
1642 if (!dbus_message_iter_close_container(&iter, &sub))
1645 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1649 DBusMessageIter iter, sub;
1651 reply = dbus_message_new_method_return(message);
1655 dbus_message_iter_init_append(reply, &iter);
1657 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1660 HASHMAP_FOREACH(seat, m->seats, i) {
1661 DBusMessageIter sub2;
1663 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1666 p = seat_bus_path(seat);
1670 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1671 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1678 if (!dbus_message_iter_close_container(&sub, &sub2))
1682 if (!dbus_message_iter_close_container(&iter, &sub))
1685 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1686 Inhibitor *inhibitor;
1688 DBusMessageIter iter, sub;
1690 reply = dbus_message_new_method_return(message);
1694 dbus_message_iter_init_append(reply, &iter);
1696 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1699 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1700 DBusMessageIter sub2;
1701 dbus_uint32_t uid, pid;
1702 const char *what, *who, *why, *mode;
1704 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1707 what = strempty(inhibit_what_to_string(inhibitor->what));
1708 who = strempty(inhibitor->who);
1709 why = strempty(inhibitor->why);
1710 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
1711 uid = (dbus_uint32_t) inhibitor->uid;
1712 pid = (dbus_uint32_t) inhibitor->pid;
1714 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1715 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1716 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1717 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
1718 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1719 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1722 if (!dbus_message_iter_close_container(&sub, &sub2))
1726 if (!dbus_message_iter_close_container(&iter, &sub))
1729 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1731 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1734 return bus_send_error_reply(connection, message, &error, r);
1737 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1739 r = bus_manager_create_session(m, message, &reply);
1741 /* Don't delay the work on OOM here, since it might be
1742 * triggered by a low RLIMIT_NOFILE here (since we
1743 * send a dupped fd to the client), and we'd rather
1744 * see this fail quickly then be retried later */
1747 return bus_send_error_reply(connection, message, NULL, r);
1749 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1753 if (!dbus_message_get_args(
1756 DBUS_TYPE_STRING, &name,
1758 return bus_send_error_reply(connection, message, &error, -EINVAL);
1760 session = hashmap_get(m->sessions, name);
1762 return bus_send_error_reply(connection, message, &error, -ENOENT);
1764 /* We use the FIFO to detect stray sessions where the
1765 process invoking PAM dies abnormally. We need to make
1766 sure that that process is not killed if at the clean
1767 end of the session it closes the FIFO. Hence, with
1768 this call explicitly turn off the FIFO logic, so that
1769 the PAM code can finish clean up on its own */
1770 session_remove_fifo(session);
1772 reply = dbus_message_new_method_return(message);
1776 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1780 if (!dbus_message_get_args(
1783 DBUS_TYPE_STRING, &name,
1785 return bus_send_error_reply(connection, message, &error, -EINVAL);
1787 session = hashmap_get(m->sessions, name);
1789 return bus_send_error_reply(connection, message, &error, -ENOENT);
1791 r = session_activate(session);
1793 return bus_send_error_reply(connection, message, NULL, r);
1795 reply = dbus_message_new_method_return(message);
1799 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1800 const char *session_name, *seat_name;
1804 /* Same as ActivateSession() but refuses to work if
1805 * the seat doesn't match */
1807 if (!dbus_message_get_args(
1810 DBUS_TYPE_STRING, &session_name,
1811 DBUS_TYPE_STRING, &seat_name,
1813 return bus_send_error_reply(connection, message, &error, -EINVAL);
1815 session = hashmap_get(m->sessions, session_name);
1817 return bus_send_error_reply(connection, message, &error, -ENOENT);
1819 seat = hashmap_get(m->seats, seat_name);
1821 return bus_send_error_reply(connection, message, &error, -ENOENT);
1823 if (session->seat != seat)
1824 return bus_send_error_reply(connection, message, &error, -EINVAL);
1826 r = session_activate(session);
1828 return bus_send_error_reply(connection, message, NULL, r);
1830 reply = dbus_message_new_method_return(message);
1834 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1835 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1839 if (!dbus_message_get_args(
1842 DBUS_TYPE_STRING, &name,
1844 return bus_send_error_reply(connection, message, &error, -EINVAL);
1846 session = hashmap_get(m->sessions, name);
1848 return bus_send_error_reply(connection, message, NULL, -ENOENT);
1850 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1853 reply = dbus_message_new_method_return(message);
1857 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions") ||
1858 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSessions")) {
1860 r = session_send_lock_all(m, streq(dbus_message_get_member(message), "LockSessions"));
1862 bus_send_error_reply(connection, message, NULL, r);
1864 reply = dbus_message_new_method_return(message);
1868 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1875 if (!dbus_message_get_args(
1878 DBUS_TYPE_STRING, &name,
1879 DBUS_TYPE_STRING, &swho,
1880 DBUS_TYPE_INT32, &signo,
1882 return bus_send_error_reply(connection, message, &error, -EINVAL);
1887 who = kill_who_from_string(swho);
1889 return bus_send_error_reply(connection, message, &error, -EINVAL);
1892 if (signo <= 0 || signo >= _NSIG)
1893 return bus_send_error_reply(connection, message, &error, -EINVAL);
1895 session = hashmap_get(m->sessions, name);
1897 return bus_send_error_reply(connection, message, &error, -ENOENT);
1899 r = session_kill(session, who, signo);
1901 return bus_send_error_reply(connection, message, NULL, r);
1903 reply = dbus_message_new_method_return(message);
1907 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1912 if (!dbus_message_get_args(
1915 DBUS_TYPE_UINT32, &uid,
1916 DBUS_TYPE_INT32, &signo,
1918 return bus_send_error_reply(connection, message, &error, -EINVAL);
1920 if (signo <= 0 || signo >= _NSIG)
1921 return bus_send_error_reply(connection, message, &error, -EINVAL);
1923 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1925 return bus_send_error_reply(connection, message, &error, -ENOENT);
1927 r = user_kill(user, signo);
1929 return bus_send_error_reply(connection, message, NULL, r);
1931 reply = dbus_message_new_method_return(message);
1935 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1939 if (!dbus_message_get_args(
1942 DBUS_TYPE_STRING, &name,
1944 return bus_send_error_reply(connection, message, &error, -EINVAL);
1946 session = hashmap_get(m->sessions, name);
1948 return bus_send_error_reply(connection, message, &error, -ENOENT);
1950 r = session_stop(session);
1952 return bus_send_error_reply(connection, message, NULL, r);
1954 reply = dbus_message_new_method_return(message);
1958 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1962 if (!dbus_message_get_args(
1965 DBUS_TYPE_UINT32, &uid,
1967 return bus_send_error_reply(connection, message, &error, -EINVAL);
1969 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1971 return bus_send_error_reply(connection, message, &error, -ENOENT);
1973 r = user_stop(user);
1975 return bus_send_error_reply(connection, message, NULL, r);
1977 reply = dbus_message_new_method_return(message);
1981 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1985 if (!dbus_message_get_args(
1988 DBUS_TYPE_STRING, &name,
1990 return bus_send_error_reply(connection, message, &error, -EINVAL);
1992 seat = hashmap_get(m->seats, name);
1994 return bus_send_error_reply(connection, message, &error, -ENOENT);
1996 r = seat_stop_sessions(seat);
1998 return bus_send_error_reply(connection, message, NULL, r);
2000 reply = dbus_message_new_method_return(message);
2004 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
2007 dbus_bool_t b, interactive;
2010 if (!dbus_message_get_args(
2013 DBUS_TYPE_UINT32, &uid,
2014 DBUS_TYPE_BOOLEAN, &b,
2015 DBUS_TYPE_BOOLEAN, &interactive,
2017 return bus_send_error_reply(connection, message, &error, -EINVAL);
2022 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
2024 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
2026 return bus_send_error_reply(connection, message, &error, r);
2028 mkdir_p_label("/var/lib/systemd", 0755);
2030 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
2032 return bus_send_error_reply(connection, message, &error, r);
2034 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
2045 return bus_send_error_reply(connection, message, &error, r);
2047 if (manager_add_user_by_uid(m, uid, &u) >= 0)
2056 if (r < 0 && errno != ENOENT)
2057 return bus_send_error_reply(connection, message, &error, -errno);
2059 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
2061 user_add_to_gc_queue(u);
2064 reply = dbus_message_new_method_return(message);
2068 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
2069 const char *sysfs, *seat;
2070 dbus_bool_t interactive;
2072 if (!dbus_message_get_args(
2075 DBUS_TYPE_STRING, &seat,
2076 DBUS_TYPE_STRING, &sysfs,
2077 DBUS_TYPE_BOOLEAN, &interactive,
2079 return bus_send_error_reply(connection, message, &error, -EINVAL);
2081 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
2082 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2084 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
2086 return bus_send_error_reply(connection, message, &error, r);
2088 r = attach_device(m, seat, sysfs);
2090 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2092 reply = dbus_message_new_method_return(message);
2097 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
2098 dbus_bool_t interactive;
2100 if (!dbus_message_get_args(
2103 DBUS_TYPE_BOOLEAN, &interactive,
2105 return bus_send_error_reply(connection, message, &error, -EINVAL);
2107 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
2109 return bus_send_error_reply(connection, message, &error, r);
2111 r = flush_devices(m);
2113 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2115 reply = dbus_message_new_method_return(message);
2119 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
2121 r = bus_manager_do_shutdown_or_sleep(
2122 m, connection, message,
2123 SPECIAL_POWEROFF_TARGET,
2125 "org.freedesktop.login1.power-off",
2126 "org.freedesktop.login1.power-off-multiple-sessions",
2127 "org.freedesktop.login1.power-off-ignore-inhibit",
2131 return bus_send_error_reply(connection, message, &error, r);
2132 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
2133 r = bus_manager_do_shutdown_or_sleep(
2134 m, connection, message,
2135 SPECIAL_REBOOT_TARGET,
2137 "org.freedesktop.login1.reboot",
2138 "org.freedesktop.login1.reboot-multiple-sessions",
2139 "org.freedesktop.login1.reboot-ignore-inhibit",
2143 return bus_send_error_reply(connection, message, &error, r);
2145 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2146 r = bus_manager_do_shutdown_or_sleep(
2147 m, connection, message,
2148 SPECIAL_SUSPEND_TARGET,
2150 "org.freedesktop.login1.suspend",
2151 "org.freedesktop.login1.suspend-multiple-sessions",
2152 "org.freedesktop.login1.suspend-ignore-inhibit",
2156 return bus_send_error_reply(connection, message, &error, r);
2157 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2158 r = bus_manager_do_shutdown_or_sleep(
2159 m, connection, message,
2160 SPECIAL_HIBERNATE_TARGET,
2162 "org.freedesktop.login1.hibernate",
2163 "org.freedesktop.login1.hibernate-multiple-sessions",
2164 "org.freedesktop.login1.hibernate-ignore-inhibit",
2168 return bus_send_error_reply(connection, message, &error, r);
2170 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "HybridSleep")) {
2171 r = bus_manager_do_shutdown_or_sleep(
2172 m, connection, message,
2173 SPECIAL_HYBRID_SLEEP_TARGET,
2175 "org.freedesktop.login1.hibernate",
2176 "org.freedesktop.login1.hibernate-multiple-sessions",
2177 "org.freedesktop.login1.hibernate-ignore-inhibit",
2181 return bus_send_error_reply(connection, message, &error, r);
2183 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2185 r = bus_manager_can_shutdown_or_sleep(
2186 m, connection, message,
2188 "org.freedesktop.login1.power-off",
2189 "org.freedesktop.login1.power-off-multiple-sessions",
2190 "org.freedesktop.login1.power-off-ignore-inhibit",
2194 return bus_send_error_reply(connection, message, &error, r);
2195 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2196 r = bus_manager_can_shutdown_or_sleep(
2197 m, connection, message,
2199 "org.freedesktop.login1.reboot",
2200 "org.freedesktop.login1.reboot-multiple-sessions",
2201 "org.freedesktop.login1.reboot-ignore-inhibit",
2205 return bus_send_error_reply(connection, message, &error, r);
2207 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2208 r = bus_manager_can_shutdown_or_sleep(
2209 m, connection, message,
2211 "org.freedesktop.login1.suspend",
2212 "org.freedesktop.login1.suspend-multiple-sessions",
2213 "org.freedesktop.login1.suspend-ignore-inhibit",
2217 return bus_send_error_reply(connection, message, &error, r);
2219 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2220 r = bus_manager_can_shutdown_or_sleep(
2221 m, connection, message,
2223 "org.freedesktop.login1.hibernate",
2224 "org.freedesktop.login1.hibernate-multiple-sessions",
2225 "org.freedesktop.login1.hibernate-ignore-inhibit",
2229 return bus_send_error_reply(connection, message, &error, r);
2231 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHybridSleep")) {
2232 r = bus_manager_can_shutdown_or_sleep(
2233 m, connection, message,
2235 "org.freedesktop.login1.hibernate",
2236 "org.freedesktop.login1.hibernate-multiple-sessions",
2237 "org.freedesktop.login1.hibernate-ignore-inhibit",
2241 return bus_send_error_reply(connection, message, &error, r);
2243 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2244 char *introspection = NULL;
2253 if (!(reply = dbus_message_new_method_return(message)))
2256 /* We roll our own introspection code here, instead of
2257 * relying on bus_default_message_handler() because we
2258 * need to generate our introspection string
2261 if (!(f = open_memstream(&introspection, &size)))
2264 fputs(INTROSPECTION_BEGIN, f);
2266 HASHMAP_FOREACH(seat, m->seats, i) {
2267 p = bus_path_escape(seat->id);
2270 fprintf(f, "<node name=\"seat/%s\"/>", p);
2275 HASHMAP_FOREACH(user, m->users, i)
2276 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2278 HASHMAP_FOREACH(session, m->sessions, i) {
2279 p = bus_path_escape(session->id);
2282 fprintf(f, "<node name=\"session/%s\"/>", p);
2287 fputs(INTROSPECTION_END, f);
2291 free(introspection);
2300 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2301 free(introspection);
2305 free(introspection);
2307 const BusBoundProperties bps[] = {
2308 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2311 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2315 if (!bus_maybe_send_reply(connection, message, reply))
2318 dbus_message_unref(reply);
2321 return DBUS_HANDLER_RESULT_HANDLED;
2325 dbus_message_unref(reply);
2327 dbus_error_free(&error);
2329 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2332 const DBusObjectPathVTable bus_manager_vtable = {
2333 .message_function = manager_message_handler
2336 DBusHandlerResult bus_message_filter(
2337 DBusConnection *connection,
2338 DBusMessage *message,
2341 Manager *m = userdata;
2348 dbus_error_init(&error);
2350 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
2353 if (!dbus_message_get_args(message, &error,
2354 DBUS_TYPE_STRING, &cgroup,
2356 log_error("Failed to parse Released message: %s", bus_error_message(&error));
2358 manager_cgroup_notify_empty(m, cgroup);
2360 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
2362 const char *path, *result, *unit;
2364 if (!dbus_message_get_args(message, &error,
2365 DBUS_TYPE_UINT32, &id,
2366 DBUS_TYPE_OBJECT_PATH, &path,
2367 DBUS_TYPE_STRING, &unit,
2368 DBUS_TYPE_STRING, &result,
2370 log_error("Failed to parse JobRemoved message: %s", bus_error_message(&error));
2371 else if (m->action_job && streq(m->action_job, path)) {
2372 log_info("Action is complete, result is '%s'.", result);
2373 free(m->action_job);
2374 m->action_job = NULL;
2376 if (m->send_resumed_after_action_job) {
2377 _cleanup_dbus_message_unref_ DBusMessage *s = NULL;
2379 s = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", "Resumed");
2381 dbus_connection_send(m->bus, s, NULL);
2386 dbus_error_free(&error);
2388 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2391 int manager_send_changed(Manager *manager, const char *properties) {
2397 m = bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties);
2401 if (!dbus_connection_send(manager->bus, m, NULL))
2408 dbus_message_unref(m);
2413 int manager_dispatch_delayed(Manager *manager) {
2414 const char *unit_name;
2421 if (!manager->delayed_unit)
2424 /* Continue delay? */
2426 manager->delayed_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC) &&
2427 manager_is_inhibited(manager, manager->delayed_what, INHIBIT_DELAY, NULL, false, false, 0);
2431 bus_manager_log_shutdown(manager, manager->delayed_what, manager->delayed_unit);
2433 /* Tell people about it */
2434 send_prepare_for(manager, manager->delayed_what, false);
2436 /* Reset delay data */
2437 unit_name = manager->delayed_unit;
2438 manager->delayed_unit = NULL;
2440 /* Actually do the shutdown */
2441 dbus_error_init(&error);
2442 r = send_start_unit(manager, unit_name, manager->delayed_what & INHIBIT_SLEEP, &error);
2444 log_warning("Failed to send delayed message: %s", bus_error_message_or_strerror(&error, -r));
2445 dbus_error_free(&error);