1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
28 #include "dbus-common.h"
31 #include "path-util.h"
34 #include "systemd/sd-id128.h"
35 #include "systemd/sd-messages.h"
37 #define BUS_MANAGER_INTERFACE \
38 " <interface name=\"org.freedesktop.login1.Manager\">\n" \
39 " <method name=\"GetSession\">\n" \
40 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
41 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
43 " <method name=\"GetSessionByPID\">\n" \
44 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
45 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
47 " <method name=\"GetUser\">\n" \
48 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
49 " <arg name=\"user\" type=\"o\" direction=\"out\"/>\n" \
51 " <method name=\"GetSeat\">\n" \
52 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
53 " <arg name=\"seat\" type=\"o\" direction=\"out\"/>\n" \
55 " <method name=\"ListSessions\">\n" \
56 " <arg name=\"sessions\" type=\"a(susso)\" direction=\"out\"/>\n" \
58 " <method name=\"ListUsers\">\n" \
59 " <arg name=\"users\" type=\"a(uso)\" direction=\"out\"/>\n" \
61 " <method name=\"ListSeats\">\n" \
62 " <arg name=\"seats\" type=\"a(so)\" direction=\"out\"/>\n" \
64 " <method name=\"CreateSession\">\n" \
65 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
66 " <arg name=\"leader\" type=\"u\" direction=\"in\"/>\n" \
67 " <arg name=\"sevice\" type=\"s\" direction=\"in\"/>\n" \
68 " <arg name=\"type\" type=\"s\" direction=\"in\"/>\n" \
69 " <arg name=\"class\" type=\"s\" direction=\"in\"/>\n" \
70 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
71 " <arg name=\"vtnr\" type=\"u\" direction=\"in\"/>\n" \
72 " <arg name=\"tty\" type=\"s\" direction=\"in\"/>\n" \
73 " <arg name=\"display\" type=\"s\" direction=\"in\"/>\n" \
74 " <arg name=\"remote\" type=\"b\" direction=\"in\"/>\n" \
75 " <arg name=\"remote_user\" type=\"s\" direction=\"in\"/>\n" \
76 " <arg name=\"remote_host\" type=\"s\" direction=\"in\"/>\n" \
77 " <arg name=\"controllers\" type=\"as\" direction=\"in\"/>\n" \
78 " <arg name=\"reset_controllers\" type=\"as\" direction=\"in\"/>\n" \
79 " <arg name=\"kill_processes\" type=\"b\" direction=\"in\"/>\n" \
80 " <arg name=\"id\" type=\"s\" direction=\"out\"/>\n" \
81 " <arg name=\"path\" type=\"o\" direction=\"out\"/>\n" \
82 " <arg name=\"runtime_path\" type=\"o\" direction=\"out\"/>\n" \
83 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
84 " <arg name=\"seat\" type=\"s\" direction=\"out\"/>\n" \
85 " <arg name=\"vtnr\" type=\"u\" direction=\"out\"/>\n" \
86 " <arg name=\"existing\" type=\"b\" direction=\"out\"/>\n" \
88 " <method name=\"ReleaseSession\">\n" \
89 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
91 " <method name=\"ActivateSession\">\n" \
92 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
94 " <method name=\"ActivateSessionOnSeat\">\n" \
95 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
96 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
98 " <method name=\"LockSession\">\n" \
99 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
101 " <method name=\"UnlockSession\">\n" \
102 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
104 " <method name=\"LockSessions\"/>\n" \
105 " <method name=\"KillSession\">\n" \
106 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
107 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
108 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
110 " <method name=\"KillUser\">\n" \
111 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
112 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
114 " <method name=\"TerminateSession\">\n" \
115 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
117 " <method name=\"TerminateUser\">\n" \
118 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
120 " <method name=\"TerminateSeat\">\n" \
121 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
123 " <method name=\"SetUserLinger\">\n" \
124 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
125 " <arg name=\"b\" type=\"b\" direction=\"in\"/>\n" \
126 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
128 " <method name=\"AttachDevice\">\n" \
129 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
130 " <arg name=\"sysfs\" type=\"s\" direction=\"in\"/>\n" \
131 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
133 " <method name=\"FlushDevices\">\n" \
134 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
136 " <method name=\"PowerOff\">\n" \
137 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
139 " <method name=\"Reboot\">\n" \
140 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
142 " <method name=\"Suspend\">\n" \
143 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
145 " <method name=\"Hibernate\">\n" \
146 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
148 " <method name=\"HybridSleep\">\n" \
149 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
151 " <method name=\"CanPowerOff\">\n" \
152 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
154 " <method name=\"CanReboot\">\n" \
155 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
157 " <method name=\"CanSuspend\">\n" \
158 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
160 " <method name=\"CanHibernate\">\n" \
161 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
163 " <method name=\"CanHybridSleep\">\n" \
164 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
166 " <method name=\"Inhibit\">\n" \
167 " <arg name=\"what\" type=\"s\" direction=\"in\"/>\n" \
168 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
169 " <arg name=\"why\" type=\"s\" direction=\"in\"/>\n" \
170 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
171 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
173 " <method name=\"ListInhibitors\">\n" \
174 " <arg name=\"inhibitors\" type=\"a(ssssuu)\" direction=\"out\"/>\n" \
176 " <signal name=\"SessionNew\">\n" \
177 " <arg name=\"id\" type=\"s\"/>\n" \
178 " <arg name=\"path\" type=\"o\"/>\n" \
180 " <signal name=\"SessionRemoved\">\n" \
181 " <arg name=\"id\" type=\"s\"/>\n" \
182 " <arg name=\"path\" type=\"o\"/>\n" \
184 " <signal name=\"UserNew\">\n" \
185 " <arg name=\"uid\" type=\"u\"/>\n" \
186 " <arg name=\"path\" type=\"o\"/>\n" \
188 " <signal name=\"UserRemoved\">\n" \
189 " <arg name=\"uid\" type=\"u\"/>\n" \
190 " <arg name=\"path\" type=\"o\"/>\n" \
192 " <signal name=\"SeatNew\">\n" \
193 " <arg name=\"id\" type=\"s\"/>\n" \
194 " <arg name=\"path\" type=\"o\"/>\n" \
196 " <signal name=\"SeatRemoved\">\n" \
197 " <arg name=\"id\" type=\"s\"/>\n" \
198 " <arg name=\"path\" type=\"o\"/>\n" \
200 " <signal name=\"PrepareForShutdown\">\n" \
201 " <arg name=\"active\" type=\"b\"/>\n" \
203 " <signal name=\"PrepareForSleep\">\n" \
204 " <arg name=\"active\" type=\"b\"/>\n" \
206 " <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
207 " <property name=\"Controllers\" type=\"as\" access=\"read\"/>\n" \
208 " <property name=\"ResetControllers\" type=\"as\" access=\"read\"/>\n" \
209 " <property name=\"NAutoVTs\" type=\"u\" access=\"read\"/>\n" \
210 " <property name=\"KillOnlyUsers\" type=\"as\" access=\"read\"/>\n" \
211 " <property name=\"KillExcludeUsers\" type=\"as\" access=\"read\"/>\n" \
212 " <property name=\"KillUserProcesses\" type=\"b\" access=\"read\"/>\n" \
213 " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
214 " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
215 " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
216 " <property name=\"BlockInhibited\" type=\"s\" access=\"read\"/>\n" \
217 " <property name=\"DelayInhibited\" type=\"s\" access=\"read\"/>\n" \
218 " <property name=\"InhibitDelayMaxUSec\" type=\"t\" access=\"read\"/>\n" \
219 " <property name=\"HandlePowerKey\" type=\"s\" access=\"read\"/>\n" \
220 " <property name=\"HandleSuspendKey\" type=\"s\" access=\"read\"/>\n" \
221 " <property name=\"HandleHibernateKey\" type=\"s\" access=\"read\"/>\n" \
222 " <property name=\"HandleLidSwitch\" type=\"s\" access=\"read\"/>\n" \
223 " <property name=\"PreparingForShutdown\" type=\"b\" access=\"read\"/>\n" \
224 " <property name=\"PreparingForSleep\" type=\"b\" access=\"read\"/>\n" \
227 #define INTROSPECTION_BEGIN \
228 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
230 BUS_MANAGER_INTERFACE \
231 BUS_PROPERTIES_INTERFACE \
233 BUS_INTROSPECTABLE_INTERFACE
235 #define INTROSPECTION_END \
238 #define INTERFACES_LIST \
239 BUS_GENERIC_INTERFACES_LIST \
240 "org.freedesktop.login1.Manager\0"
242 static int bus_manager_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
250 b = manager_get_idle_hint(m, NULL) > 0;
251 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
257 static int bus_manager_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
266 manager_get_idle_hint(m, &t);
267 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
269 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
275 static int bus_manager_append_inhibited(DBusMessageIter *i, const char *property, void *data) {
280 w = manager_inhibit_what(m, streq(property, "BlockInhibited") ? INHIBIT_BLOCK : INHIBIT_DELAY);
281 p = inhibit_what_to_string(w);
283 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &p))
289 static int bus_manager_append_preparing(DBusMessageIter *i, const char *property, void *data) {
296 if (streq(property, "PreparingForShutdown"))
297 b = !!(m->delayed_what & INHIBIT_SHUTDOWN);
299 b = !!(m->delayed_what & INHIBIT_SLEEP);
301 dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b);
305 static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMessage **_reply) {
306 Session *session = NULL;
308 const char *type, *class, *seat, *tty, *display, *remote_user, *remote_host, *service;
309 uint32_t uid, leader, audit_id = 0;
310 dbus_bool_t remote, kill_processes, exists;
311 char **controllers = NULL, **reset_controllers = NULL;
315 DBusMessageIter iter;
320 DBusMessage *reply = NULL;
327 if (!dbus_message_iter_init(message, &iter) ||
328 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
331 dbus_message_iter_get_basic(&iter, &uid);
333 if (!dbus_message_iter_next(&iter) ||
334 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
337 dbus_message_iter_get_basic(&iter, &leader);
340 !dbus_message_iter_next(&iter) ||
341 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
344 dbus_message_iter_get_basic(&iter, &service);
346 if (!dbus_message_iter_next(&iter) ||
347 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
350 dbus_message_iter_get_basic(&iter, &type);
351 t = session_type_from_string(type);
354 !dbus_message_iter_next(&iter) ||
355 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
358 dbus_message_iter_get_basic(&iter, &class);
362 c = session_class_from_string(class);
365 !dbus_message_iter_next(&iter) ||
366 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
369 dbus_message_iter_get_basic(&iter, &seat);
374 s = hashmap_get(m->seats, seat);
379 if (!dbus_message_iter_next(&iter) ||
380 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
383 dbus_message_iter_get_basic(&iter, &vtnr);
385 if (!dbus_message_iter_next(&iter) ||
386 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
389 dbus_message_iter_get_basic(&iter, &tty);
391 if (tty_is_vc(tty)) {
396 else if (s != m->vtconsole)
399 v = vtnr_from_tty(tty);
402 return v < 0 ? v : -EINVAL;
406 else if (vtnr != (uint32_t) v)
408 } else if (tty_is_console(tty)) {
412 else if (s != m->vtconsole)
418 } else if (!isempty(tty) && s && seat_is_vtconsole(s))
422 if (seat_can_multi_session(s)) {
431 if (!dbus_message_iter_next(&iter) ||
432 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
435 dbus_message_iter_get_basic(&iter, &display);
437 if (!dbus_message_iter_next(&iter) ||
438 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
441 dbus_message_iter_get_basic(&iter, &remote);
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_user);
449 if (!dbus_message_iter_next(&iter) ||
450 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
453 dbus_message_iter_get_basic(&iter, &remote_host);
455 if (!dbus_message_iter_next(&iter) ||
456 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
457 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
460 r = bus_parse_strv_iter(&iter, &controllers);
464 if (strv_contains(controllers, "systemd") ||
465 !dbus_message_iter_next(&iter) ||
466 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
467 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) {
472 r = bus_parse_strv_iter(&iter, &reset_controllers);
476 if (strv_contains(reset_controllers, "systemd") ||
477 !dbus_message_iter_next(&iter) ||
478 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) {
483 dbus_message_iter_get_basic(&iter, &kill_processes);
485 r = manager_add_user_by_uid(m, uid, &user);
489 audit_session_from_pid(leader, &audit_id);
492 asprintf(&id, "%lu", (unsigned long) audit_id);
499 session = hashmap_get(m->sessions, id);
504 fifo_fd = session_create_fifo(session);
510 /* Session already exists, client is probably
511 * something like "su" which changes uid but
512 * is still the same audit session */
514 reply = dbus_message_new_method_return(message);
520 p = session_bus_path(session);
526 seat = session->seat ? session->seat->id : "";
527 vtnr = session->vtnr;
530 b = dbus_message_append_args(
532 DBUS_TYPE_STRING, &session->id,
533 DBUS_TYPE_OBJECT_PATH, &p,
534 DBUS_TYPE_STRING, &session->user->runtime_path,
535 DBUS_TYPE_UNIX_FD, &fifo_fd,
536 DBUS_TYPE_STRING, &seat,
537 DBUS_TYPE_UINT32, &vtnr,
538 DBUS_TYPE_BOOLEAN, &exists,
547 close_nointr_nofail(fifo_fd);
550 strv_free(controllers);
551 strv_free(reset_controllers);
561 if (asprintf(&id, "c%lu", ++m->session_counter) < 0) {
566 } while (hashmap_get(m->sessions, id));
569 r = manager_add_session(m, user, id, &session);
574 session->leader = leader;
575 session->audit_id = audit_id;
578 session->remote = remote;
579 session->controllers = controllers;
580 session->reset_controllers = reset_controllers;
581 session->kill_processes = kill_processes;
582 session->vtnr = vtnr;
584 controllers = reset_controllers = NULL;
587 session->tty = strdup(tty);
594 if (!isempty(display)) {
595 session->display = strdup(display);
596 if (!session->display) {
602 if (!isempty(remote_user)) {
603 session->remote_user = strdup(remote_user);
604 if (!session->remote_user) {
610 if (!isempty(remote_host)) {
611 session->remote_host = strdup(remote_host);
612 if (!session->remote_host) {
618 if (!isempty(service)) {
619 session->service = strdup(service);
620 if (!session->service) {
626 fifo_fd = session_create_fifo(session);
633 r = seat_attach_session(s, session);
638 r = session_start(session);
642 reply = dbus_message_new_method_return(message);
648 p = session_bus_path(session);
654 seat = s ? s->id : "";
656 b = dbus_message_append_args(
658 DBUS_TYPE_STRING, &session->id,
659 DBUS_TYPE_OBJECT_PATH, &p,
660 DBUS_TYPE_STRING, &session->user->runtime_path,
661 DBUS_TYPE_UNIX_FD, &fifo_fd,
662 DBUS_TYPE_STRING, &seat,
663 DBUS_TYPE_UINT32, &vtnr,
664 DBUS_TYPE_BOOLEAN, &exists,
673 close_nointr_nofail(fifo_fd);
679 strv_free(controllers);
680 strv_free(reset_controllers);
683 session_add_to_gc_queue(session);
686 user_add_to_gc_queue(user);
689 close_nointr_nofail(fifo_fd);
692 dbus_message_unref(reply);
697 static int bus_manager_inhibit(Manager *m, DBusConnection *connection, DBusMessage *message, DBusError *error, DBusMessage **_reply) {
700 const char *who, *why, *what, *mode;
706 DBusMessage *reply = NULL;
714 if (!dbus_message_get_args(
717 DBUS_TYPE_STRING, &what,
718 DBUS_TYPE_STRING, &who,
719 DBUS_TYPE_STRING, &why,
720 DBUS_TYPE_STRING, &mode,
721 DBUS_TYPE_INVALID)) {
726 w = inhibit_what_from_string(what);
732 mm = inhibit_mode_from_string(mode);
738 /* Delay is only supported for shutdown/sleep */
739 if (mm == INHIBIT_DELAY && (w & ~(INHIBIT_SHUTDOWN|INHIBIT_SLEEP))) {
744 r = verify_polkit(connection, message,
745 w == INHIBIT_SHUTDOWN ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
746 w == INHIBIT_SLEEP ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep" : "org.freedesktop.login1.inhibit-delay-sleep") :
747 w == INHIBIT_IDLE ? "org.freedesktop.login1.inhibit-block-idle" :
748 w == INHIBIT_HANDLE_POWER_KEY ? "org.freedesktop.login1.inhibit-handle-power-key" :
749 w == INHIBIT_HANDLE_SUSPEND_KEY ? "org.freedesktop.login1.inhibit-handle-suspend-key" :
750 w == INHIBIT_HANDLE_HIBERNATE_KEY ? "org.freedesktop.login1.inhibit-handle-hibernate-key" :
751 "org.freedesktop.login1.inhibit-handle-lid-switch",
756 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
757 if (ul == (unsigned long) -1) {
762 pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
772 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
776 } while (hashmap_get(m->inhibitors, id));
778 r = manager_add_inhibitor(m, id, &i);
788 i->why = strdup(why);
789 i->who = strdup(who);
791 if (!i->why || !i->who) {
796 fifo_fd = inhibitor_create_fifo(i);
802 reply = dbus_message_new_method_return(message);
808 if (!dbus_message_append_args(
810 DBUS_TYPE_UNIX_FD, &fifo_fd,
811 DBUS_TYPE_INVALID)) {
816 close_nointr_nofail(fifo_fd);
828 close_nointr_nofail(fifo_fd);
831 dbus_message_unref(reply);
836 static int trigger_device(Manager *m, struct udev_device *d) {
837 struct udev_enumerate *e;
838 struct udev_list_entry *first, *item;
843 e = udev_enumerate_new(m->udev);
850 if (udev_enumerate_add_match_parent(e, d) < 0) {
856 if (udev_enumerate_scan_devices(e) < 0) {
861 first = udev_enumerate_get_list_entry(e);
862 udev_list_entry_foreach(item, first) {
866 p = udev_list_entry_get_name(item);
868 t = strappend(p, "/uevent");
874 write_one_line_file(t, "change");
882 udev_enumerate_unref(e);
887 static int attach_device(Manager *m, const char *seat, const char *sysfs) {
888 struct udev_device *d;
889 char *rule = NULL, *file = NULL;
890 const char *id_for_seat;
897 d = udev_device_new_from_syspath(m->udev, sysfs);
901 if (!udev_device_has_tag(d, "seat")) {
906 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
912 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
917 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
922 mkdir_p_label("/etc/udev/rules.d", 0755);
923 r = write_one_line_file_atomic(file, rule);
927 r = trigger_device(m, d);
934 udev_device_unref(d);
939 static int flush_devices(Manager *m) {
944 d = opendir("/etc/udev/rules.d");
947 log_warning("Failed to open /etc/udev/rules.d: %m");
951 while ((de = readdir(d))) {
953 if (!dirent_is_file(de))
956 if (!startswith(de->d_name, "72-seat-"))
959 if (!endswith(de->d_name, ".rules"))
962 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
963 log_warning("Failed to unlink %s: %m", de->d_name);
969 return trigger_device(m, NULL);
972 static int have_multiple_sessions(
981 /* Check for other users' sessions. Greeter sessions do not count. */
982 HASHMAP_FOREACH(session, m->sessions, i)
983 if (session->class == SESSION_USER && session->user->uid != uid)
989 static int send_start_unit(DBusConnection *connection, const char *unit_name, DBusError *error) {
990 const char *mode = "replace";
994 return bus_method_call_with_reply (
996 "org.freedesktop.systemd1",
997 "/org/freedesktop/systemd1",
998 "org.freedesktop.systemd1.Manager",
1002 DBUS_TYPE_STRING, &unit_name,
1003 DBUS_TYPE_STRING, &mode,
1007 static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
1008 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
1009 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
1010 [INHIBIT_SLEEP] = "PrepareForSleep"
1013 dbus_bool_t active = _active;
1014 DBusMessage *message;
1019 assert(w < _INHIBIT_WHAT_MAX);
1020 assert(signal_name[w]);
1022 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1026 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1027 !dbus_connection_send(m->bus, message, NULL))
1030 dbus_message_unref(message);
1034 static int delay_shutdown_or_sleep(Manager *m, InhibitWhat w, const char *unit_name) {
1037 assert(w < _INHIBIT_WHAT_MAX);
1039 /* Tell everybody to prepare for shutdown/sleep */
1040 send_prepare_for(m, w, true);
1042 /* Update timestamp for timeout */
1043 if (!m->delayed_unit)
1044 m->delayed_timestamp = now(CLOCK_MONOTONIC);
1046 /* Remember what we want to do, possibly overriding what kind
1047 * of unit we previously queued. */
1048 m->delayed_unit = unit_name;
1049 m->delayed_what = w;
1054 static int bus_manager_can_shutdown_or_sleep(
1056 DBusConnection *connection,
1057 DBusMessage *message,
1060 const char *action_multiple_sessions,
1061 const char *action_ignore_inhibit,
1062 const char *sleep_type,
1063 const char *sleep_disk_type,
1065 DBusMessage **_reply) {
1067 bool multiple_sessions, challenge, blocked, b;
1069 DBusMessage *reply = NULL;
1077 assert(w <= _INHIBIT_WHAT_MAX);
1079 assert(action_multiple_sessions);
1080 assert(action_ignore_inhibit);
1085 r = can_sleep(sleep_type);
1095 if (sleep_disk_type) {
1096 r = can_sleep_disk(sleep_disk_type);
1106 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1107 if (ul == (unsigned long) -1)
1110 r = have_multiple_sessions(m, (uid_t) ul);
1114 multiple_sessions = r > 0;
1115 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1117 if (multiple_sessions) {
1118 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1125 result = "challenge";
1131 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1135 if (r > 0 && !result)
1137 else if (challenge && (!result || streq(result, "yes")))
1138 result = "challenge";
1143 if (!multiple_sessions && !blocked) {
1144 /* If neither inhibit nor multiple sessions
1145 * apply then just check the normal policy */
1147 r = verify_polkit(connection, message, action, false, &challenge, error);
1154 result = "challenge";
1160 reply = dbus_message_new_method_return(message);
1164 b = dbus_message_append_args(
1166 DBUS_TYPE_STRING, &result,
1169 dbus_message_unref(reply);
1177 static int bus_manager_log_shutdown(
1180 const char *unit_name) {
1187 if (w != INHIBIT_SHUTDOWN)
1190 if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
1191 p = "MESSAGE=System is powering down.";
1192 q = "SHUTDOWN=power-off";
1193 } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
1194 p = "MESSAGE=System is halting.";
1195 q = "SHUTDOWN=halt";
1196 } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
1197 p = "MESSAGE=System is rebooting.";
1198 q = "SHUTDOWN=reboot";
1199 } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
1200 p = "MESSAGE=System is rebooting with kexec.";
1201 q = "SHUTDOWN=kexec";
1203 p = "MESSAGE=System is shutting down.";
1207 return log_struct(LOG_NOTICE, MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
1212 int bus_manager_shutdown_or_sleep_now_or_later(
1214 const char *unit_name,
1224 assert(w <= _INHIBIT_WHAT_MAX);
1227 m->inhibit_delay_max > 0 &&
1228 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0);
1231 /* Shutdown is delayed, keep in mind what we
1232 * want to do, and start a timeout */
1233 r = delay_shutdown_or_sleep(m, w, unit_name);
1235 bus_manager_log_shutdown(m, w, unit_name);
1237 /* Shutdown is not delayed, execute it
1239 r = send_start_unit(m->bus, unit_name, error);
1245 static int bus_manager_do_shutdown_or_sleep(
1247 DBusConnection *connection,
1248 DBusMessage *message,
1249 const char *unit_name,
1252 const char *action_multiple_sessions,
1253 const char *action_ignore_inhibit,
1254 const char *sleep_type,
1255 const char *sleep_disk_type,
1257 DBusMessage **_reply) {
1259 dbus_bool_t interactive;
1260 bool multiple_sessions, blocked;
1261 DBusMessage *reply = NULL;
1270 assert(w <= _INHIBIT_WHAT_MAX);
1272 assert(action_multiple_sessions);
1273 assert(action_ignore_inhibit);
1277 if (!dbus_message_get_args(
1280 DBUS_TYPE_BOOLEAN, &interactive,
1285 r = can_sleep(sleep_type);
1293 if (sleep_disk_type) {
1294 r = can_sleep_disk(sleep_disk_type);
1302 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1303 if (ul == (unsigned long) -1)
1306 r = have_multiple_sessions(m, (uid_t) ul);
1310 multiple_sessions = r > 0;
1311 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1313 if (multiple_sessions) {
1314 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1320 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1325 if (!multiple_sessions && !blocked) {
1326 r = verify_polkit(connection, message, action, interactive, NULL, error);
1331 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
1335 reply = dbus_message_new_method_return(message);
1343 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_button, handle_button, HandleButton);
1345 static const BusProperty bus_login_manager_properties[] = {
1346 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_path), true },
1347 { "Controllers", bus_property_append_strv, "as", offsetof(Manager, controllers), true },
1348 { "ResetControllers", bus_property_append_strv, "as", offsetof(Manager, reset_controllers), true },
1349 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1350 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1351 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1352 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1353 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1354 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1355 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
1356 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1357 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1358 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
1359 { "HandlePowerKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_power_key) },
1360 { "HandleSuspendKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_suspend_key) },
1361 { "HandleHibernateKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_hibernate_key)},
1362 { "HandleLidSwitch", bus_manager_append_handle_button, "s", offsetof(Manager, handle_lid_switch) },
1363 { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
1364 { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
1368 static DBusHandlerResult manager_message_handler(
1369 DBusConnection *connection,
1370 DBusMessage *message,
1373 Manager *m = userdata;
1376 DBusMessage *reply = NULL;
1383 dbus_error_init(&error);
1385 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1391 if (!dbus_message_get_args(
1394 DBUS_TYPE_STRING, &name,
1396 return bus_send_error_reply(connection, message, &error, -EINVAL);
1398 session = hashmap_get(m->sessions, name);
1400 return bus_send_error_reply(connection, message, &error, -ENOENT);
1402 reply = dbus_message_new_method_return(message);
1406 p = session_bus_path(session);
1410 b = dbus_message_append_args(
1412 DBUS_TYPE_OBJECT_PATH, &p,
1419 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1425 if (!dbus_message_get_args(
1428 DBUS_TYPE_UINT32, &pid,
1430 return bus_send_error_reply(connection, message, &error, -EINVAL);
1432 r = manager_get_session_by_pid(m, pid, &session);
1434 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1436 reply = dbus_message_new_method_return(message);
1440 p = session_bus_path(session);
1444 b = dbus_message_append_args(
1446 DBUS_TYPE_OBJECT_PATH, &p,
1453 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1459 if (!dbus_message_get_args(
1462 DBUS_TYPE_UINT32, &uid,
1464 return bus_send_error_reply(connection, message, &error, -EINVAL);
1466 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1468 return bus_send_error_reply(connection, message, &error, -ENOENT);
1470 reply = dbus_message_new_method_return(message);
1474 p = user_bus_path(user);
1478 b = dbus_message_append_args(
1480 DBUS_TYPE_OBJECT_PATH, &p,
1487 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1493 if (!dbus_message_get_args(
1496 DBUS_TYPE_STRING, &name,
1498 return bus_send_error_reply(connection, message, &error, -EINVAL);
1500 seat = hashmap_get(m->seats, name);
1502 return bus_send_error_reply(connection, message, &error, -ENOENT);
1504 reply = dbus_message_new_method_return(message);
1508 p = seat_bus_path(seat);
1512 b = dbus_message_append_args(
1514 DBUS_TYPE_OBJECT_PATH, &p,
1521 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1525 DBusMessageIter iter, sub;
1526 const char *empty = "";
1528 reply = dbus_message_new_method_return(message);
1532 dbus_message_iter_init_append(reply, &iter);
1534 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1537 HASHMAP_FOREACH(session, m->sessions, i) {
1538 DBusMessageIter sub2;
1541 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1544 uid = session->user->uid;
1546 p = session_bus_path(session);
1550 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1551 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1552 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1553 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1554 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1561 if (!dbus_message_iter_close_container(&sub, &sub2))
1565 if (!dbus_message_iter_close_container(&iter, &sub))
1568 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1572 DBusMessageIter iter, sub;
1574 reply = dbus_message_new_method_return(message);
1578 dbus_message_iter_init_append(reply, &iter);
1580 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1583 HASHMAP_FOREACH(user, m->users, i) {
1584 DBusMessageIter sub2;
1587 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1592 p = user_bus_path(user);
1596 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1597 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1598 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1605 if (!dbus_message_iter_close_container(&sub, &sub2))
1609 if (!dbus_message_iter_close_container(&iter, &sub))
1612 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1616 DBusMessageIter iter, sub;
1618 reply = dbus_message_new_method_return(message);
1622 dbus_message_iter_init_append(reply, &iter);
1624 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1627 HASHMAP_FOREACH(seat, m->seats, i) {
1628 DBusMessageIter sub2;
1630 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1633 p = seat_bus_path(seat);
1637 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1638 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1645 if (!dbus_message_iter_close_container(&sub, &sub2))
1649 if (!dbus_message_iter_close_container(&iter, &sub))
1652 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1653 Inhibitor *inhibitor;
1655 DBusMessageIter iter, sub;
1657 reply = dbus_message_new_method_return(message);
1661 dbus_message_iter_init_append(reply, &iter);
1663 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1666 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1667 DBusMessageIter sub2;
1668 dbus_uint32_t uid, pid;
1669 const char *what, *who, *why, *mode;
1671 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1674 what = strempty(inhibit_what_to_string(inhibitor->what));
1675 who = strempty(inhibitor->who);
1676 why = strempty(inhibitor->why);
1677 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
1678 uid = (dbus_uint32_t) inhibitor->uid;
1679 pid = (dbus_uint32_t) inhibitor->pid;
1681 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1682 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1683 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1684 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
1685 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1686 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1689 if (!dbus_message_iter_close_container(&sub, &sub2))
1693 if (!dbus_message_iter_close_container(&iter, &sub))
1696 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1698 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1701 return bus_send_error_reply(connection, message, &error, r);
1704 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1706 r = bus_manager_create_session(m, message, &reply);
1708 /* Don't delay the work on OOM here, since it might be
1709 * triggered by a low RLIMIT_NOFILE here (since we
1710 * send a dupped fd to the client), and we'd rather
1711 * see this fail quickly then be retried later */
1714 return bus_send_error_reply(connection, message, NULL, r);
1716 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1720 if (!dbus_message_get_args(
1723 DBUS_TYPE_STRING, &name,
1725 return bus_send_error_reply(connection, message, &error, -EINVAL);
1727 session = hashmap_get(m->sessions, name);
1729 return bus_send_error_reply(connection, message, &error, -ENOENT);
1731 /* We use the FIFO to detect stray sessions where the
1732 process invoking PAM dies abnormally. We need to make
1733 sure that that process is not killed if at the clean
1734 end of the session it closes the FIFO. Hence, with
1735 this call explicitly turn off the FIFO logic, so that
1736 the PAM code can finish clean up on its own */
1737 session_remove_fifo(session);
1739 reply = dbus_message_new_method_return(message);
1743 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1747 if (!dbus_message_get_args(
1750 DBUS_TYPE_STRING, &name,
1752 return bus_send_error_reply(connection, message, &error, -EINVAL);
1754 session = hashmap_get(m->sessions, name);
1756 return bus_send_error_reply(connection, message, &error, -ENOENT);
1758 r = session_activate(session);
1760 return bus_send_error_reply(connection, message, NULL, r);
1762 reply = dbus_message_new_method_return(message);
1766 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1767 const char *session_name, *seat_name;
1771 /* Same as ActivateSession() but refuses to work if
1772 * the seat doesn't match */
1774 if (!dbus_message_get_args(
1777 DBUS_TYPE_STRING, &session_name,
1778 DBUS_TYPE_STRING, &seat_name,
1780 return bus_send_error_reply(connection, message, &error, -EINVAL);
1782 session = hashmap_get(m->sessions, session_name);
1784 return bus_send_error_reply(connection, message, &error, -ENOENT);
1786 seat = hashmap_get(m->seats, seat_name);
1788 return bus_send_error_reply(connection, message, &error, -ENOENT);
1790 if (session->seat != seat)
1791 return bus_send_error_reply(connection, message, &error, -EINVAL);
1793 r = session_activate(session);
1795 return bus_send_error_reply(connection, message, NULL, r);
1797 reply = dbus_message_new_method_return(message);
1801 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1802 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1806 if (!dbus_message_get_args(
1809 DBUS_TYPE_STRING, &name,
1811 return bus_send_error_reply(connection, message, &error, -EINVAL);
1813 session = hashmap_get(m->sessions, name);
1815 return bus_send_error_reply(connection, message, &error, -ENOENT);
1817 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1820 reply = dbus_message_new_method_return(message);
1824 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions")) {
1828 HASHMAP_FOREACH(session, m->sessions, i)
1829 if (session_send_lock(session, true) < 0)
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 (!dbus_connection_send(connection, reply, NULL))
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);