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 count. */
983 HASHMAP_FOREACH(session, m->sessions, i)
984 if (session->class == SESSION_USER && session->user->uid != uid)
990 static int send_start_unit(DBusConnection *connection, const char *unit_name, DBusError *error) {
991 const char *mode = "replace";
995 return bus_method_call_with_reply (
997 "org.freedesktop.systemd1",
998 "/org/freedesktop/systemd1",
999 "org.freedesktop.systemd1.Manager",
1003 DBUS_TYPE_STRING, &unit_name,
1004 DBUS_TYPE_STRING, &mode,
1008 static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
1009 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
1010 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
1011 [INHIBIT_SLEEP] = "PrepareForSleep"
1014 dbus_bool_t active = _active;
1015 DBusMessage *message;
1020 assert(w < _INHIBIT_WHAT_MAX);
1021 assert(signal_name[w]);
1023 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1027 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1028 !dbus_connection_send(m->bus, message, NULL))
1031 dbus_message_unref(message);
1035 static int delay_shutdown_or_sleep(Manager *m, InhibitWhat w, const char *unit_name) {
1038 assert(w < _INHIBIT_WHAT_MAX);
1040 /* Tell everybody to prepare for shutdown/sleep */
1041 send_prepare_for(m, w, true);
1043 /* Update timestamp for timeout */
1044 if (!m->delayed_unit)
1045 m->delayed_timestamp = now(CLOCK_MONOTONIC);
1047 /* Remember what we want to do, possibly overriding what kind
1048 * of unit we previously queued. */
1049 m->delayed_unit = unit_name;
1050 m->delayed_what = w;
1055 static int bus_manager_can_shutdown_or_sleep(
1057 DBusConnection *connection,
1058 DBusMessage *message,
1061 const char *action_multiple_sessions,
1062 const char *action_ignore_inhibit,
1063 const char *sleep_type,
1064 const char *sleep_disk_type,
1066 DBusMessage **_reply) {
1068 bool multiple_sessions, challenge, blocked, b;
1070 DBusMessage *reply = NULL;
1078 assert(w <= _INHIBIT_WHAT_MAX);
1080 assert(action_multiple_sessions);
1081 assert(action_ignore_inhibit);
1086 r = can_sleep(sleep_type);
1096 if (sleep_disk_type) {
1097 r = can_sleep_disk(sleep_disk_type);
1107 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1108 if (ul == (unsigned long) -1)
1111 r = have_multiple_sessions(m, (uid_t) ul);
1115 multiple_sessions = r > 0;
1116 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1118 if (multiple_sessions) {
1119 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1126 result = "challenge";
1132 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1136 if (r > 0 && !result)
1138 else if (challenge && (!result || streq(result, "yes")))
1139 result = "challenge";
1144 if (!multiple_sessions && !blocked) {
1145 /* If neither inhibit nor multiple sessions
1146 * apply then just check the normal policy */
1148 r = verify_polkit(connection, message, action, false, &challenge, error);
1155 result = "challenge";
1161 reply = dbus_message_new_method_return(message);
1165 b = dbus_message_append_args(
1167 DBUS_TYPE_STRING, &result,
1170 dbus_message_unref(reply);
1178 static int bus_manager_log_shutdown(
1181 const char *unit_name) {
1188 if (w != INHIBIT_SHUTDOWN)
1191 if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
1192 p = "MESSAGE=System is powering down.";
1193 q = "SHUTDOWN=power-off";
1194 } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
1195 p = "MESSAGE=System is halting.";
1196 q = "SHUTDOWN=halt";
1197 } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
1198 p = "MESSAGE=System is rebooting.";
1199 q = "SHUTDOWN=reboot";
1200 } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
1201 p = "MESSAGE=System is rebooting with kexec.";
1202 q = "SHUTDOWN=kexec";
1204 p = "MESSAGE=System is shutting down.";
1208 return log_struct(LOG_NOTICE, MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
1213 int bus_manager_shutdown_or_sleep_now_or_later(
1215 const char *unit_name,
1225 assert(w <= _INHIBIT_WHAT_MAX);
1228 m->inhibit_delay_max > 0 &&
1229 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0);
1232 /* Shutdown is delayed, keep in mind what we
1233 * want to do, and start a timeout */
1234 r = delay_shutdown_or_sleep(m, w, unit_name);
1236 bus_manager_log_shutdown(m, w, unit_name);
1238 /* Shutdown is not delayed, execute it
1240 r = send_start_unit(m->bus, unit_name, error);
1246 static int bus_manager_do_shutdown_or_sleep(
1248 DBusConnection *connection,
1249 DBusMessage *message,
1250 const char *unit_name,
1253 const char *action_multiple_sessions,
1254 const char *action_ignore_inhibit,
1255 const char *sleep_type,
1256 const char *sleep_disk_type,
1258 DBusMessage **_reply) {
1260 dbus_bool_t interactive;
1261 bool multiple_sessions, blocked;
1262 DBusMessage *reply = NULL;
1271 assert(w <= _INHIBIT_WHAT_MAX);
1273 assert(action_multiple_sessions);
1274 assert(action_ignore_inhibit);
1278 if (!dbus_message_get_args(
1281 DBUS_TYPE_BOOLEAN, &interactive,
1286 r = can_sleep(sleep_type);
1294 if (sleep_disk_type) {
1295 r = can_sleep_disk(sleep_disk_type);
1303 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1304 if (ul == (unsigned long) -1)
1307 r = have_multiple_sessions(m, (uid_t) ul);
1311 multiple_sessions = r > 0;
1312 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1314 if (multiple_sessions) {
1315 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1321 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1326 if (!multiple_sessions && !blocked) {
1327 r = verify_polkit(connection, message, action, interactive, NULL, error);
1332 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
1336 reply = dbus_message_new_method_return(message);
1344 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_action, handle_action, HandleAction);
1346 static const BusProperty bus_login_manager_properties[] = {
1347 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_path), true },
1348 { "Controllers", bus_property_append_strv, "as", offsetof(Manager, controllers), true },
1349 { "ResetControllers", bus_property_append_strv, "as", offsetof(Manager, reset_controllers), true },
1350 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1351 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1352 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1353 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1354 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1355 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1356 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
1357 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1358 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1359 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
1360 { "HandlePowerKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_power_key) },
1361 { "HandleSuspendKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_suspend_key) },
1362 { "HandleHibernateKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_hibernate_key)},
1363 { "HandleLidSwitch", bus_manager_append_handle_action, "s", offsetof(Manager, handle_lid_switch) },
1364 { "IdleAction", bus_manager_append_handle_action, "s", offsetof(Manager, idle_action) },
1365 { "IdleActionUSec", bus_property_append_usec, "t", offsetof(Manager, idle_action_usec) },
1366 { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
1367 { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
1371 static DBusHandlerResult manager_message_handler(
1372 DBusConnection *connection,
1373 DBusMessage *message,
1376 Manager *m = userdata;
1379 DBusMessage *reply = NULL;
1386 dbus_error_init(&error);
1388 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1394 if (!dbus_message_get_args(
1397 DBUS_TYPE_STRING, &name,
1399 return bus_send_error_reply(connection, message, &error, -EINVAL);
1401 session = hashmap_get(m->sessions, name);
1403 return bus_send_error_reply(connection, message, &error, -ENOENT);
1405 reply = dbus_message_new_method_return(message);
1409 p = session_bus_path(session);
1413 b = dbus_message_append_args(
1415 DBUS_TYPE_OBJECT_PATH, &p,
1422 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1428 if (!dbus_message_get_args(
1431 DBUS_TYPE_UINT32, &pid,
1433 return bus_send_error_reply(connection, message, &error, -EINVAL);
1435 r = manager_get_session_by_pid(m, pid, &session);
1437 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1439 reply = dbus_message_new_method_return(message);
1443 p = session_bus_path(session);
1447 b = dbus_message_append_args(
1449 DBUS_TYPE_OBJECT_PATH, &p,
1456 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1462 if (!dbus_message_get_args(
1465 DBUS_TYPE_UINT32, &uid,
1467 return bus_send_error_reply(connection, message, &error, -EINVAL);
1469 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1471 return bus_send_error_reply(connection, message, &error, -ENOENT);
1473 reply = dbus_message_new_method_return(message);
1477 p = user_bus_path(user);
1481 b = dbus_message_append_args(
1483 DBUS_TYPE_OBJECT_PATH, &p,
1490 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1496 if (!dbus_message_get_args(
1499 DBUS_TYPE_STRING, &name,
1501 return bus_send_error_reply(connection, message, &error, -EINVAL);
1503 seat = hashmap_get(m->seats, name);
1505 return bus_send_error_reply(connection, message, &error, -ENOENT);
1507 reply = dbus_message_new_method_return(message);
1511 p = seat_bus_path(seat);
1515 b = dbus_message_append_args(
1517 DBUS_TYPE_OBJECT_PATH, &p,
1524 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1528 DBusMessageIter iter, sub;
1529 const char *empty = "";
1531 reply = dbus_message_new_method_return(message);
1535 dbus_message_iter_init_append(reply, &iter);
1537 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1540 HASHMAP_FOREACH(session, m->sessions, i) {
1541 DBusMessageIter sub2;
1544 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1547 uid = session->user->uid;
1549 p = session_bus_path(session);
1553 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1554 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1555 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1556 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1557 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1564 if (!dbus_message_iter_close_container(&sub, &sub2))
1568 if (!dbus_message_iter_close_container(&iter, &sub))
1571 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1575 DBusMessageIter iter, sub;
1577 reply = dbus_message_new_method_return(message);
1581 dbus_message_iter_init_append(reply, &iter);
1583 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1586 HASHMAP_FOREACH(user, m->users, i) {
1587 DBusMessageIter sub2;
1590 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1595 p = user_bus_path(user);
1599 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1600 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1601 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1608 if (!dbus_message_iter_close_container(&sub, &sub2))
1612 if (!dbus_message_iter_close_container(&iter, &sub))
1615 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1619 DBusMessageIter iter, sub;
1621 reply = dbus_message_new_method_return(message);
1625 dbus_message_iter_init_append(reply, &iter);
1627 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1630 HASHMAP_FOREACH(seat, m->seats, i) {
1631 DBusMessageIter sub2;
1633 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1636 p = seat_bus_path(seat);
1640 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1641 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1648 if (!dbus_message_iter_close_container(&sub, &sub2))
1652 if (!dbus_message_iter_close_container(&iter, &sub))
1655 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1656 Inhibitor *inhibitor;
1658 DBusMessageIter iter, sub;
1660 reply = dbus_message_new_method_return(message);
1664 dbus_message_iter_init_append(reply, &iter);
1666 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1669 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1670 DBusMessageIter sub2;
1671 dbus_uint32_t uid, pid;
1672 const char *what, *who, *why, *mode;
1674 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1677 what = strempty(inhibit_what_to_string(inhibitor->what));
1678 who = strempty(inhibitor->who);
1679 why = strempty(inhibitor->why);
1680 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
1681 uid = (dbus_uint32_t) inhibitor->uid;
1682 pid = (dbus_uint32_t) inhibitor->pid;
1684 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1685 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1686 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1687 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
1688 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1689 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1692 if (!dbus_message_iter_close_container(&sub, &sub2))
1696 if (!dbus_message_iter_close_container(&iter, &sub))
1699 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1701 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1704 return bus_send_error_reply(connection, message, &error, r);
1707 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1709 r = bus_manager_create_session(m, message, &reply);
1711 /* Don't delay the work on OOM here, since it might be
1712 * triggered by a low RLIMIT_NOFILE here (since we
1713 * send a dupped fd to the client), and we'd rather
1714 * see this fail quickly then be retried later */
1717 return bus_send_error_reply(connection, message, NULL, r);
1719 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1723 if (!dbus_message_get_args(
1726 DBUS_TYPE_STRING, &name,
1728 return bus_send_error_reply(connection, message, &error, -EINVAL);
1730 session = hashmap_get(m->sessions, name);
1732 return bus_send_error_reply(connection, message, &error, -ENOENT);
1734 /* We use the FIFO to detect stray sessions where the
1735 process invoking PAM dies abnormally. We need to make
1736 sure that that process is not killed if at the clean
1737 end of the session it closes the FIFO. Hence, with
1738 this call explicitly turn off the FIFO logic, so that
1739 the PAM code can finish clean up on its own */
1740 session_remove_fifo(session);
1742 reply = dbus_message_new_method_return(message);
1746 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1750 if (!dbus_message_get_args(
1753 DBUS_TYPE_STRING, &name,
1755 return bus_send_error_reply(connection, message, &error, -EINVAL);
1757 session = hashmap_get(m->sessions, name);
1759 return bus_send_error_reply(connection, message, &error, -ENOENT);
1761 r = session_activate(session);
1763 return bus_send_error_reply(connection, message, NULL, r);
1765 reply = dbus_message_new_method_return(message);
1769 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1770 const char *session_name, *seat_name;
1774 /* Same as ActivateSession() but refuses to work if
1775 * the seat doesn't match */
1777 if (!dbus_message_get_args(
1780 DBUS_TYPE_STRING, &session_name,
1781 DBUS_TYPE_STRING, &seat_name,
1783 return bus_send_error_reply(connection, message, &error, -EINVAL);
1785 session = hashmap_get(m->sessions, session_name);
1787 return bus_send_error_reply(connection, message, &error, -ENOENT);
1789 seat = hashmap_get(m->seats, seat_name);
1791 return bus_send_error_reply(connection, message, &error, -ENOENT);
1793 if (session->seat != seat)
1794 return bus_send_error_reply(connection, message, &error, -EINVAL);
1796 r = session_activate(session);
1798 return bus_send_error_reply(connection, message, NULL, r);
1800 reply = dbus_message_new_method_return(message);
1804 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1805 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1809 if (!dbus_message_get_args(
1812 DBUS_TYPE_STRING, &name,
1814 return bus_send_error_reply(connection, message, &error, -EINVAL);
1816 session = hashmap_get(m->sessions, name);
1818 return bus_send_error_reply(connection, message, NULL, -ENOENT);
1820 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1823 reply = dbus_message_new_method_return(message);
1827 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions")) {
1828 r = session_send_lock_all(m, true);
1830 bus_send_error_reply(connection, message, NULL, r);
1832 reply = dbus_message_new_method_return(message);
1836 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1843 if (!dbus_message_get_args(
1846 DBUS_TYPE_STRING, &name,
1847 DBUS_TYPE_STRING, &swho,
1848 DBUS_TYPE_INT32, &signo,
1850 return bus_send_error_reply(connection, message, &error, -EINVAL);
1855 who = kill_who_from_string(swho);
1857 return bus_send_error_reply(connection, message, &error, -EINVAL);
1860 if (signo <= 0 || signo >= _NSIG)
1861 return bus_send_error_reply(connection, message, &error, -EINVAL);
1863 session = hashmap_get(m->sessions, name);
1865 return bus_send_error_reply(connection, message, &error, -ENOENT);
1867 r = session_kill(session, who, signo);
1869 return bus_send_error_reply(connection, message, NULL, r);
1871 reply = dbus_message_new_method_return(message);
1875 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1880 if (!dbus_message_get_args(
1883 DBUS_TYPE_UINT32, &uid,
1884 DBUS_TYPE_INT32, &signo,
1886 return bus_send_error_reply(connection, message, &error, -EINVAL);
1888 if (signo <= 0 || signo >= _NSIG)
1889 return bus_send_error_reply(connection, message, &error, -EINVAL);
1891 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1893 return bus_send_error_reply(connection, message, &error, -ENOENT);
1895 r = user_kill(user, signo);
1897 return bus_send_error_reply(connection, message, NULL, r);
1899 reply = dbus_message_new_method_return(message);
1903 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1907 if (!dbus_message_get_args(
1910 DBUS_TYPE_STRING, &name,
1912 return bus_send_error_reply(connection, message, &error, -EINVAL);
1914 session = hashmap_get(m->sessions, name);
1916 return bus_send_error_reply(connection, message, &error, -ENOENT);
1918 r = session_stop(session);
1920 return bus_send_error_reply(connection, message, NULL, r);
1922 reply = dbus_message_new_method_return(message);
1926 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1930 if (!dbus_message_get_args(
1933 DBUS_TYPE_UINT32, &uid,
1935 return bus_send_error_reply(connection, message, &error, -EINVAL);
1937 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1939 return bus_send_error_reply(connection, message, &error, -ENOENT);
1941 r = user_stop(user);
1943 return bus_send_error_reply(connection, message, NULL, r);
1945 reply = dbus_message_new_method_return(message);
1949 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1953 if (!dbus_message_get_args(
1956 DBUS_TYPE_STRING, &name,
1958 return bus_send_error_reply(connection, message, &error, -EINVAL);
1960 seat = hashmap_get(m->seats, name);
1962 return bus_send_error_reply(connection, message, &error, -ENOENT);
1964 r = seat_stop_sessions(seat);
1966 return bus_send_error_reply(connection, message, NULL, r);
1968 reply = dbus_message_new_method_return(message);
1972 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
1975 dbus_bool_t b, interactive;
1978 if (!dbus_message_get_args(
1981 DBUS_TYPE_UINT32, &uid,
1982 DBUS_TYPE_BOOLEAN, &b,
1983 DBUS_TYPE_BOOLEAN, &interactive,
1985 return bus_send_error_reply(connection, message, &error, -EINVAL);
1990 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
1992 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
1994 return bus_send_error_reply(connection, message, &error, r);
1996 mkdir_p_label("/var/lib/systemd", 0755);
1998 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
2000 return bus_send_error_reply(connection, message, &error, r);
2002 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
2013 return bus_send_error_reply(connection, message, &error, r);
2015 if (manager_add_user_by_uid(m, uid, &u) >= 0)
2024 if (r < 0 && errno != ENOENT)
2025 return bus_send_error_reply(connection, message, &error, -errno);
2027 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
2029 user_add_to_gc_queue(u);
2032 reply = dbus_message_new_method_return(message);
2036 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
2037 const char *sysfs, *seat;
2038 dbus_bool_t interactive;
2040 if (!dbus_message_get_args(
2043 DBUS_TYPE_STRING, &seat,
2044 DBUS_TYPE_STRING, &sysfs,
2045 DBUS_TYPE_BOOLEAN, &interactive,
2047 return bus_send_error_reply(connection, message, &error, -EINVAL);
2049 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
2050 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2052 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
2054 return bus_send_error_reply(connection, message, &error, r);
2056 r = attach_device(m, seat, sysfs);
2058 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2060 reply = dbus_message_new_method_return(message);
2065 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
2066 dbus_bool_t interactive;
2068 if (!dbus_message_get_args(
2071 DBUS_TYPE_BOOLEAN, &interactive,
2073 return bus_send_error_reply(connection, message, &error, -EINVAL);
2075 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
2077 return bus_send_error_reply(connection, message, &error, r);
2079 r = flush_devices(m);
2081 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2083 reply = dbus_message_new_method_return(message);
2087 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
2089 r = bus_manager_do_shutdown_or_sleep(
2090 m, connection, message,
2091 SPECIAL_POWEROFF_TARGET,
2093 "org.freedesktop.login1.power-off",
2094 "org.freedesktop.login1.power-off-multiple-sessions",
2095 "org.freedesktop.login1.power-off-ignore-inhibit",
2099 return bus_send_error_reply(connection, message, &error, r);
2100 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
2101 r = bus_manager_do_shutdown_or_sleep(
2102 m, connection, message,
2103 SPECIAL_REBOOT_TARGET,
2105 "org.freedesktop.login1.reboot",
2106 "org.freedesktop.login1.reboot-multiple-sessions",
2107 "org.freedesktop.login1.reboot-ignore-inhibit",
2111 return bus_send_error_reply(connection, message, &error, r);
2113 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2114 r = bus_manager_do_shutdown_or_sleep(
2115 m, connection, message,
2116 SPECIAL_SUSPEND_TARGET,
2118 "org.freedesktop.login1.suspend",
2119 "org.freedesktop.login1.suspend-multiple-sessions",
2120 "org.freedesktop.login1.suspend-ignore-inhibit",
2124 return bus_send_error_reply(connection, message, &error, r);
2125 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2126 r = bus_manager_do_shutdown_or_sleep(
2127 m, connection, message,
2128 SPECIAL_HIBERNATE_TARGET,
2130 "org.freedesktop.login1.hibernate",
2131 "org.freedesktop.login1.hibernate-multiple-sessions",
2132 "org.freedesktop.login1.hibernate-ignore-inhibit",
2136 return bus_send_error_reply(connection, message, &error, r);
2138 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "HybridSleep")) {
2139 r = bus_manager_do_shutdown_or_sleep(
2140 m, connection, message,
2141 SPECIAL_HYBRID_SLEEP_TARGET,
2143 "org.freedesktop.login1.hibernate",
2144 "org.freedesktop.login1.hibernate-multiple-sessions",
2145 "org.freedesktop.login1.hibernate-ignore-inhibit",
2149 return bus_send_error_reply(connection, message, &error, r);
2151 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2153 r = bus_manager_can_shutdown_or_sleep(
2154 m, connection, message,
2156 "org.freedesktop.login1.power-off",
2157 "org.freedesktop.login1.power-off-multiple-sessions",
2158 "org.freedesktop.login1.power-off-ignore-inhibit",
2162 return bus_send_error_reply(connection, message, &error, r);
2163 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2164 r = bus_manager_can_shutdown_or_sleep(
2165 m, connection, message,
2167 "org.freedesktop.login1.reboot",
2168 "org.freedesktop.login1.reboot-multiple-sessions",
2169 "org.freedesktop.login1.reboot-ignore-inhibit",
2173 return bus_send_error_reply(connection, message, &error, r);
2175 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2176 r = bus_manager_can_shutdown_or_sleep(
2177 m, connection, message,
2179 "org.freedesktop.login1.suspend",
2180 "org.freedesktop.login1.suspend-multiple-sessions",
2181 "org.freedesktop.login1.suspend-ignore-inhibit",
2185 return bus_send_error_reply(connection, message, &error, r);
2187 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2188 r = bus_manager_can_shutdown_or_sleep(
2189 m, connection, message,
2191 "org.freedesktop.login1.hibernate",
2192 "org.freedesktop.login1.hibernate-multiple-sessions",
2193 "org.freedesktop.login1.hibernate-ignore-inhibit",
2197 return bus_send_error_reply(connection, message, &error, r);
2199 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHybridSleep")) {
2200 r = bus_manager_can_shutdown_or_sleep(
2201 m, connection, message,
2203 "org.freedesktop.login1.hibernate",
2204 "org.freedesktop.login1.hibernate-multiple-sessions",
2205 "org.freedesktop.login1.hibernate-ignore-inhibit",
2209 return bus_send_error_reply(connection, message, &error, r);
2211 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2212 char *introspection = NULL;
2221 if (!(reply = dbus_message_new_method_return(message)))
2224 /* We roll our own introspection code here, instead of
2225 * relying on bus_default_message_handler() because we
2226 * need to generate our introspection string
2229 if (!(f = open_memstream(&introspection, &size)))
2232 fputs(INTROSPECTION_BEGIN, f);
2234 HASHMAP_FOREACH(seat, m->seats, i) {
2235 p = bus_path_escape(seat->id);
2238 fprintf(f, "<node name=\"seat/%s\"/>", p);
2243 HASHMAP_FOREACH(user, m->users, i)
2244 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2246 HASHMAP_FOREACH(session, m->sessions, i) {
2247 p = bus_path_escape(session->id);
2250 fprintf(f, "<node name=\"session/%s\"/>", p);
2255 fputs(INTROSPECTION_END, f);
2259 free(introspection);
2268 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2269 free(introspection);
2273 free(introspection);
2275 const BusBoundProperties bps[] = {
2276 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2279 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2283 if (!bus_maybe_send_reply(connection, message, reply))
2286 dbus_message_unref(reply);
2289 return DBUS_HANDLER_RESULT_HANDLED;
2293 dbus_message_unref(reply);
2295 dbus_error_free(&error);
2297 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2300 const DBusObjectPathVTable bus_manager_vtable = {
2301 .message_function = manager_message_handler
2304 DBusHandlerResult bus_message_filter(
2305 DBusConnection *connection,
2306 DBusMessage *message,
2309 Manager *m = userdata;
2316 dbus_error_init(&error);
2318 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
2321 if (!dbus_message_get_args(message, &error,
2322 DBUS_TYPE_STRING, &cgroup,
2324 log_error("Failed to parse Released message: %s", bus_error_message(&error));
2326 manager_cgroup_notify_empty(m, cgroup);
2329 dbus_error_free(&error);
2331 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2334 int manager_send_changed(Manager *manager, const char *properties) {
2340 m = bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties);
2344 if (!dbus_connection_send(manager->bus, m, NULL))
2351 dbus_message_unref(m);
2356 int manager_dispatch_delayed(Manager *manager) {
2357 const char *unit_name;
2364 if (!manager->delayed_unit)
2367 /* Continue delay? */
2369 manager->delayed_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC) &&
2370 manager_is_inhibited(manager, manager->delayed_what, INHIBIT_DELAY, NULL, false, false, 0);
2374 bus_manager_log_shutdown(manager, manager->delayed_what, manager->delayed_unit);
2376 /* Reset delay data */
2377 unit_name = manager->delayed_unit;
2378 manager->delayed_unit = NULL;
2380 /* Actually do the shutdown */
2381 dbus_error_init(&error);
2382 r = send_start_unit(manager->bus, unit_name, &error);
2384 log_warning("Failed to send delayed message: %s", bus_error_message_or_strerror(&error, -r));
2385 dbus_error_free(&error);
2389 /* Tell people about it */
2390 send_prepare_for(manager, manager->delayed_what, false);