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"
34 #define BUS_MANAGER_INTERFACE \
35 " <interface name=\"org.freedesktop.login1.Manager\">\n" \
36 " <method name=\"GetSession\">\n" \
37 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
38 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
40 " <method name=\"GetSessionByPID\">\n" \
41 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
42 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
44 " <method name=\"GetUser\">\n" \
45 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
46 " <arg name=\"user\" type=\"o\" direction=\"out\"/>\n" \
48 " <method name=\"GetSeat\">\n" \
49 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
50 " <arg name=\"seat\" type=\"o\" direction=\"out\"/>\n" \
52 " <method name=\"ListSessions\">\n" \
53 " <arg name=\"sessions\" type=\"a(susso)\" direction=\"out\"/>\n" \
55 " <method name=\"ListUsers\">\n" \
56 " <arg name=\"users\" type=\"a(uso)\" direction=\"out\"/>\n" \
58 " <method name=\"ListSeats\">\n" \
59 " <arg name=\"seats\" type=\"a(so)\" direction=\"out\"/>\n" \
61 " <method name=\"CreateSession\">\n" \
62 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
63 " <arg name=\"leader\" type=\"u\" direction=\"in\"/>\n" \
64 " <arg name=\"sevice\" type=\"s\" direction=\"in\"/>\n" \
65 " <arg name=\"type\" type=\"s\" direction=\"in\"/>\n" \
66 " <arg name=\"class\" type=\"s\" direction=\"in\"/>\n" \
67 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
68 " <arg name=\"vtnr\" type=\"u\" direction=\"in\"/>\n" \
69 " <arg name=\"tty\" type=\"s\" direction=\"in\"/>\n" \
70 " <arg name=\"display\" type=\"s\" direction=\"in\"/>\n" \
71 " <arg name=\"remote\" type=\"b\" direction=\"in\"/>\n" \
72 " <arg name=\"remote_user\" type=\"s\" direction=\"in\"/>\n" \
73 " <arg name=\"remote_host\" type=\"s\" direction=\"in\"/>\n" \
74 " <arg name=\"controllers\" type=\"as\" direction=\"in\"/>\n" \
75 " <arg name=\"reset_controllers\" type=\"as\" direction=\"in\"/>\n" \
76 " <arg name=\"kill_processes\" type=\"b\" direction=\"in\"/>\n" \
77 " <arg name=\"id\" type=\"s\" direction=\"out\"/>\n" \
78 " <arg name=\"path\" type=\"o\" direction=\"out\"/>\n" \
79 " <arg name=\"runtime_path\" type=\"o\" direction=\"out\"/>\n" \
80 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
81 " <arg name=\"seat\" type=\"s\" direction=\"out\"/>\n" \
82 " <arg name=\"vtnr\" type=\"u\" direction=\"out\"/>\n" \
84 " <method name=\"ReleaseSession\">\n" \
85 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
87 " <method name=\"ActivateSession\">\n" \
88 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
90 " <method name=\"ActivateSessionOnSeat\">\n" \
91 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
92 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
94 " <method name=\"LockSession\">\n" \
95 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
97 " <method name=\"UnlockSession\">\n" \
98 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
100 " <method name=\"KillSession\">\n" \
101 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
102 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
103 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
105 " <method name=\"KillUser\">\n" \
106 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
107 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
109 " <method name=\"TerminateSession\">\n" \
110 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
112 " <method name=\"TerminateUser\">\n" \
113 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
115 " <method name=\"TerminateSeat\">\n" \
116 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
118 " <method name=\"SetUserLinger\">\n" \
119 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
120 " <arg name=\"b\" type=\"b\" direction=\"in\"/>\n" \
121 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
123 " <method name=\"AttachDevice\">\n" \
124 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
125 " <arg name=\"sysfs\" type=\"s\" direction=\"in\"/>\n" \
126 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
128 " <method name=\"FlushDevices\">\n" \
129 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
131 " <method name=\"PowerOff\">\n" \
132 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
134 " <method name=\"Reboot\">\n" \
135 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
137 " <method name=\"CanPowerOff\">\n" \
138 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
140 " <method name=\"CanReboot\">\n" \
141 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
143 " <method name=\"Inhibit\">\n" \
144 " <arg name=\"what\" type=\"s\" direction=\"in\"/>\n" \
145 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
146 " <arg name=\"why\" type=\"s\" direction=\"in\"/>\n" \
147 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
148 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
150 " <method name=\"ListInhibitors\">\n" \
151 " <arg name=\"inhibitors\" type=\"a(ssssuu)\" direction=\"out\"/>\n" \
153 " <signal name=\"SessionNew\">\n" \
154 " <arg name=\"id\" type=\"s\"/>\n" \
155 " <arg name=\"path\" type=\"o\"/>\n" \
157 " <signal name=\"SessionRemoved\">\n" \
158 " <arg name=\"id\" type=\"s\"/>\n" \
159 " <arg name=\"path\" type=\"o\"/>\n" \
161 " <signal name=\"UserNew\">\n" \
162 " <arg name=\"uid\" type=\"u\"/>\n" \
163 " <arg name=\"path\" type=\"o\"/>\n" \
165 " <signal name=\"UserRemoved\">\n" \
166 " <arg name=\"uid\" type=\"u\"/>\n" \
167 " <arg name=\"path\" type=\"o\"/>\n" \
169 " <signal name=\"SeatNew\">\n" \
170 " <arg name=\"id\" type=\"s\"/>\n" \
171 " <arg name=\"path\" type=\"o\"/>\n" \
173 " <signal name=\"SeatRemoved\">\n" \
174 " <arg name=\"id\" type=\"s\"/>\n" \
175 " <arg name=\"path\" type=\"o\"/>\n" \
177 " <signal name=\"PrepareForShutdown\">\n" \
178 " <arg name=\"active\" type=\"b\"/>\n" \
180 " <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
181 " <property name=\"Controllers\" type=\"as\" access=\"read\"/>\n" \
182 " <property name=\"ResetControllers\" type=\"as\" access=\"read\"/>\n" \
183 " <property name=\"NAutoVTs\" type=\"u\" access=\"read\"/>\n" \
184 " <property name=\"KillOnlyUsers\" type=\"as\" access=\"read\"/>\n" \
185 " <property name=\"KillExcludeUsers\" type=\"as\" access=\"read\"/>\n" \
186 " <property name=\"KillUserProcesses\" type=\"b\" access=\"read\"/>\n" \
187 " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
188 " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
189 " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
190 " <property name=\"BlockInhibited\" type=\"s\" access=\"read\"/>\n" \
191 " <property name=\"DelayInhibited\" type=\"s\" access=\"read\"/>\n" \
192 " <property name=\"InhibitDelayMaxUSec\" type=\"t\" access=\"read\"/>\n" \
195 #define INTROSPECTION_BEGIN \
196 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
198 BUS_MANAGER_INTERFACE \
199 BUS_PROPERTIES_INTERFACE \
201 BUS_INTROSPECTABLE_INTERFACE
203 #define INTROSPECTION_END \
206 #define INTERFACES_LIST \
207 BUS_GENERIC_INTERFACES_LIST \
208 "org.freedesktop.login1.Manager\0"
210 static int bus_manager_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
218 b = manager_get_idle_hint(m, NULL) > 0;
219 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
225 static int bus_manager_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
234 manager_get_idle_hint(m, &t);
235 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
237 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
243 static int bus_manager_append_inhibited(DBusMessageIter *i, const char *property, void *data) {
248 w = manager_inhibit_what(m, streq(property, "BlockInhibited") ? INHIBIT_BLOCK : INHIBIT_DELAY);
249 p = inhibit_what_to_string(w);
251 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &p))
257 static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMessage **_reply) {
258 Session *session = NULL;
260 const char *type, *class, *seat, *tty, *display, *remote_user, *remote_host, *service;
261 uint32_t uid, leader, audit_id = 0;
262 dbus_bool_t remote, kill_processes;
263 char **controllers = NULL, **reset_controllers = NULL;
267 DBusMessageIter iter;
272 DBusMessage *reply = NULL;
279 if (!dbus_message_iter_init(message, &iter) ||
280 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
283 dbus_message_iter_get_basic(&iter, &uid);
285 if (!dbus_message_iter_next(&iter) ||
286 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
289 dbus_message_iter_get_basic(&iter, &leader);
292 !dbus_message_iter_next(&iter) ||
293 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
296 dbus_message_iter_get_basic(&iter, &service);
298 if (!dbus_message_iter_next(&iter) ||
299 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
302 dbus_message_iter_get_basic(&iter, &type);
303 t = session_type_from_string(type);
306 !dbus_message_iter_next(&iter) ||
307 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
310 dbus_message_iter_get_basic(&iter, &class);
314 c = session_class_from_string(class);
317 !dbus_message_iter_next(&iter) ||
318 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
321 dbus_message_iter_get_basic(&iter, &seat);
326 s = hashmap_get(m->seats, seat);
331 if (!dbus_message_iter_next(&iter) ||
332 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
335 dbus_message_iter_get_basic(&iter, &vtnr);
337 if (!dbus_message_iter_next(&iter) ||
338 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
341 dbus_message_iter_get_basic(&iter, &tty);
343 if (tty_is_vc(tty)) {
348 else if (s != m->vtconsole)
351 v = vtnr_from_tty(tty);
354 return v < 0 ? v : -EINVAL;
358 else if (vtnr != (uint32_t) v)
360 } else if (tty_is_console(tty)) {
364 else if (s != m->vtconsole)
370 } else if (!isempty(tty) && s && seat_is_vtconsole(s))
374 if (seat_can_multi_session(s)) {
383 if (!dbus_message_iter_next(&iter) ||
384 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
387 dbus_message_iter_get_basic(&iter, &display);
389 if (!dbus_message_iter_next(&iter) ||
390 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
393 dbus_message_iter_get_basic(&iter, &remote);
395 if (!dbus_message_iter_next(&iter) ||
396 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
399 dbus_message_iter_get_basic(&iter, &remote_user);
401 if (!dbus_message_iter_next(&iter) ||
402 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
405 dbus_message_iter_get_basic(&iter, &remote_host);
407 if (!dbus_message_iter_next(&iter) ||
408 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
409 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
412 r = bus_parse_strv_iter(&iter, &controllers);
416 if (strv_contains(controllers, "systemd") ||
417 !dbus_message_iter_next(&iter) ||
418 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
419 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) {
424 r = bus_parse_strv_iter(&iter, &reset_controllers);
428 if (strv_contains(reset_controllers, "systemd") ||
429 !dbus_message_iter_next(&iter) ||
430 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) {
435 dbus_message_iter_get_basic(&iter, &kill_processes);
437 r = manager_add_user_by_uid(m, uid, &user);
441 audit_session_from_pid(leader, &audit_id);
444 asprintf(&id, "%lu", (unsigned long) audit_id);
451 session = hashmap_get(m->sessions, id);
456 fifo_fd = session_create_fifo(session);
462 /* Session already exists, client is probably
463 * something like "su" which changes uid but
464 * is still the same audit session */
466 reply = dbus_message_new_method_return(message);
472 p = session_bus_path(session);
478 seat = session->seat ? session->seat->id : "";
479 vtnr = session->vtnr;
480 b = dbus_message_append_args(
482 DBUS_TYPE_STRING, &session->id,
483 DBUS_TYPE_OBJECT_PATH, &p,
484 DBUS_TYPE_STRING, &session->user->runtime_path,
485 DBUS_TYPE_UNIX_FD, &fifo_fd,
486 DBUS_TYPE_STRING, &seat,
487 DBUS_TYPE_UINT32, &vtnr,
496 close_nointr_nofail(fifo_fd);
499 strv_free(controllers);
500 strv_free(reset_controllers);
510 if (asprintf(&id, "c%lu", ++m->session_counter) < 0) {
515 } while (hashmap_get(m->sessions, id));
518 r = manager_add_session(m, user, id, &session);
523 session->leader = leader;
524 session->audit_id = audit_id;
527 session->remote = remote;
528 session->controllers = controllers;
529 session->reset_controllers = reset_controllers;
530 session->kill_processes = kill_processes;
531 session->vtnr = vtnr;
533 controllers = reset_controllers = NULL;
536 session->tty = strdup(tty);
543 if (!isempty(display)) {
544 session->display = strdup(display);
545 if (!session->display) {
551 if (!isempty(remote_user)) {
552 session->remote_user = strdup(remote_user);
553 if (!session->remote_user) {
559 if (!isempty(remote_host)) {
560 session->remote_host = strdup(remote_host);
561 if (!session->remote_host) {
567 if (!isempty(service)) {
568 session->service = strdup(service);
569 if (!session->service) {
575 fifo_fd = session_create_fifo(session);
582 r = seat_attach_session(s, session);
587 r = session_start(session);
591 reply = dbus_message_new_method_return(message);
597 p = session_bus_path(session);
603 seat = s ? s->id : "";
604 b = dbus_message_append_args(
606 DBUS_TYPE_STRING, &session->id,
607 DBUS_TYPE_OBJECT_PATH, &p,
608 DBUS_TYPE_STRING, &session->user->runtime_path,
609 DBUS_TYPE_UNIX_FD, &fifo_fd,
610 DBUS_TYPE_STRING, &seat,
611 DBUS_TYPE_UINT32, &vtnr,
620 close_nointr_nofail(fifo_fd);
626 strv_free(controllers);
627 strv_free(reset_controllers);
630 session_add_to_gc_queue(session);
633 user_add_to_gc_queue(user);
636 close_nointr_nofail(fifo_fd);
639 dbus_message_unref(reply);
644 static int bus_manager_inhibit(Manager *m, DBusConnection *connection, DBusMessage *message, DBusError *error, DBusMessage **_reply) {
647 const char *who, *why, *what, *mode;
653 DBusMessage *reply = NULL;
661 if (!dbus_message_get_args(
664 DBUS_TYPE_STRING, &what,
665 DBUS_TYPE_STRING, &who,
666 DBUS_TYPE_STRING, &why,
667 DBUS_TYPE_STRING, &mode,
668 DBUS_TYPE_INVALID)) {
673 w = inhibit_what_from_string(what);
679 mm = inhibit_mode_from_string(mode);
685 r = verify_polkit(connection, message,
687 "org.freedesktop.login1.inhibit-block" :
688 "org.freedesktop.login1.inhibit-delay", false, NULL, error);
692 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
693 if (ul == (unsigned long) -1) {
698 pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
708 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
712 } while (hashmap_get(m->inhibitors, id));
714 r = manager_add_inhibitor(m, id, &i);
724 i->why = strdup(why);
725 i->who = strdup(who);
727 if (!i->why || !i->who) {
732 fifo_fd = inhibitor_create_fifo(i);
738 reply = dbus_message_new_method_return(message);
744 if (!dbus_message_append_args(
746 DBUS_TYPE_UNIX_FD, &fifo_fd,
747 DBUS_TYPE_INVALID)) {
752 close_nointr_nofail(fifo_fd);
764 close_nointr_nofail(fifo_fd);
767 dbus_message_unref(reply);
772 static int trigger_device(Manager *m, struct udev_device *d) {
773 struct udev_enumerate *e;
774 struct udev_list_entry *first, *item;
779 e = udev_enumerate_new(m->udev);
786 if (udev_enumerate_add_match_parent(e, d) < 0) {
792 if (udev_enumerate_scan_devices(e) < 0) {
797 first = udev_enumerate_get_list_entry(e);
798 udev_list_entry_foreach(item, first) {
802 p = udev_list_entry_get_name(item);
804 t = strappend(p, "/uevent");
810 write_one_line_file(t, "change");
818 udev_enumerate_unref(e);
823 static int attach_device(Manager *m, const char *seat, const char *sysfs) {
824 struct udev_device *d;
825 char *rule = NULL, *file = NULL;
826 const char *id_for_seat;
833 d = udev_device_new_from_syspath(m->udev, sysfs);
837 if (!udev_device_has_tag(d, "seat")) {
842 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
848 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
853 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
858 mkdir_p("/etc/udev/rules.d", 0755);
859 r = write_one_line_file_atomic(file, rule);
863 r = trigger_device(m, d);
870 udev_device_unref(d);
875 static int flush_devices(Manager *m) {
880 d = opendir("/etc/udev/rules.d");
883 log_warning("Failed to open /etc/udev/rules.d: %m");
887 while ((de = readdir(d))) {
889 if (!dirent_is_file(de))
892 if (!startswith(de->d_name, "72-seat-"))
895 if (!endswith(de->d_name, ".rules"))
898 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
899 log_warning("Failed to unlink %s: %m", de->d_name);
905 return trigger_device(m, NULL);
908 static int have_multiple_sessions(
909 DBusConnection *connection,
911 DBusMessage *message,
918 if (hashmap_size(m->sessions) > 1)
921 /* Hmm, there's only one session, but let's make sure it
922 * actually belongs to the user who is asking. If not, better
923 * be safe than sorry. */
925 s = hashmap_first(m->sessions);
929 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
930 if (ul == (unsigned long) -1)
933 return s->user->uid != ul;
939 static int send_start_unit(DBusConnection *connection, const char *name, DBusError *error) {
940 DBusMessage *message, *reply;
941 const char *mode = "replace";
946 message = dbus_message_new_method_call(
947 "org.freedesktop.systemd1",
948 "/org/freedesktop/systemd1",
949 "org.freedesktop.systemd1.Manager",
954 if (!dbus_message_append_args(message,
955 DBUS_TYPE_STRING, &name,
956 DBUS_TYPE_STRING, &mode,
957 DBUS_TYPE_INVALID)) {
958 dbus_message_unref(message);
962 reply = dbus_connection_send_with_reply_and_block(connection, message, -1, error);
963 dbus_message_unref(message);
968 dbus_message_unref(reply);
972 static int send_prepare_for_shutdown(Manager *m, bool _active) {
973 dbus_bool_t active = _active;
974 DBusMessage *message;
979 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", "PrepareForShutdown");
983 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
984 !dbus_connection_send(m->bus, message, NULL))
987 dbus_message_unref(message);
991 static int delay_shutdown(Manager *m, const char *name) {
994 if (!m->delayed_shutdown) {
995 /* Tell everybody to prepare for shutdown */
996 send_prepare_for_shutdown(m, true);
998 /* Update timestamp for timeout */
999 m->delayed_shutdown_timestamp = now(CLOCK_MONOTONIC);
1002 /* Remember what we want to do, possibly overriding what kind
1003 * of shutdown we previously queued. */
1004 m->delayed_shutdown = name;
1009 static const BusProperty bus_login_manager_properties[] = {
1010 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_path), true },
1011 { "Controllers", bus_property_append_strv, "as", offsetof(Manager, controllers), true },
1012 { "ResetControllers", bus_property_append_strv, "as", offsetof(Manager, reset_controllers), true },
1013 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1014 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1015 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1016 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1017 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1018 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1019 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
1020 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1021 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1022 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
1026 static DBusHandlerResult manager_message_handler(
1027 DBusConnection *connection,
1028 DBusMessage *message,
1031 Manager *m = userdata;
1034 DBusMessage *reply = NULL;
1041 dbus_error_init(&error);
1043 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1049 if (!dbus_message_get_args(
1052 DBUS_TYPE_STRING, &name,
1054 return bus_send_error_reply(connection, message, &error, -EINVAL);
1056 session = hashmap_get(m->sessions, name);
1058 return bus_send_error_reply(connection, message, &error, -ENOENT);
1060 reply = dbus_message_new_method_return(message);
1064 p = session_bus_path(session);
1068 b = dbus_message_append_args(
1070 DBUS_TYPE_OBJECT_PATH, &p,
1077 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1083 if (!dbus_message_get_args(
1086 DBUS_TYPE_UINT32, &pid,
1088 return bus_send_error_reply(connection, message, &error, -EINVAL);
1090 r = manager_get_session_by_pid(m, pid, &session);
1092 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1094 reply = dbus_message_new_method_return(message);
1098 p = session_bus_path(session);
1102 b = dbus_message_append_args(
1104 DBUS_TYPE_OBJECT_PATH, &p,
1111 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1117 if (!dbus_message_get_args(
1120 DBUS_TYPE_UINT32, &uid,
1122 return bus_send_error_reply(connection, message, &error, -EINVAL);
1124 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1126 return bus_send_error_reply(connection, message, &error, -ENOENT);
1128 reply = dbus_message_new_method_return(message);
1132 p = user_bus_path(user);
1136 b = dbus_message_append_args(
1138 DBUS_TYPE_OBJECT_PATH, &p,
1145 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1151 if (!dbus_message_get_args(
1154 DBUS_TYPE_STRING, &name,
1156 return bus_send_error_reply(connection, message, &error, -EINVAL);
1158 seat = hashmap_get(m->seats, name);
1160 return bus_send_error_reply(connection, message, &error, -ENOENT);
1162 reply = dbus_message_new_method_return(message);
1166 p = seat_bus_path(seat);
1170 b = dbus_message_append_args(
1172 DBUS_TYPE_OBJECT_PATH, &p,
1179 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1183 DBusMessageIter iter, sub;
1184 const char *empty = "";
1186 reply = dbus_message_new_method_return(message);
1190 dbus_message_iter_init_append(reply, &iter);
1192 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1195 HASHMAP_FOREACH(session, m->sessions, i) {
1196 DBusMessageIter sub2;
1199 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1202 uid = session->user->uid;
1204 p = session_bus_path(session);
1208 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1209 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1210 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1211 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1212 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1219 if (!dbus_message_iter_close_container(&sub, &sub2))
1223 if (!dbus_message_iter_close_container(&iter, &sub))
1226 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1230 DBusMessageIter iter, sub;
1232 reply = dbus_message_new_method_return(message);
1236 dbus_message_iter_init_append(reply, &iter);
1238 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1241 HASHMAP_FOREACH(user, m->users, i) {
1242 DBusMessageIter sub2;
1245 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1250 p = user_bus_path(user);
1254 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1255 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1256 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1263 if (!dbus_message_iter_close_container(&sub, &sub2))
1267 if (!dbus_message_iter_close_container(&iter, &sub))
1270 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1274 DBusMessageIter iter, sub;
1276 reply = dbus_message_new_method_return(message);
1280 dbus_message_iter_init_append(reply, &iter);
1282 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1285 HASHMAP_FOREACH(seat, m->seats, i) {
1286 DBusMessageIter sub2;
1288 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1291 p = seat_bus_path(seat);
1295 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1296 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1303 if (!dbus_message_iter_close_container(&sub, &sub2))
1307 if (!dbus_message_iter_close_container(&iter, &sub))
1310 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1311 Inhibitor *inhibitor;
1313 DBusMessageIter iter, sub;
1315 reply = dbus_message_new_method_return(message);
1319 dbus_message_iter_init_append(reply, &iter);
1321 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1324 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1325 DBusMessageIter sub2;
1326 dbus_uint32_t uid, pid;
1327 const char *what, *who, *why, *mode;
1329 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1332 what = strempty(inhibit_what_to_string(inhibitor->what));
1333 who = strempty(inhibitor->who);
1334 why = strempty(inhibitor->why);
1335 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
1336 uid = (dbus_uint32_t) inhibitor->uid;
1337 pid = (dbus_uint32_t) inhibitor->pid;
1339 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1340 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1341 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1342 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
1343 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1344 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1347 if (!dbus_message_iter_close_container(&sub, &sub2))
1351 if (!dbus_message_iter_close_container(&iter, &sub))
1354 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1356 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1359 return bus_send_error_reply(connection, message, &error, r);
1362 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1364 r = bus_manager_create_session(m, message, &reply);
1366 /* Don't delay the work on OOM here, since it might be
1367 * triggered by a low RLIMIT_NOFILE here (since we
1368 * send a dupped fd to the client), and we'd rather
1369 * see this fail quickly then be retried later */
1372 return bus_send_error_reply(connection, message, NULL, r);
1374 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1378 if (!dbus_message_get_args(
1381 DBUS_TYPE_STRING, &name,
1383 return bus_send_error_reply(connection, message, &error, -EINVAL);
1385 session = hashmap_get(m->sessions, name);
1387 return bus_send_error_reply(connection, message, &error, -ENOENT);
1389 /* We use the FIFO to detect stray sessions where the
1390 process invoking PAM dies abnormally. We need to make
1391 sure that that process is not killed if at the clean
1392 end of the session it closes the FIFO. Hence, with
1393 this call explicitly turn off the FIFO logic, so that
1394 the PAM code can finish clean up on its own */
1395 session_remove_fifo(session);
1397 reply = dbus_message_new_method_return(message);
1401 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1405 if (!dbus_message_get_args(
1408 DBUS_TYPE_STRING, &name,
1410 return bus_send_error_reply(connection, message, &error, -EINVAL);
1412 session = hashmap_get(m->sessions, name);
1414 return bus_send_error_reply(connection, message, &error, -ENOENT);
1416 r = session_activate(session);
1418 return bus_send_error_reply(connection, message, NULL, r);
1420 reply = dbus_message_new_method_return(message);
1424 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1425 const char *session_name, *seat_name;
1429 /* Same as ActivateSession() but refuses to work if
1430 * the seat doesn't match */
1432 if (!dbus_message_get_args(
1435 DBUS_TYPE_STRING, &session_name,
1436 DBUS_TYPE_STRING, &seat_name,
1438 return bus_send_error_reply(connection, message, &error, -EINVAL);
1440 session = hashmap_get(m->sessions, session_name);
1442 return bus_send_error_reply(connection, message, &error, -ENOENT);
1444 seat = hashmap_get(m->seats, seat_name);
1446 return bus_send_error_reply(connection, message, &error, -ENOENT);
1448 if (session->seat != seat)
1449 return bus_send_error_reply(connection, message, &error, -EINVAL);
1451 r = session_activate(session);
1453 return bus_send_error_reply(connection, message, NULL, r);
1455 reply = dbus_message_new_method_return(message);
1459 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1460 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1464 if (!dbus_message_get_args(
1467 DBUS_TYPE_STRING, &name,
1469 return bus_send_error_reply(connection, message, &error, -EINVAL);
1471 session = hashmap_get(m->sessions, name);
1473 return bus_send_error_reply(connection, message, &error, -ENOENT);
1475 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1478 reply = dbus_message_new_method_return(message);
1482 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1489 if (!dbus_message_get_args(
1492 DBUS_TYPE_STRING, &name,
1493 DBUS_TYPE_STRING, &swho,
1494 DBUS_TYPE_INT32, &signo,
1496 return bus_send_error_reply(connection, message, &error, -EINVAL);
1501 who = kill_who_from_string(swho);
1503 return bus_send_error_reply(connection, message, &error, -EINVAL);
1506 if (signo <= 0 || signo >= _NSIG)
1507 return bus_send_error_reply(connection, message, &error, -EINVAL);
1509 session = hashmap_get(m->sessions, name);
1511 return bus_send_error_reply(connection, message, &error, -ENOENT);
1513 r = session_kill(session, who, signo);
1515 return bus_send_error_reply(connection, message, NULL, r);
1517 reply = dbus_message_new_method_return(message);
1521 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1526 if (!dbus_message_get_args(
1529 DBUS_TYPE_UINT32, &uid,
1530 DBUS_TYPE_INT32, &signo,
1532 return bus_send_error_reply(connection, message, &error, -EINVAL);
1534 if (signo <= 0 || signo >= _NSIG)
1535 return bus_send_error_reply(connection, message, &error, -EINVAL);
1537 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1539 return bus_send_error_reply(connection, message, &error, -ENOENT);
1541 r = user_kill(user, signo);
1543 return bus_send_error_reply(connection, message, NULL, r);
1545 reply = dbus_message_new_method_return(message);
1549 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1553 if (!dbus_message_get_args(
1556 DBUS_TYPE_STRING, &name,
1558 return bus_send_error_reply(connection, message, &error, -EINVAL);
1560 session = hashmap_get(m->sessions, name);
1562 return bus_send_error_reply(connection, message, &error, -ENOENT);
1564 r = session_stop(session);
1566 return bus_send_error_reply(connection, message, NULL, r);
1568 reply = dbus_message_new_method_return(message);
1572 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1576 if (!dbus_message_get_args(
1579 DBUS_TYPE_UINT32, &uid,
1581 return bus_send_error_reply(connection, message, &error, -EINVAL);
1583 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1585 return bus_send_error_reply(connection, message, &error, -ENOENT);
1587 r = user_stop(user);
1589 return bus_send_error_reply(connection, message, NULL, r);
1591 reply = dbus_message_new_method_return(message);
1595 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1599 if (!dbus_message_get_args(
1602 DBUS_TYPE_STRING, &name,
1604 return bus_send_error_reply(connection, message, &error, -EINVAL);
1606 seat = hashmap_get(m->seats, name);
1608 return bus_send_error_reply(connection, message, &error, -ENOENT);
1610 r = seat_stop_sessions(seat);
1612 return bus_send_error_reply(connection, message, NULL, r);
1614 reply = dbus_message_new_method_return(message);
1618 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
1621 dbus_bool_t b, interactive;
1624 if (!dbus_message_get_args(
1627 DBUS_TYPE_UINT32, &uid,
1628 DBUS_TYPE_BOOLEAN, &b,
1629 DBUS_TYPE_BOOLEAN, &interactive,
1631 return bus_send_error_reply(connection, message, &error, -EINVAL);
1636 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
1638 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
1640 return bus_send_error_reply(connection, message, &error, r);
1642 mkdir_p("/var/lib/systemd", 0755);
1644 r = safe_mkdir("/var/lib/systemd/linger", 0755, 0, 0);
1646 return bus_send_error_reply(connection, message, &error, r);
1648 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
1659 return bus_send_error_reply(connection, message, &error, r);
1661 if (manager_add_user_by_uid(m, uid, &u) >= 0)
1670 if (r < 0 && errno != ENOENT)
1671 return bus_send_error_reply(connection, message, &error, -errno);
1673 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1675 user_add_to_gc_queue(u);
1678 reply = dbus_message_new_method_return(message);
1682 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
1683 const char *sysfs, *seat;
1684 dbus_bool_t interactive;
1686 if (!dbus_message_get_args(
1689 DBUS_TYPE_STRING, &seat,
1690 DBUS_TYPE_STRING, &sysfs,
1691 DBUS_TYPE_BOOLEAN, &interactive,
1693 return bus_send_error_reply(connection, message, &error, -EINVAL);
1695 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
1696 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1698 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
1700 return bus_send_error_reply(connection, message, &error, r);
1702 r = attach_device(m, seat, sysfs);
1704 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1706 reply = dbus_message_new_method_return(message);
1711 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
1712 dbus_bool_t interactive;
1714 if (!dbus_message_get_args(
1717 DBUS_TYPE_BOOLEAN, &interactive,
1719 return bus_send_error_reply(connection, message, &error, -EINVAL);
1721 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
1723 return bus_send_error_reply(connection, message, &error, r);
1725 r = flush_devices(m);
1727 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1729 reply = dbus_message_new_method_return(message);
1733 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff") ||
1734 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
1735 dbus_bool_t interactive;
1736 bool multiple_sessions, blocked, delayed;
1737 const char *name, *action;
1739 if (!dbus_message_get_args(
1742 DBUS_TYPE_BOOLEAN, &interactive,
1744 return bus_send_error_reply(connection, message, &error, -EINVAL);
1746 r = have_multiple_sessions(connection, m, message, &error);
1748 return bus_send_error_reply(connection, message, &error, r);
1750 multiple_sessions = r > 0;
1751 blocked = manager_is_inhibited(m, INHIBIT_SHUTDOWN, INHIBIT_BLOCK, NULL);
1753 if (multiple_sessions) {
1754 action = streq(dbus_message_get_member(message), "PowerOff") ?
1755 "org.freedesktop.login1.power-off-multiple-sessions" :
1756 "org.freedesktop.login1.reboot-multiple-sessions";
1758 r = verify_polkit(connection, message, action, interactive, NULL, &error);
1760 return bus_send_error_reply(connection, message, &error, r);
1764 action = streq(dbus_message_get_member(message), "PowerOff") ?
1765 "org.freedesktop.login1.power-off-ignore-inhibit" :
1766 "org.freedesktop.login1.reboot-ignore-inhibit";
1768 r = verify_polkit(connection, message, action, interactive, NULL, &error);
1770 return bus_send_error_reply(connection, message, &error, r);
1773 if (!multiple_sessions && !blocked) {
1774 action = streq(dbus_message_get_member(message), "PowerOff") ?
1775 "org.freedesktop.login1.power-off" :
1776 "org.freedesktop.login1.reboot";
1778 r = verify_polkit(connection, message, action, interactive, NULL, &error);
1780 return bus_send_error_reply(connection, message, &error, r);
1783 name = streq(dbus_message_get_member(message), "PowerOff") ?
1784 SPECIAL_POWEROFF_TARGET : SPECIAL_REBOOT_TARGET;
1787 m->inhibit_delay_max > 0 &&
1788 manager_is_inhibited(m, INHIBIT_SHUTDOWN, INHIBIT_DELAY, NULL);
1791 /* Shutdown is delayed, keep in mind what we
1792 * want to do, and start a timeout */
1793 r = delay_shutdown(m, name);
1795 return bus_send_error_reply(connection, message, NULL, r);
1797 /* Shutdown is not delayed, execute it
1799 r = send_start_unit(connection, name, &error);
1801 return bus_send_error_reply(connection, message, &error, r);
1804 reply = dbus_message_new_method_return(message);
1808 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff") ||
1809 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
1811 bool multiple_sessions, challenge, inhibit, b;
1812 const char *action, *result;
1814 r = have_multiple_sessions(connection, m, message, &error);
1816 return bus_send_error_reply(connection, message, &error, r);
1818 multiple_sessions = r > 0;
1819 inhibit = manager_is_inhibited(m, INHIBIT_SHUTDOWN, INHIBIT_BLOCK, NULL);
1821 if (multiple_sessions) {
1822 action = streq(dbus_message_get_member(message), "CanPowerOff") ?
1823 "org.freedesktop.login1.power-off-multiple-sessions" :
1824 "org.freedesktop.login1.reboot-multiple-sessions";
1826 r = verify_polkit(connection, message, action, false, &challenge, &error);
1828 return bus_send_error_reply(connection, message, &error, r);
1833 result = "challenge";
1839 action = streq(dbus_message_get_member(message), "CanPowerOff") ?
1840 "org.freedesktop.login1.power-off-ignore-inhibit" :
1841 "org.freedesktop.login1.reboot-ignore-inhibit";
1843 r = verify_polkit(connection, message, action, false, &challenge, &error);
1845 return bus_send_error_reply(connection, message, &error, r);
1847 if (r > 0 && !result)
1849 else if (challenge && (!result || streq(result, "yes")))
1850 result = "challenge";
1855 if (!multiple_sessions && !inhibit) {
1856 /* If neither inhibit nor multiple sessions
1857 * apply then just check the normal policy */
1859 action = streq(dbus_message_get_member(message), "CanPowerOff") ?
1860 "org.freedesktop.login1.power-off" :
1861 "org.freedesktop.login1.reboot";
1863 r = verify_polkit(connection, message, action, false, &challenge, &error);
1865 return bus_send_error_reply(connection, message, &error, r);
1870 result = "challenge";
1875 reply = dbus_message_new_method_return(message);
1879 b = dbus_message_append_args(
1881 DBUS_TYPE_STRING, &result,
1886 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1887 char *introspection = NULL;
1896 if (!(reply = dbus_message_new_method_return(message)))
1899 /* We roll our own introspection code here, instead of
1900 * relying on bus_default_message_handler() because we
1901 * need to generate our introspection string
1904 if (!(f = open_memstream(&introspection, &size)))
1907 fputs(INTROSPECTION_BEGIN, f);
1909 HASHMAP_FOREACH(seat, m->seats, i) {
1910 p = bus_path_escape(seat->id);
1913 fprintf(f, "<node name=\"seat/%s\"/>", p);
1918 HASHMAP_FOREACH(user, m->users, i)
1919 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
1921 HASHMAP_FOREACH(session, m->sessions, i) {
1922 p = bus_path_escape(session->id);
1925 fprintf(f, "<node name=\"session/%s\"/>", p);
1930 fputs(INTROSPECTION_END, f);
1934 free(introspection);
1943 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
1944 free(introspection);
1948 free(introspection);
1950 const BusBoundProperties bps[] = {
1951 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
1954 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
1958 if (!dbus_connection_send(connection, reply, NULL))
1961 dbus_message_unref(reply);
1964 return DBUS_HANDLER_RESULT_HANDLED;
1968 dbus_message_unref(reply);
1970 dbus_error_free(&error);
1972 return DBUS_HANDLER_RESULT_NEED_MEMORY;
1975 const DBusObjectPathVTable bus_manager_vtable = {
1976 .message_function = manager_message_handler
1979 DBusHandlerResult bus_message_filter(
1980 DBusConnection *connection,
1981 DBusMessage *message,
1984 Manager *m = userdata;
1991 dbus_error_init(&error);
1993 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
1996 if (!dbus_message_get_args(message, &error,
1997 DBUS_TYPE_STRING, &cgroup,
1999 log_error("Failed to parse Released message: %s", bus_error_message(&error));
2001 manager_cgroup_notify_empty(m, cgroup);
2004 dbus_error_free(&error);
2006 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2009 int manager_send_changed(Manager *manager, const char *properties) {
2015 m = bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties);
2019 if (!dbus_connection_send(manager->bus, m, NULL))
2026 dbus_message_unref(m);
2031 int manager_dispatch_delayed_shutdown(Manager *manager) {
2039 if (!manager->delayed_shutdown)
2042 /* Continue delay? */
2044 manager->delayed_shutdown_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC) &&
2045 manager_is_inhibited(manager, INHIBIT_SHUTDOWN, INHIBIT_DELAY, NULL);
2049 /* Reset delay data */
2050 name = manager->delayed_shutdown;
2051 manager->delayed_shutdown = NULL;
2053 /* Actually do the shutdown */
2054 dbus_error_init(&error);
2055 r = send_start_unit(manager->bus, name, &error);
2057 log_warning("Failed to send delayed shutdown message: %s", bus_error_message_or_strerror(&error, -r));
2061 /* Tell people about it */
2062 send_prepare_for_shutdown(manager, false);