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"
35 #define BUS_MANAGER_INTERFACE \
36 " <interface name=\"org.freedesktop.login1.Manager\">\n" \
37 " <method name=\"GetSession\">\n" \
38 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
39 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
41 " <method name=\"GetSessionByPID\">\n" \
42 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
43 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
45 " <method name=\"GetUser\">\n" \
46 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
47 " <arg name=\"user\" type=\"o\" direction=\"out\"/>\n" \
49 " <method name=\"GetSeat\">\n" \
50 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
51 " <arg name=\"seat\" type=\"o\" direction=\"out\"/>\n" \
53 " <method name=\"ListSessions\">\n" \
54 " <arg name=\"sessions\" type=\"a(susso)\" direction=\"out\"/>\n" \
56 " <method name=\"ListUsers\">\n" \
57 " <arg name=\"users\" type=\"a(uso)\" direction=\"out\"/>\n" \
59 " <method name=\"ListSeats\">\n" \
60 " <arg name=\"seats\" type=\"a(so)\" direction=\"out\"/>\n" \
62 " <method name=\"CreateSession\">\n" \
63 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
64 " <arg name=\"leader\" type=\"u\" direction=\"in\"/>\n" \
65 " <arg name=\"sevice\" type=\"s\" direction=\"in\"/>\n" \
66 " <arg name=\"type\" type=\"s\" direction=\"in\"/>\n" \
67 " <arg name=\"class\" type=\"s\" direction=\"in\"/>\n" \
68 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
69 " <arg name=\"vtnr\" type=\"u\" direction=\"in\"/>\n" \
70 " <arg name=\"tty\" type=\"s\" direction=\"in\"/>\n" \
71 " <arg name=\"display\" type=\"s\" direction=\"in\"/>\n" \
72 " <arg name=\"remote\" type=\"b\" direction=\"in\"/>\n" \
73 " <arg name=\"remote_user\" type=\"s\" direction=\"in\"/>\n" \
74 " <arg name=\"remote_host\" type=\"s\" direction=\"in\"/>\n" \
75 " <arg name=\"controllers\" type=\"as\" direction=\"in\"/>\n" \
76 " <arg name=\"reset_controllers\" type=\"as\" direction=\"in\"/>\n" \
77 " <arg name=\"kill_processes\" type=\"b\" direction=\"in\"/>\n" \
78 " <arg name=\"id\" type=\"s\" direction=\"out\"/>\n" \
79 " <arg name=\"path\" type=\"o\" direction=\"out\"/>\n" \
80 " <arg name=\"runtime_path\" type=\"o\" direction=\"out\"/>\n" \
81 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
82 " <arg name=\"seat\" type=\"s\" direction=\"out\"/>\n" \
83 " <arg name=\"vtnr\" type=\"u\" direction=\"out\"/>\n" \
85 " <method name=\"ReleaseSession\">\n" \
86 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
88 " <method name=\"ActivateSession\">\n" \
89 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
91 " <method name=\"ActivateSessionOnSeat\">\n" \
92 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
93 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
95 " <method name=\"LockSession\">\n" \
96 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
98 " <method name=\"UnlockSession\">\n" \
99 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
101 " <method name=\"LockSessions\"/>\n" \
102 " <method name=\"KillSession\">\n" \
103 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
104 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
105 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
107 " <method name=\"KillUser\">\n" \
108 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
109 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
111 " <method name=\"TerminateSession\">\n" \
112 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
114 " <method name=\"TerminateUser\">\n" \
115 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
117 " <method name=\"TerminateSeat\">\n" \
118 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
120 " <method name=\"SetUserLinger\">\n" \
121 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
122 " <arg name=\"b\" type=\"b\" direction=\"in\"/>\n" \
123 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
125 " <method name=\"AttachDevice\">\n" \
126 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
127 " <arg name=\"sysfs\" type=\"s\" direction=\"in\"/>\n" \
128 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
130 " <method name=\"FlushDevices\">\n" \
131 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
133 " <method name=\"PowerOff\">\n" \
134 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
136 " <method name=\"Reboot\">\n" \
137 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
139 " <method name=\"Suspend\">\n" \
140 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
142 " <method name=\"Hibernate\">\n" \
143 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
145 " <method name=\"CanPowerOff\">\n" \
146 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
148 " <method name=\"CanReboot\">\n" \
149 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
151 " <method name=\"CanSuspend\">\n" \
152 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
154 " <method name=\"CanHibernate\">\n" \
155 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
157 " <method name=\"Inhibit\">\n" \
158 " <arg name=\"what\" type=\"s\" direction=\"in\"/>\n" \
159 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
160 " <arg name=\"why\" type=\"s\" direction=\"in\"/>\n" \
161 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
162 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
164 " <method name=\"ListInhibitors\">\n" \
165 " <arg name=\"inhibitors\" type=\"a(ssssuu)\" direction=\"out\"/>\n" \
167 " <signal name=\"SessionNew\">\n" \
168 " <arg name=\"id\" type=\"s\"/>\n" \
169 " <arg name=\"path\" type=\"o\"/>\n" \
171 " <signal name=\"SessionRemoved\">\n" \
172 " <arg name=\"id\" type=\"s\"/>\n" \
173 " <arg name=\"path\" type=\"o\"/>\n" \
175 " <signal name=\"UserNew\">\n" \
176 " <arg name=\"uid\" type=\"u\"/>\n" \
177 " <arg name=\"path\" type=\"o\"/>\n" \
179 " <signal name=\"UserRemoved\">\n" \
180 " <arg name=\"uid\" type=\"u\"/>\n" \
181 " <arg name=\"path\" type=\"o\"/>\n" \
183 " <signal name=\"SeatNew\">\n" \
184 " <arg name=\"id\" type=\"s\"/>\n" \
185 " <arg name=\"path\" type=\"o\"/>\n" \
187 " <signal name=\"SeatRemoved\">\n" \
188 " <arg name=\"id\" type=\"s\"/>\n" \
189 " <arg name=\"path\" type=\"o\"/>\n" \
191 " <signal name=\"PrepareForShutdown\">\n" \
192 " <arg name=\"active\" type=\"b\"/>\n" \
194 " <signal name=\"PrepareForSleep\">\n" \
195 " <arg name=\"active\" type=\"b\"/>\n" \
197 " <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
198 " <property name=\"Controllers\" type=\"as\" access=\"read\"/>\n" \
199 " <property name=\"ResetControllers\" type=\"as\" access=\"read\"/>\n" \
200 " <property name=\"NAutoVTs\" type=\"u\" access=\"read\"/>\n" \
201 " <property name=\"KillOnlyUsers\" type=\"as\" access=\"read\"/>\n" \
202 " <property name=\"KillExcludeUsers\" type=\"as\" access=\"read\"/>\n" \
203 " <property name=\"KillUserProcesses\" type=\"b\" access=\"read\"/>\n" \
204 " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
205 " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
206 " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
207 " <property name=\"BlockInhibited\" type=\"s\" access=\"read\"/>\n" \
208 " <property name=\"DelayInhibited\" type=\"s\" access=\"read\"/>\n" \
209 " <property name=\"InhibitDelayMaxUSec\" type=\"t\" access=\"read\"/>\n" \
210 " <property name=\"HandlePowerKey\" type=\"s\" access=\"read\"/>\n" \
211 " <property name=\"HandleSleepKey\" type=\"s\" access=\"read\"/>\n" \
212 " <property name=\"HandleLidSwitch\" type=\"s\" access=\"read\"/>\n" \
213 " <property name=\"PreparingForShutdown\" type=\"b\" access=\"read\"/>\n" \
214 " <property name=\"PreparingForSleep\" type=\"b\" access=\"read\"/>\n" \
217 #define INTROSPECTION_BEGIN \
218 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
220 BUS_MANAGER_INTERFACE \
221 BUS_PROPERTIES_INTERFACE \
223 BUS_INTROSPECTABLE_INTERFACE
225 #define INTROSPECTION_END \
228 #define INTERFACES_LIST \
229 BUS_GENERIC_INTERFACES_LIST \
230 "org.freedesktop.login1.Manager\0"
232 static int bus_manager_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
240 b = manager_get_idle_hint(m, NULL) > 0;
241 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
247 static int bus_manager_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
256 manager_get_idle_hint(m, &t);
257 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
259 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
265 static int bus_manager_append_inhibited(DBusMessageIter *i, const char *property, void *data) {
270 w = manager_inhibit_what(m, streq(property, "BlockInhibited") ? INHIBIT_BLOCK : INHIBIT_DELAY);
271 p = inhibit_what_to_string(w);
273 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &p))
279 static int bus_manager_append_preparing(DBusMessageIter *i, const char *property, void *data) {
286 if (streq(property, "PreparingForShutdown"))
287 b = !!(m->delayed_what & INHIBIT_SHUTDOWN);
289 b = !!(m->delayed_what & INHIBIT_SLEEP);
291 dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b);
295 static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMessage **_reply) {
296 Session *session = NULL;
298 const char *type, *class, *seat, *tty, *display, *remote_user, *remote_host, *service;
299 uint32_t uid, leader, audit_id = 0;
300 dbus_bool_t remote, kill_processes;
301 char **controllers = NULL, **reset_controllers = NULL;
305 DBusMessageIter iter;
310 DBusMessage *reply = NULL;
317 if (!dbus_message_iter_init(message, &iter) ||
318 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
321 dbus_message_iter_get_basic(&iter, &uid);
323 if (!dbus_message_iter_next(&iter) ||
324 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
327 dbus_message_iter_get_basic(&iter, &leader);
330 !dbus_message_iter_next(&iter) ||
331 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
334 dbus_message_iter_get_basic(&iter, &service);
336 if (!dbus_message_iter_next(&iter) ||
337 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
340 dbus_message_iter_get_basic(&iter, &type);
341 t = session_type_from_string(type);
344 !dbus_message_iter_next(&iter) ||
345 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
348 dbus_message_iter_get_basic(&iter, &class);
352 c = session_class_from_string(class);
355 !dbus_message_iter_next(&iter) ||
356 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
359 dbus_message_iter_get_basic(&iter, &seat);
364 s = hashmap_get(m->seats, seat);
369 if (!dbus_message_iter_next(&iter) ||
370 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
373 dbus_message_iter_get_basic(&iter, &vtnr);
375 if (!dbus_message_iter_next(&iter) ||
376 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
379 dbus_message_iter_get_basic(&iter, &tty);
381 if (tty_is_vc(tty)) {
386 else if (s != m->vtconsole)
389 v = vtnr_from_tty(tty);
392 return v < 0 ? v : -EINVAL;
396 else if (vtnr != (uint32_t) v)
398 } else if (tty_is_console(tty)) {
402 else if (s != m->vtconsole)
408 } else if (!isempty(tty) && s && seat_is_vtconsole(s))
412 if (seat_can_multi_session(s)) {
421 if (!dbus_message_iter_next(&iter) ||
422 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
425 dbus_message_iter_get_basic(&iter, &display);
427 if (!dbus_message_iter_next(&iter) ||
428 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
431 dbus_message_iter_get_basic(&iter, &remote);
433 if (!dbus_message_iter_next(&iter) ||
434 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
437 dbus_message_iter_get_basic(&iter, &remote_user);
439 if (!dbus_message_iter_next(&iter) ||
440 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
443 dbus_message_iter_get_basic(&iter, &remote_host);
445 if (!dbus_message_iter_next(&iter) ||
446 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
447 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
450 r = bus_parse_strv_iter(&iter, &controllers);
454 if (strv_contains(controllers, "systemd") ||
455 !dbus_message_iter_next(&iter) ||
456 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
457 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) {
462 r = bus_parse_strv_iter(&iter, &reset_controllers);
466 if (strv_contains(reset_controllers, "systemd") ||
467 !dbus_message_iter_next(&iter) ||
468 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) {
473 dbus_message_iter_get_basic(&iter, &kill_processes);
475 r = manager_add_user_by_uid(m, uid, &user);
479 audit_session_from_pid(leader, &audit_id);
482 asprintf(&id, "%lu", (unsigned long) audit_id);
489 session = hashmap_get(m->sessions, id);
494 fifo_fd = session_create_fifo(session);
500 /* Session already exists, client is probably
501 * something like "su" which changes uid but
502 * is still the same audit session */
504 reply = dbus_message_new_method_return(message);
510 p = session_bus_path(session);
516 seat = session->seat ? session->seat->id : "";
517 vtnr = session->vtnr;
518 b = dbus_message_append_args(
520 DBUS_TYPE_STRING, &session->id,
521 DBUS_TYPE_OBJECT_PATH, &p,
522 DBUS_TYPE_STRING, &session->user->runtime_path,
523 DBUS_TYPE_UNIX_FD, &fifo_fd,
524 DBUS_TYPE_STRING, &seat,
525 DBUS_TYPE_UINT32, &vtnr,
534 close_nointr_nofail(fifo_fd);
537 strv_free(controllers);
538 strv_free(reset_controllers);
548 if (asprintf(&id, "c%lu", ++m->session_counter) < 0) {
553 } while (hashmap_get(m->sessions, id));
556 r = manager_add_session(m, user, id, &session);
561 session->leader = leader;
562 session->audit_id = audit_id;
565 session->remote = remote;
566 session->controllers = controllers;
567 session->reset_controllers = reset_controllers;
568 session->kill_processes = kill_processes;
569 session->vtnr = vtnr;
571 controllers = reset_controllers = NULL;
574 session->tty = strdup(tty);
581 if (!isempty(display)) {
582 session->display = strdup(display);
583 if (!session->display) {
589 if (!isempty(remote_user)) {
590 session->remote_user = strdup(remote_user);
591 if (!session->remote_user) {
597 if (!isempty(remote_host)) {
598 session->remote_host = strdup(remote_host);
599 if (!session->remote_host) {
605 if (!isempty(service)) {
606 session->service = strdup(service);
607 if (!session->service) {
613 fifo_fd = session_create_fifo(session);
620 r = seat_attach_session(s, session);
625 r = session_start(session);
629 reply = dbus_message_new_method_return(message);
635 p = session_bus_path(session);
641 seat = s ? s->id : "";
642 b = dbus_message_append_args(
644 DBUS_TYPE_STRING, &session->id,
645 DBUS_TYPE_OBJECT_PATH, &p,
646 DBUS_TYPE_STRING, &session->user->runtime_path,
647 DBUS_TYPE_UNIX_FD, &fifo_fd,
648 DBUS_TYPE_STRING, &seat,
649 DBUS_TYPE_UINT32, &vtnr,
658 close_nointr_nofail(fifo_fd);
664 strv_free(controllers);
665 strv_free(reset_controllers);
668 session_add_to_gc_queue(session);
671 user_add_to_gc_queue(user);
674 close_nointr_nofail(fifo_fd);
677 dbus_message_unref(reply);
682 static int bus_manager_inhibit(Manager *m, DBusConnection *connection, DBusMessage *message, DBusError *error, DBusMessage **_reply) {
685 const char *who, *why, *what, *mode;
691 DBusMessage *reply = NULL;
699 if (!dbus_message_get_args(
702 DBUS_TYPE_STRING, &what,
703 DBUS_TYPE_STRING, &who,
704 DBUS_TYPE_STRING, &why,
705 DBUS_TYPE_STRING, &mode,
706 DBUS_TYPE_INVALID)) {
711 w = inhibit_what_from_string(what);
717 mm = inhibit_mode_from_string(mode);
723 r = verify_polkit(connection, message,
725 "org.freedesktop.login1.inhibit-block" :
726 "org.freedesktop.login1.inhibit-delay", false, NULL, error);
730 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
731 if (ul == (unsigned long) -1) {
736 pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
746 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
750 } while (hashmap_get(m->inhibitors, id));
752 r = manager_add_inhibitor(m, id, &i);
762 i->why = strdup(why);
763 i->who = strdup(who);
765 if (!i->why || !i->who) {
770 fifo_fd = inhibitor_create_fifo(i);
776 reply = dbus_message_new_method_return(message);
782 if (!dbus_message_append_args(
784 DBUS_TYPE_UNIX_FD, &fifo_fd,
785 DBUS_TYPE_INVALID)) {
790 close_nointr_nofail(fifo_fd);
802 close_nointr_nofail(fifo_fd);
805 dbus_message_unref(reply);
810 static int trigger_device(Manager *m, struct udev_device *d) {
811 struct udev_enumerate *e;
812 struct udev_list_entry *first, *item;
817 e = udev_enumerate_new(m->udev);
824 if (udev_enumerate_add_match_parent(e, d) < 0) {
830 if (udev_enumerate_scan_devices(e) < 0) {
835 first = udev_enumerate_get_list_entry(e);
836 udev_list_entry_foreach(item, first) {
840 p = udev_list_entry_get_name(item);
842 t = strappend(p, "/uevent");
848 write_one_line_file(t, "change");
856 udev_enumerate_unref(e);
861 static int attach_device(Manager *m, const char *seat, const char *sysfs) {
862 struct udev_device *d;
863 char *rule = NULL, *file = NULL;
864 const char *id_for_seat;
871 d = udev_device_new_from_syspath(m->udev, sysfs);
875 if (!udev_device_has_tag(d, "seat")) {
880 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
886 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
891 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
896 mkdir_p_label("/etc/udev/rules.d", 0755);
897 r = write_one_line_file_atomic(file, rule);
901 r = trigger_device(m, d);
908 udev_device_unref(d);
913 static int flush_devices(Manager *m) {
918 d = opendir("/etc/udev/rules.d");
921 log_warning("Failed to open /etc/udev/rules.d: %m");
925 while ((de = readdir(d))) {
927 if (!dirent_is_file(de))
930 if (!startswith(de->d_name, "72-seat-"))
933 if (!endswith(de->d_name, ".rules"))
936 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
937 log_warning("Failed to unlink %s: %m", de->d_name);
943 return trigger_device(m, NULL);
946 static int have_multiple_sessions(
947 DBusConnection *connection,
949 DBusMessage *message,
958 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
959 if (ul == (unsigned long) -1)
962 /* Check for other users' sessions. Greeter sessions do not count. */
963 HASHMAP_FOREACH(session, m->sessions, i)
964 if (session->class == SESSION_USER && session->user->uid != ul)
970 static int send_start_unit(DBusConnection *connection, const char *unit_name, DBusError *error) {
971 const char *mode = "replace";
975 return bus_method_call_with_reply (
977 "org.freedesktop.systemd1",
978 "/org/freedesktop/systemd1",
979 "org.freedesktop.systemd1.Manager",
983 DBUS_TYPE_STRING, &unit_name,
984 DBUS_TYPE_STRING, &mode,
988 static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
989 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
990 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
991 [INHIBIT_SLEEP] = "PrepareForSleep"
994 dbus_bool_t active = _active;
995 DBusMessage *message;
1000 assert(w < _INHIBIT_WHAT_MAX);
1001 assert(signal_name[w]);
1003 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1007 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1008 !dbus_connection_send(m->bus, message, NULL))
1011 dbus_message_unref(message);
1015 static int delay_shutdown_or_sleep(Manager *m, InhibitWhat w, const char *unit_name) {
1018 assert(w < _INHIBIT_WHAT_MAX);
1020 /* Tell everybody to prepare for shutdown/sleep */
1021 send_prepare_for(m, w, true);
1023 /* Update timestamp for timeout */
1024 if (!m->delayed_unit)
1025 m->delayed_timestamp = now(CLOCK_MONOTONIC);
1027 /* Remember what we want to do, possibly overriding what kind
1028 * of unit we previously queued. */
1029 m->delayed_unit = unit_name;
1030 m->delayed_what = w;
1035 static int bus_manager_can_shutdown_or_sleep(
1037 DBusConnection *connection,
1038 DBusMessage *message,
1041 const char *action_multiple_sessions,
1042 const char *action_ignore_inhibit,
1043 const char *sleep_type,
1045 DBusMessage **_reply) {
1047 bool multiple_sessions, challenge, blocked, b;
1049 DBusMessage *reply = NULL;
1056 assert(w <= _INHIBIT_WHAT_MAX);
1058 assert(action_multiple_sessions);
1059 assert(action_ignore_inhibit);
1064 r = can_sleep(sleep_type);
1074 r = have_multiple_sessions(connection, m, message, error);
1078 multiple_sessions = r > 0;
1079 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL);
1081 if (multiple_sessions) {
1082 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1089 result = "challenge";
1095 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1099 if (r > 0 && !result)
1101 else if (challenge && (!result || streq(result, "yes")))
1102 result = "challenge";
1107 if (!multiple_sessions && !blocked) {
1108 /* If neither inhibit nor multiple sessions
1109 * apply then just check the normal policy */
1111 r = verify_polkit(connection, message, action, false, &challenge, error);
1118 result = "challenge";
1124 reply = dbus_message_new_method_return(message);
1128 b = dbus_message_append_args(
1130 DBUS_TYPE_STRING, &result,
1133 dbus_message_unref(reply);
1141 int bus_manager_shutdown_or_sleep_now_or_later(
1143 const char *unit_name,
1153 assert(w <= _INHIBIT_WHAT_MAX);
1156 m->inhibit_delay_max > 0 &&
1157 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL);
1160 /* Shutdown is delayed, keep in mind what we
1161 * want to do, and start a timeout */
1162 r = delay_shutdown_or_sleep(m, w, unit_name);
1164 /* Shutdown is not delayed, execute it
1166 r = send_start_unit(m->bus, unit_name, error);
1171 static int bus_manager_do_shutdown_or_sleep(
1173 DBusConnection *connection,
1174 DBusMessage *message,
1175 const char *unit_name,
1178 const char *action_multiple_sessions,
1179 const char *action_ignore_inhibit,
1180 const char *sleep_type,
1182 DBusMessage **_reply) {
1184 dbus_bool_t interactive;
1185 bool multiple_sessions, blocked;
1186 DBusMessage *reply = NULL;
1194 assert(w <= _INHIBIT_WHAT_MAX);
1196 assert(action_multiple_sessions);
1197 assert(action_ignore_inhibit);
1201 if (!dbus_message_get_args(
1204 DBUS_TYPE_BOOLEAN, &interactive,
1209 r = can_sleep(sleep_type);
1217 r = have_multiple_sessions(connection, m, message, error);
1221 multiple_sessions = r > 0;
1222 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL);
1224 if (multiple_sessions) {
1225 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1231 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1236 if (!multiple_sessions && !blocked) {
1237 r = verify_polkit(connection, message, action, interactive, NULL, error);
1242 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
1246 reply = dbus_message_new_method_return(message);
1254 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_button, handle_button, HandleButton);
1256 static const BusProperty bus_login_manager_properties[] = {
1257 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_path), true },
1258 { "Controllers", bus_property_append_strv, "as", offsetof(Manager, controllers), true },
1259 { "ResetControllers", bus_property_append_strv, "as", offsetof(Manager, reset_controllers), true },
1260 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1261 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1262 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1263 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1264 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1265 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1266 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
1267 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1268 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1269 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
1270 { "HandlePowerKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_power_key) },
1271 { "HandleSleepKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_sleep_key) },
1272 { "HandleLidSwitch", bus_manager_append_handle_button, "s", offsetof(Manager, handle_lid_switch) },
1273 { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
1274 { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
1278 static DBusHandlerResult manager_message_handler(
1279 DBusConnection *connection,
1280 DBusMessage *message,
1283 Manager *m = userdata;
1286 DBusMessage *reply = NULL;
1293 dbus_error_init(&error);
1295 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1301 if (!dbus_message_get_args(
1304 DBUS_TYPE_STRING, &name,
1306 return bus_send_error_reply(connection, message, &error, -EINVAL);
1308 session = hashmap_get(m->sessions, name);
1310 return bus_send_error_reply(connection, message, &error, -ENOENT);
1312 reply = dbus_message_new_method_return(message);
1316 p = session_bus_path(session);
1320 b = dbus_message_append_args(
1322 DBUS_TYPE_OBJECT_PATH, &p,
1329 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1335 if (!dbus_message_get_args(
1338 DBUS_TYPE_UINT32, &pid,
1340 return bus_send_error_reply(connection, message, &error, -EINVAL);
1342 r = manager_get_session_by_pid(m, pid, &session);
1344 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1346 reply = dbus_message_new_method_return(message);
1350 p = session_bus_path(session);
1354 b = dbus_message_append_args(
1356 DBUS_TYPE_OBJECT_PATH, &p,
1363 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1369 if (!dbus_message_get_args(
1372 DBUS_TYPE_UINT32, &uid,
1374 return bus_send_error_reply(connection, message, &error, -EINVAL);
1376 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1378 return bus_send_error_reply(connection, message, &error, -ENOENT);
1380 reply = dbus_message_new_method_return(message);
1384 p = user_bus_path(user);
1388 b = dbus_message_append_args(
1390 DBUS_TYPE_OBJECT_PATH, &p,
1397 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1403 if (!dbus_message_get_args(
1406 DBUS_TYPE_STRING, &name,
1408 return bus_send_error_reply(connection, message, &error, -EINVAL);
1410 seat = hashmap_get(m->seats, name);
1412 return bus_send_error_reply(connection, message, &error, -ENOENT);
1414 reply = dbus_message_new_method_return(message);
1418 p = seat_bus_path(seat);
1422 b = dbus_message_append_args(
1424 DBUS_TYPE_OBJECT_PATH, &p,
1431 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1435 DBusMessageIter iter, sub;
1436 const char *empty = "";
1438 reply = dbus_message_new_method_return(message);
1442 dbus_message_iter_init_append(reply, &iter);
1444 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1447 HASHMAP_FOREACH(session, m->sessions, i) {
1448 DBusMessageIter sub2;
1451 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1454 uid = session->user->uid;
1456 p = session_bus_path(session);
1460 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1461 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1462 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1463 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1464 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1471 if (!dbus_message_iter_close_container(&sub, &sub2))
1475 if (!dbus_message_iter_close_container(&iter, &sub))
1478 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1482 DBusMessageIter iter, sub;
1484 reply = dbus_message_new_method_return(message);
1488 dbus_message_iter_init_append(reply, &iter);
1490 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1493 HASHMAP_FOREACH(user, m->users, i) {
1494 DBusMessageIter sub2;
1497 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1502 p = user_bus_path(user);
1506 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1507 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1508 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1515 if (!dbus_message_iter_close_container(&sub, &sub2))
1519 if (!dbus_message_iter_close_container(&iter, &sub))
1522 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1526 DBusMessageIter iter, sub;
1528 reply = dbus_message_new_method_return(message);
1532 dbus_message_iter_init_append(reply, &iter);
1534 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1537 HASHMAP_FOREACH(seat, m->seats, i) {
1538 DBusMessageIter sub2;
1540 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1543 p = seat_bus_path(seat);
1547 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1548 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1555 if (!dbus_message_iter_close_container(&sub, &sub2))
1559 if (!dbus_message_iter_close_container(&iter, &sub))
1562 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1563 Inhibitor *inhibitor;
1565 DBusMessageIter iter, sub;
1567 reply = dbus_message_new_method_return(message);
1571 dbus_message_iter_init_append(reply, &iter);
1573 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1576 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1577 DBusMessageIter sub2;
1578 dbus_uint32_t uid, pid;
1579 const char *what, *who, *why, *mode;
1581 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1584 what = strempty(inhibit_what_to_string(inhibitor->what));
1585 who = strempty(inhibitor->who);
1586 why = strempty(inhibitor->why);
1587 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
1588 uid = (dbus_uint32_t) inhibitor->uid;
1589 pid = (dbus_uint32_t) inhibitor->pid;
1591 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1592 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1593 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1594 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
1595 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1596 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1599 if (!dbus_message_iter_close_container(&sub, &sub2))
1603 if (!dbus_message_iter_close_container(&iter, &sub))
1606 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1608 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1611 return bus_send_error_reply(connection, message, &error, r);
1614 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1616 r = bus_manager_create_session(m, message, &reply);
1618 /* Don't delay the work on OOM here, since it might be
1619 * triggered by a low RLIMIT_NOFILE here (since we
1620 * send a dupped fd to the client), and we'd rather
1621 * see this fail quickly then be retried later */
1624 return bus_send_error_reply(connection, message, NULL, r);
1626 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1630 if (!dbus_message_get_args(
1633 DBUS_TYPE_STRING, &name,
1635 return bus_send_error_reply(connection, message, &error, -EINVAL);
1637 session = hashmap_get(m->sessions, name);
1639 return bus_send_error_reply(connection, message, &error, -ENOENT);
1641 /* We use the FIFO to detect stray sessions where the
1642 process invoking PAM dies abnormally. We need to make
1643 sure that that process is not killed if at the clean
1644 end of the session it closes the FIFO. Hence, with
1645 this call explicitly turn off the FIFO logic, so that
1646 the PAM code can finish clean up on its own */
1647 session_remove_fifo(session);
1649 reply = dbus_message_new_method_return(message);
1653 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1657 if (!dbus_message_get_args(
1660 DBUS_TYPE_STRING, &name,
1662 return bus_send_error_reply(connection, message, &error, -EINVAL);
1664 session = hashmap_get(m->sessions, name);
1666 return bus_send_error_reply(connection, message, &error, -ENOENT);
1668 r = session_activate(session);
1670 return bus_send_error_reply(connection, message, NULL, r);
1672 reply = dbus_message_new_method_return(message);
1676 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1677 const char *session_name, *seat_name;
1681 /* Same as ActivateSession() but refuses to work if
1682 * the seat doesn't match */
1684 if (!dbus_message_get_args(
1687 DBUS_TYPE_STRING, &session_name,
1688 DBUS_TYPE_STRING, &seat_name,
1690 return bus_send_error_reply(connection, message, &error, -EINVAL);
1692 session = hashmap_get(m->sessions, session_name);
1694 return bus_send_error_reply(connection, message, &error, -ENOENT);
1696 seat = hashmap_get(m->seats, seat_name);
1698 return bus_send_error_reply(connection, message, &error, -ENOENT);
1700 if (session->seat != seat)
1701 return bus_send_error_reply(connection, message, &error, -EINVAL);
1703 r = session_activate(session);
1705 return bus_send_error_reply(connection, message, NULL, r);
1707 reply = dbus_message_new_method_return(message);
1711 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1712 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1716 if (!dbus_message_get_args(
1719 DBUS_TYPE_STRING, &name,
1721 return bus_send_error_reply(connection, message, &error, -EINVAL);
1723 session = hashmap_get(m->sessions, name);
1725 return bus_send_error_reply(connection, message, &error, -ENOENT);
1727 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1730 reply = dbus_message_new_method_return(message);
1734 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions")) {
1738 HASHMAP_FOREACH(session, m->sessions, i)
1739 if (session_send_lock(session, true) < 0)
1742 reply = dbus_message_new_method_return(message);
1746 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1753 if (!dbus_message_get_args(
1756 DBUS_TYPE_STRING, &name,
1757 DBUS_TYPE_STRING, &swho,
1758 DBUS_TYPE_INT32, &signo,
1760 return bus_send_error_reply(connection, message, &error, -EINVAL);
1765 who = kill_who_from_string(swho);
1767 return bus_send_error_reply(connection, message, &error, -EINVAL);
1770 if (signo <= 0 || signo >= _NSIG)
1771 return bus_send_error_reply(connection, message, &error, -EINVAL);
1773 session = hashmap_get(m->sessions, name);
1775 return bus_send_error_reply(connection, message, &error, -ENOENT);
1777 r = session_kill(session, who, signo);
1779 return bus_send_error_reply(connection, message, NULL, r);
1781 reply = dbus_message_new_method_return(message);
1785 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1790 if (!dbus_message_get_args(
1793 DBUS_TYPE_UINT32, &uid,
1794 DBUS_TYPE_INT32, &signo,
1796 return bus_send_error_reply(connection, message, &error, -EINVAL);
1798 if (signo <= 0 || signo >= _NSIG)
1799 return bus_send_error_reply(connection, message, &error, -EINVAL);
1801 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1803 return bus_send_error_reply(connection, message, &error, -ENOENT);
1805 r = user_kill(user, signo);
1807 return bus_send_error_reply(connection, message, NULL, r);
1809 reply = dbus_message_new_method_return(message);
1813 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1817 if (!dbus_message_get_args(
1820 DBUS_TYPE_STRING, &name,
1822 return bus_send_error_reply(connection, message, &error, -EINVAL);
1824 session = hashmap_get(m->sessions, name);
1826 return bus_send_error_reply(connection, message, &error, -ENOENT);
1828 r = session_stop(session);
1830 return bus_send_error_reply(connection, message, NULL, r);
1832 reply = dbus_message_new_method_return(message);
1836 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1840 if (!dbus_message_get_args(
1843 DBUS_TYPE_UINT32, &uid,
1845 return bus_send_error_reply(connection, message, &error, -EINVAL);
1847 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1849 return bus_send_error_reply(connection, message, &error, -ENOENT);
1851 r = user_stop(user);
1853 return bus_send_error_reply(connection, message, NULL, r);
1855 reply = dbus_message_new_method_return(message);
1859 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1863 if (!dbus_message_get_args(
1866 DBUS_TYPE_STRING, &name,
1868 return bus_send_error_reply(connection, message, &error, -EINVAL);
1870 seat = hashmap_get(m->seats, name);
1872 return bus_send_error_reply(connection, message, &error, -ENOENT);
1874 r = seat_stop_sessions(seat);
1876 return bus_send_error_reply(connection, message, NULL, r);
1878 reply = dbus_message_new_method_return(message);
1882 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
1885 dbus_bool_t b, interactive;
1888 if (!dbus_message_get_args(
1891 DBUS_TYPE_UINT32, &uid,
1892 DBUS_TYPE_BOOLEAN, &b,
1893 DBUS_TYPE_BOOLEAN, &interactive,
1895 return bus_send_error_reply(connection, message, &error, -EINVAL);
1900 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
1902 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
1904 return bus_send_error_reply(connection, message, &error, r);
1906 mkdir_p_label("/var/lib/systemd", 0755);
1908 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
1910 return bus_send_error_reply(connection, message, &error, r);
1912 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
1923 return bus_send_error_reply(connection, message, &error, r);
1925 if (manager_add_user_by_uid(m, uid, &u) >= 0)
1934 if (r < 0 && errno != ENOENT)
1935 return bus_send_error_reply(connection, message, &error, -errno);
1937 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1939 user_add_to_gc_queue(u);
1942 reply = dbus_message_new_method_return(message);
1946 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
1947 const char *sysfs, *seat;
1948 dbus_bool_t interactive;
1950 if (!dbus_message_get_args(
1953 DBUS_TYPE_STRING, &seat,
1954 DBUS_TYPE_STRING, &sysfs,
1955 DBUS_TYPE_BOOLEAN, &interactive,
1957 return bus_send_error_reply(connection, message, &error, -EINVAL);
1959 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
1960 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1962 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
1964 return bus_send_error_reply(connection, message, &error, r);
1966 r = attach_device(m, seat, sysfs);
1968 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1970 reply = dbus_message_new_method_return(message);
1975 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
1976 dbus_bool_t interactive;
1978 if (!dbus_message_get_args(
1981 DBUS_TYPE_BOOLEAN, &interactive,
1983 return bus_send_error_reply(connection, message, &error, -EINVAL);
1985 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
1987 return bus_send_error_reply(connection, message, &error, r);
1989 r = flush_devices(m);
1991 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1993 reply = dbus_message_new_method_return(message);
1997 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
1999 r = bus_manager_do_shutdown_or_sleep(
2000 m, connection, message,
2001 SPECIAL_POWEROFF_TARGET,
2003 "org.freedesktop.login1.power-off",
2004 "org.freedesktop.login1.power-off-multiple-sessions",
2005 "org.freedesktop.login1.power-off-ignore-inhibit",
2009 return bus_send_error_reply(connection, message, &error, r);
2010 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
2011 r = bus_manager_do_shutdown_or_sleep(
2012 m, connection, message,
2013 SPECIAL_REBOOT_TARGET,
2015 "org.freedesktop.login1.reboot",
2016 "org.freedesktop.login1.reboot-multiple-sessions",
2017 "org.freedesktop.login1.reboot-ignore-inhibit",
2021 return bus_send_error_reply(connection, message, &error, r);
2023 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2024 r = bus_manager_do_shutdown_or_sleep(
2025 m, connection, message,
2026 SPECIAL_SUSPEND_TARGET,
2028 "org.freedesktop.login1.suspend",
2029 "org.freedesktop.login1.suspend-multiple-sessions",
2030 "org.freedesktop.login1.suspend-ignore-inhibit",
2034 return bus_send_error_reply(connection, message, &error, r);
2035 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2036 r = bus_manager_do_shutdown_or_sleep(
2037 m, connection, message,
2038 SPECIAL_HIBERNATE_TARGET,
2040 "org.freedesktop.login1.hibernate",
2041 "org.freedesktop.login1.hibernate-multiple-sessions",
2042 "org.freedesktop.login1.hibernate-ignore-inhibit",
2046 return bus_send_error_reply(connection, message, &error, r);
2048 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2050 r = bus_manager_can_shutdown_or_sleep(
2051 m, connection, message,
2053 "org.freedesktop.login1.power-off",
2054 "org.freedesktop.login1.power-off-multiple-sessions",
2055 "org.freedesktop.login1.power-off-ignore-inhibit",
2059 return bus_send_error_reply(connection, message, &error, r);
2060 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2061 r = bus_manager_can_shutdown_or_sleep(
2062 m, connection, message,
2064 "org.freedesktop.login1.reboot",
2065 "org.freedesktop.login1.reboot-multiple-sessions",
2066 "org.freedesktop.login1.reboot-ignore-inhibit",
2070 return bus_send_error_reply(connection, message, &error, r);
2072 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2073 r = bus_manager_can_shutdown_or_sleep(
2074 m, connection, message,
2076 "org.freedesktop.login1.suspend",
2077 "org.freedesktop.login1.suspend-multiple-sessions",
2078 "org.freedesktop.login1.suspend-ignore-inhibit",
2082 return bus_send_error_reply(connection, message, &error, r);
2084 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2085 r = bus_manager_can_shutdown_or_sleep(
2086 m, connection, message,
2088 "org.freedesktop.login1.hibernate",
2089 "org.freedesktop.login1.hibernate-multiple-sessions",
2090 "org.freedesktop.login1.hibernate-ignore-inhibit",
2094 return bus_send_error_reply(connection, message, &error, r);
2096 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2097 char *introspection = NULL;
2106 if (!(reply = dbus_message_new_method_return(message)))
2109 /* We roll our own introspection code here, instead of
2110 * relying on bus_default_message_handler() because we
2111 * need to generate our introspection string
2114 if (!(f = open_memstream(&introspection, &size)))
2117 fputs(INTROSPECTION_BEGIN, f);
2119 HASHMAP_FOREACH(seat, m->seats, i) {
2120 p = bus_path_escape(seat->id);
2123 fprintf(f, "<node name=\"seat/%s\"/>", p);
2128 HASHMAP_FOREACH(user, m->users, i)
2129 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2131 HASHMAP_FOREACH(session, m->sessions, i) {
2132 p = bus_path_escape(session->id);
2135 fprintf(f, "<node name=\"session/%s\"/>", p);
2140 fputs(INTROSPECTION_END, f);
2144 free(introspection);
2153 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2154 free(introspection);
2158 free(introspection);
2160 const BusBoundProperties bps[] = {
2161 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2164 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2168 if (!dbus_connection_send(connection, reply, NULL))
2171 dbus_message_unref(reply);
2174 return DBUS_HANDLER_RESULT_HANDLED;
2178 dbus_message_unref(reply);
2180 dbus_error_free(&error);
2182 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2185 const DBusObjectPathVTable bus_manager_vtable = {
2186 .message_function = manager_message_handler
2189 DBusHandlerResult bus_message_filter(
2190 DBusConnection *connection,
2191 DBusMessage *message,
2194 Manager *m = userdata;
2201 dbus_error_init(&error);
2203 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
2206 if (!dbus_message_get_args(message, &error,
2207 DBUS_TYPE_STRING, &cgroup,
2209 log_error("Failed to parse Released message: %s", bus_error_message(&error));
2211 manager_cgroup_notify_empty(m, cgroup);
2214 dbus_error_free(&error);
2216 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2219 int manager_send_changed(Manager *manager, const char *properties) {
2225 m = bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties);
2229 if (!dbus_connection_send(manager->bus, m, NULL))
2236 dbus_message_unref(m);
2241 int manager_dispatch_delayed(Manager *manager) {
2242 const char *unit_name;
2249 if (!manager->delayed_unit)
2252 /* Continue delay? */
2254 manager->delayed_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC) &&
2255 manager_is_inhibited(manager, manager->delayed_what, INHIBIT_DELAY, NULL);
2259 /* Reset delay data */
2260 unit_name = manager->delayed_unit;
2261 manager->delayed_unit = NULL;
2263 /* Actually do the shutdown */
2264 dbus_error_init(&error);
2265 r = send_start_unit(manager->bus, unit_name, &error);
2267 log_warning("Failed to send delayed message: %s", bus_error_message_or_strerror(&error, -r));
2268 dbus_error_free(&error);
2272 /* Tell people about it */
2273 send_prepare_for(manager, manager->delayed_what, false);