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=\"IdleAction\" type=\"s\" access=\"read\"/>\n" \
224 " <property name=\"IdleActionUSec\" type=\"t\" access=\"read\"/>\n" \
225 " <property name=\"PreparingForShutdown\" type=\"b\" access=\"read\"/>\n" \
226 " <property name=\"PreparingForSleep\" type=\"b\" access=\"read\"/>\n" \
229 #define INTROSPECTION_BEGIN \
230 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
232 BUS_MANAGER_INTERFACE \
233 BUS_PROPERTIES_INTERFACE \
235 BUS_INTROSPECTABLE_INTERFACE
237 #define INTROSPECTION_END \
240 #define INTERFACES_LIST \
241 BUS_GENERIC_INTERFACES_LIST \
242 "org.freedesktop.login1.Manager\0"
244 static int bus_manager_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
252 b = manager_get_idle_hint(m, NULL) > 0;
253 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
259 static int bus_manager_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
268 manager_get_idle_hint(m, &t);
269 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
271 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
277 static int bus_manager_append_inhibited(DBusMessageIter *i, const char *property, void *data) {
282 w = manager_inhibit_what(m, streq(property, "BlockInhibited") ? INHIBIT_BLOCK : INHIBIT_DELAY);
283 p = inhibit_what_to_string(w);
285 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &p))
291 static int bus_manager_append_preparing(DBusMessageIter *i, const char *property, void *data) {
298 if (streq(property, "PreparingForShutdown"))
299 b = !!(m->delayed_what & INHIBIT_SHUTDOWN);
301 b = !!(m->delayed_what & INHIBIT_SLEEP);
303 dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b);
307 static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMessage **_reply) {
308 Session *session = NULL;
310 const char *type, *class, *seat, *tty, *display, *remote_user, *remote_host, *service;
311 uint32_t uid, leader, audit_id = 0;
312 dbus_bool_t remote, kill_processes, exists;
313 char **controllers = NULL, **reset_controllers = NULL;
317 DBusMessageIter iter;
322 DBusMessage *reply = NULL;
329 if (!dbus_message_iter_init(message, &iter) ||
330 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
333 dbus_message_iter_get_basic(&iter, &uid);
335 if (!dbus_message_iter_next(&iter) ||
336 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
339 dbus_message_iter_get_basic(&iter, &leader);
342 !dbus_message_iter_next(&iter) ||
343 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
346 dbus_message_iter_get_basic(&iter, &service);
348 if (!dbus_message_iter_next(&iter) ||
349 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
352 dbus_message_iter_get_basic(&iter, &type);
353 t = session_type_from_string(type);
356 !dbus_message_iter_next(&iter) ||
357 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
360 dbus_message_iter_get_basic(&iter, &class);
364 c = session_class_from_string(class);
367 !dbus_message_iter_next(&iter) ||
368 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
371 dbus_message_iter_get_basic(&iter, &seat);
376 s = hashmap_get(m->seats, seat);
381 if (!dbus_message_iter_next(&iter) ||
382 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
385 dbus_message_iter_get_basic(&iter, &vtnr);
387 if (!dbus_message_iter_next(&iter) ||
388 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
391 dbus_message_iter_get_basic(&iter, &tty);
393 if (tty_is_vc(tty)) {
398 else if (s != m->vtconsole)
401 v = vtnr_from_tty(tty);
404 return v < 0 ? v : -EINVAL;
408 else if (vtnr != (uint32_t) v)
410 } else if (tty_is_console(tty)) {
414 else if (s != m->vtconsole)
423 if (seat_can_multi_session(s)) {
432 if (!dbus_message_iter_next(&iter) ||
433 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
436 dbus_message_iter_get_basic(&iter, &display);
438 if (!dbus_message_iter_next(&iter) ||
439 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
442 dbus_message_iter_get_basic(&iter, &remote);
444 if (!dbus_message_iter_next(&iter) ||
445 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
448 dbus_message_iter_get_basic(&iter, &remote_user);
450 if (!dbus_message_iter_next(&iter) ||
451 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
454 dbus_message_iter_get_basic(&iter, &remote_host);
456 if (!dbus_message_iter_next(&iter) ||
457 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
458 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
461 r = bus_parse_strv_iter(&iter, &controllers);
465 if (strv_contains(controllers, "systemd") ||
466 !dbus_message_iter_next(&iter) ||
467 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
468 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) {
473 r = bus_parse_strv_iter(&iter, &reset_controllers);
477 if (strv_contains(reset_controllers, "systemd") ||
478 !dbus_message_iter_next(&iter) ||
479 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) {
484 dbus_message_iter_get_basic(&iter, &kill_processes);
486 r = manager_add_user_by_uid(m, uid, &user);
490 audit_session_from_pid(leader, &audit_id);
493 asprintf(&id, "%lu", (unsigned long) audit_id);
500 session = hashmap_get(m->sessions, id);
505 fifo_fd = session_create_fifo(session);
511 /* Session already exists, client is probably
512 * something like "su" which changes uid but
513 * is still the same audit session */
515 reply = dbus_message_new_method_return(message);
521 p = session_bus_path(session);
527 seat = session->seat ? session->seat->id : "";
528 vtnr = session->vtnr;
531 b = dbus_message_append_args(
533 DBUS_TYPE_STRING, &session->id,
534 DBUS_TYPE_OBJECT_PATH, &p,
535 DBUS_TYPE_STRING, &session->user->runtime_path,
536 DBUS_TYPE_UNIX_FD, &fifo_fd,
537 DBUS_TYPE_STRING, &seat,
538 DBUS_TYPE_UINT32, &vtnr,
539 DBUS_TYPE_BOOLEAN, &exists,
548 close_nointr_nofail(fifo_fd);
551 strv_free(controllers);
552 strv_free(reset_controllers);
562 if (asprintf(&id, "c%lu", ++m->session_counter) < 0) {
567 } while (hashmap_get(m->sessions, id));
570 r = manager_add_session(m, user, id, &session);
575 session->leader = leader;
576 session->audit_id = audit_id;
579 session->remote = remote;
580 session->controllers = controllers;
581 session->reset_controllers = reset_controllers;
582 session->kill_processes = kill_processes;
583 session->vtnr = vtnr;
585 controllers = reset_controllers = NULL;
588 session->tty = strdup(tty);
595 if (!isempty(display)) {
596 session->display = strdup(display);
597 if (!session->display) {
603 if (!isempty(remote_user)) {
604 session->remote_user = strdup(remote_user);
605 if (!session->remote_user) {
611 if (!isempty(remote_host)) {
612 session->remote_host = strdup(remote_host);
613 if (!session->remote_host) {
619 if (!isempty(service)) {
620 session->service = strdup(service);
621 if (!session->service) {
627 fifo_fd = session_create_fifo(session);
634 r = seat_attach_session(s, session);
639 r = session_start(session);
643 reply = dbus_message_new_method_return(message);
649 p = session_bus_path(session);
655 seat = s ? s->id : "";
657 b = dbus_message_append_args(
659 DBUS_TYPE_STRING, &session->id,
660 DBUS_TYPE_OBJECT_PATH, &p,
661 DBUS_TYPE_STRING, &session->user->runtime_path,
662 DBUS_TYPE_UNIX_FD, &fifo_fd,
663 DBUS_TYPE_STRING, &seat,
664 DBUS_TYPE_UINT32, &vtnr,
665 DBUS_TYPE_BOOLEAN, &exists,
674 close_nointr_nofail(fifo_fd);
680 strv_free(controllers);
681 strv_free(reset_controllers);
684 session_add_to_gc_queue(session);
687 user_add_to_gc_queue(user);
690 close_nointr_nofail(fifo_fd);
693 dbus_message_unref(reply);
698 static int bus_manager_inhibit(Manager *m, DBusConnection *connection, DBusMessage *message, DBusError *error, DBusMessage **_reply) {
701 const char *who, *why, *what, *mode;
707 DBusMessage *reply = NULL;
715 if (!dbus_message_get_args(
718 DBUS_TYPE_STRING, &what,
719 DBUS_TYPE_STRING, &who,
720 DBUS_TYPE_STRING, &why,
721 DBUS_TYPE_STRING, &mode,
722 DBUS_TYPE_INVALID)) {
727 w = inhibit_what_from_string(what);
733 mm = inhibit_mode_from_string(mode);
739 /* Delay is only supported for shutdown/sleep */
740 if (mm == INHIBIT_DELAY && (w & ~(INHIBIT_SHUTDOWN|INHIBIT_SLEEP))) {
745 r = verify_polkit(connection, message,
746 w == INHIBIT_SHUTDOWN ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
747 w == INHIBIT_SLEEP ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep" : "org.freedesktop.login1.inhibit-delay-sleep") :
748 w == INHIBIT_IDLE ? "org.freedesktop.login1.inhibit-block-idle" :
749 w == INHIBIT_HANDLE_POWER_KEY ? "org.freedesktop.login1.inhibit-handle-power-key" :
750 w == INHIBIT_HANDLE_SUSPEND_KEY ? "org.freedesktop.login1.inhibit-handle-suspend-key" :
751 w == INHIBIT_HANDLE_HIBERNATE_KEY ? "org.freedesktop.login1.inhibit-handle-hibernate-key" :
752 "org.freedesktop.login1.inhibit-handle-lid-switch",
757 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
758 if (ul == (unsigned long) -1) {
763 pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
773 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
777 } while (hashmap_get(m->inhibitors, id));
779 r = manager_add_inhibitor(m, id, &i);
789 i->why = strdup(why);
790 i->who = strdup(who);
792 if (!i->why || !i->who) {
797 fifo_fd = inhibitor_create_fifo(i);
803 reply = dbus_message_new_method_return(message);
809 if (!dbus_message_append_args(
811 DBUS_TYPE_UNIX_FD, &fifo_fd,
812 DBUS_TYPE_INVALID)) {
817 close_nointr_nofail(fifo_fd);
829 close_nointr_nofail(fifo_fd);
832 dbus_message_unref(reply);
837 static int trigger_device(Manager *m, struct udev_device *d) {
838 struct udev_enumerate *e;
839 struct udev_list_entry *first, *item;
844 e = udev_enumerate_new(m->udev);
851 if (udev_enumerate_add_match_parent(e, d) < 0) {
857 if (udev_enumerate_scan_devices(e) < 0) {
862 first = udev_enumerate_get_list_entry(e);
863 udev_list_entry_foreach(item, first) {
867 p = udev_list_entry_get_name(item);
869 t = strappend(p, "/uevent");
875 write_one_line_file(t, "change");
883 udev_enumerate_unref(e);
888 static int attach_device(Manager *m, const char *seat, const char *sysfs) {
889 struct udev_device *d;
890 char *rule = NULL, *file = NULL;
891 const char *id_for_seat;
898 d = udev_device_new_from_syspath(m->udev, sysfs);
902 if (!udev_device_has_tag(d, "seat")) {
907 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
913 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
918 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
923 mkdir_p_label("/etc/udev/rules.d", 0755);
924 r = write_one_line_file_atomic(file, rule);
928 r = trigger_device(m, d);
935 udev_device_unref(d);
940 static int flush_devices(Manager *m) {
945 d = opendir("/etc/udev/rules.d");
948 log_warning("Failed to open /etc/udev/rules.d: %m");
952 while ((de = readdir(d))) {
954 if (!dirent_is_file(de))
957 if (!startswith(de->d_name, "72-seat-"))
960 if (!endswith(de->d_name, ".rules"))
963 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
964 log_warning("Failed to unlink %s: %m", de->d_name);
970 return trigger_device(m, NULL);
973 static int have_multiple_sessions(
982 /* Check for other users' sessions. Greeter sessions do not
983 * count, and non-login sessions do not count either. */
984 HASHMAP_FOREACH(session, m->sessions, i)
985 if (session->class == SESSION_USER &&
986 (session->type == SESSION_TTY || session->type == SESSION_X11) &&
987 session->user->uid != uid)
993 static int send_start_unit(DBusConnection *connection, const char *unit_name, DBusError *error) {
994 const char *mode = "replace";
998 return bus_method_call_with_reply (
1000 "org.freedesktop.systemd1",
1001 "/org/freedesktop/systemd1",
1002 "org.freedesktop.systemd1.Manager",
1006 DBUS_TYPE_STRING, &unit_name,
1007 DBUS_TYPE_STRING, &mode,
1011 static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
1012 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
1013 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
1014 [INHIBIT_SLEEP] = "PrepareForSleep"
1017 dbus_bool_t active = _active;
1018 DBusMessage *message;
1023 assert(w < _INHIBIT_WHAT_MAX);
1024 assert(signal_name[w]);
1026 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1030 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1031 !dbus_connection_send(m->bus, message, NULL))
1034 dbus_message_unref(message);
1038 static int delay_shutdown_or_sleep(Manager *m, InhibitWhat w, const char *unit_name) {
1041 assert(w < _INHIBIT_WHAT_MAX);
1043 /* Tell everybody to prepare for shutdown/sleep */
1044 send_prepare_for(m, w, true);
1046 /* Update timestamp for timeout */
1047 if (!m->delayed_unit)
1048 m->delayed_timestamp = now(CLOCK_MONOTONIC);
1050 /* Remember what we want to do, possibly overriding what kind
1051 * of unit we previously queued. */
1052 m->delayed_unit = unit_name;
1053 m->delayed_what = w;
1058 static int bus_manager_can_shutdown_or_sleep(
1060 DBusConnection *connection,
1061 DBusMessage *message,
1064 const char *action_multiple_sessions,
1065 const char *action_ignore_inhibit,
1066 const char *sleep_type,
1067 const char *sleep_disk_type,
1069 DBusMessage **_reply) {
1071 bool multiple_sessions, challenge, blocked, b;
1073 DBusMessage *reply = NULL;
1081 assert(w <= _INHIBIT_WHAT_MAX);
1083 assert(action_multiple_sessions);
1084 assert(action_ignore_inhibit);
1089 r = can_sleep(sleep_type);
1099 if (sleep_disk_type) {
1100 r = can_sleep_disk(sleep_disk_type);
1110 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1111 if (ul == (unsigned long) -1)
1114 r = have_multiple_sessions(m, (uid_t) ul);
1118 multiple_sessions = r > 0;
1119 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1121 if (multiple_sessions) {
1122 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1129 result = "challenge";
1135 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1139 if (r > 0 && !result)
1141 else if (challenge && (!result || streq(result, "yes")))
1142 result = "challenge";
1147 if (!multiple_sessions && !blocked) {
1148 /* If neither inhibit nor multiple sessions
1149 * apply then just check the normal policy */
1151 r = verify_polkit(connection, message, action, false, &challenge, error);
1158 result = "challenge";
1164 reply = dbus_message_new_method_return(message);
1168 b = dbus_message_append_args(
1170 DBUS_TYPE_STRING, &result,
1173 dbus_message_unref(reply);
1181 static int bus_manager_log_shutdown(
1184 const char *unit_name) {
1191 if (w != INHIBIT_SHUTDOWN)
1194 if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
1195 p = "MESSAGE=System is powering down.";
1196 q = "SHUTDOWN=power-off";
1197 } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
1198 p = "MESSAGE=System is halting.";
1199 q = "SHUTDOWN=halt";
1200 } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
1201 p = "MESSAGE=System is rebooting.";
1202 q = "SHUTDOWN=reboot";
1203 } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
1204 p = "MESSAGE=System is rebooting with kexec.";
1205 q = "SHUTDOWN=kexec";
1207 p = "MESSAGE=System is shutting down.";
1211 return log_struct(LOG_NOTICE, MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
1216 int bus_manager_shutdown_or_sleep_now_or_later(
1218 const char *unit_name,
1228 assert(w <= _INHIBIT_WHAT_MAX);
1231 m->inhibit_delay_max > 0 &&
1232 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0);
1235 /* Shutdown is delayed, keep in mind what we
1236 * want to do, and start a timeout */
1237 r = delay_shutdown_or_sleep(m, w, unit_name);
1239 bus_manager_log_shutdown(m, w, unit_name);
1241 /* Shutdown is not delayed, execute it
1243 r = send_start_unit(m->bus, unit_name, error);
1249 static int bus_manager_do_shutdown_or_sleep(
1251 DBusConnection *connection,
1252 DBusMessage *message,
1253 const char *unit_name,
1256 const char *action_multiple_sessions,
1257 const char *action_ignore_inhibit,
1258 const char *sleep_type,
1259 const char *sleep_disk_type,
1261 DBusMessage **_reply) {
1263 dbus_bool_t interactive;
1264 bool multiple_sessions, blocked;
1265 DBusMessage *reply = NULL;
1274 assert(w <= _INHIBIT_WHAT_MAX);
1276 assert(action_multiple_sessions);
1277 assert(action_ignore_inhibit);
1281 if (!dbus_message_get_args(
1284 DBUS_TYPE_BOOLEAN, &interactive,
1289 r = can_sleep(sleep_type);
1297 if (sleep_disk_type) {
1298 r = can_sleep_disk(sleep_disk_type);
1306 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1307 if (ul == (unsigned long) -1)
1310 r = have_multiple_sessions(m, (uid_t) ul);
1314 multiple_sessions = r > 0;
1315 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1317 if (multiple_sessions) {
1318 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1324 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1329 if (!multiple_sessions && !blocked) {
1330 r = verify_polkit(connection, message, action, interactive, NULL, error);
1335 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
1339 reply = dbus_message_new_method_return(message);
1347 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_action, handle_action, HandleAction);
1349 static const BusProperty bus_login_manager_properties[] = {
1350 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_path), true },
1351 { "Controllers", bus_property_append_strv, "as", offsetof(Manager, controllers), true },
1352 { "ResetControllers", bus_property_append_strv, "as", offsetof(Manager, reset_controllers), true },
1353 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1354 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1355 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1356 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1357 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1358 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1359 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
1360 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1361 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1362 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
1363 { "HandlePowerKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_power_key) },
1364 { "HandleSuspendKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_suspend_key) },
1365 { "HandleHibernateKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_hibernate_key)},
1366 { "HandleLidSwitch", bus_manager_append_handle_action, "s", offsetof(Manager, handle_lid_switch) },
1367 { "IdleAction", bus_manager_append_handle_action, "s", offsetof(Manager, idle_action) },
1368 { "IdleActionUSec", bus_property_append_usec, "t", offsetof(Manager, idle_action_usec) },
1369 { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
1370 { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
1374 static DBusHandlerResult manager_message_handler(
1375 DBusConnection *connection,
1376 DBusMessage *message,
1379 Manager *m = userdata;
1382 DBusMessage *reply = NULL;
1389 dbus_error_init(&error);
1391 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1397 if (!dbus_message_get_args(
1400 DBUS_TYPE_STRING, &name,
1402 return bus_send_error_reply(connection, message, &error, -EINVAL);
1404 session = hashmap_get(m->sessions, name);
1406 return bus_send_error_reply(connection, message, &error, -ENOENT);
1408 reply = dbus_message_new_method_return(message);
1412 p = session_bus_path(session);
1416 b = dbus_message_append_args(
1418 DBUS_TYPE_OBJECT_PATH, &p,
1425 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1431 if (!dbus_message_get_args(
1434 DBUS_TYPE_UINT32, &pid,
1436 return bus_send_error_reply(connection, message, &error, -EINVAL);
1438 r = manager_get_session_by_pid(m, pid, &session);
1440 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1442 reply = dbus_message_new_method_return(message);
1446 p = session_bus_path(session);
1450 b = dbus_message_append_args(
1452 DBUS_TYPE_OBJECT_PATH, &p,
1459 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1465 if (!dbus_message_get_args(
1468 DBUS_TYPE_UINT32, &uid,
1470 return bus_send_error_reply(connection, message, &error, -EINVAL);
1472 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1474 return bus_send_error_reply(connection, message, &error, -ENOENT);
1476 reply = dbus_message_new_method_return(message);
1480 p = user_bus_path(user);
1484 b = dbus_message_append_args(
1486 DBUS_TYPE_OBJECT_PATH, &p,
1493 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1499 if (!dbus_message_get_args(
1502 DBUS_TYPE_STRING, &name,
1504 return bus_send_error_reply(connection, message, &error, -EINVAL);
1506 seat = hashmap_get(m->seats, name);
1508 return bus_send_error_reply(connection, message, &error, -ENOENT);
1510 reply = dbus_message_new_method_return(message);
1514 p = seat_bus_path(seat);
1518 b = dbus_message_append_args(
1520 DBUS_TYPE_OBJECT_PATH, &p,
1527 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1531 DBusMessageIter iter, sub;
1532 const char *empty = "";
1534 reply = dbus_message_new_method_return(message);
1538 dbus_message_iter_init_append(reply, &iter);
1540 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1543 HASHMAP_FOREACH(session, m->sessions, i) {
1544 DBusMessageIter sub2;
1547 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1550 uid = session->user->uid;
1552 p = session_bus_path(session);
1556 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1557 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1558 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1559 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1560 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1567 if (!dbus_message_iter_close_container(&sub, &sub2))
1571 if (!dbus_message_iter_close_container(&iter, &sub))
1574 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1578 DBusMessageIter iter, sub;
1580 reply = dbus_message_new_method_return(message);
1584 dbus_message_iter_init_append(reply, &iter);
1586 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1589 HASHMAP_FOREACH(user, m->users, i) {
1590 DBusMessageIter sub2;
1593 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1598 p = user_bus_path(user);
1602 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1603 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1604 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1611 if (!dbus_message_iter_close_container(&sub, &sub2))
1615 if (!dbus_message_iter_close_container(&iter, &sub))
1618 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1622 DBusMessageIter iter, sub;
1624 reply = dbus_message_new_method_return(message);
1628 dbus_message_iter_init_append(reply, &iter);
1630 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1633 HASHMAP_FOREACH(seat, m->seats, i) {
1634 DBusMessageIter sub2;
1636 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1639 p = seat_bus_path(seat);
1643 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1644 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1651 if (!dbus_message_iter_close_container(&sub, &sub2))
1655 if (!dbus_message_iter_close_container(&iter, &sub))
1658 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1659 Inhibitor *inhibitor;
1661 DBusMessageIter iter, sub;
1663 reply = dbus_message_new_method_return(message);
1667 dbus_message_iter_init_append(reply, &iter);
1669 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1672 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1673 DBusMessageIter sub2;
1674 dbus_uint32_t uid, pid;
1675 const char *what, *who, *why, *mode;
1677 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1680 what = strempty(inhibit_what_to_string(inhibitor->what));
1681 who = strempty(inhibitor->who);
1682 why = strempty(inhibitor->why);
1683 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
1684 uid = (dbus_uint32_t) inhibitor->uid;
1685 pid = (dbus_uint32_t) inhibitor->pid;
1687 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1688 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1689 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1690 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
1691 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1692 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1695 if (!dbus_message_iter_close_container(&sub, &sub2))
1699 if (!dbus_message_iter_close_container(&iter, &sub))
1702 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1704 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1707 return bus_send_error_reply(connection, message, &error, r);
1710 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1712 r = bus_manager_create_session(m, message, &reply);
1714 /* Don't delay the work on OOM here, since it might be
1715 * triggered by a low RLIMIT_NOFILE here (since we
1716 * send a dupped fd to the client), and we'd rather
1717 * see this fail quickly then be retried later */
1720 return bus_send_error_reply(connection, message, NULL, r);
1722 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1726 if (!dbus_message_get_args(
1729 DBUS_TYPE_STRING, &name,
1731 return bus_send_error_reply(connection, message, &error, -EINVAL);
1733 session = hashmap_get(m->sessions, name);
1735 return bus_send_error_reply(connection, message, &error, -ENOENT);
1737 /* We use the FIFO to detect stray sessions where the
1738 process invoking PAM dies abnormally. We need to make
1739 sure that that process is not killed if at the clean
1740 end of the session it closes the FIFO. Hence, with
1741 this call explicitly turn off the FIFO logic, so that
1742 the PAM code can finish clean up on its own */
1743 session_remove_fifo(session);
1745 reply = dbus_message_new_method_return(message);
1749 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1753 if (!dbus_message_get_args(
1756 DBUS_TYPE_STRING, &name,
1758 return bus_send_error_reply(connection, message, &error, -EINVAL);
1760 session = hashmap_get(m->sessions, name);
1762 return bus_send_error_reply(connection, message, &error, -ENOENT);
1764 r = session_activate(session);
1766 return bus_send_error_reply(connection, message, NULL, r);
1768 reply = dbus_message_new_method_return(message);
1772 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1773 const char *session_name, *seat_name;
1777 /* Same as ActivateSession() but refuses to work if
1778 * the seat doesn't match */
1780 if (!dbus_message_get_args(
1783 DBUS_TYPE_STRING, &session_name,
1784 DBUS_TYPE_STRING, &seat_name,
1786 return bus_send_error_reply(connection, message, &error, -EINVAL);
1788 session = hashmap_get(m->sessions, session_name);
1790 return bus_send_error_reply(connection, message, &error, -ENOENT);
1792 seat = hashmap_get(m->seats, seat_name);
1794 return bus_send_error_reply(connection, message, &error, -ENOENT);
1796 if (session->seat != seat)
1797 return bus_send_error_reply(connection, message, &error, -EINVAL);
1799 r = session_activate(session);
1801 return bus_send_error_reply(connection, message, NULL, r);
1803 reply = dbus_message_new_method_return(message);
1807 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1808 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1812 if (!dbus_message_get_args(
1815 DBUS_TYPE_STRING, &name,
1817 return bus_send_error_reply(connection, message, &error, -EINVAL);
1819 session = hashmap_get(m->sessions, name);
1821 return bus_send_error_reply(connection, message, NULL, -ENOENT);
1823 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1826 reply = dbus_message_new_method_return(message);
1830 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions")) {
1831 r = session_send_lock_all(m, true);
1833 bus_send_error_reply(connection, message, NULL, r);
1835 reply = dbus_message_new_method_return(message);
1839 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1846 if (!dbus_message_get_args(
1849 DBUS_TYPE_STRING, &name,
1850 DBUS_TYPE_STRING, &swho,
1851 DBUS_TYPE_INT32, &signo,
1853 return bus_send_error_reply(connection, message, &error, -EINVAL);
1858 who = kill_who_from_string(swho);
1860 return bus_send_error_reply(connection, message, &error, -EINVAL);
1863 if (signo <= 0 || signo >= _NSIG)
1864 return bus_send_error_reply(connection, message, &error, -EINVAL);
1866 session = hashmap_get(m->sessions, name);
1868 return bus_send_error_reply(connection, message, &error, -ENOENT);
1870 r = session_kill(session, who, signo);
1872 return bus_send_error_reply(connection, message, NULL, r);
1874 reply = dbus_message_new_method_return(message);
1878 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1883 if (!dbus_message_get_args(
1886 DBUS_TYPE_UINT32, &uid,
1887 DBUS_TYPE_INT32, &signo,
1889 return bus_send_error_reply(connection, message, &error, -EINVAL);
1891 if (signo <= 0 || signo >= _NSIG)
1892 return bus_send_error_reply(connection, message, &error, -EINVAL);
1894 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1896 return bus_send_error_reply(connection, message, &error, -ENOENT);
1898 r = user_kill(user, signo);
1900 return bus_send_error_reply(connection, message, NULL, r);
1902 reply = dbus_message_new_method_return(message);
1906 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1910 if (!dbus_message_get_args(
1913 DBUS_TYPE_STRING, &name,
1915 return bus_send_error_reply(connection, message, &error, -EINVAL);
1917 session = hashmap_get(m->sessions, name);
1919 return bus_send_error_reply(connection, message, &error, -ENOENT);
1921 r = session_stop(session);
1923 return bus_send_error_reply(connection, message, NULL, r);
1925 reply = dbus_message_new_method_return(message);
1929 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1933 if (!dbus_message_get_args(
1936 DBUS_TYPE_UINT32, &uid,
1938 return bus_send_error_reply(connection, message, &error, -EINVAL);
1940 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1942 return bus_send_error_reply(connection, message, &error, -ENOENT);
1944 r = user_stop(user);
1946 return bus_send_error_reply(connection, message, NULL, r);
1948 reply = dbus_message_new_method_return(message);
1952 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1956 if (!dbus_message_get_args(
1959 DBUS_TYPE_STRING, &name,
1961 return bus_send_error_reply(connection, message, &error, -EINVAL);
1963 seat = hashmap_get(m->seats, name);
1965 return bus_send_error_reply(connection, message, &error, -ENOENT);
1967 r = seat_stop_sessions(seat);
1969 return bus_send_error_reply(connection, message, NULL, r);
1971 reply = dbus_message_new_method_return(message);
1975 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
1978 dbus_bool_t b, interactive;
1981 if (!dbus_message_get_args(
1984 DBUS_TYPE_UINT32, &uid,
1985 DBUS_TYPE_BOOLEAN, &b,
1986 DBUS_TYPE_BOOLEAN, &interactive,
1988 return bus_send_error_reply(connection, message, &error, -EINVAL);
1993 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
1995 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
1997 return bus_send_error_reply(connection, message, &error, r);
1999 mkdir_p_label("/var/lib/systemd", 0755);
2001 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
2003 return bus_send_error_reply(connection, message, &error, r);
2005 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
2016 return bus_send_error_reply(connection, message, &error, r);
2018 if (manager_add_user_by_uid(m, uid, &u) >= 0)
2027 if (r < 0 && errno != ENOENT)
2028 return bus_send_error_reply(connection, message, &error, -errno);
2030 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
2032 user_add_to_gc_queue(u);
2035 reply = dbus_message_new_method_return(message);
2039 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
2040 const char *sysfs, *seat;
2041 dbus_bool_t interactive;
2043 if (!dbus_message_get_args(
2046 DBUS_TYPE_STRING, &seat,
2047 DBUS_TYPE_STRING, &sysfs,
2048 DBUS_TYPE_BOOLEAN, &interactive,
2050 return bus_send_error_reply(connection, message, &error, -EINVAL);
2052 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
2053 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2055 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
2057 return bus_send_error_reply(connection, message, &error, r);
2059 r = attach_device(m, seat, sysfs);
2061 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2063 reply = dbus_message_new_method_return(message);
2068 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
2069 dbus_bool_t interactive;
2071 if (!dbus_message_get_args(
2074 DBUS_TYPE_BOOLEAN, &interactive,
2076 return bus_send_error_reply(connection, message, &error, -EINVAL);
2078 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
2080 return bus_send_error_reply(connection, message, &error, r);
2082 r = flush_devices(m);
2084 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2086 reply = dbus_message_new_method_return(message);
2090 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
2092 r = bus_manager_do_shutdown_or_sleep(
2093 m, connection, message,
2094 SPECIAL_POWEROFF_TARGET,
2096 "org.freedesktop.login1.power-off",
2097 "org.freedesktop.login1.power-off-multiple-sessions",
2098 "org.freedesktop.login1.power-off-ignore-inhibit",
2102 return bus_send_error_reply(connection, message, &error, r);
2103 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
2104 r = bus_manager_do_shutdown_or_sleep(
2105 m, connection, message,
2106 SPECIAL_REBOOT_TARGET,
2108 "org.freedesktop.login1.reboot",
2109 "org.freedesktop.login1.reboot-multiple-sessions",
2110 "org.freedesktop.login1.reboot-ignore-inhibit",
2114 return bus_send_error_reply(connection, message, &error, r);
2116 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2117 r = bus_manager_do_shutdown_or_sleep(
2118 m, connection, message,
2119 SPECIAL_SUSPEND_TARGET,
2121 "org.freedesktop.login1.suspend",
2122 "org.freedesktop.login1.suspend-multiple-sessions",
2123 "org.freedesktop.login1.suspend-ignore-inhibit",
2127 return bus_send_error_reply(connection, message, &error, r);
2128 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2129 r = bus_manager_do_shutdown_or_sleep(
2130 m, connection, message,
2131 SPECIAL_HIBERNATE_TARGET,
2133 "org.freedesktop.login1.hibernate",
2134 "org.freedesktop.login1.hibernate-multiple-sessions",
2135 "org.freedesktop.login1.hibernate-ignore-inhibit",
2139 return bus_send_error_reply(connection, message, &error, r);
2141 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "HybridSleep")) {
2142 r = bus_manager_do_shutdown_or_sleep(
2143 m, connection, message,
2144 SPECIAL_HYBRID_SLEEP_TARGET,
2146 "org.freedesktop.login1.hibernate",
2147 "org.freedesktop.login1.hibernate-multiple-sessions",
2148 "org.freedesktop.login1.hibernate-ignore-inhibit",
2152 return bus_send_error_reply(connection, message, &error, r);
2154 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2156 r = bus_manager_can_shutdown_or_sleep(
2157 m, connection, message,
2159 "org.freedesktop.login1.power-off",
2160 "org.freedesktop.login1.power-off-multiple-sessions",
2161 "org.freedesktop.login1.power-off-ignore-inhibit",
2165 return bus_send_error_reply(connection, message, &error, r);
2166 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2167 r = bus_manager_can_shutdown_or_sleep(
2168 m, connection, message,
2170 "org.freedesktop.login1.reboot",
2171 "org.freedesktop.login1.reboot-multiple-sessions",
2172 "org.freedesktop.login1.reboot-ignore-inhibit",
2176 return bus_send_error_reply(connection, message, &error, r);
2178 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2179 r = bus_manager_can_shutdown_or_sleep(
2180 m, connection, message,
2182 "org.freedesktop.login1.suspend",
2183 "org.freedesktop.login1.suspend-multiple-sessions",
2184 "org.freedesktop.login1.suspend-ignore-inhibit",
2188 return bus_send_error_reply(connection, message, &error, r);
2190 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2191 r = bus_manager_can_shutdown_or_sleep(
2192 m, connection, message,
2194 "org.freedesktop.login1.hibernate",
2195 "org.freedesktop.login1.hibernate-multiple-sessions",
2196 "org.freedesktop.login1.hibernate-ignore-inhibit",
2200 return bus_send_error_reply(connection, message, &error, r);
2202 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHybridSleep")) {
2203 r = bus_manager_can_shutdown_or_sleep(
2204 m, connection, message,
2206 "org.freedesktop.login1.hibernate",
2207 "org.freedesktop.login1.hibernate-multiple-sessions",
2208 "org.freedesktop.login1.hibernate-ignore-inhibit",
2212 return bus_send_error_reply(connection, message, &error, r);
2214 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2215 char *introspection = NULL;
2224 if (!(reply = dbus_message_new_method_return(message)))
2227 /* We roll our own introspection code here, instead of
2228 * relying on bus_default_message_handler() because we
2229 * need to generate our introspection string
2232 if (!(f = open_memstream(&introspection, &size)))
2235 fputs(INTROSPECTION_BEGIN, f);
2237 HASHMAP_FOREACH(seat, m->seats, i) {
2238 p = bus_path_escape(seat->id);
2241 fprintf(f, "<node name=\"seat/%s\"/>", p);
2246 HASHMAP_FOREACH(user, m->users, i)
2247 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2249 HASHMAP_FOREACH(session, m->sessions, i) {
2250 p = bus_path_escape(session->id);
2253 fprintf(f, "<node name=\"session/%s\"/>", p);
2258 fputs(INTROSPECTION_END, f);
2262 free(introspection);
2271 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2272 free(introspection);
2276 free(introspection);
2278 const BusBoundProperties bps[] = {
2279 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2282 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2286 if (!bus_maybe_send_reply(connection, message, reply))
2289 dbus_message_unref(reply);
2292 return DBUS_HANDLER_RESULT_HANDLED;
2296 dbus_message_unref(reply);
2298 dbus_error_free(&error);
2300 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2303 const DBusObjectPathVTable bus_manager_vtable = {
2304 .message_function = manager_message_handler
2307 DBusHandlerResult bus_message_filter(
2308 DBusConnection *connection,
2309 DBusMessage *message,
2312 Manager *m = userdata;
2319 dbus_error_init(&error);
2321 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
2324 if (!dbus_message_get_args(message, &error,
2325 DBUS_TYPE_STRING, &cgroup,
2327 log_error("Failed to parse Released message: %s", bus_error_message(&error));
2329 manager_cgroup_notify_empty(m, cgroup);
2332 dbus_error_free(&error);
2334 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2337 int manager_send_changed(Manager *manager, const char *properties) {
2343 m = bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties);
2347 if (!dbus_connection_send(manager->bus, m, NULL))
2354 dbus_message_unref(m);
2359 int manager_dispatch_delayed(Manager *manager) {
2360 const char *unit_name;
2367 if (!manager->delayed_unit)
2370 /* Continue delay? */
2372 manager->delayed_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC) &&
2373 manager_is_inhibited(manager, manager->delayed_what, INHIBIT_DELAY, NULL, false, false, 0);
2377 bus_manager_log_shutdown(manager, manager->delayed_what, manager->delayed_unit);
2379 /* Reset delay data */
2380 unit_name = manager->delayed_unit;
2381 manager->delayed_unit = NULL;
2383 /* Actually do the shutdown */
2384 dbus_error_init(&error);
2385 r = send_start_unit(manager->bus, unit_name, &error);
2387 log_warning("Failed to send delayed message: %s", bus_error_message_or_strerror(&error, -r));
2388 dbus_error_free(&error);
2392 /* Tell people about it */
2393 send_prepare_for(manager, manager->delayed_what, false);