1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
28 #include "dbus-common.h"
31 #include "path-util.h"
34 #include "systemd/sd-id128.h"
35 #include "systemd/sd-messages.h"
36 #include "fileio-label.h"
39 #define BUS_MANAGER_INTERFACE \
40 " <interface name=\"org.freedesktop.login1.Manager\">\n" \
41 " <method name=\"GetSession\">\n" \
42 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
43 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
45 " <method name=\"GetSessionByPID\">\n" \
46 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
47 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
49 " <method name=\"GetUser\">\n" \
50 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
51 " <arg name=\"user\" type=\"o\" direction=\"out\"/>\n" \
53 " <method name=\"GetSeat\">\n" \
54 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
55 " <arg name=\"seat\" type=\"o\" direction=\"out\"/>\n" \
57 " <method name=\"ListSessions\">\n" \
58 " <arg name=\"sessions\" type=\"a(susso)\" direction=\"out\"/>\n" \
60 " <method name=\"ListUsers\">\n" \
61 " <arg name=\"users\" type=\"a(uso)\" direction=\"out\"/>\n" \
63 " <method name=\"ListSeats\">\n" \
64 " <arg name=\"seats\" type=\"a(so)\" direction=\"out\"/>\n" \
66 " <method name=\"CreateSession\">\n" \
67 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
68 " <arg name=\"leader\" type=\"u\" direction=\"in\"/>\n" \
69 " <arg name=\"sevice\" type=\"s\" direction=\"in\"/>\n" \
70 " <arg name=\"type\" type=\"s\" direction=\"in\"/>\n" \
71 " <arg name=\"class\" type=\"s\" direction=\"in\"/>\n" \
72 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
73 " <arg name=\"vtnr\" type=\"u\" direction=\"in\"/>\n" \
74 " <arg name=\"tty\" type=\"s\" direction=\"in\"/>\n" \
75 " <arg name=\"display\" type=\"s\" direction=\"in\"/>\n" \
76 " <arg name=\"remote\" type=\"b\" direction=\"in\"/>\n" \
77 " <arg name=\"remote_user\" type=\"s\" direction=\"in\"/>\n" \
78 " <arg name=\"remote_host\" type=\"s\" direction=\"in\"/>\n" \
79 " <arg name=\"controllers\" type=\"as\" direction=\"in\"/>\n" \
80 " <arg name=\"reset_controllers\" type=\"as\" direction=\"in\"/>\n" \
81 " <arg name=\"kill_processes\" type=\"b\" direction=\"in\"/>\n" \
82 " <arg name=\"id\" type=\"s\" direction=\"out\"/>\n" \
83 " <arg name=\"path\" type=\"o\" direction=\"out\"/>\n" \
84 " <arg name=\"runtime_path\" type=\"o\" direction=\"out\"/>\n" \
85 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
86 " <arg name=\"seat\" type=\"s\" direction=\"out\"/>\n" \
87 " <arg name=\"vtnr\" type=\"u\" direction=\"out\"/>\n" \
88 " <arg name=\"existing\" type=\"b\" direction=\"out\"/>\n" \
90 " <method name=\"ReleaseSession\">\n" \
91 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
93 " <method name=\"ActivateSession\">\n" \
94 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
96 " <method name=\"ActivateSessionOnSeat\">\n" \
97 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
98 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
100 " <method name=\"LockSession\">\n" \
101 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
103 " <method name=\"UnlockSession\">\n" \
104 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
106 " <method name=\"LockSessions\"/>\n" \
107 " <method name=\"UnlockSessions\"/>\n" \
108 " <method name=\"KillSession\">\n" \
109 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
110 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
111 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
113 " <method name=\"KillUser\">\n" \
114 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
115 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
117 " <method name=\"TerminateSession\">\n" \
118 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
120 " <method name=\"TerminateUser\">\n" \
121 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
123 " <method name=\"TerminateSeat\">\n" \
124 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
126 " <method name=\"SetUserLinger\">\n" \
127 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
128 " <arg name=\"b\" type=\"b\" direction=\"in\"/>\n" \
129 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
131 " <method name=\"AttachDevice\">\n" \
132 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
133 " <arg name=\"sysfs\" type=\"s\" direction=\"in\"/>\n" \
134 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
136 " <method name=\"FlushDevices\">\n" \
137 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
139 " <method name=\"PowerOff\">\n" \
140 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
142 " <method name=\"Reboot\">\n" \
143 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
145 " <method name=\"Suspend\">\n" \
146 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
148 " <method name=\"Hibernate\">\n" \
149 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
151 " <method name=\"HybridSleep\">\n" \
152 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
154 " <method name=\"CanPowerOff\">\n" \
155 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
157 " <method name=\"CanReboot\">\n" \
158 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
160 " <method name=\"CanSuspend\">\n" \
161 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
163 " <method name=\"CanHibernate\">\n" \
164 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
166 " <method name=\"CanHybridSleep\">\n" \
167 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
169 " <method name=\"Inhibit\">\n" \
170 " <arg name=\"what\" type=\"s\" direction=\"in\"/>\n" \
171 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
172 " <arg name=\"why\" type=\"s\" direction=\"in\"/>\n" \
173 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
174 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
176 " <method name=\"ListInhibitors\">\n" \
177 " <arg name=\"inhibitors\" type=\"a(ssssuu)\" direction=\"out\"/>\n" \
179 " <signal name=\"SessionNew\">\n" \
180 " <arg name=\"id\" type=\"s\"/>\n" \
181 " <arg name=\"path\" type=\"o\"/>\n" \
183 " <signal name=\"SessionRemoved\">\n" \
184 " <arg name=\"id\" type=\"s\"/>\n" \
185 " <arg name=\"path\" type=\"o\"/>\n" \
187 " <signal name=\"UserNew\">\n" \
188 " <arg name=\"uid\" type=\"u\"/>\n" \
189 " <arg name=\"path\" type=\"o\"/>\n" \
191 " <signal name=\"UserRemoved\">\n" \
192 " <arg name=\"uid\" type=\"u\"/>\n" \
193 " <arg name=\"path\" type=\"o\"/>\n" \
195 " <signal name=\"SeatNew\">\n" \
196 " <arg name=\"id\" type=\"s\"/>\n" \
197 " <arg name=\"path\" type=\"o\"/>\n" \
199 " <signal name=\"SeatRemoved\">\n" \
200 " <arg name=\"id\" type=\"s\"/>\n" \
201 " <arg name=\"path\" type=\"o\"/>\n" \
203 " <signal name=\"PrepareForShutdown\">\n" \
204 " <arg name=\"active\" type=\"b\"/>\n" \
206 " <signal name=\"PrepareForSleep\">\n" \
207 " <arg name=\"active\" type=\"b\"/>\n" \
209 " <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
210 " <property name=\"Controllers\" type=\"as\" access=\"read\"/>\n" \
211 " <property name=\"ResetControllers\" type=\"as\" access=\"read\"/>\n" \
212 " <property name=\"NAutoVTs\" type=\"u\" access=\"read\"/>\n" \
213 " <property name=\"KillOnlyUsers\" type=\"as\" access=\"read\"/>\n" \
214 " <property name=\"KillExcludeUsers\" type=\"as\" access=\"read\"/>\n" \
215 " <property name=\"KillUserProcesses\" type=\"b\" access=\"read\"/>\n" \
216 " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
217 " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
218 " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
219 " <property name=\"BlockInhibited\" type=\"s\" access=\"read\"/>\n" \
220 " <property name=\"DelayInhibited\" type=\"s\" access=\"read\"/>\n" \
221 " <property name=\"InhibitDelayMaxUSec\" type=\"t\" access=\"read\"/>\n" \
222 " <property name=\"HandlePowerKey\" type=\"s\" access=\"read\"/>\n" \
223 " <property name=\"HandleSuspendKey\" type=\"s\" access=\"read\"/>\n" \
224 " <property name=\"HandleHibernateKey\" type=\"s\" access=\"read\"/>\n" \
225 " <property name=\"HandleLidSwitch\" type=\"s\" access=\"read\"/>\n" \
226 " <property name=\"IdleAction\" type=\"s\" access=\"read\"/>\n" \
227 " <property name=\"IdleActionUSec\" type=\"t\" access=\"read\"/>\n" \
228 " <property name=\"PreparingForShutdown\" type=\"b\" access=\"read\"/>\n" \
229 " <property name=\"PreparingForSleep\" type=\"b\" access=\"read\"/>\n" \
232 #define INTROSPECTION_BEGIN \
233 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
235 BUS_MANAGER_INTERFACE \
236 BUS_PROPERTIES_INTERFACE \
238 BUS_INTROSPECTABLE_INTERFACE
240 #define INTROSPECTION_END \
243 #define INTERFACES_LIST \
244 BUS_GENERIC_INTERFACES_LIST \
245 "org.freedesktop.login1.Manager\0"
247 static int bus_manager_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
255 b = manager_get_idle_hint(m, NULL) > 0;
256 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
262 static int bus_manager_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
271 manager_get_idle_hint(m, &t);
272 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
274 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
280 static int bus_manager_append_inhibited(DBusMessageIter *i, const char *property, void *data) {
285 w = manager_inhibit_what(m, streq(property, "BlockInhibited") ? INHIBIT_BLOCK : INHIBIT_DELAY);
286 p = inhibit_what_to_string(w);
288 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &p))
294 static int bus_manager_append_preparing(DBusMessageIter *i, const char *property, void *data) {
301 if (streq(property, "PreparingForShutdown"))
302 b = !!(m->action_what & INHIBIT_SHUTDOWN);
304 b = !!(m->action_what & INHIBIT_SLEEP);
306 dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b);
310 static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMessage **_reply) {
311 Session *session = NULL;
313 const char *type, *class, *seat, *tty, *display, *remote_user, *remote_host, *service;
314 uint32_t uid, leader, audit_id = 0;
315 dbus_bool_t remote, kill_processes, exists;
316 char **controllers = NULL, **reset_controllers = NULL;
320 DBusMessageIter iter;
325 DBusMessage *reply = NULL;
332 if (!dbus_message_iter_init(message, &iter) ||
333 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
336 dbus_message_iter_get_basic(&iter, &uid);
338 if (!dbus_message_iter_next(&iter) ||
339 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
342 dbus_message_iter_get_basic(&iter, &leader);
345 !dbus_message_iter_next(&iter) ||
346 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
349 dbus_message_iter_get_basic(&iter, &service);
351 if (!dbus_message_iter_next(&iter) ||
352 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
355 dbus_message_iter_get_basic(&iter, &type);
356 t = session_type_from_string(type);
359 !dbus_message_iter_next(&iter) ||
360 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
363 dbus_message_iter_get_basic(&iter, &class);
367 c = session_class_from_string(class);
370 !dbus_message_iter_next(&iter) ||
371 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
374 dbus_message_iter_get_basic(&iter, &seat);
379 s = hashmap_get(m->seats, seat);
384 if (!dbus_message_iter_next(&iter) ||
385 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
388 dbus_message_iter_get_basic(&iter, &vtnr);
390 if (!dbus_message_iter_next(&iter) ||
391 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
394 dbus_message_iter_get_basic(&iter, &tty);
396 if (tty_is_vc(tty)) {
401 else if (s != m->vtconsole)
404 v = vtnr_from_tty(tty);
407 return v < 0 ? v : -EINVAL;
411 else if (vtnr != (uint32_t) v)
413 } else if (tty_is_console(tty)) {
417 else if (s != m->vtconsole)
426 if (seat_can_multi_session(s)) {
435 if (!dbus_message_iter_next(&iter) ||
436 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
439 dbus_message_iter_get_basic(&iter, &display);
441 if (!dbus_message_iter_next(&iter) ||
442 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
445 dbus_message_iter_get_basic(&iter, &remote);
447 if (!dbus_message_iter_next(&iter) ||
448 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
451 dbus_message_iter_get_basic(&iter, &remote_user);
453 if (!dbus_message_iter_next(&iter) ||
454 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
457 dbus_message_iter_get_basic(&iter, &remote_host);
459 if (!dbus_message_iter_next(&iter) ||
460 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
461 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
464 r = bus_parse_strv_iter(&iter, &controllers);
468 if (strv_contains(controllers, "systemd") ||
469 !dbus_message_iter_next(&iter) ||
470 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
471 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) {
476 r = bus_parse_strv_iter(&iter, &reset_controllers);
480 if (strv_contains(reset_controllers, "systemd") ||
481 !dbus_message_iter_next(&iter) ||
482 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) {
487 dbus_message_iter_get_basic(&iter, &kill_processes);
489 r = manager_add_user_by_uid(m, uid, &user);
493 audit_session_from_pid(leader, &audit_id);
496 asprintf(&id, "%lu", (unsigned long) audit_id);
503 session = hashmap_get(m->sessions, id);
508 fifo_fd = session_create_fifo(session);
514 /* Session already exists, client is probably
515 * something like "su" which changes uid but
516 * is still the same audit session */
518 reply = dbus_message_new_method_return(message);
524 p = session_bus_path(session);
530 seat = session->seat ? session->seat->id : "";
531 vtnr = session->vtnr;
534 b = dbus_message_append_args(
536 DBUS_TYPE_STRING, &session->id,
537 DBUS_TYPE_OBJECT_PATH, &p,
538 DBUS_TYPE_STRING, &session->user->runtime_path,
539 DBUS_TYPE_UNIX_FD, &fifo_fd,
540 DBUS_TYPE_STRING, &seat,
541 DBUS_TYPE_UINT32, &vtnr,
542 DBUS_TYPE_BOOLEAN, &exists,
551 close_nointr_nofail(fifo_fd);
554 strv_free(controllers);
555 strv_free(reset_controllers);
565 if (asprintf(&id, "c%lu", ++m->session_counter) < 0) {
570 } while (hashmap_get(m->sessions, id));
573 r = manager_add_session(m, user, id, &session);
578 session->leader = leader;
579 session->audit_id = audit_id;
582 session->remote = remote;
583 session->controllers = controllers;
584 session->reset_controllers = reset_controllers;
585 session->kill_processes = kill_processes;
586 session->vtnr = vtnr;
588 controllers = reset_controllers = NULL;
591 session->tty = strdup(tty);
598 if (!isempty(display)) {
599 session->display = strdup(display);
600 if (!session->display) {
606 if (!isempty(remote_user)) {
607 session->remote_user = strdup(remote_user);
608 if (!session->remote_user) {
614 if (!isempty(remote_host)) {
615 session->remote_host = strdup(remote_host);
616 if (!session->remote_host) {
622 if (!isempty(service)) {
623 session->service = strdup(service);
624 if (!session->service) {
630 fifo_fd = session_create_fifo(session);
637 r = seat_attach_session(s, session);
642 r = session_start(session);
646 reply = dbus_message_new_method_return(message);
652 p = session_bus_path(session);
658 seat = s ? s->id : "";
660 b = dbus_message_append_args(
662 DBUS_TYPE_STRING, &session->id,
663 DBUS_TYPE_OBJECT_PATH, &p,
664 DBUS_TYPE_STRING, &session->user->runtime_path,
665 DBUS_TYPE_UNIX_FD, &fifo_fd,
666 DBUS_TYPE_STRING, &seat,
667 DBUS_TYPE_UINT32, &vtnr,
668 DBUS_TYPE_BOOLEAN, &exists,
677 close_nointr_nofail(fifo_fd);
683 strv_free(controllers);
684 strv_free(reset_controllers);
687 session_add_to_gc_queue(session);
690 user_add_to_gc_queue(user);
693 close_nointr_nofail(fifo_fd);
696 dbus_message_unref(reply);
701 static int bus_manager_inhibit(
703 DBusConnection *connection,
704 DBusMessage *message,
706 DBusMessage **_reply) {
710 const char *who, *why, *what, *mode;
716 DBusMessage *reply = NULL;
724 if (!dbus_message_get_args(
727 DBUS_TYPE_STRING, &what,
728 DBUS_TYPE_STRING, &who,
729 DBUS_TYPE_STRING, &why,
730 DBUS_TYPE_STRING, &mode,
731 DBUS_TYPE_INVALID)) {
736 w = inhibit_what_from_string(what);
742 mm = inhibit_mode_from_string(mode);
748 /* Delay is only supported for shutdown/sleep */
749 if (mm == INHIBIT_DELAY && (w & ~(INHIBIT_SHUTDOWN|INHIBIT_SLEEP))) {
754 /* Don't allow taking delay locks while we are already
755 * executing the operation. We shouldn't create the impression
756 * that the lock was successful if the machine is about to go
757 * down/suspend any moment. */
758 if (m->action_what & w) {
763 r = verify_polkit(connection, message,
764 w == INHIBIT_SHUTDOWN ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
765 w == INHIBIT_SLEEP ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep" : "org.freedesktop.login1.inhibit-delay-sleep") :
766 w == INHIBIT_IDLE ? "org.freedesktop.login1.inhibit-block-idle" :
767 w == INHIBIT_HANDLE_POWER_KEY ? "org.freedesktop.login1.inhibit-handle-power-key" :
768 w == INHIBIT_HANDLE_SUSPEND_KEY ? "org.freedesktop.login1.inhibit-handle-suspend-key" :
769 w == INHIBIT_HANDLE_HIBERNATE_KEY ? "org.freedesktop.login1.inhibit-handle-hibernate-key" :
770 "org.freedesktop.login1.inhibit-handle-lid-switch",
775 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
776 if (ul == (unsigned long) -1) {
781 pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
791 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
795 } while (hashmap_get(m->inhibitors, id));
797 r = manager_add_inhibitor(m, id, &i);
807 i->why = strdup(why);
808 i->who = strdup(who);
810 if (!i->why || !i->who) {
815 fifo_fd = inhibitor_create_fifo(i);
821 reply = dbus_message_new_method_return(message);
827 if (!dbus_message_append_args(
829 DBUS_TYPE_UNIX_FD, &fifo_fd,
830 DBUS_TYPE_INVALID)) {
835 close_nointr_nofail(fifo_fd);
847 close_nointr_nofail(fifo_fd);
850 dbus_message_unref(reply);
855 static int trigger_device(Manager *m, struct udev_device *d) {
856 struct udev_enumerate *e;
857 struct udev_list_entry *first, *item;
862 e = udev_enumerate_new(m->udev);
869 if (udev_enumerate_add_match_parent(e, d) < 0) {
875 if (udev_enumerate_scan_devices(e) < 0) {
880 first = udev_enumerate_get_list_entry(e);
881 udev_list_entry_foreach(item, first) {
885 p = udev_list_entry_get_name(item);
887 t = strappend(p, "/uevent");
893 write_one_line_file(t, "change");
901 udev_enumerate_unref(e);
906 static int attach_device(Manager *m, const char *seat, const char *sysfs) {
907 struct udev_device *d;
908 char *rule = NULL, *file = NULL;
909 const char *id_for_seat;
916 d = udev_device_new_from_syspath(m->udev, sysfs);
920 if (!udev_device_has_tag(d, "seat")) {
925 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
931 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
936 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
941 mkdir_p_label("/etc/udev/rules.d", 0755);
943 r = write_one_line_file_atomic_label(file, rule);
947 r = trigger_device(m, d);
954 udev_device_unref(d);
959 static int flush_devices(Manager *m) {
964 d = opendir("/etc/udev/rules.d");
967 log_warning("Failed to open /etc/udev/rules.d: %m");
971 while ((de = readdir(d))) {
973 if (!dirent_is_file(de))
976 if (!startswith(de->d_name, "72-seat-"))
979 if (!endswith(de->d_name, ".rules"))
982 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
983 log_warning("Failed to unlink %s: %m", de->d_name);
989 return trigger_device(m, NULL);
992 static int have_multiple_sessions(
1001 /* Check for other users' sessions. Greeter sessions do not
1002 * count, and non-login sessions do not count either. */
1003 HASHMAP_FOREACH(session, m->sessions, i)
1004 if (session->class == SESSION_USER &&
1005 (session->type == SESSION_TTY || session->type == SESSION_X11) &&
1006 session->user->uid != uid)
1012 static int bus_manager_log_shutdown(
1015 const char *unit_name) {
1022 if (w != INHIBIT_SHUTDOWN)
1025 if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
1026 p = "MESSAGE=System is powering down.";
1027 q = "SHUTDOWN=power-off";
1028 } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
1029 p = "MESSAGE=System is halting.";
1030 q = "SHUTDOWN=halt";
1031 } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
1032 p = "MESSAGE=System is rebooting.";
1033 q = "SHUTDOWN=reboot";
1034 } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
1035 p = "MESSAGE=System is rebooting with kexec.";
1036 q = "SHUTDOWN=kexec";
1038 p = "MESSAGE=System is shutting down.";
1042 return log_struct(LOG_NOTICE, MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
1047 static int execute_shutdown_or_sleep(
1050 const char *unit_name,
1053 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1054 const char *mode = "replace", *p;
1060 assert(w < _INHIBIT_WHAT_MAX);
1063 bus_manager_log_shutdown(m, w, unit_name);
1065 r = bus_method_call_with_reply(
1067 "org.freedesktop.systemd1",
1068 "/org/freedesktop/systemd1",
1069 "org.freedesktop.systemd1.Manager",
1073 DBUS_TYPE_STRING, &unit_name,
1074 DBUS_TYPE_STRING, &mode,
1079 if (!dbus_message_get_args(
1082 DBUS_TYPE_OBJECT_PATH, &p,
1090 m->action_unit = unit_name;
1091 free(m->action_job);
1098 static int delay_shutdown_or_sleep(
1101 const char *unit_name) {
1105 assert(w < _INHIBIT_WHAT_MAX);
1108 m->action_timestamp = now(CLOCK_MONOTONIC);
1109 m->action_unit = unit_name;
1115 static int bus_manager_can_shutdown_or_sleep(
1117 DBusConnection *connection,
1118 DBusMessage *message,
1121 const char *action_multiple_sessions,
1122 const char *action_ignore_inhibit,
1123 const char *sleep_type,
1124 const char *sleep_disk_type,
1126 DBusMessage **_reply) {
1128 bool multiple_sessions, challenge, blocked, b;
1130 DBusMessage *reply = NULL;
1138 assert(w <= _INHIBIT_WHAT_MAX);
1140 assert(action_multiple_sessions);
1141 assert(action_ignore_inhibit);
1146 r = can_sleep(sleep_type);
1156 if (sleep_disk_type) {
1157 r = can_sleep_disk(sleep_disk_type);
1167 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1168 if (ul == (unsigned long) -1)
1171 r = have_multiple_sessions(m, (uid_t) ul);
1175 multiple_sessions = r > 0;
1176 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1178 if (multiple_sessions) {
1179 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1186 result = "challenge";
1192 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1196 if (r > 0 && !result)
1198 else if (challenge && (!result || streq(result, "yes")))
1199 result = "challenge";
1204 if (!multiple_sessions && !blocked) {
1205 /* If neither inhibit nor multiple sessions
1206 * apply then just check the normal policy */
1208 r = verify_polkit(connection, message, action, false, &challenge, error);
1215 result = "challenge";
1221 reply = dbus_message_new_method_return(message);
1225 b = dbus_message_append_args(
1227 DBUS_TYPE_STRING, &result,
1230 dbus_message_unref(reply);
1238 static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
1239 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
1240 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
1241 [INHIBIT_SLEEP] = "PrepareForSleep"
1244 dbus_bool_t active = _active;
1245 _cleanup_dbus_message_unref_ DBusMessage *message = NULL;
1249 assert(w < _INHIBIT_WHAT_MAX);
1250 assert(signal_name[w]);
1252 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1256 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1257 !dbus_connection_send(m->bus, message, NULL))
1263 int bus_manager_shutdown_or_sleep_now_or_later(
1265 const char *unit_name,
1275 assert(w <= _INHIBIT_WHAT_MAX);
1276 assert(!m->action_job);
1278 /* Tell everybody to prepare for shutdown/sleep */
1279 send_prepare_for(m, w, true);
1282 m->inhibit_delay_max > 0 &&
1283 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0);
1286 /* Shutdown is delayed, keep in mind what we
1287 * want to do, and start a timeout */
1288 r = delay_shutdown_or_sleep(m, w, unit_name);
1290 /* Shutdown is not delayed, execute it
1292 r = execute_shutdown_or_sleep(m, w, unit_name, error);
1297 static int bus_manager_do_shutdown_or_sleep(
1299 DBusConnection *connection,
1300 DBusMessage *message,
1301 const char *unit_name,
1304 const char *action_multiple_sessions,
1305 const char *action_ignore_inhibit,
1306 const char *sleep_type,
1307 const char *sleep_disk_type,
1309 DBusMessage **_reply) {
1311 dbus_bool_t interactive;
1312 bool multiple_sessions, blocked;
1313 DBusMessage *reply = NULL;
1322 assert(w <= _INHIBIT_WHAT_MAX);
1324 assert(action_multiple_sessions);
1325 assert(action_ignore_inhibit);
1329 /* Don't allow multiple jobs being executed at the same time */
1333 if (!dbus_message_get_args(
1336 DBUS_TYPE_BOOLEAN, &interactive,
1341 r = can_sleep(sleep_type);
1349 if (sleep_disk_type) {
1350 r = can_sleep_disk(sleep_disk_type);
1358 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1359 if (ul == (unsigned long) -1)
1362 r = have_multiple_sessions(m, (uid_t) ul);
1366 multiple_sessions = r > 0;
1367 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1369 if (multiple_sessions) {
1370 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1376 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1381 if (!multiple_sessions && !blocked) {
1382 r = verify_polkit(connection, message, action, interactive, NULL, error);
1387 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
1391 reply = dbus_message_new_method_return(message);
1399 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_action, handle_action, HandleAction);
1401 static const BusProperty bus_login_manager_properties[] = {
1402 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_path), true },
1403 { "Controllers", bus_property_append_strv, "as", offsetof(Manager, controllers), true },
1404 { "ResetControllers", bus_property_append_strv, "as", offsetof(Manager, reset_controllers), true },
1405 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1406 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1407 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1408 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1409 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1410 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1411 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
1412 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1413 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1414 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
1415 { "HandlePowerKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_power_key) },
1416 { "HandleSuspendKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_suspend_key) },
1417 { "HandleHibernateKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_hibernate_key)},
1418 { "HandleLidSwitch", bus_manager_append_handle_action, "s", offsetof(Manager, handle_lid_switch) },
1419 { "IdleAction", bus_manager_append_handle_action, "s", offsetof(Manager, idle_action) },
1420 { "IdleActionUSec", bus_property_append_usec, "t", offsetof(Manager, idle_action_usec) },
1421 { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
1422 { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
1426 static DBusHandlerResult manager_message_handler(
1427 DBusConnection *connection,
1428 DBusMessage *message,
1431 Manager *m = userdata;
1434 DBusMessage *reply = NULL;
1441 dbus_error_init(&error);
1443 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1449 if (!dbus_message_get_args(
1452 DBUS_TYPE_STRING, &name,
1454 return bus_send_error_reply(connection, message, &error, -EINVAL);
1456 session = hashmap_get(m->sessions, name);
1458 return bus_send_error_reply(connection, message, &error, -ENOENT);
1460 reply = dbus_message_new_method_return(message);
1464 p = session_bus_path(session);
1468 b = dbus_message_append_args(
1470 DBUS_TYPE_OBJECT_PATH, &p,
1477 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1483 if (!dbus_message_get_args(
1486 DBUS_TYPE_UINT32, &pid,
1488 return bus_send_error_reply(connection, message, &error, -EINVAL);
1490 r = manager_get_session_by_pid(m, pid, &session);
1492 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1494 reply = dbus_message_new_method_return(message);
1498 p = session_bus_path(session);
1502 b = dbus_message_append_args(
1504 DBUS_TYPE_OBJECT_PATH, &p,
1511 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1517 if (!dbus_message_get_args(
1520 DBUS_TYPE_UINT32, &uid,
1522 return bus_send_error_reply(connection, message, &error, -EINVAL);
1524 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1526 return bus_send_error_reply(connection, message, &error, -ENOENT);
1528 reply = dbus_message_new_method_return(message);
1532 p = user_bus_path(user);
1536 b = dbus_message_append_args(
1538 DBUS_TYPE_OBJECT_PATH, &p,
1545 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1551 if (!dbus_message_get_args(
1554 DBUS_TYPE_STRING, &name,
1556 return bus_send_error_reply(connection, message, &error, -EINVAL);
1558 seat = hashmap_get(m->seats, name);
1560 return bus_send_error_reply(connection, message, &error, -ENOENT);
1562 reply = dbus_message_new_method_return(message);
1566 p = seat_bus_path(seat);
1570 b = dbus_message_append_args(
1572 DBUS_TYPE_OBJECT_PATH, &p,
1579 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1583 DBusMessageIter iter, sub;
1584 const char *empty = "";
1586 reply = dbus_message_new_method_return(message);
1590 dbus_message_iter_init_append(reply, &iter);
1592 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1595 HASHMAP_FOREACH(session, m->sessions, i) {
1596 DBusMessageIter sub2;
1599 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1602 uid = session->user->uid;
1604 p = session_bus_path(session);
1608 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1609 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1610 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1611 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1612 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1619 if (!dbus_message_iter_close_container(&sub, &sub2))
1623 if (!dbus_message_iter_close_container(&iter, &sub))
1626 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1630 DBusMessageIter iter, sub;
1632 reply = dbus_message_new_method_return(message);
1636 dbus_message_iter_init_append(reply, &iter);
1638 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1641 HASHMAP_FOREACH(user, m->users, i) {
1642 DBusMessageIter sub2;
1645 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1650 p = user_bus_path(user);
1654 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1655 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1656 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1663 if (!dbus_message_iter_close_container(&sub, &sub2))
1667 if (!dbus_message_iter_close_container(&iter, &sub))
1670 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1674 DBusMessageIter iter, sub;
1676 reply = dbus_message_new_method_return(message);
1680 dbus_message_iter_init_append(reply, &iter);
1682 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1685 HASHMAP_FOREACH(seat, m->seats, i) {
1686 DBusMessageIter sub2;
1688 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1691 p = seat_bus_path(seat);
1695 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1696 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1703 if (!dbus_message_iter_close_container(&sub, &sub2))
1707 if (!dbus_message_iter_close_container(&iter, &sub))
1710 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1711 Inhibitor *inhibitor;
1713 DBusMessageIter iter, sub;
1715 reply = dbus_message_new_method_return(message);
1719 dbus_message_iter_init_append(reply, &iter);
1721 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1724 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1725 DBusMessageIter sub2;
1726 dbus_uint32_t uid, pid;
1727 const char *what, *who, *why, *mode;
1729 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1732 what = strempty(inhibit_what_to_string(inhibitor->what));
1733 who = strempty(inhibitor->who);
1734 why = strempty(inhibitor->why);
1735 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
1736 uid = (dbus_uint32_t) inhibitor->uid;
1737 pid = (dbus_uint32_t) inhibitor->pid;
1739 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1740 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1741 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1742 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
1743 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1744 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1747 if (!dbus_message_iter_close_container(&sub, &sub2))
1751 if (!dbus_message_iter_close_container(&iter, &sub))
1754 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1756 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1759 return bus_send_error_reply(connection, message, &error, r);
1762 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1764 r = bus_manager_create_session(m, message, &reply);
1766 /* Don't delay the work on OOM here, since it might be
1767 * triggered by a low RLIMIT_NOFILE here (since we
1768 * send a dupped fd to the client), and we'd rather
1769 * see this fail quickly then be retried later */
1772 return bus_send_error_reply(connection, message, NULL, r);
1774 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1778 if (!dbus_message_get_args(
1781 DBUS_TYPE_STRING, &name,
1783 return bus_send_error_reply(connection, message, &error, -EINVAL);
1785 session = hashmap_get(m->sessions, name);
1787 return bus_send_error_reply(connection, message, &error, -ENOENT);
1789 /* We use the FIFO to detect stray sessions where the
1790 process invoking PAM dies abnormally. We need to make
1791 sure that that process is not killed if at the clean
1792 end of the session it closes the FIFO. Hence, with
1793 this call explicitly turn off the FIFO logic, so that
1794 the PAM code can finish clean up on its own */
1795 session_remove_fifo(session);
1797 reply = dbus_message_new_method_return(message);
1801 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1805 if (!dbus_message_get_args(
1808 DBUS_TYPE_STRING, &name,
1810 return bus_send_error_reply(connection, message, &error, -EINVAL);
1812 session = hashmap_get(m->sessions, name);
1814 return bus_send_error_reply(connection, message, &error, -ENOENT);
1816 r = session_activate(session);
1818 return bus_send_error_reply(connection, message, NULL, r);
1820 reply = dbus_message_new_method_return(message);
1824 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1825 const char *session_name, *seat_name;
1829 /* Same as ActivateSession() but refuses to work if
1830 * the seat doesn't match */
1832 if (!dbus_message_get_args(
1835 DBUS_TYPE_STRING, &session_name,
1836 DBUS_TYPE_STRING, &seat_name,
1838 return bus_send_error_reply(connection, message, &error, -EINVAL);
1840 session = hashmap_get(m->sessions, session_name);
1842 return bus_send_error_reply(connection, message, &error, -ENOENT);
1844 seat = hashmap_get(m->seats, seat_name);
1846 return bus_send_error_reply(connection, message, &error, -ENOENT);
1848 if (session->seat != seat)
1849 return bus_send_error_reply(connection, message, &error, -EINVAL);
1851 r = session_activate(session);
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", "LockSession") ||
1860 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1864 if (!dbus_message_get_args(
1867 DBUS_TYPE_STRING, &name,
1869 return bus_send_error_reply(connection, message, &error, -EINVAL);
1871 session = hashmap_get(m->sessions, name);
1873 return bus_send_error_reply(connection, message, NULL, -ENOENT);
1875 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1878 reply = dbus_message_new_method_return(message);
1882 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions") ||
1883 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSessions")) {
1885 r = session_send_lock_all(m, streq(dbus_message_get_member(message), "LockSessions"));
1887 bus_send_error_reply(connection, message, NULL, r);
1889 reply = dbus_message_new_method_return(message);
1893 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1900 if (!dbus_message_get_args(
1903 DBUS_TYPE_STRING, &name,
1904 DBUS_TYPE_STRING, &swho,
1905 DBUS_TYPE_INT32, &signo,
1907 return bus_send_error_reply(connection, message, &error, -EINVAL);
1912 who = kill_who_from_string(swho);
1914 return bus_send_error_reply(connection, message, &error, -EINVAL);
1917 if (signo <= 0 || signo >= _NSIG)
1918 return bus_send_error_reply(connection, message, &error, -EINVAL);
1920 session = hashmap_get(m->sessions, name);
1922 return bus_send_error_reply(connection, message, &error, -ENOENT);
1924 r = session_kill(session, who, signo);
1926 return bus_send_error_reply(connection, message, NULL, r);
1928 reply = dbus_message_new_method_return(message);
1932 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1937 if (!dbus_message_get_args(
1940 DBUS_TYPE_UINT32, &uid,
1941 DBUS_TYPE_INT32, &signo,
1943 return bus_send_error_reply(connection, message, &error, -EINVAL);
1945 if (signo <= 0 || signo >= _NSIG)
1946 return bus_send_error_reply(connection, message, &error, -EINVAL);
1948 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1950 return bus_send_error_reply(connection, message, &error, -ENOENT);
1952 r = user_kill(user, signo);
1954 return bus_send_error_reply(connection, message, NULL, r);
1956 reply = dbus_message_new_method_return(message);
1960 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1964 if (!dbus_message_get_args(
1967 DBUS_TYPE_STRING, &name,
1969 return bus_send_error_reply(connection, message, &error, -EINVAL);
1971 session = hashmap_get(m->sessions, name);
1973 return bus_send_error_reply(connection, message, &error, -ENOENT);
1975 r = session_stop(session);
1977 return bus_send_error_reply(connection, message, NULL, r);
1979 reply = dbus_message_new_method_return(message);
1983 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1987 if (!dbus_message_get_args(
1990 DBUS_TYPE_UINT32, &uid,
1992 return bus_send_error_reply(connection, message, &error, -EINVAL);
1994 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1996 return bus_send_error_reply(connection, message, &error, -ENOENT);
1998 r = user_stop(user);
2000 return bus_send_error_reply(connection, message, NULL, r);
2002 reply = dbus_message_new_method_return(message);
2006 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
2010 if (!dbus_message_get_args(
2013 DBUS_TYPE_STRING, &name,
2015 return bus_send_error_reply(connection, message, &error, -EINVAL);
2017 seat = hashmap_get(m->seats, name);
2019 return bus_send_error_reply(connection, message, &error, -ENOENT);
2021 r = seat_stop_sessions(seat);
2023 return bus_send_error_reply(connection, message, NULL, r);
2025 reply = dbus_message_new_method_return(message);
2029 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
2032 dbus_bool_t b, interactive;
2035 if (!dbus_message_get_args(
2038 DBUS_TYPE_UINT32, &uid,
2039 DBUS_TYPE_BOOLEAN, &b,
2040 DBUS_TYPE_BOOLEAN, &interactive,
2042 return bus_send_error_reply(connection, message, &error, -EINVAL);
2047 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
2049 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
2051 return bus_send_error_reply(connection, message, &error, r);
2053 mkdir_p_label("/var/lib/systemd", 0755);
2055 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
2057 return bus_send_error_reply(connection, message, &error, r);
2059 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
2070 return bus_send_error_reply(connection, message, &error, r);
2072 if (manager_add_user_by_uid(m, uid, &u) >= 0)
2081 if (r < 0 && errno != ENOENT)
2082 return bus_send_error_reply(connection, message, &error, -errno);
2084 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
2086 user_add_to_gc_queue(u);
2089 reply = dbus_message_new_method_return(message);
2093 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
2094 const char *sysfs, *seat;
2095 dbus_bool_t interactive;
2097 if (!dbus_message_get_args(
2100 DBUS_TYPE_STRING, &seat,
2101 DBUS_TYPE_STRING, &sysfs,
2102 DBUS_TYPE_BOOLEAN, &interactive,
2104 return bus_send_error_reply(connection, message, &error, -EINVAL);
2106 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
2107 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2109 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
2111 return bus_send_error_reply(connection, message, &error, r);
2113 r = attach_device(m, seat, sysfs);
2115 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2117 reply = dbus_message_new_method_return(message);
2122 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
2123 dbus_bool_t interactive;
2125 if (!dbus_message_get_args(
2128 DBUS_TYPE_BOOLEAN, &interactive,
2130 return bus_send_error_reply(connection, message, &error, -EINVAL);
2132 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
2134 return bus_send_error_reply(connection, message, &error, r);
2136 r = flush_devices(m);
2138 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2140 reply = dbus_message_new_method_return(message);
2144 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
2146 r = bus_manager_do_shutdown_or_sleep(
2147 m, connection, message,
2148 SPECIAL_POWEROFF_TARGET,
2150 "org.freedesktop.login1.power-off",
2151 "org.freedesktop.login1.power-off-multiple-sessions",
2152 "org.freedesktop.login1.power-off-ignore-inhibit",
2156 return bus_send_error_reply(connection, message, &error, r);
2157 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
2158 r = bus_manager_do_shutdown_or_sleep(
2159 m, connection, message,
2160 SPECIAL_REBOOT_TARGET,
2162 "org.freedesktop.login1.reboot",
2163 "org.freedesktop.login1.reboot-multiple-sessions",
2164 "org.freedesktop.login1.reboot-ignore-inhibit",
2168 return bus_send_error_reply(connection, message, &error, r);
2170 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2171 r = bus_manager_do_shutdown_or_sleep(
2172 m, connection, message,
2173 SPECIAL_SUSPEND_TARGET,
2175 "org.freedesktop.login1.suspend",
2176 "org.freedesktop.login1.suspend-multiple-sessions",
2177 "org.freedesktop.login1.suspend-ignore-inhibit",
2181 return bus_send_error_reply(connection, message, &error, r);
2182 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2183 r = bus_manager_do_shutdown_or_sleep(
2184 m, connection, message,
2185 SPECIAL_HIBERNATE_TARGET,
2187 "org.freedesktop.login1.hibernate",
2188 "org.freedesktop.login1.hibernate-multiple-sessions",
2189 "org.freedesktop.login1.hibernate-ignore-inhibit",
2193 return bus_send_error_reply(connection, message, &error, r);
2195 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "HybridSleep")) {
2196 r = bus_manager_do_shutdown_or_sleep(
2197 m, connection, message,
2198 SPECIAL_HYBRID_SLEEP_TARGET,
2200 "org.freedesktop.login1.hibernate",
2201 "org.freedesktop.login1.hibernate-multiple-sessions",
2202 "org.freedesktop.login1.hibernate-ignore-inhibit",
2206 return bus_send_error_reply(connection, message, &error, r);
2208 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2210 r = bus_manager_can_shutdown_or_sleep(
2211 m, connection, message,
2213 "org.freedesktop.login1.power-off",
2214 "org.freedesktop.login1.power-off-multiple-sessions",
2215 "org.freedesktop.login1.power-off-ignore-inhibit",
2219 return bus_send_error_reply(connection, message, &error, r);
2220 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2221 r = bus_manager_can_shutdown_or_sleep(
2222 m, connection, message,
2224 "org.freedesktop.login1.reboot",
2225 "org.freedesktop.login1.reboot-multiple-sessions",
2226 "org.freedesktop.login1.reboot-ignore-inhibit",
2230 return bus_send_error_reply(connection, message, &error, r);
2232 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2233 r = bus_manager_can_shutdown_or_sleep(
2234 m, connection, message,
2236 "org.freedesktop.login1.suspend",
2237 "org.freedesktop.login1.suspend-multiple-sessions",
2238 "org.freedesktop.login1.suspend-ignore-inhibit",
2242 return bus_send_error_reply(connection, message, &error, r);
2244 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2245 r = bus_manager_can_shutdown_or_sleep(
2246 m, connection, message,
2248 "org.freedesktop.login1.hibernate",
2249 "org.freedesktop.login1.hibernate-multiple-sessions",
2250 "org.freedesktop.login1.hibernate-ignore-inhibit",
2254 return bus_send_error_reply(connection, message, &error, r);
2256 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHybridSleep")) {
2257 r = bus_manager_can_shutdown_or_sleep(
2258 m, connection, message,
2260 "org.freedesktop.login1.hibernate",
2261 "org.freedesktop.login1.hibernate-multiple-sessions",
2262 "org.freedesktop.login1.hibernate-ignore-inhibit",
2266 return bus_send_error_reply(connection, message, &error, r);
2268 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2269 char *introspection = NULL;
2278 if (!(reply = dbus_message_new_method_return(message)))
2281 /* We roll our own introspection code here, instead of
2282 * relying on bus_default_message_handler() because we
2283 * need to generate our introspection string
2286 if (!(f = open_memstream(&introspection, &size)))
2289 fputs(INTROSPECTION_BEGIN, f);
2291 HASHMAP_FOREACH(seat, m->seats, i) {
2292 p = bus_path_escape(seat->id);
2295 fprintf(f, "<node name=\"seat/%s\"/>", p);
2300 HASHMAP_FOREACH(user, m->users, i)
2301 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2303 HASHMAP_FOREACH(session, m->sessions, i) {
2304 p = bus_path_escape(session->id);
2307 fprintf(f, "<node name=\"session/%s\"/>", p);
2312 fputs(INTROSPECTION_END, f);
2316 free(introspection);
2325 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2326 free(introspection);
2330 free(introspection);
2332 const BusBoundProperties bps[] = {
2333 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2336 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2340 if (!bus_maybe_send_reply(connection, message, reply))
2343 dbus_message_unref(reply);
2346 return DBUS_HANDLER_RESULT_HANDLED;
2350 dbus_message_unref(reply);
2352 dbus_error_free(&error);
2354 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2357 const DBusObjectPathVTable bus_manager_vtable = {
2358 .message_function = manager_message_handler
2361 DBusHandlerResult bus_message_filter(
2362 DBusConnection *connection,
2363 DBusMessage *message,
2366 Manager *m = userdata;
2373 dbus_error_init(&error);
2375 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
2378 if (!dbus_message_get_args(message, &error,
2379 DBUS_TYPE_STRING, &cgroup,
2381 log_error("Failed to parse Released message: %s", bus_error_message(&error));
2383 manager_cgroup_notify_empty(m, cgroup);
2385 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
2387 const char *path, *result, *unit;
2389 if (!dbus_message_get_args(message, &error,
2390 DBUS_TYPE_UINT32, &id,
2391 DBUS_TYPE_OBJECT_PATH, &path,
2392 DBUS_TYPE_STRING, &unit,
2393 DBUS_TYPE_STRING, &result,
2395 log_error("Failed to parse JobRemoved message: %s", bus_error_message(&error));
2397 else if (m->action_job && streq(m->action_job, path)) {
2399 log_info("Operation finished.");
2401 /* Tell people that they now may take a lock again */
2402 send_prepare_for(m, m->action_what, false);
2404 free(m->action_job);
2405 m->action_job = NULL;
2406 m->action_unit = NULL;
2411 dbus_error_free(&error);
2413 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2416 int manager_send_changed(Manager *manager, const char *properties) {
2422 m = bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties);
2426 if (!dbus_connection_send(manager->bus, m, NULL))
2433 dbus_message_unref(m);
2438 int manager_dispatch_delayed(Manager *manager) {
2444 if (!manager->action_unit || manager->action_job)
2447 /* Continue delay? */
2448 if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0)) {
2450 if (manager->action_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC))
2453 log_info("Delay lock is active but inhibitor timeout is reached.");
2456 /* Actually do the operation */
2457 dbus_error_init(&error);
2458 r = execute_shutdown_or_sleep(manager, manager->action_what, manager->action_unit, &error);
2460 log_warning("Failed to send delayed message: %s", bus_error_message_or_strerror(&error, -r));
2461 dbus_error_free(&error);
2463 manager->action_unit = NULL;
2464 manager->action_what = 0;