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=\"CanPowerOff\">\n" \
139 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
141 " <method name=\"CanReboot\">\n" \
142 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
144 " <method name=\"Inhibit\">\n" \
145 " <arg name=\"what\" type=\"s\" direction=\"in\"/>\n" \
146 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
147 " <arg name=\"why\" type=\"s\" direction=\"in\"/>\n" \
148 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
149 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
151 " <method name=\"ListInhibitors\">\n" \
152 " <arg name=\"inhibitors\" type=\"a(ssssuu)\" direction=\"out\"/>\n" \
154 " <signal name=\"SessionNew\">\n" \
155 " <arg name=\"id\" type=\"s\"/>\n" \
156 " <arg name=\"path\" type=\"o\"/>\n" \
158 " <signal name=\"SessionRemoved\">\n" \
159 " <arg name=\"id\" type=\"s\"/>\n" \
160 " <arg name=\"path\" type=\"o\"/>\n" \
162 " <signal name=\"UserNew\">\n" \
163 " <arg name=\"uid\" type=\"u\"/>\n" \
164 " <arg name=\"path\" type=\"o\"/>\n" \
166 " <signal name=\"UserRemoved\">\n" \
167 " <arg name=\"uid\" type=\"u\"/>\n" \
168 " <arg name=\"path\" type=\"o\"/>\n" \
170 " <signal name=\"SeatNew\">\n" \
171 " <arg name=\"id\" type=\"s\"/>\n" \
172 " <arg name=\"path\" type=\"o\"/>\n" \
174 " <signal name=\"SeatRemoved\">\n" \
175 " <arg name=\"id\" type=\"s\"/>\n" \
176 " <arg name=\"path\" type=\"o\"/>\n" \
178 " <signal name=\"PrepareForShutdown\">\n" \
179 " <arg name=\"active\" type=\"b\"/>\n" \
181 " <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
182 " <property name=\"Controllers\" type=\"as\" access=\"read\"/>\n" \
183 " <property name=\"ResetControllers\" type=\"as\" access=\"read\"/>\n" \
184 " <property name=\"NAutoVTs\" type=\"u\" access=\"read\"/>\n" \
185 " <property name=\"KillOnlyUsers\" type=\"as\" access=\"read\"/>\n" \
186 " <property name=\"KillExcludeUsers\" type=\"as\" access=\"read\"/>\n" \
187 " <property name=\"KillUserProcesses\" type=\"b\" access=\"read\"/>\n" \
188 " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
189 " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
190 " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
191 " <property name=\"BlockInhibited\" type=\"s\" access=\"read\"/>\n" \
192 " <property name=\"DelayInhibited\" type=\"s\" access=\"read\"/>\n" \
193 " <property name=\"InhibitDelayMaxUSec\" type=\"t\" access=\"read\"/>\n" \
196 #define INTROSPECTION_BEGIN \
197 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
199 BUS_MANAGER_INTERFACE \
200 BUS_PROPERTIES_INTERFACE \
202 BUS_INTROSPECTABLE_INTERFACE
204 #define INTROSPECTION_END \
207 #define INTERFACES_LIST \
208 BUS_GENERIC_INTERFACES_LIST \
209 "org.freedesktop.login1.Manager\0"
211 static int bus_manager_append_idle_hint(DBusMessageIter
*i
, const char *property
, void *data
) {
219 b
= manager_get_idle_hint(m
, NULL
) > 0;
220 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_BOOLEAN
, &b
))
226 static int bus_manager_append_idle_hint_since(DBusMessageIter
*i
, const char *property
, void *data
) {
235 manager_get_idle_hint(m
, &t
);
236 u
= streq(property
, "IdleSinceHint") ? t
.realtime
: t
.monotonic
;
238 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_UINT64
, &u
))
244 static int bus_manager_append_inhibited(DBusMessageIter
*i
, const char *property
, void *data
) {
249 w
= manager_inhibit_what(m
, streq(property
, "BlockInhibited") ? INHIBIT_BLOCK
: INHIBIT_DELAY
);
250 p
= inhibit_what_to_string(w
);
252 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_STRING
, &p
))
258 static int bus_manager_create_session(Manager
*m
, DBusMessage
*message
, DBusMessage
**_reply
) {
259 Session
*session
= NULL
;
261 const char *type
, *class, *seat
, *tty
, *display
, *remote_user
, *remote_host
, *service
;
262 uint32_t uid
, leader
, audit_id
= 0;
263 dbus_bool_t remote
, kill_processes
;
264 char **controllers
= NULL
, **reset_controllers
= NULL
;
268 DBusMessageIter iter
;
273 DBusMessage
*reply
= NULL
;
280 if (!dbus_message_iter_init(message
, &iter
) ||
281 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_UINT32
)
284 dbus_message_iter_get_basic(&iter
, &uid
);
286 if (!dbus_message_iter_next(&iter
) ||
287 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_UINT32
)
290 dbus_message_iter_get_basic(&iter
, &leader
);
293 !dbus_message_iter_next(&iter
) ||
294 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_STRING
)
297 dbus_message_iter_get_basic(&iter
, &service
);
299 if (!dbus_message_iter_next(&iter
) ||
300 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_STRING
)
303 dbus_message_iter_get_basic(&iter
, &type
);
304 t
= session_type_from_string(type
);
307 !dbus_message_iter_next(&iter
) ||
308 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_STRING
)
311 dbus_message_iter_get_basic(&iter
, &class);
315 c
= session_class_from_string(class);
318 !dbus_message_iter_next(&iter
) ||
319 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_STRING
)
322 dbus_message_iter_get_basic(&iter
, &seat
);
327 s
= hashmap_get(m
->seats
, seat
);
332 if (!dbus_message_iter_next(&iter
) ||
333 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_UINT32
)
336 dbus_message_iter_get_basic(&iter
, &vtnr
);
338 if (!dbus_message_iter_next(&iter
) ||
339 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_STRING
)
342 dbus_message_iter_get_basic(&iter
, &tty
);
344 if (tty_is_vc(tty
)) {
349 else if (s
!= m
->vtconsole
)
352 v
= vtnr_from_tty(tty
);
355 return v
< 0 ? v
: -EINVAL
;
359 else if (vtnr
!= (uint32_t) v
)
361 } else if (tty_is_console(tty
)) {
365 else if (s
!= m
->vtconsole
)
371 } else if (!isempty(tty
) && s
&& seat_is_vtconsole(s
))
375 if (seat_can_multi_session(s
)) {
384 if (!dbus_message_iter_next(&iter
) ||
385 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_STRING
)
388 dbus_message_iter_get_basic(&iter
, &display
);
390 if (!dbus_message_iter_next(&iter
) ||
391 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_BOOLEAN
)
394 dbus_message_iter_get_basic(&iter
, &remote
);
396 if (!dbus_message_iter_next(&iter
) ||
397 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_STRING
)
400 dbus_message_iter_get_basic(&iter
, &remote_user
);
402 if (!dbus_message_iter_next(&iter
) ||
403 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_STRING
)
406 dbus_message_iter_get_basic(&iter
, &remote_host
);
408 if (!dbus_message_iter_next(&iter
) ||
409 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_ARRAY
||
410 dbus_message_iter_get_element_type(&iter
) != DBUS_TYPE_STRING
)
413 r
= bus_parse_strv_iter(&iter
, &controllers
);
417 if (strv_contains(controllers
, "systemd") ||
418 !dbus_message_iter_next(&iter
) ||
419 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_ARRAY
||
420 dbus_message_iter_get_element_type(&iter
) != DBUS_TYPE_STRING
) {
425 r
= bus_parse_strv_iter(&iter
, &reset_controllers
);
429 if (strv_contains(reset_controllers
, "systemd") ||
430 !dbus_message_iter_next(&iter
) ||
431 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_BOOLEAN
) {
436 dbus_message_iter_get_basic(&iter
, &kill_processes
);
438 r
= manager_add_user_by_uid(m
, uid
, &user
);
442 audit_session_from_pid(leader
, &audit_id
);
445 asprintf(&id
, "%lu", (unsigned long) audit_id
);
452 session
= hashmap_get(m
->sessions
, id
);
457 fifo_fd
= session_create_fifo(session
);
463 /* Session already exists, client is probably
464 * something like "su" which changes uid but
465 * is still the same audit session */
467 reply
= dbus_message_new_method_return(message
);
473 p
= session_bus_path(session
);
479 seat
= session
->seat
? session
->seat
->id
: "";
480 vtnr
= session
->vtnr
;
481 b
= dbus_message_append_args(
483 DBUS_TYPE_STRING
, &session
->id
,
484 DBUS_TYPE_OBJECT_PATH
, &p
,
485 DBUS_TYPE_STRING
, &session
->user
->runtime_path
,
486 DBUS_TYPE_UNIX_FD
, &fifo_fd
,
487 DBUS_TYPE_STRING
, &seat
,
488 DBUS_TYPE_UINT32
, &vtnr
,
497 close_nointr_nofail(fifo_fd
);
500 strv_free(controllers
);
501 strv_free(reset_controllers
);
511 if (asprintf(&id
, "c%lu", ++m
->session_counter
) < 0) {
516 } while (hashmap_get(m
->sessions
, id
));
519 r
= manager_add_session(m
, user
, id
, &session
);
524 session
->leader
= leader
;
525 session
->audit_id
= audit_id
;
528 session
->remote
= remote
;
529 session
->controllers
= controllers
;
530 session
->reset_controllers
= reset_controllers
;
531 session
->kill_processes
= kill_processes
;
532 session
->vtnr
= vtnr
;
534 controllers
= reset_controllers
= NULL
;
537 session
->tty
= strdup(tty
);
544 if (!isempty(display
)) {
545 session
->display
= strdup(display
);
546 if (!session
->display
) {
552 if (!isempty(remote_user
)) {
553 session
->remote_user
= strdup(remote_user
);
554 if (!session
->remote_user
) {
560 if (!isempty(remote_host
)) {
561 session
->remote_host
= strdup(remote_host
);
562 if (!session
->remote_host
) {
568 if (!isempty(service
)) {
569 session
->service
= strdup(service
);
570 if (!session
->service
) {
576 fifo_fd
= session_create_fifo(session
);
583 r
= seat_attach_session(s
, session
);
588 r
= session_start(session
);
592 reply
= dbus_message_new_method_return(message
);
598 p
= session_bus_path(session
);
604 seat
= s
? s
->id
: "";
605 b
= dbus_message_append_args(
607 DBUS_TYPE_STRING
, &session
->id
,
608 DBUS_TYPE_OBJECT_PATH
, &p
,
609 DBUS_TYPE_STRING
, &session
->user
->runtime_path
,
610 DBUS_TYPE_UNIX_FD
, &fifo_fd
,
611 DBUS_TYPE_STRING
, &seat
,
612 DBUS_TYPE_UINT32
, &vtnr
,
621 close_nointr_nofail(fifo_fd
);
627 strv_free(controllers
);
628 strv_free(reset_controllers
);
631 session_add_to_gc_queue(session
);
634 user_add_to_gc_queue(user
);
637 close_nointr_nofail(fifo_fd
);
640 dbus_message_unref(reply
);
645 static int bus_manager_inhibit(Manager
*m
, DBusConnection
*connection
, DBusMessage
*message
, DBusError
*error
, DBusMessage
**_reply
) {
648 const char *who
, *why
, *what
, *mode
;
654 DBusMessage
*reply
= NULL
;
662 if (!dbus_message_get_args(
665 DBUS_TYPE_STRING
, &what
,
666 DBUS_TYPE_STRING
, &who
,
667 DBUS_TYPE_STRING
, &why
,
668 DBUS_TYPE_STRING
, &mode
,
669 DBUS_TYPE_INVALID
)) {
674 w
= inhibit_what_from_string(what
);
680 mm
= inhibit_mode_from_string(mode
);
686 r
= verify_polkit(connection
, message
,
688 "org.freedesktop.login1.inhibit-block" :
689 "org.freedesktop.login1.inhibit-delay", false, NULL
, error
);
693 ul
= dbus_bus_get_unix_user(connection
, dbus_message_get_sender(message
), error
);
694 if (ul
== (unsigned long) -1) {
699 pid
= bus_get_unix_process_id(connection
, dbus_message_get_sender(message
), error
);
709 if (asprintf(&id
, "%lu", ++m
->inhibit_counter
) < 0) {
713 } while (hashmap_get(m
->inhibitors
, id
));
715 r
= manager_add_inhibitor(m
, id
, &i
);
725 i
->why
= strdup(why
);
726 i
->who
= strdup(who
);
728 if (!i
->why
|| !i
->who
) {
733 fifo_fd
= inhibitor_create_fifo(i
);
739 reply
= dbus_message_new_method_return(message
);
745 if (!dbus_message_append_args(
747 DBUS_TYPE_UNIX_FD
, &fifo_fd
,
748 DBUS_TYPE_INVALID
)) {
753 close_nointr_nofail(fifo_fd
);
765 close_nointr_nofail(fifo_fd
);
768 dbus_message_unref(reply
);
773 static int trigger_device(Manager
*m
, struct udev_device
*d
) {
774 struct udev_enumerate
*e
;
775 struct udev_list_entry
*first
, *item
;
780 e
= udev_enumerate_new(m
->udev
);
787 if (udev_enumerate_add_match_parent(e
, d
) < 0) {
793 if (udev_enumerate_scan_devices(e
) < 0) {
798 first
= udev_enumerate_get_list_entry(e
);
799 udev_list_entry_foreach(item
, first
) {
803 p
= udev_list_entry_get_name(item
);
805 t
= strappend(p
, "/uevent");
811 write_one_line_file(t
, "change");
819 udev_enumerate_unref(e
);
824 static int attach_device(Manager
*m
, const char *seat
, const char *sysfs
) {
825 struct udev_device
*d
;
826 char *rule
= NULL
, *file
= NULL
;
827 const char *id_for_seat
;
834 d
= udev_device_new_from_syspath(m
->udev
, sysfs
);
838 if (!udev_device_has_tag(d
, "seat")) {
843 id_for_seat
= udev_device_get_property_value(d
, "ID_FOR_SEAT");
849 if (asprintf(&file
, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat
) < 0) {
854 if (asprintf(&rule
, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat
, seat
) < 0) {
859 mkdir_p("/etc/udev/rules.d", 0755);
860 r
= write_one_line_file_atomic(file
, rule
);
864 r
= trigger_device(m
, d
);
871 udev_device_unref(d
);
876 static int flush_devices(Manager
*m
) {
881 d
= opendir("/etc/udev/rules.d");
884 log_warning("Failed to open /etc/udev/rules.d: %m");
888 while ((de
= readdir(d
))) {
890 if (!dirent_is_file(de
))
893 if (!startswith(de
->d_name
, "72-seat-"))
896 if (!endswith(de
->d_name
, ".rules"))
899 if (unlinkat(dirfd(d
), de
->d_name
, 0) < 0)
900 log_warning("Failed to unlink %s: %m", de
->d_name
);
906 return trigger_device(m
, NULL
);
909 static int have_multiple_sessions(
910 DBusConnection
*connection
,
912 DBusMessage
*message
,
919 if (hashmap_size(m
->sessions
) > 1)
922 /* Hmm, there's only one session, but let's make sure it
923 * actually belongs to the user who is asking. If not, better
924 * be safe than sorry. */
926 s
= hashmap_first(m
->sessions
);
930 ul
= dbus_bus_get_unix_user(connection
, dbus_message_get_sender(message
), error
);
931 if (ul
== (unsigned long) -1)
934 return s
->user
->uid
!= ul
;
940 static int send_start_unit(DBusConnection
*connection
, const char *name
, DBusError
*error
) {
941 DBusMessage
*message
, *reply
;
942 const char *mode
= "replace";
947 message
= dbus_message_new_method_call(
948 "org.freedesktop.systemd1",
949 "/org/freedesktop/systemd1",
950 "org.freedesktop.systemd1.Manager",
955 if (!dbus_message_append_args(message
,
956 DBUS_TYPE_STRING
, &name
,
957 DBUS_TYPE_STRING
, &mode
,
958 DBUS_TYPE_INVALID
)) {
959 dbus_message_unref(message
);
963 reply
= dbus_connection_send_with_reply_and_block(connection
, message
, -1, error
);
964 dbus_message_unref(message
);
969 dbus_message_unref(reply
);
973 static int send_prepare_for_shutdown(Manager
*m
, bool _active
) {
974 dbus_bool_t active
= _active
;
975 DBusMessage
*message
;
980 message
= dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", "PrepareForShutdown");
984 if (!dbus_message_append_args(message
, DBUS_TYPE_BOOLEAN
, &active
, DBUS_TYPE_INVALID
) ||
985 !dbus_connection_send(m
->bus
, message
, NULL
))
988 dbus_message_unref(message
);
992 static int delay_shutdown(Manager
*m
, const char *name
) {
995 if (!m
->delayed_shutdown
) {
996 /* Tell everybody to prepare for shutdown */
997 send_prepare_for_shutdown(m
, true);
999 /* Update timestamp for timeout */
1000 m
->delayed_shutdown_timestamp
= now(CLOCK_MONOTONIC
);
1003 /* Remember what we want to do, possibly overriding what kind
1004 * of shutdown we previously queued. */
1005 m
->delayed_shutdown
= name
;
1010 static const BusProperty bus_login_manager_properties
[] = {
1011 { "ControlGroupHierarchy", bus_property_append_string
, "s", offsetof(Manager
, cgroup_path
), true },
1012 { "Controllers", bus_property_append_strv
, "as", offsetof(Manager
, controllers
), true },
1013 { "ResetControllers", bus_property_append_strv
, "as", offsetof(Manager
, reset_controllers
), true },
1014 { "NAutoVTs", bus_property_append_unsigned
, "u", offsetof(Manager
, n_autovts
) },
1015 { "KillOnlyUsers", bus_property_append_strv
, "as", offsetof(Manager
, kill_only_users
), true },
1016 { "KillExcludeUsers", bus_property_append_strv
, "as", offsetof(Manager
, kill_exclude_users
), true },
1017 { "KillUserProcesses", bus_property_append_bool
, "b", offsetof(Manager
, kill_user_processes
) },
1018 { "IdleHint", bus_manager_append_idle_hint
, "b", 0 },
1019 { "IdleSinceHint", bus_manager_append_idle_hint_since
, "t", 0 },
1020 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since
, "t", 0 },
1021 { "BlockInhibited", bus_manager_append_inhibited
, "s", 0 },
1022 { "DelayInhibited", bus_manager_append_inhibited
, "s", 0 },
1023 { "InhibitDelayMaxUSec", bus_property_append_usec
, "t", offsetof(Manager
, inhibit_delay_max
) },
1027 static DBusHandlerResult
manager_message_handler(
1028 DBusConnection
*connection
,
1029 DBusMessage
*message
,
1032 Manager
*m
= userdata
;
1035 DBusMessage
*reply
= NULL
;
1042 dbus_error_init(&error
);
1044 if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "GetSession")) {
1050 if (!dbus_message_get_args(
1053 DBUS_TYPE_STRING
, &name
,
1055 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1057 session
= hashmap_get(m
->sessions
, name
);
1059 return bus_send_error_reply(connection
, message
, &error
, -ENOENT
);
1061 reply
= dbus_message_new_method_return(message
);
1065 p
= session_bus_path(session
);
1069 b
= dbus_message_append_args(
1071 DBUS_TYPE_OBJECT_PATH
, &p
,
1078 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1084 if (!dbus_message_get_args(
1087 DBUS_TYPE_UINT32
, &pid
,
1089 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1091 r
= manager_get_session_by_pid(m
, pid
, &session
);
1093 return bus_send_error_reply(connection
, message
, NULL
, r
< 0 ? r
: -ENOENT
);
1095 reply
= dbus_message_new_method_return(message
);
1099 p
= session_bus_path(session
);
1103 b
= dbus_message_append_args(
1105 DBUS_TYPE_OBJECT_PATH
, &p
,
1112 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "GetUser")) {
1118 if (!dbus_message_get_args(
1121 DBUS_TYPE_UINT32
, &uid
,
1123 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1125 user
= hashmap_get(m
->users
, ULONG_TO_PTR((unsigned long) uid
));
1127 return bus_send_error_reply(connection
, message
, &error
, -ENOENT
);
1129 reply
= dbus_message_new_method_return(message
);
1133 p
= user_bus_path(user
);
1137 b
= dbus_message_append_args(
1139 DBUS_TYPE_OBJECT_PATH
, &p
,
1146 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "GetSeat")) {
1152 if (!dbus_message_get_args(
1155 DBUS_TYPE_STRING
, &name
,
1157 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1159 seat
= hashmap_get(m
->seats
, name
);
1161 return bus_send_error_reply(connection
, message
, &error
, -ENOENT
);
1163 reply
= dbus_message_new_method_return(message
);
1167 p
= seat_bus_path(seat
);
1171 b
= dbus_message_append_args(
1173 DBUS_TYPE_OBJECT_PATH
, &p
,
1180 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "ListSessions")) {
1184 DBusMessageIter iter
, sub
;
1185 const char *empty
= "";
1187 reply
= dbus_message_new_method_return(message
);
1191 dbus_message_iter_init_append(reply
, &iter
);
1193 if (!dbus_message_iter_open_container(&iter
, DBUS_TYPE_ARRAY
, "(susso)", &sub
))
1196 HASHMAP_FOREACH(session
, m
->sessions
, i
) {
1197 DBusMessageIter sub2
;
1200 if (!dbus_message_iter_open_container(&sub
, DBUS_TYPE_STRUCT
, NULL
, &sub2
))
1203 uid
= session
->user
->uid
;
1205 p
= session_bus_path(session
);
1209 if (!dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_STRING
, &session
->id
) ||
1210 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_UINT32
, &uid
) ||
1211 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_STRING
, &session
->user
->name
) ||
1212 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_STRING
, session
->seat
? (const char**) &session
->seat
->id
: &empty
) ||
1213 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_OBJECT_PATH
, &p
)) {
1220 if (!dbus_message_iter_close_container(&sub
, &sub2
))
1224 if (!dbus_message_iter_close_container(&iter
, &sub
))
1227 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "ListUsers")) {
1231 DBusMessageIter iter
, sub
;
1233 reply
= dbus_message_new_method_return(message
);
1237 dbus_message_iter_init_append(reply
, &iter
);
1239 if (!dbus_message_iter_open_container(&iter
, DBUS_TYPE_ARRAY
, "(uso)", &sub
))
1242 HASHMAP_FOREACH(user
, m
->users
, i
) {
1243 DBusMessageIter sub2
;
1246 if (!dbus_message_iter_open_container(&sub
, DBUS_TYPE_STRUCT
, NULL
, &sub2
))
1251 p
= user_bus_path(user
);
1255 if (!dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_UINT32
, &uid
) ||
1256 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_STRING
, &user
->name
) ||
1257 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_OBJECT_PATH
, &p
)) {
1264 if (!dbus_message_iter_close_container(&sub
, &sub2
))
1268 if (!dbus_message_iter_close_container(&iter
, &sub
))
1271 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "ListSeats")) {
1275 DBusMessageIter iter
, sub
;
1277 reply
= dbus_message_new_method_return(message
);
1281 dbus_message_iter_init_append(reply
, &iter
);
1283 if (!dbus_message_iter_open_container(&iter
, DBUS_TYPE_ARRAY
, "(so)", &sub
))
1286 HASHMAP_FOREACH(seat
, m
->seats
, i
) {
1287 DBusMessageIter sub2
;
1289 if (!dbus_message_iter_open_container(&sub
, DBUS_TYPE_STRUCT
, NULL
, &sub2
))
1292 p
= seat_bus_path(seat
);
1296 if (!dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_STRING
, &seat
->id
) ||
1297 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_OBJECT_PATH
, &p
)) {
1304 if (!dbus_message_iter_close_container(&sub
, &sub2
))
1308 if (!dbus_message_iter_close_container(&iter
, &sub
))
1311 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1312 Inhibitor
*inhibitor
;
1314 DBusMessageIter iter
, sub
;
1316 reply
= dbus_message_new_method_return(message
);
1320 dbus_message_iter_init_append(reply
, &iter
);
1322 if (!dbus_message_iter_open_container(&iter
, DBUS_TYPE_ARRAY
, "(ssssuu)", &sub
))
1325 HASHMAP_FOREACH(inhibitor
, m
->inhibitors
, i
) {
1326 DBusMessageIter sub2
;
1327 dbus_uint32_t uid
, pid
;
1328 const char *what
, *who
, *why
, *mode
;
1330 if (!dbus_message_iter_open_container(&sub
, DBUS_TYPE_STRUCT
, NULL
, &sub2
))
1333 what
= strempty(inhibit_what_to_string(inhibitor
->what
));
1334 who
= strempty(inhibitor
->who
);
1335 why
= strempty(inhibitor
->why
);
1336 mode
= strempty(inhibit_mode_to_string(inhibitor
->mode
));
1337 uid
= (dbus_uint32_t
) inhibitor
->uid
;
1338 pid
= (dbus_uint32_t
) inhibitor
->pid
;
1340 if (!dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_STRING
, &what
) ||
1341 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_STRING
, &who
) ||
1342 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_STRING
, &why
) ||
1343 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_STRING
, &mode
) ||
1344 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_UINT32
, &uid
) ||
1345 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_UINT32
, &pid
))
1348 if (!dbus_message_iter_close_container(&sub
, &sub2
))
1352 if (!dbus_message_iter_close_container(&iter
, &sub
))
1355 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "Inhibit")) {
1357 r
= bus_manager_inhibit(m
, connection
, message
, &error
, &reply
);
1360 return bus_send_error_reply(connection
, message
, &error
, r
);
1363 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "CreateSession")) {
1365 r
= bus_manager_create_session(m
, message
, &reply
);
1367 /* Don't delay the work on OOM here, since it might be
1368 * triggered by a low RLIMIT_NOFILE here (since we
1369 * send a dupped fd to the client), and we'd rather
1370 * see this fail quickly then be retried later */
1373 return bus_send_error_reply(connection
, message
, NULL
, r
);
1375 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1379 if (!dbus_message_get_args(
1382 DBUS_TYPE_STRING
, &name
,
1384 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1386 session
= hashmap_get(m
->sessions
, name
);
1388 return bus_send_error_reply(connection
, message
, &error
, -ENOENT
);
1390 /* We use the FIFO to detect stray sessions where the
1391 process invoking PAM dies abnormally. We need to make
1392 sure that that process is not killed if at the clean
1393 end of the session it closes the FIFO. Hence, with
1394 this call explicitly turn off the FIFO logic, so that
1395 the PAM code can finish clean up on its own */
1396 session_remove_fifo(session
);
1398 reply
= dbus_message_new_method_return(message
);
1402 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "ActivateSession")) {
1406 if (!dbus_message_get_args(
1409 DBUS_TYPE_STRING
, &name
,
1411 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1413 session
= hashmap_get(m
->sessions
, name
);
1415 return bus_send_error_reply(connection
, message
, &error
, -ENOENT
);
1417 r
= session_activate(session
);
1419 return bus_send_error_reply(connection
, message
, NULL
, r
);
1421 reply
= dbus_message_new_method_return(message
);
1425 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1426 const char *session_name
, *seat_name
;
1430 /* Same as ActivateSession() but refuses to work if
1431 * the seat doesn't match */
1433 if (!dbus_message_get_args(
1436 DBUS_TYPE_STRING
, &session_name
,
1437 DBUS_TYPE_STRING
, &seat_name
,
1439 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1441 session
= hashmap_get(m
->sessions
, session_name
);
1443 return bus_send_error_reply(connection
, message
, &error
, -ENOENT
);
1445 seat
= hashmap_get(m
->seats
, seat_name
);
1447 return bus_send_error_reply(connection
, message
, &error
, -ENOENT
);
1449 if (session
->seat
!= seat
)
1450 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1452 r
= session_activate(session
);
1454 return bus_send_error_reply(connection
, message
, NULL
, r
);
1456 reply
= dbus_message_new_method_return(message
);
1460 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "LockSession") ||
1461 dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "UnlockSession")) {
1465 if (!dbus_message_get_args(
1468 DBUS_TYPE_STRING
, &name
,
1470 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1472 session
= hashmap_get(m
->sessions
, name
);
1474 return bus_send_error_reply(connection
, message
, &error
, -ENOENT
);
1476 if (session_send_lock(session
, streq(dbus_message_get_member(message
), "LockSession")) < 0)
1479 reply
= dbus_message_new_method_return(message
);
1483 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "KillSession")) {
1490 if (!dbus_message_get_args(
1493 DBUS_TYPE_STRING
, &name
,
1494 DBUS_TYPE_STRING
, &swho
,
1495 DBUS_TYPE_INT32
, &signo
,
1497 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1502 who
= kill_who_from_string(swho
);
1504 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1507 if (signo
<= 0 || signo
>= _NSIG
)
1508 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1510 session
= hashmap_get(m
->sessions
, name
);
1512 return bus_send_error_reply(connection
, message
, &error
, -ENOENT
);
1514 r
= session_kill(session
, who
, signo
);
1516 return bus_send_error_reply(connection
, message
, NULL
, r
);
1518 reply
= dbus_message_new_method_return(message
);
1522 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "KillUser")) {
1527 if (!dbus_message_get_args(
1530 DBUS_TYPE_UINT32
, &uid
,
1531 DBUS_TYPE_INT32
, &signo
,
1533 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1535 if (signo
<= 0 || signo
>= _NSIG
)
1536 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1538 user
= hashmap_get(m
->users
, ULONG_TO_PTR((unsigned long) uid
));
1540 return bus_send_error_reply(connection
, message
, &error
, -ENOENT
);
1542 r
= user_kill(user
, signo
);
1544 return bus_send_error_reply(connection
, message
, NULL
, r
);
1546 reply
= dbus_message_new_method_return(message
);
1550 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "TerminateSession")) {
1554 if (!dbus_message_get_args(
1557 DBUS_TYPE_STRING
, &name
,
1559 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1561 session
= hashmap_get(m
->sessions
, name
);
1563 return bus_send_error_reply(connection
, message
, &error
, -ENOENT
);
1565 r
= session_stop(session
);
1567 return bus_send_error_reply(connection
, message
, NULL
, r
);
1569 reply
= dbus_message_new_method_return(message
);
1573 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "TerminateUser")) {
1577 if (!dbus_message_get_args(
1580 DBUS_TYPE_UINT32
, &uid
,
1582 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1584 user
= hashmap_get(m
->users
, ULONG_TO_PTR((unsigned long) uid
));
1586 return bus_send_error_reply(connection
, message
, &error
, -ENOENT
);
1588 r
= user_stop(user
);
1590 return bus_send_error_reply(connection
, message
, NULL
, r
);
1592 reply
= dbus_message_new_method_return(message
);
1596 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1600 if (!dbus_message_get_args(
1603 DBUS_TYPE_STRING
, &name
,
1605 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1607 seat
= hashmap_get(m
->seats
, name
);
1609 return bus_send_error_reply(connection
, message
, &error
, -ENOENT
);
1611 r
= seat_stop_sessions(seat
);
1613 return bus_send_error_reply(connection
, message
, NULL
, r
);
1615 reply
= dbus_message_new_method_return(message
);
1619 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "SetUserLinger")) {
1622 dbus_bool_t b
, interactive
;
1625 if (!dbus_message_get_args(
1628 DBUS_TYPE_UINT32
, &uid
,
1629 DBUS_TYPE_BOOLEAN
, &b
,
1630 DBUS_TYPE_BOOLEAN
, &interactive
,
1632 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1637 return bus_send_error_reply(connection
, message
, NULL
, errno
? -errno
: -EINVAL
);
1639 r
= verify_polkit(connection
, message
, "org.freedesktop.login1.set-user-linger", interactive
, NULL
, &error
);
1641 return bus_send_error_reply(connection
, message
, &error
, r
);
1643 mkdir_p("/var/lib/systemd", 0755);
1645 r
= safe_mkdir("/var/lib/systemd/linger", 0755, 0, 0);
1647 return bus_send_error_reply(connection
, message
, &error
, r
);
1649 path
= strappend("/var/lib/systemd/linger/", pw
->pw_name
);
1660 return bus_send_error_reply(connection
, message
, &error
, r
);
1662 if (manager_add_user_by_uid(m
, uid
, &u
) >= 0)
1671 if (r
< 0 && errno
!= ENOENT
)
1672 return bus_send_error_reply(connection
, message
, &error
, -errno
);
1674 u
= hashmap_get(m
->users
, ULONG_TO_PTR((unsigned long) uid
));
1676 user_add_to_gc_queue(u
);
1679 reply
= dbus_message_new_method_return(message
);
1683 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "AttachDevice")) {
1684 const char *sysfs
, *seat
;
1685 dbus_bool_t interactive
;
1687 if (!dbus_message_get_args(
1690 DBUS_TYPE_STRING
, &seat
,
1691 DBUS_TYPE_STRING
, &sysfs
,
1692 DBUS_TYPE_BOOLEAN
, &interactive
,
1694 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1696 if (!path_startswith(sysfs
, "/sys") || !seat_name_is_valid(seat
))
1697 return bus_send_error_reply(connection
, message
, NULL
, -EINVAL
);
1699 r
= verify_polkit(connection
, message
, "org.freedesktop.login1.attach-device", interactive
, NULL
, &error
);
1701 return bus_send_error_reply(connection
, message
, &error
, r
);
1703 r
= attach_device(m
, seat
, sysfs
);
1705 return bus_send_error_reply(connection
, message
, NULL
, -EINVAL
);
1707 reply
= dbus_message_new_method_return(message
);
1712 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "FlushDevices")) {
1713 dbus_bool_t interactive
;
1715 if (!dbus_message_get_args(
1718 DBUS_TYPE_BOOLEAN
, &interactive
,
1720 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1722 r
= verify_polkit(connection
, message
, "org.freedesktop.login1.flush-devices", interactive
, NULL
, &error
);
1724 return bus_send_error_reply(connection
, message
, &error
, r
);
1726 r
= flush_devices(m
);
1728 return bus_send_error_reply(connection
, message
, NULL
, -EINVAL
);
1730 reply
= dbus_message_new_method_return(message
);
1734 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "PowerOff") ||
1735 dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "Reboot")) {
1736 dbus_bool_t interactive
;
1737 bool multiple_sessions
, blocked
, delayed
;
1738 const char *name
, *action
;
1740 if (!dbus_message_get_args(
1743 DBUS_TYPE_BOOLEAN
, &interactive
,
1745 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1747 r
= have_multiple_sessions(connection
, m
, message
, &error
);
1749 return bus_send_error_reply(connection
, message
, &error
, r
);
1751 multiple_sessions
= r
> 0;
1752 blocked
= manager_is_inhibited(m
, INHIBIT_SHUTDOWN
, INHIBIT_BLOCK
, NULL
);
1754 if (multiple_sessions
) {
1755 action
= streq(dbus_message_get_member(message
), "PowerOff") ?
1756 "org.freedesktop.login1.power-off-multiple-sessions" :
1757 "org.freedesktop.login1.reboot-multiple-sessions";
1759 r
= verify_polkit(connection
, message
, action
, interactive
, NULL
, &error
);
1761 return bus_send_error_reply(connection
, message
, &error
, r
);
1765 action
= streq(dbus_message_get_member(message
), "PowerOff") ?
1766 "org.freedesktop.login1.power-off-ignore-inhibit" :
1767 "org.freedesktop.login1.reboot-ignore-inhibit";
1769 r
= verify_polkit(connection
, message
, action
, interactive
, NULL
, &error
);
1771 return bus_send_error_reply(connection
, message
, &error
, r
);
1774 if (!multiple_sessions
&& !blocked
) {
1775 action
= streq(dbus_message_get_member(message
), "PowerOff") ?
1776 "org.freedesktop.login1.power-off" :
1777 "org.freedesktop.login1.reboot";
1779 r
= verify_polkit(connection
, message
, action
, interactive
, NULL
, &error
);
1781 return bus_send_error_reply(connection
, message
, &error
, r
);
1784 name
= streq(dbus_message_get_member(message
), "PowerOff") ?
1785 SPECIAL_POWEROFF_TARGET
: SPECIAL_REBOOT_TARGET
;
1788 m
->inhibit_delay_max
> 0 &&
1789 manager_is_inhibited(m
, INHIBIT_SHUTDOWN
, INHIBIT_DELAY
, NULL
);
1792 /* Shutdown is delayed, keep in mind what we
1793 * want to do, and start a timeout */
1794 r
= delay_shutdown(m
, name
);
1796 return bus_send_error_reply(connection
, message
, NULL
, r
);
1798 /* Shutdown is not delayed, execute it
1800 r
= send_start_unit(connection
, name
, &error
);
1802 return bus_send_error_reply(connection
, message
, &error
, r
);
1805 reply
= dbus_message_new_method_return(message
);
1809 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "CanPowerOff") ||
1810 dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "CanReboot")) {
1812 bool multiple_sessions
, challenge
, inhibit
, b
;
1813 const char *action
, *result
;
1815 r
= have_multiple_sessions(connection
, m
, message
, &error
);
1817 return bus_send_error_reply(connection
, message
, &error
, r
);
1819 multiple_sessions
= r
> 0;
1820 inhibit
= manager_is_inhibited(m
, INHIBIT_SHUTDOWN
, INHIBIT_BLOCK
, NULL
);
1822 if (multiple_sessions
) {
1823 action
= streq(dbus_message_get_member(message
), "CanPowerOff") ?
1824 "org.freedesktop.login1.power-off-multiple-sessions" :
1825 "org.freedesktop.login1.reboot-multiple-sessions";
1827 r
= verify_polkit(connection
, message
, action
, false, &challenge
, &error
);
1829 return bus_send_error_reply(connection
, message
, &error
, r
);
1834 result
= "challenge";
1840 action
= streq(dbus_message_get_member(message
), "CanPowerOff") ?
1841 "org.freedesktop.login1.power-off-ignore-inhibit" :
1842 "org.freedesktop.login1.reboot-ignore-inhibit";
1844 r
= verify_polkit(connection
, message
, action
, false, &challenge
, &error
);
1846 return bus_send_error_reply(connection
, message
, &error
, r
);
1848 if (r
> 0 && !result
)
1850 else if (challenge
&& (!result
|| streq(result
, "yes")))
1851 result
= "challenge";
1856 if (!multiple_sessions
&& !inhibit
) {
1857 /* If neither inhibit nor multiple sessions
1858 * apply then just check the normal policy */
1860 action
= streq(dbus_message_get_member(message
), "CanPowerOff") ?
1861 "org.freedesktop.login1.power-off" :
1862 "org.freedesktop.login1.reboot";
1864 r
= verify_polkit(connection
, message
, action
, false, &challenge
, &error
);
1866 return bus_send_error_reply(connection
, message
, &error
, r
);
1871 result
= "challenge";
1876 reply
= dbus_message_new_method_return(message
);
1880 b
= dbus_message_append_args(
1882 DBUS_TYPE_STRING
, &result
,
1887 } else if (dbus_message_is_method_call(message
, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1888 char *introspection
= NULL
;
1897 if (!(reply
= dbus_message_new_method_return(message
)))
1900 /* We roll our own introspection code here, instead of
1901 * relying on bus_default_message_handler() because we
1902 * need to generate our introspection string
1905 if (!(f
= open_memstream(&introspection
, &size
)))
1908 fputs(INTROSPECTION_BEGIN
, f
);
1910 HASHMAP_FOREACH(seat
, m
->seats
, i
) {
1911 p
= bus_path_escape(seat
->id
);
1914 fprintf(f
, "<node name=\"seat/%s\"/>", p
);
1919 HASHMAP_FOREACH(user
, m
->users
, i
)
1920 fprintf(f
, "<node name=\"user/%llu\"/>", (unsigned long long) user
->uid
);
1922 HASHMAP_FOREACH(session
, m
->sessions
, i
) {
1923 p
= bus_path_escape(session
->id
);
1926 fprintf(f
, "<node name=\"session/%s\"/>", p
);
1931 fputs(INTROSPECTION_END
, f
);
1935 free(introspection
);
1944 if (!dbus_message_append_args(reply
, DBUS_TYPE_STRING
, &introspection
, DBUS_TYPE_INVALID
)) {
1945 free(introspection
);
1949 free(introspection
);
1951 const BusBoundProperties bps
[] = {
1952 { "org.freedesktop.login1.Manager", bus_login_manager_properties
, m
},
1955 return bus_default_message_handler(connection
, message
, NULL
, INTERFACES_LIST
, bps
);
1959 if (!dbus_connection_send(connection
, reply
, NULL
))
1962 dbus_message_unref(reply
);
1965 return DBUS_HANDLER_RESULT_HANDLED
;
1969 dbus_message_unref(reply
);
1971 dbus_error_free(&error
);
1973 return DBUS_HANDLER_RESULT_NEED_MEMORY
;
1976 const DBusObjectPathVTable bus_manager_vtable
= {
1977 .message_function
= manager_message_handler
1980 DBusHandlerResult
bus_message_filter(
1981 DBusConnection
*connection
,
1982 DBusMessage
*message
,
1985 Manager
*m
= userdata
;
1992 dbus_error_init(&error
);
1994 if (dbus_message_is_signal(message
, "org.freedesktop.systemd1.Agent", "Released")) {
1997 if (!dbus_message_get_args(message
, &error
,
1998 DBUS_TYPE_STRING
, &cgroup
,
2000 log_error("Failed to parse Released message: %s", bus_error_message(&error
));
2002 manager_cgroup_notify_empty(m
, cgroup
);
2005 dbus_error_free(&error
);
2007 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
2010 int manager_send_changed(Manager
*manager
, const char *properties
) {
2016 m
= bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties
);
2020 if (!dbus_connection_send(manager
->bus
, m
, NULL
))
2027 dbus_message_unref(m
);
2032 int manager_dispatch_delayed_shutdown(Manager
*manager
) {
2040 if (!manager
->delayed_shutdown
)
2043 /* Continue delay? */
2045 manager
->delayed_shutdown_timestamp
+ manager
->inhibit_delay_max
> now(CLOCK_MONOTONIC
) &&
2046 manager_is_inhibited(manager
, INHIBIT_SHUTDOWN
, INHIBIT_DELAY
, NULL
);
2050 /* Reset delay data */
2051 name
= manager
->delayed_shutdown
;
2052 manager
->delayed_shutdown
= NULL
;
2054 /* Actually do the shutdown */
2055 dbus_error_init(&error
);
2056 r
= send_start_unit(manager
->bus
, name
, &error
);
2058 log_warning("Failed to send delayed shutdown message: %s", bus_error_message_or_strerror(&error
, -r
));
2062 /* Tell people about it */
2063 send_prepare_for_shutdown(manager
, false);