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 DBusMessage *message, *reply;
972 const char *mode = "replace";
977 message = dbus_message_new_method_call(
978 "org.freedesktop.systemd1",
979 "/org/freedesktop/systemd1",
980 "org.freedesktop.systemd1.Manager",
985 if (!dbus_message_append_args(message,
986 DBUS_TYPE_STRING, &unit_name,
987 DBUS_TYPE_STRING, &mode,
988 DBUS_TYPE_INVALID)) {
989 dbus_message_unref(message);
993 reply = dbus_connection_send_with_reply_and_block(connection, message, -1, error);
994 dbus_message_unref(message);
999 dbus_message_unref(reply);
1003 static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
1004 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
1005 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
1006 [INHIBIT_SLEEP] = "PrepareForSleep"
1009 dbus_bool_t active = _active;
1010 DBusMessage *message;
1015 assert(w < _INHIBIT_WHAT_MAX);
1016 assert(signal_name[w]);
1018 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1022 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1023 !dbus_connection_send(m->bus, message, NULL))
1026 dbus_message_unref(message);
1030 static int delay_shutdown_or_sleep(Manager *m, InhibitWhat w, const char *unit_name) {
1033 assert(w < _INHIBIT_WHAT_MAX);
1035 /* Tell everybody to prepare for shutdown/sleep */
1036 send_prepare_for(m, w, true);
1038 /* Update timestamp for timeout */
1039 if (!m->delayed_unit)
1040 m->delayed_timestamp = now(CLOCK_MONOTONIC);
1042 /* Remember what we want to do, possibly overriding what kind
1043 * of unit we previously queued. */
1044 m->delayed_unit = unit_name;
1045 m->delayed_what = w;
1050 static int bus_manager_can_shutdown_or_sleep(
1052 DBusConnection *connection,
1053 DBusMessage *message,
1056 const char *action_multiple_sessions,
1057 const char *action_ignore_inhibit,
1058 const char *sleep_type,
1060 DBusMessage **_reply) {
1062 bool multiple_sessions, challenge, blocked, b;
1064 DBusMessage *reply = NULL;
1071 assert(w <= _INHIBIT_WHAT_MAX);
1073 assert(action_multiple_sessions);
1074 assert(action_ignore_inhibit);
1079 r = can_sleep(sleep_type);
1089 r = have_multiple_sessions(connection, m, message, error);
1093 multiple_sessions = r > 0;
1094 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL);
1096 if (multiple_sessions) {
1097 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1104 result = "challenge";
1110 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1114 if (r > 0 && !result)
1116 else if (challenge && (!result || streq(result, "yes")))
1117 result = "challenge";
1122 if (!multiple_sessions && !blocked) {
1123 /* If neither inhibit nor multiple sessions
1124 * apply then just check the normal policy */
1126 r = verify_polkit(connection, message, action, false, &challenge, error);
1133 result = "challenge";
1139 reply = dbus_message_new_method_return(message);
1143 b = dbus_message_append_args(
1145 DBUS_TYPE_STRING, &result,
1148 dbus_message_unref(reply);
1156 int bus_manager_shutdown_or_sleep_now_or_later(
1158 const char *unit_name,
1168 assert(w <= _INHIBIT_WHAT_MAX);
1171 m->inhibit_delay_max > 0 &&
1172 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL);
1175 /* Shutdown is delayed, keep in mind what we
1176 * want to do, and start a timeout */
1177 r = delay_shutdown_or_sleep(m, w, unit_name);
1179 /* Shutdown is not delayed, execute it
1181 r = send_start_unit(m->bus, unit_name, error);
1186 static int bus_manager_do_shutdown_or_sleep(
1188 DBusConnection *connection,
1189 DBusMessage *message,
1190 const char *unit_name,
1193 const char *action_multiple_sessions,
1194 const char *action_ignore_inhibit,
1195 const char *sleep_type,
1197 DBusMessage **_reply) {
1199 dbus_bool_t interactive;
1200 bool multiple_sessions, blocked;
1201 DBusMessage *reply = NULL;
1209 assert(w <= _INHIBIT_WHAT_MAX);
1211 assert(action_multiple_sessions);
1212 assert(action_ignore_inhibit);
1216 if (!dbus_message_get_args(
1219 DBUS_TYPE_BOOLEAN, &interactive,
1224 r = can_sleep(sleep_type);
1232 r = have_multiple_sessions(connection, m, message, error);
1236 multiple_sessions = r > 0;
1237 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL);
1239 if (multiple_sessions) {
1240 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1246 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1251 if (!multiple_sessions && !blocked) {
1252 r = verify_polkit(connection, message, action, interactive, NULL, error);
1257 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
1261 reply = dbus_message_new_method_return(message);
1269 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_button, handle_button, HandleButton);
1271 static const BusProperty bus_login_manager_properties[] = {
1272 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_path), true },
1273 { "Controllers", bus_property_append_strv, "as", offsetof(Manager, controllers), true },
1274 { "ResetControllers", bus_property_append_strv, "as", offsetof(Manager, reset_controllers), true },
1275 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1276 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1277 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1278 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1279 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1280 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1281 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
1282 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1283 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1284 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
1285 { "HandlePowerKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_power_key) },
1286 { "HandleSleepKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_sleep_key) },
1287 { "HandleLidSwitch", bus_manager_append_handle_button, "s", offsetof(Manager, handle_lid_switch) },
1288 { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
1289 { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
1293 static DBusHandlerResult manager_message_handler(
1294 DBusConnection *connection,
1295 DBusMessage *message,
1298 Manager *m = userdata;
1301 DBusMessage *reply = NULL;
1308 dbus_error_init(&error);
1310 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1316 if (!dbus_message_get_args(
1319 DBUS_TYPE_STRING, &name,
1321 return bus_send_error_reply(connection, message, &error, -EINVAL);
1323 session = hashmap_get(m->sessions, name);
1325 return bus_send_error_reply(connection, message, &error, -ENOENT);
1327 reply = dbus_message_new_method_return(message);
1331 p = session_bus_path(session);
1335 b = dbus_message_append_args(
1337 DBUS_TYPE_OBJECT_PATH, &p,
1344 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1350 if (!dbus_message_get_args(
1353 DBUS_TYPE_UINT32, &pid,
1355 return bus_send_error_reply(connection, message, &error, -EINVAL);
1357 r = manager_get_session_by_pid(m, pid, &session);
1359 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1361 reply = dbus_message_new_method_return(message);
1365 p = session_bus_path(session);
1369 b = dbus_message_append_args(
1371 DBUS_TYPE_OBJECT_PATH, &p,
1378 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1384 if (!dbus_message_get_args(
1387 DBUS_TYPE_UINT32, &uid,
1389 return bus_send_error_reply(connection, message, &error, -EINVAL);
1391 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1393 return bus_send_error_reply(connection, message, &error, -ENOENT);
1395 reply = dbus_message_new_method_return(message);
1399 p = user_bus_path(user);
1403 b = dbus_message_append_args(
1405 DBUS_TYPE_OBJECT_PATH, &p,
1412 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1418 if (!dbus_message_get_args(
1421 DBUS_TYPE_STRING, &name,
1423 return bus_send_error_reply(connection, message, &error, -EINVAL);
1425 seat = hashmap_get(m->seats, name);
1427 return bus_send_error_reply(connection, message, &error, -ENOENT);
1429 reply = dbus_message_new_method_return(message);
1433 p = seat_bus_path(seat);
1437 b = dbus_message_append_args(
1439 DBUS_TYPE_OBJECT_PATH, &p,
1446 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1450 DBusMessageIter iter, sub;
1451 const char *empty = "";
1453 reply = dbus_message_new_method_return(message);
1457 dbus_message_iter_init_append(reply, &iter);
1459 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1462 HASHMAP_FOREACH(session, m->sessions, i) {
1463 DBusMessageIter sub2;
1466 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1469 uid = session->user->uid;
1471 p = session_bus_path(session);
1475 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1476 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1477 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1478 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1479 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1486 if (!dbus_message_iter_close_container(&sub, &sub2))
1490 if (!dbus_message_iter_close_container(&iter, &sub))
1493 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1497 DBusMessageIter iter, sub;
1499 reply = dbus_message_new_method_return(message);
1503 dbus_message_iter_init_append(reply, &iter);
1505 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1508 HASHMAP_FOREACH(user, m->users, i) {
1509 DBusMessageIter sub2;
1512 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1517 p = user_bus_path(user);
1521 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1522 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1523 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1530 if (!dbus_message_iter_close_container(&sub, &sub2))
1534 if (!dbus_message_iter_close_container(&iter, &sub))
1537 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1541 DBusMessageIter iter, sub;
1543 reply = dbus_message_new_method_return(message);
1547 dbus_message_iter_init_append(reply, &iter);
1549 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1552 HASHMAP_FOREACH(seat, m->seats, i) {
1553 DBusMessageIter sub2;
1555 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1558 p = seat_bus_path(seat);
1562 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1563 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1570 if (!dbus_message_iter_close_container(&sub, &sub2))
1574 if (!dbus_message_iter_close_container(&iter, &sub))
1577 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1578 Inhibitor *inhibitor;
1580 DBusMessageIter iter, sub;
1582 reply = dbus_message_new_method_return(message);
1586 dbus_message_iter_init_append(reply, &iter);
1588 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1591 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1592 DBusMessageIter sub2;
1593 dbus_uint32_t uid, pid;
1594 const char *what, *who, *why, *mode;
1596 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1599 what = strempty(inhibit_what_to_string(inhibitor->what));
1600 who = strempty(inhibitor->who);
1601 why = strempty(inhibitor->why);
1602 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
1603 uid = (dbus_uint32_t) inhibitor->uid;
1604 pid = (dbus_uint32_t) inhibitor->pid;
1606 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1607 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1608 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1609 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
1610 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1611 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1614 if (!dbus_message_iter_close_container(&sub, &sub2))
1618 if (!dbus_message_iter_close_container(&iter, &sub))
1621 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1623 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1626 return bus_send_error_reply(connection, message, &error, r);
1629 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1631 r = bus_manager_create_session(m, message, &reply);
1633 /* Don't delay the work on OOM here, since it might be
1634 * triggered by a low RLIMIT_NOFILE here (since we
1635 * send a dupped fd to the client), and we'd rather
1636 * see this fail quickly then be retried later */
1639 return bus_send_error_reply(connection, message, NULL, r);
1641 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1645 if (!dbus_message_get_args(
1648 DBUS_TYPE_STRING, &name,
1650 return bus_send_error_reply(connection, message, &error, -EINVAL);
1652 session = hashmap_get(m->sessions, name);
1654 return bus_send_error_reply(connection, message, &error, -ENOENT);
1656 /* We use the FIFO to detect stray sessions where the
1657 process invoking PAM dies abnormally. We need to make
1658 sure that that process is not killed if at the clean
1659 end of the session it closes the FIFO. Hence, with
1660 this call explicitly turn off the FIFO logic, so that
1661 the PAM code can finish clean up on its own */
1662 session_remove_fifo(session);
1664 reply = dbus_message_new_method_return(message);
1668 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1672 if (!dbus_message_get_args(
1675 DBUS_TYPE_STRING, &name,
1677 return bus_send_error_reply(connection, message, &error, -EINVAL);
1679 session = hashmap_get(m->sessions, name);
1681 return bus_send_error_reply(connection, message, &error, -ENOENT);
1683 r = session_activate(session);
1685 return bus_send_error_reply(connection, message, NULL, r);
1687 reply = dbus_message_new_method_return(message);
1691 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1692 const char *session_name, *seat_name;
1696 /* Same as ActivateSession() but refuses to work if
1697 * the seat doesn't match */
1699 if (!dbus_message_get_args(
1702 DBUS_TYPE_STRING, &session_name,
1703 DBUS_TYPE_STRING, &seat_name,
1705 return bus_send_error_reply(connection, message, &error, -EINVAL);
1707 session = hashmap_get(m->sessions, session_name);
1709 return bus_send_error_reply(connection, message, &error, -ENOENT);
1711 seat = hashmap_get(m->seats, seat_name);
1713 return bus_send_error_reply(connection, message, &error, -ENOENT);
1715 if (session->seat != seat)
1716 return bus_send_error_reply(connection, message, &error, -EINVAL);
1718 r = session_activate(session);
1720 return bus_send_error_reply(connection, message, NULL, r);
1722 reply = dbus_message_new_method_return(message);
1726 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1727 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1731 if (!dbus_message_get_args(
1734 DBUS_TYPE_STRING, &name,
1736 return bus_send_error_reply(connection, message, &error, -EINVAL);
1738 session = hashmap_get(m->sessions, name);
1740 return bus_send_error_reply(connection, message, &error, -ENOENT);
1742 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1745 reply = dbus_message_new_method_return(message);
1749 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions")) {
1753 HASHMAP_FOREACH(session, m->sessions, i)
1754 if (session_send_lock(session, true) < 0)
1757 reply = dbus_message_new_method_return(message);
1761 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1768 if (!dbus_message_get_args(
1771 DBUS_TYPE_STRING, &name,
1772 DBUS_TYPE_STRING, &swho,
1773 DBUS_TYPE_INT32, &signo,
1775 return bus_send_error_reply(connection, message, &error, -EINVAL);
1780 who = kill_who_from_string(swho);
1782 return bus_send_error_reply(connection, message, &error, -EINVAL);
1785 if (signo <= 0 || signo >= _NSIG)
1786 return bus_send_error_reply(connection, message, &error, -EINVAL);
1788 session = hashmap_get(m->sessions, name);
1790 return bus_send_error_reply(connection, message, &error, -ENOENT);
1792 r = session_kill(session, who, signo);
1794 return bus_send_error_reply(connection, message, NULL, r);
1796 reply = dbus_message_new_method_return(message);
1800 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1805 if (!dbus_message_get_args(
1808 DBUS_TYPE_UINT32, &uid,
1809 DBUS_TYPE_INT32, &signo,
1811 return bus_send_error_reply(connection, message, &error, -EINVAL);
1813 if (signo <= 0 || signo >= _NSIG)
1814 return bus_send_error_reply(connection, message, &error, -EINVAL);
1816 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1818 return bus_send_error_reply(connection, message, &error, -ENOENT);
1820 r = user_kill(user, signo);
1822 return bus_send_error_reply(connection, message, NULL, r);
1824 reply = dbus_message_new_method_return(message);
1828 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1832 if (!dbus_message_get_args(
1835 DBUS_TYPE_STRING, &name,
1837 return bus_send_error_reply(connection, message, &error, -EINVAL);
1839 session = hashmap_get(m->sessions, name);
1841 return bus_send_error_reply(connection, message, &error, -ENOENT);
1843 r = session_stop(session);
1845 return bus_send_error_reply(connection, message, NULL, r);
1847 reply = dbus_message_new_method_return(message);
1851 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1855 if (!dbus_message_get_args(
1858 DBUS_TYPE_UINT32, &uid,
1860 return bus_send_error_reply(connection, message, &error, -EINVAL);
1862 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1864 return bus_send_error_reply(connection, message, &error, -ENOENT);
1866 r = user_stop(user);
1868 return bus_send_error_reply(connection, message, NULL, r);
1870 reply = dbus_message_new_method_return(message);
1874 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1878 if (!dbus_message_get_args(
1881 DBUS_TYPE_STRING, &name,
1883 return bus_send_error_reply(connection, message, &error, -EINVAL);
1885 seat = hashmap_get(m->seats, name);
1887 return bus_send_error_reply(connection, message, &error, -ENOENT);
1889 r = seat_stop_sessions(seat);
1891 return bus_send_error_reply(connection, message, NULL, r);
1893 reply = dbus_message_new_method_return(message);
1897 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
1900 dbus_bool_t b, interactive;
1903 if (!dbus_message_get_args(
1906 DBUS_TYPE_UINT32, &uid,
1907 DBUS_TYPE_BOOLEAN, &b,
1908 DBUS_TYPE_BOOLEAN, &interactive,
1910 return bus_send_error_reply(connection, message, &error, -EINVAL);
1915 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
1917 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
1919 return bus_send_error_reply(connection, message, &error, r);
1921 mkdir_p_label("/var/lib/systemd", 0755);
1923 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
1925 return bus_send_error_reply(connection, message, &error, r);
1927 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
1938 return bus_send_error_reply(connection, message, &error, r);
1940 if (manager_add_user_by_uid(m, uid, &u) >= 0)
1949 if (r < 0 && errno != ENOENT)
1950 return bus_send_error_reply(connection, message, &error, -errno);
1952 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1954 user_add_to_gc_queue(u);
1957 reply = dbus_message_new_method_return(message);
1961 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
1962 const char *sysfs, *seat;
1963 dbus_bool_t interactive;
1965 if (!dbus_message_get_args(
1968 DBUS_TYPE_STRING, &seat,
1969 DBUS_TYPE_STRING, &sysfs,
1970 DBUS_TYPE_BOOLEAN, &interactive,
1972 return bus_send_error_reply(connection, message, &error, -EINVAL);
1974 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
1975 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1977 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
1979 return bus_send_error_reply(connection, message, &error, r);
1981 r = attach_device(m, seat, sysfs);
1983 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1985 reply = dbus_message_new_method_return(message);
1990 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
1991 dbus_bool_t interactive;
1993 if (!dbus_message_get_args(
1996 DBUS_TYPE_BOOLEAN, &interactive,
1998 return bus_send_error_reply(connection, message, &error, -EINVAL);
2000 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
2002 return bus_send_error_reply(connection, message, &error, r);
2004 r = flush_devices(m);
2006 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2008 reply = dbus_message_new_method_return(message);
2012 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
2014 r = bus_manager_do_shutdown_or_sleep(
2015 m, connection, message,
2016 SPECIAL_POWEROFF_TARGET,
2018 "org.freedesktop.login1.power-off",
2019 "org.freedesktop.login1.power-off-multiple-sessions",
2020 "org.freedesktop.login1.power-off-ignore-inhibit",
2024 return bus_send_error_reply(connection, message, &error, r);
2025 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
2026 r = bus_manager_do_shutdown_or_sleep(
2027 m, connection, message,
2028 SPECIAL_REBOOT_TARGET,
2030 "org.freedesktop.login1.reboot",
2031 "org.freedesktop.login1.reboot-multiple-sessions",
2032 "org.freedesktop.login1.reboot-ignore-inhibit",
2036 return bus_send_error_reply(connection, message, &error, r);
2038 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2039 r = bus_manager_do_shutdown_or_sleep(
2040 m, connection, message,
2041 SPECIAL_SUSPEND_TARGET,
2043 "org.freedesktop.login1.suspend",
2044 "org.freedesktop.login1.suspend-multiple-sessions",
2045 "org.freedesktop.login1.suspend-ignore-inhibit",
2049 return bus_send_error_reply(connection, message, &error, r);
2050 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2051 r = bus_manager_do_shutdown_or_sleep(
2052 m, connection, message,
2053 SPECIAL_HIBERNATE_TARGET,
2055 "org.freedesktop.login1.hibernate",
2056 "org.freedesktop.login1.hibernate-multiple-sessions",
2057 "org.freedesktop.login1.hibernate-ignore-inhibit",
2061 return bus_send_error_reply(connection, message, &error, r);
2063 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2065 r = bus_manager_can_shutdown_or_sleep(
2066 m, connection, message,
2068 "org.freedesktop.login1.power-off",
2069 "org.freedesktop.login1.power-off-multiple-sessions",
2070 "org.freedesktop.login1.power-off-ignore-inhibit",
2074 return bus_send_error_reply(connection, message, &error, r);
2075 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2076 r = bus_manager_can_shutdown_or_sleep(
2077 m, connection, message,
2079 "org.freedesktop.login1.reboot",
2080 "org.freedesktop.login1.reboot-multiple-sessions",
2081 "org.freedesktop.login1.reboot-ignore-inhibit",
2085 return bus_send_error_reply(connection, message, &error, r);
2087 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2088 r = bus_manager_can_shutdown_or_sleep(
2089 m, connection, message,
2091 "org.freedesktop.login1.suspend",
2092 "org.freedesktop.login1.suspend-multiple-sessions",
2093 "org.freedesktop.login1.suspend-ignore-inhibit",
2097 return bus_send_error_reply(connection, message, &error, r);
2099 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2100 r = bus_manager_can_shutdown_or_sleep(
2101 m, connection, message,
2103 "org.freedesktop.login1.hibernate",
2104 "org.freedesktop.login1.hibernate-multiple-sessions",
2105 "org.freedesktop.login1.hibernate-ignore-inhibit",
2109 return bus_send_error_reply(connection, message, &error, r);
2111 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2112 char *introspection = NULL;
2121 if (!(reply = dbus_message_new_method_return(message)))
2124 /* We roll our own introspection code here, instead of
2125 * relying on bus_default_message_handler() because we
2126 * need to generate our introspection string
2129 if (!(f = open_memstream(&introspection, &size)))
2132 fputs(INTROSPECTION_BEGIN, f);
2134 HASHMAP_FOREACH(seat, m->seats, i) {
2135 p = bus_path_escape(seat->id);
2138 fprintf(f, "<node name=\"seat/%s\"/>", p);
2143 HASHMAP_FOREACH(user, m->users, i)
2144 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2146 HASHMAP_FOREACH(session, m->sessions, i) {
2147 p = bus_path_escape(session->id);
2150 fprintf(f, "<node name=\"session/%s\"/>", p);
2155 fputs(INTROSPECTION_END, f);
2159 free(introspection);
2168 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2169 free(introspection);
2173 free(introspection);
2175 const BusBoundProperties bps[] = {
2176 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2179 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2183 if (!dbus_connection_send(connection, reply, NULL))
2186 dbus_message_unref(reply);
2189 return DBUS_HANDLER_RESULT_HANDLED;
2193 dbus_message_unref(reply);
2195 dbus_error_free(&error);
2197 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2200 const DBusObjectPathVTable bus_manager_vtable = {
2201 .message_function = manager_message_handler
2204 DBusHandlerResult bus_message_filter(
2205 DBusConnection *connection,
2206 DBusMessage *message,
2209 Manager *m = userdata;
2216 dbus_error_init(&error);
2218 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
2221 if (!dbus_message_get_args(message, &error,
2222 DBUS_TYPE_STRING, &cgroup,
2224 log_error("Failed to parse Released message: %s", bus_error_message(&error));
2226 manager_cgroup_notify_empty(m, cgroup);
2229 dbus_error_free(&error);
2231 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2234 int manager_send_changed(Manager *manager, const char *properties) {
2240 m = bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties);
2244 if (!dbus_connection_send(manager->bus, m, NULL))
2251 dbus_message_unref(m);
2256 int manager_dispatch_delayed(Manager *manager) {
2257 const char *unit_name;
2264 if (!manager->delayed_unit)
2267 /* Continue delay? */
2269 manager->delayed_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC) &&
2270 manager_is_inhibited(manager, manager->delayed_what, INHIBIT_DELAY, NULL);
2274 /* Reset delay data */
2275 unit_name = manager->delayed_unit;
2276 manager->delayed_unit = NULL;
2278 /* Actually do the shutdown */
2279 dbus_error_init(&error);
2280 r = send_start_unit(manager->bus, unit_name, &error);
2282 log_warning("Failed to send delayed message: %s", bus_error_message_or_strerror(&error, -r));
2283 dbus_error_free(&error);
2287 /* Tell people about it */
2288 send_prepare_for(manager, manager->delayed_what, false);