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"
36 #include "fileio-label.h"
39 #define BUS_MANAGER_INTERFACE \
40 " <interface name=\"org.freedesktop.login1.Manager\">\n" \
41 " <method name=\"GetSession\">\n" \
42 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
43 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
45 " <method name=\"GetSessionByPID\">\n" \
46 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
47 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
49 " <method name=\"GetUser\">\n" \
50 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
51 " <arg name=\"user\" type=\"o\" direction=\"out\"/>\n" \
53 " <method name=\"GetSeat\">\n" \
54 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
55 " <arg name=\"seat\" type=\"o\" direction=\"out\"/>\n" \
57 " <method name=\"ListSessions\">\n" \
58 " <arg name=\"sessions\" type=\"a(susso)\" direction=\"out\"/>\n" \
60 " <method name=\"ListUsers\">\n" \
61 " <arg name=\"users\" type=\"a(uso)\" direction=\"out\"/>\n" \
63 " <method name=\"ListSeats\">\n" \
64 " <arg name=\"seats\" type=\"a(so)\" direction=\"out\"/>\n" \
66 " <method name=\"CreateSession\">\n" \
67 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
68 " <arg name=\"leader\" type=\"u\" direction=\"in\"/>\n" \
69 " <arg name=\"service\" type=\"s\" direction=\"in\"/>\n" \
70 " <arg name=\"type\" type=\"s\" direction=\"in\"/>\n" \
71 " <arg name=\"class\" type=\"s\" direction=\"in\"/>\n" \
72 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
73 " <arg name=\"vtnr\" type=\"u\" direction=\"in\"/>\n" \
74 " <arg name=\"tty\" type=\"s\" direction=\"in\"/>\n" \
75 " <arg name=\"display\" type=\"s\" direction=\"in\"/>\n" \
76 " <arg name=\"remote\" type=\"b\" direction=\"in\"/>\n" \
77 " <arg name=\"remote_user\" type=\"s\" direction=\"in\"/>\n" \
78 " <arg name=\"remote_host\" type=\"s\" direction=\"in\"/>\n" \
79 " <arg name=\"controllers\" type=\"as\" direction=\"in\"/>\n" \
80 " <arg name=\"reset_controllers\" type=\"as\" direction=\"in\"/>\n" \
81 " <arg name=\"kill_processes\" type=\"b\" direction=\"in\"/>\n" \
82 " <arg name=\"id\" type=\"s\" direction=\"out\"/>\n" \
83 " <arg name=\"path\" type=\"o\" direction=\"out\"/>\n" \
84 " <arg name=\"runtime_path\" type=\"o\" direction=\"out\"/>\n" \
85 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
86 " <arg name=\"seat\" type=\"s\" direction=\"out\"/>\n" \
87 " <arg name=\"vtnr\" type=\"u\" direction=\"out\"/>\n" \
88 " <arg name=\"existing\" type=\"b\" direction=\"out\"/>\n" \
90 " <method name=\"ReleaseSession\">\n" \
91 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
93 " <method name=\"ActivateSession\">\n" \
94 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
96 " <method name=\"ActivateSessionOnSeat\">\n" \
97 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
98 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
100 " <method name=\"LockSession\">\n" \
101 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
103 " <method name=\"UnlockSession\">\n" \
104 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
106 " <method name=\"LockSessions\"/>\n" \
107 " <method name=\"UnlockSessions\"/>\n" \
108 " <method name=\"KillSession\">\n" \
109 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
110 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
111 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
113 " <method name=\"KillUser\">\n" \
114 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
115 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
117 " <method name=\"TerminateSession\">\n" \
118 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
120 " <method name=\"TerminateUser\">\n" \
121 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
123 " <method name=\"TerminateSeat\">\n" \
124 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
126 " <method name=\"SetUserLinger\">\n" \
127 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
128 " <arg name=\"b\" type=\"b\" direction=\"in\"/>\n" \
129 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
131 " <method name=\"AttachDevice\">\n" \
132 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
133 " <arg name=\"sysfs\" type=\"s\" direction=\"in\"/>\n" \
134 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
136 " <method name=\"FlushDevices\">\n" \
137 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
139 " <method name=\"PowerOff\">\n" \
140 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
142 " <method name=\"Reboot\">\n" \
143 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
145 " <method name=\"Suspend\">\n" \
146 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
148 " <method name=\"Hibernate\">\n" \
149 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
151 " <method name=\"HybridSleep\">\n" \
152 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
154 " <method name=\"CanPowerOff\">\n" \
155 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
157 " <method name=\"CanReboot\">\n" \
158 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
160 " <method name=\"CanSuspend\">\n" \
161 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
163 " <method name=\"CanHibernate\">\n" \
164 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
166 " <method name=\"CanHybridSleep\">\n" \
167 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
169 " <method name=\"Inhibit\">\n" \
170 " <arg name=\"what\" type=\"s\" direction=\"in\"/>\n" \
171 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
172 " <arg name=\"why\" type=\"s\" direction=\"in\"/>\n" \
173 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
174 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
176 " <method name=\"ListInhibitors\">\n" \
177 " <arg name=\"inhibitors\" type=\"a(ssssuu)\" direction=\"out\"/>\n" \
179 " <signal name=\"SessionNew\">\n" \
180 " <arg name=\"id\" type=\"s\"/>\n" \
181 " <arg name=\"path\" type=\"o\"/>\n" \
183 " <signal name=\"SessionRemoved\">\n" \
184 " <arg name=\"id\" type=\"s\"/>\n" \
185 " <arg name=\"path\" type=\"o\"/>\n" \
187 " <signal name=\"UserNew\">\n" \
188 " <arg name=\"uid\" type=\"u\"/>\n" \
189 " <arg name=\"path\" type=\"o\"/>\n" \
191 " <signal name=\"UserRemoved\">\n" \
192 " <arg name=\"uid\" type=\"u\"/>\n" \
193 " <arg name=\"path\" type=\"o\"/>\n" \
195 " <signal name=\"SeatNew\">\n" \
196 " <arg name=\"id\" type=\"s\"/>\n" \
197 " <arg name=\"path\" type=\"o\"/>\n" \
199 " <signal name=\"SeatRemoved\">\n" \
200 " <arg name=\"id\" type=\"s\"/>\n" \
201 " <arg name=\"path\" type=\"o\"/>\n" \
203 " <signal name=\"PrepareForShutdown\">\n" \
204 " <arg name=\"active\" type=\"b\"/>\n" \
206 " <signal name=\"PrepareForSleep\">\n" \
207 " <arg name=\"active\" type=\"b\"/>\n" \
209 " <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
210 " <property name=\"Controllers\" type=\"as\" access=\"read\"/>\n" \
211 " <property name=\"ResetControllers\" type=\"as\" access=\"read\"/>\n" \
212 " <property name=\"NAutoVTs\" type=\"u\" access=\"read\"/>\n" \
213 " <property name=\"KillOnlyUsers\" type=\"as\" access=\"read\"/>\n" \
214 " <property name=\"KillExcludeUsers\" type=\"as\" access=\"read\"/>\n" \
215 " <property name=\"KillUserProcesses\" type=\"b\" access=\"read\"/>\n" \
216 " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
217 " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
218 " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
219 " <property name=\"BlockInhibited\" type=\"s\" access=\"read\"/>\n" \
220 " <property name=\"DelayInhibited\" type=\"s\" access=\"read\"/>\n" \
221 " <property name=\"InhibitDelayMaxUSec\" type=\"t\" access=\"read\"/>\n" \
222 " <property name=\"HandlePowerKey\" type=\"s\" access=\"read\"/>\n" \
223 " <property name=\"HandleSuspendKey\" type=\"s\" access=\"read\"/>\n" \
224 " <property name=\"HandleHibernateKey\" type=\"s\" access=\"read\"/>\n" \
225 " <property name=\"HandleLidSwitch\" type=\"s\" access=\"read\"/>\n" \
226 " <property name=\"IdleAction\" type=\"s\" access=\"read\"/>\n" \
227 " <property name=\"IdleActionUSec\" type=\"t\" access=\"read\"/>\n" \
228 " <property name=\"PreparingForShutdown\" type=\"b\" access=\"read\"/>\n" \
229 " <property name=\"PreparingForSleep\" type=\"b\" access=\"read\"/>\n" \
232 #define INTROSPECTION_BEGIN \
233 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
235 BUS_MANAGER_INTERFACE \
236 BUS_PROPERTIES_INTERFACE \
238 BUS_INTROSPECTABLE_INTERFACE
240 #define INTROSPECTION_END \
243 #define INTERFACES_LIST \
244 BUS_GENERIC_INTERFACES_LIST \
245 "org.freedesktop.login1.Manager\0"
247 static int bus_manager_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
255 b = manager_get_idle_hint(m, NULL) > 0;
256 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
262 static int bus_manager_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
271 manager_get_idle_hint(m, &t);
272 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
274 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
280 static int bus_manager_append_inhibited(DBusMessageIter *i, const char *property, void *data) {
285 w = manager_inhibit_what(m, streq(property, "BlockInhibited") ? INHIBIT_BLOCK : INHIBIT_DELAY);
286 p = inhibit_what_to_string(w);
288 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &p))
294 static int bus_manager_append_preparing(DBusMessageIter *i, const char *property, void *data) {
301 if (streq(property, "PreparingForShutdown"))
302 b = !!(m->action_what & INHIBIT_SHUTDOWN);
304 b = !!(m->action_what & INHIBIT_SLEEP);
306 dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b);
310 static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMessage **_reply) {
311 const char *type, *class, *cseat, *tty, *display, *remote_user, *remote_host, *service;
312 uint32_t uid, leader, audit_id = 0;
313 dbus_bool_t remote, kill_processes, exists;
314 _cleanup_strv_free_ char **controllers = NULL, **reset_controllers = NULL;
315 _cleanup_free_ char *cgroup = NULL, *id = NULL, *p = NULL;
318 DBusMessageIter iter;
321 _cleanup_close_ int fifo_fd = -1;
322 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
323 Session *session = NULL;
332 if (!dbus_message_iter_init(message, &iter) ||
333 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
336 dbus_message_iter_get_basic(&iter, &uid);
338 if (!dbus_message_iter_next(&iter) ||
339 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
342 dbus_message_iter_get_basic(&iter, &leader);
345 !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);
481 if (!dbus_message_iter_next(&iter) ||
482 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
483 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
486 r = bus_parse_strv_iter(&iter, &controllers);
490 if (!dbus_message_iter_next(&iter) ||
491 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
492 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) {
497 r = bus_parse_strv_iter(&iter, &reset_controllers);
501 if (!dbus_message_iter_next(&iter) ||
502 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) {
507 dbus_message_iter_get_basic(&iter, &kill_processes);
509 r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, leader, &cgroup);
513 r = manager_get_session_by_cgroup(m, cgroup, &session);
518 fifo_fd = session_create_fifo(session);
524 /* Session already exists, client is probably
525 * something like "su" which changes uid but
526 * is still the same audit session */
528 reply = dbus_message_new_method_return(message);
534 p = session_bus_path(session);
540 cseat = session->seat ? session->seat->id : "";
541 vtnr = session->vtnr;
544 b = dbus_message_append_args(
546 DBUS_TYPE_STRING, &session->id,
547 DBUS_TYPE_OBJECT_PATH, &p,
548 DBUS_TYPE_STRING, &session->user->runtime_path,
549 DBUS_TYPE_UNIX_FD, &fifo_fd,
550 DBUS_TYPE_STRING, &cseat,
551 DBUS_TYPE_UINT32, &vtnr,
552 DBUS_TYPE_BOOLEAN, &exists,
565 audit_session_from_pid(leader, &audit_id);
567 /* Keep our session IDs and the audit session IDs in sync */
569 if (asprintf(&id, "%lu", (unsigned long) audit_id) < 0) {
574 /* Wut? There's already a session by this name and we
575 * didn't find it above? Weird, then let's not trust
576 * the audit data and let's better register a new
578 if (hashmap_get(m->sessions, id)) {
591 if (asprintf(&id, "c%lu", ++m->session_counter) < 0) {
596 } while (hashmap_get(m->sessions, id));
599 r = manager_add_user_by_uid(m, uid, &user);
603 r = manager_add_session(m, user, id, &session);
607 session->leader = leader;
608 session->audit_id = audit_id;
611 session->remote = remote;
612 session->kill_processes = kill_processes;
613 session->vtnr = vtnr;
615 session->controllers = cg_shorten_controllers(controllers);
616 session->reset_controllers = cg_shorten_controllers(reset_controllers);
617 controllers = reset_controllers = NULL;
620 session->tty = strdup(tty);
627 if (!isempty(display)) {
628 session->display = strdup(display);
629 if (!session->display) {
635 if (!isempty(remote_user)) {
636 session->remote_user = strdup(remote_user);
637 if (!session->remote_user) {
643 if (!isempty(remote_host)) {
644 session->remote_host = strdup(remote_host);
645 if (!session->remote_host) {
651 if (!isempty(service)) {
652 session->service = strdup(service);
653 if (!session->service) {
659 fifo_fd = session_create_fifo(session);
666 r = seat_attach_session(seat, session);
671 r = session_start(session);
675 reply = dbus_message_new_method_return(message);
681 p = session_bus_path(session);
687 cseat = seat ? seat->id : "";
689 b = dbus_message_append_args(
691 DBUS_TYPE_STRING, &session->id,
692 DBUS_TYPE_OBJECT_PATH, &p,
693 DBUS_TYPE_STRING, &session->user->runtime_path,
694 DBUS_TYPE_UNIX_FD, &fifo_fd,
695 DBUS_TYPE_STRING, &cseat,
696 DBUS_TYPE_UINT32, &vtnr,
697 DBUS_TYPE_BOOLEAN, &exists,
712 session_add_to_gc_queue(session);
715 user_add_to_gc_queue(user);
720 static int bus_manager_inhibit(
722 DBusConnection *connection,
723 DBusMessage *message,
725 DBusMessage **_reply) {
729 const char *who, *why, *what, *mode;
735 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
743 if (!dbus_message_get_args(
746 DBUS_TYPE_STRING, &what,
747 DBUS_TYPE_STRING, &who,
748 DBUS_TYPE_STRING, &why,
749 DBUS_TYPE_STRING, &mode,
750 DBUS_TYPE_INVALID)) {
755 w = inhibit_what_from_string(what);
761 mm = inhibit_mode_from_string(mode);
767 /* Delay is only supported for shutdown/sleep */
768 if (mm == INHIBIT_DELAY && (w & ~(INHIBIT_SHUTDOWN|INHIBIT_SLEEP))) {
773 /* Don't allow taking delay locks while we are already
774 * executing the operation. We shouldn't create the impression
775 * that the lock was successful if the machine is about to go
776 * down/suspend any moment. */
777 if (m->action_what & w) {
782 r = verify_polkit(connection, message,
783 w == INHIBIT_SHUTDOWN ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
784 w == INHIBIT_SLEEP ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep" : "org.freedesktop.login1.inhibit-delay-sleep") :
785 w == INHIBIT_IDLE ? "org.freedesktop.login1.inhibit-block-idle" :
786 w == INHIBIT_HANDLE_POWER_KEY ? "org.freedesktop.login1.inhibit-handle-power-key" :
787 w == INHIBIT_HANDLE_SUSPEND_KEY ? "org.freedesktop.login1.inhibit-handle-suspend-key" :
788 w == INHIBIT_HANDLE_HIBERNATE_KEY ? "org.freedesktop.login1.inhibit-handle-hibernate-key" :
789 "org.freedesktop.login1.inhibit-handle-lid-switch",
794 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
795 if (ul == (unsigned long) -1) {
800 pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
810 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
814 } while (hashmap_get(m->inhibitors, id));
816 r = manager_add_inhibitor(m, id, &i);
826 i->why = strdup(why);
827 i->who = strdup(who);
829 if (!i->why || !i->who) {
834 fifo_fd = inhibitor_create_fifo(i);
840 reply = dbus_message_new_method_return(message);
846 if (!dbus_message_append_args(
848 DBUS_TYPE_UNIX_FD, &fifo_fd,
849 DBUS_TYPE_INVALID)) {
854 close_nointr_nofail(fifo_fd);
867 close_nointr_nofail(fifo_fd);
872 static int trigger_device(Manager *m, struct udev_device *d) {
873 struct udev_enumerate *e;
874 struct udev_list_entry *first, *item;
879 e = udev_enumerate_new(m->udev);
886 if (udev_enumerate_add_match_parent(e, d) < 0) {
892 if (udev_enumerate_scan_devices(e) < 0) {
897 first = udev_enumerate_get_list_entry(e);
898 udev_list_entry_foreach(item, first) {
902 p = udev_list_entry_get_name(item);
904 t = strappend(p, "/uevent");
910 write_string_file(t, "change");
918 udev_enumerate_unref(e);
923 static int attach_device(Manager *m, const char *seat, const char *sysfs) {
924 struct udev_device *d;
925 _cleanup_free_ char *rule = NULL, *file = NULL;
926 const char *id_for_seat;
933 d = udev_device_new_from_syspath(m->udev, sysfs);
937 if (!udev_device_has_tag(d, "seat")) {
942 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
948 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
953 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
958 mkdir_p_label("/etc/udev/rules.d", 0755);
960 r = write_string_file_atomic_label(file, rule);
964 r = trigger_device(m, d);
968 udev_device_unref(d);
973 static int flush_devices(Manager *m) {
974 _cleanup_closedir_ DIR *d;
978 d = opendir("/etc/udev/rules.d");
981 log_warning("Failed to open /etc/udev/rules.d: %m");
985 while ((de = readdir(d))) {
987 if (!dirent_is_file(de))
990 if (!startswith(de->d_name, "72-seat-"))
993 if (!endswith(de->d_name, ".rules"))
996 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
997 log_warning("Failed to unlink %s: %m", de->d_name);
1001 return trigger_device(m, NULL);
1004 static int have_multiple_sessions(
1013 /* Check for other users' sessions. Greeter sessions do not
1014 * count, and non-login sessions do not count either. */
1015 HASHMAP_FOREACH(session, m->sessions, i)
1016 if (session->class == SESSION_USER &&
1017 session->user->uid != uid)
1023 static int bus_manager_log_shutdown(
1026 const char *unit_name) {
1033 if (w != INHIBIT_SHUTDOWN)
1036 if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
1037 p = "MESSAGE=System is powering down.";
1038 q = "SHUTDOWN=power-off";
1039 } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
1040 p = "MESSAGE=System is halting.";
1041 q = "SHUTDOWN=halt";
1042 } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
1043 p = "MESSAGE=System is rebooting.";
1044 q = "SHUTDOWN=reboot";
1045 } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
1046 p = "MESSAGE=System is rebooting with kexec.";
1047 q = "SHUTDOWN=kexec";
1049 p = "MESSAGE=System is shutting down.";
1053 return log_struct(LOG_NOTICE, MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
1058 static int execute_shutdown_or_sleep(
1061 const char *unit_name,
1064 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1065 const char *mode = "replace-irreversibly", *p;
1071 assert(w < _INHIBIT_WHAT_MAX);
1074 bus_manager_log_shutdown(m, w, unit_name);
1076 r = bus_method_call_with_reply(
1078 "org.freedesktop.systemd1",
1079 "/org/freedesktop/systemd1",
1080 "org.freedesktop.systemd1.Manager",
1084 DBUS_TYPE_STRING, &unit_name,
1085 DBUS_TYPE_STRING, &mode,
1090 if (!dbus_message_get_args(
1093 DBUS_TYPE_OBJECT_PATH, &p,
1101 m->action_unit = unit_name;
1102 free(m->action_job);
1109 static int delay_shutdown_or_sleep(
1112 const char *unit_name) {
1116 assert(w < _INHIBIT_WHAT_MAX);
1119 m->action_timestamp = now(CLOCK_MONOTONIC);
1120 m->action_unit = unit_name;
1126 static int bus_manager_can_shutdown_or_sleep(
1128 DBusConnection *connection,
1129 DBusMessage *message,
1132 const char *action_multiple_sessions,
1133 const char *action_ignore_inhibit,
1134 const char *sleep_type,
1135 const char *sleep_disk_type,
1137 DBusMessage **_reply) {
1139 bool multiple_sessions, challenge, blocked, b;
1140 const char *result = NULL;
1141 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1149 assert(w <= _INHIBIT_WHAT_MAX);
1151 assert(action_multiple_sessions);
1152 assert(action_ignore_inhibit);
1157 r = can_sleep(sleep_type);
1167 if (sleep_disk_type) {
1168 r = can_sleep_disk(sleep_disk_type);
1178 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1179 if (ul == (unsigned long) -1)
1182 r = have_multiple_sessions(m, (uid_t) ul);
1186 multiple_sessions = r > 0;
1187 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1189 if (multiple_sessions) {
1190 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1197 result = "challenge";
1203 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1207 if (r > 0 && !result)
1209 else if (challenge && (!result || streq(result, "yes")))
1210 result = "challenge";
1215 if (!multiple_sessions && !blocked) {
1216 /* If neither inhibit nor multiple sessions
1217 * apply then just check the normal policy */
1219 r = verify_polkit(connection, message, action, false, &challenge, error);
1226 result = "challenge";
1232 reply = dbus_message_new_method_return(message);
1236 b = dbus_message_append_args(
1238 DBUS_TYPE_STRING, &result,
1248 static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
1249 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
1250 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
1251 [INHIBIT_SLEEP] = "PrepareForSleep"
1254 dbus_bool_t active = _active;
1255 _cleanup_dbus_message_unref_ DBusMessage *message = NULL;
1259 assert(w < _INHIBIT_WHAT_MAX);
1260 assert(signal_name[w]);
1262 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1266 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1267 !dbus_connection_send(m->bus, message, NULL))
1273 int bus_manager_shutdown_or_sleep_now_or_later(
1275 const char *unit_name,
1285 assert(w <= _INHIBIT_WHAT_MAX);
1286 assert(!m->action_job);
1288 /* Tell everybody to prepare for shutdown/sleep */
1289 send_prepare_for(m, w, true);
1292 m->inhibit_delay_max > 0 &&
1293 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0);
1296 /* Shutdown is delayed, keep in mind what we
1297 * want to do, and start a timeout */
1298 r = delay_shutdown_or_sleep(m, w, unit_name);
1300 /* Shutdown is not delayed, execute it
1302 r = execute_shutdown_or_sleep(m, w, unit_name, error);
1307 static int bus_manager_do_shutdown_or_sleep(
1309 DBusConnection *connection,
1310 DBusMessage *message,
1311 const char *unit_name,
1314 const char *action_multiple_sessions,
1315 const char *action_ignore_inhibit,
1316 const char *sleep_type,
1317 const char *sleep_disk_type,
1319 DBusMessage **_reply) {
1321 dbus_bool_t interactive;
1322 bool multiple_sessions, blocked;
1323 DBusMessage *reply = NULL;
1332 assert(w <= _INHIBIT_WHAT_MAX);
1334 assert(action_multiple_sessions);
1335 assert(action_ignore_inhibit);
1339 /* Don't allow multiple jobs being executed at the same time */
1343 if (!dbus_message_get_args(
1346 DBUS_TYPE_BOOLEAN, &interactive,
1351 r = can_sleep(sleep_type);
1359 if (sleep_disk_type) {
1360 r = can_sleep_disk(sleep_disk_type);
1368 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1369 if (ul == (unsigned long) -1)
1372 r = have_multiple_sessions(m, (uid_t) ul);
1376 multiple_sessions = r > 0;
1377 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1379 if (multiple_sessions) {
1380 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1386 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1391 if (!multiple_sessions && !blocked) {
1392 r = verify_polkit(connection, message, action, interactive, NULL, error);
1397 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
1401 reply = dbus_message_new_method_return(message);
1409 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_action, handle_action, HandleAction);
1411 static const BusProperty bus_login_manager_properties[] = {
1412 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_path), true },
1413 { "Controllers", bus_property_append_strv, "as", offsetof(Manager, controllers), true },
1414 { "ResetControllers", bus_property_append_strv, "as", offsetof(Manager, reset_controllers), true },
1415 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1416 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1417 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1418 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1419 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1420 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1421 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
1422 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1423 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1424 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
1425 { "HandlePowerKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_power_key) },
1426 { "HandleSuspendKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_suspend_key) },
1427 { "HandleHibernateKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_hibernate_key)},
1428 { "HandleLidSwitch", bus_manager_append_handle_action, "s", offsetof(Manager, handle_lid_switch) },
1429 { "IdleAction", bus_manager_append_handle_action, "s", offsetof(Manager, idle_action) },
1430 { "IdleActionUSec", bus_property_append_usec, "t", offsetof(Manager, idle_action_usec) },
1431 { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
1432 { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
1436 static DBusHandlerResult manager_message_handler(
1437 DBusConnection *connection,
1438 DBusMessage *message,
1441 Manager *m = userdata;
1444 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1451 dbus_error_init(&error);
1453 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1459 if (!dbus_message_get_args(
1462 DBUS_TYPE_STRING, &name,
1464 return bus_send_error_reply(connection, message, &error, -EINVAL);
1466 session = hashmap_get(m->sessions, name);
1468 return bus_send_error_reply(connection, message, &error, -ENOENT);
1470 reply = dbus_message_new_method_return(message);
1474 p = session_bus_path(session);
1478 b = dbus_message_append_args(
1480 DBUS_TYPE_OBJECT_PATH, &p,
1487 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1493 if (!dbus_message_get_args(
1496 DBUS_TYPE_UINT32, &pid,
1498 return bus_send_error_reply(connection, message, &error, -EINVAL);
1500 r = manager_get_session_by_pid(m, pid, &session);
1502 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1504 reply = dbus_message_new_method_return(message);
1508 p = session_bus_path(session);
1512 b = dbus_message_append_args(
1514 DBUS_TYPE_OBJECT_PATH, &p,
1521 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1527 if (!dbus_message_get_args(
1530 DBUS_TYPE_UINT32, &uid,
1532 return bus_send_error_reply(connection, message, &error, -EINVAL);
1534 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1536 return bus_send_error_reply(connection, message, &error, -ENOENT);
1538 reply = dbus_message_new_method_return(message);
1542 p = user_bus_path(user);
1546 b = dbus_message_append_args(
1548 DBUS_TYPE_OBJECT_PATH, &p,
1555 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1561 if (!dbus_message_get_args(
1564 DBUS_TYPE_STRING, &name,
1566 return bus_send_error_reply(connection, message, &error, -EINVAL);
1568 seat = hashmap_get(m->seats, name);
1570 return bus_send_error_reply(connection, message, &error, -ENOENT);
1572 reply = dbus_message_new_method_return(message);
1576 p = seat_bus_path(seat);
1580 b = dbus_message_append_args(
1582 DBUS_TYPE_OBJECT_PATH, &p,
1589 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1593 DBusMessageIter iter, sub;
1594 const char *empty = "";
1596 reply = dbus_message_new_method_return(message);
1600 dbus_message_iter_init_append(reply, &iter);
1602 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1605 HASHMAP_FOREACH(session, m->sessions, i) {
1606 DBusMessageIter sub2;
1609 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1612 uid = session->user->uid;
1614 p = session_bus_path(session);
1618 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1619 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1620 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1621 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1622 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1629 if (!dbus_message_iter_close_container(&sub, &sub2))
1633 if (!dbus_message_iter_close_container(&iter, &sub))
1636 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1640 DBusMessageIter iter, sub;
1642 reply = dbus_message_new_method_return(message);
1646 dbus_message_iter_init_append(reply, &iter);
1648 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1651 HASHMAP_FOREACH(user, m->users, i) {
1652 DBusMessageIter sub2;
1655 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1660 p = user_bus_path(user);
1664 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1665 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1666 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1673 if (!dbus_message_iter_close_container(&sub, &sub2))
1677 if (!dbus_message_iter_close_container(&iter, &sub))
1680 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1684 DBusMessageIter iter, sub;
1686 reply = dbus_message_new_method_return(message);
1690 dbus_message_iter_init_append(reply, &iter);
1692 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1695 HASHMAP_FOREACH(seat, m->seats, i) {
1696 DBusMessageIter sub2;
1698 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1701 p = seat_bus_path(seat);
1705 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1706 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1713 if (!dbus_message_iter_close_container(&sub, &sub2))
1717 if (!dbus_message_iter_close_container(&iter, &sub))
1720 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1721 Inhibitor *inhibitor;
1723 DBusMessageIter iter, sub;
1725 reply = dbus_message_new_method_return(message);
1729 dbus_message_iter_init_append(reply, &iter);
1731 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1734 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1735 DBusMessageIter sub2;
1736 dbus_uint32_t uid, pid;
1737 const char *what, *who, *why, *mode;
1739 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1742 what = strempty(inhibit_what_to_string(inhibitor->what));
1743 who = strempty(inhibitor->who);
1744 why = strempty(inhibitor->why);
1745 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
1746 uid = (dbus_uint32_t) inhibitor->uid;
1747 pid = (dbus_uint32_t) inhibitor->pid;
1749 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1750 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1751 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1752 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
1753 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1754 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1757 if (!dbus_message_iter_close_container(&sub, &sub2))
1761 if (!dbus_message_iter_close_container(&iter, &sub))
1764 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1766 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1769 return bus_send_error_reply(connection, message, &error, r);
1772 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1774 r = bus_manager_create_session(m, message, &reply);
1776 /* Don't delay the work on OOM here, since it might be
1777 * triggered by a low RLIMIT_NOFILE here (since we
1778 * send a dupped fd to the client), and we'd rather
1779 * see this fail quickly then be retried later */
1782 return bus_send_error_reply(connection, message, NULL, r);
1784 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1788 if (!dbus_message_get_args(
1791 DBUS_TYPE_STRING, &name,
1793 return bus_send_error_reply(connection, message, &error, -EINVAL);
1795 session = hashmap_get(m->sessions, name);
1797 return bus_send_error_reply(connection, message, &error, -ENOENT);
1799 /* We use the FIFO to detect stray sessions where the
1800 process invoking PAM dies abnormally. We need to make
1801 sure that that process is not killed if at the clean
1802 end of the session it closes the FIFO. Hence, with
1803 this call explicitly turn off the FIFO logic, so that
1804 the PAM code can finish clean up on its own */
1805 session_remove_fifo(session);
1807 reply = dbus_message_new_method_return(message);
1811 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1815 if (!dbus_message_get_args(
1818 DBUS_TYPE_STRING, &name,
1820 return bus_send_error_reply(connection, message, &error, -EINVAL);
1822 session = hashmap_get(m->sessions, name);
1824 return bus_send_error_reply(connection, message, &error, -ENOENT);
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", "ActivateSessionOnSeat")) {
1835 const char *session_name, *seat_name;
1839 /* Same as ActivateSession() but refuses to work if
1840 * the seat doesn't match */
1842 if (!dbus_message_get_args(
1845 DBUS_TYPE_STRING, &session_name,
1846 DBUS_TYPE_STRING, &seat_name,
1848 return bus_send_error_reply(connection, message, &error, -EINVAL);
1850 session = hashmap_get(m->sessions, session_name);
1852 return bus_send_error_reply(connection, message, &error, -ENOENT);
1854 seat = hashmap_get(m->seats, seat_name);
1856 return bus_send_error_reply(connection, message, &error, -ENOENT);
1858 if (session->seat != seat)
1859 return bus_send_error_reply(connection, message, &error, -EINVAL);
1861 r = session_activate(session);
1863 return bus_send_error_reply(connection, message, NULL, r);
1865 reply = dbus_message_new_method_return(message);
1869 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1870 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1874 if (!dbus_message_get_args(
1877 DBUS_TYPE_STRING, &name,
1879 return bus_send_error_reply(connection, message, &error, -EINVAL);
1881 session = hashmap_get(m->sessions, name);
1883 return bus_send_error_reply(connection, message, NULL, -ENOENT);
1885 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1888 reply = dbus_message_new_method_return(message);
1892 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions") ||
1893 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSessions")) {
1895 r = session_send_lock_all(m, streq(dbus_message_get_member(message), "LockSessions"));
1897 bus_send_error_reply(connection, message, NULL, r);
1899 reply = dbus_message_new_method_return(message);
1903 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1910 if (!dbus_message_get_args(
1913 DBUS_TYPE_STRING, &name,
1914 DBUS_TYPE_STRING, &swho,
1915 DBUS_TYPE_INT32, &signo,
1917 return bus_send_error_reply(connection, message, &error, -EINVAL);
1922 who = kill_who_from_string(swho);
1924 return bus_send_error_reply(connection, message, &error, -EINVAL);
1927 if (signo <= 0 || signo >= _NSIG)
1928 return bus_send_error_reply(connection, message, &error, -EINVAL);
1930 session = hashmap_get(m->sessions, name);
1932 return bus_send_error_reply(connection, message, &error, -ENOENT);
1934 r = session_kill(session, who, signo);
1936 return bus_send_error_reply(connection, message, NULL, r);
1938 reply = dbus_message_new_method_return(message);
1942 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1947 if (!dbus_message_get_args(
1950 DBUS_TYPE_UINT32, &uid,
1951 DBUS_TYPE_INT32, &signo,
1953 return bus_send_error_reply(connection, message, &error, -EINVAL);
1955 if (signo <= 0 || signo >= _NSIG)
1956 return bus_send_error_reply(connection, message, &error, -EINVAL);
1958 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1960 return bus_send_error_reply(connection, message, &error, -ENOENT);
1962 r = user_kill(user, signo);
1964 return bus_send_error_reply(connection, message, NULL, r);
1966 reply = dbus_message_new_method_return(message);
1970 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1974 if (!dbus_message_get_args(
1977 DBUS_TYPE_STRING, &name,
1979 return bus_send_error_reply(connection, message, &error, -EINVAL);
1981 session = hashmap_get(m->sessions, name);
1983 return bus_send_error_reply(connection, message, &error, -ENOENT);
1985 r = session_stop(session);
1987 return bus_send_error_reply(connection, message, NULL, r);
1989 reply = dbus_message_new_method_return(message);
1993 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1997 if (!dbus_message_get_args(
2000 DBUS_TYPE_UINT32, &uid,
2002 return bus_send_error_reply(connection, message, &error, -EINVAL);
2004 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
2006 return bus_send_error_reply(connection, message, &error, -ENOENT);
2008 r = user_stop(user);
2010 return bus_send_error_reply(connection, message, NULL, r);
2012 reply = dbus_message_new_method_return(message);
2016 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
2020 if (!dbus_message_get_args(
2023 DBUS_TYPE_STRING, &name,
2025 return bus_send_error_reply(connection, message, &error, -EINVAL);
2027 seat = hashmap_get(m->seats, name);
2029 return bus_send_error_reply(connection, message, &error, -ENOENT);
2031 r = seat_stop_sessions(seat);
2033 return bus_send_error_reply(connection, message, NULL, r);
2035 reply = dbus_message_new_method_return(message);
2039 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
2042 dbus_bool_t b, interactive;
2045 if (!dbus_message_get_args(
2048 DBUS_TYPE_UINT32, &uid,
2049 DBUS_TYPE_BOOLEAN, &b,
2050 DBUS_TYPE_BOOLEAN, &interactive,
2052 return bus_send_error_reply(connection, message, &error, -EINVAL);
2057 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
2059 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
2061 return bus_send_error_reply(connection, message, &error, r);
2063 mkdir_p_label("/var/lib/systemd", 0755);
2065 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
2067 return bus_send_error_reply(connection, message, &error, r);
2069 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
2080 return bus_send_error_reply(connection, message, &error, r);
2082 if (manager_add_user_by_uid(m, uid, &u) >= 0)
2091 if (r < 0 && errno != ENOENT)
2092 return bus_send_error_reply(connection, message, &error, -errno);
2094 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
2096 user_add_to_gc_queue(u);
2099 reply = dbus_message_new_method_return(message);
2103 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
2104 const char *sysfs, *seat;
2105 dbus_bool_t interactive;
2107 if (!dbus_message_get_args(
2110 DBUS_TYPE_STRING, &seat,
2111 DBUS_TYPE_STRING, &sysfs,
2112 DBUS_TYPE_BOOLEAN, &interactive,
2114 return bus_send_error_reply(connection, message, &error, -EINVAL);
2116 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
2117 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2119 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
2121 return bus_send_error_reply(connection, message, &error, r);
2123 r = attach_device(m, seat, sysfs);
2125 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2127 reply = dbus_message_new_method_return(message);
2132 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
2133 dbus_bool_t interactive;
2135 if (!dbus_message_get_args(
2138 DBUS_TYPE_BOOLEAN, &interactive,
2140 return bus_send_error_reply(connection, message, &error, -EINVAL);
2142 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
2144 return bus_send_error_reply(connection, message, &error, r);
2146 r = flush_devices(m);
2148 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2150 reply = dbus_message_new_method_return(message);
2154 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
2156 r = bus_manager_do_shutdown_or_sleep(
2157 m, connection, message,
2158 SPECIAL_POWEROFF_TARGET,
2160 "org.freedesktop.login1.power-off",
2161 "org.freedesktop.login1.power-off-multiple-sessions",
2162 "org.freedesktop.login1.power-off-ignore-inhibit",
2166 return bus_send_error_reply(connection, message, &error, r);
2167 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
2168 r = bus_manager_do_shutdown_or_sleep(
2169 m, connection, message,
2170 SPECIAL_REBOOT_TARGET,
2172 "org.freedesktop.login1.reboot",
2173 "org.freedesktop.login1.reboot-multiple-sessions",
2174 "org.freedesktop.login1.reboot-ignore-inhibit",
2178 return bus_send_error_reply(connection, message, &error, r);
2180 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2181 r = bus_manager_do_shutdown_or_sleep(
2182 m, connection, message,
2183 SPECIAL_SUSPEND_TARGET,
2185 "org.freedesktop.login1.suspend",
2186 "org.freedesktop.login1.suspend-multiple-sessions",
2187 "org.freedesktop.login1.suspend-ignore-inhibit",
2191 return bus_send_error_reply(connection, message, &error, r);
2192 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2193 r = bus_manager_do_shutdown_or_sleep(
2194 m, connection, message,
2195 SPECIAL_HIBERNATE_TARGET,
2197 "org.freedesktop.login1.hibernate",
2198 "org.freedesktop.login1.hibernate-multiple-sessions",
2199 "org.freedesktop.login1.hibernate-ignore-inhibit",
2203 return bus_send_error_reply(connection, message, &error, r);
2205 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "HybridSleep")) {
2206 r = bus_manager_do_shutdown_or_sleep(
2207 m, connection, message,
2208 SPECIAL_HYBRID_SLEEP_TARGET,
2210 "org.freedesktop.login1.hibernate",
2211 "org.freedesktop.login1.hibernate-multiple-sessions",
2212 "org.freedesktop.login1.hibernate-ignore-inhibit",
2216 return bus_send_error_reply(connection, message, &error, r);
2218 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2220 r = bus_manager_can_shutdown_or_sleep(
2221 m, connection, message,
2223 "org.freedesktop.login1.power-off",
2224 "org.freedesktop.login1.power-off-multiple-sessions",
2225 "org.freedesktop.login1.power-off-ignore-inhibit",
2229 return bus_send_error_reply(connection, message, &error, r);
2230 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2231 r = bus_manager_can_shutdown_or_sleep(
2232 m, connection, message,
2234 "org.freedesktop.login1.reboot",
2235 "org.freedesktop.login1.reboot-multiple-sessions",
2236 "org.freedesktop.login1.reboot-ignore-inhibit",
2240 return bus_send_error_reply(connection, message, &error, r);
2242 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2243 r = bus_manager_can_shutdown_or_sleep(
2244 m, connection, message,
2246 "org.freedesktop.login1.suspend",
2247 "org.freedesktop.login1.suspend-multiple-sessions",
2248 "org.freedesktop.login1.suspend-ignore-inhibit",
2252 return bus_send_error_reply(connection, message, &error, r);
2254 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2255 r = bus_manager_can_shutdown_or_sleep(
2256 m, connection, message,
2258 "org.freedesktop.login1.hibernate",
2259 "org.freedesktop.login1.hibernate-multiple-sessions",
2260 "org.freedesktop.login1.hibernate-ignore-inhibit",
2264 return bus_send_error_reply(connection, message, &error, r);
2266 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHybridSleep")) {
2267 r = bus_manager_can_shutdown_or_sleep(
2268 m, connection, message,
2270 "org.freedesktop.login1.hibernate",
2271 "org.freedesktop.login1.hibernate-multiple-sessions",
2272 "org.freedesktop.login1.hibernate-ignore-inhibit",
2276 return bus_send_error_reply(connection, message, &error, r);
2278 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2279 char *introspection = NULL;
2288 if (!(reply = dbus_message_new_method_return(message)))
2291 /* We roll our own introspection code here, instead of
2292 * relying on bus_default_message_handler() because we
2293 * need to generate our introspection string
2296 if (!(f = open_memstream(&introspection, &size)))
2299 fputs(INTROSPECTION_BEGIN, f);
2301 HASHMAP_FOREACH(seat, m->seats, i) {
2302 p = bus_path_escape(seat->id);
2305 fprintf(f, "<node name=\"seat/%s\"/>", p);
2310 HASHMAP_FOREACH(user, m->users, i)
2311 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2313 HASHMAP_FOREACH(session, m->sessions, i) {
2314 p = bus_path_escape(session->id);
2317 fprintf(f, "<node name=\"session/%s\"/>", p);
2322 fputs(INTROSPECTION_END, f);
2326 free(introspection);
2335 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2336 free(introspection);
2340 free(introspection);
2342 const BusBoundProperties bps[] = {
2343 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2346 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2350 if (!bus_maybe_send_reply(connection, message, reply))
2354 return DBUS_HANDLER_RESULT_HANDLED;
2357 dbus_error_free(&error);
2359 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2362 const DBusObjectPathVTable bus_manager_vtable = {
2363 .message_function = manager_message_handler
2366 DBusHandlerResult bus_message_filter(
2367 DBusConnection *connection,
2368 DBusMessage *message,
2371 Manager *m = userdata;
2378 dbus_error_init(&error);
2380 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
2383 if (!dbus_message_get_args(message, &error,
2384 DBUS_TYPE_STRING, &cgroup,
2386 log_error("Failed to parse Released message: %s", bus_error_message(&error));
2388 manager_cgroup_notify_empty(m, cgroup);
2390 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
2392 const char *path, *result, *unit;
2394 if (!dbus_message_get_args(message, &error,
2395 DBUS_TYPE_UINT32, &id,
2396 DBUS_TYPE_OBJECT_PATH, &path,
2397 DBUS_TYPE_STRING, &unit,
2398 DBUS_TYPE_STRING, &result,
2400 log_error("Failed to parse JobRemoved message: %s", bus_error_message(&error));
2402 else if (m->action_job && streq(m->action_job, path)) {
2403 log_info("Operation finished.");
2405 /* Tell people that they now may take a lock again */
2406 send_prepare_for(m, m->action_what, false);
2408 free(m->action_job);
2409 m->action_job = NULL;
2410 m->action_unit = NULL;
2415 dbus_error_free(&error);
2417 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2420 int manager_send_changed(Manager *manager, const char *properties) {
2421 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
2425 m = bus_properties_changed_new("/org/freedesktop/login1",
2426 "org.freedesktop.login1.Manager",
2431 if (!dbus_connection_send(manager->bus, m, NULL))
2437 int manager_dispatch_delayed(Manager *manager) {
2443 if (manager->action_what == 0 || manager->action_job)
2446 /* Continue delay? */
2447 if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0)) {
2449 if (manager->action_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC))
2452 log_info("Delay lock is active but inhibitor timeout is reached.");
2455 /* Actually do the operation */
2456 dbus_error_init(&error);
2457 r = execute_shutdown_or_sleep(manager, manager->action_what, manager->action_unit, &error);
2459 log_warning("Failed to send delayed message: %s", bus_error(&error, r));
2460 dbus_error_free(&error);
2462 manager->action_unit = NULL;
2463 manager->action_what = 0;