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,
727 "org.freedesktop.login1.inhibit-block" :
728 "org.freedesktop.login1.inhibit-delay", false, NULL, error);
732 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
733 if (ul == (unsigned long) -1) {
738 pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
748 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
752 } while (hashmap_get(m->inhibitors, id));
754 r = manager_add_inhibitor(m, id, &i);
764 i->why = strdup(why);
765 i->who = strdup(who);
767 if (!i->why || !i->who) {
772 fifo_fd = inhibitor_create_fifo(i);
778 reply = dbus_message_new_method_return(message);
784 if (!dbus_message_append_args(
786 DBUS_TYPE_UNIX_FD, &fifo_fd,
787 DBUS_TYPE_INVALID)) {
792 close_nointr_nofail(fifo_fd);
804 close_nointr_nofail(fifo_fd);
807 dbus_message_unref(reply);
812 static int trigger_device(Manager *m, struct udev_device *d) {
813 struct udev_enumerate *e;
814 struct udev_list_entry *first, *item;
819 e = udev_enumerate_new(m->udev);
826 if (udev_enumerate_add_match_parent(e, d) < 0) {
832 if (udev_enumerate_scan_devices(e) < 0) {
837 first = udev_enumerate_get_list_entry(e);
838 udev_list_entry_foreach(item, first) {
842 p = udev_list_entry_get_name(item);
844 t = strappend(p, "/uevent");
850 write_one_line_file(t, "change");
858 udev_enumerate_unref(e);
863 static int attach_device(Manager *m, const char *seat, const char *sysfs) {
864 struct udev_device *d;
865 char *rule = NULL, *file = NULL;
866 const char *id_for_seat;
873 d = udev_device_new_from_syspath(m->udev, sysfs);
877 if (!udev_device_has_tag(d, "seat")) {
882 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
888 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
893 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
898 mkdir_p_label("/etc/udev/rules.d", 0755);
899 r = write_one_line_file_atomic(file, rule);
903 r = trigger_device(m, d);
910 udev_device_unref(d);
915 static int flush_devices(Manager *m) {
920 d = opendir("/etc/udev/rules.d");
923 log_warning("Failed to open /etc/udev/rules.d: %m");
927 while ((de = readdir(d))) {
929 if (!dirent_is_file(de))
932 if (!startswith(de->d_name, "72-seat-"))
935 if (!endswith(de->d_name, ".rules"))
938 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
939 log_warning("Failed to unlink %s: %m", de->d_name);
945 return trigger_device(m, NULL);
948 static int have_multiple_sessions(
949 DBusConnection *connection,
951 DBusMessage *message,
960 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
961 if (ul == (unsigned long) -1)
964 /* Check for other users' sessions. Greeter sessions do not count. */
965 HASHMAP_FOREACH(session, m->sessions, i)
966 if (session->class == SESSION_USER && session->user->uid != ul)
972 static int send_start_unit(DBusConnection *connection, const char *unit_name, DBusError *error) {
973 const char *mode = "replace";
977 return bus_method_call_with_reply (
979 "org.freedesktop.systemd1",
980 "/org/freedesktop/systemd1",
981 "org.freedesktop.systemd1.Manager",
985 DBUS_TYPE_STRING, &unit_name,
986 DBUS_TYPE_STRING, &mode,
990 static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
991 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
992 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
993 [INHIBIT_SLEEP] = "PrepareForSleep"
996 dbus_bool_t active = _active;
997 DBusMessage *message;
1002 assert(w < _INHIBIT_WHAT_MAX);
1003 assert(signal_name[w]);
1005 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1009 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1010 !dbus_connection_send(m->bus, message, NULL))
1013 dbus_message_unref(message);
1017 static int delay_shutdown_or_sleep(Manager *m, InhibitWhat w, const char *unit_name) {
1020 assert(w < _INHIBIT_WHAT_MAX);
1022 /* Tell everybody to prepare for shutdown/sleep */
1023 send_prepare_for(m, w, true);
1025 /* Update timestamp for timeout */
1026 if (!m->delayed_unit)
1027 m->delayed_timestamp = now(CLOCK_MONOTONIC);
1029 /* Remember what we want to do, possibly overriding what kind
1030 * of unit we previously queued. */
1031 m->delayed_unit = unit_name;
1032 m->delayed_what = w;
1037 static int bus_manager_can_shutdown_or_sleep(
1039 DBusConnection *connection,
1040 DBusMessage *message,
1043 const char *action_multiple_sessions,
1044 const char *action_ignore_inhibit,
1045 const char *sleep_type,
1047 DBusMessage **_reply) {
1049 bool multiple_sessions, challenge, blocked, b;
1051 DBusMessage *reply = NULL;
1058 assert(w <= _INHIBIT_WHAT_MAX);
1060 assert(action_multiple_sessions);
1061 assert(action_ignore_inhibit);
1066 r = can_sleep(sleep_type);
1076 r = have_multiple_sessions(connection, m, message, error);
1080 multiple_sessions = r > 0;
1081 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL);
1083 if (multiple_sessions) {
1084 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1091 result = "challenge";
1097 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1101 if (r > 0 && !result)
1103 else if (challenge && (!result || streq(result, "yes")))
1104 result = "challenge";
1109 if (!multiple_sessions && !blocked) {
1110 /* If neither inhibit nor multiple sessions
1111 * apply then just check the normal policy */
1113 r = verify_polkit(connection, message, action, false, &challenge, error);
1120 result = "challenge";
1126 reply = dbus_message_new_method_return(message);
1130 b = dbus_message_append_args(
1132 DBUS_TYPE_STRING, &result,
1135 dbus_message_unref(reply);
1143 static int bus_manager_log_shutdown(
1146 const char *unit_name) {
1153 if (w != INHIBIT_SHUTDOWN)
1156 if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
1157 p = "MESSAGE=System is powering down.";
1158 q = "SHUTDOWN=power-off";
1159 } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
1160 p = "MESSAGE=System is halting.";
1161 q = "SHUTDOWN=halt";
1162 } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
1163 p = "MESSAGE=System is rebooting.";
1164 q = "SHUTDOWN=reboot";
1165 } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
1166 p = "MESSAGE=System is rebooting with kexec.";
1167 q = "SHUTDOWN=kexec";
1169 p = "MESSAGE=System is shutting down.";
1173 return log_struct(LOG_NOTICE,
1174 "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(SD_MESSAGE_SHUTDOWN),
1179 int bus_manager_shutdown_or_sleep_now_or_later(
1181 const char *unit_name,
1191 assert(w <= _INHIBIT_WHAT_MAX);
1194 m->inhibit_delay_max > 0 &&
1195 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL);
1198 /* Shutdown is delayed, keep in mind what we
1199 * want to do, and start a timeout */
1200 r = delay_shutdown_or_sleep(m, w, unit_name);
1202 bus_manager_log_shutdown(m, w, unit_name);
1204 /* Shutdown is not delayed, execute it
1206 r = send_start_unit(m->bus, unit_name, error);
1212 static int bus_manager_do_shutdown_or_sleep(
1214 DBusConnection *connection,
1215 DBusMessage *message,
1216 const char *unit_name,
1219 const char *action_multiple_sessions,
1220 const char *action_ignore_inhibit,
1221 const char *sleep_type,
1223 DBusMessage **_reply) {
1225 dbus_bool_t interactive;
1226 bool multiple_sessions, blocked;
1227 DBusMessage *reply = NULL;
1235 assert(w <= _INHIBIT_WHAT_MAX);
1237 assert(action_multiple_sessions);
1238 assert(action_ignore_inhibit);
1242 if (!dbus_message_get_args(
1245 DBUS_TYPE_BOOLEAN, &interactive,
1250 r = can_sleep(sleep_type);
1258 r = have_multiple_sessions(connection, m, message, error);
1262 multiple_sessions = r > 0;
1263 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL);
1265 if (multiple_sessions) {
1266 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1272 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1277 if (!multiple_sessions && !blocked) {
1278 r = verify_polkit(connection, message, action, interactive, NULL, error);
1283 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
1287 reply = dbus_message_new_method_return(message);
1295 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_button, handle_button, HandleButton);
1297 static const BusProperty bus_login_manager_properties[] = {
1298 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_path), true },
1299 { "Controllers", bus_property_append_strv, "as", offsetof(Manager, controllers), true },
1300 { "ResetControllers", bus_property_append_strv, "as", offsetof(Manager, reset_controllers), true },
1301 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1302 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1303 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1304 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1305 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1306 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1307 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
1308 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1309 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1310 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
1311 { "HandlePowerKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_power_key) },
1312 { "HandleSleepKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_sleep_key) },
1313 { "HandleLidSwitch", bus_manager_append_handle_button, "s", offsetof(Manager, handle_lid_switch) },
1314 { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
1315 { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
1319 static DBusHandlerResult manager_message_handler(
1320 DBusConnection *connection,
1321 DBusMessage *message,
1324 Manager *m = userdata;
1327 DBusMessage *reply = NULL;
1334 dbus_error_init(&error);
1336 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1342 if (!dbus_message_get_args(
1345 DBUS_TYPE_STRING, &name,
1347 return bus_send_error_reply(connection, message, &error, -EINVAL);
1349 session = hashmap_get(m->sessions, name);
1351 return bus_send_error_reply(connection, message, &error, -ENOENT);
1353 reply = dbus_message_new_method_return(message);
1357 p = session_bus_path(session);
1361 b = dbus_message_append_args(
1363 DBUS_TYPE_OBJECT_PATH, &p,
1370 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1376 if (!dbus_message_get_args(
1379 DBUS_TYPE_UINT32, &pid,
1381 return bus_send_error_reply(connection, message, &error, -EINVAL);
1383 r = manager_get_session_by_pid(m, pid, &session);
1385 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1387 reply = dbus_message_new_method_return(message);
1391 p = session_bus_path(session);
1395 b = dbus_message_append_args(
1397 DBUS_TYPE_OBJECT_PATH, &p,
1404 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1410 if (!dbus_message_get_args(
1413 DBUS_TYPE_UINT32, &uid,
1415 return bus_send_error_reply(connection, message, &error, -EINVAL);
1417 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1419 return bus_send_error_reply(connection, message, &error, -ENOENT);
1421 reply = dbus_message_new_method_return(message);
1425 p = user_bus_path(user);
1429 b = dbus_message_append_args(
1431 DBUS_TYPE_OBJECT_PATH, &p,
1438 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1444 if (!dbus_message_get_args(
1447 DBUS_TYPE_STRING, &name,
1449 return bus_send_error_reply(connection, message, &error, -EINVAL);
1451 seat = hashmap_get(m->seats, name);
1453 return bus_send_error_reply(connection, message, &error, -ENOENT);
1455 reply = dbus_message_new_method_return(message);
1459 p = seat_bus_path(seat);
1463 b = dbus_message_append_args(
1465 DBUS_TYPE_OBJECT_PATH, &p,
1472 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1476 DBusMessageIter iter, sub;
1477 const char *empty = "";
1479 reply = dbus_message_new_method_return(message);
1483 dbus_message_iter_init_append(reply, &iter);
1485 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1488 HASHMAP_FOREACH(session, m->sessions, i) {
1489 DBusMessageIter sub2;
1492 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1495 uid = session->user->uid;
1497 p = session_bus_path(session);
1501 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1502 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1503 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1504 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1505 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1512 if (!dbus_message_iter_close_container(&sub, &sub2))
1516 if (!dbus_message_iter_close_container(&iter, &sub))
1519 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1523 DBusMessageIter iter, sub;
1525 reply = dbus_message_new_method_return(message);
1529 dbus_message_iter_init_append(reply, &iter);
1531 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1534 HASHMAP_FOREACH(user, m->users, i) {
1535 DBusMessageIter sub2;
1538 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1543 p = user_bus_path(user);
1547 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1548 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1549 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1556 if (!dbus_message_iter_close_container(&sub, &sub2))
1560 if (!dbus_message_iter_close_container(&iter, &sub))
1563 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1567 DBusMessageIter iter, sub;
1569 reply = dbus_message_new_method_return(message);
1573 dbus_message_iter_init_append(reply, &iter);
1575 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1578 HASHMAP_FOREACH(seat, m->seats, i) {
1579 DBusMessageIter sub2;
1581 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1584 p = seat_bus_path(seat);
1588 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1589 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1596 if (!dbus_message_iter_close_container(&sub, &sub2))
1600 if (!dbus_message_iter_close_container(&iter, &sub))
1603 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1604 Inhibitor *inhibitor;
1606 DBusMessageIter iter, sub;
1608 reply = dbus_message_new_method_return(message);
1612 dbus_message_iter_init_append(reply, &iter);
1614 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1617 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1618 DBusMessageIter sub2;
1619 dbus_uint32_t uid, pid;
1620 const char *what, *who, *why, *mode;
1622 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1625 what = strempty(inhibit_what_to_string(inhibitor->what));
1626 who = strempty(inhibitor->who);
1627 why = strempty(inhibitor->why);
1628 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
1629 uid = (dbus_uint32_t) inhibitor->uid;
1630 pid = (dbus_uint32_t) inhibitor->pid;
1632 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1633 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1634 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1635 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
1636 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1637 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1640 if (!dbus_message_iter_close_container(&sub, &sub2))
1644 if (!dbus_message_iter_close_container(&iter, &sub))
1647 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1649 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1652 return bus_send_error_reply(connection, message, &error, r);
1655 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1657 r = bus_manager_create_session(m, message, &reply);
1659 /* Don't delay the work on OOM here, since it might be
1660 * triggered by a low RLIMIT_NOFILE here (since we
1661 * send a dupped fd to the client), and we'd rather
1662 * see this fail quickly then be retried later */
1665 return bus_send_error_reply(connection, message, NULL, r);
1667 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1671 if (!dbus_message_get_args(
1674 DBUS_TYPE_STRING, &name,
1676 return bus_send_error_reply(connection, message, &error, -EINVAL);
1678 session = hashmap_get(m->sessions, name);
1680 return bus_send_error_reply(connection, message, &error, -ENOENT);
1682 /* We use the FIFO to detect stray sessions where the
1683 process invoking PAM dies abnormally. We need to make
1684 sure that that process is not killed if at the clean
1685 end of the session it closes the FIFO. Hence, with
1686 this call explicitly turn off the FIFO logic, so that
1687 the PAM code can finish clean up on its own */
1688 session_remove_fifo(session);
1690 reply = dbus_message_new_method_return(message);
1694 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1698 if (!dbus_message_get_args(
1701 DBUS_TYPE_STRING, &name,
1703 return bus_send_error_reply(connection, message, &error, -EINVAL);
1705 session = hashmap_get(m->sessions, name);
1707 return bus_send_error_reply(connection, message, &error, -ENOENT);
1709 r = session_activate(session);
1711 return bus_send_error_reply(connection, message, NULL, r);
1713 reply = dbus_message_new_method_return(message);
1717 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1718 const char *session_name, *seat_name;
1722 /* Same as ActivateSession() but refuses to work if
1723 * the seat doesn't match */
1725 if (!dbus_message_get_args(
1728 DBUS_TYPE_STRING, &session_name,
1729 DBUS_TYPE_STRING, &seat_name,
1731 return bus_send_error_reply(connection, message, &error, -EINVAL);
1733 session = hashmap_get(m->sessions, session_name);
1735 return bus_send_error_reply(connection, message, &error, -ENOENT);
1737 seat = hashmap_get(m->seats, seat_name);
1739 return bus_send_error_reply(connection, message, &error, -ENOENT);
1741 if (session->seat != seat)
1742 return bus_send_error_reply(connection, message, &error, -EINVAL);
1744 r = session_activate(session);
1746 return bus_send_error_reply(connection, message, NULL, r);
1748 reply = dbus_message_new_method_return(message);
1752 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1753 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1757 if (!dbus_message_get_args(
1760 DBUS_TYPE_STRING, &name,
1762 return bus_send_error_reply(connection, message, &error, -EINVAL);
1764 session = hashmap_get(m->sessions, name);
1766 return bus_send_error_reply(connection, message, &error, -ENOENT);
1768 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1771 reply = dbus_message_new_method_return(message);
1775 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions")) {
1779 HASHMAP_FOREACH(session, m->sessions, i)
1780 if (session_send_lock(session, true) < 0)
1783 reply = dbus_message_new_method_return(message);
1787 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1794 if (!dbus_message_get_args(
1797 DBUS_TYPE_STRING, &name,
1798 DBUS_TYPE_STRING, &swho,
1799 DBUS_TYPE_INT32, &signo,
1801 return bus_send_error_reply(connection, message, &error, -EINVAL);
1806 who = kill_who_from_string(swho);
1808 return bus_send_error_reply(connection, message, &error, -EINVAL);
1811 if (signo <= 0 || signo >= _NSIG)
1812 return bus_send_error_reply(connection, message, &error, -EINVAL);
1814 session = hashmap_get(m->sessions, name);
1816 return bus_send_error_reply(connection, message, &error, -ENOENT);
1818 r = session_kill(session, who, signo);
1820 return bus_send_error_reply(connection, message, NULL, r);
1822 reply = dbus_message_new_method_return(message);
1826 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1831 if (!dbus_message_get_args(
1834 DBUS_TYPE_UINT32, &uid,
1835 DBUS_TYPE_INT32, &signo,
1837 return bus_send_error_reply(connection, message, &error, -EINVAL);
1839 if (signo <= 0 || signo >= _NSIG)
1840 return bus_send_error_reply(connection, message, &error, -EINVAL);
1842 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1844 return bus_send_error_reply(connection, message, &error, -ENOENT);
1846 r = user_kill(user, signo);
1848 return bus_send_error_reply(connection, message, NULL, r);
1850 reply = dbus_message_new_method_return(message);
1854 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1858 if (!dbus_message_get_args(
1861 DBUS_TYPE_STRING, &name,
1863 return bus_send_error_reply(connection, message, &error, -EINVAL);
1865 session = hashmap_get(m->sessions, name);
1867 return bus_send_error_reply(connection, message, &error, -ENOENT);
1869 r = session_stop(session);
1871 return bus_send_error_reply(connection, message, NULL, r);
1873 reply = dbus_message_new_method_return(message);
1877 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1881 if (!dbus_message_get_args(
1884 DBUS_TYPE_UINT32, &uid,
1886 return bus_send_error_reply(connection, message, &error, -EINVAL);
1888 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1890 return bus_send_error_reply(connection, message, &error, -ENOENT);
1892 r = user_stop(user);
1894 return bus_send_error_reply(connection, message, NULL, r);
1896 reply = dbus_message_new_method_return(message);
1900 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1904 if (!dbus_message_get_args(
1907 DBUS_TYPE_STRING, &name,
1909 return bus_send_error_reply(connection, message, &error, -EINVAL);
1911 seat = hashmap_get(m->seats, name);
1913 return bus_send_error_reply(connection, message, &error, -ENOENT);
1915 r = seat_stop_sessions(seat);
1917 return bus_send_error_reply(connection, message, NULL, r);
1919 reply = dbus_message_new_method_return(message);
1923 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
1926 dbus_bool_t b, interactive;
1929 if (!dbus_message_get_args(
1932 DBUS_TYPE_UINT32, &uid,
1933 DBUS_TYPE_BOOLEAN, &b,
1934 DBUS_TYPE_BOOLEAN, &interactive,
1936 return bus_send_error_reply(connection, message, &error, -EINVAL);
1941 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
1943 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
1945 return bus_send_error_reply(connection, message, &error, r);
1947 mkdir_p_label("/var/lib/systemd", 0755);
1949 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
1951 return bus_send_error_reply(connection, message, &error, r);
1953 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
1964 return bus_send_error_reply(connection, message, &error, r);
1966 if (manager_add_user_by_uid(m, uid, &u) >= 0)
1975 if (r < 0 && errno != ENOENT)
1976 return bus_send_error_reply(connection, message, &error, -errno);
1978 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1980 user_add_to_gc_queue(u);
1983 reply = dbus_message_new_method_return(message);
1987 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
1988 const char *sysfs, *seat;
1989 dbus_bool_t interactive;
1991 if (!dbus_message_get_args(
1994 DBUS_TYPE_STRING, &seat,
1995 DBUS_TYPE_STRING, &sysfs,
1996 DBUS_TYPE_BOOLEAN, &interactive,
1998 return bus_send_error_reply(connection, message, &error, -EINVAL);
2000 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
2001 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2003 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
2005 return bus_send_error_reply(connection, message, &error, r);
2007 r = attach_device(m, seat, sysfs);
2009 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2011 reply = dbus_message_new_method_return(message);
2016 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
2017 dbus_bool_t interactive;
2019 if (!dbus_message_get_args(
2022 DBUS_TYPE_BOOLEAN, &interactive,
2024 return bus_send_error_reply(connection, message, &error, -EINVAL);
2026 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
2028 return bus_send_error_reply(connection, message, &error, r);
2030 r = flush_devices(m);
2032 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2034 reply = dbus_message_new_method_return(message);
2038 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
2040 r = bus_manager_do_shutdown_or_sleep(
2041 m, connection, message,
2042 SPECIAL_POWEROFF_TARGET,
2044 "org.freedesktop.login1.power-off",
2045 "org.freedesktop.login1.power-off-multiple-sessions",
2046 "org.freedesktop.login1.power-off-ignore-inhibit",
2050 return bus_send_error_reply(connection, message, &error, r);
2051 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
2052 r = bus_manager_do_shutdown_or_sleep(
2053 m, connection, message,
2054 SPECIAL_REBOOT_TARGET,
2056 "org.freedesktop.login1.reboot",
2057 "org.freedesktop.login1.reboot-multiple-sessions",
2058 "org.freedesktop.login1.reboot-ignore-inhibit",
2062 return bus_send_error_reply(connection, message, &error, r);
2064 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2065 r = bus_manager_do_shutdown_or_sleep(
2066 m, connection, message,
2067 SPECIAL_SUSPEND_TARGET,
2069 "org.freedesktop.login1.suspend",
2070 "org.freedesktop.login1.suspend-multiple-sessions",
2071 "org.freedesktop.login1.suspend-ignore-inhibit",
2075 return bus_send_error_reply(connection, message, &error, r);
2076 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2077 r = bus_manager_do_shutdown_or_sleep(
2078 m, connection, message,
2079 SPECIAL_HIBERNATE_TARGET,
2081 "org.freedesktop.login1.hibernate",
2082 "org.freedesktop.login1.hibernate-multiple-sessions",
2083 "org.freedesktop.login1.hibernate-ignore-inhibit",
2087 return bus_send_error_reply(connection, message, &error, r);
2089 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2091 r = bus_manager_can_shutdown_or_sleep(
2092 m, connection, message,
2094 "org.freedesktop.login1.power-off",
2095 "org.freedesktop.login1.power-off-multiple-sessions",
2096 "org.freedesktop.login1.power-off-ignore-inhibit",
2100 return bus_send_error_reply(connection, message, &error, r);
2101 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2102 r = bus_manager_can_shutdown_or_sleep(
2103 m, connection, message,
2105 "org.freedesktop.login1.reboot",
2106 "org.freedesktop.login1.reboot-multiple-sessions",
2107 "org.freedesktop.login1.reboot-ignore-inhibit",
2111 return bus_send_error_reply(connection, message, &error, r);
2113 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2114 r = bus_manager_can_shutdown_or_sleep(
2115 m, connection, message,
2117 "org.freedesktop.login1.suspend",
2118 "org.freedesktop.login1.suspend-multiple-sessions",
2119 "org.freedesktop.login1.suspend-ignore-inhibit",
2123 return bus_send_error_reply(connection, message, &error, r);
2125 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2126 r = bus_manager_can_shutdown_or_sleep(
2127 m, connection, message,
2129 "org.freedesktop.login1.hibernate",
2130 "org.freedesktop.login1.hibernate-multiple-sessions",
2131 "org.freedesktop.login1.hibernate-ignore-inhibit",
2135 return bus_send_error_reply(connection, message, &error, r);
2137 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2138 char *introspection = NULL;
2147 if (!(reply = dbus_message_new_method_return(message)))
2150 /* We roll our own introspection code here, instead of
2151 * relying on bus_default_message_handler() because we
2152 * need to generate our introspection string
2155 if (!(f = open_memstream(&introspection, &size)))
2158 fputs(INTROSPECTION_BEGIN, f);
2160 HASHMAP_FOREACH(seat, m->seats, i) {
2161 p = bus_path_escape(seat->id);
2164 fprintf(f, "<node name=\"seat/%s\"/>", p);
2169 HASHMAP_FOREACH(user, m->users, i)
2170 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2172 HASHMAP_FOREACH(session, m->sessions, i) {
2173 p = bus_path_escape(session->id);
2176 fprintf(f, "<node name=\"session/%s\"/>", p);
2181 fputs(INTROSPECTION_END, f);
2185 free(introspection);
2194 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2195 free(introspection);
2199 free(introspection);
2201 const BusBoundProperties bps[] = {
2202 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2205 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2209 if (!dbus_connection_send(connection, reply, NULL))
2212 dbus_message_unref(reply);
2215 return DBUS_HANDLER_RESULT_HANDLED;
2219 dbus_message_unref(reply);
2221 dbus_error_free(&error);
2223 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2226 const DBusObjectPathVTable bus_manager_vtable = {
2227 .message_function = manager_message_handler
2230 DBusHandlerResult bus_message_filter(
2231 DBusConnection *connection,
2232 DBusMessage *message,
2235 Manager *m = userdata;
2242 dbus_error_init(&error);
2244 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
2247 if (!dbus_message_get_args(message, &error,
2248 DBUS_TYPE_STRING, &cgroup,
2250 log_error("Failed to parse Released message: %s", bus_error_message(&error));
2252 manager_cgroup_notify_empty(m, cgroup);
2255 dbus_error_free(&error);
2257 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2260 int manager_send_changed(Manager *manager, const char *properties) {
2266 m = bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties);
2270 if (!dbus_connection_send(manager->bus, m, NULL))
2277 dbus_message_unref(m);
2282 int manager_dispatch_delayed(Manager *manager) {
2283 const char *unit_name;
2290 if (!manager->delayed_unit)
2293 /* Continue delay? */
2295 manager->delayed_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC) &&
2296 manager_is_inhibited(manager, manager->delayed_what, INHIBIT_DELAY, NULL);
2300 bus_manager_log_shutdown(manager, manager->delayed_what, manager->delayed_unit);
2302 /* Reset delay data */
2303 unit_name = manager->delayed_unit;
2304 manager->delayed_unit = NULL;
2306 /* Actually do the shutdown */
2307 dbus_error_init(&error);
2308 r = send_start_unit(manager->bus, unit_name, &error);
2310 log_warning("Failed to send delayed message: %s", bus_error_message_or_strerror(&error, -r));
2311 dbus_error_free(&error);
2315 /* Tell people about it */
2316 send_prepare_for(manager, manager->delayed_what, false);