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, NULL, -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")) {
1825 r = session_send_lock_all(m, true);
1827 bus_send_error_reply(connection, message, NULL, r);
1829 reply = dbus_message_new_method_return(message);
1833 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1840 if (!dbus_message_get_args(
1843 DBUS_TYPE_STRING, &name,
1844 DBUS_TYPE_STRING, &swho,
1845 DBUS_TYPE_INT32, &signo,
1847 return bus_send_error_reply(connection, message, &error, -EINVAL);
1852 who = kill_who_from_string(swho);
1854 return bus_send_error_reply(connection, message, &error, -EINVAL);
1857 if (signo <= 0 || signo >= _NSIG)
1858 return bus_send_error_reply(connection, message, &error, -EINVAL);
1860 session = hashmap_get(m->sessions, name);
1862 return bus_send_error_reply(connection, message, &error, -ENOENT);
1864 r = session_kill(session, who, signo);
1866 return bus_send_error_reply(connection, message, NULL, r);
1868 reply = dbus_message_new_method_return(message);
1872 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1877 if (!dbus_message_get_args(
1880 DBUS_TYPE_UINT32, &uid,
1881 DBUS_TYPE_INT32, &signo,
1883 return bus_send_error_reply(connection, message, &error, -EINVAL);
1885 if (signo <= 0 || signo >= _NSIG)
1886 return bus_send_error_reply(connection, message, &error, -EINVAL);
1888 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1890 return bus_send_error_reply(connection, message, &error, -ENOENT);
1892 r = user_kill(user, signo);
1894 return bus_send_error_reply(connection, message, NULL, r);
1896 reply = dbus_message_new_method_return(message);
1900 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1904 if (!dbus_message_get_args(
1907 DBUS_TYPE_STRING, &name,
1909 return bus_send_error_reply(connection, message, &error, -EINVAL);
1911 session = hashmap_get(m->sessions, name);
1913 return bus_send_error_reply(connection, message, &error, -ENOENT);
1915 r = session_stop(session);
1917 return bus_send_error_reply(connection, message, NULL, r);
1919 reply = dbus_message_new_method_return(message);
1923 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1927 if (!dbus_message_get_args(
1930 DBUS_TYPE_UINT32, &uid,
1932 return bus_send_error_reply(connection, message, &error, -EINVAL);
1934 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1936 return bus_send_error_reply(connection, message, &error, -ENOENT);
1938 r = user_stop(user);
1940 return bus_send_error_reply(connection, message, NULL, r);
1942 reply = dbus_message_new_method_return(message);
1946 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1950 if (!dbus_message_get_args(
1953 DBUS_TYPE_STRING, &name,
1955 return bus_send_error_reply(connection, message, &error, -EINVAL);
1957 seat = hashmap_get(m->seats, name);
1959 return bus_send_error_reply(connection, message, &error, -ENOENT);
1961 r = seat_stop_sessions(seat);
1963 return bus_send_error_reply(connection, message, NULL, r);
1965 reply = dbus_message_new_method_return(message);
1969 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
1972 dbus_bool_t b, interactive;
1975 if (!dbus_message_get_args(
1978 DBUS_TYPE_UINT32, &uid,
1979 DBUS_TYPE_BOOLEAN, &b,
1980 DBUS_TYPE_BOOLEAN, &interactive,
1982 return bus_send_error_reply(connection, message, &error, -EINVAL);
1987 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
1989 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
1991 return bus_send_error_reply(connection, message, &error, r);
1993 mkdir_p_label("/var/lib/systemd", 0755);
1995 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
1997 return bus_send_error_reply(connection, message, &error, r);
1999 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
2010 return bus_send_error_reply(connection, message, &error, r);
2012 if (manager_add_user_by_uid(m, uid, &u) >= 0)
2021 if (r < 0 && errno != ENOENT)
2022 return bus_send_error_reply(connection, message, &error, -errno);
2024 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
2026 user_add_to_gc_queue(u);
2029 reply = dbus_message_new_method_return(message);
2033 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
2034 const char *sysfs, *seat;
2035 dbus_bool_t interactive;
2037 if (!dbus_message_get_args(
2040 DBUS_TYPE_STRING, &seat,
2041 DBUS_TYPE_STRING, &sysfs,
2042 DBUS_TYPE_BOOLEAN, &interactive,
2044 return bus_send_error_reply(connection, message, &error, -EINVAL);
2046 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
2047 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2049 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
2051 return bus_send_error_reply(connection, message, &error, r);
2053 r = attach_device(m, seat, sysfs);
2055 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2057 reply = dbus_message_new_method_return(message);
2062 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
2063 dbus_bool_t interactive;
2065 if (!dbus_message_get_args(
2068 DBUS_TYPE_BOOLEAN, &interactive,
2070 return bus_send_error_reply(connection, message, &error, -EINVAL);
2072 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
2074 return bus_send_error_reply(connection, message, &error, r);
2076 r = flush_devices(m);
2078 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2080 reply = dbus_message_new_method_return(message);
2084 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
2086 r = bus_manager_do_shutdown_or_sleep(
2087 m, connection, message,
2088 SPECIAL_POWEROFF_TARGET,
2090 "org.freedesktop.login1.power-off",
2091 "org.freedesktop.login1.power-off-multiple-sessions",
2092 "org.freedesktop.login1.power-off-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", "Reboot")) {
2098 r = bus_manager_do_shutdown_or_sleep(
2099 m, connection, message,
2100 SPECIAL_REBOOT_TARGET,
2102 "org.freedesktop.login1.reboot",
2103 "org.freedesktop.login1.reboot-multiple-sessions",
2104 "org.freedesktop.login1.reboot-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", "Suspend")) {
2111 r = bus_manager_do_shutdown_or_sleep(
2112 m, connection, message,
2113 SPECIAL_SUSPEND_TARGET,
2115 "org.freedesktop.login1.suspend",
2116 "org.freedesktop.login1.suspend-multiple-sessions",
2117 "org.freedesktop.login1.suspend-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", "Hibernate")) {
2123 r = bus_manager_do_shutdown_or_sleep(
2124 m, connection, message,
2125 SPECIAL_HIBERNATE_TARGET,
2127 "org.freedesktop.login1.hibernate",
2128 "org.freedesktop.login1.hibernate-multiple-sessions",
2129 "org.freedesktop.login1.hibernate-ignore-inhibit",
2133 return bus_send_error_reply(connection, message, &error, r);
2135 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "HybridSleep")) {
2136 r = bus_manager_do_shutdown_or_sleep(
2137 m, connection, message,
2138 SPECIAL_HYBRID_SLEEP_TARGET,
2140 "org.freedesktop.login1.hibernate",
2141 "org.freedesktop.login1.hibernate-multiple-sessions",
2142 "org.freedesktop.login1.hibernate-ignore-inhibit",
2146 return bus_send_error_reply(connection, message, &error, r);
2148 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2150 r = bus_manager_can_shutdown_or_sleep(
2151 m, connection, message,
2153 "org.freedesktop.login1.power-off",
2154 "org.freedesktop.login1.power-off-multiple-sessions",
2155 "org.freedesktop.login1.power-off-ignore-inhibit",
2159 return bus_send_error_reply(connection, message, &error, r);
2160 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2161 r = bus_manager_can_shutdown_or_sleep(
2162 m, connection, message,
2164 "org.freedesktop.login1.reboot",
2165 "org.freedesktop.login1.reboot-multiple-sessions",
2166 "org.freedesktop.login1.reboot-ignore-inhibit",
2170 return bus_send_error_reply(connection, message, &error, r);
2172 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2173 r = bus_manager_can_shutdown_or_sleep(
2174 m, connection, message,
2176 "org.freedesktop.login1.suspend",
2177 "org.freedesktop.login1.suspend-multiple-sessions",
2178 "org.freedesktop.login1.suspend-ignore-inhibit",
2182 return bus_send_error_reply(connection, message, &error, r);
2184 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2185 r = bus_manager_can_shutdown_or_sleep(
2186 m, connection, message,
2188 "org.freedesktop.login1.hibernate",
2189 "org.freedesktop.login1.hibernate-multiple-sessions",
2190 "org.freedesktop.login1.hibernate-ignore-inhibit",
2194 return bus_send_error_reply(connection, message, &error, r);
2196 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHybridSleep")) {
2197 r = bus_manager_can_shutdown_or_sleep(
2198 m, connection, message,
2200 "org.freedesktop.login1.hibernate",
2201 "org.freedesktop.login1.hibernate-multiple-sessions",
2202 "org.freedesktop.login1.hibernate-ignore-inhibit",
2206 return bus_send_error_reply(connection, message, &error, r);
2208 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2209 char *introspection = NULL;
2218 if (!(reply = dbus_message_new_method_return(message)))
2221 /* We roll our own introspection code here, instead of
2222 * relying on bus_default_message_handler() because we
2223 * need to generate our introspection string
2226 if (!(f = open_memstream(&introspection, &size)))
2229 fputs(INTROSPECTION_BEGIN, f);
2231 HASHMAP_FOREACH(seat, m->seats, i) {
2232 p = bus_path_escape(seat->id);
2235 fprintf(f, "<node name=\"seat/%s\"/>", p);
2240 HASHMAP_FOREACH(user, m->users, i)
2241 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2243 HASHMAP_FOREACH(session, m->sessions, i) {
2244 p = bus_path_escape(session->id);
2247 fprintf(f, "<node name=\"session/%s\"/>", p);
2252 fputs(INTROSPECTION_END, f);
2256 free(introspection);
2265 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2266 free(introspection);
2270 free(introspection);
2272 const BusBoundProperties bps[] = {
2273 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2276 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2280 if (!dbus_connection_send(connection, reply, NULL))
2283 dbus_message_unref(reply);
2286 return DBUS_HANDLER_RESULT_HANDLED;
2290 dbus_message_unref(reply);
2292 dbus_error_free(&error);
2294 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2297 const DBusObjectPathVTable bus_manager_vtable = {
2298 .message_function = manager_message_handler
2301 DBusHandlerResult bus_message_filter(
2302 DBusConnection *connection,
2303 DBusMessage *message,
2306 Manager *m = userdata;
2313 dbus_error_init(&error);
2315 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
2318 if (!dbus_message_get_args(message, &error,
2319 DBUS_TYPE_STRING, &cgroup,
2321 log_error("Failed to parse Released message: %s", bus_error_message(&error));
2323 manager_cgroup_notify_empty(m, cgroup);
2326 dbus_error_free(&error);
2328 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2331 int manager_send_changed(Manager *manager, const char *properties) {
2337 m = bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties);
2341 if (!dbus_connection_send(manager->bus, m, NULL))
2348 dbus_message_unref(m);
2353 int manager_dispatch_delayed(Manager *manager) {
2354 const char *unit_name;
2361 if (!manager->delayed_unit)
2364 /* Continue delay? */
2366 manager->delayed_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC) &&
2367 manager_is_inhibited(manager, manager->delayed_what, INHIBIT_DELAY, NULL, false, false, 0);
2371 bus_manager_log_shutdown(manager, manager->delayed_what, manager->delayed_unit);
2373 /* Reset delay data */
2374 unit_name = manager->delayed_unit;
2375 manager->delayed_unit = NULL;
2377 /* Actually do the shutdown */
2378 dbus_error_init(&error);
2379 r = send_start_unit(manager->bus, unit_name, &error);
2381 log_warning("Failed to send delayed message: %s", bus_error_message_or_strerror(&error, -r));
2382 dbus_error_free(&error);
2386 /* Tell people about it */
2387 send_prepare_for(manager, manager->delayed_what, false);