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=\"CanPowerOff\">\n" \
149 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
151 " <method name=\"CanReboot\">\n" \
152 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
154 " <method name=\"CanSuspend\">\n" \
155 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
157 " <method name=\"CanHibernate\">\n" \
158 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
160 " <method name=\"Inhibit\">\n" \
161 " <arg name=\"what\" type=\"s\" direction=\"in\"/>\n" \
162 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
163 " <arg name=\"why\" type=\"s\" direction=\"in\"/>\n" \
164 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
165 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
167 " <method name=\"ListInhibitors\">\n" \
168 " <arg name=\"inhibitors\" type=\"a(ssssuu)\" direction=\"out\"/>\n" \
170 " <signal name=\"SessionNew\">\n" \
171 " <arg name=\"id\" type=\"s\"/>\n" \
172 " <arg name=\"path\" type=\"o\"/>\n" \
174 " <signal name=\"SessionRemoved\">\n" \
175 " <arg name=\"id\" type=\"s\"/>\n" \
176 " <arg name=\"path\" type=\"o\"/>\n" \
178 " <signal name=\"UserNew\">\n" \
179 " <arg name=\"uid\" type=\"u\"/>\n" \
180 " <arg name=\"path\" type=\"o\"/>\n" \
182 " <signal name=\"UserRemoved\">\n" \
183 " <arg name=\"uid\" type=\"u\"/>\n" \
184 " <arg name=\"path\" type=\"o\"/>\n" \
186 " <signal name=\"SeatNew\">\n" \
187 " <arg name=\"id\" type=\"s\"/>\n" \
188 " <arg name=\"path\" type=\"o\"/>\n" \
190 " <signal name=\"SeatRemoved\">\n" \
191 " <arg name=\"id\" type=\"s\"/>\n" \
192 " <arg name=\"path\" type=\"o\"/>\n" \
194 " <signal name=\"PrepareForShutdown\">\n" \
195 " <arg name=\"active\" type=\"b\"/>\n" \
197 " <signal name=\"PrepareForSleep\">\n" \
198 " <arg name=\"active\" type=\"b\"/>\n" \
200 " <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
201 " <property name=\"Controllers\" type=\"as\" access=\"read\"/>\n" \
202 " <property name=\"ResetControllers\" type=\"as\" access=\"read\"/>\n" \
203 " <property name=\"NAutoVTs\" type=\"u\" access=\"read\"/>\n" \
204 " <property name=\"KillOnlyUsers\" type=\"as\" access=\"read\"/>\n" \
205 " <property name=\"KillExcludeUsers\" type=\"as\" access=\"read\"/>\n" \
206 " <property name=\"KillUserProcesses\" type=\"b\" access=\"read\"/>\n" \
207 " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
208 " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
209 " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
210 " <property name=\"BlockInhibited\" type=\"s\" access=\"read\"/>\n" \
211 " <property name=\"DelayInhibited\" type=\"s\" access=\"read\"/>\n" \
212 " <property name=\"InhibitDelayMaxUSec\" type=\"t\" access=\"read\"/>\n" \
213 " <property name=\"HandlePowerKey\" type=\"s\" access=\"read\"/>\n" \
214 " <property name=\"HandleSuspendKey\" type=\"s\" access=\"read\"/>\n" \
215 " <property name=\"HandleHibernateKey\" type=\"s\" access=\"read\"/>\n" \
216 " <property name=\"HandleLidSwitch\" type=\"s\" access=\"read\"/>\n" \
217 " <property name=\"PreparingForShutdown\" type=\"b\" access=\"read\"/>\n" \
218 " <property name=\"PreparingForSleep\" type=\"b\" access=\"read\"/>\n" \
221 #define INTROSPECTION_BEGIN \
222 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
224 BUS_MANAGER_INTERFACE \
225 BUS_PROPERTIES_INTERFACE \
227 BUS_INTROSPECTABLE_INTERFACE
229 #define INTROSPECTION_END \
232 #define INTERFACES_LIST \
233 BUS_GENERIC_INTERFACES_LIST \
234 "org.freedesktop.login1.Manager\0"
236 static int bus_manager_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
244 b = manager_get_idle_hint(m, NULL) > 0;
245 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
251 static int bus_manager_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
260 manager_get_idle_hint(m, &t);
261 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
263 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
269 static int bus_manager_append_inhibited(DBusMessageIter *i, const char *property, void *data) {
274 w = manager_inhibit_what(m, streq(property, "BlockInhibited") ? INHIBIT_BLOCK : INHIBIT_DELAY);
275 p = inhibit_what_to_string(w);
277 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &p))
283 static int bus_manager_append_preparing(DBusMessageIter *i, const char *property, void *data) {
290 if (streq(property, "PreparingForShutdown"))
291 b = !!(m->delayed_what & INHIBIT_SHUTDOWN);
293 b = !!(m->delayed_what & INHIBIT_SLEEP);
295 dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b);
299 static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMessage **_reply) {
300 Session *session = NULL;
302 const char *type, *class, *seat, *tty, *display, *remote_user, *remote_host, *service;
303 uint32_t uid, leader, audit_id = 0;
304 dbus_bool_t remote, kill_processes, exists;
305 char **controllers = NULL, **reset_controllers = NULL;
309 DBusMessageIter iter;
314 DBusMessage *reply = NULL;
321 if (!dbus_message_iter_init(message, &iter) ||
322 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
325 dbus_message_iter_get_basic(&iter, &uid);
327 if (!dbus_message_iter_next(&iter) ||
328 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
331 dbus_message_iter_get_basic(&iter, &leader);
334 !dbus_message_iter_next(&iter) ||
335 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
338 dbus_message_iter_get_basic(&iter, &service);
340 if (!dbus_message_iter_next(&iter) ||
341 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
344 dbus_message_iter_get_basic(&iter, &type);
345 t = session_type_from_string(type);
348 !dbus_message_iter_next(&iter) ||
349 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
352 dbus_message_iter_get_basic(&iter, &class);
356 c = session_class_from_string(class);
359 !dbus_message_iter_next(&iter) ||
360 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
363 dbus_message_iter_get_basic(&iter, &seat);
368 s = hashmap_get(m->seats, seat);
373 if (!dbus_message_iter_next(&iter) ||
374 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
377 dbus_message_iter_get_basic(&iter, &vtnr);
379 if (!dbus_message_iter_next(&iter) ||
380 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
383 dbus_message_iter_get_basic(&iter, &tty);
385 if (tty_is_vc(tty)) {
390 else if (s != m->vtconsole)
393 v = vtnr_from_tty(tty);
396 return v < 0 ? v : -EINVAL;
400 else if (vtnr != (uint32_t) v)
402 } else if (tty_is_console(tty)) {
406 else if (s != m->vtconsole)
412 } else if (!isempty(tty) && s && seat_is_vtconsole(s))
416 if (seat_can_multi_session(s)) {
425 if (!dbus_message_iter_next(&iter) ||
426 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
429 dbus_message_iter_get_basic(&iter, &display);
431 if (!dbus_message_iter_next(&iter) ||
432 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
435 dbus_message_iter_get_basic(&iter, &remote);
437 if (!dbus_message_iter_next(&iter) ||
438 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
441 dbus_message_iter_get_basic(&iter, &remote_user);
443 if (!dbus_message_iter_next(&iter) ||
444 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
447 dbus_message_iter_get_basic(&iter, &remote_host);
449 if (!dbus_message_iter_next(&iter) ||
450 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
451 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
454 r = bus_parse_strv_iter(&iter, &controllers);
458 if (strv_contains(controllers, "systemd") ||
459 !dbus_message_iter_next(&iter) ||
460 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
461 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) {
466 r = bus_parse_strv_iter(&iter, &reset_controllers);
470 if (strv_contains(reset_controllers, "systemd") ||
471 !dbus_message_iter_next(&iter) ||
472 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) {
477 dbus_message_iter_get_basic(&iter, &kill_processes);
479 r = manager_add_user_by_uid(m, uid, &user);
483 audit_session_from_pid(leader, &audit_id);
486 asprintf(&id, "%lu", (unsigned long) audit_id);
493 session = hashmap_get(m->sessions, id);
498 fifo_fd = session_create_fifo(session);
504 /* Session already exists, client is probably
505 * something like "su" which changes uid but
506 * is still the same audit session */
508 reply = dbus_message_new_method_return(message);
514 p = session_bus_path(session);
520 seat = session->seat ? session->seat->id : "";
521 vtnr = session->vtnr;
524 b = dbus_message_append_args(
526 DBUS_TYPE_STRING, &session->id,
527 DBUS_TYPE_OBJECT_PATH, &p,
528 DBUS_TYPE_STRING, &session->user->runtime_path,
529 DBUS_TYPE_UNIX_FD, &fifo_fd,
530 DBUS_TYPE_STRING, &seat,
531 DBUS_TYPE_UINT32, &vtnr,
532 DBUS_TYPE_BOOLEAN, &exists,
541 close_nointr_nofail(fifo_fd);
544 strv_free(controllers);
545 strv_free(reset_controllers);
555 if (asprintf(&id, "c%lu", ++m->session_counter) < 0) {
560 } while (hashmap_get(m->sessions, id));
563 r = manager_add_session(m, user, id, &session);
568 session->leader = leader;
569 session->audit_id = audit_id;
572 session->remote = remote;
573 session->controllers = controllers;
574 session->reset_controllers = reset_controllers;
575 session->kill_processes = kill_processes;
576 session->vtnr = vtnr;
578 controllers = reset_controllers = NULL;
581 session->tty = strdup(tty);
588 if (!isempty(display)) {
589 session->display = strdup(display);
590 if (!session->display) {
596 if (!isempty(remote_user)) {
597 session->remote_user = strdup(remote_user);
598 if (!session->remote_user) {
604 if (!isempty(remote_host)) {
605 session->remote_host = strdup(remote_host);
606 if (!session->remote_host) {
612 if (!isempty(service)) {
613 session->service = strdup(service);
614 if (!session->service) {
620 fifo_fd = session_create_fifo(session);
627 r = seat_attach_session(s, session);
632 r = session_start(session);
636 reply = dbus_message_new_method_return(message);
642 p = session_bus_path(session);
648 seat = s ? s->id : "";
650 b = dbus_message_append_args(
652 DBUS_TYPE_STRING, &session->id,
653 DBUS_TYPE_OBJECT_PATH, &p,
654 DBUS_TYPE_STRING, &session->user->runtime_path,
655 DBUS_TYPE_UNIX_FD, &fifo_fd,
656 DBUS_TYPE_STRING, &seat,
657 DBUS_TYPE_UINT32, &vtnr,
658 DBUS_TYPE_BOOLEAN, &exists,
667 close_nointr_nofail(fifo_fd);
673 strv_free(controllers);
674 strv_free(reset_controllers);
677 session_add_to_gc_queue(session);
680 user_add_to_gc_queue(user);
683 close_nointr_nofail(fifo_fd);
686 dbus_message_unref(reply);
691 static int bus_manager_inhibit(Manager *m, DBusConnection *connection, DBusMessage *message, DBusError *error, DBusMessage **_reply) {
694 const char *who, *why, *what, *mode;
700 DBusMessage *reply = NULL;
708 if (!dbus_message_get_args(
711 DBUS_TYPE_STRING, &what,
712 DBUS_TYPE_STRING, &who,
713 DBUS_TYPE_STRING, &why,
714 DBUS_TYPE_STRING, &mode,
715 DBUS_TYPE_INVALID)) {
720 w = inhibit_what_from_string(what);
726 mm = inhibit_mode_from_string(mode);
732 /* Delay is only supported for shutdown/sleep */
733 if (mm == INHIBIT_DELAY && (w & ~(INHIBIT_SHUTDOWN|INHIBIT_SLEEP))) {
738 r = verify_polkit(connection, message,
739 w == INHIBIT_SHUTDOWN ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
740 w == INHIBIT_SLEEP ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep" : "org.freedesktop.login1.inhibit-delay-sleep") :
741 w == INHIBIT_IDLE ? "org.freedesktop.login1.inhibit-block-idle" :
742 w == INHIBIT_HANDLE_POWER_KEY ? "org.freedesktop.login1.inhibit-handle-power-key" :
743 w == INHIBIT_HANDLE_SUSPEND_KEY ? "org.freedesktop.login1.inhibit-handle-suspend-key" :
744 w == INHIBIT_HANDLE_HIBERNATE_KEY ? "org.freedesktop.login1.inhibit-handle-hibernate-key" :
745 "org.freedesktop.login1.inhibit-handle-lid-switch",
750 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
751 if (ul == (unsigned long) -1) {
756 pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
766 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
770 } while (hashmap_get(m->inhibitors, id));
772 r = manager_add_inhibitor(m, id, &i);
782 i->why = strdup(why);
783 i->who = strdup(who);
785 if (!i->why || !i->who) {
790 fifo_fd = inhibitor_create_fifo(i);
796 reply = dbus_message_new_method_return(message);
802 if (!dbus_message_append_args(
804 DBUS_TYPE_UNIX_FD, &fifo_fd,
805 DBUS_TYPE_INVALID)) {
810 close_nointr_nofail(fifo_fd);
822 close_nointr_nofail(fifo_fd);
825 dbus_message_unref(reply);
830 static int trigger_device(Manager *m, struct udev_device *d) {
831 struct udev_enumerate *e;
832 struct udev_list_entry *first, *item;
837 e = udev_enumerate_new(m->udev);
844 if (udev_enumerate_add_match_parent(e, d) < 0) {
850 if (udev_enumerate_scan_devices(e) < 0) {
855 first = udev_enumerate_get_list_entry(e);
856 udev_list_entry_foreach(item, first) {
860 p = udev_list_entry_get_name(item);
862 t = strappend(p, "/uevent");
868 write_one_line_file(t, "change");
876 udev_enumerate_unref(e);
881 static int attach_device(Manager *m, const char *seat, const char *sysfs) {
882 struct udev_device *d;
883 char *rule = NULL, *file = NULL;
884 const char *id_for_seat;
891 d = udev_device_new_from_syspath(m->udev, sysfs);
895 if (!udev_device_has_tag(d, "seat")) {
900 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
906 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
911 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
916 mkdir_p_label("/etc/udev/rules.d", 0755);
917 r = write_one_line_file_atomic(file, rule);
921 r = trigger_device(m, d);
928 udev_device_unref(d);
933 static int flush_devices(Manager *m) {
938 d = opendir("/etc/udev/rules.d");
941 log_warning("Failed to open /etc/udev/rules.d: %m");
945 while ((de = readdir(d))) {
947 if (!dirent_is_file(de))
950 if (!startswith(de->d_name, "72-seat-"))
953 if (!endswith(de->d_name, ".rules"))
956 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
957 log_warning("Failed to unlink %s: %m", de->d_name);
963 return trigger_device(m, NULL);
966 static int have_multiple_sessions(
975 /* Check for other users' sessions. Greeter sessions do not count. */
976 HASHMAP_FOREACH(session, m->sessions, i)
977 if (session->class == SESSION_USER && session->user->uid != uid)
983 static int send_start_unit(DBusConnection *connection, const char *unit_name, DBusError *error) {
984 const char *mode = "replace";
988 return bus_method_call_with_reply (
990 "org.freedesktop.systemd1",
991 "/org/freedesktop/systemd1",
992 "org.freedesktop.systemd1.Manager",
996 DBUS_TYPE_STRING, &unit_name,
997 DBUS_TYPE_STRING, &mode,
1001 static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
1002 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
1003 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
1004 [INHIBIT_SLEEP] = "PrepareForSleep"
1007 dbus_bool_t active = _active;
1008 DBusMessage *message;
1013 assert(w < _INHIBIT_WHAT_MAX);
1014 assert(signal_name[w]);
1016 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1020 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1021 !dbus_connection_send(m->bus, message, NULL))
1024 dbus_message_unref(message);
1028 static int delay_shutdown_or_sleep(Manager *m, InhibitWhat w, const char *unit_name) {
1031 assert(w < _INHIBIT_WHAT_MAX);
1033 /* Tell everybody to prepare for shutdown/sleep */
1034 send_prepare_for(m, w, true);
1036 /* Update timestamp for timeout */
1037 if (!m->delayed_unit)
1038 m->delayed_timestamp = now(CLOCK_MONOTONIC);
1040 /* Remember what we want to do, possibly overriding what kind
1041 * of unit we previously queued. */
1042 m->delayed_unit = unit_name;
1043 m->delayed_what = w;
1048 static int bus_manager_can_shutdown_or_sleep(
1050 DBusConnection *connection,
1051 DBusMessage *message,
1054 const char *action_multiple_sessions,
1055 const char *action_ignore_inhibit,
1056 const char *sleep_type,
1058 DBusMessage **_reply) {
1060 bool multiple_sessions, challenge, blocked, b;
1062 DBusMessage *reply = NULL;
1070 assert(w <= _INHIBIT_WHAT_MAX);
1072 assert(action_multiple_sessions);
1073 assert(action_ignore_inhibit);
1078 r = can_sleep(sleep_type);
1088 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1089 if (ul == (unsigned long) -1)
1092 r = have_multiple_sessions(m, (uid_t) ul);
1096 multiple_sessions = r > 0;
1097 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1099 if (multiple_sessions) {
1100 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1107 result = "challenge";
1113 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1117 if (r > 0 && !result)
1119 else if (challenge && (!result || streq(result, "yes")))
1120 result = "challenge";
1125 if (!multiple_sessions && !blocked) {
1126 /* If neither inhibit nor multiple sessions
1127 * apply then just check the normal policy */
1129 r = verify_polkit(connection, message, action, false, &challenge, error);
1136 result = "challenge";
1142 reply = dbus_message_new_method_return(message);
1146 b = dbus_message_append_args(
1148 DBUS_TYPE_STRING, &result,
1151 dbus_message_unref(reply);
1159 static int bus_manager_log_shutdown(
1162 const char *unit_name) {
1169 if (w != INHIBIT_SHUTDOWN)
1172 if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
1173 p = "MESSAGE=System is powering down.";
1174 q = "SHUTDOWN=power-off";
1175 } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
1176 p = "MESSAGE=System is halting.";
1177 q = "SHUTDOWN=halt";
1178 } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
1179 p = "MESSAGE=System is rebooting.";
1180 q = "SHUTDOWN=reboot";
1181 } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
1182 p = "MESSAGE=System is rebooting with kexec.";
1183 q = "SHUTDOWN=kexec";
1185 p = "MESSAGE=System is shutting down.";
1189 return log_struct(LOG_NOTICE, MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
1194 int bus_manager_shutdown_or_sleep_now_or_later(
1196 const char *unit_name,
1206 assert(w <= _INHIBIT_WHAT_MAX);
1209 m->inhibit_delay_max > 0 &&
1210 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0);
1213 /* Shutdown is delayed, keep in mind what we
1214 * want to do, and start a timeout */
1215 r = delay_shutdown_or_sleep(m, w, unit_name);
1217 bus_manager_log_shutdown(m, w, unit_name);
1219 /* Shutdown is not delayed, execute it
1221 r = send_start_unit(m->bus, unit_name, error);
1227 static int bus_manager_do_shutdown_or_sleep(
1229 DBusConnection *connection,
1230 DBusMessage *message,
1231 const char *unit_name,
1234 const char *action_multiple_sessions,
1235 const char *action_ignore_inhibit,
1236 const char *sleep_type,
1238 DBusMessage **_reply) {
1240 dbus_bool_t interactive;
1241 bool multiple_sessions, blocked;
1242 DBusMessage *reply = NULL;
1251 assert(w <= _INHIBIT_WHAT_MAX);
1253 assert(action_multiple_sessions);
1254 assert(action_ignore_inhibit);
1258 if (!dbus_message_get_args(
1261 DBUS_TYPE_BOOLEAN, &interactive,
1266 r = can_sleep(sleep_type);
1274 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1275 if (ul == (unsigned long) -1)
1278 r = have_multiple_sessions(m, (uid_t) ul);
1282 multiple_sessions = r > 0;
1283 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1285 if (multiple_sessions) {
1286 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1292 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1297 if (!multiple_sessions && !blocked) {
1298 r = verify_polkit(connection, message, action, interactive, NULL, error);
1303 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
1307 reply = dbus_message_new_method_return(message);
1315 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_button, handle_button, HandleButton);
1317 static const BusProperty bus_login_manager_properties[] = {
1318 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_path), true },
1319 { "Controllers", bus_property_append_strv, "as", offsetof(Manager, controllers), true },
1320 { "ResetControllers", bus_property_append_strv, "as", offsetof(Manager, reset_controllers), true },
1321 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1322 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1323 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1324 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1325 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1326 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1327 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
1328 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1329 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1330 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
1331 { "HandlePowerKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_power_key) },
1332 { "HandleSuspendKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_suspend_key) },
1333 { "HandleHibernateKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_hibernate_key)},
1334 { "HandleLidSwitch", bus_manager_append_handle_button, "s", offsetof(Manager, handle_lid_switch) },
1335 { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
1336 { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
1340 static DBusHandlerResult manager_message_handler(
1341 DBusConnection *connection,
1342 DBusMessage *message,
1345 Manager *m = userdata;
1348 DBusMessage *reply = NULL;
1355 dbus_error_init(&error);
1357 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1363 if (!dbus_message_get_args(
1366 DBUS_TYPE_STRING, &name,
1368 return bus_send_error_reply(connection, message, &error, -EINVAL);
1370 session = hashmap_get(m->sessions, name);
1372 return bus_send_error_reply(connection, message, &error, -ENOENT);
1374 reply = dbus_message_new_method_return(message);
1378 p = session_bus_path(session);
1382 b = dbus_message_append_args(
1384 DBUS_TYPE_OBJECT_PATH, &p,
1391 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1397 if (!dbus_message_get_args(
1400 DBUS_TYPE_UINT32, &pid,
1402 return bus_send_error_reply(connection, message, &error, -EINVAL);
1404 r = manager_get_session_by_pid(m, pid, &session);
1406 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -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", "GetUser")) {
1431 if (!dbus_message_get_args(
1434 DBUS_TYPE_UINT32, &uid,
1436 return bus_send_error_reply(connection, message, &error, -EINVAL);
1438 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1440 return bus_send_error_reply(connection, message, &error, -ENOENT);
1442 reply = dbus_message_new_method_return(message);
1446 p = user_bus_path(user);
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", "GetSeat")) {
1465 if (!dbus_message_get_args(
1468 DBUS_TYPE_STRING, &name,
1470 return bus_send_error_reply(connection, message, &error, -EINVAL);
1472 seat = hashmap_get(m->seats, name);
1474 return bus_send_error_reply(connection, message, &error, -ENOENT);
1476 reply = dbus_message_new_method_return(message);
1480 p = seat_bus_path(seat);
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", "ListSessions")) {
1497 DBusMessageIter iter, sub;
1498 const char *empty = "";
1500 reply = dbus_message_new_method_return(message);
1504 dbus_message_iter_init_append(reply, &iter);
1506 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1509 HASHMAP_FOREACH(session, m->sessions, i) {
1510 DBusMessageIter sub2;
1513 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1516 uid = session->user->uid;
1518 p = session_bus_path(session);
1522 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1523 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1524 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1525 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1526 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1533 if (!dbus_message_iter_close_container(&sub, &sub2))
1537 if (!dbus_message_iter_close_container(&iter, &sub))
1540 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1544 DBusMessageIter iter, sub;
1546 reply = dbus_message_new_method_return(message);
1550 dbus_message_iter_init_append(reply, &iter);
1552 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1555 HASHMAP_FOREACH(user, m->users, i) {
1556 DBusMessageIter sub2;
1559 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1564 p = user_bus_path(user);
1568 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1569 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1570 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1577 if (!dbus_message_iter_close_container(&sub, &sub2))
1581 if (!dbus_message_iter_close_container(&iter, &sub))
1584 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1588 DBusMessageIter iter, sub;
1590 reply = dbus_message_new_method_return(message);
1594 dbus_message_iter_init_append(reply, &iter);
1596 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1599 HASHMAP_FOREACH(seat, m->seats, i) {
1600 DBusMessageIter sub2;
1602 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1605 p = seat_bus_path(seat);
1609 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1610 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1617 if (!dbus_message_iter_close_container(&sub, &sub2))
1621 if (!dbus_message_iter_close_container(&iter, &sub))
1624 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1625 Inhibitor *inhibitor;
1627 DBusMessageIter iter, sub;
1629 reply = dbus_message_new_method_return(message);
1633 dbus_message_iter_init_append(reply, &iter);
1635 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1638 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1639 DBusMessageIter sub2;
1640 dbus_uint32_t uid, pid;
1641 const char *what, *who, *why, *mode;
1643 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1646 what = strempty(inhibit_what_to_string(inhibitor->what));
1647 who = strempty(inhibitor->who);
1648 why = strempty(inhibitor->why);
1649 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
1650 uid = (dbus_uint32_t) inhibitor->uid;
1651 pid = (dbus_uint32_t) inhibitor->pid;
1653 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1654 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1655 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1656 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
1657 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1658 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1661 if (!dbus_message_iter_close_container(&sub, &sub2))
1665 if (!dbus_message_iter_close_container(&iter, &sub))
1668 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1670 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1673 return bus_send_error_reply(connection, message, &error, r);
1676 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1678 r = bus_manager_create_session(m, message, &reply);
1680 /* Don't delay the work on OOM here, since it might be
1681 * triggered by a low RLIMIT_NOFILE here (since we
1682 * send a dupped fd to the client), and we'd rather
1683 * see this fail quickly then be retried later */
1686 return bus_send_error_reply(connection, message, NULL, r);
1688 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1692 if (!dbus_message_get_args(
1695 DBUS_TYPE_STRING, &name,
1697 return bus_send_error_reply(connection, message, &error, -EINVAL);
1699 session = hashmap_get(m->sessions, name);
1701 return bus_send_error_reply(connection, message, &error, -ENOENT);
1703 /* We use the FIFO to detect stray sessions where the
1704 process invoking PAM dies abnormally. We need to make
1705 sure that that process is not killed if at the clean
1706 end of the session it closes the FIFO. Hence, with
1707 this call explicitly turn off the FIFO logic, so that
1708 the PAM code can finish clean up on its own */
1709 session_remove_fifo(session);
1711 reply = dbus_message_new_method_return(message);
1715 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1719 if (!dbus_message_get_args(
1722 DBUS_TYPE_STRING, &name,
1724 return bus_send_error_reply(connection, message, &error, -EINVAL);
1726 session = hashmap_get(m->sessions, name);
1728 return bus_send_error_reply(connection, message, &error, -ENOENT);
1730 r = session_activate(session);
1732 return bus_send_error_reply(connection, message, NULL, r);
1734 reply = dbus_message_new_method_return(message);
1738 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1739 const char *session_name, *seat_name;
1743 /* Same as ActivateSession() but refuses to work if
1744 * the seat doesn't match */
1746 if (!dbus_message_get_args(
1749 DBUS_TYPE_STRING, &session_name,
1750 DBUS_TYPE_STRING, &seat_name,
1752 return bus_send_error_reply(connection, message, &error, -EINVAL);
1754 session = hashmap_get(m->sessions, session_name);
1756 return bus_send_error_reply(connection, message, &error, -ENOENT);
1758 seat = hashmap_get(m->seats, seat_name);
1760 return bus_send_error_reply(connection, message, &error, -ENOENT);
1762 if (session->seat != seat)
1763 return bus_send_error_reply(connection, message, &error, -EINVAL);
1765 r = session_activate(session);
1767 return bus_send_error_reply(connection, message, NULL, r);
1769 reply = dbus_message_new_method_return(message);
1773 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1774 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1778 if (!dbus_message_get_args(
1781 DBUS_TYPE_STRING, &name,
1783 return bus_send_error_reply(connection, message, &error, -EINVAL);
1785 session = hashmap_get(m->sessions, name);
1787 return bus_send_error_reply(connection, message, &error, -ENOENT);
1789 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1792 reply = dbus_message_new_method_return(message);
1796 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions")) {
1800 HASHMAP_FOREACH(session, m->sessions, i)
1801 if (session_send_lock(session, true) < 0)
1804 reply = dbus_message_new_method_return(message);
1808 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1815 if (!dbus_message_get_args(
1818 DBUS_TYPE_STRING, &name,
1819 DBUS_TYPE_STRING, &swho,
1820 DBUS_TYPE_INT32, &signo,
1822 return bus_send_error_reply(connection, message, &error, -EINVAL);
1827 who = kill_who_from_string(swho);
1829 return bus_send_error_reply(connection, message, &error, -EINVAL);
1832 if (signo <= 0 || signo >= _NSIG)
1833 return bus_send_error_reply(connection, message, &error, -EINVAL);
1835 session = hashmap_get(m->sessions, name);
1837 return bus_send_error_reply(connection, message, &error, -ENOENT);
1839 r = session_kill(session, who, signo);
1841 return bus_send_error_reply(connection, message, NULL, r);
1843 reply = dbus_message_new_method_return(message);
1847 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1852 if (!dbus_message_get_args(
1855 DBUS_TYPE_UINT32, &uid,
1856 DBUS_TYPE_INT32, &signo,
1858 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 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1865 return bus_send_error_reply(connection, message, &error, -ENOENT);
1867 r = user_kill(user, 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", "TerminateSession")) {
1879 if (!dbus_message_get_args(
1882 DBUS_TYPE_STRING, &name,
1884 return bus_send_error_reply(connection, message, &error, -EINVAL);
1886 session = hashmap_get(m->sessions, name);
1888 return bus_send_error_reply(connection, message, &error, -ENOENT);
1890 r = session_stop(session);
1892 return bus_send_error_reply(connection, message, NULL, r);
1894 reply = dbus_message_new_method_return(message);
1898 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1902 if (!dbus_message_get_args(
1905 DBUS_TYPE_UINT32, &uid,
1907 return bus_send_error_reply(connection, message, &error, -EINVAL);
1909 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1911 return bus_send_error_reply(connection, message, &error, -ENOENT);
1913 r = user_stop(user);
1915 return bus_send_error_reply(connection, message, NULL, r);
1917 reply = dbus_message_new_method_return(message);
1921 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1925 if (!dbus_message_get_args(
1928 DBUS_TYPE_STRING, &name,
1930 return bus_send_error_reply(connection, message, &error, -EINVAL);
1932 seat = hashmap_get(m->seats, name);
1934 return bus_send_error_reply(connection, message, &error, -ENOENT);
1936 r = seat_stop_sessions(seat);
1938 return bus_send_error_reply(connection, message, NULL, r);
1940 reply = dbus_message_new_method_return(message);
1944 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
1947 dbus_bool_t b, interactive;
1950 if (!dbus_message_get_args(
1953 DBUS_TYPE_UINT32, &uid,
1954 DBUS_TYPE_BOOLEAN, &b,
1955 DBUS_TYPE_BOOLEAN, &interactive,
1957 return bus_send_error_reply(connection, message, &error, -EINVAL);
1962 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
1964 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
1966 return bus_send_error_reply(connection, message, &error, r);
1968 mkdir_p_label("/var/lib/systemd", 0755);
1970 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
1972 return bus_send_error_reply(connection, message, &error, r);
1974 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
1985 return bus_send_error_reply(connection, message, &error, r);
1987 if (manager_add_user_by_uid(m, uid, &u) >= 0)
1996 if (r < 0 && errno != ENOENT)
1997 return bus_send_error_reply(connection, message, &error, -errno);
1999 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
2001 user_add_to_gc_queue(u);
2004 reply = dbus_message_new_method_return(message);
2008 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
2009 const char *sysfs, *seat;
2010 dbus_bool_t interactive;
2012 if (!dbus_message_get_args(
2015 DBUS_TYPE_STRING, &seat,
2016 DBUS_TYPE_STRING, &sysfs,
2017 DBUS_TYPE_BOOLEAN, &interactive,
2019 return bus_send_error_reply(connection, message, &error, -EINVAL);
2021 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
2022 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2024 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
2026 return bus_send_error_reply(connection, message, &error, r);
2028 r = attach_device(m, seat, sysfs);
2030 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2032 reply = dbus_message_new_method_return(message);
2037 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
2038 dbus_bool_t interactive;
2040 if (!dbus_message_get_args(
2043 DBUS_TYPE_BOOLEAN, &interactive,
2045 return bus_send_error_reply(connection, message, &error, -EINVAL);
2047 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
2049 return bus_send_error_reply(connection, message, &error, r);
2051 r = flush_devices(m);
2053 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2055 reply = dbus_message_new_method_return(message);
2059 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
2061 r = bus_manager_do_shutdown_or_sleep(
2062 m, connection, message,
2063 SPECIAL_POWEROFF_TARGET,
2065 "org.freedesktop.login1.power-off",
2066 "org.freedesktop.login1.power-off-multiple-sessions",
2067 "org.freedesktop.login1.power-off-ignore-inhibit",
2071 return bus_send_error_reply(connection, message, &error, r);
2072 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
2073 r = bus_manager_do_shutdown_or_sleep(
2074 m, connection, message,
2075 SPECIAL_REBOOT_TARGET,
2077 "org.freedesktop.login1.reboot",
2078 "org.freedesktop.login1.reboot-multiple-sessions",
2079 "org.freedesktop.login1.reboot-ignore-inhibit",
2083 return bus_send_error_reply(connection, message, &error, r);
2085 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2086 r = bus_manager_do_shutdown_or_sleep(
2087 m, connection, message,
2088 SPECIAL_SUSPEND_TARGET,
2090 "org.freedesktop.login1.suspend",
2091 "org.freedesktop.login1.suspend-multiple-sessions",
2092 "org.freedesktop.login1.suspend-ignore-inhibit",
2096 return bus_send_error_reply(connection, message, &error, r);
2097 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2098 r = bus_manager_do_shutdown_or_sleep(
2099 m, connection, message,
2100 SPECIAL_HIBERNATE_TARGET,
2102 "org.freedesktop.login1.hibernate",
2103 "org.freedesktop.login1.hibernate-multiple-sessions",
2104 "org.freedesktop.login1.hibernate-ignore-inhibit",
2108 return bus_send_error_reply(connection, message, &error, r);
2110 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2112 r = bus_manager_can_shutdown_or_sleep(
2113 m, connection, message,
2115 "org.freedesktop.login1.power-off",
2116 "org.freedesktop.login1.power-off-multiple-sessions",
2117 "org.freedesktop.login1.power-off-ignore-inhibit",
2121 return bus_send_error_reply(connection, message, &error, r);
2122 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2123 r = bus_manager_can_shutdown_or_sleep(
2124 m, connection, message,
2126 "org.freedesktop.login1.reboot",
2127 "org.freedesktop.login1.reboot-multiple-sessions",
2128 "org.freedesktop.login1.reboot-ignore-inhibit",
2132 return bus_send_error_reply(connection, message, &error, r);
2134 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2135 r = bus_manager_can_shutdown_or_sleep(
2136 m, connection, message,
2138 "org.freedesktop.login1.suspend",
2139 "org.freedesktop.login1.suspend-multiple-sessions",
2140 "org.freedesktop.login1.suspend-ignore-inhibit",
2144 return bus_send_error_reply(connection, message, &error, r);
2146 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2147 r = bus_manager_can_shutdown_or_sleep(
2148 m, connection, message,
2150 "org.freedesktop.login1.hibernate",
2151 "org.freedesktop.login1.hibernate-multiple-sessions",
2152 "org.freedesktop.login1.hibernate-ignore-inhibit",
2156 return bus_send_error_reply(connection, message, &error, r);
2158 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2159 char *introspection = NULL;
2168 if (!(reply = dbus_message_new_method_return(message)))
2171 /* We roll our own introspection code here, instead of
2172 * relying on bus_default_message_handler() because we
2173 * need to generate our introspection string
2176 if (!(f = open_memstream(&introspection, &size)))
2179 fputs(INTROSPECTION_BEGIN, f);
2181 HASHMAP_FOREACH(seat, m->seats, i) {
2182 p = bus_path_escape(seat->id);
2185 fprintf(f, "<node name=\"seat/%s\"/>", p);
2190 HASHMAP_FOREACH(user, m->users, i)
2191 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2193 HASHMAP_FOREACH(session, m->sessions, i) {
2194 p = bus_path_escape(session->id);
2197 fprintf(f, "<node name=\"session/%s\"/>", p);
2202 fputs(INTROSPECTION_END, f);
2206 free(introspection);
2215 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2216 free(introspection);
2220 free(introspection);
2222 const BusBoundProperties bps[] = {
2223 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2226 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2230 if (!dbus_connection_send(connection, reply, NULL))
2233 dbus_message_unref(reply);
2236 return DBUS_HANDLER_RESULT_HANDLED;
2240 dbus_message_unref(reply);
2242 dbus_error_free(&error);
2244 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2247 const DBusObjectPathVTable bus_manager_vtable = {
2248 .message_function = manager_message_handler
2251 DBusHandlerResult bus_message_filter(
2252 DBusConnection *connection,
2253 DBusMessage *message,
2256 Manager *m = userdata;
2263 dbus_error_init(&error);
2265 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
2268 if (!dbus_message_get_args(message, &error,
2269 DBUS_TYPE_STRING, &cgroup,
2271 log_error("Failed to parse Released message: %s", bus_error_message(&error));
2273 manager_cgroup_notify_empty(m, cgroup);
2276 dbus_error_free(&error);
2278 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2281 int manager_send_changed(Manager *manager, const char *properties) {
2287 m = bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties);
2291 if (!dbus_connection_send(manager->bus, m, NULL))
2298 dbus_message_unref(m);
2303 int manager_dispatch_delayed(Manager *manager) {
2304 const char *unit_name;
2311 if (!manager->delayed_unit)
2314 /* Continue delay? */
2316 manager->delayed_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC) &&
2317 manager_is_inhibited(manager, manager->delayed_what, INHIBIT_DELAY, NULL, false, false, 0);
2321 bus_manager_log_shutdown(manager, manager->delayed_what, manager->delayed_unit);
2323 /* Reset delay data */
2324 unit_name = manager->delayed_unit;
2325 manager->delayed_unit = NULL;
2327 /* Actually do the shutdown */
2328 dbus_error_init(&error);
2329 r = send_start_unit(manager->bus, unit_name, &error);
2331 log_warning("Failed to send delayed message: %s", bus_error_message_or_strerror(&error, -r));
2332 dbus_error_free(&error);
2336 /* Tell people about it */
2337 send_prepare_for(manager, manager->delayed_what, false);