1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
28 #include "dbus-common.h"
31 #include "path-util.h"
34 #include "systemd/sd-id128.h"
35 #include "systemd/sd-messages.h"
37 #define BUS_MANAGER_INTERFACE \
38 " <interface name=\"org.freedesktop.login1.Manager\">\n" \
39 " <method name=\"GetSession\">\n" \
40 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
41 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
43 " <method name=\"GetSessionByPID\">\n" \
44 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
45 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
47 " <method name=\"GetUser\">\n" \
48 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
49 " <arg name=\"user\" type=\"o\" direction=\"out\"/>\n" \
51 " <method name=\"GetSeat\">\n" \
52 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
53 " <arg name=\"seat\" type=\"o\" direction=\"out\"/>\n" \
55 " <method name=\"ListSessions\">\n" \
56 " <arg name=\"sessions\" type=\"a(susso)\" direction=\"out\"/>\n" \
58 " <method name=\"ListUsers\">\n" \
59 " <arg name=\"users\" type=\"a(uso)\" direction=\"out\"/>\n" \
61 " <method name=\"ListSeats\">\n" \
62 " <arg name=\"seats\" type=\"a(so)\" direction=\"out\"/>\n" \
64 " <method name=\"CreateSession\">\n" \
65 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
66 " <arg name=\"leader\" type=\"u\" direction=\"in\"/>\n" \
67 " <arg name=\"sevice\" type=\"s\" direction=\"in\"/>\n" \
68 " <arg name=\"type\" type=\"s\" direction=\"in\"/>\n" \
69 " <arg name=\"class\" type=\"s\" direction=\"in\"/>\n" \
70 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
71 " <arg name=\"vtnr\" type=\"u\" direction=\"in\"/>\n" \
72 " <arg name=\"tty\" type=\"s\" direction=\"in\"/>\n" \
73 " <arg name=\"display\" type=\"s\" direction=\"in\"/>\n" \
74 " <arg name=\"remote\" type=\"b\" direction=\"in\"/>\n" \
75 " <arg name=\"remote_user\" type=\"s\" direction=\"in\"/>\n" \
76 " <arg name=\"remote_host\" type=\"s\" direction=\"in\"/>\n" \
77 " <arg name=\"controllers\" type=\"as\" direction=\"in\"/>\n" \
78 " <arg name=\"reset_controllers\" type=\"as\" direction=\"in\"/>\n" \
79 " <arg name=\"kill_processes\" type=\"b\" direction=\"in\"/>\n" \
80 " <arg name=\"id\" type=\"s\" direction=\"out\"/>\n" \
81 " <arg name=\"path\" type=\"o\" direction=\"out\"/>\n" \
82 " <arg name=\"runtime_path\" type=\"o\" direction=\"out\"/>\n" \
83 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
84 " <arg name=\"seat\" type=\"s\" direction=\"out\"/>\n" \
85 " <arg name=\"vtnr\" type=\"u\" direction=\"out\"/>\n" \
86 " <arg name=\"existing\" type=\"b\" direction=\"out\"/>\n" \
88 " <method name=\"ReleaseSession\">\n" \
89 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
91 " <method name=\"ActivateSession\">\n" \
92 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
94 " <method name=\"ActivateSessionOnSeat\">\n" \
95 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
96 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
98 " <method name=\"LockSession\">\n" \
99 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
101 " <method name=\"UnlockSession\">\n" \
102 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
104 " <method name=\"LockSessions\"/>\n" \
105 " <method name=\"KillSession\">\n" \
106 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
107 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
108 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
110 " <method name=\"KillUser\">\n" \
111 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
112 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
114 " <method name=\"TerminateSession\">\n" \
115 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
117 " <method name=\"TerminateUser\">\n" \
118 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
120 " <method name=\"TerminateSeat\">\n" \
121 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
123 " <method name=\"SetUserLinger\">\n" \
124 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
125 " <arg name=\"b\" type=\"b\" direction=\"in\"/>\n" \
126 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
128 " <method name=\"AttachDevice\">\n" \
129 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
130 " <arg name=\"sysfs\" type=\"s\" direction=\"in\"/>\n" \
131 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
133 " <method name=\"FlushDevices\">\n" \
134 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
136 " <method name=\"PowerOff\">\n" \
137 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
139 " <method name=\"Reboot\">\n" \
140 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
142 " <method name=\"Suspend\">\n" \
143 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
145 " <method name=\"Hibernate\">\n" \
146 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
148 " <method name=\"HybridSleep\">\n" \
149 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
151 " <method name=\"CanPowerOff\">\n" \
152 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
154 " <method name=\"CanReboot\">\n" \
155 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
157 " <method name=\"CanSuspend\">\n" \
158 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
160 " <method name=\"CanHibernate\">\n" \
161 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
163 " <method name=\"CanHybridSleep\">\n" \
164 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
166 " <method name=\"Inhibit\">\n" \
167 " <arg name=\"what\" type=\"s\" direction=\"in\"/>\n" \
168 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
169 " <arg name=\"why\" type=\"s\" direction=\"in\"/>\n" \
170 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
171 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
173 " <method name=\"ListInhibitors\">\n" \
174 " <arg name=\"inhibitors\" type=\"a(ssssuu)\" direction=\"out\"/>\n" \
176 " <signal name=\"SessionNew\">\n" \
177 " <arg name=\"id\" type=\"s\"/>\n" \
178 " <arg name=\"path\" type=\"o\"/>\n" \
180 " <signal name=\"SessionRemoved\">\n" \
181 " <arg name=\"id\" type=\"s\"/>\n" \
182 " <arg name=\"path\" type=\"o\"/>\n" \
184 " <signal name=\"UserNew\">\n" \
185 " <arg name=\"uid\" type=\"u\"/>\n" \
186 " <arg name=\"path\" type=\"o\"/>\n" \
188 " <signal name=\"UserRemoved\">\n" \
189 " <arg name=\"uid\" type=\"u\"/>\n" \
190 " <arg name=\"path\" type=\"o\"/>\n" \
192 " <signal name=\"SeatNew\">\n" \
193 " <arg name=\"id\" type=\"s\"/>\n" \
194 " <arg name=\"path\" type=\"o\"/>\n" \
196 " <signal name=\"SeatRemoved\">\n" \
197 " <arg name=\"id\" type=\"s\"/>\n" \
198 " <arg name=\"path\" type=\"o\"/>\n" \
200 " <signal name=\"PrepareForShutdown\">\n" \
201 " <arg name=\"active\" type=\"b\"/>\n" \
203 " <signal name=\"PrepareForSleep\">\n" \
204 " <arg name=\"active\" type=\"b\"/>\n" \
206 " <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
207 " <property name=\"Controllers\" type=\"as\" access=\"read\"/>\n" \
208 " <property name=\"ResetControllers\" type=\"as\" access=\"read\"/>\n" \
209 " <property name=\"NAutoVTs\" type=\"u\" access=\"read\"/>\n" \
210 " <property name=\"KillOnlyUsers\" type=\"as\" access=\"read\"/>\n" \
211 " <property name=\"KillExcludeUsers\" type=\"as\" access=\"read\"/>\n" \
212 " <property name=\"KillUserProcesses\" type=\"b\" access=\"read\"/>\n" \
213 " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
214 " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
215 " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
216 " <property name=\"BlockInhibited\" type=\"s\" access=\"read\"/>\n" \
217 " <property name=\"DelayInhibited\" type=\"s\" access=\"read\"/>\n" \
218 " <property name=\"InhibitDelayMaxUSec\" type=\"t\" access=\"read\"/>\n" \
219 " <property name=\"HandlePowerKey\" type=\"s\" access=\"read\"/>\n" \
220 " <property name=\"HandleSuspendKey\" type=\"s\" access=\"read\"/>\n" \
221 " <property name=\"HandleHibernateKey\" type=\"s\" access=\"read\"/>\n" \
222 " <property name=\"HandleLidSwitch\" type=\"s\" access=\"read\"/>\n" \
223 " <property name=\"PreparingForShutdown\" type=\"b\" access=\"read\"/>\n" \
224 " <property name=\"PreparingForSleep\" type=\"b\" access=\"read\"/>\n" \
227 #define INTROSPECTION_BEGIN \
228 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
230 BUS_MANAGER_INTERFACE \
231 BUS_PROPERTIES_INTERFACE \
233 BUS_INTROSPECTABLE_INTERFACE
235 #define INTROSPECTION_END \
238 #define INTERFACES_LIST \
239 BUS_GENERIC_INTERFACES_LIST \
240 "org.freedesktop.login1.Manager\0"
242 static int bus_manager_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
250 b = manager_get_idle_hint(m, NULL) > 0;
251 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
257 static int bus_manager_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
266 manager_get_idle_hint(m, &t);
267 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
269 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
275 static int bus_manager_append_inhibited(DBusMessageIter *i, const char *property, void *data) {
280 w = manager_inhibit_what(m, streq(property, "BlockInhibited") ? INHIBIT_BLOCK : INHIBIT_DELAY);
281 p = inhibit_what_to_string(w);
283 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &p))
289 static int bus_manager_append_preparing(DBusMessageIter *i, const char *property, void *data) {
296 if (streq(property, "PreparingForShutdown"))
297 b = !!(m->delayed_what & INHIBIT_SHUTDOWN);
299 b = !!(m->delayed_what & INHIBIT_SLEEP);
301 dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b);
305 static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMessage **_reply) {
306 Session *session = NULL;
308 const char *type, *class, *seat, *tty, *display, *remote_user, *remote_host, *service;
309 uint32_t uid, leader, audit_id = 0;
310 dbus_bool_t remote, kill_processes, exists;
311 char **controllers = NULL, **reset_controllers = NULL;
315 DBusMessageIter iter;
320 DBusMessage *reply = NULL;
327 if (!dbus_message_iter_init(message, &iter) ||
328 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
331 dbus_message_iter_get_basic(&iter, &uid);
333 if (!dbus_message_iter_next(&iter) ||
334 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
337 dbus_message_iter_get_basic(&iter, &leader);
340 !dbus_message_iter_next(&iter) ||
341 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
344 dbus_message_iter_get_basic(&iter, &service);
346 if (!dbus_message_iter_next(&iter) ||
347 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
350 dbus_message_iter_get_basic(&iter, &type);
351 t = session_type_from_string(type);
354 !dbus_message_iter_next(&iter) ||
355 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
358 dbus_message_iter_get_basic(&iter, &class);
362 c = session_class_from_string(class);
365 !dbus_message_iter_next(&iter) ||
366 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
369 dbus_message_iter_get_basic(&iter, &seat);
374 s = hashmap_get(m->seats, seat);
379 if (!dbus_message_iter_next(&iter) ||
380 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
383 dbus_message_iter_get_basic(&iter, &vtnr);
385 if (!dbus_message_iter_next(&iter) ||
386 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
389 dbus_message_iter_get_basic(&iter, &tty);
391 if (tty_is_vc(tty)) {
396 else if (s != m->vtconsole)
399 v = vtnr_from_tty(tty);
402 return v < 0 ? v : -EINVAL;
406 else if (vtnr != (uint32_t) v)
408 } else if (tty_is_console(tty)) {
412 else if (s != m->vtconsole)
421 if (seat_can_multi_session(s)) {
430 if (!dbus_message_iter_next(&iter) ||
431 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
434 dbus_message_iter_get_basic(&iter, &display);
436 if (!dbus_message_iter_next(&iter) ||
437 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
440 dbus_message_iter_get_basic(&iter, &remote);
442 if (!dbus_message_iter_next(&iter) ||
443 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
446 dbus_message_iter_get_basic(&iter, &remote_user);
448 if (!dbus_message_iter_next(&iter) ||
449 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
452 dbus_message_iter_get_basic(&iter, &remote_host);
454 if (!dbus_message_iter_next(&iter) ||
455 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
456 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
459 r = bus_parse_strv_iter(&iter, &controllers);
463 if (strv_contains(controllers, "systemd") ||
464 !dbus_message_iter_next(&iter) ||
465 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
466 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) {
471 r = bus_parse_strv_iter(&iter, &reset_controllers);
475 if (strv_contains(reset_controllers, "systemd") ||
476 !dbus_message_iter_next(&iter) ||
477 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) {
482 dbus_message_iter_get_basic(&iter, &kill_processes);
484 r = manager_add_user_by_uid(m, uid, &user);
488 audit_session_from_pid(leader, &audit_id);
491 asprintf(&id, "%lu", (unsigned long) audit_id);
498 session = hashmap_get(m->sessions, id);
503 fifo_fd = session_create_fifo(session);
509 /* Session already exists, client is probably
510 * something like "su" which changes uid but
511 * is still the same audit session */
513 reply = dbus_message_new_method_return(message);
519 p = session_bus_path(session);
525 seat = session->seat ? session->seat->id : "";
526 vtnr = session->vtnr;
529 b = dbus_message_append_args(
531 DBUS_TYPE_STRING, &session->id,
532 DBUS_TYPE_OBJECT_PATH, &p,
533 DBUS_TYPE_STRING, &session->user->runtime_path,
534 DBUS_TYPE_UNIX_FD, &fifo_fd,
535 DBUS_TYPE_STRING, &seat,
536 DBUS_TYPE_UINT32, &vtnr,
537 DBUS_TYPE_BOOLEAN, &exists,
546 close_nointr_nofail(fifo_fd);
549 strv_free(controllers);
550 strv_free(reset_controllers);
560 if (asprintf(&id, "c%lu", ++m->session_counter) < 0) {
565 } while (hashmap_get(m->sessions, id));
568 r = manager_add_session(m, user, id, &session);
573 session->leader = leader;
574 session->audit_id = audit_id;
577 session->remote = remote;
578 session->controllers = controllers;
579 session->reset_controllers = reset_controllers;
580 session->kill_processes = kill_processes;
581 session->vtnr = vtnr;
583 controllers = reset_controllers = NULL;
586 session->tty = strdup(tty);
593 if (!isempty(display)) {
594 session->display = strdup(display);
595 if (!session->display) {
601 if (!isempty(remote_user)) {
602 session->remote_user = strdup(remote_user);
603 if (!session->remote_user) {
609 if (!isempty(remote_host)) {
610 session->remote_host = strdup(remote_host);
611 if (!session->remote_host) {
617 if (!isempty(service)) {
618 session->service = strdup(service);
619 if (!session->service) {
625 fifo_fd = session_create_fifo(session);
632 r = seat_attach_session(s, session);
637 r = session_start(session);
641 reply = dbus_message_new_method_return(message);
647 p = session_bus_path(session);
653 seat = s ? s->id : "";
655 b = dbus_message_append_args(
657 DBUS_TYPE_STRING, &session->id,
658 DBUS_TYPE_OBJECT_PATH, &p,
659 DBUS_TYPE_STRING, &session->user->runtime_path,
660 DBUS_TYPE_UNIX_FD, &fifo_fd,
661 DBUS_TYPE_STRING, &seat,
662 DBUS_TYPE_UINT32, &vtnr,
663 DBUS_TYPE_BOOLEAN, &exists,
672 close_nointr_nofail(fifo_fd);
678 strv_free(controllers);
679 strv_free(reset_controllers);
682 session_add_to_gc_queue(session);
685 user_add_to_gc_queue(user);
688 close_nointr_nofail(fifo_fd);
691 dbus_message_unref(reply);
696 static int bus_manager_inhibit(Manager *m, DBusConnection *connection, DBusMessage *message, DBusError *error, DBusMessage **_reply) {
699 const char *who, *why, *what, *mode;
705 DBusMessage *reply = NULL;
713 if (!dbus_message_get_args(
716 DBUS_TYPE_STRING, &what,
717 DBUS_TYPE_STRING, &who,
718 DBUS_TYPE_STRING, &why,
719 DBUS_TYPE_STRING, &mode,
720 DBUS_TYPE_INVALID)) {
725 w = inhibit_what_from_string(what);
731 mm = inhibit_mode_from_string(mode);
737 /* Delay is only supported for shutdown/sleep */
738 if (mm == INHIBIT_DELAY && (w & ~(INHIBIT_SHUTDOWN|INHIBIT_SLEEP))) {
743 r = verify_polkit(connection, message,
744 w == INHIBIT_SHUTDOWN ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
745 w == INHIBIT_SLEEP ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep" : "org.freedesktop.login1.inhibit-delay-sleep") :
746 w == INHIBIT_IDLE ? "org.freedesktop.login1.inhibit-block-idle" :
747 w == INHIBIT_HANDLE_POWER_KEY ? "org.freedesktop.login1.inhibit-handle-power-key" :
748 w == INHIBIT_HANDLE_SUSPEND_KEY ? "org.freedesktop.login1.inhibit-handle-suspend-key" :
749 w == INHIBIT_HANDLE_HIBERNATE_KEY ? "org.freedesktop.login1.inhibit-handle-hibernate-key" :
750 "org.freedesktop.login1.inhibit-handle-lid-switch",
755 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
756 if (ul == (unsigned long) -1) {
761 pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
771 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
775 } while (hashmap_get(m->inhibitors, id));
777 r = manager_add_inhibitor(m, id, &i);
787 i->why = strdup(why);
788 i->who = strdup(who);
790 if (!i->why || !i->who) {
795 fifo_fd = inhibitor_create_fifo(i);
801 reply = dbus_message_new_method_return(message);
807 if (!dbus_message_append_args(
809 DBUS_TYPE_UNIX_FD, &fifo_fd,
810 DBUS_TYPE_INVALID)) {
815 close_nointr_nofail(fifo_fd);
827 close_nointr_nofail(fifo_fd);
830 dbus_message_unref(reply);
835 static int trigger_device(Manager *m, struct udev_device *d) {
836 struct udev_enumerate *e;
837 struct udev_list_entry *first, *item;
842 e = udev_enumerate_new(m->udev);
849 if (udev_enumerate_add_match_parent(e, d) < 0) {
855 if (udev_enumerate_scan_devices(e) < 0) {
860 first = udev_enumerate_get_list_entry(e);
861 udev_list_entry_foreach(item, first) {
865 p = udev_list_entry_get_name(item);
867 t = strappend(p, "/uevent");
873 write_one_line_file(t, "change");
881 udev_enumerate_unref(e);
886 static int attach_device(Manager *m, const char *seat, const char *sysfs) {
887 struct udev_device *d;
888 char *rule = NULL, *file = NULL;
889 const char *id_for_seat;
896 d = udev_device_new_from_syspath(m->udev, sysfs);
900 if (!udev_device_has_tag(d, "seat")) {
905 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
911 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
916 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
921 mkdir_p_label("/etc/udev/rules.d", 0755);
922 r = write_one_line_file_atomic(file, rule);
926 r = trigger_device(m, d);
933 udev_device_unref(d);
938 static int flush_devices(Manager *m) {
943 d = opendir("/etc/udev/rules.d");
946 log_warning("Failed to open /etc/udev/rules.d: %m");
950 while ((de = readdir(d))) {
952 if (!dirent_is_file(de))
955 if (!startswith(de->d_name, "72-seat-"))
958 if (!endswith(de->d_name, ".rules"))
961 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
962 log_warning("Failed to unlink %s: %m", de->d_name);
968 return trigger_device(m, NULL);
971 static int have_multiple_sessions(
980 /* Check for other users' sessions. Greeter sessions do not count. */
981 HASHMAP_FOREACH(session, m->sessions, i)
982 if (session->class == SESSION_USER && session->user->uid != uid)
988 static int send_start_unit(DBusConnection *connection, const char *unit_name, DBusError *error) {
989 const char *mode = "replace";
993 return bus_method_call_with_reply (
995 "org.freedesktop.systemd1",
996 "/org/freedesktop/systemd1",
997 "org.freedesktop.systemd1.Manager",
1001 DBUS_TYPE_STRING, &unit_name,
1002 DBUS_TYPE_STRING, &mode,
1006 static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
1007 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
1008 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
1009 [INHIBIT_SLEEP] = "PrepareForSleep"
1012 dbus_bool_t active = _active;
1013 DBusMessage *message;
1018 assert(w < _INHIBIT_WHAT_MAX);
1019 assert(signal_name[w]);
1021 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1025 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1026 !dbus_connection_send(m->bus, message, NULL))
1029 dbus_message_unref(message);
1033 static int delay_shutdown_or_sleep(Manager *m, InhibitWhat w, const char *unit_name) {
1036 assert(w < _INHIBIT_WHAT_MAX);
1038 /* Tell everybody to prepare for shutdown/sleep */
1039 send_prepare_for(m, w, true);
1041 /* Update timestamp for timeout */
1042 if (!m->delayed_unit)
1043 m->delayed_timestamp = now(CLOCK_MONOTONIC);
1045 /* Remember what we want to do, possibly overriding what kind
1046 * of unit we previously queued. */
1047 m->delayed_unit = unit_name;
1048 m->delayed_what = w;
1053 static int bus_manager_can_shutdown_or_sleep(
1055 DBusConnection *connection,
1056 DBusMessage *message,
1059 const char *action_multiple_sessions,
1060 const char *action_ignore_inhibit,
1061 const char *sleep_type,
1062 const char *sleep_disk_type,
1064 DBusMessage **_reply) {
1066 bool multiple_sessions, challenge, blocked, b;
1068 DBusMessage *reply = NULL;
1076 assert(w <= _INHIBIT_WHAT_MAX);
1078 assert(action_multiple_sessions);
1079 assert(action_ignore_inhibit);
1084 r = can_sleep(sleep_type);
1094 if (sleep_disk_type) {
1095 r = can_sleep_disk(sleep_disk_type);
1105 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1106 if (ul == (unsigned long) -1)
1109 r = have_multiple_sessions(m, (uid_t) ul);
1113 multiple_sessions = r > 0;
1114 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1116 if (multiple_sessions) {
1117 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1124 result = "challenge";
1130 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1134 if (r > 0 && !result)
1136 else if (challenge && (!result || streq(result, "yes")))
1137 result = "challenge";
1142 if (!multiple_sessions && !blocked) {
1143 /* If neither inhibit nor multiple sessions
1144 * apply then just check the normal policy */
1146 r = verify_polkit(connection, message, action, false, &challenge, error);
1153 result = "challenge";
1159 reply = dbus_message_new_method_return(message);
1163 b = dbus_message_append_args(
1165 DBUS_TYPE_STRING, &result,
1168 dbus_message_unref(reply);
1176 static int bus_manager_log_shutdown(
1179 const char *unit_name) {
1186 if (w != INHIBIT_SHUTDOWN)
1189 if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
1190 p = "MESSAGE=System is powering down.";
1191 q = "SHUTDOWN=power-off";
1192 } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
1193 p = "MESSAGE=System is halting.";
1194 q = "SHUTDOWN=halt";
1195 } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
1196 p = "MESSAGE=System is rebooting.";
1197 q = "SHUTDOWN=reboot";
1198 } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
1199 p = "MESSAGE=System is rebooting with kexec.";
1200 q = "SHUTDOWN=kexec";
1202 p = "MESSAGE=System is shutting down.";
1206 return log_struct(LOG_NOTICE, MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
1211 int bus_manager_shutdown_or_sleep_now_or_later(
1213 const char *unit_name,
1223 assert(w <= _INHIBIT_WHAT_MAX);
1226 m->inhibit_delay_max > 0 &&
1227 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0);
1230 /* Shutdown is delayed, keep in mind what we
1231 * want to do, and start a timeout */
1232 r = delay_shutdown_or_sleep(m, w, unit_name);
1234 bus_manager_log_shutdown(m, w, unit_name);
1236 /* Shutdown is not delayed, execute it
1238 r = send_start_unit(m->bus, unit_name, error);
1244 static int bus_manager_do_shutdown_or_sleep(
1246 DBusConnection *connection,
1247 DBusMessage *message,
1248 const char *unit_name,
1251 const char *action_multiple_sessions,
1252 const char *action_ignore_inhibit,
1253 const char *sleep_type,
1254 const char *sleep_disk_type,
1256 DBusMessage **_reply) {
1258 dbus_bool_t interactive;
1259 bool multiple_sessions, blocked;
1260 DBusMessage *reply = NULL;
1269 assert(w <= _INHIBIT_WHAT_MAX);
1271 assert(action_multiple_sessions);
1272 assert(action_ignore_inhibit);
1276 if (!dbus_message_get_args(
1279 DBUS_TYPE_BOOLEAN, &interactive,
1284 r = can_sleep(sleep_type);
1292 if (sleep_disk_type) {
1293 r = can_sleep_disk(sleep_disk_type);
1301 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1302 if (ul == (unsigned long) -1)
1305 r = have_multiple_sessions(m, (uid_t) ul);
1309 multiple_sessions = r > 0;
1310 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1312 if (multiple_sessions) {
1313 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1319 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1324 if (!multiple_sessions && !blocked) {
1325 r = verify_polkit(connection, message, action, interactive, NULL, error);
1330 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
1334 reply = dbus_message_new_method_return(message);
1342 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_button, handle_button, HandleButton);
1344 static const BusProperty bus_login_manager_properties[] = {
1345 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_path), true },
1346 { "Controllers", bus_property_append_strv, "as", offsetof(Manager, controllers), true },
1347 { "ResetControllers", bus_property_append_strv, "as", offsetof(Manager, reset_controllers), true },
1348 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1349 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1350 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1351 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1352 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1353 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1354 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
1355 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1356 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1357 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
1358 { "HandlePowerKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_power_key) },
1359 { "HandleSuspendKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_suspend_key) },
1360 { "HandleHibernateKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_hibernate_key)},
1361 { "HandleLidSwitch", bus_manager_append_handle_button, "s", offsetof(Manager, handle_lid_switch) },
1362 { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
1363 { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
1367 static DBusHandlerResult manager_message_handler(
1368 DBusConnection *connection,
1369 DBusMessage *message,
1372 Manager *m = userdata;
1375 DBusMessage *reply = NULL;
1382 dbus_error_init(&error);
1384 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1390 if (!dbus_message_get_args(
1393 DBUS_TYPE_STRING, &name,
1395 return bus_send_error_reply(connection, message, &error, -EINVAL);
1397 session = hashmap_get(m->sessions, name);
1399 return bus_send_error_reply(connection, message, &error, -ENOENT);
1401 reply = dbus_message_new_method_return(message);
1405 p = session_bus_path(session);
1409 b = dbus_message_append_args(
1411 DBUS_TYPE_OBJECT_PATH, &p,
1418 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1424 if (!dbus_message_get_args(
1427 DBUS_TYPE_UINT32, &pid,
1429 return bus_send_error_reply(connection, message, &error, -EINVAL);
1431 r = manager_get_session_by_pid(m, pid, &session);
1433 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1435 reply = dbus_message_new_method_return(message);
1439 p = session_bus_path(session);
1443 b = dbus_message_append_args(
1445 DBUS_TYPE_OBJECT_PATH, &p,
1452 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1458 if (!dbus_message_get_args(
1461 DBUS_TYPE_UINT32, &uid,
1463 return bus_send_error_reply(connection, message, &error, -EINVAL);
1465 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1467 return bus_send_error_reply(connection, message, &error, -ENOENT);
1469 reply = dbus_message_new_method_return(message);
1473 p = user_bus_path(user);
1477 b = dbus_message_append_args(
1479 DBUS_TYPE_OBJECT_PATH, &p,
1486 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1492 if (!dbus_message_get_args(
1495 DBUS_TYPE_STRING, &name,
1497 return bus_send_error_reply(connection, message, &error, -EINVAL);
1499 seat = hashmap_get(m->seats, name);
1501 return bus_send_error_reply(connection, message, &error, -ENOENT);
1503 reply = dbus_message_new_method_return(message);
1507 p = seat_bus_path(seat);
1511 b = dbus_message_append_args(
1513 DBUS_TYPE_OBJECT_PATH, &p,
1520 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1524 DBusMessageIter iter, sub;
1525 const char *empty = "";
1527 reply = dbus_message_new_method_return(message);
1531 dbus_message_iter_init_append(reply, &iter);
1533 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1536 HASHMAP_FOREACH(session, m->sessions, i) {
1537 DBusMessageIter sub2;
1540 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1543 uid = session->user->uid;
1545 p = session_bus_path(session);
1549 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1550 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1551 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1552 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1553 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1560 if (!dbus_message_iter_close_container(&sub, &sub2))
1564 if (!dbus_message_iter_close_container(&iter, &sub))
1567 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1571 DBusMessageIter iter, sub;
1573 reply = dbus_message_new_method_return(message);
1577 dbus_message_iter_init_append(reply, &iter);
1579 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1582 HASHMAP_FOREACH(user, m->users, i) {
1583 DBusMessageIter sub2;
1586 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1591 p = user_bus_path(user);
1595 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1596 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1597 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1604 if (!dbus_message_iter_close_container(&sub, &sub2))
1608 if (!dbus_message_iter_close_container(&iter, &sub))
1611 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1615 DBusMessageIter iter, sub;
1617 reply = dbus_message_new_method_return(message);
1621 dbus_message_iter_init_append(reply, &iter);
1623 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1626 HASHMAP_FOREACH(seat, m->seats, i) {
1627 DBusMessageIter sub2;
1629 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1632 p = seat_bus_path(seat);
1636 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1637 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1644 if (!dbus_message_iter_close_container(&sub, &sub2))
1648 if (!dbus_message_iter_close_container(&iter, &sub))
1651 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1652 Inhibitor *inhibitor;
1654 DBusMessageIter iter, sub;
1656 reply = dbus_message_new_method_return(message);
1660 dbus_message_iter_init_append(reply, &iter);
1662 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1665 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1666 DBusMessageIter sub2;
1667 dbus_uint32_t uid, pid;
1668 const char *what, *who, *why, *mode;
1670 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1673 what = strempty(inhibit_what_to_string(inhibitor->what));
1674 who = strempty(inhibitor->who);
1675 why = strempty(inhibitor->why);
1676 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
1677 uid = (dbus_uint32_t) inhibitor->uid;
1678 pid = (dbus_uint32_t) inhibitor->pid;
1680 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1681 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1682 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1683 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
1684 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1685 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1688 if (!dbus_message_iter_close_container(&sub, &sub2))
1692 if (!dbus_message_iter_close_container(&iter, &sub))
1695 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1697 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1700 return bus_send_error_reply(connection, message, &error, r);
1703 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1705 r = bus_manager_create_session(m, message, &reply);
1707 /* Don't delay the work on OOM here, since it might be
1708 * triggered by a low RLIMIT_NOFILE here (since we
1709 * send a dupped fd to the client), and we'd rather
1710 * see this fail quickly then be retried later */
1713 return bus_send_error_reply(connection, message, NULL, r);
1715 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1719 if (!dbus_message_get_args(
1722 DBUS_TYPE_STRING, &name,
1724 return bus_send_error_reply(connection, message, &error, -EINVAL);
1726 session = hashmap_get(m->sessions, name);
1728 return bus_send_error_reply(connection, message, &error, -ENOENT);
1730 /* We use the FIFO to detect stray sessions where the
1731 process invoking PAM dies abnormally. We need to make
1732 sure that that process is not killed if at the clean
1733 end of the session it closes the FIFO. Hence, with
1734 this call explicitly turn off the FIFO logic, so that
1735 the PAM code can finish clean up on its own */
1736 session_remove_fifo(session);
1738 reply = dbus_message_new_method_return(message);
1742 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1746 if (!dbus_message_get_args(
1749 DBUS_TYPE_STRING, &name,
1751 return bus_send_error_reply(connection, message, &error, -EINVAL);
1753 session = hashmap_get(m->sessions, name);
1755 return bus_send_error_reply(connection, message, &error, -ENOENT);
1757 r = session_activate(session);
1759 return bus_send_error_reply(connection, message, NULL, r);
1761 reply = dbus_message_new_method_return(message);
1765 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1766 const char *session_name, *seat_name;
1770 /* Same as ActivateSession() but refuses to work if
1771 * the seat doesn't match */
1773 if (!dbus_message_get_args(
1776 DBUS_TYPE_STRING, &session_name,
1777 DBUS_TYPE_STRING, &seat_name,
1779 return bus_send_error_reply(connection, message, &error, -EINVAL);
1781 session = hashmap_get(m->sessions, session_name);
1783 return bus_send_error_reply(connection, message, &error, -ENOENT);
1785 seat = hashmap_get(m->seats, seat_name);
1787 return bus_send_error_reply(connection, message, &error, -ENOENT);
1789 if (session->seat != seat)
1790 return bus_send_error_reply(connection, message, &error, -EINVAL);
1792 r = session_activate(session);
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", "LockSession") ||
1801 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
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, NULL, -ENOENT);
1816 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1819 reply = dbus_message_new_method_return(message);
1823 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions")) {
1824 r = session_send_lock_all(m, true);
1826 bus_send_error_reply(connection, message, NULL, r);
1828 reply = dbus_message_new_method_return(message);
1832 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1839 if (!dbus_message_get_args(
1842 DBUS_TYPE_STRING, &name,
1843 DBUS_TYPE_STRING, &swho,
1844 DBUS_TYPE_INT32, &signo,
1846 return bus_send_error_reply(connection, message, &error, -EINVAL);
1851 who = kill_who_from_string(swho);
1853 return bus_send_error_reply(connection, message, &error, -EINVAL);
1856 if (signo <= 0 || signo >= _NSIG)
1857 return bus_send_error_reply(connection, message, &error, -EINVAL);
1859 session = hashmap_get(m->sessions, name);
1861 return bus_send_error_reply(connection, message, &error, -ENOENT);
1863 r = session_kill(session, who, signo);
1865 return bus_send_error_reply(connection, message, NULL, r);
1867 reply = dbus_message_new_method_return(message);
1871 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1876 if (!dbus_message_get_args(
1879 DBUS_TYPE_UINT32, &uid,
1880 DBUS_TYPE_INT32, &signo,
1882 return bus_send_error_reply(connection, message, &error, -EINVAL);
1884 if (signo <= 0 || signo >= _NSIG)
1885 return bus_send_error_reply(connection, message, &error, -EINVAL);
1887 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1889 return bus_send_error_reply(connection, message, &error, -ENOENT);
1891 r = user_kill(user, signo);
1893 return bus_send_error_reply(connection, message, NULL, r);
1895 reply = dbus_message_new_method_return(message);
1899 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1903 if (!dbus_message_get_args(
1906 DBUS_TYPE_STRING, &name,
1908 return bus_send_error_reply(connection, message, &error, -EINVAL);
1910 session = hashmap_get(m->sessions, name);
1912 return bus_send_error_reply(connection, message, &error, -ENOENT);
1914 r = session_stop(session);
1916 return bus_send_error_reply(connection, message, NULL, r);
1918 reply = dbus_message_new_method_return(message);
1922 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1926 if (!dbus_message_get_args(
1929 DBUS_TYPE_UINT32, &uid,
1931 return bus_send_error_reply(connection, message, &error, -EINVAL);
1933 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1935 return bus_send_error_reply(connection, message, &error, -ENOENT);
1937 r = user_stop(user);
1939 return bus_send_error_reply(connection, message, NULL, r);
1941 reply = dbus_message_new_method_return(message);
1945 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1949 if (!dbus_message_get_args(
1952 DBUS_TYPE_STRING, &name,
1954 return bus_send_error_reply(connection, message, &error, -EINVAL);
1956 seat = hashmap_get(m->seats, name);
1958 return bus_send_error_reply(connection, message, &error, -ENOENT);
1960 r = seat_stop_sessions(seat);
1962 return bus_send_error_reply(connection, message, NULL, r);
1964 reply = dbus_message_new_method_return(message);
1968 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
1971 dbus_bool_t b, interactive;
1974 if (!dbus_message_get_args(
1977 DBUS_TYPE_UINT32, &uid,
1978 DBUS_TYPE_BOOLEAN, &b,
1979 DBUS_TYPE_BOOLEAN, &interactive,
1981 return bus_send_error_reply(connection, message, &error, -EINVAL);
1986 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
1988 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
1990 return bus_send_error_reply(connection, message, &error, r);
1992 mkdir_p_label("/var/lib/systemd", 0755);
1994 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
1996 return bus_send_error_reply(connection, message, &error, r);
1998 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
2009 return bus_send_error_reply(connection, message, &error, r);
2011 if (manager_add_user_by_uid(m, uid, &u) >= 0)
2020 if (r < 0 && errno != ENOENT)
2021 return bus_send_error_reply(connection, message, &error, -errno);
2023 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
2025 user_add_to_gc_queue(u);
2028 reply = dbus_message_new_method_return(message);
2032 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
2033 const char *sysfs, *seat;
2034 dbus_bool_t interactive;
2036 if (!dbus_message_get_args(
2039 DBUS_TYPE_STRING, &seat,
2040 DBUS_TYPE_STRING, &sysfs,
2041 DBUS_TYPE_BOOLEAN, &interactive,
2043 return bus_send_error_reply(connection, message, &error, -EINVAL);
2045 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
2046 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2048 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
2050 return bus_send_error_reply(connection, message, &error, r);
2052 r = attach_device(m, seat, sysfs);
2054 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2056 reply = dbus_message_new_method_return(message);
2061 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
2062 dbus_bool_t interactive;
2064 if (!dbus_message_get_args(
2067 DBUS_TYPE_BOOLEAN, &interactive,
2069 return bus_send_error_reply(connection, message, &error, -EINVAL);
2071 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
2073 return bus_send_error_reply(connection, message, &error, r);
2075 r = flush_devices(m);
2077 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2079 reply = dbus_message_new_method_return(message);
2083 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
2085 r = bus_manager_do_shutdown_or_sleep(
2086 m, connection, message,
2087 SPECIAL_POWEROFF_TARGET,
2089 "org.freedesktop.login1.power-off",
2090 "org.freedesktop.login1.power-off-multiple-sessions",
2091 "org.freedesktop.login1.power-off-ignore-inhibit",
2095 return bus_send_error_reply(connection, message, &error, r);
2096 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
2097 r = bus_manager_do_shutdown_or_sleep(
2098 m, connection, message,
2099 SPECIAL_REBOOT_TARGET,
2101 "org.freedesktop.login1.reboot",
2102 "org.freedesktop.login1.reboot-multiple-sessions",
2103 "org.freedesktop.login1.reboot-ignore-inhibit",
2107 return bus_send_error_reply(connection, message, &error, r);
2109 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2110 r = bus_manager_do_shutdown_or_sleep(
2111 m, connection, message,
2112 SPECIAL_SUSPEND_TARGET,
2114 "org.freedesktop.login1.suspend",
2115 "org.freedesktop.login1.suspend-multiple-sessions",
2116 "org.freedesktop.login1.suspend-ignore-inhibit",
2120 return bus_send_error_reply(connection, message, &error, r);
2121 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2122 r = bus_manager_do_shutdown_or_sleep(
2123 m, connection, message,
2124 SPECIAL_HIBERNATE_TARGET,
2126 "org.freedesktop.login1.hibernate",
2127 "org.freedesktop.login1.hibernate-multiple-sessions",
2128 "org.freedesktop.login1.hibernate-ignore-inhibit",
2132 return bus_send_error_reply(connection, message, &error, r);
2134 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "HybridSleep")) {
2135 r = bus_manager_do_shutdown_or_sleep(
2136 m, connection, message,
2137 SPECIAL_HYBRID_SLEEP_TARGET,
2139 "org.freedesktop.login1.hibernate",
2140 "org.freedesktop.login1.hibernate-multiple-sessions",
2141 "org.freedesktop.login1.hibernate-ignore-inhibit",
2145 return bus_send_error_reply(connection, message, &error, r);
2147 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2149 r = bus_manager_can_shutdown_or_sleep(
2150 m, connection, message,
2152 "org.freedesktop.login1.power-off",
2153 "org.freedesktop.login1.power-off-multiple-sessions",
2154 "org.freedesktop.login1.power-off-ignore-inhibit",
2158 return bus_send_error_reply(connection, message, &error, r);
2159 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2160 r = bus_manager_can_shutdown_or_sleep(
2161 m, connection, message,
2163 "org.freedesktop.login1.reboot",
2164 "org.freedesktop.login1.reboot-multiple-sessions",
2165 "org.freedesktop.login1.reboot-ignore-inhibit",
2169 return bus_send_error_reply(connection, message, &error, r);
2171 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2172 r = bus_manager_can_shutdown_or_sleep(
2173 m, connection, message,
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);
2183 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2184 r = bus_manager_can_shutdown_or_sleep(
2185 m, connection, message,
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", "CanHybridSleep")) {
2196 r = bus_manager_can_shutdown_or_sleep(
2197 m, connection, message,
2199 "org.freedesktop.login1.hibernate",
2200 "org.freedesktop.login1.hibernate-multiple-sessions",
2201 "org.freedesktop.login1.hibernate-ignore-inhibit",
2205 return bus_send_error_reply(connection, message, &error, r);
2207 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2208 char *introspection = NULL;
2217 if (!(reply = dbus_message_new_method_return(message)))
2220 /* We roll our own introspection code here, instead of
2221 * relying on bus_default_message_handler() because we
2222 * need to generate our introspection string
2225 if (!(f = open_memstream(&introspection, &size)))
2228 fputs(INTROSPECTION_BEGIN, f);
2230 HASHMAP_FOREACH(seat, m->seats, i) {
2231 p = bus_path_escape(seat->id);
2234 fprintf(f, "<node name=\"seat/%s\"/>", p);
2239 HASHMAP_FOREACH(user, m->users, i)
2240 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2242 HASHMAP_FOREACH(session, m->sessions, i) {
2243 p = bus_path_escape(session->id);
2246 fprintf(f, "<node name=\"session/%s\"/>", p);
2251 fputs(INTROSPECTION_END, f);
2255 free(introspection);
2264 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2265 free(introspection);
2269 free(introspection);
2271 const BusBoundProperties bps[] = {
2272 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2275 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2279 if (!bus_maybe_send_reply(connection, message, reply))
2282 dbus_message_unref(reply);
2285 return DBUS_HANDLER_RESULT_HANDLED;
2289 dbus_message_unref(reply);
2291 dbus_error_free(&error);
2293 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2296 const DBusObjectPathVTable bus_manager_vtable = {
2297 .message_function = manager_message_handler
2300 DBusHandlerResult bus_message_filter(
2301 DBusConnection *connection,
2302 DBusMessage *message,
2305 Manager *m = userdata;
2312 dbus_error_init(&error);
2314 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
2317 if (!dbus_message_get_args(message, &error,
2318 DBUS_TYPE_STRING, &cgroup,
2320 log_error("Failed to parse Released message: %s", bus_error_message(&error));
2322 manager_cgroup_notify_empty(m, cgroup);
2325 dbus_error_free(&error);
2327 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2330 int manager_send_changed(Manager *manager, const char *properties) {
2336 m = bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties);
2340 if (!dbus_connection_send(manager->bus, m, NULL))
2347 dbus_message_unref(m);
2352 int manager_dispatch_delayed(Manager *manager) {
2353 const char *unit_name;
2360 if (!manager->delayed_unit)
2363 /* Continue delay? */
2365 manager->delayed_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC) &&
2366 manager_is_inhibited(manager, manager->delayed_what, INHIBIT_DELAY, NULL, false, false, 0);
2370 bus_manager_log_shutdown(manager, manager->delayed_what, manager->delayed_unit);
2372 /* Reset delay data */
2373 unit_name = manager->delayed_unit;
2374 manager->delayed_unit = NULL;
2376 /* Actually do the shutdown */
2377 dbus_error_init(&error);
2378 r = send_start_unit(manager->bus, unit_name, &error);
2380 log_warning("Failed to send delayed message: %s", bus_error_message_or_strerror(&error, -r));
2381 dbus_error_free(&error);
2385 /* Tell people about it */
2386 send_prepare_for(manager, manager->delayed_what, false);