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=\"HandleSleepKey\" type=\"s\" access=\"read\"/>\n" \
214 " <property name=\"HandleLidSwitch\" type=\"s\" access=\"read\"/>\n" \
215 " <property name=\"PreparingForShutdown\" type=\"b\" access=\"read\"/>\n" \
216 " <property name=\"PreparingForSleep\" type=\"b\" access=\"read\"/>\n" \
219 #define INTROSPECTION_BEGIN \
220 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
222 BUS_MANAGER_INTERFACE \
223 BUS_PROPERTIES_INTERFACE \
225 BUS_INTROSPECTABLE_INTERFACE
227 #define INTROSPECTION_END \
230 #define INTERFACES_LIST \
231 BUS_GENERIC_INTERFACES_LIST \
232 "org.freedesktop.login1.Manager\0"
234 static int bus_manager_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
242 b = manager_get_idle_hint(m, NULL) > 0;
243 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
249 static int bus_manager_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
258 manager_get_idle_hint(m, &t);
259 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
261 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
267 static int bus_manager_append_inhibited(DBusMessageIter *i, const char *property, void *data) {
272 w = manager_inhibit_what(m, streq(property, "BlockInhibited") ? INHIBIT_BLOCK : INHIBIT_DELAY);
273 p = inhibit_what_to_string(w);
275 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &p))
281 static int bus_manager_append_preparing(DBusMessageIter *i, const char *property, void *data) {
288 if (streq(property, "PreparingForShutdown"))
289 b = !!(m->delayed_what & INHIBIT_SHUTDOWN);
291 b = !!(m->delayed_what & INHIBIT_SLEEP);
293 dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b);
297 static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMessage **_reply) {
298 Session *session = NULL;
300 const char *type, *class, *seat, *tty, *display, *remote_user, *remote_host, *service;
301 uint32_t uid, leader, audit_id = 0;
302 dbus_bool_t remote, kill_processes;
303 char **controllers = NULL, **reset_controllers = NULL;
307 DBusMessageIter iter;
312 DBusMessage *reply = NULL;
319 if (!dbus_message_iter_init(message, &iter) ||
320 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
323 dbus_message_iter_get_basic(&iter, &uid);
325 if (!dbus_message_iter_next(&iter) ||
326 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
329 dbus_message_iter_get_basic(&iter, &leader);
332 !dbus_message_iter_next(&iter) ||
333 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
336 dbus_message_iter_get_basic(&iter, &service);
338 if (!dbus_message_iter_next(&iter) ||
339 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
342 dbus_message_iter_get_basic(&iter, &type);
343 t = session_type_from_string(type);
346 !dbus_message_iter_next(&iter) ||
347 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
350 dbus_message_iter_get_basic(&iter, &class);
354 c = session_class_from_string(class);
357 !dbus_message_iter_next(&iter) ||
358 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
361 dbus_message_iter_get_basic(&iter, &seat);
366 s = hashmap_get(m->seats, seat);
371 if (!dbus_message_iter_next(&iter) ||
372 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
375 dbus_message_iter_get_basic(&iter, &vtnr);
377 if (!dbus_message_iter_next(&iter) ||
378 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
381 dbus_message_iter_get_basic(&iter, &tty);
383 if (tty_is_vc(tty)) {
388 else if (s != m->vtconsole)
391 v = vtnr_from_tty(tty);
394 return v < 0 ? v : -EINVAL;
398 else if (vtnr != (uint32_t) v)
400 } else if (tty_is_console(tty)) {
404 else if (s != m->vtconsole)
410 } else if (!isempty(tty) && s && seat_is_vtconsole(s))
414 if (seat_can_multi_session(s)) {
423 if (!dbus_message_iter_next(&iter) ||
424 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
427 dbus_message_iter_get_basic(&iter, &display);
429 if (!dbus_message_iter_next(&iter) ||
430 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
433 dbus_message_iter_get_basic(&iter, &remote);
435 if (!dbus_message_iter_next(&iter) ||
436 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
439 dbus_message_iter_get_basic(&iter, &remote_user);
441 if (!dbus_message_iter_next(&iter) ||
442 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
445 dbus_message_iter_get_basic(&iter, &remote_host);
447 if (!dbus_message_iter_next(&iter) ||
448 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
449 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
452 r = bus_parse_strv_iter(&iter, &controllers);
456 if (strv_contains(controllers, "systemd") ||
457 !dbus_message_iter_next(&iter) ||
458 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
459 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) {
464 r = bus_parse_strv_iter(&iter, &reset_controllers);
468 if (strv_contains(reset_controllers, "systemd") ||
469 !dbus_message_iter_next(&iter) ||
470 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) {
475 dbus_message_iter_get_basic(&iter, &kill_processes);
477 r = manager_add_user_by_uid(m, uid, &user);
481 audit_session_from_pid(leader, &audit_id);
484 asprintf(&id, "%lu", (unsigned long) audit_id);
491 session = hashmap_get(m->sessions, id);
496 fifo_fd = session_create_fifo(session);
502 /* Session already exists, client is probably
503 * something like "su" which changes uid but
504 * is still the same audit session */
506 reply = dbus_message_new_method_return(message);
512 p = session_bus_path(session);
518 seat = session->seat ? session->seat->id : "";
519 vtnr = session->vtnr;
520 b = dbus_message_append_args(
522 DBUS_TYPE_STRING, &session->id,
523 DBUS_TYPE_OBJECT_PATH, &p,
524 DBUS_TYPE_STRING, &session->user->runtime_path,
525 DBUS_TYPE_UNIX_FD, &fifo_fd,
526 DBUS_TYPE_STRING, &seat,
527 DBUS_TYPE_UINT32, &vtnr,
536 close_nointr_nofail(fifo_fd);
539 strv_free(controllers);
540 strv_free(reset_controllers);
550 if (asprintf(&id, "c%lu", ++m->session_counter) < 0) {
555 } while (hashmap_get(m->sessions, id));
558 r = manager_add_session(m, user, id, &session);
563 session->leader = leader;
564 session->audit_id = audit_id;
567 session->remote = remote;
568 session->controllers = controllers;
569 session->reset_controllers = reset_controllers;
570 session->kill_processes = kill_processes;
571 session->vtnr = vtnr;
573 controllers = reset_controllers = NULL;
576 session->tty = strdup(tty);
583 if (!isempty(display)) {
584 session->display = strdup(display);
585 if (!session->display) {
591 if (!isempty(remote_user)) {
592 session->remote_user = strdup(remote_user);
593 if (!session->remote_user) {
599 if (!isempty(remote_host)) {
600 session->remote_host = strdup(remote_host);
601 if (!session->remote_host) {
607 if (!isempty(service)) {
608 session->service = strdup(service);
609 if (!session->service) {
615 fifo_fd = session_create_fifo(session);
622 r = seat_attach_session(s, session);
627 r = session_start(session);
631 reply = dbus_message_new_method_return(message);
637 p = session_bus_path(session);
643 seat = s ? s->id : "";
644 b = dbus_message_append_args(
646 DBUS_TYPE_STRING, &session->id,
647 DBUS_TYPE_OBJECT_PATH, &p,
648 DBUS_TYPE_STRING, &session->user->runtime_path,
649 DBUS_TYPE_UNIX_FD, &fifo_fd,
650 DBUS_TYPE_STRING, &seat,
651 DBUS_TYPE_UINT32, &vtnr,
660 close_nointr_nofail(fifo_fd);
666 strv_free(controllers);
667 strv_free(reset_controllers);
670 session_add_to_gc_queue(session);
673 user_add_to_gc_queue(user);
676 close_nointr_nofail(fifo_fd);
679 dbus_message_unref(reply);
684 static int bus_manager_inhibit(Manager *m, DBusConnection *connection, DBusMessage *message, DBusError *error, DBusMessage **_reply) {
687 const char *who, *why, *what, *mode;
693 DBusMessage *reply = NULL;
701 if (!dbus_message_get_args(
704 DBUS_TYPE_STRING, &what,
705 DBUS_TYPE_STRING, &who,
706 DBUS_TYPE_STRING, &why,
707 DBUS_TYPE_STRING, &mode,
708 DBUS_TYPE_INVALID)) {
713 w = inhibit_what_from_string(what);
719 mm = inhibit_mode_from_string(mode);
725 r = verify_polkit(connection, message,
726 w == INHIBIT_SHUTDOWN ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
727 w == INHIBIT_SLEEP ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep" : "org.freedesktop.login1.inhibit-delay-sleep") :
728 (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-idle" : "org.freedesktop.login1.inhibit-delay-idle"),
733 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
734 if (ul == (unsigned long) -1) {
739 pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
749 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
753 } while (hashmap_get(m->inhibitors, id));
755 r = manager_add_inhibitor(m, id, &i);
765 i->why = strdup(why);
766 i->who = strdup(who);
768 if (!i->why || !i->who) {
773 fifo_fd = inhibitor_create_fifo(i);
779 reply = dbus_message_new_method_return(message);
785 if (!dbus_message_append_args(
787 DBUS_TYPE_UNIX_FD, &fifo_fd,
788 DBUS_TYPE_INVALID)) {
793 close_nointr_nofail(fifo_fd);
805 close_nointr_nofail(fifo_fd);
808 dbus_message_unref(reply);
813 static int trigger_device(Manager *m, struct udev_device *d) {
814 struct udev_enumerate *e;
815 struct udev_list_entry *first, *item;
820 e = udev_enumerate_new(m->udev);
827 if (udev_enumerate_add_match_parent(e, d) < 0) {
833 if (udev_enumerate_scan_devices(e) < 0) {
838 first = udev_enumerate_get_list_entry(e);
839 udev_list_entry_foreach(item, first) {
843 p = udev_list_entry_get_name(item);
845 t = strappend(p, "/uevent");
851 write_one_line_file(t, "change");
859 udev_enumerate_unref(e);
864 static int attach_device(Manager *m, const char *seat, const char *sysfs) {
865 struct udev_device *d;
866 char *rule = NULL, *file = NULL;
867 const char *id_for_seat;
874 d = udev_device_new_from_syspath(m->udev, sysfs);
878 if (!udev_device_has_tag(d, "seat")) {
883 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
889 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
894 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
899 mkdir_p_label("/etc/udev/rules.d", 0755);
900 r = write_one_line_file_atomic(file, rule);
904 r = trigger_device(m, d);
911 udev_device_unref(d);
916 static int flush_devices(Manager *m) {
921 d = opendir("/etc/udev/rules.d");
924 log_warning("Failed to open /etc/udev/rules.d: %m");
928 while ((de = readdir(d))) {
930 if (!dirent_is_file(de))
933 if (!startswith(de->d_name, "72-seat-"))
936 if (!endswith(de->d_name, ".rules"))
939 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
940 log_warning("Failed to unlink %s: %m", de->d_name);
946 return trigger_device(m, NULL);
949 static int have_multiple_sessions(
950 DBusConnection *connection,
952 DBusMessage *message,
961 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
962 if (ul == (unsigned long) -1)
965 /* Check for other users' sessions. Greeter sessions do not count. */
966 HASHMAP_FOREACH(session, m->sessions, i)
967 if (session->class == SESSION_USER && session->user->uid != ul)
973 static int send_start_unit(DBusConnection *connection, const char *unit_name, DBusError *error) {
974 const char *mode = "replace";
978 return bus_method_call_with_reply (
980 "org.freedesktop.systemd1",
981 "/org/freedesktop/systemd1",
982 "org.freedesktop.systemd1.Manager",
986 DBUS_TYPE_STRING, &unit_name,
987 DBUS_TYPE_STRING, &mode,
991 static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
992 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
993 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
994 [INHIBIT_SLEEP] = "PrepareForSleep"
997 dbus_bool_t active = _active;
998 DBusMessage *message;
1003 assert(w < _INHIBIT_WHAT_MAX);
1004 assert(signal_name[w]);
1006 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1010 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1011 !dbus_connection_send(m->bus, message, NULL))
1014 dbus_message_unref(message);
1018 static int delay_shutdown_or_sleep(Manager *m, InhibitWhat w, const char *unit_name) {
1021 assert(w < _INHIBIT_WHAT_MAX);
1023 /* Tell everybody to prepare for shutdown/sleep */
1024 send_prepare_for(m, w, true);
1026 /* Update timestamp for timeout */
1027 if (!m->delayed_unit)
1028 m->delayed_timestamp = now(CLOCK_MONOTONIC);
1030 /* Remember what we want to do, possibly overriding what kind
1031 * of unit we previously queued. */
1032 m->delayed_unit = unit_name;
1033 m->delayed_what = w;
1038 static int bus_manager_can_shutdown_or_sleep(
1040 DBusConnection *connection,
1041 DBusMessage *message,
1044 const char *action_multiple_sessions,
1045 const char *action_ignore_inhibit,
1046 const char *sleep_type,
1048 DBusMessage **_reply) {
1050 bool multiple_sessions, challenge, blocked, b;
1052 DBusMessage *reply = NULL;
1059 assert(w <= _INHIBIT_WHAT_MAX);
1061 assert(action_multiple_sessions);
1062 assert(action_ignore_inhibit);
1067 r = can_sleep(sleep_type);
1077 r = have_multiple_sessions(connection, m, message, error);
1081 multiple_sessions = r > 0;
1082 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL);
1084 if (multiple_sessions) {
1085 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1092 result = "challenge";
1098 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1102 if (r > 0 && !result)
1104 else if (challenge && (!result || streq(result, "yes")))
1105 result = "challenge";
1110 if (!multiple_sessions && !blocked) {
1111 /* If neither inhibit nor multiple sessions
1112 * apply then just check the normal policy */
1114 r = verify_polkit(connection, message, action, false, &challenge, error);
1121 result = "challenge";
1127 reply = dbus_message_new_method_return(message);
1131 b = dbus_message_append_args(
1133 DBUS_TYPE_STRING, &result,
1136 dbus_message_unref(reply);
1144 static int bus_manager_log_shutdown(
1147 const char *unit_name) {
1154 if (w != INHIBIT_SHUTDOWN)
1157 if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
1158 p = "MESSAGE=System is powering down.";
1159 q = "SHUTDOWN=power-off";
1160 } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
1161 p = "MESSAGE=System is halting.";
1162 q = "SHUTDOWN=halt";
1163 } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
1164 p = "MESSAGE=System is rebooting.";
1165 q = "SHUTDOWN=reboot";
1166 } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
1167 p = "MESSAGE=System is rebooting with kexec.";
1168 q = "SHUTDOWN=kexec";
1170 p = "MESSAGE=System is shutting down.";
1174 return log_struct(LOG_NOTICE,
1175 "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(SD_MESSAGE_SHUTDOWN),
1180 int bus_manager_shutdown_or_sleep_now_or_later(
1182 const char *unit_name,
1192 assert(w <= _INHIBIT_WHAT_MAX);
1195 m->inhibit_delay_max > 0 &&
1196 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL);
1199 /* Shutdown is delayed, keep in mind what we
1200 * want to do, and start a timeout */
1201 r = delay_shutdown_or_sleep(m, w, unit_name);
1203 bus_manager_log_shutdown(m, w, unit_name);
1205 /* Shutdown is not delayed, execute it
1207 r = send_start_unit(m->bus, unit_name, error);
1213 static int bus_manager_do_shutdown_or_sleep(
1215 DBusConnection *connection,
1216 DBusMessage *message,
1217 const char *unit_name,
1220 const char *action_multiple_sessions,
1221 const char *action_ignore_inhibit,
1222 const char *sleep_type,
1224 DBusMessage **_reply) {
1226 dbus_bool_t interactive;
1227 bool multiple_sessions, blocked;
1228 DBusMessage *reply = NULL;
1236 assert(w <= _INHIBIT_WHAT_MAX);
1238 assert(action_multiple_sessions);
1239 assert(action_ignore_inhibit);
1243 if (!dbus_message_get_args(
1246 DBUS_TYPE_BOOLEAN, &interactive,
1251 r = can_sleep(sleep_type);
1259 r = have_multiple_sessions(connection, m, message, error);
1263 multiple_sessions = r > 0;
1264 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL);
1266 if (multiple_sessions) {
1267 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1273 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1278 if (!multiple_sessions && !blocked) {
1279 r = verify_polkit(connection, message, action, interactive, NULL, error);
1284 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
1288 reply = dbus_message_new_method_return(message);
1296 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_button, handle_button, HandleButton);
1298 static const BusProperty bus_login_manager_properties[] = {
1299 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_path), true },
1300 { "Controllers", bus_property_append_strv, "as", offsetof(Manager, controllers), true },
1301 { "ResetControllers", bus_property_append_strv, "as", offsetof(Manager, reset_controllers), true },
1302 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1303 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1304 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1305 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1306 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1307 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1308 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
1309 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1310 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1311 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
1312 { "HandlePowerKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_power_key) },
1313 { "HandleSleepKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_sleep_key) },
1314 { "HandleLidSwitch", bus_manager_append_handle_button, "s", offsetof(Manager, handle_lid_switch) },
1315 { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
1316 { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
1320 static DBusHandlerResult manager_message_handler(
1321 DBusConnection *connection,
1322 DBusMessage *message,
1325 Manager *m = userdata;
1328 DBusMessage *reply = NULL;
1335 dbus_error_init(&error);
1337 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1343 if (!dbus_message_get_args(
1346 DBUS_TYPE_STRING, &name,
1348 return bus_send_error_reply(connection, message, &error, -EINVAL);
1350 session = hashmap_get(m->sessions, name);
1352 return bus_send_error_reply(connection, message, &error, -ENOENT);
1354 reply = dbus_message_new_method_return(message);
1358 p = session_bus_path(session);
1362 b = dbus_message_append_args(
1364 DBUS_TYPE_OBJECT_PATH, &p,
1371 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1377 if (!dbus_message_get_args(
1380 DBUS_TYPE_UINT32, &pid,
1382 return bus_send_error_reply(connection, message, &error, -EINVAL);
1384 r = manager_get_session_by_pid(m, pid, &session);
1386 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1388 reply = dbus_message_new_method_return(message);
1392 p = session_bus_path(session);
1396 b = dbus_message_append_args(
1398 DBUS_TYPE_OBJECT_PATH, &p,
1405 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1411 if (!dbus_message_get_args(
1414 DBUS_TYPE_UINT32, &uid,
1416 return bus_send_error_reply(connection, message, &error, -EINVAL);
1418 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1420 return bus_send_error_reply(connection, message, &error, -ENOENT);
1422 reply = dbus_message_new_method_return(message);
1426 p = user_bus_path(user);
1430 b = dbus_message_append_args(
1432 DBUS_TYPE_OBJECT_PATH, &p,
1439 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1445 if (!dbus_message_get_args(
1448 DBUS_TYPE_STRING, &name,
1450 return bus_send_error_reply(connection, message, &error, -EINVAL);
1452 seat = hashmap_get(m->seats, name);
1454 return bus_send_error_reply(connection, message, &error, -ENOENT);
1456 reply = dbus_message_new_method_return(message);
1460 p = seat_bus_path(seat);
1464 b = dbus_message_append_args(
1466 DBUS_TYPE_OBJECT_PATH, &p,
1473 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1477 DBusMessageIter iter, sub;
1478 const char *empty = "";
1480 reply = dbus_message_new_method_return(message);
1484 dbus_message_iter_init_append(reply, &iter);
1486 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1489 HASHMAP_FOREACH(session, m->sessions, i) {
1490 DBusMessageIter sub2;
1493 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1496 uid = session->user->uid;
1498 p = session_bus_path(session);
1502 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1503 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1504 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1505 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1506 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1513 if (!dbus_message_iter_close_container(&sub, &sub2))
1517 if (!dbus_message_iter_close_container(&iter, &sub))
1520 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1524 DBusMessageIter iter, sub;
1526 reply = dbus_message_new_method_return(message);
1530 dbus_message_iter_init_append(reply, &iter);
1532 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1535 HASHMAP_FOREACH(user, m->users, i) {
1536 DBusMessageIter sub2;
1539 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1544 p = user_bus_path(user);
1548 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1549 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1550 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1557 if (!dbus_message_iter_close_container(&sub, &sub2))
1561 if (!dbus_message_iter_close_container(&iter, &sub))
1564 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1568 DBusMessageIter iter, sub;
1570 reply = dbus_message_new_method_return(message);
1574 dbus_message_iter_init_append(reply, &iter);
1576 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1579 HASHMAP_FOREACH(seat, m->seats, i) {
1580 DBusMessageIter sub2;
1582 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1585 p = seat_bus_path(seat);
1589 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1590 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1597 if (!dbus_message_iter_close_container(&sub, &sub2))
1601 if (!dbus_message_iter_close_container(&iter, &sub))
1604 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1605 Inhibitor *inhibitor;
1607 DBusMessageIter iter, sub;
1609 reply = dbus_message_new_method_return(message);
1613 dbus_message_iter_init_append(reply, &iter);
1615 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1618 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1619 DBusMessageIter sub2;
1620 dbus_uint32_t uid, pid;
1621 const char *what, *who, *why, *mode;
1623 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1626 what = strempty(inhibit_what_to_string(inhibitor->what));
1627 who = strempty(inhibitor->who);
1628 why = strempty(inhibitor->why);
1629 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
1630 uid = (dbus_uint32_t) inhibitor->uid;
1631 pid = (dbus_uint32_t) inhibitor->pid;
1633 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1634 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1635 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1636 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
1637 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1638 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1641 if (!dbus_message_iter_close_container(&sub, &sub2))
1645 if (!dbus_message_iter_close_container(&iter, &sub))
1648 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1650 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1653 return bus_send_error_reply(connection, message, &error, r);
1656 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1658 r = bus_manager_create_session(m, message, &reply);
1660 /* Don't delay the work on OOM here, since it might be
1661 * triggered by a low RLIMIT_NOFILE here (since we
1662 * send a dupped fd to the client), and we'd rather
1663 * see this fail quickly then be retried later */
1666 return bus_send_error_reply(connection, message, NULL, r);
1668 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1672 if (!dbus_message_get_args(
1675 DBUS_TYPE_STRING, &name,
1677 return bus_send_error_reply(connection, message, &error, -EINVAL);
1679 session = hashmap_get(m->sessions, name);
1681 return bus_send_error_reply(connection, message, &error, -ENOENT);
1683 /* We use the FIFO to detect stray sessions where the
1684 process invoking PAM dies abnormally. We need to make
1685 sure that that process is not killed if at the clean
1686 end of the session it closes the FIFO. Hence, with
1687 this call explicitly turn off the FIFO logic, so that
1688 the PAM code can finish clean up on its own */
1689 session_remove_fifo(session);
1691 reply = dbus_message_new_method_return(message);
1695 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1699 if (!dbus_message_get_args(
1702 DBUS_TYPE_STRING, &name,
1704 return bus_send_error_reply(connection, message, &error, -EINVAL);
1706 session = hashmap_get(m->sessions, name);
1708 return bus_send_error_reply(connection, message, &error, -ENOENT);
1710 r = session_activate(session);
1712 return bus_send_error_reply(connection, message, NULL, r);
1714 reply = dbus_message_new_method_return(message);
1718 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1719 const char *session_name, *seat_name;
1723 /* Same as ActivateSession() but refuses to work if
1724 * the seat doesn't match */
1726 if (!dbus_message_get_args(
1729 DBUS_TYPE_STRING, &session_name,
1730 DBUS_TYPE_STRING, &seat_name,
1732 return bus_send_error_reply(connection, message, &error, -EINVAL);
1734 session = hashmap_get(m->sessions, session_name);
1736 return bus_send_error_reply(connection, message, &error, -ENOENT);
1738 seat = hashmap_get(m->seats, seat_name);
1740 return bus_send_error_reply(connection, message, &error, -ENOENT);
1742 if (session->seat != seat)
1743 return bus_send_error_reply(connection, message, &error, -EINVAL);
1745 r = session_activate(session);
1747 return bus_send_error_reply(connection, message, NULL, r);
1749 reply = dbus_message_new_method_return(message);
1753 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1754 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1758 if (!dbus_message_get_args(
1761 DBUS_TYPE_STRING, &name,
1763 return bus_send_error_reply(connection, message, &error, -EINVAL);
1765 session = hashmap_get(m->sessions, name);
1767 return bus_send_error_reply(connection, message, &error, -ENOENT);
1769 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1772 reply = dbus_message_new_method_return(message);
1776 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions")) {
1780 HASHMAP_FOREACH(session, m->sessions, i)
1781 if (session_send_lock(session, true) < 0)
1784 reply = dbus_message_new_method_return(message);
1788 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1795 if (!dbus_message_get_args(
1798 DBUS_TYPE_STRING, &name,
1799 DBUS_TYPE_STRING, &swho,
1800 DBUS_TYPE_INT32, &signo,
1802 return bus_send_error_reply(connection, message, &error, -EINVAL);
1807 who = kill_who_from_string(swho);
1809 return bus_send_error_reply(connection, message, &error, -EINVAL);
1812 if (signo <= 0 || signo >= _NSIG)
1813 return bus_send_error_reply(connection, message, &error, -EINVAL);
1815 session = hashmap_get(m->sessions, name);
1817 return bus_send_error_reply(connection, message, &error, -ENOENT);
1819 r = session_kill(session, who, signo);
1821 return bus_send_error_reply(connection, message, NULL, r);
1823 reply = dbus_message_new_method_return(message);
1827 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1832 if (!dbus_message_get_args(
1835 DBUS_TYPE_UINT32, &uid,
1836 DBUS_TYPE_INT32, &signo,
1838 return bus_send_error_reply(connection, message, &error, -EINVAL);
1840 if (signo <= 0 || signo >= _NSIG)
1841 return bus_send_error_reply(connection, message, &error, -EINVAL);
1843 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1845 return bus_send_error_reply(connection, message, &error, -ENOENT);
1847 r = user_kill(user, signo);
1849 return bus_send_error_reply(connection, message, NULL, r);
1851 reply = dbus_message_new_method_return(message);
1855 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1859 if (!dbus_message_get_args(
1862 DBUS_TYPE_STRING, &name,
1864 return bus_send_error_reply(connection, message, &error, -EINVAL);
1866 session = hashmap_get(m->sessions, name);
1868 return bus_send_error_reply(connection, message, &error, -ENOENT);
1870 r = session_stop(session);
1872 return bus_send_error_reply(connection, message, NULL, r);
1874 reply = dbus_message_new_method_return(message);
1878 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1882 if (!dbus_message_get_args(
1885 DBUS_TYPE_UINT32, &uid,
1887 return bus_send_error_reply(connection, message, &error, -EINVAL);
1889 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1891 return bus_send_error_reply(connection, message, &error, -ENOENT);
1893 r = user_stop(user);
1895 return bus_send_error_reply(connection, message, NULL, r);
1897 reply = dbus_message_new_method_return(message);
1901 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1905 if (!dbus_message_get_args(
1908 DBUS_TYPE_STRING, &name,
1910 return bus_send_error_reply(connection, message, &error, -EINVAL);
1912 seat = hashmap_get(m->seats, name);
1914 return bus_send_error_reply(connection, message, &error, -ENOENT);
1916 r = seat_stop_sessions(seat);
1918 return bus_send_error_reply(connection, message, NULL, r);
1920 reply = dbus_message_new_method_return(message);
1924 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
1927 dbus_bool_t b, interactive;
1930 if (!dbus_message_get_args(
1933 DBUS_TYPE_UINT32, &uid,
1934 DBUS_TYPE_BOOLEAN, &b,
1935 DBUS_TYPE_BOOLEAN, &interactive,
1937 return bus_send_error_reply(connection, message, &error, -EINVAL);
1942 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
1944 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
1946 return bus_send_error_reply(connection, message, &error, r);
1948 mkdir_p_label("/var/lib/systemd", 0755);
1950 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
1952 return bus_send_error_reply(connection, message, &error, r);
1954 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
1965 return bus_send_error_reply(connection, message, &error, r);
1967 if (manager_add_user_by_uid(m, uid, &u) >= 0)
1976 if (r < 0 && errno != ENOENT)
1977 return bus_send_error_reply(connection, message, &error, -errno);
1979 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1981 user_add_to_gc_queue(u);
1984 reply = dbus_message_new_method_return(message);
1988 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
1989 const char *sysfs, *seat;
1990 dbus_bool_t interactive;
1992 if (!dbus_message_get_args(
1995 DBUS_TYPE_STRING, &seat,
1996 DBUS_TYPE_STRING, &sysfs,
1997 DBUS_TYPE_BOOLEAN, &interactive,
1999 return bus_send_error_reply(connection, message, &error, -EINVAL);
2001 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
2002 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2004 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
2006 return bus_send_error_reply(connection, message, &error, r);
2008 r = attach_device(m, seat, sysfs);
2010 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2012 reply = dbus_message_new_method_return(message);
2017 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
2018 dbus_bool_t interactive;
2020 if (!dbus_message_get_args(
2023 DBUS_TYPE_BOOLEAN, &interactive,
2025 return bus_send_error_reply(connection, message, &error, -EINVAL);
2027 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
2029 return bus_send_error_reply(connection, message, &error, r);
2031 r = flush_devices(m);
2033 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2035 reply = dbus_message_new_method_return(message);
2039 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
2041 r = bus_manager_do_shutdown_or_sleep(
2042 m, connection, message,
2043 SPECIAL_POWEROFF_TARGET,
2045 "org.freedesktop.login1.power-off",
2046 "org.freedesktop.login1.power-off-multiple-sessions",
2047 "org.freedesktop.login1.power-off-ignore-inhibit",
2051 return bus_send_error_reply(connection, message, &error, r);
2052 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
2053 r = bus_manager_do_shutdown_or_sleep(
2054 m, connection, message,
2055 SPECIAL_REBOOT_TARGET,
2057 "org.freedesktop.login1.reboot",
2058 "org.freedesktop.login1.reboot-multiple-sessions",
2059 "org.freedesktop.login1.reboot-ignore-inhibit",
2063 return bus_send_error_reply(connection, message, &error, r);
2065 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2066 r = bus_manager_do_shutdown_or_sleep(
2067 m, connection, message,
2068 SPECIAL_SUSPEND_TARGET,
2070 "org.freedesktop.login1.suspend",
2071 "org.freedesktop.login1.suspend-multiple-sessions",
2072 "org.freedesktop.login1.suspend-ignore-inhibit",
2076 return bus_send_error_reply(connection, message, &error, r);
2077 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2078 r = bus_manager_do_shutdown_or_sleep(
2079 m, connection, message,
2080 SPECIAL_HIBERNATE_TARGET,
2082 "org.freedesktop.login1.hibernate",
2083 "org.freedesktop.login1.hibernate-multiple-sessions",
2084 "org.freedesktop.login1.hibernate-ignore-inhibit",
2088 return bus_send_error_reply(connection, message, &error, r);
2090 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2092 r = bus_manager_can_shutdown_or_sleep(
2093 m, connection, message,
2095 "org.freedesktop.login1.power-off",
2096 "org.freedesktop.login1.power-off-multiple-sessions",
2097 "org.freedesktop.login1.power-off-ignore-inhibit",
2101 return bus_send_error_reply(connection, message, &error, r);
2102 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2103 r = bus_manager_can_shutdown_or_sleep(
2104 m, connection, message,
2106 "org.freedesktop.login1.reboot",
2107 "org.freedesktop.login1.reboot-multiple-sessions",
2108 "org.freedesktop.login1.reboot-ignore-inhibit",
2112 return bus_send_error_reply(connection, message, &error, r);
2114 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2115 r = bus_manager_can_shutdown_or_sleep(
2116 m, connection, message,
2118 "org.freedesktop.login1.suspend",
2119 "org.freedesktop.login1.suspend-multiple-sessions",
2120 "org.freedesktop.login1.suspend-ignore-inhibit",
2124 return bus_send_error_reply(connection, message, &error, r);
2126 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2127 r = bus_manager_can_shutdown_or_sleep(
2128 m, connection, message,
2130 "org.freedesktop.login1.hibernate",
2131 "org.freedesktop.login1.hibernate-multiple-sessions",
2132 "org.freedesktop.login1.hibernate-ignore-inhibit",
2136 return bus_send_error_reply(connection, message, &error, r);
2138 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2139 char *introspection = NULL;
2148 if (!(reply = dbus_message_new_method_return(message)))
2151 /* We roll our own introspection code here, instead of
2152 * relying on bus_default_message_handler() because we
2153 * need to generate our introspection string
2156 if (!(f = open_memstream(&introspection, &size)))
2159 fputs(INTROSPECTION_BEGIN, f);
2161 HASHMAP_FOREACH(seat, m->seats, i) {
2162 p = bus_path_escape(seat->id);
2165 fprintf(f, "<node name=\"seat/%s\"/>", p);
2170 HASHMAP_FOREACH(user, m->users, i)
2171 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2173 HASHMAP_FOREACH(session, m->sessions, i) {
2174 p = bus_path_escape(session->id);
2177 fprintf(f, "<node name=\"session/%s\"/>", p);
2182 fputs(INTROSPECTION_END, f);
2186 free(introspection);
2195 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2196 free(introspection);
2200 free(introspection);
2202 const BusBoundProperties bps[] = {
2203 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2206 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2210 if (!dbus_connection_send(connection, reply, NULL))
2213 dbus_message_unref(reply);
2216 return DBUS_HANDLER_RESULT_HANDLED;
2220 dbus_message_unref(reply);
2222 dbus_error_free(&error);
2224 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2227 const DBusObjectPathVTable bus_manager_vtable = {
2228 .message_function = manager_message_handler
2231 DBusHandlerResult bus_message_filter(
2232 DBusConnection *connection,
2233 DBusMessage *message,
2236 Manager *m = userdata;
2243 dbus_error_init(&error);
2245 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
2248 if (!dbus_message_get_args(message, &error,
2249 DBUS_TYPE_STRING, &cgroup,
2251 log_error("Failed to parse Released message: %s", bus_error_message(&error));
2253 manager_cgroup_notify_empty(m, cgroup);
2256 dbus_error_free(&error);
2258 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2261 int manager_send_changed(Manager *manager, const char *properties) {
2267 m = bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties);
2271 if (!dbus_connection_send(manager->bus, m, NULL))
2278 dbus_message_unref(m);
2283 int manager_dispatch_delayed(Manager *manager) {
2284 const char *unit_name;
2291 if (!manager->delayed_unit)
2294 /* Continue delay? */
2296 manager->delayed_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC) &&
2297 manager_is_inhibited(manager, manager->delayed_what, INHIBIT_DELAY, NULL);
2301 bus_manager_log_shutdown(manager, manager->delayed_what, manager->delayed_unit);
2303 /* Reset delay data */
2304 unit_name = manager->delayed_unit;
2305 manager->delayed_unit = NULL;
2307 /* Actually do the shutdown */
2308 dbus_error_init(&error);
2309 r = send_start_unit(manager->bus, unit_name, &error);
2311 log_warning("Failed to send delayed message: %s", bus_error_message_or_strerror(&error, -r));
2312 dbus_error_free(&error);
2316 /* Tell people about it */
2317 send_prepare_for(manager, manager->delayed_what, false);