1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
28 #include "dbus-common.h"
31 #include "path-util.h"
34 #include "sleep-config.h"
35 #include "systemd/sd-id128.h"
36 #include "systemd/sd-messages.h"
37 #include "fileio-label.h"
40 #include "unit-name.h"
41 #include "bus-errors.h"
44 #define BUS_MANAGER_INTERFACE \
45 " <interface name=\"org.freedesktop.login1.Manager\">\n" \
46 " <method name=\"GetSession\">\n" \
47 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
48 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
50 " <method name=\"GetSessionByPID\">\n" \
51 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
52 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
54 " <method name=\"GetUser\">\n" \
55 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
56 " <arg name=\"user\" type=\"o\" direction=\"out\"/>\n" \
58 " <method name=\"GetUserByPID\">\n" \
59 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
60 " <arg name=\"user\" type=\"o\" direction=\"out\"/>\n" \
62 " <method name=\"GetSeat\">\n" \
63 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
64 " <arg name=\"seat\" type=\"o\" direction=\"out\"/>\n" \
66 " <method name=\"ListSessions\">\n" \
67 " <arg name=\"sessions\" type=\"a(susso)\" direction=\"out\"/>\n" \
69 " <method name=\"ListUsers\">\n" \
70 " <arg name=\"users\" type=\"a(uso)\" direction=\"out\"/>\n" \
72 " <method name=\"ListSeats\">\n" \
73 " <arg name=\"seats\" type=\"a(so)\" direction=\"out\"/>\n" \
75 " <method name=\"CreateSession\">\n" \
76 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
77 " <arg name=\"leader\" type=\"u\" direction=\"in\"/>\n" \
78 " <arg name=\"service\" type=\"s\" direction=\"in\"/>\n" \
79 " <arg name=\"type\" type=\"s\" direction=\"in\"/>\n" \
80 " <arg name=\"class\" type=\"s\" direction=\"in\"/>\n" \
81 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
82 " <arg name=\"vtnr\" type=\"u\" direction=\"in\"/>\n" \
83 " <arg name=\"tty\" type=\"s\" direction=\"in\"/>\n" \
84 " <arg name=\"display\" type=\"s\" direction=\"in\"/>\n" \
85 " <arg name=\"remote\" type=\"b\" direction=\"in\"/>\n" \
86 " <arg name=\"remote_user\" type=\"s\" direction=\"in\"/>\n" \
87 " <arg name=\"remote_host\" type=\"s\" direction=\"in\"/>\n" \
88 " <arg name=\"scope_properties\" type=\"a(sv)\" direction=\"in\"/>\n" \
89 " <arg name=\"id\" type=\"s\" direction=\"out\"/>\n" \
90 " <arg name=\"path\" type=\"o\" direction=\"out\"/>\n" \
91 " <arg name=\"runtime_path\" type=\"o\" direction=\"out\"/>\n" \
92 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
93 " <arg name=\"seat\" type=\"s\" direction=\"out\"/>\n" \
94 " <arg name=\"vtnr\" type=\"u\" direction=\"out\"/>\n" \
95 " <arg name=\"existing\" type=\"b\" direction=\"out\"/>\n" \
97 " <method name=\"ReleaseSession\">\n" \
98 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
100 " <method name=\"ActivateSession\">\n" \
101 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
103 " <method name=\"ActivateSessionOnSeat\">\n" \
104 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
105 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
107 " <method name=\"LockSession\">\n" \
108 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
110 " <method name=\"UnlockSession\">\n" \
111 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
113 " <method name=\"LockSessions\"/>\n" \
114 " <method name=\"UnlockSessions\"/>\n" \
115 " <method name=\"KillSession\">\n" \
116 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
117 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
118 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
120 " <method name=\"KillUser\">\n" \
121 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
122 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
124 " <method name=\"TerminateSession\">\n" \
125 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
127 " <method name=\"TerminateUser\">\n" \
128 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
130 " <method name=\"TerminateSeat\">\n" \
131 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
133 " <method name=\"SetUserLinger\">\n" \
134 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
135 " <arg name=\"b\" type=\"b\" direction=\"in\"/>\n" \
136 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
138 " <method name=\"AttachDevice\">\n" \
139 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
140 " <arg name=\"sysfs\" type=\"s\" direction=\"in\"/>\n" \
141 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
143 " <method name=\"FlushDevices\">\n" \
144 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
146 " <method name=\"PowerOff\">\n" \
147 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
149 " <method name=\"Reboot\">\n" \
150 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
152 " <method name=\"Suspend\">\n" \
153 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
155 " <method name=\"Hibernate\">\n" \
156 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
158 " <method name=\"HybridSleep\">\n" \
159 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
161 " <method name=\"CanPowerOff\">\n" \
162 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
164 " <method name=\"CanReboot\">\n" \
165 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
167 " <method name=\"CanSuspend\">\n" \
168 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
170 " <method name=\"CanHibernate\">\n" \
171 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
173 " <method name=\"CanHybridSleep\">\n" \
174 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
176 " <method name=\"Inhibit\">\n" \
177 " <arg name=\"what\" type=\"s\" direction=\"in\"/>\n" \
178 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
179 " <arg name=\"why\" type=\"s\" direction=\"in\"/>\n" \
180 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
181 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
183 " <method name=\"ListInhibitors\">\n" \
184 " <arg name=\"inhibitors\" type=\"a(ssssuu)\" direction=\"out\"/>\n" \
186 " <signal name=\"SessionNew\">\n" \
187 " <arg name=\"id\" type=\"s\"/>\n" \
188 " <arg name=\"path\" type=\"o\"/>\n" \
190 " <signal name=\"SessionRemoved\">\n" \
191 " <arg name=\"id\" type=\"s\"/>\n" \
192 " <arg name=\"path\" type=\"o\"/>\n" \
194 " <signal name=\"UserNew\">\n" \
195 " <arg name=\"uid\" type=\"u\"/>\n" \
196 " <arg name=\"path\" type=\"o\"/>\n" \
198 " <signal name=\"UserRemoved\">\n" \
199 " <arg name=\"uid\" type=\"u\"/>\n" \
200 " <arg name=\"path\" type=\"o\"/>\n" \
202 " <signal name=\"SeatNew\">\n" \
203 " <arg name=\"id\" type=\"s\"/>\n" \
204 " <arg name=\"path\" type=\"o\"/>\n" \
206 " <signal name=\"SeatRemoved\">\n" \
207 " <arg name=\"id\" type=\"s\"/>\n" \
208 " <arg name=\"path\" type=\"o\"/>\n" \
210 " <signal name=\"PrepareForShutdown\">\n" \
211 " <arg name=\"active\" type=\"b\"/>\n" \
213 " <signal name=\"PrepareForSleep\">\n" \
214 " <arg name=\"active\" type=\"b\"/>\n" \
216 " <property name=\"NAutoVTs\" type=\"u\" access=\"read\"/>\n" \
217 " <property name=\"KillOnlyUsers\" type=\"as\" access=\"read\"/>\n" \
218 " <property name=\"KillExcludeUsers\" type=\"as\" access=\"read\"/>\n" \
219 " <property name=\"KillUserProcesses\" type=\"b\" access=\"read\"/>\n" \
220 " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
221 " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
222 " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
223 " <property name=\"BlockInhibited\" type=\"s\" access=\"read\"/>\n" \
224 " <property name=\"DelayInhibited\" type=\"s\" access=\"read\"/>\n" \
225 " <property name=\"InhibitDelayMaxUSec\" type=\"t\" access=\"read\"/>\n" \
226 " <property name=\"HandlePowerKey\" type=\"s\" access=\"read\"/>\n" \
227 " <property name=\"HandleSuspendKey\" type=\"s\" access=\"read\"/>\n" \
228 " <property name=\"HandleHibernateKey\" type=\"s\" access=\"read\"/>\n" \
229 " <property name=\"HandleLidSwitch\" type=\"s\" access=\"read\"/>\n" \
230 " <property name=\"IdleAction\" type=\"s\" access=\"read\"/>\n" \
231 " <property name=\"IdleActionUSec\" type=\"t\" access=\"read\"/>\n" \
232 " <property name=\"PreparingForShutdown\" type=\"b\" access=\"read\"/>\n" \
233 " <property name=\"PreparingForSleep\" type=\"b\" access=\"read\"/>\n" \
236 #define INTROSPECTION_BEGIN \
237 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
239 BUS_MANAGER_INTERFACE \
240 BUS_PROPERTIES_INTERFACE \
242 BUS_INTROSPECTABLE_INTERFACE
244 #define INTROSPECTION_END \
247 #define INTERFACES_LIST \
248 BUS_GENERIC_INTERFACES_LIST \
249 "org.freedesktop.login1.Manager\0"
251 static int bus_manager_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
259 b = manager_get_idle_hint(m, NULL) > 0;
260 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
266 static int bus_manager_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
275 manager_get_idle_hint(m, &t);
276 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
278 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
284 static int bus_manager_append_inhibited(DBusMessageIter *i, const char *property, void *data) {
289 w = manager_inhibit_what(m, streq(property, "BlockInhibited") ? INHIBIT_BLOCK : INHIBIT_DELAY);
290 p = inhibit_what_to_string(w);
292 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &p))
298 static int bus_manager_append_preparing(DBusMessageIter *i, const char *property, void *data) {
305 if (streq(property, "PreparingForShutdown"))
306 b = !!(m->action_what & INHIBIT_SHUTDOWN);
308 b = !!(m->action_what & INHIBIT_SLEEP);
310 dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b);
314 static int bus_manager_create_session(Manager *m, DBusMessage *message) {
316 const char *type, *class, *cseat, *tty, *display, *remote_user, *remote_host, *service;
317 uint32_t uid, leader, audit_id = 0;
318 _cleanup_free_ char *id = NULL;
319 Session *session = NULL;
322 DBusMessageIter iter;
333 if (!dbus_message_iter_init(message, &iter) ||
334 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
337 dbus_message_iter_get_basic(&iter, &uid);
339 if (!dbus_message_iter_next(&iter) ||
340 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
343 dbus_message_iter_get_basic(&iter, &leader);
345 if (!dbus_message_iter_next(&iter) ||
346 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
349 dbus_message_iter_get_basic(&iter, &service);
351 if (!dbus_message_iter_next(&iter) ||
352 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
355 dbus_message_iter_get_basic(&iter, &type);
357 t = _SESSION_TYPE_INVALID;
359 t = session_type_from_string(type);
364 if (!dbus_message_iter_next(&iter) ||
365 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
368 dbus_message_iter_get_basic(&iter, &class);
370 c = _SESSION_CLASS_INVALID;
372 c = session_class_from_string(class);
377 if (!dbus_message_iter_next(&iter) ||
378 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
381 dbus_message_iter_get_basic(&iter, &cseat);
386 seat = hashmap_get(m->seats, cseat);
391 if (!dbus_message_iter_next(&iter) ||
392 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
395 dbus_message_iter_get_basic(&iter, &vtnr);
397 if (!dbus_message_iter_next(&iter) ||
398 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
401 dbus_message_iter_get_basic(&iter, &tty);
403 if (tty_is_vc(tty)) {
408 else if (seat != m->vtconsole)
411 v = vtnr_from_tty(tty);
414 return v < 0 ? v : -EINVAL;
418 else if (vtnr != (uint32_t) v)
420 } else if (tty_is_console(tty)) {
424 else if (seat != m->vtconsole)
432 if (seat_can_multi_session(seat)) {
441 if (!dbus_message_iter_next(&iter) ||
442 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
445 dbus_message_iter_get_basic(&iter, &display);
447 if (!dbus_message_iter_next(&iter) ||
448 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
451 if (t == _SESSION_TYPE_INVALID) {
452 if (!isempty(display))
454 else if (!isempty(tty))
457 t = SESSION_UNSPECIFIED;
460 if (c == _SESSION_CLASS_INVALID) {
461 if (!isempty(display) || !isempty(tty))
464 c = SESSION_BACKGROUND;
467 dbus_message_iter_get_basic(&iter, &remote);
469 if (!dbus_message_iter_next(&iter) ||
470 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
473 dbus_message_iter_get_basic(&iter, &remote_user);
475 if (!dbus_message_iter_next(&iter) ||
476 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
479 dbus_message_iter_get_basic(&iter, &remote_host);
482 leader = bus_get_unix_process_id(m->bus, dbus_message_get_sender(message), NULL);
487 r = manager_get_session_by_pid(m, leader, &session);
489 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
490 _cleanup_free_ char *path = NULL;
491 _cleanup_close_ int fifo_fd = -1;
494 /* Session already exists, client is probably
495 * something like "su" which changes uid but is still
496 * the same session */
498 fifo_fd = session_create_fifo(session);
504 path = session_bus_path(session);
510 reply = dbus_message_new_method_return(message);
516 cseat = session->seat ? session->seat->id : "";
517 vtnr = session->vtnr;
520 b = dbus_message_append_args(
522 DBUS_TYPE_STRING, &session->id,
523 DBUS_TYPE_OBJECT_PATH, &path,
524 DBUS_TYPE_STRING, &session->user->runtime_path,
525 DBUS_TYPE_UNIX_FD, &fifo_fd,
526 DBUS_TYPE_STRING, &cseat,
527 DBUS_TYPE_UINT32, &vtnr,
528 DBUS_TYPE_BOOLEAN, &exists,
535 if (!dbus_connection_send(m->bus, reply, NULL)) {
543 audit_session_from_pid(leader, &audit_id);
545 /* Keep our session IDs and the audit session IDs in sync */
547 if (asprintf(&id, "%lu", (unsigned long) audit_id) < 0) {
552 /* Wut? There's already a session by this name and we
553 * didn't find it above? Weird, then let's not trust
554 * the audit data and let's better register a new
556 if (hashmap_get(m->sessions, id)) {
569 if (asprintf(&id, "c%lu", ++m->session_counter) < 0) {
574 } while (hashmap_get(m->sessions, id));
577 r = manager_add_user_by_uid(m, uid, &user);
581 r = manager_add_session(m, id, &session);
585 session_set_user(session, user);
587 session->leader = leader;
588 session->audit_id = audit_id;
591 session->remote = remote;
592 session->vtnr = vtnr;
595 session->tty = strdup(tty);
602 if (!isempty(display)) {
603 session->display = strdup(display);
604 if (!session->display) {
610 if (!isempty(remote_user)) {
611 session->remote_user = strdup(remote_user);
612 if (!session->remote_user) {
618 if (!isempty(remote_host)) {
619 session->remote_host = strdup(remote_host);
620 if (!session->remote_host) {
626 if (!isempty(service)) {
627 session->service = strdup(service);
628 if (!session->service) {
635 r = seat_attach_session(seat, session);
640 r = session_start(session);
644 session->create_message = dbus_message_ref(message);
650 session_add_to_gc_queue(session);
653 user_add_to_gc_queue(user);
658 static int bus_manager_inhibit(
660 DBusConnection *connection,
661 DBusMessage *message,
663 DBusMessage **_reply) {
667 const char *who, *why, *what, *mode;
673 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
681 if (!dbus_message_get_args(
684 DBUS_TYPE_STRING, &what,
685 DBUS_TYPE_STRING, &who,
686 DBUS_TYPE_STRING, &why,
687 DBUS_TYPE_STRING, &mode,
688 DBUS_TYPE_INVALID)) {
693 w = inhibit_what_from_string(what);
699 mm = inhibit_mode_from_string(mode);
705 /* Delay is only supported for shutdown/sleep */
706 if (mm == INHIBIT_DELAY && (w & ~(INHIBIT_SHUTDOWN|INHIBIT_SLEEP))) {
711 /* Don't allow taking delay locks while we are already
712 * executing the operation. We shouldn't create the impression
713 * that the lock was successful if the machine is about to go
714 * down/suspend any moment. */
715 if (m->action_what & w) {
720 r = verify_polkit(connection, message,
721 w == INHIBIT_SHUTDOWN ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
722 w == INHIBIT_SLEEP ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep" : "org.freedesktop.login1.inhibit-delay-sleep") :
723 w == INHIBIT_IDLE ? "org.freedesktop.login1.inhibit-block-idle" :
724 w == INHIBIT_HANDLE_POWER_KEY ? "org.freedesktop.login1.inhibit-handle-power-key" :
725 w == INHIBIT_HANDLE_SUSPEND_KEY ? "org.freedesktop.login1.inhibit-handle-suspend-key" :
726 w == INHIBIT_HANDLE_HIBERNATE_KEY ? "org.freedesktop.login1.inhibit-handle-hibernate-key" :
727 "org.freedesktop.login1.inhibit-handle-lid-switch",
732 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
733 if (ul == (unsigned long) -1) {
738 pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
748 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
752 } while (hashmap_get(m->inhibitors, id));
754 r = manager_add_inhibitor(m, id, &i);
764 i->why = strdup(why);
765 i->who = strdup(who);
767 if (!i->why || !i->who) {
772 fifo_fd = inhibitor_create_fifo(i);
778 reply = dbus_message_new_method_return(message);
784 if (!dbus_message_append_args(
786 DBUS_TYPE_UNIX_FD, &fifo_fd,
787 DBUS_TYPE_INVALID)) {
792 close_nointr_nofail(fifo_fd);
805 close_nointr_nofail(fifo_fd);
810 static int trigger_device(Manager *m, struct udev_device *d) {
811 struct udev_enumerate *e;
812 struct udev_list_entry *first, *item;
817 e = udev_enumerate_new(m->udev);
824 if (udev_enumerate_add_match_parent(e, d) < 0) {
830 if (udev_enumerate_scan_devices(e) < 0) {
835 first = udev_enumerate_get_list_entry(e);
836 udev_list_entry_foreach(item, first) {
840 p = udev_list_entry_get_name(item);
842 t = strappend(p, "/uevent");
848 write_string_file(t, "change");
856 udev_enumerate_unref(e);
861 static int attach_device(Manager *m, const char *seat, const char *sysfs) {
862 struct udev_device *d;
863 _cleanup_free_ char *rule = NULL, *file = NULL;
864 const char *id_for_seat;
871 d = udev_device_new_from_syspath(m->udev, sysfs);
875 if (!udev_device_has_tag(d, "seat")) {
880 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
886 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
891 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
896 mkdir_p_label("/etc/udev/rules.d", 0755);
898 r = write_string_file_atomic_label(file, rule);
902 r = trigger_device(m, d);
906 udev_device_unref(d);
911 static int flush_devices(Manager *m) {
912 _cleanup_closedir_ DIR *d;
916 d = opendir("/etc/udev/rules.d");
919 log_warning("Failed to open /etc/udev/rules.d: %m");
923 while ((de = readdir(d))) {
925 if (!dirent_is_file(de))
928 if (!startswith(de->d_name, "72-seat-"))
931 if (!endswith(de->d_name, ".rules"))
934 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
935 log_warning("Failed to unlink %s: %m", de->d_name);
939 return trigger_device(m, NULL);
942 static int have_multiple_sessions(
951 /* Check for other users' sessions. Greeter sessions do not
952 * count, and non-login sessions do not count either. */
953 HASHMAP_FOREACH(session, m->sessions, i)
954 if (session->class == SESSION_USER &&
955 session->user->uid != uid)
961 static int bus_manager_log_shutdown(
964 const char *unit_name) {
971 if (w != INHIBIT_SHUTDOWN)
974 if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
975 p = "MESSAGE=System is powering down.";
976 q = "SHUTDOWN=power-off";
977 } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
978 p = "MESSAGE=System is halting.";
980 } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
981 p = "MESSAGE=System is rebooting.";
982 q = "SHUTDOWN=reboot";
983 } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
984 p = "MESSAGE=System is rebooting with kexec.";
985 q = "SHUTDOWN=kexec";
987 p = "MESSAGE=System is shutting down.";
991 return log_struct(LOG_NOTICE, MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
996 static int execute_shutdown_or_sleep(
999 const char *unit_name,
1002 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1003 const char *mode = "replace-irreversibly", *p;
1009 assert(w < _INHIBIT_WHAT_MAX);
1012 bus_manager_log_shutdown(m, w, unit_name);
1014 r = bus_method_call_with_reply(
1016 "org.freedesktop.systemd1",
1017 "/org/freedesktop/systemd1",
1018 "org.freedesktop.systemd1.Manager",
1022 DBUS_TYPE_STRING, &unit_name,
1023 DBUS_TYPE_STRING, &mode,
1028 if (!dbus_message_get_args(
1031 DBUS_TYPE_OBJECT_PATH, &p,
1039 m->action_unit = unit_name;
1040 free(m->action_job);
1047 static int delay_shutdown_or_sleep(
1050 const char *unit_name) {
1054 assert(w < _INHIBIT_WHAT_MAX);
1057 m->action_timestamp = now(CLOCK_MONOTONIC);
1058 m->action_unit = unit_name;
1064 static int bus_manager_can_shutdown_or_sleep(
1066 DBusConnection *connection,
1067 DBusMessage *message,
1070 const char *action_multiple_sessions,
1071 const char *action_ignore_inhibit,
1072 const char *sleep_verb,
1074 DBusMessage **_reply) {
1076 bool multiple_sessions, challenge, blocked, b;
1077 const char *result = NULL;
1078 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1086 assert(w <= _INHIBIT_WHAT_MAX);
1088 assert(action_multiple_sessions);
1089 assert(action_ignore_inhibit);
1094 r = can_sleep(sleep_verb);
1103 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1104 if (ul == (unsigned long) -1)
1107 r = have_multiple_sessions(m, (uid_t) ul);
1111 multiple_sessions = r > 0;
1112 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1114 if (multiple_sessions) {
1115 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1122 result = "challenge";
1128 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1132 if (r > 0 && !result)
1134 else if (challenge && (!result || streq(result, "yes")))
1135 result = "challenge";
1140 if (!multiple_sessions && !blocked) {
1141 /* If neither inhibit nor multiple sessions
1142 * apply then just check the normal policy */
1144 r = verify_polkit(connection, message, action, false, &challenge, error);
1151 result = "challenge";
1157 reply = dbus_message_new_method_return(message);
1161 b = dbus_message_append_args(
1163 DBUS_TYPE_STRING, &result,
1173 static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
1174 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
1175 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
1176 [INHIBIT_SLEEP] = "PrepareForSleep"
1179 dbus_bool_t active = _active;
1180 _cleanup_dbus_message_unref_ DBusMessage *message = NULL;
1184 assert(w < _INHIBIT_WHAT_MAX);
1185 assert(signal_name[w]);
1187 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1191 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1192 !dbus_connection_send(m->bus, message, NULL))
1198 int bus_manager_shutdown_or_sleep_now_or_later(
1200 const char *unit_name,
1210 assert(w <= _INHIBIT_WHAT_MAX);
1211 assert(!m->action_job);
1213 /* Tell everybody to prepare for shutdown/sleep */
1214 send_prepare_for(m, w, true);
1217 m->inhibit_delay_max > 0 &&
1218 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0);
1221 /* Shutdown is delayed, keep in mind what we
1222 * want to do, and start a timeout */
1223 r = delay_shutdown_or_sleep(m, w, unit_name);
1225 /* Shutdown is not delayed, execute it
1227 r = execute_shutdown_or_sleep(m, w, unit_name, error);
1232 static int bus_manager_do_shutdown_or_sleep(
1234 DBusConnection *connection,
1235 DBusMessage *message,
1236 const char *unit_name,
1239 const char *action_multiple_sessions,
1240 const char *action_ignore_inhibit,
1241 const char *sleep_verb,
1243 DBusMessage **_reply) {
1245 dbus_bool_t interactive;
1246 bool multiple_sessions, blocked;
1247 DBusMessage *reply = NULL;
1256 assert(w <= _INHIBIT_WHAT_MAX);
1258 assert(action_multiple_sessions);
1259 assert(action_ignore_inhibit);
1263 /* Don't allow multiple jobs being executed at the same time */
1267 if (!dbus_message_get_args(
1270 DBUS_TYPE_BOOLEAN, &interactive,
1275 r = can_sleep(sleep_verb);
1283 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1284 if (ul == (unsigned long) -1)
1287 r = have_multiple_sessions(m, (uid_t) ul);
1291 multiple_sessions = r > 0;
1292 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1294 if (multiple_sessions) {
1295 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1301 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1306 if (!multiple_sessions && !blocked) {
1307 r = verify_polkit(connection, message, action, interactive, NULL, error);
1312 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
1316 reply = dbus_message_new_method_return(message);
1324 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_action, handle_action, HandleAction);
1326 static const BusProperty bus_login_manager_properties[] = {
1327 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1328 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1329 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1330 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1331 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1332 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1333 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
1334 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1335 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1336 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
1337 { "HandlePowerKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_power_key) },
1338 { "HandleSuspendKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_suspend_key) },
1339 { "HandleHibernateKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_hibernate_key)},
1340 { "HandleLidSwitch", bus_manager_append_handle_action, "s", offsetof(Manager, handle_lid_switch) },
1341 { "IdleAction", bus_manager_append_handle_action, "s", offsetof(Manager, idle_action) },
1342 { "IdleActionUSec", bus_property_append_usec, "t", offsetof(Manager, idle_action_usec) },
1343 { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
1344 { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
1348 static DBusHandlerResult manager_message_handler(
1349 DBusConnection *connection,
1350 DBusMessage *message,
1353 Manager *m = userdata;
1356 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1363 dbus_error_init(&error);
1365 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1371 if (!dbus_message_get_args(
1374 DBUS_TYPE_STRING, &name,
1376 return bus_send_error_reply(connection, message, &error, -EINVAL);
1378 session = hashmap_get(m->sessions, name);
1380 return bus_send_error_reply(connection, message, &error, -ENOENT);
1382 reply = dbus_message_new_method_return(message);
1386 p = session_bus_path(session);
1390 b = dbus_message_append_args(
1392 DBUS_TYPE_OBJECT_PATH, &p,
1399 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1405 if (!dbus_message_get_args(
1408 DBUS_TYPE_UINT32, &pid,
1410 return bus_send_error_reply(connection, message, &error, -EINVAL);
1412 r = manager_get_session_by_pid(m, pid, &session);
1414 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1416 reply = dbus_message_new_method_return(message);
1420 p = session_bus_path(session);
1424 b = dbus_message_append_args(
1426 DBUS_TYPE_OBJECT_PATH, &p,
1433 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1439 if (!dbus_message_get_args(
1442 DBUS_TYPE_UINT32, &uid,
1444 return bus_send_error_reply(connection, message, &error, -EINVAL);
1446 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1448 return bus_send_error_reply(connection, message, &error, -ENOENT);
1450 reply = dbus_message_new_method_return(message);
1454 p = user_bus_path(user);
1458 b = dbus_message_append_args(
1460 DBUS_TYPE_OBJECT_PATH, &p,
1467 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUserByPID")) {
1473 if (!dbus_message_get_args(
1476 DBUS_TYPE_UINT32, &pid,
1478 return bus_send_error_reply(connection, message, &error, -EINVAL);
1480 r = manager_get_user_by_pid(m, pid, &user);
1482 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1484 reply = dbus_message_new_method_return(message);
1488 p = user_bus_path(user);
1492 b = dbus_message_append_args(
1494 DBUS_TYPE_OBJECT_PATH, &p,
1501 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1507 if (!dbus_message_get_args(
1510 DBUS_TYPE_STRING, &name,
1512 return bus_send_error_reply(connection, message, &error, -EINVAL);
1514 seat = hashmap_get(m->seats, name);
1516 return bus_send_error_reply(connection, message, &error, -ENOENT);
1518 reply = dbus_message_new_method_return(message);
1522 p = seat_bus_path(seat);
1526 b = dbus_message_append_args(
1528 DBUS_TYPE_OBJECT_PATH, &p,
1535 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1539 DBusMessageIter iter, sub;
1540 const char *empty = "";
1542 reply = dbus_message_new_method_return(message);
1546 dbus_message_iter_init_append(reply, &iter);
1548 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1551 HASHMAP_FOREACH(session, m->sessions, i) {
1552 DBusMessageIter sub2;
1555 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1558 uid = session->user->uid;
1560 p = session_bus_path(session);
1564 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1565 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1566 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1567 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1568 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1575 if (!dbus_message_iter_close_container(&sub, &sub2))
1579 if (!dbus_message_iter_close_container(&iter, &sub))
1582 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1585 DBusMessageIter iter, sub;
1587 reply = dbus_message_new_method_return(message);
1591 dbus_message_iter_init_append(reply, &iter);
1593 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1596 HASHMAP_FOREACH(user, m->users, i) {
1597 _cleanup_free_ char *p = NULL;
1598 DBusMessageIter sub2;
1601 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1606 p = user_bus_path(user);
1610 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1611 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1612 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1617 if (!dbus_message_iter_close_container(&sub, &sub2))
1621 if (!dbus_message_iter_close_container(&iter, &sub))
1624 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1627 DBusMessageIter iter, sub;
1629 reply = dbus_message_new_method_return(message);
1633 dbus_message_iter_init_append(reply, &iter);
1635 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1638 HASHMAP_FOREACH(seat, m->seats, i) {
1639 _cleanup_free_ char *p = NULL;
1640 DBusMessageIter sub2;
1642 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1645 p = seat_bus_path(seat);
1649 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1650 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1655 if (!dbus_message_iter_close_container(&sub, &sub2))
1659 if (!dbus_message_iter_close_container(&iter, &sub))
1662 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1663 Inhibitor *inhibitor;
1665 DBusMessageIter iter, sub;
1667 reply = dbus_message_new_method_return(message);
1671 dbus_message_iter_init_append(reply, &iter);
1673 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1676 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1677 DBusMessageIter sub2;
1678 dbus_uint32_t uid, pid;
1679 const char *what, *who, *why, *mode;
1681 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1684 what = strempty(inhibit_what_to_string(inhibitor->what));
1685 who = strempty(inhibitor->who);
1686 why = strempty(inhibitor->why);
1687 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
1688 uid = (dbus_uint32_t) inhibitor->uid;
1689 pid = (dbus_uint32_t) inhibitor->pid;
1691 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1692 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1693 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1694 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
1695 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1696 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1699 if (!dbus_message_iter_close_container(&sub, &sub2))
1703 if (!dbus_message_iter_close_container(&iter, &sub))
1707 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1709 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1712 return bus_send_error_reply(connection, message, &error, r);
1715 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1717 r = bus_manager_create_session(m, message);
1719 /* Don't delay the work on OOM here, since it might be
1720 * triggered by a low RLIMIT_NOFILE here (since we
1721 * send a dupped fd to the client), and we'd rather
1722 * see this fail quickly then be retried later */
1725 return bus_send_error_reply(connection, message, NULL, r);
1727 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1731 if (!dbus_message_get_args(
1734 DBUS_TYPE_STRING, &name,
1736 return bus_send_error_reply(connection, message, &error, -EINVAL);
1738 session = hashmap_get(m->sessions, name);
1740 return bus_send_error_reply(connection, message, &error, -ENOENT);
1742 /* We use the FIFO to detect stray sessions where the
1743 process invoking PAM dies abnormally. We need to make
1744 sure that that process is not killed if at the clean
1745 end of the session it closes the FIFO. Hence, with
1746 this call explicitly turn off the FIFO logic, so that
1747 the PAM code can finish clean up on its own */
1748 session_remove_fifo(session);
1750 reply = dbus_message_new_method_return(message);
1754 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1758 if (!dbus_message_get_args(
1761 DBUS_TYPE_STRING, &name,
1763 return bus_send_error_reply(connection, message, &error, -EINVAL);
1765 session = hashmap_get(m->sessions, name);
1767 return bus_send_error_reply(connection, message, &error, -ENOENT);
1769 r = session_activate(session);
1771 return bus_send_error_reply(connection, message, NULL, r);
1773 reply = dbus_message_new_method_return(message);
1777 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1778 const char *session_name, *seat_name;
1782 /* Same as ActivateSession() but refuses to work if
1783 * the seat doesn't match */
1785 if (!dbus_message_get_args(
1788 DBUS_TYPE_STRING, &session_name,
1789 DBUS_TYPE_STRING, &seat_name,
1791 return bus_send_error_reply(connection, message, &error, -EINVAL);
1793 session = hashmap_get(m->sessions, session_name);
1795 return bus_send_error_reply(connection, message, &error, -ENOENT);
1797 seat = hashmap_get(m->seats, seat_name);
1799 return bus_send_error_reply(connection, message, &error, -ENOENT);
1801 if (session->seat != seat)
1802 return bus_send_error_reply(connection, message, &error, -EINVAL);
1804 r = session_activate(session);
1806 return bus_send_error_reply(connection, message, NULL, r);
1808 reply = dbus_message_new_method_return(message);
1812 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1813 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1817 if (!dbus_message_get_args(
1820 DBUS_TYPE_STRING, &name,
1822 return bus_send_error_reply(connection, message, &error, -EINVAL);
1824 session = hashmap_get(m->sessions, name);
1826 return bus_send_error_reply(connection, message, NULL, -ENOENT);
1828 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1831 reply = dbus_message_new_method_return(message);
1835 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions") ||
1836 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSessions")) {
1838 r = session_send_lock_all(m, streq(dbus_message_get_member(message), "LockSessions"));
1840 bus_send_error_reply(connection, message, NULL, r);
1842 reply = dbus_message_new_method_return(message);
1846 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1853 if (!dbus_message_get_args(
1856 DBUS_TYPE_STRING, &name,
1857 DBUS_TYPE_STRING, &swho,
1858 DBUS_TYPE_INT32, &signo,
1860 return bus_send_error_reply(connection, message, &error, -EINVAL);
1865 who = kill_who_from_string(swho);
1867 return bus_send_error_reply(connection, message, &error, -EINVAL);
1870 if (signo <= 0 || signo >= _NSIG)
1871 return bus_send_error_reply(connection, message, &error, -EINVAL);
1873 session = hashmap_get(m->sessions, name);
1875 return bus_send_error_reply(connection, message, &error, -ENOENT);
1877 r = session_kill(session, who, signo);
1879 return bus_send_error_reply(connection, message, NULL, r);
1881 reply = dbus_message_new_method_return(message);
1885 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1890 if (!dbus_message_get_args(
1893 DBUS_TYPE_UINT32, &uid,
1894 DBUS_TYPE_INT32, &signo,
1896 return bus_send_error_reply(connection, message, &error, -EINVAL);
1898 if (signo <= 0 || signo >= _NSIG)
1899 return bus_send_error_reply(connection, message, &error, -EINVAL);
1901 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1903 return bus_send_error_reply(connection, message, &error, -ENOENT);
1905 r = user_kill(user, signo);
1907 return bus_send_error_reply(connection, message, NULL, r);
1909 reply = dbus_message_new_method_return(message);
1913 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1917 if (!dbus_message_get_args(
1920 DBUS_TYPE_STRING, &name,
1922 return bus_send_error_reply(connection, message, &error, -EINVAL);
1924 session = hashmap_get(m->sessions, name);
1926 return bus_send_error_reply(connection, message, &error, -ENOENT);
1928 r = session_stop(session);
1930 return bus_send_error_reply(connection, message, NULL, r);
1932 reply = dbus_message_new_method_return(message);
1936 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1940 if (!dbus_message_get_args(
1943 DBUS_TYPE_UINT32, &uid,
1945 return bus_send_error_reply(connection, message, &error, -EINVAL);
1947 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1949 return bus_send_error_reply(connection, message, &error, -ENOENT);
1951 r = user_stop(user);
1953 return bus_send_error_reply(connection, message, NULL, r);
1955 reply = dbus_message_new_method_return(message);
1959 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1963 if (!dbus_message_get_args(
1966 DBUS_TYPE_STRING, &name,
1968 return bus_send_error_reply(connection, message, &error, -EINVAL);
1970 seat = hashmap_get(m->seats, name);
1972 return bus_send_error_reply(connection, message, &error, -ENOENT);
1974 r = seat_stop_sessions(seat);
1976 return bus_send_error_reply(connection, message, NULL, r);
1978 reply = dbus_message_new_method_return(message);
1982 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
1985 dbus_bool_t b, interactive;
1988 if (!dbus_message_get_args(
1991 DBUS_TYPE_UINT32, &uid,
1992 DBUS_TYPE_BOOLEAN, &b,
1993 DBUS_TYPE_BOOLEAN, &interactive,
1995 return bus_send_error_reply(connection, message, &error, -EINVAL);
2000 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
2002 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
2004 return bus_send_error_reply(connection, message, &error, r);
2006 mkdir_p_label("/var/lib/systemd", 0755);
2008 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
2010 return bus_send_error_reply(connection, message, &error, r);
2012 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
2023 return bus_send_error_reply(connection, message, &error, r);
2025 if (manager_add_user_by_uid(m, uid, &u) >= 0)
2034 if (r < 0 && errno != ENOENT)
2035 return bus_send_error_reply(connection, message, &error, -errno);
2037 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
2039 user_add_to_gc_queue(u);
2042 reply = dbus_message_new_method_return(message);
2046 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
2047 const char *sysfs, *seat;
2048 dbus_bool_t interactive;
2050 if (!dbus_message_get_args(
2053 DBUS_TYPE_STRING, &seat,
2054 DBUS_TYPE_STRING, &sysfs,
2055 DBUS_TYPE_BOOLEAN, &interactive,
2057 return bus_send_error_reply(connection, message, &error, -EINVAL);
2059 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
2060 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2062 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
2064 return bus_send_error_reply(connection, message, &error, r);
2066 r = attach_device(m, seat, sysfs);
2068 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2070 reply = dbus_message_new_method_return(message);
2075 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
2076 dbus_bool_t interactive;
2078 if (!dbus_message_get_args(
2081 DBUS_TYPE_BOOLEAN, &interactive,
2083 return bus_send_error_reply(connection, message, &error, -EINVAL);
2085 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
2087 return bus_send_error_reply(connection, message, &error, r);
2089 r = flush_devices(m);
2091 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2093 reply = dbus_message_new_method_return(message);
2097 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
2099 r = bus_manager_do_shutdown_or_sleep(
2100 m, connection, message,
2101 SPECIAL_POWEROFF_TARGET,
2103 "org.freedesktop.login1.power-off",
2104 "org.freedesktop.login1.power-off-multiple-sessions",
2105 "org.freedesktop.login1.power-off-ignore-inhibit",
2109 return bus_send_error_reply(connection, message, &error, r);
2110 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
2111 r = bus_manager_do_shutdown_or_sleep(
2112 m, connection, message,
2113 SPECIAL_REBOOT_TARGET,
2115 "org.freedesktop.login1.reboot",
2116 "org.freedesktop.login1.reboot-multiple-sessions",
2117 "org.freedesktop.login1.reboot-ignore-inhibit",
2121 return bus_send_error_reply(connection, message, &error, r);
2123 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2124 r = bus_manager_do_shutdown_or_sleep(
2125 m, connection, message,
2126 SPECIAL_SUSPEND_TARGET,
2128 "org.freedesktop.login1.suspend",
2129 "org.freedesktop.login1.suspend-multiple-sessions",
2130 "org.freedesktop.login1.suspend-ignore-inhibit",
2134 return bus_send_error_reply(connection, message, &error, r);
2135 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2136 r = bus_manager_do_shutdown_or_sleep(
2137 m, connection, message,
2138 SPECIAL_HIBERNATE_TARGET,
2140 "org.freedesktop.login1.hibernate",
2141 "org.freedesktop.login1.hibernate-multiple-sessions",
2142 "org.freedesktop.login1.hibernate-ignore-inhibit",
2146 return bus_send_error_reply(connection, message, &error, r);
2148 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "HybridSleep")) {
2149 r = bus_manager_do_shutdown_or_sleep(
2150 m, connection, message,
2151 SPECIAL_HYBRID_SLEEP_TARGET,
2153 "org.freedesktop.login1.hibernate",
2154 "org.freedesktop.login1.hibernate-multiple-sessions",
2155 "org.freedesktop.login1.hibernate-ignore-inhibit",
2159 return bus_send_error_reply(connection, message, &error, r);
2161 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2163 r = bus_manager_can_shutdown_or_sleep(
2164 m, connection, message,
2166 "org.freedesktop.login1.power-off",
2167 "org.freedesktop.login1.power-off-multiple-sessions",
2168 "org.freedesktop.login1.power-off-ignore-inhibit",
2172 return bus_send_error_reply(connection, message, &error, r);
2173 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2174 r = bus_manager_can_shutdown_or_sleep(
2175 m, connection, message,
2177 "org.freedesktop.login1.reboot",
2178 "org.freedesktop.login1.reboot-multiple-sessions",
2179 "org.freedesktop.login1.reboot-ignore-inhibit",
2183 return bus_send_error_reply(connection, message, &error, r);
2185 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2186 r = bus_manager_can_shutdown_or_sleep(
2187 m, connection, message,
2189 "org.freedesktop.login1.suspend",
2190 "org.freedesktop.login1.suspend-multiple-sessions",
2191 "org.freedesktop.login1.suspend-ignore-inhibit",
2195 return bus_send_error_reply(connection, message, &error, r);
2197 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2198 r = bus_manager_can_shutdown_or_sleep(
2199 m, connection, message,
2201 "org.freedesktop.login1.hibernate",
2202 "org.freedesktop.login1.hibernate-multiple-sessions",
2203 "org.freedesktop.login1.hibernate-ignore-inhibit",
2207 return bus_send_error_reply(connection, message, &error, r);
2209 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHybridSleep")) {
2210 r = bus_manager_can_shutdown_or_sleep(
2211 m, connection, message,
2213 "org.freedesktop.login1.hibernate",
2214 "org.freedesktop.login1.hibernate-multiple-sessions",
2215 "org.freedesktop.login1.hibernate-ignore-inhibit",
2219 return bus_send_error_reply(connection, message, &error, r);
2221 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2222 char *introspection = NULL;
2231 if (!(reply = dbus_message_new_method_return(message)))
2234 /* We roll our own introspection code here, instead of
2235 * relying on bus_default_message_handler() because we
2236 * need to generate our introspection string
2239 if (!(f = open_memstream(&introspection, &size)))
2242 fputs(INTROSPECTION_BEGIN, f);
2244 HASHMAP_FOREACH(seat, m->seats, i) {
2245 p = bus_path_escape(seat->id);
2248 fprintf(f, "<node name=\"seat/%s\"/>", p);
2253 HASHMAP_FOREACH(user, m->users, i)
2254 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2256 HASHMAP_FOREACH(session, m->sessions, i) {
2257 p = bus_path_escape(session->id);
2260 fprintf(f, "<node name=\"session/%s\"/>", p);
2265 fputs(INTROSPECTION_END, f);
2269 free(introspection);
2278 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2279 free(introspection);
2283 free(introspection);
2285 const BusBoundProperties bps[] = {
2286 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2289 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2293 if (!bus_maybe_send_reply(connection, message, reply))
2297 return DBUS_HANDLER_RESULT_HANDLED;
2300 dbus_error_free(&error);
2302 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2305 const DBusObjectPathVTable bus_manager_vtable = {
2306 .message_function = manager_message_handler
2309 DBusHandlerResult bus_message_filter(
2310 DBusConnection *connection,
2311 DBusMessage *message,
2314 Manager *m = userdata;
2321 dbus_error_init(&error);
2323 log_debug("Got message: %s %s %s", strna(dbus_message_get_sender(message)), strna(dbus_message_get_interface(message)), strna(dbus_message_get_member(message)));
2325 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
2326 const char *path, *result, *unit;
2329 if (!dbus_message_get_args(message, &error,
2330 DBUS_TYPE_UINT32, &id,
2331 DBUS_TYPE_OBJECT_PATH, &path,
2332 DBUS_TYPE_STRING, &unit,
2333 DBUS_TYPE_STRING, &result,
2334 DBUS_TYPE_INVALID)) {
2335 log_error("Failed to parse JobRemoved message: %s", bus_error_message(&error));
2339 if (m->action_job && streq(m->action_job, path)) {
2340 log_info("Operation finished.");
2342 /* Tell people that they now may take a lock again */
2343 send_prepare_for(m, m->action_what, false);
2345 free(m->action_job);
2346 m->action_job = NULL;
2347 m->action_unit = NULL;
2354 s = hashmap_get(m->session_units, unit);
2356 if (streq_ptr(path, s->scope_job)) {
2358 s->scope_job = NULL;
2362 if (streq(result, "done"))
2363 session_send_create_reply(s, NULL);
2365 dbus_set_error(&error, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
2366 session_send_create_reply(s, &error);
2371 session_add_to_gc_queue(s);
2374 u = hashmap_get(m->user_units, unit);
2376 if (streq_ptr(path, u->service_job)) {
2377 free(u->service_job);
2378 u->service_job = NULL;
2381 if (streq_ptr(path, u->slice_job)) {
2383 u->slice_job = NULL;
2387 user_add_to_gc_queue(u);
2391 } else if (dbus_message_is_signal(message, "org.freedesktop.DBus.Properties", "PropertiesChanged")) {
2393 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2394 _cleanup_free_ char *unit = NULL;
2397 path = dbus_message_get_path(message);
2401 unit_name_from_dbus_path(path, &unit);
2406 s = hashmap_get(m->session_units, unit);
2408 session_add_to_gc_queue(s);
2410 u = hashmap_get(m->user_units, unit);
2412 user_add_to_gc_queue(u);
2417 dbus_error_free(&error);
2419 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2422 int manager_send_changed(Manager *manager, const char *properties) {
2423 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
2427 m = bus_properties_changed_new("/org/freedesktop/login1",
2428 "org.freedesktop.login1.Manager",
2433 if (!dbus_connection_send(manager->bus, m, NULL))
2439 int manager_dispatch_delayed(Manager *manager) {
2445 if (manager->action_what == 0 || manager->action_job)
2448 /* Continue delay? */
2449 if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0)) {
2451 if (manager->action_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC))
2454 log_info("Delay lock is active but inhibitor timeout is reached.");
2457 /* Actually do the operation */
2458 dbus_error_init(&error);
2459 r = execute_shutdown_or_sleep(manager, manager->action_what, manager->action_unit, &error);
2461 log_warning("Failed to send delayed message: %s", bus_error(&error, r));
2462 dbus_error_free(&error);
2464 manager->action_unit = NULL;
2465 manager->action_what = 0;
2472 int manager_start_scope(
2477 const char *description,
2481 _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
2482 DBusMessageIter iter, sub, sub2, sub3, sub4;
2483 const char *timeout_stop_property = "TimeoutStopUSec";
2484 const char *pids_property = "PIDs";
2485 uint64_t timeout = 500 * USEC_PER_MSEC;
2486 const char *fail = "fail";
2496 m = dbus_message_new_method_call(
2497 "org.freedesktop.systemd1",
2498 "/org/freedesktop/systemd1",
2499 "org.freedesktop.systemd1.Manager",
2500 "StartTransientUnit");
2504 dbus_message_iter_init_append(m, &iter);
2506 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &scope) ||
2507 !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &fail) ||
2508 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sv)", &sub))
2511 if (!isempty(slice)) {
2512 const char *slice_property = "Slice";
2514 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2515 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &slice_property) ||
2516 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "s", &sub3) ||
2517 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &slice) ||
2518 !dbus_message_iter_close_container(&sub2, &sub3) ||
2519 !dbus_message_iter_close_container(&sub, &sub2))
2523 if (!isempty(description)) {
2524 const char *description_property = "Description";
2526 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2527 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description_property) ||
2528 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "s", &sub3) ||
2529 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &description) ||
2530 !dbus_message_iter_close_container(&sub2, &sub3) ||
2531 !dbus_message_iter_close_container(&sub, &sub2))
2535 /* cgroup empty notification is not available in containers
2536 * currently. To make this less problematic, let's shorten the
2537 * stop timeout for sessions, so that we don't wait
2540 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2541 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &timeout_stop_property) ||
2542 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "t", &sub3) ||
2543 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_UINT64, &timeout) ||
2544 !dbus_message_iter_close_container(&sub2, &sub3) ||
2545 !dbus_message_iter_close_container(&sub, &sub2))
2549 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2550 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &pids_property) ||
2551 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "au", &sub3) ||
2552 !dbus_message_iter_open_container(&sub3, DBUS_TYPE_ARRAY, "u", &sub4) ||
2553 !dbus_message_iter_append_basic(&sub4, DBUS_TYPE_UINT32, &u) ||
2554 !dbus_message_iter_close_container(&sub3, &sub4) ||
2555 !dbus_message_iter_close_container(&sub2, &sub3) ||
2556 !dbus_message_iter_close_container(&sub, &sub2) ||
2557 !dbus_message_iter_close_container(&iter, &sub))
2560 reply = dbus_connection_send_with_reply_and_block(manager->bus, m, -1, error);
2568 if (!dbus_message_get_args(reply, error, DBUS_TYPE_OBJECT_PATH, &j, DBUS_TYPE_INVALID))
2581 int manager_start_unit(Manager *manager, const char *unit, DBusError *error, char **job) {
2582 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2583 const char *fail = "fail";
2589 r = bus_method_call_with_reply(
2591 "org.freedesktop.systemd1",
2592 "/org/freedesktop/systemd1",
2593 "org.freedesktop.systemd1.Manager",
2597 DBUS_TYPE_STRING, &unit,
2598 DBUS_TYPE_STRING, &fail,
2601 log_error("Failed to start unit %s: %s", unit, bus_error(error, r));
2609 if (!dbus_message_get_args(reply, error,
2610 DBUS_TYPE_OBJECT_PATH, &j,
2611 DBUS_TYPE_INVALID)) {
2612 log_error("Failed to parse reply.");
2626 int manager_stop_unit(Manager *manager, const char *unit, DBusError *error, char **job) {
2627 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2628 const char *fail = "fail";
2634 r = bus_method_call_with_reply(
2636 "org.freedesktop.systemd1",
2637 "/org/freedesktop/systemd1",
2638 "org.freedesktop.systemd1.Manager",
2642 DBUS_TYPE_STRING, &unit,
2643 DBUS_TYPE_STRING, &fail,
2646 log_error("Failed to stop unit %s: %s", unit, bus_error(error, r));
2654 if (!dbus_message_get_args(reply, error,
2655 DBUS_TYPE_OBJECT_PATH, &j,
2656 DBUS_TYPE_INVALID)) {
2657 log_error("Failed to parse reply.");
2671 int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, DBusError *error) {
2672 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2679 w = who == KILL_LEADER ? "process" : "cgroup";
2680 assert_cc(sizeof(signo) == sizeof(int32_t));
2682 r = bus_method_call_with_reply(
2684 "org.freedesktop.systemd1",
2685 "/org/freedesktop/systemd1",
2686 "org.freedesktop.systemd1.Manager",
2690 DBUS_TYPE_STRING, &unit,
2691 DBUS_TYPE_STRING, &w,
2692 DBUS_TYPE_INT32, &signo,
2695 log_error("Failed to stop unit %s: %s", unit, bus_error(error, r));
2702 int manager_unit_is_active(Manager *manager, const char *unit) {
2704 const char *interface = "org.freedesktop.systemd1.Unit";
2705 const char *property = "ActiveState";
2706 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2707 _cleanup_free_ char *path = NULL;
2708 DBusMessageIter iter, sub;
2716 dbus_error_init(&error);
2718 path = unit_dbus_path_from_name(unit);
2722 r = bus_method_call_with_reply(
2724 "org.freedesktop.systemd1",
2726 "org.freedesktop.DBus.Properties",
2730 DBUS_TYPE_STRING, &interface,
2731 DBUS_TYPE_STRING, &property,
2735 log_error("Failed to query ActiveState: %s", bus_error(&error, r));
2736 dbus_error_free(&error);
2740 if (!dbus_message_iter_init(reply, &iter) ||
2741 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
2742 log_error("Failed to parse reply.");
2746 dbus_message_iter_recurse(&iter, &sub);
2747 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
2748 log_error("Failed to parse reply.");
2752 dbus_message_iter_get_basic(&sub, &state);
2754 return !streq(state, "inactive") && !streq(state, "failed");