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=\"sevice\" 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);
356 t = session_type_from_string(type);
359 !dbus_message_iter_next(&iter) ||
360 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
363 dbus_message_iter_get_basic(&iter, &class);
367 c = session_class_from_string(class);
370 !dbus_message_iter_next(&iter) ||
371 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
374 dbus_message_iter_get_basic(&iter, &cseat);
379 seat = hashmap_get(m->seats, cseat);
384 if (!dbus_message_iter_next(&iter) ||
385 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
388 dbus_message_iter_get_basic(&iter, &vtnr);
390 if (!dbus_message_iter_next(&iter) ||
391 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
394 dbus_message_iter_get_basic(&iter, &tty);
396 if (tty_is_vc(tty)) {
401 else if (seat != m->vtconsole)
404 v = vtnr_from_tty(tty);
407 return v < 0 ? v : -EINVAL;
411 else if (vtnr != (uint32_t) v)
413 } else if (tty_is_console(tty)) {
417 else if (seat != m->vtconsole)
425 if (seat_can_multi_session(seat)) {
434 if (!dbus_message_iter_next(&iter) ||
435 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
438 dbus_message_iter_get_basic(&iter, &display);
440 if (!dbus_message_iter_next(&iter) ||
441 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
444 dbus_message_iter_get_basic(&iter, &remote);
446 if (!dbus_message_iter_next(&iter) ||
447 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
450 dbus_message_iter_get_basic(&iter, &remote_user);
452 if (!dbus_message_iter_next(&iter) ||
453 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
456 dbus_message_iter_get_basic(&iter, &remote_host);
458 if (!dbus_message_iter_next(&iter) ||
459 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
460 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
463 r = bus_parse_strv_iter(&iter, &controllers);
467 if (strv_contains(controllers, "systemd") ||
468 !dbus_message_iter_next(&iter) ||
469 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
470 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) {
475 r = bus_parse_strv_iter(&iter, &reset_controllers);
479 if (strv_contains(reset_controllers, "systemd") ||
480 !dbus_message_iter_next(&iter) ||
481 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) {
486 dbus_message_iter_get_basic(&iter, &kill_processes);
488 r = cg_pid_get_cgroup(leader, NULL, &cgroup);
492 r = manager_get_session_by_cgroup(m, cgroup, &session);
497 fifo_fd = session_create_fifo(session);
503 /* Session already exists, client is probably
504 * something like "su" which changes uid but
505 * is still the same audit session */
507 reply = dbus_message_new_method_return(message);
513 p = session_bus_path(session);
519 cseat = session->seat ? session->seat->id : "";
520 vtnr = session->vtnr;
523 b = dbus_message_append_args(
525 DBUS_TYPE_STRING, &session->id,
526 DBUS_TYPE_OBJECT_PATH, &p,
527 DBUS_TYPE_STRING, &session->user->runtime_path,
528 DBUS_TYPE_UNIX_FD, &fifo_fd,
529 DBUS_TYPE_STRING, &cseat,
530 DBUS_TYPE_UINT32, &vtnr,
531 DBUS_TYPE_BOOLEAN, &exists,
544 audit_session_from_pid(leader, &audit_id);
546 /* Keep our session IDs and the audit session IDs in sync */
548 if (asprintf(&id, "%lu", (unsigned long) audit_id) < 0) {
553 /* Wut? There's already a session by this name and we
554 * didn't find it above? Weird, then let's not trust
555 * the audit data and let's better register a new
557 if (hashmap_get(m->sessions, id)) {
570 if (asprintf(&id, "c%lu", ++m->session_counter) < 0) {
575 } while (hashmap_get(m->sessions, id));
578 r = manager_add_user_by_uid(m, uid, &user);
582 r = manager_add_session(m, user, id, &session);
586 session->leader = leader;
587 session->audit_id = audit_id;
590 session->remote = remote;
591 session->controllers = controllers;
592 session->reset_controllers = reset_controllers;
593 session->kill_processes = kill_processes;
594 session->vtnr = vtnr;
596 controllers = reset_controllers = NULL;
599 session->tty = strdup(tty);
606 if (!isempty(display)) {
607 session->display = strdup(display);
608 if (!session->display) {
614 if (!isempty(remote_user)) {
615 session->remote_user = strdup(remote_user);
616 if (!session->remote_user) {
622 if (!isempty(remote_host)) {
623 session->remote_host = strdup(remote_host);
624 if (!session->remote_host) {
630 if (!isempty(service)) {
631 session->service = strdup(service);
632 if (!session->service) {
638 fifo_fd = session_create_fifo(session);
645 r = seat_attach_session(seat, session);
650 r = session_start(session);
654 reply = dbus_message_new_method_return(message);
660 p = session_bus_path(session);
666 cseat = seat ? seat->id : "";
668 b = dbus_message_append_args(
670 DBUS_TYPE_STRING, &session->id,
671 DBUS_TYPE_OBJECT_PATH, &p,
672 DBUS_TYPE_STRING, &session->user->runtime_path,
673 DBUS_TYPE_UNIX_FD, &fifo_fd,
674 DBUS_TYPE_STRING, &cseat,
675 DBUS_TYPE_UINT32, &vtnr,
676 DBUS_TYPE_BOOLEAN, &exists,
691 session_add_to_gc_queue(session);
694 user_add_to_gc_queue(user);
699 static int bus_manager_inhibit(
701 DBusConnection *connection,
702 DBusMessage *message,
704 DBusMessage **_reply) {
708 const char *who, *why, *what, *mode;
714 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
722 if (!dbus_message_get_args(
725 DBUS_TYPE_STRING, &what,
726 DBUS_TYPE_STRING, &who,
727 DBUS_TYPE_STRING, &why,
728 DBUS_TYPE_STRING, &mode,
729 DBUS_TYPE_INVALID)) {
734 w = inhibit_what_from_string(what);
740 mm = inhibit_mode_from_string(mode);
746 /* Delay is only supported for shutdown/sleep */
747 if (mm == INHIBIT_DELAY && (w & ~(INHIBIT_SHUTDOWN|INHIBIT_SLEEP))) {
752 /* Don't allow taking delay locks while we are already
753 * executing the operation. We shouldn't create the impression
754 * that the lock was successful if the machine is about to go
755 * down/suspend any moment. */
756 if (m->action_what & w) {
761 r = verify_polkit(connection, message,
762 w == INHIBIT_SHUTDOWN ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
763 w == INHIBIT_SLEEP ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep" : "org.freedesktop.login1.inhibit-delay-sleep") :
764 w == INHIBIT_IDLE ? "org.freedesktop.login1.inhibit-block-idle" :
765 w == INHIBIT_HANDLE_POWER_KEY ? "org.freedesktop.login1.inhibit-handle-power-key" :
766 w == INHIBIT_HANDLE_SUSPEND_KEY ? "org.freedesktop.login1.inhibit-handle-suspend-key" :
767 w == INHIBIT_HANDLE_HIBERNATE_KEY ? "org.freedesktop.login1.inhibit-handle-hibernate-key" :
768 "org.freedesktop.login1.inhibit-handle-lid-switch",
773 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
774 if (ul == (unsigned long) -1) {
779 pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
789 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
793 } while (hashmap_get(m->inhibitors, id));
795 r = manager_add_inhibitor(m, id, &i);
805 i->why = strdup(why);
806 i->who = strdup(who);
808 if (!i->why || !i->who) {
813 fifo_fd = inhibitor_create_fifo(i);
819 reply = dbus_message_new_method_return(message);
825 if (!dbus_message_append_args(
827 DBUS_TYPE_UNIX_FD, &fifo_fd,
828 DBUS_TYPE_INVALID)) {
833 close_nointr_nofail(fifo_fd);
846 close_nointr_nofail(fifo_fd);
851 static int trigger_device(Manager *m, struct udev_device *d) {
852 struct udev_enumerate *e;
853 struct udev_list_entry *first, *item;
858 e = udev_enumerate_new(m->udev);
865 if (udev_enumerate_add_match_parent(e, d) < 0) {
871 if (udev_enumerate_scan_devices(e) < 0) {
876 first = udev_enumerate_get_list_entry(e);
877 udev_list_entry_foreach(item, first) {
881 p = udev_list_entry_get_name(item);
883 t = strappend(p, "/uevent");
889 write_one_line_file(t, "change");
897 udev_enumerate_unref(e);
902 static int attach_device(Manager *m, const char *seat, const char *sysfs) {
903 struct udev_device *d;
904 char _cleanup_free_ *rule = NULL, *file = NULL;
905 const char *id_for_seat;
912 d = udev_device_new_from_syspath(m->udev, sysfs);
916 if (!udev_device_has_tag(d, "seat")) {
921 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
927 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
932 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
937 mkdir_p_label("/etc/udev/rules.d", 0755);
939 r = write_one_line_file_atomic_label(file, rule);
943 r = trigger_device(m, d);
947 udev_device_unref(d);
952 static int flush_devices(Manager *m) {
953 DIR _cleanup_closedir_ *d;
957 d = opendir("/etc/udev/rules.d");
960 log_warning("Failed to open /etc/udev/rules.d: %m");
964 while ((de = readdir(d))) {
966 if (!dirent_is_file(de))
969 if (!startswith(de->d_name, "72-seat-"))
972 if (!endswith(de->d_name, ".rules"))
975 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
976 log_warning("Failed to unlink %s: %m", de->d_name);
980 return trigger_device(m, NULL);
983 static int have_multiple_sessions(
992 /* Check for other users' sessions. Greeter sessions do not
993 * count, and non-login sessions do not count either. */
994 HASHMAP_FOREACH(session, m->sessions, i)
995 if (session->class == SESSION_USER &&
996 (session->type == SESSION_TTY || session->type == SESSION_X11) &&
997 session->user->uid != uid)
1003 static int bus_manager_log_shutdown(
1006 const char *unit_name) {
1013 if (w != INHIBIT_SHUTDOWN)
1016 if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
1017 p = "MESSAGE=System is powering down.";
1018 q = "SHUTDOWN=power-off";
1019 } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
1020 p = "MESSAGE=System is halting.";
1021 q = "SHUTDOWN=halt";
1022 } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
1023 p = "MESSAGE=System is rebooting.";
1024 q = "SHUTDOWN=reboot";
1025 } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
1026 p = "MESSAGE=System is rebooting with kexec.";
1027 q = "SHUTDOWN=kexec";
1029 p = "MESSAGE=System is shutting down.";
1033 return log_struct(LOG_NOTICE, MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
1038 static int execute_shutdown_or_sleep(
1041 const char *unit_name,
1044 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1045 const char *mode = "replace-irreversibly", *p;
1051 assert(w < _INHIBIT_WHAT_MAX);
1054 bus_manager_log_shutdown(m, w, unit_name);
1056 r = bus_method_call_with_reply(
1058 "org.freedesktop.systemd1",
1059 "/org/freedesktop/systemd1",
1060 "org.freedesktop.systemd1.Manager",
1064 DBUS_TYPE_STRING, &unit_name,
1065 DBUS_TYPE_STRING, &mode,
1070 if (!dbus_message_get_args(
1073 DBUS_TYPE_OBJECT_PATH, &p,
1081 m->action_unit = unit_name;
1082 free(m->action_job);
1089 static int delay_shutdown_or_sleep(
1092 const char *unit_name) {
1096 assert(w < _INHIBIT_WHAT_MAX);
1099 m->action_timestamp = now(CLOCK_MONOTONIC);
1100 m->action_unit = unit_name;
1106 static int bus_manager_can_shutdown_or_sleep(
1108 DBusConnection *connection,
1109 DBusMessage *message,
1112 const char *action_multiple_sessions,
1113 const char *action_ignore_inhibit,
1114 const char *sleep_type,
1115 const char *sleep_disk_type,
1117 DBusMessage **_reply) {
1119 bool multiple_sessions, challenge, blocked, b;
1121 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1129 assert(w <= _INHIBIT_WHAT_MAX);
1131 assert(action_multiple_sessions);
1132 assert(action_ignore_inhibit);
1137 r = can_sleep(sleep_type);
1147 if (sleep_disk_type) {
1148 r = can_sleep_disk(sleep_disk_type);
1158 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1159 if (ul == (unsigned long) -1)
1162 r = have_multiple_sessions(m, (uid_t) ul);
1166 multiple_sessions = r > 0;
1167 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1169 if (multiple_sessions) {
1170 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1177 result = "challenge";
1183 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1187 if (r > 0 && !result)
1189 else if (challenge && (!result || streq(result, "yes")))
1190 result = "challenge";
1195 if (!multiple_sessions && !blocked) {
1196 /* If neither inhibit nor multiple sessions
1197 * apply then just check the normal policy */
1199 r = verify_polkit(connection, message, action, false, &challenge, error);
1206 result = "challenge";
1212 reply = dbus_message_new_method_return(message);
1216 b = dbus_message_append_args(
1218 DBUS_TYPE_STRING, &result,
1228 static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
1229 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
1230 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
1231 [INHIBIT_SLEEP] = "PrepareForSleep"
1234 dbus_bool_t active = _active;
1235 _cleanup_dbus_message_unref_ DBusMessage *message = NULL;
1239 assert(w < _INHIBIT_WHAT_MAX);
1240 assert(signal_name[w]);
1242 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1246 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1247 !dbus_connection_send(m->bus, message, NULL))
1253 int bus_manager_shutdown_or_sleep_now_or_later(
1255 const char *unit_name,
1265 assert(w <= _INHIBIT_WHAT_MAX);
1266 assert(!m->action_job);
1268 /* Tell everybody to prepare for shutdown/sleep */
1269 send_prepare_for(m, w, true);
1272 m->inhibit_delay_max > 0 &&
1273 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0);
1276 /* Shutdown is delayed, keep in mind what we
1277 * want to do, and start a timeout */
1278 r = delay_shutdown_or_sleep(m, w, unit_name);
1280 /* Shutdown is not delayed, execute it
1282 r = execute_shutdown_or_sleep(m, w, unit_name, error);
1287 static int bus_manager_do_shutdown_or_sleep(
1289 DBusConnection *connection,
1290 DBusMessage *message,
1291 const char *unit_name,
1294 const char *action_multiple_sessions,
1295 const char *action_ignore_inhibit,
1296 const char *sleep_type,
1297 const char *sleep_disk_type,
1299 DBusMessage **_reply) {
1301 dbus_bool_t interactive;
1302 bool multiple_sessions, blocked;
1303 DBusMessage *reply = NULL;
1312 assert(w <= _INHIBIT_WHAT_MAX);
1314 assert(action_multiple_sessions);
1315 assert(action_ignore_inhibit);
1319 /* Don't allow multiple jobs being executed at the same time */
1323 if (!dbus_message_get_args(
1326 DBUS_TYPE_BOOLEAN, &interactive,
1331 r = can_sleep(sleep_type);
1339 if (sleep_disk_type) {
1340 r = can_sleep_disk(sleep_disk_type);
1348 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1349 if (ul == (unsigned long) -1)
1352 r = have_multiple_sessions(m, (uid_t) ul);
1356 multiple_sessions = r > 0;
1357 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1359 if (multiple_sessions) {
1360 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1366 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1371 if (!multiple_sessions && !blocked) {
1372 r = verify_polkit(connection, message, action, interactive, NULL, error);
1377 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
1381 reply = dbus_message_new_method_return(message);
1389 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_action, handle_action, HandleAction);
1391 static const BusProperty bus_login_manager_properties[] = {
1392 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_path), true },
1393 { "Controllers", bus_property_append_strv, "as", offsetof(Manager, controllers), true },
1394 { "ResetControllers", bus_property_append_strv, "as", offsetof(Manager, reset_controllers), true },
1395 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1396 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1397 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1398 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1399 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1400 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1401 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
1402 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1403 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1404 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
1405 { "HandlePowerKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_power_key) },
1406 { "HandleSuspendKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_suspend_key) },
1407 { "HandleHibernateKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_hibernate_key)},
1408 { "HandleLidSwitch", bus_manager_append_handle_action, "s", offsetof(Manager, handle_lid_switch) },
1409 { "IdleAction", bus_manager_append_handle_action, "s", offsetof(Manager, idle_action) },
1410 { "IdleActionUSec", bus_property_append_usec, "t", offsetof(Manager, idle_action_usec) },
1411 { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
1412 { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
1416 static DBusHandlerResult manager_message_handler(
1417 DBusConnection *connection,
1418 DBusMessage *message,
1421 Manager *m = userdata;
1424 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1431 dbus_error_init(&error);
1433 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1439 if (!dbus_message_get_args(
1442 DBUS_TYPE_STRING, &name,
1444 return bus_send_error_reply(connection, message, &error, -EINVAL);
1446 session = hashmap_get(m->sessions, name);
1448 return bus_send_error_reply(connection, message, &error, -ENOENT);
1450 reply = dbus_message_new_method_return(message);
1454 p = session_bus_path(session);
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", "GetSessionByPID")) {
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_session_by_pid(m, pid, &session);
1482 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1484 reply = dbus_message_new_method_return(message);
1488 p = session_bus_path(session);
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", "GetUser")) {
1507 if (!dbus_message_get_args(
1510 DBUS_TYPE_UINT32, &uid,
1512 return bus_send_error_reply(connection, message, &error, -EINVAL);
1514 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1516 return bus_send_error_reply(connection, message, &error, -ENOENT);
1518 reply = dbus_message_new_method_return(message);
1522 p = user_bus_path(user);
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", "GetSeat")) {
1541 if (!dbus_message_get_args(
1544 DBUS_TYPE_STRING, &name,
1546 return bus_send_error_reply(connection, message, &error, -EINVAL);
1548 seat = hashmap_get(m->seats, name);
1550 return bus_send_error_reply(connection, message, &error, -ENOENT);
1552 reply = dbus_message_new_method_return(message);
1556 p = seat_bus_path(seat);
1560 b = dbus_message_append_args(
1562 DBUS_TYPE_OBJECT_PATH, &p,
1569 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1573 DBusMessageIter iter, sub;
1574 const char *empty = "";
1576 reply = dbus_message_new_method_return(message);
1580 dbus_message_iter_init_append(reply, &iter);
1582 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1585 HASHMAP_FOREACH(session, m->sessions, i) {
1586 DBusMessageIter sub2;
1589 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1592 uid = session->user->uid;
1594 p = session_bus_path(session);
1598 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1599 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1600 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1601 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1602 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1609 if (!dbus_message_iter_close_container(&sub, &sub2))
1613 if (!dbus_message_iter_close_container(&iter, &sub))
1616 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1620 DBusMessageIter iter, sub;
1622 reply = dbus_message_new_method_return(message);
1626 dbus_message_iter_init_append(reply, &iter);
1628 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1631 HASHMAP_FOREACH(user, m->users, i) {
1632 DBusMessageIter sub2;
1635 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1640 p = user_bus_path(user);
1644 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1645 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1646 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1653 if (!dbus_message_iter_close_container(&sub, &sub2))
1657 if (!dbus_message_iter_close_container(&iter, &sub))
1660 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1664 DBusMessageIter iter, sub;
1666 reply = dbus_message_new_method_return(message);
1670 dbus_message_iter_init_append(reply, &iter);
1672 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1675 HASHMAP_FOREACH(seat, m->seats, i) {
1676 DBusMessageIter sub2;
1678 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1681 p = seat_bus_path(seat);
1685 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1686 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1693 if (!dbus_message_iter_close_container(&sub, &sub2))
1697 if (!dbus_message_iter_close_container(&iter, &sub))
1700 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1701 Inhibitor *inhibitor;
1703 DBusMessageIter iter, sub;
1705 reply = dbus_message_new_method_return(message);
1709 dbus_message_iter_init_append(reply, &iter);
1711 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1714 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1715 DBusMessageIter sub2;
1716 dbus_uint32_t uid, pid;
1717 const char *what, *who, *why, *mode;
1719 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1722 what = strempty(inhibit_what_to_string(inhibitor->what));
1723 who = strempty(inhibitor->who);
1724 why = strempty(inhibitor->why);
1725 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
1726 uid = (dbus_uint32_t) inhibitor->uid;
1727 pid = (dbus_uint32_t) inhibitor->pid;
1729 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1730 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1731 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1732 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
1733 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1734 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1737 if (!dbus_message_iter_close_container(&sub, &sub2))
1741 if (!dbus_message_iter_close_container(&iter, &sub))
1744 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1746 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1749 return bus_send_error_reply(connection, message, &error, r);
1752 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1754 r = bus_manager_create_session(m, message, &reply);
1756 /* Don't delay the work on OOM here, since it might be
1757 * triggered by a low RLIMIT_NOFILE here (since we
1758 * send a dupped fd to the client), and we'd rather
1759 * see this fail quickly then be retried later */
1762 return bus_send_error_reply(connection, message, NULL, r);
1764 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1768 if (!dbus_message_get_args(
1771 DBUS_TYPE_STRING, &name,
1773 return bus_send_error_reply(connection, message, &error, -EINVAL);
1775 session = hashmap_get(m->sessions, name);
1777 return bus_send_error_reply(connection, message, &error, -ENOENT);
1779 /* We use the FIFO to detect stray sessions where the
1780 process invoking PAM dies abnormally. We need to make
1781 sure that that process is not killed if at the clean
1782 end of the session it closes the FIFO. Hence, with
1783 this call explicitly turn off the FIFO logic, so that
1784 the PAM code can finish clean up on its own */
1785 session_remove_fifo(session);
1787 reply = dbus_message_new_method_return(message);
1791 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1795 if (!dbus_message_get_args(
1798 DBUS_TYPE_STRING, &name,
1800 return bus_send_error_reply(connection, message, &error, -EINVAL);
1802 session = hashmap_get(m->sessions, name);
1804 return bus_send_error_reply(connection, message, &error, -ENOENT);
1806 r = session_activate(session);
1808 return bus_send_error_reply(connection, message, NULL, r);
1810 reply = dbus_message_new_method_return(message);
1814 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1815 const char *session_name, *seat_name;
1819 /* Same as ActivateSession() but refuses to work if
1820 * the seat doesn't match */
1822 if (!dbus_message_get_args(
1825 DBUS_TYPE_STRING, &session_name,
1826 DBUS_TYPE_STRING, &seat_name,
1828 return bus_send_error_reply(connection, message, &error, -EINVAL);
1830 session = hashmap_get(m->sessions, session_name);
1832 return bus_send_error_reply(connection, message, &error, -ENOENT);
1834 seat = hashmap_get(m->seats, seat_name);
1836 return bus_send_error_reply(connection, message, &error, -ENOENT);
1838 if (session->seat != seat)
1839 return bus_send_error_reply(connection, message, &error, -EINVAL);
1841 r = session_activate(session);
1843 return bus_send_error_reply(connection, message, NULL, r);
1845 reply = dbus_message_new_method_return(message);
1849 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1850 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1854 if (!dbus_message_get_args(
1857 DBUS_TYPE_STRING, &name,
1859 return bus_send_error_reply(connection, message, &error, -EINVAL);
1861 session = hashmap_get(m->sessions, name);
1863 return bus_send_error_reply(connection, message, NULL, -ENOENT);
1865 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1868 reply = dbus_message_new_method_return(message);
1872 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions") ||
1873 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSessions")) {
1875 r = session_send_lock_all(m, streq(dbus_message_get_member(message), "LockSessions"));
1877 bus_send_error_reply(connection, message, NULL, r);
1879 reply = dbus_message_new_method_return(message);
1883 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1890 if (!dbus_message_get_args(
1893 DBUS_TYPE_STRING, &name,
1894 DBUS_TYPE_STRING, &swho,
1895 DBUS_TYPE_INT32, &signo,
1897 return bus_send_error_reply(connection, message, &error, -EINVAL);
1902 who = kill_who_from_string(swho);
1904 return bus_send_error_reply(connection, message, &error, -EINVAL);
1907 if (signo <= 0 || signo >= _NSIG)
1908 return bus_send_error_reply(connection, message, &error, -EINVAL);
1910 session = hashmap_get(m->sessions, name);
1912 return bus_send_error_reply(connection, message, &error, -ENOENT);
1914 r = session_kill(session, who, signo);
1916 return bus_send_error_reply(connection, message, NULL, r);
1918 reply = dbus_message_new_method_return(message);
1922 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1927 if (!dbus_message_get_args(
1930 DBUS_TYPE_UINT32, &uid,
1931 DBUS_TYPE_INT32, &signo,
1933 return bus_send_error_reply(connection, message, &error, -EINVAL);
1935 if (signo <= 0 || signo >= _NSIG)
1936 return bus_send_error_reply(connection, message, &error, -EINVAL);
1938 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1940 return bus_send_error_reply(connection, message, &error, -ENOENT);
1942 r = user_kill(user, signo);
1944 return bus_send_error_reply(connection, message, NULL, r);
1946 reply = dbus_message_new_method_return(message);
1950 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1954 if (!dbus_message_get_args(
1957 DBUS_TYPE_STRING, &name,
1959 return bus_send_error_reply(connection, message, &error, -EINVAL);
1961 session = hashmap_get(m->sessions, name);
1963 return bus_send_error_reply(connection, message, &error, -ENOENT);
1965 r = session_stop(session);
1967 return bus_send_error_reply(connection, message, NULL, r);
1969 reply = dbus_message_new_method_return(message);
1973 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1977 if (!dbus_message_get_args(
1980 DBUS_TYPE_UINT32, &uid,
1982 return bus_send_error_reply(connection, message, &error, -EINVAL);
1984 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1986 return bus_send_error_reply(connection, message, &error, -ENOENT);
1988 r = user_stop(user);
1990 return bus_send_error_reply(connection, message, NULL, r);
1992 reply = dbus_message_new_method_return(message);
1996 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
2000 if (!dbus_message_get_args(
2003 DBUS_TYPE_STRING, &name,
2005 return bus_send_error_reply(connection, message, &error, -EINVAL);
2007 seat = hashmap_get(m->seats, name);
2009 return bus_send_error_reply(connection, message, &error, -ENOENT);
2011 r = seat_stop_sessions(seat);
2013 return bus_send_error_reply(connection, message, NULL, r);
2015 reply = dbus_message_new_method_return(message);
2019 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
2022 dbus_bool_t b, interactive;
2025 if (!dbus_message_get_args(
2028 DBUS_TYPE_UINT32, &uid,
2029 DBUS_TYPE_BOOLEAN, &b,
2030 DBUS_TYPE_BOOLEAN, &interactive,
2032 return bus_send_error_reply(connection, message, &error, -EINVAL);
2037 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
2039 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
2041 return bus_send_error_reply(connection, message, &error, r);
2043 mkdir_p_label("/var/lib/systemd", 0755);
2045 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
2047 return bus_send_error_reply(connection, message, &error, r);
2049 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
2060 return bus_send_error_reply(connection, message, &error, r);
2062 if (manager_add_user_by_uid(m, uid, &u) >= 0)
2071 if (r < 0 && errno != ENOENT)
2072 return bus_send_error_reply(connection, message, &error, -errno);
2074 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
2076 user_add_to_gc_queue(u);
2079 reply = dbus_message_new_method_return(message);
2083 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
2084 const char *sysfs, *seat;
2085 dbus_bool_t interactive;
2087 if (!dbus_message_get_args(
2090 DBUS_TYPE_STRING, &seat,
2091 DBUS_TYPE_STRING, &sysfs,
2092 DBUS_TYPE_BOOLEAN, &interactive,
2094 return bus_send_error_reply(connection, message, &error, -EINVAL);
2096 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
2097 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2099 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
2101 return bus_send_error_reply(connection, message, &error, r);
2103 r = attach_device(m, seat, sysfs);
2105 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2107 reply = dbus_message_new_method_return(message);
2112 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
2113 dbus_bool_t interactive;
2115 if (!dbus_message_get_args(
2118 DBUS_TYPE_BOOLEAN, &interactive,
2120 return bus_send_error_reply(connection, message, &error, -EINVAL);
2122 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
2124 return bus_send_error_reply(connection, message, &error, r);
2126 r = flush_devices(m);
2128 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2130 reply = dbus_message_new_method_return(message);
2134 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
2136 r = bus_manager_do_shutdown_or_sleep(
2137 m, connection, message,
2138 SPECIAL_POWEROFF_TARGET,
2140 "org.freedesktop.login1.power-off",
2141 "org.freedesktop.login1.power-off-multiple-sessions",
2142 "org.freedesktop.login1.power-off-ignore-inhibit",
2146 return bus_send_error_reply(connection, message, &error, r);
2147 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
2148 r = bus_manager_do_shutdown_or_sleep(
2149 m, connection, message,
2150 SPECIAL_REBOOT_TARGET,
2152 "org.freedesktop.login1.reboot",
2153 "org.freedesktop.login1.reboot-multiple-sessions",
2154 "org.freedesktop.login1.reboot-ignore-inhibit",
2158 return bus_send_error_reply(connection, message, &error, r);
2160 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2161 r = bus_manager_do_shutdown_or_sleep(
2162 m, connection, message,
2163 SPECIAL_SUSPEND_TARGET,
2165 "org.freedesktop.login1.suspend",
2166 "org.freedesktop.login1.suspend-multiple-sessions",
2167 "org.freedesktop.login1.suspend-ignore-inhibit",
2171 return bus_send_error_reply(connection, message, &error, r);
2172 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2173 r = bus_manager_do_shutdown_or_sleep(
2174 m, connection, message,
2175 SPECIAL_HIBERNATE_TARGET,
2177 "org.freedesktop.login1.hibernate",
2178 "org.freedesktop.login1.hibernate-multiple-sessions",
2179 "org.freedesktop.login1.hibernate-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", "HybridSleep")) {
2186 r = bus_manager_do_shutdown_or_sleep(
2187 m, connection, message,
2188 SPECIAL_HYBRID_SLEEP_TARGET,
2190 "org.freedesktop.login1.hibernate",
2191 "org.freedesktop.login1.hibernate-multiple-sessions",
2192 "org.freedesktop.login1.hibernate-ignore-inhibit",
2196 return bus_send_error_reply(connection, message, &error, r);
2198 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2200 r = bus_manager_can_shutdown_or_sleep(
2201 m, connection, message,
2203 "org.freedesktop.login1.power-off",
2204 "org.freedesktop.login1.power-off-multiple-sessions",
2205 "org.freedesktop.login1.power-off-ignore-inhibit",
2209 return bus_send_error_reply(connection, message, &error, r);
2210 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2211 r = bus_manager_can_shutdown_or_sleep(
2212 m, connection, message,
2214 "org.freedesktop.login1.reboot",
2215 "org.freedesktop.login1.reboot-multiple-sessions",
2216 "org.freedesktop.login1.reboot-ignore-inhibit",
2220 return bus_send_error_reply(connection, message, &error, r);
2222 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2223 r = bus_manager_can_shutdown_or_sleep(
2224 m, connection, message,
2226 "org.freedesktop.login1.suspend",
2227 "org.freedesktop.login1.suspend-multiple-sessions",
2228 "org.freedesktop.login1.suspend-ignore-inhibit",
2232 return bus_send_error_reply(connection, message, &error, r);
2234 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2235 r = bus_manager_can_shutdown_or_sleep(
2236 m, connection, message,
2238 "org.freedesktop.login1.hibernate",
2239 "org.freedesktop.login1.hibernate-multiple-sessions",
2240 "org.freedesktop.login1.hibernate-ignore-inhibit",
2244 return bus_send_error_reply(connection, message, &error, r);
2246 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHybridSleep")) {
2247 r = bus_manager_can_shutdown_or_sleep(
2248 m, connection, message,
2250 "org.freedesktop.login1.hibernate",
2251 "org.freedesktop.login1.hibernate-multiple-sessions",
2252 "org.freedesktop.login1.hibernate-ignore-inhibit",
2256 return bus_send_error_reply(connection, message, &error, r);
2258 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2259 char *introspection = NULL;
2268 if (!(reply = dbus_message_new_method_return(message)))
2271 /* We roll our own introspection code here, instead of
2272 * relying on bus_default_message_handler() because we
2273 * need to generate our introspection string
2276 if (!(f = open_memstream(&introspection, &size)))
2279 fputs(INTROSPECTION_BEGIN, f);
2281 HASHMAP_FOREACH(seat, m->seats, i) {
2282 p = bus_path_escape(seat->id);
2285 fprintf(f, "<node name=\"seat/%s\"/>", p);
2290 HASHMAP_FOREACH(user, m->users, i)
2291 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2293 HASHMAP_FOREACH(session, m->sessions, i) {
2294 p = bus_path_escape(session->id);
2297 fprintf(f, "<node name=\"session/%s\"/>", p);
2302 fputs(INTROSPECTION_END, f);
2306 free(introspection);
2315 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2316 free(introspection);
2320 free(introspection);
2322 const BusBoundProperties bps[] = {
2323 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2326 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2330 if (!bus_maybe_send_reply(connection, message, reply))
2334 return DBUS_HANDLER_RESULT_HANDLED;
2337 dbus_error_free(&error);
2339 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2342 const DBusObjectPathVTable bus_manager_vtable = {
2343 .message_function = manager_message_handler
2346 DBusHandlerResult bus_message_filter(
2347 DBusConnection *connection,
2348 DBusMessage *message,
2351 Manager *m = userdata;
2358 dbus_error_init(&error);
2360 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
2363 if (!dbus_message_get_args(message, &error,
2364 DBUS_TYPE_STRING, &cgroup,
2366 log_error("Failed to parse Released message: %s", bus_error_message(&error));
2368 manager_cgroup_notify_empty(m, cgroup);
2370 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
2372 const char *path, *result, *unit;
2374 if (!dbus_message_get_args(message, &error,
2375 DBUS_TYPE_UINT32, &id,
2376 DBUS_TYPE_OBJECT_PATH, &path,
2377 DBUS_TYPE_STRING, &unit,
2378 DBUS_TYPE_STRING, &result,
2380 log_error("Failed to parse JobRemoved message: %s", bus_error_message(&error));
2382 else if (m->action_job && streq(m->action_job, path)) {
2384 log_info("Operation finished.");
2386 /* Tell people that they now may take a lock again */
2387 send_prepare_for(m, m->action_what, false);
2389 free(m->action_job);
2390 m->action_job = NULL;
2391 m->action_unit = NULL;
2396 dbus_error_free(&error);
2398 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2401 int manager_send_changed(Manager *manager, const char *properties) {
2402 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
2406 m = bus_properties_changed_new("/org/freedesktop/login1",
2407 "org.freedesktop.login1.Manager",
2412 if (!dbus_connection_send(manager->bus, m, NULL))
2418 int manager_dispatch_delayed(Manager *manager) {
2424 if (!manager->action_unit || manager->action_job)
2427 /* Continue delay? */
2428 if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0)) {
2430 if (manager->action_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC))
2433 log_info("Delay lock is active but inhibitor timeout is reached.");
2436 /* Actually do the operation */
2437 dbus_error_init(&error);
2438 r = execute_shutdown_or_sleep(manager, manager->action_what, manager->action_unit, &error);
2440 log_warning("Failed to send delayed message: %s", bus_error_message_or_strerror(&error, -r));
2441 dbus_error_free(&error);
2443 manager->action_unit = NULL;
2444 manager->action_what = 0;