1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
28 #include "dbus-common.h"
31 #include "path-util.h"
34 #include "systemd/sd-id128.h"
35 #include "systemd/sd-messages.h"
37 #define BUS_MANAGER_INTERFACE \
38 " <interface name=\"org.freedesktop.login1.Manager\">\n" \
39 " <method name=\"GetSession\">\n" \
40 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
41 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
43 " <method name=\"GetSessionByPID\">\n" \
44 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
45 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
47 " <method name=\"GetUser\">\n" \
48 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
49 " <arg name=\"user\" type=\"o\" direction=\"out\"/>\n" \
51 " <method name=\"GetSeat\">\n" \
52 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
53 " <arg name=\"seat\" type=\"o\" direction=\"out\"/>\n" \
55 " <method name=\"ListSessions\">\n" \
56 " <arg name=\"sessions\" type=\"a(susso)\" direction=\"out\"/>\n" \
58 " <method name=\"ListUsers\">\n" \
59 " <arg name=\"users\" type=\"a(uso)\" direction=\"out\"/>\n" \
61 " <method name=\"ListSeats\">\n" \
62 " <arg name=\"seats\" type=\"a(so)\" direction=\"out\"/>\n" \
64 " <method name=\"CreateSession\">\n" \
65 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
66 " <arg name=\"leader\" type=\"u\" direction=\"in\"/>\n" \
67 " <arg name=\"sevice\" type=\"s\" direction=\"in\"/>\n" \
68 " <arg name=\"type\" type=\"s\" direction=\"in\"/>\n" \
69 " <arg name=\"class\" type=\"s\" direction=\"in\"/>\n" \
70 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
71 " <arg name=\"vtnr\" type=\"u\" direction=\"in\"/>\n" \
72 " <arg name=\"tty\" type=\"s\" direction=\"in\"/>\n" \
73 " <arg name=\"display\" type=\"s\" direction=\"in\"/>\n" \
74 " <arg name=\"remote\" type=\"b\" direction=\"in\"/>\n" \
75 " <arg name=\"remote_user\" type=\"s\" direction=\"in\"/>\n" \
76 " <arg name=\"remote_host\" type=\"s\" direction=\"in\"/>\n" \
77 " <arg name=\"controllers\" type=\"as\" direction=\"in\"/>\n" \
78 " <arg name=\"reset_controllers\" type=\"as\" direction=\"in\"/>\n" \
79 " <arg name=\"kill_processes\" type=\"b\" direction=\"in\"/>\n" \
80 " <arg name=\"id\" type=\"s\" direction=\"out\"/>\n" \
81 " <arg name=\"path\" type=\"o\" direction=\"out\"/>\n" \
82 " <arg name=\"runtime_path\" type=\"o\" direction=\"out\"/>\n" \
83 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
84 " <arg name=\"seat\" type=\"s\" direction=\"out\"/>\n" \
85 " <arg name=\"vtnr\" type=\"u\" direction=\"out\"/>\n" \
87 " <method name=\"ReleaseSession\">\n" \
88 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
90 " <method name=\"ActivateSession\">\n" \
91 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
93 " <method name=\"ActivateSessionOnSeat\">\n" \
94 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
95 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
97 " <method name=\"LockSession\">\n" \
98 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
100 " <method name=\"UnlockSession\">\n" \
101 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
103 " <method name=\"LockSessions\"/>\n" \
104 " <method name=\"KillSession\">\n" \
105 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
106 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
107 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
109 " <method name=\"KillUser\">\n" \
110 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
111 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
113 " <method name=\"TerminateSession\">\n" \
114 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
116 " <method name=\"TerminateUser\">\n" \
117 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
119 " <method name=\"TerminateSeat\">\n" \
120 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
122 " <method name=\"SetUserLinger\">\n" \
123 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
124 " <arg name=\"b\" type=\"b\" direction=\"in\"/>\n" \
125 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
127 " <method name=\"AttachDevice\">\n" \
128 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
129 " <arg name=\"sysfs\" type=\"s\" direction=\"in\"/>\n" \
130 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
132 " <method name=\"FlushDevices\">\n" \
133 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
135 " <method name=\"PowerOff\">\n" \
136 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
138 " <method name=\"Reboot\">\n" \
139 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
141 " <method name=\"Suspend\">\n" \
142 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
144 " <method name=\"Hibernate\">\n" \
145 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
147 " <method name=\"CanPowerOff\">\n" \
148 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
150 " <method name=\"CanReboot\">\n" \
151 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
153 " <method name=\"CanSuspend\">\n" \
154 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
156 " <method name=\"CanHibernate\">\n" \
157 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
159 " <method name=\"Inhibit\">\n" \
160 " <arg name=\"what\" type=\"s\" direction=\"in\"/>\n" \
161 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
162 " <arg name=\"why\" type=\"s\" direction=\"in\"/>\n" \
163 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
164 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
166 " <method name=\"ListInhibitors\">\n" \
167 " <arg name=\"inhibitors\" type=\"a(ssssuu)\" direction=\"out\"/>\n" \
169 " <signal name=\"SessionNew\">\n" \
170 " <arg name=\"id\" type=\"s\"/>\n" \
171 " <arg name=\"path\" type=\"o\"/>\n" \
173 " <signal name=\"SessionRemoved\">\n" \
174 " <arg name=\"id\" type=\"s\"/>\n" \
175 " <arg name=\"path\" type=\"o\"/>\n" \
177 " <signal name=\"UserNew\">\n" \
178 " <arg name=\"uid\" type=\"u\"/>\n" \
179 " <arg name=\"path\" type=\"o\"/>\n" \
181 " <signal name=\"UserRemoved\">\n" \
182 " <arg name=\"uid\" type=\"u\"/>\n" \
183 " <arg name=\"path\" type=\"o\"/>\n" \
185 " <signal name=\"SeatNew\">\n" \
186 " <arg name=\"id\" type=\"s\"/>\n" \
187 " <arg name=\"path\" type=\"o\"/>\n" \
189 " <signal name=\"SeatRemoved\">\n" \
190 " <arg name=\"id\" type=\"s\"/>\n" \
191 " <arg name=\"path\" type=\"o\"/>\n" \
193 " <signal name=\"PrepareForShutdown\">\n" \
194 " <arg name=\"active\" type=\"b\"/>\n" \
196 " <signal name=\"PrepareForSleep\">\n" \
197 " <arg name=\"active\" type=\"b\"/>\n" \
199 " <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
200 " <property name=\"Controllers\" type=\"as\" access=\"read\"/>\n" \
201 " <property name=\"ResetControllers\" type=\"as\" access=\"read\"/>\n" \
202 " <property name=\"NAutoVTs\" type=\"u\" access=\"read\"/>\n" \
203 " <property name=\"KillOnlyUsers\" type=\"as\" access=\"read\"/>\n" \
204 " <property name=\"KillExcludeUsers\" type=\"as\" access=\"read\"/>\n" \
205 " <property name=\"KillUserProcesses\" type=\"b\" access=\"read\"/>\n" \
206 " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
207 " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
208 " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
209 " <property name=\"BlockInhibited\" type=\"s\" access=\"read\"/>\n" \
210 " <property name=\"DelayInhibited\" type=\"s\" access=\"read\"/>\n" \
211 " <property name=\"InhibitDelayMaxUSec\" type=\"t\" access=\"read\"/>\n" \
212 " <property name=\"HandlePowerKey\" type=\"s\" access=\"read\"/>\n" \
213 " <property name=\"HandleSuspendKey\" type=\"s\" access=\"read\"/>\n" \
214 " <property name=\"HandleHibernateKey\" type=\"s\" access=\"read\"/>\n" \
215 " <property name=\"HandleLidSwitch\" type=\"s\" access=\"read\"/>\n" \
216 " <property name=\"PreparingForShutdown\" type=\"b\" access=\"read\"/>\n" \
217 " <property name=\"PreparingForSleep\" type=\"b\" access=\"read\"/>\n" \
220 #define INTROSPECTION_BEGIN \
221 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
223 BUS_MANAGER_INTERFACE \
224 BUS_PROPERTIES_INTERFACE \
226 BUS_INTROSPECTABLE_INTERFACE
228 #define INTROSPECTION_END \
231 #define INTERFACES_LIST \
232 BUS_GENERIC_INTERFACES_LIST \
233 "org.freedesktop.login1.Manager\0"
235 static int bus_manager_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
243 b = manager_get_idle_hint(m, NULL) > 0;
244 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
250 static int bus_manager_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
259 manager_get_idle_hint(m, &t);
260 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
262 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
268 static int bus_manager_append_inhibited(DBusMessageIter *i, const char *property, void *data) {
273 w = manager_inhibit_what(m, streq(property, "BlockInhibited") ? INHIBIT_BLOCK : INHIBIT_DELAY);
274 p = inhibit_what_to_string(w);
276 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &p))
282 static int bus_manager_append_preparing(DBusMessageIter *i, const char *property, void *data) {
289 if (streq(property, "PreparingForShutdown"))
290 b = !!(m->delayed_what & INHIBIT_SHUTDOWN);
292 b = !!(m->delayed_what & INHIBIT_SLEEP);
294 dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b);
298 static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMessage **_reply) {
299 Session *session = NULL;
301 const char *type, *class, *seat, *tty, *display, *remote_user, *remote_host, *service;
302 uint32_t uid, leader, audit_id = 0;
303 dbus_bool_t remote, kill_processes;
304 char **controllers = NULL, **reset_controllers = NULL;
308 DBusMessageIter iter;
313 DBusMessage *reply = NULL;
320 if (!dbus_message_iter_init(message, &iter) ||
321 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
324 dbus_message_iter_get_basic(&iter, &uid);
326 if (!dbus_message_iter_next(&iter) ||
327 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
330 dbus_message_iter_get_basic(&iter, &leader);
333 !dbus_message_iter_next(&iter) ||
334 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
337 dbus_message_iter_get_basic(&iter, &service);
339 if (!dbus_message_iter_next(&iter) ||
340 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
343 dbus_message_iter_get_basic(&iter, &type);
344 t = session_type_from_string(type);
347 !dbus_message_iter_next(&iter) ||
348 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
351 dbus_message_iter_get_basic(&iter, &class);
355 c = session_class_from_string(class);
358 !dbus_message_iter_next(&iter) ||
359 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
362 dbus_message_iter_get_basic(&iter, &seat);
367 s = hashmap_get(m->seats, seat);
372 if (!dbus_message_iter_next(&iter) ||
373 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
376 dbus_message_iter_get_basic(&iter, &vtnr);
378 if (!dbus_message_iter_next(&iter) ||
379 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
382 dbus_message_iter_get_basic(&iter, &tty);
384 if (tty_is_vc(tty)) {
389 else if (s != m->vtconsole)
392 v = vtnr_from_tty(tty);
395 return v < 0 ? v : -EINVAL;
399 else if (vtnr != (uint32_t) v)
401 } else if (tty_is_console(tty)) {
405 else if (s != m->vtconsole)
411 } else if (!isempty(tty) && s && seat_is_vtconsole(s))
415 if (seat_can_multi_session(s)) {
424 if (!dbus_message_iter_next(&iter) ||
425 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
428 dbus_message_iter_get_basic(&iter, &display);
430 if (!dbus_message_iter_next(&iter) ||
431 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
434 dbus_message_iter_get_basic(&iter, &remote);
436 if (!dbus_message_iter_next(&iter) ||
437 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
440 dbus_message_iter_get_basic(&iter, &remote_user);
442 if (!dbus_message_iter_next(&iter) ||
443 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
446 dbus_message_iter_get_basic(&iter, &remote_host);
448 if (!dbus_message_iter_next(&iter) ||
449 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
450 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
453 r = bus_parse_strv_iter(&iter, &controllers);
457 if (strv_contains(controllers, "systemd") ||
458 !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) {
465 r = bus_parse_strv_iter(&iter, &reset_controllers);
469 if (strv_contains(reset_controllers, "systemd") ||
470 !dbus_message_iter_next(&iter) ||
471 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) {
476 dbus_message_iter_get_basic(&iter, &kill_processes);
478 r = manager_add_user_by_uid(m, uid, &user);
482 audit_session_from_pid(leader, &audit_id);
485 asprintf(&id, "%lu", (unsigned long) audit_id);
492 session = hashmap_get(m->sessions, id);
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 seat = session->seat ? session->seat->id : "";
520 vtnr = session->vtnr;
521 b = dbus_message_append_args(
523 DBUS_TYPE_STRING, &session->id,
524 DBUS_TYPE_OBJECT_PATH, &p,
525 DBUS_TYPE_STRING, &session->user->runtime_path,
526 DBUS_TYPE_UNIX_FD, &fifo_fd,
527 DBUS_TYPE_STRING, &seat,
528 DBUS_TYPE_UINT32, &vtnr,
537 close_nointr_nofail(fifo_fd);
540 strv_free(controllers);
541 strv_free(reset_controllers);
551 if (asprintf(&id, "c%lu", ++m->session_counter) < 0) {
556 } while (hashmap_get(m->sessions, id));
559 r = manager_add_session(m, user, id, &session);
564 session->leader = leader;
565 session->audit_id = audit_id;
568 session->remote = remote;
569 session->controllers = controllers;
570 session->reset_controllers = reset_controllers;
571 session->kill_processes = kill_processes;
572 session->vtnr = vtnr;
574 controllers = reset_controllers = NULL;
577 session->tty = strdup(tty);
584 if (!isempty(display)) {
585 session->display = strdup(display);
586 if (!session->display) {
592 if (!isempty(remote_user)) {
593 session->remote_user = strdup(remote_user);
594 if (!session->remote_user) {
600 if (!isempty(remote_host)) {
601 session->remote_host = strdup(remote_host);
602 if (!session->remote_host) {
608 if (!isempty(service)) {
609 session->service = strdup(service);
610 if (!session->service) {
616 fifo_fd = session_create_fifo(session);
623 r = seat_attach_session(s, session);
628 r = session_start(session);
632 reply = dbus_message_new_method_return(message);
638 p = session_bus_path(session);
644 seat = s ? s->id : "";
645 b = dbus_message_append_args(
647 DBUS_TYPE_STRING, &session->id,
648 DBUS_TYPE_OBJECT_PATH, &p,
649 DBUS_TYPE_STRING, &session->user->runtime_path,
650 DBUS_TYPE_UNIX_FD, &fifo_fd,
651 DBUS_TYPE_STRING, &seat,
652 DBUS_TYPE_UINT32, &vtnr,
661 close_nointr_nofail(fifo_fd);
667 strv_free(controllers);
668 strv_free(reset_controllers);
671 session_add_to_gc_queue(session);
674 user_add_to_gc_queue(user);
677 close_nointr_nofail(fifo_fd);
680 dbus_message_unref(reply);
685 static int bus_manager_inhibit(Manager *m, DBusConnection *connection, DBusMessage *message, DBusError *error, DBusMessage **_reply) {
688 const char *who, *why, *what, *mode;
694 DBusMessage *reply = NULL;
702 if (!dbus_message_get_args(
705 DBUS_TYPE_STRING, &what,
706 DBUS_TYPE_STRING, &who,
707 DBUS_TYPE_STRING, &why,
708 DBUS_TYPE_STRING, &mode,
709 DBUS_TYPE_INVALID)) {
714 w = inhibit_what_from_string(what);
720 mm = inhibit_mode_from_string(mode);
726 /* Delay is only supported for shutdown/sleep */
727 if (mm == INHIBIT_DELAY && (w & ~(INHIBIT_SHUTDOWN|INHIBIT_SLEEP))) {
732 r = verify_polkit(connection, message,
733 w == INHIBIT_SHUTDOWN ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
734 w == INHIBIT_SLEEP ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep" : "org.freedesktop.login1.inhibit-delay-sleep") :
735 w == INHIBIT_IDLE ? "org.freedesktop.login1.inhibit-block-idle" :
736 w == INHIBIT_HANDLE_POWER_KEY ? "org.freedesktop.login1.inhibit-handle-power-key" :
737 w == INHIBIT_HANDLE_SUSPEND_KEY ? "org.freedesktop.login1.inhibit-handle-suspend-key" :
738 w == INHIBIT_HANDLE_HIBERNATE_KEY ? "org.freedesktop.login1.inhibit-handle-hibernate-key" :
739 "org.freedesktop.login1.inhibit-handle-lid-switch",
744 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
745 if (ul == (unsigned long) -1) {
750 pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
760 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
764 } while (hashmap_get(m->inhibitors, id));
766 r = manager_add_inhibitor(m, id, &i);
776 i->why = strdup(why);
777 i->who = strdup(who);
779 if (!i->why || !i->who) {
784 fifo_fd = inhibitor_create_fifo(i);
790 reply = dbus_message_new_method_return(message);
796 if (!dbus_message_append_args(
798 DBUS_TYPE_UNIX_FD, &fifo_fd,
799 DBUS_TYPE_INVALID)) {
804 close_nointr_nofail(fifo_fd);
816 close_nointr_nofail(fifo_fd);
819 dbus_message_unref(reply);
824 static int trigger_device(Manager *m, struct udev_device *d) {
825 struct udev_enumerate *e;
826 struct udev_list_entry *first, *item;
831 e = udev_enumerate_new(m->udev);
838 if (udev_enumerate_add_match_parent(e, d) < 0) {
844 if (udev_enumerate_scan_devices(e) < 0) {
849 first = udev_enumerate_get_list_entry(e);
850 udev_list_entry_foreach(item, first) {
854 p = udev_list_entry_get_name(item);
856 t = strappend(p, "/uevent");
862 write_one_line_file(t, "change");
870 udev_enumerate_unref(e);
875 static int attach_device(Manager *m, const char *seat, const char *sysfs) {
876 struct udev_device *d;
877 char *rule = NULL, *file = NULL;
878 const char *id_for_seat;
885 d = udev_device_new_from_syspath(m->udev, sysfs);
889 if (!udev_device_has_tag(d, "seat")) {
894 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
900 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
905 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
910 mkdir_p_label("/etc/udev/rules.d", 0755);
911 r = write_one_line_file_atomic(file, rule);
915 r = trigger_device(m, d);
922 udev_device_unref(d);
927 static int flush_devices(Manager *m) {
932 d = opendir("/etc/udev/rules.d");
935 log_warning("Failed to open /etc/udev/rules.d: %m");
939 while ((de = readdir(d))) {
941 if (!dirent_is_file(de))
944 if (!startswith(de->d_name, "72-seat-"))
947 if (!endswith(de->d_name, ".rules"))
950 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
951 log_warning("Failed to unlink %s: %m", de->d_name);
957 return trigger_device(m, NULL);
960 static int have_multiple_sessions(
969 /* Check for other users' sessions. Greeter sessions do not count. */
970 HASHMAP_FOREACH(session, m->sessions, i)
971 if (session->class == SESSION_USER && session->user->uid != uid)
977 static int send_start_unit(DBusConnection *connection, const char *unit_name, DBusError *error) {
978 const char *mode = "replace";
982 return bus_method_call_with_reply (
984 "org.freedesktop.systemd1",
985 "/org/freedesktop/systemd1",
986 "org.freedesktop.systemd1.Manager",
990 DBUS_TYPE_STRING, &unit_name,
991 DBUS_TYPE_STRING, &mode,
995 static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
996 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
997 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
998 [INHIBIT_SLEEP] = "PrepareForSleep"
1001 dbus_bool_t active = _active;
1002 DBusMessage *message;
1007 assert(w < _INHIBIT_WHAT_MAX);
1008 assert(signal_name[w]);
1010 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1014 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1015 !dbus_connection_send(m->bus, message, NULL))
1018 dbus_message_unref(message);
1022 static int delay_shutdown_or_sleep(Manager *m, InhibitWhat w, const char *unit_name) {
1025 assert(w < _INHIBIT_WHAT_MAX);
1027 /* Tell everybody to prepare for shutdown/sleep */
1028 send_prepare_for(m, w, true);
1030 /* Update timestamp for timeout */
1031 if (!m->delayed_unit)
1032 m->delayed_timestamp = now(CLOCK_MONOTONIC);
1034 /* Remember what we want to do, possibly overriding what kind
1035 * of unit we previously queued. */
1036 m->delayed_unit = unit_name;
1037 m->delayed_what = w;
1042 static int bus_manager_can_shutdown_or_sleep(
1044 DBusConnection *connection,
1045 DBusMessage *message,
1048 const char *action_multiple_sessions,
1049 const char *action_ignore_inhibit,
1050 const char *sleep_type,
1052 DBusMessage **_reply) {
1054 bool multiple_sessions, challenge, blocked, b;
1056 DBusMessage *reply = NULL;
1064 assert(w <= _INHIBIT_WHAT_MAX);
1066 assert(action_multiple_sessions);
1067 assert(action_ignore_inhibit);
1072 r = can_sleep(sleep_type);
1082 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1083 if (ul == (unsigned long) -1)
1086 r = have_multiple_sessions(m, (uid_t) ul);
1090 multiple_sessions = r > 0;
1091 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1093 if (multiple_sessions) {
1094 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1101 result = "challenge";
1107 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1111 if (r > 0 && !result)
1113 else if (challenge && (!result || streq(result, "yes")))
1114 result = "challenge";
1119 if (!multiple_sessions && !blocked) {
1120 /* If neither inhibit nor multiple sessions
1121 * apply then just check the normal policy */
1123 r = verify_polkit(connection, message, action, false, &challenge, error);
1130 result = "challenge";
1136 reply = dbus_message_new_method_return(message);
1140 b = dbus_message_append_args(
1142 DBUS_TYPE_STRING, &result,
1145 dbus_message_unref(reply);
1153 static int bus_manager_log_shutdown(
1156 const char *unit_name) {
1163 if (w != INHIBIT_SHUTDOWN)
1166 if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
1167 p = "MESSAGE=System is powering down.";
1168 q = "SHUTDOWN=power-off";
1169 } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
1170 p = "MESSAGE=System is halting.";
1171 q = "SHUTDOWN=halt";
1172 } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
1173 p = "MESSAGE=System is rebooting.";
1174 q = "SHUTDOWN=reboot";
1175 } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
1176 p = "MESSAGE=System is rebooting with kexec.";
1177 q = "SHUTDOWN=kexec";
1179 p = "MESSAGE=System is shutting down.";
1183 return log_struct(LOG_NOTICE,
1184 "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(SD_MESSAGE_SHUTDOWN),
1189 int bus_manager_shutdown_or_sleep_now_or_later(
1191 const char *unit_name,
1201 assert(w <= _INHIBIT_WHAT_MAX);
1204 m->inhibit_delay_max > 0 &&
1205 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0);
1208 /* Shutdown is delayed, keep in mind what we
1209 * want to do, and start a timeout */
1210 r = delay_shutdown_or_sleep(m, w, unit_name);
1212 bus_manager_log_shutdown(m, w, unit_name);
1214 /* Shutdown is not delayed, execute it
1216 r = send_start_unit(m->bus, unit_name, error);
1222 static int bus_manager_do_shutdown_or_sleep(
1224 DBusConnection *connection,
1225 DBusMessage *message,
1226 const char *unit_name,
1229 const char *action_multiple_sessions,
1230 const char *action_ignore_inhibit,
1231 const char *sleep_type,
1233 DBusMessage **_reply) {
1235 dbus_bool_t interactive;
1236 bool multiple_sessions, blocked;
1237 DBusMessage *reply = NULL;
1246 assert(w <= _INHIBIT_WHAT_MAX);
1248 assert(action_multiple_sessions);
1249 assert(action_ignore_inhibit);
1253 if (!dbus_message_get_args(
1256 DBUS_TYPE_BOOLEAN, &interactive,
1261 r = can_sleep(sleep_type);
1269 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1270 if (ul == (unsigned long) -1)
1273 r = have_multiple_sessions(m, (uid_t) ul);
1277 multiple_sessions = r > 0;
1278 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1280 if (multiple_sessions) {
1281 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1287 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1292 if (!multiple_sessions && !blocked) {
1293 r = verify_polkit(connection, message, action, interactive, NULL, error);
1298 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
1302 reply = dbus_message_new_method_return(message);
1310 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_button, handle_button, HandleButton);
1312 static const BusProperty bus_login_manager_properties[] = {
1313 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_path), true },
1314 { "Controllers", bus_property_append_strv, "as", offsetof(Manager, controllers), true },
1315 { "ResetControllers", bus_property_append_strv, "as", offsetof(Manager, reset_controllers), true },
1316 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1317 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1318 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1319 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1320 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1321 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1322 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
1323 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1324 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1325 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
1326 { "HandlePowerKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_power_key) },
1327 { "HandleSuspendKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_suspend_key) },
1328 { "HandleHibernateKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_hibernate_key)},
1329 { "HandleLidSwitch", bus_manager_append_handle_button, "s", offsetof(Manager, handle_lid_switch) },
1330 { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
1331 { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
1335 static DBusHandlerResult manager_message_handler(
1336 DBusConnection *connection,
1337 DBusMessage *message,
1340 Manager *m = userdata;
1343 DBusMessage *reply = NULL;
1350 dbus_error_init(&error);
1352 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1358 if (!dbus_message_get_args(
1361 DBUS_TYPE_STRING, &name,
1363 return bus_send_error_reply(connection, message, &error, -EINVAL);
1365 session = hashmap_get(m->sessions, name);
1367 return bus_send_error_reply(connection, message, &error, -ENOENT);
1369 reply = dbus_message_new_method_return(message);
1373 p = session_bus_path(session);
1377 b = dbus_message_append_args(
1379 DBUS_TYPE_OBJECT_PATH, &p,
1386 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1392 if (!dbus_message_get_args(
1395 DBUS_TYPE_UINT32, &pid,
1397 return bus_send_error_reply(connection, message, &error, -EINVAL);
1399 r = manager_get_session_by_pid(m, pid, &session);
1401 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1403 reply = dbus_message_new_method_return(message);
1407 p = session_bus_path(session);
1411 b = dbus_message_append_args(
1413 DBUS_TYPE_OBJECT_PATH, &p,
1420 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1426 if (!dbus_message_get_args(
1429 DBUS_TYPE_UINT32, &uid,
1431 return bus_send_error_reply(connection, message, &error, -EINVAL);
1433 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1435 return bus_send_error_reply(connection, message, &error, -ENOENT);
1437 reply = dbus_message_new_method_return(message);
1441 p = user_bus_path(user);
1445 b = dbus_message_append_args(
1447 DBUS_TYPE_OBJECT_PATH, &p,
1454 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1460 if (!dbus_message_get_args(
1463 DBUS_TYPE_STRING, &name,
1465 return bus_send_error_reply(connection, message, &error, -EINVAL);
1467 seat = hashmap_get(m->seats, name);
1469 return bus_send_error_reply(connection, message, &error, -ENOENT);
1471 reply = dbus_message_new_method_return(message);
1475 p = seat_bus_path(seat);
1479 b = dbus_message_append_args(
1481 DBUS_TYPE_OBJECT_PATH, &p,
1488 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1492 DBusMessageIter iter, sub;
1493 const char *empty = "";
1495 reply = dbus_message_new_method_return(message);
1499 dbus_message_iter_init_append(reply, &iter);
1501 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1504 HASHMAP_FOREACH(session, m->sessions, i) {
1505 DBusMessageIter sub2;
1508 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1511 uid = session->user->uid;
1513 p = session_bus_path(session);
1517 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1518 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1519 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1520 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1521 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1528 if (!dbus_message_iter_close_container(&sub, &sub2))
1532 if (!dbus_message_iter_close_container(&iter, &sub))
1535 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1539 DBusMessageIter iter, sub;
1541 reply = dbus_message_new_method_return(message);
1545 dbus_message_iter_init_append(reply, &iter);
1547 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1550 HASHMAP_FOREACH(user, m->users, i) {
1551 DBusMessageIter sub2;
1554 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1559 p = user_bus_path(user);
1563 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1564 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1565 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1572 if (!dbus_message_iter_close_container(&sub, &sub2))
1576 if (!dbus_message_iter_close_container(&iter, &sub))
1579 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1583 DBusMessageIter iter, sub;
1585 reply = dbus_message_new_method_return(message);
1589 dbus_message_iter_init_append(reply, &iter);
1591 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1594 HASHMAP_FOREACH(seat, m->seats, i) {
1595 DBusMessageIter sub2;
1597 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1600 p = seat_bus_path(seat);
1604 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1605 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1612 if (!dbus_message_iter_close_container(&sub, &sub2))
1616 if (!dbus_message_iter_close_container(&iter, &sub))
1619 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1620 Inhibitor *inhibitor;
1622 DBusMessageIter iter, sub;
1624 reply = dbus_message_new_method_return(message);
1628 dbus_message_iter_init_append(reply, &iter);
1630 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1633 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1634 DBusMessageIter sub2;
1635 dbus_uint32_t uid, pid;
1636 const char *what, *who, *why, *mode;
1638 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1641 what = strempty(inhibit_what_to_string(inhibitor->what));
1642 who = strempty(inhibitor->who);
1643 why = strempty(inhibitor->why);
1644 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
1645 uid = (dbus_uint32_t) inhibitor->uid;
1646 pid = (dbus_uint32_t) inhibitor->pid;
1648 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1649 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1650 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1651 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
1652 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1653 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1656 if (!dbus_message_iter_close_container(&sub, &sub2))
1660 if (!dbus_message_iter_close_container(&iter, &sub))
1663 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1665 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1668 return bus_send_error_reply(connection, message, &error, r);
1671 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1673 r = bus_manager_create_session(m, message, &reply);
1675 /* Don't delay the work on OOM here, since it might be
1676 * triggered by a low RLIMIT_NOFILE here (since we
1677 * send a dupped fd to the client), and we'd rather
1678 * see this fail quickly then be retried later */
1681 return bus_send_error_reply(connection, message, NULL, r);
1683 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1687 if (!dbus_message_get_args(
1690 DBUS_TYPE_STRING, &name,
1692 return bus_send_error_reply(connection, message, &error, -EINVAL);
1694 session = hashmap_get(m->sessions, name);
1696 return bus_send_error_reply(connection, message, &error, -ENOENT);
1698 /* We use the FIFO to detect stray sessions where the
1699 process invoking PAM dies abnormally. We need to make
1700 sure that that process is not killed if at the clean
1701 end of the session it closes the FIFO. Hence, with
1702 this call explicitly turn off the FIFO logic, so that
1703 the PAM code can finish clean up on its own */
1704 session_remove_fifo(session);
1706 reply = dbus_message_new_method_return(message);
1710 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1714 if (!dbus_message_get_args(
1717 DBUS_TYPE_STRING, &name,
1719 return bus_send_error_reply(connection, message, &error, -EINVAL);
1721 session = hashmap_get(m->sessions, name);
1723 return bus_send_error_reply(connection, message, &error, -ENOENT);
1725 r = session_activate(session);
1727 return bus_send_error_reply(connection, message, NULL, r);
1729 reply = dbus_message_new_method_return(message);
1733 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1734 const char *session_name, *seat_name;
1738 /* Same as ActivateSession() but refuses to work if
1739 * the seat doesn't match */
1741 if (!dbus_message_get_args(
1744 DBUS_TYPE_STRING, &session_name,
1745 DBUS_TYPE_STRING, &seat_name,
1747 return bus_send_error_reply(connection, message, &error, -EINVAL);
1749 session = hashmap_get(m->sessions, session_name);
1751 return bus_send_error_reply(connection, message, &error, -ENOENT);
1753 seat = hashmap_get(m->seats, seat_name);
1755 return bus_send_error_reply(connection, message, &error, -ENOENT);
1757 if (session->seat != seat)
1758 return bus_send_error_reply(connection, message, &error, -EINVAL);
1760 r = session_activate(session);
1762 return bus_send_error_reply(connection, message, NULL, r);
1764 reply = dbus_message_new_method_return(message);
1768 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1769 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1773 if (!dbus_message_get_args(
1776 DBUS_TYPE_STRING, &name,
1778 return bus_send_error_reply(connection, message, &error, -EINVAL);
1780 session = hashmap_get(m->sessions, name);
1782 return bus_send_error_reply(connection, message, &error, -ENOENT);
1784 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1787 reply = dbus_message_new_method_return(message);
1791 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions")) {
1795 HASHMAP_FOREACH(session, m->sessions, i)
1796 if (session_send_lock(session, true) < 0)
1799 reply = dbus_message_new_method_return(message);
1803 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1810 if (!dbus_message_get_args(
1813 DBUS_TYPE_STRING, &name,
1814 DBUS_TYPE_STRING, &swho,
1815 DBUS_TYPE_INT32, &signo,
1817 return bus_send_error_reply(connection, message, &error, -EINVAL);
1822 who = kill_who_from_string(swho);
1824 return bus_send_error_reply(connection, message, &error, -EINVAL);
1827 if (signo <= 0 || signo >= _NSIG)
1828 return bus_send_error_reply(connection, message, &error, -EINVAL);
1830 session = hashmap_get(m->sessions, name);
1832 return bus_send_error_reply(connection, message, &error, -ENOENT);
1834 r = session_kill(session, who, signo);
1836 return bus_send_error_reply(connection, message, NULL, r);
1838 reply = dbus_message_new_method_return(message);
1842 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1847 if (!dbus_message_get_args(
1850 DBUS_TYPE_UINT32, &uid,
1851 DBUS_TYPE_INT32, &signo,
1853 return bus_send_error_reply(connection, message, &error, -EINVAL);
1855 if (signo <= 0 || signo >= _NSIG)
1856 return bus_send_error_reply(connection, message, &error, -EINVAL);
1858 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1860 return bus_send_error_reply(connection, message, &error, -ENOENT);
1862 r = user_kill(user, signo);
1864 return bus_send_error_reply(connection, message, NULL, r);
1866 reply = dbus_message_new_method_return(message);
1870 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
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, &error, -ENOENT);
1885 r = session_stop(session);
1887 return bus_send_error_reply(connection, message, NULL, r);
1889 reply = dbus_message_new_method_return(message);
1893 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1897 if (!dbus_message_get_args(
1900 DBUS_TYPE_UINT32, &uid,
1902 return bus_send_error_reply(connection, message, &error, -EINVAL);
1904 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1906 return bus_send_error_reply(connection, message, &error, -ENOENT);
1908 r = user_stop(user);
1910 return bus_send_error_reply(connection, message, NULL, r);
1912 reply = dbus_message_new_method_return(message);
1916 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1920 if (!dbus_message_get_args(
1923 DBUS_TYPE_STRING, &name,
1925 return bus_send_error_reply(connection, message, &error, -EINVAL);
1927 seat = hashmap_get(m->seats, name);
1929 return bus_send_error_reply(connection, message, &error, -ENOENT);
1931 r = seat_stop_sessions(seat);
1933 return bus_send_error_reply(connection, message, NULL, r);
1935 reply = dbus_message_new_method_return(message);
1939 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
1942 dbus_bool_t b, interactive;
1945 if (!dbus_message_get_args(
1948 DBUS_TYPE_UINT32, &uid,
1949 DBUS_TYPE_BOOLEAN, &b,
1950 DBUS_TYPE_BOOLEAN, &interactive,
1952 return bus_send_error_reply(connection, message, &error, -EINVAL);
1957 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
1959 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
1961 return bus_send_error_reply(connection, message, &error, r);
1963 mkdir_p_label("/var/lib/systemd", 0755);
1965 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
1967 return bus_send_error_reply(connection, message, &error, r);
1969 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
1980 return bus_send_error_reply(connection, message, &error, r);
1982 if (manager_add_user_by_uid(m, uid, &u) >= 0)
1991 if (r < 0 && errno != ENOENT)
1992 return bus_send_error_reply(connection, message, &error, -errno);
1994 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1996 user_add_to_gc_queue(u);
1999 reply = dbus_message_new_method_return(message);
2003 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
2004 const char *sysfs, *seat;
2005 dbus_bool_t interactive;
2007 if (!dbus_message_get_args(
2010 DBUS_TYPE_STRING, &seat,
2011 DBUS_TYPE_STRING, &sysfs,
2012 DBUS_TYPE_BOOLEAN, &interactive,
2014 return bus_send_error_reply(connection, message, &error, -EINVAL);
2016 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
2017 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2019 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
2021 return bus_send_error_reply(connection, message, &error, r);
2023 r = attach_device(m, seat, sysfs);
2025 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2027 reply = dbus_message_new_method_return(message);
2032 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
2033 dbus_bool_t interactive;
2035 if (!dbus_message_get_args(
2038 DBUS_TYPE_BOOLEAN, &interactive,
2040 return bus_send_error_reply(connection, message, &error, -EINVAL);
2042 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
2044 return bus_send_error_reply(connection, message, &error, r);
2046 r = flush_devices(m);
2048 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2050 reply = dbus_message_new_method_return(message);
2054 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
2056 r = bus_manager_do_shutdown_or_sleep(
2057 m, connection, message,
2058 SPECIAL_POWEROFF_TARGET,
2060 "org.freedesktop.login1.power-off",
2061 "org.freedesktop.login1.power-off-multiple-sessions",
2062 "org.freedesktop.login1.power-off-ignore-inhibit",
2066 return bus_send_error_reply(connection, message, &error, r);
2067 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
2068 r = bus_manager_do_shutdown_or_sleep(
2069 m, connection, message,
2070 SPECIAL_REBOOT_TARGET,
2072 "org.freedesktop.login1.reboot",
2073 "org.freedesktop.login1.reboot-multiple-sessions",
2074 "org.freedesktop.login1.reboot-ignore-inhibit",
2078 return bus_send_error_reply(connection, message, &error, r);
2080 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2081 r = bus_manager_do_shutdown_or_sleep(
2082 m, connection, message,
2083 SPECIAL_SUSPEND_TARGET,
2085 "org.freedesktop.login1.suspend",
2086 "org.freedesktop.login1.suspend-multiple-sessions",
2087 "org.freedesktop.login1.suspend-ignore-inhibit",
2091 return bus_send_error_reply(connection, message, &error, r);
2092 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2093 r = bus_manager_do_shutdown_or_sleep(
2094 m, connection, message,
2095 SPECIAL_HIBERNATE_TARGET,
2097 "org.freedesktop.login1.hibernate",
2098 "org.freedesktop.login1.hibernate-multiple-sessions",
2099 "org.freedesktop.login1.hibernate-ignore-inhibit",
2103 return bus_send_error_reply(connection, message, &error, r);
2105 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2107 r = bus_manager_can_shutdown_or_sleep(
2108 m, connection, message,
2110 "org.freedesktop.login1.power-off",
2111 "org.freedesktop.login1.power-off-multiple-sessions",
2112 "org.freedesktop.login1.power-off-ignore-inhibit",
2116 return bus_send_error_reply(connection, message, &error, r);
2117 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2118 r = bus_manager_can_shutdown_or_sleep(
2119 m, connection, message,
2121 "org.freedesktop.login1.reboot",
2122 "org.freedesktop.login1.reboot-multiple-sessions",
2123 "org.freedesktop.login1.reboot-ignore-inhibit",
2127 return bus_send_error_reply(connection, message, &error, r);
2129 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2130 r = bus_manager_can_shutdown_or_sleep(
2131 m, connection, message,
2133 "org.freedesktop.login1.suspend",
2134 "org.freedesktop.login1.suspend-multiple-sessions",
2135 "org.freedesktop.login1.suspend-ignore-inhibit",
2139 return bus_send_error_reply(connection, message, &error, r);
2141 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2142 r = bus_manager_can_shutdown_or_sleep(
2143 m, connection, message,
2145 "org.freedesktop.login1.hibernate",
2146 "org.freedesktop.login1.hibernate-multiple-sessions",
2147 "org.freedesktop.login1.hibernate-ignore-inhibit",
2151 return bus_send_error_reply(connection, message, &error, r);
2153 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2154 char *introspection = NULL;
2163 if (!(reply = dbus_message_new_method_return(message)))
2166 /* We roll our own introspection code here, instead of
2167 * relying on bus_default_message_handler() because we
2168 * need to generate our introspection string
2171 if (!(f = open_memstream(&introspection, &size)))
2174 fputs(INTROSPECTION_BEGIN, f);
2176 HASHMAP_FOREACH(seat, m->seats, i) {
2177 p = bus_path_escape(seat->id);
2180 fprintf(f, "<node name=\"seat/%s\"/>", p);
2185 HASHMAP_FOREACH(user, m->users, i)
2186 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2188 HASHMAP_FOREACH(session, m->sessions, i) {
2189 p = bus_path_escape(session->id);
2192 fprintf(f, "<node name=\"session/%s\"/>", p);
2197 fputs(INTROSPECTION_END, f);
2201 free(introspection);
2210 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2211 free(introspection);
2215 free(introspection);
2217 const BusBoundProperties bps[] = {
2218 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2221 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2225 if (!dbus_connection_send(connection, reply, NULL))
2228 dbus_message_unref(reply);
2231 return DBUS_HANDLER_RESULT_HANDLED;
2235 dbus_message_unref(reply);
2237 dbus_error_free(&error);
2239 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2242 const DBusObjectPathVTable bus_manager_vtable = {
2243 .message_function = manager_message_handler
2246 DBusHandlerResult bus_message_filter(
2247 DBusConnection *connection,
2248 DBusMessage *message,
2251 Manager *m = userdata;
2258 dbus_error_init(&error);
2260 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
2263 if (!dbus_message_get_args(message, &error,
2264 DBUS_TYPE_STRING, &cgroup,
2266 log_error("Failed to parse Released message: %s", bus_error_message(&error));
2268 manager_cgroup_notify_empty(m, cgroup);
2271 dbus_error_free(&error);
2273 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2276 int manager_send_changed(Manager *manager, const char *properties) {
2282 m = bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties);
2286 if (!dbus_connection_send(manager->bus, m, NULL))
2293 dbus_message_unref(m);
2298 int manager_dispatch_delayed(Manager *manager) {
2299 const char *unit_name;
2306 if (!manager->delayed_unit)
2309 /* Continue delay? */
2311 manager->delayed_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC) &&
2312 manager_is_inhibited(manager, manager->delayed_what, INHIBIT_DELAY, NULL, false, false, 0);
2316 bus_manager_log_shutdown(manager, manager->delayed_what, manager->delayed_unit);
2318 /* Reset delay data */
2319 unit_name = manager->delayed_unit;
2320 manager->delayed_unit = NULL;
2322 /* Actually do the shutdown */
2323 dbus_error_init(&error);
2324 r = send_start_unit(manager->bus, unit_name, &error);
2326 log_warning("Failed to send delayed message: %s", bus_error_message_or_strerror(&error, -r));
2327 dbus_error_free(&error);
2331 /* Tell people about it */
2332 send_prepare_for(manager, manager->delayed_what, false);