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, MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
1188 int bus_manager_shutdown_or_sleep_now_or_later(
1190 const char *unit_name,
1200 assert(w <= _INHIBIT_WHAT_MAX);
1203 m->inhibit_delay_max > 0 &&
1204 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0);
1207 /* Shutdown is delayed, keep in mind what we
1208 * want to do, and start a timeout */
1209 r = delay_shutdown_or_sleep(m, w, unit_name);
1211 bus_manager_log_shutdown(m, w, unit_name);
1213 /* Shutdown is not delayed, execute it
1215 r = send_start_unit(m->bus, unit_name, error);
1221 static int bus_manager_do_shutdown_or_sleep(
1223 DBusConnection *connection,
1224 DBusMessage *message,
1225 const char *unit_name,
1228 const char *action_multiple_sessions,
1229 const char *action_ignore_inhibit,
1230 const char *sleep_type,
1232 DBusMessage **_reply) {
1234 dbus_bool_t interactive;
1235 bool multiple_sessions, blocked;
1236 DBusMessage *reply = NULL;
1245 assert(w <= _INHIBIT_WHAT_MAX);
1247 assert(action_multiple_sessions);
1248 assert(action_ignore_inhibit);
1252 if (!dbus_message_get_args(
1255 DBUS_TYPE_BOOLEAN, &interactive,
1260 r = can_sleep(sleep_type);
1268 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1269 if (ul == (unsigned long) -1)
1272 r = have_multiple_sessions(m, (uid_t) ul);
1276 multiple_sessions = r > 0;
1277 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1279 if (multiple_sessions) {
1280 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1286 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1291 if (!multiple_sessions && !blocked) {
1292 r = verify_polkit(connection, message, action, interactive, NULL, error);
1297 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
1301 reply = dbus_message_new_method_return(message);
1309 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_button, handle_button, HandleButton);
1311 static const BusProperty bus_login_manager_properties[] = {
1312 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_path), true },
1313 { "Controllers", bus_property_append_strv, "as", offsetof(Manager, controllers), true },
1314 { "ResetControllers", bus_property_append_strv, "as", offsetof(Manager, reset_controllers), true },
1315 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1316 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1317 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1318 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1319 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1320 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1321 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
1322 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1323 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1324 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
1325 { "HandlePowerKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_power_key) },
1326 { "HandleSuspendKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_suspend_key) },
1327 { "HandleHibernateKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_hibernate_key)},
1328 { "HandleLidSwitch", bus_manager_append_handle_button, "s", offsetof(Manager, handle_lid_switch) },
1329 { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
1330 { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
1334 static DBusHandlerResult manager_message_handler(
1335 DBusConnection *connection,
1336 DBusMessage *message,
1339 Manager *m = userdata;
1342 DBusMessage *reply = NULL;
1349 dbus_error_init(&error);
1351 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1357 if (!dbus_message_get_args(
1360 DBUS_TYPE_STRING, &name,
1362 return bus_send_error_reply(connection, message, &error, -EINVAL);
1364 session = hashmap_get(m->sessions, name);
1366 return bus_send_error_reply(connection, message, &error, -ENOENT);
1368 reply = dbus_message_new_method_return(message);
1372 p = session_bus_path(session);
1376 b = dbus_message_append_args(
1378 DBUS_TYPE_OBJECT_PATH, &p,
1385 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1391 if (!dbus_message_get_args(
1394 DBUS_TYPE_UINT32, &pid,
1396 return bus_send_error_reply(connection, message, &error, -EINVAL);
1398 r = manager_get_session_by_pid(m, pid, &session);
1400 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1402 reply = dbus_message_new_method_return(message);
1406 p = session_bus_path(session);
1410 b = dbus_message_append_args(
1412 DBUS_TYPE_OBJECT_PATH, &p,
1419 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1425 if (!dbus_message_get_args(
1428 DBUS_TYPE_UINT32, &uid,
1430 return bus_send_error_reply(connection, message, &error, -EINVAL);
1432 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1434 return bus_send_error_reply(connection, message, &error, -ENOENT);
1436 reply = dbus_message_new_method_return(message);
1440 p = user_bus_path(user);
1444 b = dbus_message_append_args(
1446 DBUS_TYPE_OBJECT_PATH, &p,
1453 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1459 if (!dbus_message_get_args(
1462 DBUS_TYPE_STRING, &name,
1464 return bus_send_error_reply(connection, message, &error, -EINVAL);
1466 seat = hashmap_get(m->seats, name);
1468 return bus_send_error_reply(connection, message, &error, -ENOENT);
1470 reply = dbus_message_new_method_return(message);
1474 p = seat_bus_path(seat);
1478 b = dbus_message_append_args(
1480 DBUS_TYPE_OBJECT_PATH, &p,
1487 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1491 DBusMessageIter iter, sub;
1492 const char *empty = "";
1494 reply = dbus_message_new_method_return(message);
1498 dbus_message_iter_init_append(reply, &iter);
1500 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1503 HASHMAP_FOREACH(session, m->sessions, i) {
1504 DBusMessageIter sub2;
1507 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1510 uid = session->user->uid;
1512 p = session_bus_path(session);
1516 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1517 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1518 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1519 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1520 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1527 if (!dbus_message_iter_close_container(&sub, &sub2))
1531 if (!dbus_message_iter_close_container(&iter, &sub))
1534 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1538 DBusMessageIter iter, sub;
1540 reply = dbus_message_new_method_return(message);
1544 dbus_message_iter_init_append(reply, &iter);
1546 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1549 HASHMAP_FOREACH(user, m->users, i) {
1550 DBusMessageIter sub2;
1553 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1558 p = user_bus_path(user);
1562 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1563 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1564 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1571 if (!dbus_message_iter_close_container(&sub, &sub2))
1575 if (!dbus_message_iter_close_container(&iter, &sub))
1578 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1582 DBusMessageIter iter, sub;
1584 reply = dbus_message_new_method_return(message);
1588 dbus_message_iter_init_append(reply, &iter);
1590 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1593 HASHMAP_FOREACH(seat, m->seats, i) {
1594 DBusMessageIter sub2;
1596 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1599 p = seat_bus_path(seat);
1603 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1604 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1611 if (!dbus_message_iter_close_container(&sub, &sub2))
1615 if (!dbus_message_iter_close_container(&iter, &sub))
1618 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1619 Inhibitor *inhibitor;
1621 DBusMessageIter iter, sub;
1623 reply = dbus_message_new_method_return(message);
1627 dbus_message_iter_init_append(reply, &iter);
1629 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1632 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1633 DBusMessageIter sub2;
1634 dbus_uint32_t uid, pid;
1635 const char *what, *who, *why, *mode;
1637 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1640 what = strempty(inhibit_what_to_string(inhibitor->what));
1641 who = strempty(inhibitor->who);
1642 why = strempty(inhibitor->why);
1643 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
1644 uid = (dbus_uint32_t) inhibitor->uid;
1645 pid = (dbus_uint32_t) inhibitor->pid;
1647 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1648 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1649 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1650 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
1651 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1652 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1655 if (!dbus_message_iter_close_container(&sub, &sub2))
1659 if (!dbus_message_iter_close_container(&iter, &sub))
1662 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1664 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1667 return bus_send_error_reply(connection, message, &error, r);
1670 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1672 r = bus_manager_create_session(m, message, &reply);
1674 /* Don't delay the work on OOM here, since it might be
1675 * triggered by a low RLIMIT_NOFILE here (since we
1676 * send a dupped fd to the client), and we'd rather
1677 * see this fail quickly then be retried later */
1680 return bus_send_error_reply(connection, message, NULL, r);
1682 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1686 if (!dbus_message_get_args(
1689 DBUS_TYPE_STRING, &name,
1691 return bus_send_error_reply(connection, message, &error, -EINVAL);
1693 session = hashmap_get(m->sessions, name);
1695 return bus_send_error_reply(connection, message, &error, -ENOENT);
1697 /* We use the FIFO to detect stray sessions where the
1698 process invoking PAM dies abnormally. We need to make
1699 sure that that process is not killed if at the clean
1700 end of the session it closes the FIFO. Hence, with
1701 this call explicitly turn off the FIFO logic, so that
1702 the PAM code can finish clean up on its own */
1703 session_remove_fifo(session);
1705 reply = dbus_message_new_method_return(message);
1709 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1713 if (!dbus_message_get_args(
1716 DBUS_TYPE_STRING, &name,
1718 return bus_send_error_reply(connection, message, &error, -EINVAL);
1720 session = hashmap_get(m->sessions, name);
1722 return bus_send_error_reply(connection, message, &error, -ENOENT);
1724 r = session_activate(session);
1726 return bus_send_error_reply(connection, message, NULL, r);
1728 reply = dbus_message_new_method_return(message);
1732 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1733 const char *session_name, *seat_name;
1737 /* Same as ActivateSession() but refuses to work if
1738 * the seat doesn't match */
1740 if (!dbus_message_get_args(
1743 DBUS_TYPE_STRING, &session_name,
1744 DBUS_TYPE_STRING, &seat_name,
1746 return bus_send_error_reply(connection, message, &error, -EINVAL);
1748 session = hashmap_get(m->sessions, session_name);
1750 return bus_send_error_reply(connection, message, &error, -ENOENT);
1752 seat = hashmap_get(m->seats, seat_name);
1754 return bus_send_error_reply(connection, message, &error, -ENOENT);
1756 if (session->seat != seat)
1757 return bus_send_error_reply(connection, message, &error, -EINVAL);
1759 r = session_activate(session);
1761 return bus_send_error_reply(connection, message, NULL, r);
1763 reply = dbus_message_new_method_return(message);
1767 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1768 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1772 if (!dbus_message_get_args(
1775 DBUS_TYPE_STRING, &name,
1777 return bus_send_error_reply(connection, message, &error, -EINVAL);
1779 session = hashmap_get(m->sessions, name);
1781 return bus_send_error_reply(connection, message, &error, -ENOENT);
1783 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1786 reply = dbus_message_new_method_return(message);
1790 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions")) {
1794 HASHMAP_FOREACH(session, m->sessions, i)
1795 if (session_send_lock(session, true) < 0)
1798 reply = dbus_message_new_method_return(message);
1802 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1809 if (!dbus_message_get_args(
1812 DBUS_TYPE_STRING, &name,
1813 DBUS_TYPE_STRING, &swho,
1814 DBUS_TYPE_INT32, &signo,
1816 return bus_send_error_reply(connection, message, &error, -EINVAL);
1821 who = kill_who_from_string(swho);
1823 return bus_send_error_reply(connection, message, &error, -EINVAL);
1826 if (signo <= 0 || signo >= _NSIG)
1827 return bus_send_error_reply(connection, message, &error, -EINVAL);
1829 session = hashmap_get(m->sessions, name);
1831 return bus_send_error_reply(connection, message, &error, -ENOENT);
1833 r = session_kill(session, who, signo);
1835 return bus_send_error_reply(connection, message, NULL, r);
1837 reply = dbus_message_new_method_return(message);
1841 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1846 if (!dbus_message_get_args(
1849 DBUS_TYPE_UINT32, &uid,
1850 DBUS_TYPE_INT32, &signo,
1852 return bus_send_error_reply(connection, message, &error, -EINVAL);
1854 if (signo <= 0 || signo >= _NSIG)
1855 return bus_send_error_reply(connection, message, &error, -EINVAL);
1857 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1859 return bus_send_error_reply(connection, message, &error, -ENOENT);
1861 r = user_kill(user, signo);
1863 return bus_send_error_reply(connection, message, NULL, r);
1865 reply = dbus_message_new_method_return(message);
1869 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1873 if (!dbus_message_get_args(
1876 DBUS_TYPE_STRING, &name,
1878 return bus_send_error_reply(connection, message, &error, -EINVAL);
1880 session = hashmap_get(m->sessions, name);
1882 return bus_send_error_reply(connection, message, &error, -ENOENT);
1884 r = session_stop(session);
1886 return bus_send_error_reply(connection, message, NULL, r);
1888 reply = dbus_message_new_method_return(message);
1892 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1896 if (!dbus_message_get_args(
1899 DBUS_TYPE_UINT32, &uid,
1901 return bus_send_error_reply(connection, message, &error, -EINVAL);
1903 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1905 return bus_send_error_reply(connection, message, &error, -ENOENT);
1907 r = user_stop(user);
1909 return bus_send_error_reply(connection, message, NULL, r);
1911 reply = dbus_message_new_method_return(message);
1915 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1919 if (!dbus_message_get_args(
1922 DBUS_TYPE_STRING, &name,
1924 return bus_send_error_reply(connection, message, &error, -EINVAL);
1926 seat = hashmap_get(m->seats, name);
1928 return bus_send_error_reply(connection, message, &error, -ENOENT);
1930 r = seat_stop_sessions(seat);
1932 return bus_send_error_reply(connection, message, NULL, r);
1934 reply = dbus_message_new_method_return(message);
1938 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
1941 dbus_bool_t b, interactive;
1944 if (!dbus_message_get_args(
1947 DBUS_TYPE_UINT32, &uid,
1948 DBUS_TYPE_BOOLEAN, &b,
1949 DBUS_TYPE_BOOLEAN, &interactive,
1951 return bus_send_error_reply(connection, message, &error, -EINVAL);
1956 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
1958 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
1960 return bus_send_error_reply(connection, message, &error, r);
1962 mkdir_p_label("/var/lib/systemd", 0755);
1964 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
1966 return bus_send_error_reply(connection, message, &error, r);
1968 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
1979 return bus_send_error_reply(connection, message, &error, r);
1981 if (manager_add_user_by_uid(m, uid, &u) >= 0)
1990 if (r < 0 && errno != ENOENT)
1991 return bus_send_error_reply(connection, message, &error, -errno);
1993 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1995 user_add_to_gc_queue(u);
1998 reply = dbus_message_new_method_return(message);
2002 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
2003 const char *sysfs, *seat;
2004 dbus_bool_t interactive;
2006 if (!dbus_message_get_args(
2009 DBUS_TYPE_STRING, &seat,
2010 DBUS_TYPE_STRING, &sysfs,
2011 DBUS_TYPE_BOOLEAN, &interactive,
2013 return bus_send_error_reply(connection, message, &error, -EINVAL);
2015 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
2016 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2018 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
2020 return bus_send_error_reply(connection, message, &error, r);
2022 r = attach_device(m, seat, sysfs);
2024 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2026 reply = dbus_message_new_method_return(message);
2031 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
2032 dbus_bool_t interactive;
2034 if (!dbus_message_get_args(
2037 DBUS_TYPE_BOOLEAN, &interactive,
2039 return bus_send_error_reply(connection, message, &error, -EINVAL);
2041 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
2043 return bus_send_error_reply(connection, message, &error, r);
2045 r = flush_devices(m);
2047 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2049 reply = dbus_message_new_method_return(message);
2053 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
2055 r = bus_manager_do_shutdown_or_sleep(
2056 m, connection, message,
2057 SPECIAL_POWEROFF_TARGET,
2059 "org.freedesktop.login1.power-off",
2060 "org.freedesktop.login1.power-off-multiple-sessions",
2061 "org.freedesktop.login1.power-off-ignore-inhibit",
2065 return bus_send_error_reply(connection, message, &error, r);
2066 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
2067 r = bus_manager_do_shutdown_or_sleep(
2068 m, connection, message,
2069 SPECIAL_REBOOT_TARGET,
2071 "org.freedesktop.login1.reboot",
2072 "org.freedesktop.login1.reboot-multiple-sessions",
2073 "org.freedesktop.login1.reboot-ignore-inhibit",
2077 return bus_send_error_reply(connection, message, &error, r);
2079 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2080 r = bus_manager_do_shutdown_or_sleep(
2081 m, connection, message,
2082 SPECIAL_SUSPEND_TARGET,
2084 "org.freedesktop.login1.suspend",
2085 "org.freedesktop.login1.suspend-multiple-sessions",
2086 "org.freedesktop.login1.suspend-ignore-inhibit",
2090 return bus_send_error_reply(connection, message, &error, r);
2091 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2092 r = bus_manager_do_shutdown_or_sleep(
2093 m, connection, message,
2094 SPECIAL_HIBERNATE_TARGET,
2096 "org.freedesktop.login1.hibernate",
2097 "org.freedesktop.login1.hibernate-multiple-sessions",
2098 "org.freedesktop.login1.hibernate-ignore-inhibit",
2102 return bus_send_error_reply(connection, message, &error, r);
2104 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2106 r = bus_manager_can_shutdown_or_sleep(
2107 m, connection, message,
2109 "org.freedesktop.login1.power-off",
2110 "org.freedesktop.login1.power-off-multiple-sessions",
2111 "org.freedesktop.login1.power-off-ignore-inhibit",
2115 return bus_send_error_reply(connection, message, &error, r);
2116 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2117 r = bus_manager_can_shutdown_or_sleep(
2118 m, connection, message,
2120 "org.freedesktop.login1.reboot",
2121 "org.freedesktop.login1.reboot-multiple-sessions",
2122 "org.freedesktop.login1.reboot-ignore-inhibit",
2126 return bus_send_error_reply(connection, message, &error, r);
2128 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2129 r = bus_manager_can_shutdown_or_sleep(
2130 m, connection, message,
2132 "org.freedesktop.login1.suspend",
2133 "org.freedesktop.login1.suspend-multiple-sessions",
2134 "org.freedesktop.login1.suspend-ignore-inhibit",
2138 return bus_send_error_reply(connection, message, &error, r);
2140 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2141 r = bus_manager_can_shutdown_or_sleep(
2142 m, connection, message,
2144 "org.freedesktop.login1.hibernate",
2145 "org.freedesktop.login1.hibernate-multiple-sessions",
2146 "org.freedesktop.login1.hibernate-ignore-inhibit",
2150 return bus_send_error_reply(connection, message, &error, r);
2152 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2153 char *introspection = NULL;
2162 if (!(reply = dbus_message_new_method_return(message)))
2165 /* We roll our own introspection code here, instead of
2166 * relying on bus_default_message_handler() because we
2167 * need to generate our introspection string
2170 if (!(f = open_memstream(&introspection, &size)))
2173 fputs(INTROSPECTION_BEGIN, f);
2175 HASHMAP_FOREACH(seat, m->seats, i) {
2176 p = bus_path_escape(seat->id);
2179 fprintf(f, "<node name=\"seat/%s\"/>", p);
2184 HASHMAP_FOREACH(user, m->users, i)
2185 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2187 HASHMAP_FOREACH(session, m->sessions, i) {
2188 p = bus_path_escape(session->id);
2191 fprintf(f, "<node name=\"session/%s\"/>", p);
2196 fputs(INTROSPECTION_END, f);
2200 free(introspection);
2209 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2210 free(introspection);
2214 free(introspection);
2216 const BusBoundProperties bps[] = {
2217 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2220 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2224 if (!dbus_connection_send(connection, reply, NULL))
2227 dbus_message_unref(reply);
2230 return DBUS_HANDLER_RESULT_HANDLED;
2234 dbus_message_unref(reply);
2236 dbus_error_free(&error);
2238 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2241 const DBusObjectPathVTable bus_manager_vtable = {
2242 .message_function = manager_message_handler
2245 DBusHandlerResult bus_message_filter(
2246 DBusConnection *connection,
2247 DBusMessage *message,
2250 Manager *m = userdata;
2257 dbus_error_init(&error);
2259 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
2262 if (!dbus_message_get_args(message, &error,
2263 DBUS_TYPE_STRING, &cgroup,
2265 log_error("Failed to parse Released message: %s", bus_error_message(&error));
2267 manager_cgroup_notify_empty(m, cgroup);
2270 dbus_error_free(&error);
2272 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2275 int manager_send_changed(Manager *manager, const char *properties) {
2281 m = bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties);
2285 if (!dbus_connection_send(manager->bus, m, NULL))
2292 dbus_message_unref(m);
2297 int manager_dispatch_delayed(Manager *manager) {
2298 const char *unit_name;
2305 if (!manager->delayed_unit)
2308 /* Continue delay? */
2310 manager->delayed_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC) &&
2311 manager_is_inhibited(manager, manager->delayed_what, INHIBIT_DELAY, NULL, false, false, 0);
2315 bus_manager_log_shutdown(manager, manager->delayed_what, manager->delayed_unit);
2317 /* Reset delay data */
2318 unit_name = manager->delayed_unit;
2319 manager->delayed_unit = NULL;
2321 /* Actually do the shutdown */
2322 dbus_error_init(&error);
2323 r = send_start_unit(manager->bus, unit_name, &error);
2325 log_warning("Failed to send delayed message: %s", bus_error_message_or_strerror(&error, -r));
2326 dbus_error_free(&error);
2330 /* Tell people about it */
2331 send_prepare_for(manager, manager->delayed_what, false);