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"
35 #define BUS_MANAGER_INTERFACE \
36 " <interface name=\"org.freedesktop.login1.Manager\">\n" \
37 " <method name=\"GetSession\">\n" \
38 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
39 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
41 " <method name=\"GetSessionByPID\">\n" \
42 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
43 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
45 " <method name=\"GetUser\">\n" \
46 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
47 " <arg name=\"user\" type=\"o\" direction=\"out\"/>\n" \
49 " <method name=\"GetSeat\">\n" \
50 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
51 " <arg name=\"seat\" type=\"o\" direction=\"out\"/>\n" \
53 " <method name=\"ListSessions\">\n" \
54 " <arg name=\"sessions\" type=\"a(susso)\" direction=\"out\"/>\n" \
56 " <method name=\"ListUsers\">\n" \
57 " <arg name=\"users\" type=\"a(uso)\" direction=\"out\"/>\n" \
59 " <method name=\"ListSeats\">\n" \
60 " <arg name=\"seats\" type=\"a(so)\" direction=\"out\"/>\n" \
62 " <method name=\"CreateSession\">\n" \
63 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
64 " <arg name=\"leader\" type=\"u\" direction=\"in\"/>\n" \
65 " <arg name=\"sevice\" type=\"s\" direction=\"in\"/>\n" \
66 " <arg name=\"type\" type=\"s\" direction=\"in\"/>\n" \
67 " <arg name=\"class\" type=\"s\" direction=\"in\"/>\n" \
68 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
69 " <arg name=\"vtnr\" type=\"u\" direction=\"in\"/>\n" \
70 " <arg name=\"tty\" type=\"s\" direction=\"in\"/>\n" \
71 " <arg name=\"display\" type=\"s\" direction=\"in\"/>\n" \
72 " <arg name=\"remote\" type=\"b\" direction=\"in\"/>\n" \
73 " <arg name=\"remote_user\" type=\"s\" direction=\"in\"/>\n" \
74 " <arg name=\"remote_host\" type=\"s\" direction=\"in\"/>\n" \
75 " <arg name=\"controllers\" type=\"as\" direction=\"in\"/>\n" \
76 " <arg name=\"reset_controllers\" type=\"as\" direction=\"in\"/>\n" \
77 " <arg name=\"kill_processes\" type=\"b\" direction=\"in\"/>\n" \
78 " <arg name=\"id\" type=\"s\" direction=\"out\"/>\n" \
79 " <arg name=\"path\" type=\"o\" direction=\"out\"/>\n" \
80 " <arg name=\"runtime_path\" type=\"o\" direction=\"out\"/>\n" \
81 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
82 " <arg name=\"seat\" type=\"s\" direction=\"out\"/>\n" \
83 " <arg name=\"vtnr\" type=\"u\" direction=\"out\"/>\n" \
85 " <method name=\"ReleaseSession\">\n" \
86 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
88 " <method name=\"ActivateSession\">\n" \
89 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
91 " <method name=\"ActivateSessionOnSeat\">\n" \
92 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
93 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
95 " <method name=\"LockSession\">\n" \
96 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
98 " <method name=\"UnlockSession\">\n" \
99 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
101 " <method name=\"KillSession\">\n" \
102 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
103 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
104 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
106 " <method name=\"KillUser\">\n" \
107 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
108 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
110 " <method name=\"TerminateSession\">\n" \
111 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
113 " <method name=\"TerminateUser\">\n" \
114 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
116 " <method name=\"TerminateSeat\">\n" \
117 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
119 " <method name=\"SetUserLinger\">\n" \
120 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
121 " <arg name=\"b\" type=\"b\" direction=\"in\"/>\n" \
122 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
124 " <method name=\"AttachDevice\">\n" \
125 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
126 " <arg name=\"sysfs\" type=\"s\" direction=\"in\"/>\n" \
127 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
129 " <method name=\"FlushDevices\">\n" \
130 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
132 " <method name=\"PowerOff\">\n" \
133 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
135 " <method name=\"Reboot\">\n" \
136 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
138 " <method name=\"Suspend\">\n" \
139 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
141 " <method name=\"Hibernate\">\n" \
142 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
144 " <method name=\"CanPowerOff\">\n" \
145 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
147 " <method name=\"CanReboot\">\n" \
148 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
150 " <method name=\"CanSuspend\">\n" \
151 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
153 " <method name=\"CanHibernate\">\n" \
154 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
156 " <method name=\"Inhibit\">\n" \
157 " <arg name=\"what\" type=\"s\" direction=\"in\"/>\n" \
158 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
159 " <arg name=\"why\" type=\"s\" direction=\"in\"/>\n" \
160 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
161 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
163 " <method name=\"ListInhibitors\">\n" \
164 " <arg name=\"inhibitors\" type=\"a(ssssuu)\" direction=\"out\"/>\n" \
166 " <signal name=\"SessionNew\">\n" \
167 " <arg name=\"id\" type=\"s\"/>\n" \
168 " <arg name=\"path\" type=\"o\"/>\n" \
170 " <signal name=\"SessionRemoved\">\n" \
171 " <arg name=\"id\" type=\"s\"/>\n" \
172 " <arg name=\"path\" type=\"o\"/>\n" \
174 " <signal name=\"UserNew\">\n" \
175 " <arg name=\"uid\" type=\"u\"/>\n" \
176 " <arg name=\"path\" type=\"o\"/>\n" \
178 " <signal name=\"UserRemoved\">\n" \
179 " <arg name=\"uid\" type=\"u\"/>\n" \
180 " <arg name=\"path\" type=\"o\"/>\n" \
182 " <signal name=\"SeatNew\">\n" \
183 " <arg name=\"id\" type=\"s\"/>\n" \
184 " <arg name=\"path\" type=\"o\"/>\n" \
186 " <signal name=\"SeatRemoved\">\n" \
187 " <arg name=\"id\" type=\"s\"/>\n" \
188 " <arg name=\"path\" type=\"o\"/>\n" \
190 " <signal name=\"PrepareForShutdown\">\n" \
191 " <arg name=\"active\" type=\"b\"/>\n" \
193 " <signal name=\"PrepareForSleep\">\n" \
194 " <arg name=\"active\" type=\"b\"/>\n" \
196 " <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
197 " <property name=\"Controllers\" type=\"as\" access=\"read\"/>\n" \
198 " <property name=\"ResetControllers\" type=\"as\" access=\"read\"/>\n" \
199 " <property name=\"NAutoVTs\" type=\"u\" access=\"read\"/>\n" \
200 " <property name=\"KillOnlyUsers\" type=\"as\" access=\"read\"/>\n" \
201 " <property name=\"KillExcludeUsers\" type=\"as\" access=\"read\"/>\n" \
202 " <property name=\"KillUserProcesses\" type=\"b\" access=\"read\"/>\n" \
203 " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
204 " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
205 " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
206 " <property name=\"BlockInhibited\" type=\"s\" access=\"read\"/>\n" \
207 " <property name=\"DelayInhibited\" type=\"s\" access=\"read\"/>\n" \
208 " <property name=\"InhibitDelayMaxUSec\" type=\"t\" access=\"read\"/>\n" \
209 " <property name=\"HandlePowerKey\" type=\"s\" access=\"read\"/>\n" \
210 " <property name=\"HandleSleepKey\" type=\"s\" access=\"read\"/>\n" \
211 " <property name=\"HandleLidSwitch\" type=\"s\" access=\"read\"/>\n" \
212 " <property name=\"PreparingForShutdown\" type=\"b\" access=\"read\"/>\n" \
213 " <property name=\"PreparingForSleep\" type=\"b\" access=\"read\"/>\n" \
216 #define INTROSPECTION_BEGIN \
217 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
219 BUS_MANAGER_INTERFACE \
220 BUS_PROPERTIES_INTERFACE \
222 BUS_INTROSPECTABLE_INTERFACE
224 #define INTROSPECTION_END \
227 #define INTERFACES_LIST \
228 BUS_GENERIC_INTERFACES_LIST \
229 "org.freedesktop.login1.Manager\0"
231 static int bus_manager_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
239 b = manager_get_idle_hint(m, NULL) > 0;
240 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
246 static int bus_manager_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
255 manager_get_idle_hint(m, &t);
256 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
258 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
264 static int bus_manager_append_inhibited(DBusMessageIter *i, const char *property, void *data) {
269 w = manager_inhibit_what(m, streq(property, "BlockInhibited") ? INHIBIT_BLOCK : INHIBIT_DELAY);
270 p = inhibit_what_to_string(w);
272 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &p))
278 static int bus_manager_append_preparing(DBusMessageIter *i, const char *property, void *data) {
285 if (streq(property, "PreparingForShutdown"))
286 b = !!(m->delayed_what & INHIBIT_SHUTDOWN);
288 b = !!(m->delayed_what & INHIBIT_SLEEP);
290 dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b);
294 static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMessage **_reply) {
295 Session *session = NULL;
297 const char *type, *class, *seat, *tty, *display, *remote_user, *remote_host, *service;
298 uint32_t uid, leader, audit_id = 0;
299 dbus_bool_t remote, kill_processes;
300 char **controllers = NULL, **reset_controllers = NULL;
304 DBusMessageIter iter;
309 DBusMessage *reply = NULL;
316 if (!dbus_message_iter_init(message, &iter) ||
317 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
320 dbus_message_iter_get_basic(&iter, &uid);
322 if (!dbus_message_iter_next(&iter) ||
323 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
326 dbus_message_iter_get_basic(&iter, &leader);
329 !dbus_message_iter_next(&iter) ||
330 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
333 dbus_message_iter_get_basic(&iter, &service);
335 if (!dbus_message_iter_next(&iter) ||
336 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
339 dbus_message_iter_get_basic(&iter, &type);
340 t = session_type_from_string(type);
343 !dbus_message_iter_next(&iter) ||
344 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
347 dbus_message_iter_get_basic(&iter, &class);
351 c = session_class_from_string(class);
354 !dbus_message_iter_next(&iter) ||
355 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
358 dbus_message_iter_get_basic(&iter, &seat);
363 s = hashmap_get(m->seats, seat);
368 if (!dbus_message_iter_next(&iter) ||
369 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
372 dbus_message_iter_get_basic(&iter, &vtnr);
374 if (!dbus_message_iter_next(&iter) ||
375 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
378 dbus_message_iter_get_basic(&iter, &tty);
380 if (tty_is_vc(tty)) {
385 else if (s != m->vtconsole)
388 v = vtnr_from_tty(tty);
391 return v < 0 ? v : -EINVAL;
395 else if (vtnr != (uint32_t) v)
397 } else if (tty_is_console(tty)) {
401 else if (s != m->vtconsole)
407 } else if (!isempty(tty) && s && seat_is_vtconsole(s))
411 if (seat_can_multi_session(s)) {
420 if (!dbus_message_iter_next(&iter) ||
421 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
424 dbus_message_iter_get_basic(&iter, &display);
426 if (!dbus_message_iter_next(&iter) ||
427 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
430 dbus_message_iter_get_basic(&iter, &remote);
432 if (!dbus_message_iter_next(&iter) ||
433 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
436 dbus_message_iter_get_basic(&iter, &remote_user);
438 if (!dbus_message_iter_next(&iter) ||
439 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
442 dbus_message_iter_get_basic(&iter, &remote_host);
444 if (!dbus_message_iter_next(&iter) ||
445 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
446 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
449 r = bus_parse_strv_iter(&iter, &controllers);
453 if (strv_contains(controllers, "systemd") ||
454 !dbus_message_iter_next(&iter) ||
455 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
456 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) {
461 r = bus_parse_strv_iter(&iter, &reset_controllers);
465 if (strv_contains(reset_controllers, "systemd") ||
466 !dbus_message_iter_next(&iter) ||
467 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) {
472 dbus_message_iter_get_basic(&iter, &kill_processes);
474 r = manager_add_user_by_uid(m, uid, &user);
478 audit_session_from_pid(leader, &audit_id);
481 asprintf(&id, "%lu", (unsigned long) audit_id);
488 session = hashmap_get(m->sessions, id);
493 fifo_fd = session_create_fifo(session);
499 /* Session already exists, client is probably
500 * something like "su" which changes uid but
501 * is still the same audit session */
503 reply = dbus_message_new_method_return(message);
509 p = session_bus_path(session);
515 seat = session->seat ? session->seat->id : "";
516 vtnr = session->vtnr;
517 b = dbus_message_append_args(
519 DBUS_TYPE_STRING, &session->id,
520 DBUS_TYPE_OBJECT_PATH, &p,
521 DBUS_TYPE_STRING, &session->user->runtime_path,
522 DBUS_TYPE_UNIX_FD, &fifo_fd,
523 DBUS_TYPE_STRING, &seat,
524 DBUS_TYPE_UINT32, &vtnr,
533 close_nointr_nofail(fifo_fd);
536 strv_free(controllers);
537 strv_free(reset_controllers);
547 if (asprintf(&id, "c%lu", ++m->session_counter) < 0) {
552 } while (hashmap_get(m->sessions, id));
555 r = manager_add_session(m, user, id, &session);
560 session->leader = leader;
561 session->audit_id = audit_id;
564 session->remote = remote;
565 session->controllers = controllers;
566 session->reset_controllers = reset_controllers;
567 session->kill_processes = kill_processes;
568 session->vtnr = vtnr;
570 controllers = reset_controllers = NULL;
573 session->tty = strdup(tty);
580 if (!isempty(display)) {
581 session->display = strdup(display);
582 if (!session->display) {
588 if (!isempty(remote_user)) {
589 session->remote_user = strdup(remote_user);
590 if (!session->remote_user) {
596 if (!isempty(remote_host)) {
597 session->remote_host = strdup(remote_host);
598 if (!session->remote_host) {
604 if (!isempty(service)) {
605 session->service = strdup(service);
606 if (!session->service) {
612 fifo_fd = session_create_fifo(session);
619 r = seat_attach_session(s, session);
624 r = session_start(session);
628 reply = dbus_message_new_method_return(message);
634 p = session_bus_path(session);
640 seat = s ? s->id : "";
641 b = dbus_message_append_args(
643 DBUS_TYPE_STRING, &session->id,
644 DBUS_TYPE_OBJECT_PATH, &p,
645 DBUS_TYPE_STRING, &session->user->runtime_path,
646 DBUS_TYPE_UNIX_FD, &fifo_fd,
647 DBUS_TYPE_STRING, &seat,
648 DBUS_TYPE_UINT32, &vtnr,
657 close_nointr_nofail(fifo_fd);
663 strv_free(controllers);
664 strv_free(reset_controllers);
667 session_add_to_gc_queue(session);
670 user_add_to_gc_queue(user);
673 close_nointr_nofail(fifo_fd);
676 dbus_message_unref(reply);
681 static int bus_manager_inhibit(Manager *m, DBusConnection *connection, DBusMessage *message, DBusError *error, DBusMessage **_reply) {
684 const char *who, *why, *what, *mode;
690 DBusMessage *reply = NULL;
698 if (!dbus_message_get_args(
701 DBUS_TYPE_STRING, &what,
702 DBUS_TYPE_STRING, &who,
703 DBUS_TYPE_STRING, &why,
704 DBUS_TYPE_STRING, &mode,
705 DBUS_TYPE_INVALID)) {
710 w = inhibit_what_from_string(what);
716 mm = inhibit_mode_from_string(mode);
722 r = verify_polkit(connection, message,
724 "org.freedesktop.login1.inhibit-block" :
725 "org.freedesktop.login1.inhibit-delay", false, NULL, error);
729 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
730 if (ul == (unsigned long) -1) {
735 pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
745 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
749 } while (hashmap_get(m->inhibitors, id));
751 r = manager_add_inhibitor(m, id, &i);
761 i->why = strdup(why);
762 i->who = strdup(who);
764 if (!i->why || !i->who) {
769 fifo_fd = inhibitor_create_fifo(i);
775 reply = dbus_message_new_method_return(message);
781 if (!dbus_message_append_args(
783 DBUS_TYPE_UNIX_FD, &fifo_fd,
784 DBUS_TYPE_INVALID)) {
789 close_nointr_nofail(fifo_fd);
801 close_nointr_nofail(fifo_fd);
804 dbus_message_unref(reply);
809 static int trigger_device(Manager *m, struct udev_device *d) {
810 struct udev_enumerate *e;
811 struct udev_list_entry *first, *item;
816 e = udev_enumerate_new(m->udev);
823 if (udev_enumerate_add_match_parent(e, d) < 0) {
829 if (udev_enumerate_scan_devices(e) < 0) {
834 first = udev_enumerate_get_list_entry(e);
835 udev_list_entry_foreach(item, first) {
839 p = udev_list_entry_get_name(item);
841 t = strappend(p, "/uevent");
847 write_one_line_file(t, "change");
855 udev_enumerate_unref(e);
860 static int attach_device(Manager *m, const char *seat, const char *sysfs) {
861 struct udev_device *d;
862 char *rule = NULL, *file = NULL;
863 const char *id_for_seat;
870 d = udev_device_new_from_syspath(m->udev, sysfs);
874 if (!udev_device_has_tag(d, "seat")) {
879 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
885 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
890 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
895 mkdir_p_label("/etc/udev/rules.d", 0755);
896 r = write_one_line_file_atomic(file, rule);
900 r = trigger_device(m, d);
907 udev_device_unref(d);
912 static int flush_devices(Manager *m) {
917 d = opendir("/etc/udev/rules.d");
920 log_warning("Failed to open /etc/udev/rules.d: %m");
924 while ((de = readdir(d))) {
926 if (!dirent_is_file(de))
929 if (!startswith(de->d_name, "72-seat-"))
932 if (!endswith(de->d_name, ".rules"))
935 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
936 log_warning("Failed to unlink %s: %m", de->d_name);
942 return trigger_device(m, NULL);
945 static int have_multiple_sessions(
946 DBusConnection *connection,
948 DBusMessage *message,
957 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
958 if (ul == (unsigned long) -1)
961 /* Check for other users' sessions. Greeter sessions do not count. */
962 HASHMAP_FOREACH(session, m->sessions, i)
963 if (session->class == SESSION_USER && session->user->uid != ul)
969 static int send_start_unit(DBusConnection *connection, const char *unit_name, DBusError *error) {
970 DBusMessage *message, *reply;
971 const char *mode = "replace";
976 message = dbus_message_new_method_call(
977 "org.freedesktop.systemd1",
978 "/org/freedesktop/systemd1",
979 "org.freedesktop.systemd1.Manager",
984 if (!dbus_message_append_args(message,
985 DBUS_TYPE_STRING, &unit_name,
986 DBUS_TYPE_STRING, &mode,
987 DBUS_TYPE_INVALID)) {
988 dbus_message_unref(message);
992 reply = dbus_connection_send_with_reply_and_block(connection, message, -1, error);
993 dbus_message_unref(message);
998 dbus_message_unref(reply);
1002 static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
1003 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
1004 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
1005 [INHIBIT_SLEEP] = "PrepareForSleep"
1008 dbus_bool_t active = _active;
1009 DBusMessage *message;
1014 assert(w < _INHIBIT_WHAT_MAX);
1015 assert(signal_name[w]);
1017 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1021 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1022 !dbus_connection_send(m->bus, message, NULL))
1025 dbus_message_unref(message);
1029 static int delay_shutdown_or_sleep(Manager *m, InhibitWhat w, const char *unit_name) {
1032 assert(w < _INHIBIT_WHAT_MAX);
1034 /* Tell everybody to prepare for shutdown/sleep */
1035 send_prepare_for(m, w, true);
1037 /* Update timestamp for timeout */
1038 if (!m->delayed_unit)
1039 m->delayed_timestamp = now(CLOCK_MONOTONIC);
1041 /* Remember what we want to do, possibly overriding what kind
1042 * of unit we previously queued. */
1043 m->delayed_unit = unit_name;
1044 m->delayed_what = w;
1049 static int bus_manager_can_shutdown_or_sleep(
1051 DBusConnection *connection,
1052 DBusMessage *message,
1055 const char *action_multiple_sessions,
1056 const char *action_ignore_inhibit,
1057 const char *sleep_type,
1059 DBusMessage **_reply) {
1061 bool multiple_sessions, challenge, blocked, b;
1063 DBusMessage *reply = NULL;
1070 assert(w <= _INHIBIT_WHAT_MAX);
1072 assert(action_multiple_sessions);
1073 assert(action_ignore_inhibit);
1078 r = can_sleep(sleep_type);
1088 r = have_multiple_sessions(connection, m, message, error);
1092 multiple_sessions = r > 0;
1093 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL);
1095 if (multiple_sessions) {
1096 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1103 result = "challenge";
1109 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1113 if (r > 0 && !result)
1115 else if (challenge && (!result || streq(result, "yes")))
1116 result = "challenge";
1121 if (!multiple_sessions && !blocked) {
1122 /* If neither inhibit nor multiple sessions
1123 * apply then just check the normal policy */
1125 r = verify_polkit(connection, message, action, false, &challenge, error);
1132 result = "challenge";
1138 reply = dbus_message_new_method_return(message);
1142 b = dbus_message_append_args(
1144 DBUS_TYPE_STRING, &result,
1147 dbus_message_unref(reply);
1155 int bus_manager_shutdown_or_sleep_now_or_later(
1157 const char *unit_name,
1167 assert(w <= _INHIBIT_WHAT_MAX);
1170 m->inhibit_delay_max > 0 &&
1171 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL);
1174 /* Shutdown is delayed, keep in mind what we
1175 * want to do, and start a timeout */
1176 r = delay_shutdown_or_sleep(m, w, unit_name);
1178 /* Shutdown is not delayed, execute it
1180 r = send_start_unit(m->bus, unit_name, error);
1185 static int bus_manager_do_shutdown_or_sleep(
1187 DBusConnection *connection,
1188 DBusMessage *message,
1189 const char *unit_name,
1192 const char *action_multiple_sessions,
1193 const char *action_ignore_inhibit,
1194 const char *sleep_type,
1196 DBusMessage **_reply) {
1198 dbus_bool_t interactive;
1199 bool multiple_sessions, blocked;
1200 DBusMessage *reply = NULL;
1208 assert(w <= _INHIBIT_WHAT_MAX);
1210 assert(action_multiple_sessions);
1211 assert(action_ignore_inhibit);
1215 if (!dbus_message_get_args(
1218 DBUS_TYPE_BOOLEAN, &interactive,
1223 r = can_sleep(sleep_type);
1231 r = have_multiple_sessions(connection, m, message, error);
1235 multiple_sessions = r > 0;
1236 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL);
1238 if (multiple_sessions) {
1239 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1245 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1250 if (!multiple_sessions && !blocked) {
1251 r = verify_polkit(connection, message, action, interactive, NULL, error);
1256 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
1260 reply = dbus_message_new_method_return(message);
1268 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_button, handle_button, HandleButton);
1270 static const BusProperty bus_login_manager_properties[] = {
1271 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_path), true },
1272 { "Controllers", bus_property_append_strv, "as", offsetof(Manager, controllers), true },
1273 { "ResetControllers", bus_property_append_strv, "as", offsetof(Manager, reset_controllers), true },
1274 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1275 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1276 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1277 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1278 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1279 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1280 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
1281 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1282 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1283 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
1284 { "HandlePowerKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_power_key) },
1285 { "HandleSleepKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_sleep_key) },
1286 { "HandleLidSwitch", bus_manager_append_handle_button, "s", offsetof(Manager, handle_lid_switch) },
1287 { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
1288 { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
1292 static DBusHandlerResult manager_message_handler(
1293 DBusConnection *connection,
1294 DBusMessage *message,
1297 Manager *m = userdata;
1300 DBusMessage *reply = NULL;
1307 dbus_error_init(&error);
1309 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1315 if (!dbus_message_get_args(
1318 DBUS_TYPE_STRING, &name,
1320 return bus_send_error_reply(connection, message, &error, -EINVAL);
1322 session = hashmap_get(m->sessions, name);
1324 return bus_send_error_reply(connection, message, &error, -ENOENT);
1326 reply = dbus_message_new_method_return(message);
1330 p = session_bus_path(session);
1334 b = dbus_message_append_args(
1336 DBUS_TYPE_OBJECT_PATH, &p,
1343 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1349 if (!dbus_message_get_args(
1352 DBUS_TYPE_UINT32, &pid,
1354 return bus_send_error_reply(connection, message, &error, -EINVAL);
1356 r = manager_get_session_by_pid(m, pid, &session);
1358 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1360 reply = dbus_message_new_method_return(message);
1364 p = session_bus_path(session);
1368 b = dbus_message_append_args(
1370 DBUS_TYPE_OBJECT_PATH, &p,
1377 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1383 if (!dbus_message_get_args(
1386 DBUS_TYPE_UINT32, &uid,
1388 return bus_send_error_reply(connection, message, &error, -EINVAL);
1390 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1392 return bus_send_error_reply(connection, message, &error, -ENOENT);
1394 reply = dbus_message_new_method_return(message);
1398 p = user_bus_path(user);
1402 b = dbus_message_append_args(
1404 DBUS_TYPE_OBJECT_PATH, &p,
1411 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1417 if (!dbus_message_get_args(
1420 DBUS_TYPE_STRING, &name,
1422 return bus_send_error_reply(connection, message, &error, -EINVAL);
1424 seat = hashmap_get(m->seats, name);
1426 return bus_send_error_reply(connection, message, &error, -ENOENT);
1428 reply = dbus_message_new_method_return(message);
1432 p = seat_bus_path(seat);
1436 b = dbus_message_append_args(
1438 DBUS_TYPE_OBJECT_PATH, &p,
1445 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1449 DBusMessageIter iter, sub;
1450 const char *empty = "";
1452 reply = dbus_message_new_method_return(message);
1456 dbus_message_iter_init_append(reply, &iter);
1458 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1461 HASHMAP_FOREACH(session, m->sessions, i) {
1462 DBusMessageIter sub2;
1465 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1468 uid = session->user->uid;
1470 p = session_bus_path(session);
1474 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1475 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1476 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1477 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1478 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1485 if (!dbus_message_iter_close_container(&sub, &sub2))
1489 if (!dbus_message_iter_close_container(&iter, &sub))
1492 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1496 DBusMessageIter iter, sub;
1498 reply = dbus_message_new_method_return(message);
1502 dbus_message_iter_init_append(reply, &iter);
1504 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1507 HASHMAP_FOREACH(user, m->users, i) {
1508 DBusMessageIter sub2;
1511 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1516 p = user_bus_path(user);
1520 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1521 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1522 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1529 if (!dbus_message_iter_close_container(&sub, &sub2))
1533 if (!dbus_message_iter_close_container(&iter, &sub))
1536 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1540 DBusMessageIter iter, sub;
1542 reply = dbus_message_new_method_return(message);
1546 dbus_message_iter_init_append(reply, &iter);
1548 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1551 HASHMAP_FOREACH(seat, m->seats, i) {
1552 DBusMessageIter sub2;
1554 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1557 p = seat_bus_path(seat);
1561 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1562 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1569 if (!dbus_message_iter_close_container(&sub, &sub2))
1573 if (!dbus_message_iter_close_container(&iter, &sub))
1576 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1577 Inhibitor *inhibitor;
1579 DBusMessageIter iter, sub;
1581 reply = dbus_message_new_method_return(message);
1585 dbus_message_iter_init_append(reply, &iter);
1587 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1590 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1591 DBusMessageIter sub2;
1592 dbus_uint32_t uid, pid;
1593 const char *what, *who, *why, *mode;
1595 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1598 what = strempty(inhibit_what_to_string(inhibitor->what));
1599 who = strempty(inhibitor->who);
1600 why = strempty(inhibitor->why);
1601 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
1602 uid = (dbus_uint32_t) inhibitor->uid;
1603 pid = (dbus_uint32_t) inhibitor->pid;
1605 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1606 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1607 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1608 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
1609 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1610 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1613 if (!dbus_message_iter_close_container(&sub, &sub2))
1617 if (!dbus_message_iter_close_container(&iter, &sub))
1620 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1622 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1625 return bus_send_error_reply(connection, message, &error, r);
1628 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1630 r = bus_manager_create_session(m, message, &reply);
1632 /* Don't delay the work on OOM here, since it might be
1633 * triggered by a low RLIMIT_NOFILE here (since we
1634 * send a dupped fd to the client), and we'd rather
1635 * see this fail quickly then be retried later */
1638 return bus_send_error_reply(connection, message, NULL, r);
1640 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1644 if (!dbus_message_get_args(
1647 DBUS_TYPE_STRING, &name,
1649 return bus_send_error_reply(connection, message, &error, -EINVAL);
1651 session = hashmap_get(m->sessions, name);
1653 return bus_send_error_reply(connection, message, &error, -ENOENT);
1655 /* We use the FIFO to detect stray sessions where the
1656 process invoking PAM dies abnormally. We need to make
1657 sure that that process is not killed if at the clean
1658 end of the session it closes the FIFO. Hence, with
1659 this call explicitly turn off the FIFO logic, so that
1660 the PAM code can finish clean up on its own */
1661 session_remove_fifo(session);
1663 reply = dbus_message_new_method_return(message);
1667 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1671 if (!dbus_message_get_args(
1674 DBUS_TYPE_STRING, &name,
1676 return bus_send_error_reply(connection, message, &error, -EINVAL);
1678 session = hashmap_get(m->sessions, name);
1680 return bus_send_error_reply(connection, message, &error, -ENOENT);
1682 r = session_activate(session);
1684 return bus_send_error_reply(connection, message, NULL, r);
1686 reply = dbus_message_new_method_return(message);
1690 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1691 const char *session_name, *seat_name;
1695 /* Same as ActivateSession() but refuses to work if
1696 * the seat doesn't match */
1698 if (!dbus_message_get_args(
1701 DBUS_TYPE_STRING, &session_name,
1702 DBUS_TYPE_STRING, &seat_name,
1704 return bus_send_error_reply(connection, message, &error, -EINVAL);
1706 session = hashmap_get(m->sessions, session_name);
1708 return bus_send_error_reply(connection, message, &error, -ENOENT);
1710 seat = hashmap_get(m->seats, seat_name);
1712 return bus_send_error_reply(connection, message, &error, -ENOENT);
1714 if (session->seat != seat)
1715 return bus_send_error_reply(connection, message, &error, -EINVAL);
1717 r = session_activate(session);
1719 return bus_send_error_reply(connection, message, NULL, r);
1721 reply = dbus_message_new_method_return(message);
1725 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1726 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1730 if (!dbus_message_get_args(
1733 DBUS_TYPE_STRING, &name,
1735 return bus_send_error_reply(connection, message, &error, -EINVAL);
1737 session = hashmap_get(m->sessions, name);
1739 return bus_send_error_reply(connection, message, &error, -ENOENT);
1741 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1744 reply = dbus_message_new_method_return(message);
1748 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1755 if (!dbus_message_get_args(
1758 DBUS_TYPE_STRING, &name,
1759 DBUS_TYPE_STRING, &swho,
1760 DBUS_TYPE_INT32, &signo,
1762 return bus_send_error_reply(connection, message, &error, -EINVAL);
1767 who = kill_who_from_string(swho);
1769 return bus_send_error_reply(connection, message, &error, -EINVAL);
1772 if (signo <= 0 || signo >= _NSIG)
1773 return bus_send_error_reply(connection, message, &error, -EINVAL);
1775 session = hashmap_get(m->sessions, name);
1777 return bus_send_error_reply(connection, message, &error, -ENOENT);
1779 r = session_kill(session, who, signo);
1781 return bus_send_error_reply(connection, message, NULL, r);
1783 reply = dbus_message_new_method_return(message);
1787 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1792 if (!dbus_message_get_args(
1795 DBUS_TYPE_UINT32, &uid,
1796 DBUS_TYPE_INT32, &signo,
1798 return bus_send_error_reply(connection, message, &error, -EINVAL);
1800 if (signo <= 0 || signo >= _NSIG)
1801 return bus_send_error_reply(connection, message, &error, -EINVAL);
1803 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1805 return bus_send_error_reply(connection, message, &error, -ENOENT);
1807 r = user_kill(user, signo);
1809 return bus_send_error_reply(connection, message, NULL, r);
1811 reply = dbus_message_new_method_return(message);
1815 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1819 if (!dbus_message_get_args(
1822 DBUS_TYPE_STRING, &name,
1824 return bus_send_error_reply(connection, message, &error, -EINVAL);
1826 session = hashmap_get(m->sessions, name);
1828 return bus_send_error_reply(connection, message, &error, -ENOENT);
1830 r = session_stop(session);
1832 return bus_send_error_reply(connection, message, NULL, r);
1834 reply = dbus_message_new_method_return(message);
1838 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1842 if (!dbus_message_get_args(
1845 DBUS_TYPE_UINT32, &uid,
1847 return bus_send_error_reply(connection, message, &error, -EINVAL);
1849 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1851 return bus_send_error_reply(connection, message, &error, -ENOENT);
1853 r = user_stop(user);
1855 return bus_send_error_reply(connection, message, NULL, r);
1857 reply = dbus_message_new_method_return(message);
1861 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1865 if (!dbus_message_get_args(
1868 DBUS_TYPE_STRING, &name,
1870 return bus_send_error_reply(connection, message, &error, -EINVAL);
1872 seat = hashmap_get(m->seats, name);
1874 return bus_send_error_reply(connection, message, &error, -ENOENT);
1876 r = seat_stop_sessions(seat);
1878 return bus_send_error_reply(connection, message, NULL, r);
1880 reply = dbus_message_new_method_return(message);
1884 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
1887 dbus_bool_t b, interactive;
1890 if (!dbus_message_get_args(
1893 DBUS_TYPE_UINT32, &uid,
1894 DBUS_TYPE_BOOLEAN, &b,
1895 DBUS_TYPE_BOOLEAN, &interactive,
1897 return bus_send_error_reply(connection, message, &error, -EINVAL);
1902 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
1904 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
1906 return bus_send_error_reply(connection, message, &error, r);
1908 mkdir_p_label("/var/lib/systemd", 0755);
1910 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
1912 return bus_send_error_reply(connection, message, &error, r);
1914 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
1925 return bus_send_error_reply(connection, message, &error, r);
1927 if (manager_add_user_by_uid(m, uid, &u) >= 0)
1936 if (r < 0 && errno != ENOENT)
1937 return bus_send_error_reply(connection, message, &error, -errno);
1939 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1941 user_add_to_gc_queue(u);
1944 reply = dbus_message_new_method_return(message);
1948 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
1949 const char *sysfs, *seat;
1950 dbus_bool_t interactive;
1952 if (!dbus_message_get_args(
1955 DBUS_TYPE_STRING, &seat,
1956 DBUS_TYPE_STRING, &sysfs,
1957 DBUS_TYPE_BOOLEAN, &interactive,
1959 return bus_send_error_reply(connection, message, &error, -EINVAL);
1961 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
1962 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1964 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
1966 return bus_send_error_reply(connection, message, &error, r);
1968 r = attach_device(m, seat, sysfs);
1970 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1972 reply = dbus_message_new_method_return(message);
1977 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
1978 dbus_bool_t interactive;
1980 if (!dbus_message_get_args(
1983 DBUS_TYPE_BOOLEAN, &interactive,
1985 return bus_send_error_reply(connection, message, &error, -EINVAL);
1987 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
1989 return bus_send_error_reply(connection, message, &error, r);
1991 r = flush_devices(m);
1993 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1995 reply = dbus_message_new_method_return(message);
1999 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
2001 r = bus_manager_do_shutdown_or_sleep(
2002 m, connection, message,
2003 SPECIAL_POWEROFF_TARGET,
2005 "org.freedesktop.login1.power-off",
2006 "org.freedesktop.login1.power-off-multiple-sessions",
2007 "org.freedesktop.login1.power-off-ignore-inhibit",
2011 return bus_send_error_reply(connection, message, &error, r);
2012 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
2013 r = bus_manager_do_shutdown_or_sleep(
2014 m, connection, message,
2015 SPECIAL_REBOOT_TARGET,
2017 "org.freedesktop.login1.reboot",
2018 "org.freedesktop.login1.reboot-multiple-sessions",
2019 "org.freedesktop.login1.reboot-ignore-inhibit",
2023 return bus_send_error_reply(connection, message, &error, r);
2025 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2026 r = bus_manager_do_shutdown_or_sleep(
2027 m, connection, message,
2028 SPECIAL_SUSPEND_TARGET,
2030 "org.freedesktop.login1.suspend",
2031 "org.freedesktop.login1.suspend-multiple-sessions",
2032 "org.freedesktop.login1.suspend-ignore-inhibit",
2036 return bus_send_error_reply(connection, message, &error, r);
2037 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2038 r = bus_manager_do_shutdown_or_sleep(
2039 m, connection, message,
2040 SPECIAL_HIBERNATE_TARGET,
2042 "org.freedesktop.login1.hibernate",
2043 "org.freedesktop.login1.hibernate-multiple-sessions",
2044 "org.freedesktop.login1.hibernate-ignore-inhibit",
2048 return bus_send_error_reply(connection, message, &error, r);
2050 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2052 r = bus_manager_can_shutdown_or_sleep(
2053 m, connection, message,
2055 "org.freedesktop.login1.power-off",
2056 "org.freedesktop.login1.power-off-multiple-sessions",
2057 "org.freedesktop.login1.power-off-ignore-inhibit",
2061 return bus_send_error_reply(connection, message, &error, r);
2062 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2063 r = bus_manager_can_shutdown_or_sleep(
2064 m, connection, message,
2066 "org.freedesktop.login1.reboot",
2067 "org.freedesktop.login1.reboot-multiple-sessions",
2068 "org.freedesktop.login1.reboot-ignore-inhibit",
2072 return bus_send_error_reply(connection, message, &error, r);
2074 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2075 r = bus_manager_can_shutdown_or_sleep(
2076 m, connection, message,
2078 "org.freedesktop.login1.suspend",
2079 "org.freedesktop.login1.suspend-multiple-sessions",
2080 "org.freedesktop.login1.suspend-ignore-inhibit",
2084 return bus_send_error_reply(connection, message, &error, r);
2086 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2087 r = bus_manager_can_shutdown_or_sleep(
2088 m, connection, message,
2090 "org.freedesktop.login1.hibernate",
2091 "org.freedesktop.login1.hibernate-multiple-sessions",
2092 "org.freedesktop.login1.hibernate-ignore-inhibit",
2096 return bus_send_error_reply(connection, message, &error, r);
2098 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2099 char *introspection = NULL;
2108 if (!(reply = dbus_message_new_method_return(message)))
2111 /* We roll our own introspection code here, instead of
2112 * relying on bus_default_message_handler() because we
2113 * need to generate our introspection string
2116 if (!(f = open_memstream(&introspection, &size)))
2119 fputs(INTROSPECTION_BEGIN, f);
2121 HASHMAP_FOREACH(seat, m->seats, i) {
2122 p = bus_path_escape(seat->id);
2125 fprintf(f, "<node name=\"seat/%s\"/>", p);
2130 HASHMAP_FOREACH(user, m->users, i)
2131 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2133 HASHMAP_FOREACH(session, m->sessions, i) {
2134 p = bus_path_escape(session->id);
2137 fprintf(f, "<node name=\"session/%s\"/>", p);
2142 fputs(INTROSPECTION_END, f);
2146 free(introspection);
2155 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2156 free(introspection);
2160 free(introspection);
2162 const BusBoundProperties bps[] = {
2163 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2166 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2170 if (!dbus_connection_send(connection, reply, NULL))
2173 dbus_message_unref(reply);
2176 return DBUS_HANDLER_RESULT_HANDLED;
2180 dbus_message_unref(reply);
2182 dbus_error_free(&error);
2184 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2187 const DBusObjectPathVTable bus_manager_vtable = {
2188 .message_function = manager_message_handler
2191 DBusHandlerResult bus_message_filter(
2192 DBusConnection *connection,
2193 DBusMessage *message,
2196 Manager *m = userdata;
2203 dbus_error_init(&error);
2205 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
2208 if (!dbus_message_get_args(message, &error,
2209 DBUS_TYPE_STRING, &cgroup,
2211 log_error("Failed to parse Released message: %s", bus_error_message(&error));
2213 manager_cgroup_notify_empty(m, cgroup);
2216 dbus_error_free(&error);
2218 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2221 int manager_send_changed(Manager *manager, const char *properties) {
2227 m = bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties);
2231 if (!dbus_connection_send(manager->bus, m, NULL))
2238 dbus_message_unref(m);
2243 int manager_dispatch_delayed(Manager *manager) {
2244 const char *unit_name;
2251 if (!manager->delayed_unit)
2254 /* Continue delay? */
2256 manager->delayed_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC) &&
2257 manager_is_inhibited(manager, manager->delayed_what, INHIBIT_DELAY, NULL);
2261 /* Reset delay data */
2262 unit_name = manager->delayed_unit;
2263 manager->delayed_unit = NULL;
2265 /* Actually do the shutdown */
2266 dbus_error_init(&error);
2267 r = send_start_unit(manager->bus, unit_name, &error);
2269 log_warning("Failed to send delayed message: %s", bus_error_message_or_strerror(&error, -r));
2270 dbus_error_free(&error);
2274 /* Tell people about it */
2275 send_prepare_for(manager, manager->delayed_what, false);