1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
28 #include "dbus-common.h"
31 #include "path-util.h"
34 #include "systemd/sd-id128.h"
35 #include "systemd/sd-messages.h"
36 #include "fileio-label.h"
39 #define BUS_MANAGER_INTERFACE \
40 " <interface name=\"org.freedesktop.login1.Manager\">\n" \
41 " <method name=\"GetSession\">\n" \
42 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
43 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
45 " <method name=\"GetSessionByPID\">\n" \
46 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
47 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
49 " <method name=\"GetUser\">\n" \
50 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
51 " <arg name=\"user\" type=\"o\" direction=\"out\"/>\n" \
53 " <method name=\"GetSeat\">\n" \
54 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
55 " <arg name=\"seat\" type=\"o\" direction=\"out\"/>\n" \
57 " <method name=\"ListSessions\">\n" \
58 " <arg name=\"sessions\" type=\"a(susso)\" direction=\"out\"/>\n" \
60 " <method name=\"ListUsers\">\n" \
61 " <arg name=\"users\" type=\"a(uso)\" direction=\"out\"/>\n" \
63 " <method name=\"ListSeats\">\n" \
64 " <arg name=\"seats\" type=\"a(so)\" direction=\"out\"/>\n" \
66 " <method name=\"CreateSession\">\n" \
67 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
68 " <arg name=\"leader\" type=\"u\" direction=\"in\"/>\n" \
69 " <arg name=\"sevice\" type=\"s\" direction=\"in\"/>\n" \
70 " <arg name=\"type\" type=\"s\" direction=\"in\"/>\n" \
71 " <arg name=\"class\" type=\"s\" direction=\"in\"/>\n" \
72 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
73 " <arg name=\"vtnr\" type=\"u\" direction=\"in\"/>\n" \
74 " <arg name=\"tty\" type=\"s\" direction=\"in\"/>\n" \
75 " <arg name=\"display\" type=\"s\" direction=\"in\"/>\n" \
76 " <arg name=\"remote\" type=\"b\" direction=\"in\"/>\n" \
77 " <arg name=\"remote_user\" type=\"s\" direction=\"in\"/>\n" \
78 " <arg name=\"remote_host\" type=\"s\" direction=\"in\"/>\n" \
79 " <arg name=\"controllers\" type=\"as\" direction=\"in\"/>\n" \
80 " <arg name=\"reset_controllers\" type=\"as\" direction=\"in\"/>\n" \
81 " <arg name=\"kill_processes\" type=\"b\" direction=\"in\"/>\n" \
82 " <arg name=\"id\" type=\"s\" direction=\"out\"/>\n" \
83 " <arg name=\"path\" type=\"o\" direction=\"out\"/>\n" \
84 " <arg name=\"runtime_path\" type=\"o\" direction=\"out\"/>\n" \
85 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
86 " <arg name=\"seat\" type=\"s\" direction=\"out\"/>\n" \
87 " <arg name=\"vtnr\" type=\"u\" direction=\"out\"/>\n" \
88 " <arg name=\"existing\" type=\"b\" direction=\"out\"/>\n" \
90 " <method name=\"ReleaseSession\">\n" \
91 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
93 " <method name=\"ActivateSession\">\n" \
94 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
96 " <method name=\"ActivateSessionOnSeat\">\n" \
97 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
98 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
100 " <method name=\"LockSession\">\n" \
101 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
103 " <method name=\"UnlockSession\">\n" \
104 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
106 " <method name=\"LockSessions\"/>\n" \
107 " <method name=\"UnlockSessions\"/>\n" \
108 " <method name=\"KillSession\">\n" \
109 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
110 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
111 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
113 " <method name=\"KillUser\">\n" \
114 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
115 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
117 " <method name=\"TerminateSession\">\n" \
118 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
120 " <method name=\"TerminateUser\">\n" \
121 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
123 " <method name=\"TerminateSeat\">\n" \
124 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
126 " <method name=\"SetUserLinger\">\n" \
127 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
128 " <arg name=\"b\" type=\"b\" direction=\"in\"/>\n" \
129 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
131 " <method name=\"AttachDevice\">\n" \
132 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
133 " <arg name=\"sysfs\" type=\"s\" direction=\"in\"/>\n" \
134 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
136 " <method name=\"FlushDevices\">\n" \
137 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
139 " <method name=\"PowerOff\">\n" \
140 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
142 " <method name=\"Reboot\">\n" \
143 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
145 " <method name=\"Suspend\">\n" \
146 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
148 " <method name=\"Hibernate\">\n" \
149 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
151 " <method name=\"HybridSleep\">\n" \
152 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
154 " <method name=\"CanPowerOff\">\n" \
155 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
157 " <method name=\"CanReboot\">\n" \
158 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
160 " <method name=\"CanSuspend\">\n" \
161 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
163 " <method name=\"CanHibernate\">\n" \
164 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
166 " <method name=\"CanHybridSleep\">\n" \
167 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
169 " <method name=\"Inhibit\">\n" \
170 " <arg name=\"what\" type=\"s\" direction=\"in\"/>\n" \
171 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
172 " <arg name=\"why\" type=\"s\" direction=\"in\"/>\n" \
173 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
174 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
176 " <method name=\"ListInhibitors\">\n" \
177 " <arg name=\"inhibitors\" type=\"a(ssssuu)\" direction=\"out\"/>\n" \
179 " <signal name=\"SessionNew\">\n" \
180 " <arg name=\"id\" type=\"s\"/>\n" \
181 " <arg name=\"path\" type=\"o\"/>\n" \
183 " <signal name=\"SessionRemoved\">\n" \
184 " <arg name=\"id\" type=\"s\"/>\n" \
185 " <arg name=\"path\" type=\"o\"/>\n" \
187 " <signal name=\"UserNew\">\n" \
188 " <arg name=\"uid\" type=\"u\"/>\n" \
189 " <arg name=\"path\" type=\"o\"/>\n" \
191 " <signal name=\"UserRemoved\">\n" \
192 " <arg name=\"uid\" type=\"u\"/>\n" \
193 " <arg name=\"path\" type=\"o\"/>\n" \
195 " <signal name=\"SeatNew\">\n" \
196 " <arg name=\"id\" type=\"s\"/>\n" \
197 " <arg name=\"path\" type=\"o\"/>\n" \
199 " <signal name=\"SeatRemoved\">\n" \
200 " <arg name=\"id\" type=\"s\"/>\n" \
201 " <arg name=\"path\" type=\"o\"/>\n" \
203 " <signal name=\"PrepareForShutdown\">\n" \
204 " <arg name=\"active\" type=\"b\"/>\n" \
206 " <signal name=\"PrepareForSleep\">\n" \
207 " <arg name=\"active\" type=\"b\"/>\n" \
209 " <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
210 " <property name=\"Controllers\" type=\"as\" access=\"read\"/>\n" \
211 " <property name=\"ResetControllers\" type=\"as\" access=\"read\"/>\n" \
212 " <property name=\"NAutoVTs\" type=\"u\" access=\"read\"/>\n" \
213 " <property name=\"KillOnlyUsers\" type=\"as\" access=\"read\"/>\n" \
214 " <property name=\"KillExcludeUsers\" type=\"as\" access=\"read\"/>\n" \
215 " <property name=\"KillUserProcesses\" type=\"b\" access=\"read\"/>\n" \
216 " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
217 " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
218 " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
219 " <property name=\"BlockInhibited\" type=\"s\" access=\"read\"/>\n" \
220 " <property name=\"DelayInhibited\" type=\"s\" access=\"read\"/>\n" \
221 " <property name=\"InhibitDelayMaxUSec\" type=\"t\" access=\"read\"/>\n" \
222 " <property name=\"HandlePowerKey\" type=\"s\" access=\"read\"/>\n" \
223 " <property name=\"HandleSuspendKey\" type=\"s\" access=\"read\"/>\n" \
224 " <property name=\"HandleHibernateKey\" type=\"s\" access=\"read\"/>\n" \
225 " <property name=\"HandleLidSwitch\" type=\"s\" access=\"read\"/>\n" \
226 " <property name=\"IdleAction\" type=\"s\" access=\"read\"/>\n" \
227 " <property name=\"IdleActionUSec\" type=\"t\" access=\"read\"/>\n" \
228 " <property name=\"PreparingForShutdown\" type=\"b\" access=\"read\"/>\n" \
229 " <property name=\"PreparingForSleep\" type=\"b\" access=\"read\"/>\n" \
232 #define INTROSPECTION_BEGIN \
233 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
235 BUS_MANAGER_INTERFACE \
236 BUS_PROPERTIES_INTERFACE \
238 BUS_INTROSPECTABLE_INTERFACE
240 #define INTROSPECTION_END \
243 #define INTERFACES_LIST \
244 BUS_GENERIC_INTERFACES_LIST \
245 "org.freedesktop.login1.Manager\0"
247 static int bus_manager_append_idle_hint(DBusMessageIter
*i
, const char *property
, void *data
) {
255 b
= manager_get_idle_hint(m
, NULL
) > 0;
256 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_BOOLEAN
, &b
))
262 static int bus_manager_append_idle_hint_since(DBusMessageIter
*i
, const char *property
, void *data
) {
271 manager_get_idle_hint(m
, &t
);
272 u
= streq(property
, "IdleSinceHint") ? t
.realtime
: t
.monotonic
;
274 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_UINT64
, &u
))
280 static int bus_manager_append_inhibited(DBusMessageIter
*i
, const char *property
, void *data
) {
285 w
= manager_inhibit_what(m
, streq(property
, "BlockInhibited") ? INHIBIT_BLOCK
: INHIBIT_DELAY
);
286 p
= inhibit_what_to_string(w
);
288 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_STRING
, &p
))
294 static int bus_manager_append_preparing(DBusMessageIter
*i
, const char *property
, void *data
) {
301 if (streq(property
, "PreparingForShutdown"))
302 b
= !!(m
->action_what
& INHIBIT_SHUTDOWN
);
304 b
= !!(m
->action_what
& INHIBIT_SLEEP
);
306 dbus_message_iter_append_basic(i
, DBUS_TYPE_BOOLEAN
, &b
);
310 static int bus_manager_create_session(Manager
*m
, DBusMessage
*message
, DBusMessage
**_reply
) {
311 const char *type
, *class, *cseat
, *tty
, *display
, *remote_user
, *remote_host
, *service
;
312 uint32_t uid
, leader
, audit_id
= 0;
313 dbus_bool_t remote
, kill_processes
, exists
;
314 _cleanup_strv_free_
char **controllers
= NULL
, **reset_controllers
= NULL
;
315 _cleanup_free_
char *cgroup
= NULL
, *id
= NULL
, *p
= NULL
;
318 DBusMessageIter iter
;
321 _cleanup_close_
int fifo_fd
= -1;
322 _cleanup_dbus_message_unref_ DBusMessage
*reply
= NULL
;
323 Session
*session
= NULL
;
332 if (!dbus_message_iter_init(message
, &iter
) ||
333 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_UINT32
)
336 dbus_message_iter_get_basic(&iter
, &uid
);
338 if (!dbus_message_iter_next(&iter
) ||
339 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_UINT32
)
342 dbus_message_iter_get_basic(&iter
, &leader
);
345 !dbus_message_iter_next(&iter
) ||
346 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_STRING
)
349 dbus_message_iter_get_basic(&iter
, &service
);
351 if (!dbus_message_iter_next(&iter
) ||
352 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_STRING
)
355 dbus_message_iter_get_basic(&iter
, &type
);
357 t
= _SESSION_TYPE_INVALID
;
359 t
= session_type_from_string(type
);
364 if (!dbus_message_iter_next(&iter
) ||
365 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_STRING
)
368 dbus_message_iter_get_basic(&iter
, &class);
370 c
= _SESSION_CLASS_INVALID
;
372 c
= session_class_from_string(class);
377 if (!dbus_message_iter_next(&iter
) ||
378 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_STRING
)
381 dbus_message_iter_get_basic(&iter
, &cseat
);
386 seat
= hashmap_get(m
->seats
, cseat
);
391 if (!dbus_message_iter_next(&iter
) ||
392 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_UINT32
)
395 dbus_message_iter_get_basic(&iter
, &vtnr
);
397 if (!dbus_message_iter_next(&iter
) ||
398 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_STRING
)
401 dbus_message_iter_get_basic(&iter
, &tty
);
403 if (tty_is_vc(tty
)) {
408 else if (seat
!= m
->vtconsole
)
411 v
= vtnr_from_tty(tty
);
414 return v
< 0 ? v
: -EINVAL
;
418 else if (vtnr
!= (uint32_t) v
)
420 } else if (tty_is_console(tty
)) {
424 else if (seat
!= m
->vtconsole
)
432 if (seat_can_multi_session(seat
)) {
441 if (!dbus_message_iter_next(&iter
) ||
442 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_STRING
)
445 dbus_message_iter_get_basic(&iter
, &display
);
447 if (!dbus_message_iter_next(&iter
) ||
448 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_BOOLEAN
)
451 if (t
== _SESSION_TYPE_INVALID
) {
452 if (!isempty(display
))
454 else if (!isempty(tty
))
457 t
= SESSION_UNSPECIFIED
;
460 if (c
== _SESSION_CLASS_INVALID
) {
461 if (!isempty(display
) || !isempty(tty
))
464 c
= SESSION_BACKGROUND
;
467 dbus_message_iter_get_basic(&iter
, &remote
);
469 if (!dbus_message_iter_next(&iter
) ||
470 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_STRING
)
473 dbus_message_iter_get_basic(&iter
, &remote_user
);
475 if (!dbus_message_iter_next(&iter
) ||
476 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_STRING
)
479 dbus_message_iter_get_basic(&iter
, &remote_host
);
481 if (!dbus_message_iter_next(&iter
) ||
482 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_ARRAY
||
483 dbus_message_iter_get_element_type(&iter
) != DBUS_TYPE_STRING
)
486 r
= bus_parse_strv_iter(&iter
, &controllers
);
490 if (strv_contains(controllers
, "systemd") ||
491 !dbus_message_iter_next(&iter
) ||
492 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_ARRAY
||
493 dbus_message_iter_get_element_type(&iter
) != DBUS_TYPE_STRING
) {
498 r
= bus_parse_strv_iter(&iter
, &reset_controllers
);
502 if (strv_contains(reset_controllers
, "systemd") ||
503 !dbus_message_iter_next(&iter
) ||
504 dbus_message_iter_get_arg_type(&iter
) != DBUS_TYPE_BOOLEAN
) {
509 dbus_message_iter_get_basic(&iter
, &kill_processes
);
511 r
= cg_pid_get_cgroup(leader
, NULL
, &cgroup
);
515 r
= manager_get_session_by_cgroup(m
, cgroup
, &session
);
520 fifo_fd
= session_create_fifo(session
);
526 /* Session already exists, client is probably
527 * something like "su" which changes uid but
528 * is still the same audit session */
530 reply
= dbus_message_new_method_return(message
);
536 p
= session_bus_path(session
);
542 cseat
= session
->seat
? session
->seat
->id
: "";
543 vtnr
= session
->vtnr
;
546 b
= dbus_message_append_args(
548 DBUS_TYPE_STRING
, &session
->id
,
549 DBUS_TYPE_OBJECT_PATH
, &p
,
550 DBUS_TYPE_STRING
, &session
->user
->runtime_path
,
551 DBUS_TYPE_UNIX_FD
, &fifo_fd
,
552 DBUS_TYPE_STRING
, &cseat
,
553 DBUS_TYPE_UINT32
, &vtnr
,
554 DBUS_TYPE_BOOLEAN
, &exists
,
567 audit_session_from_pid(leader
, &audit_id
);
569 /* Keep our session IDs and the audit session IDs in sync */
571 if (asprintf(&id
, "%lu", (unsigned long) audit_id
) < 0) {
576 /* Wut? There's already a session by this name and we
577 * didn't find it above? Weird, then let's not trust
578 * the audit data and let's better register a new
580 if (hashmap_get(m
->sessions
, id
)) {
593 if (asprintf(&id
, "c%lu", ++m
->session_counter
) < 0) {
598 } while (hashmap_get(m
->sessions
, id
));
601 r
= manager_add_user_by_uid(m
, uid
, &user
);
605 r
= manager_add_session(m
, user
, id
, &session
);
609 session
->leader
= leader
;
610 session
->audit_id
= audit_id
;
613 session
->remote
= remote
;
614 session
->controllers
= controllers
;
615 session
->reset_controllers
= reset_controllers
;
616 session
->kill_processes
= kill_processes
;
617 session
->vtnr
= vtnr
;
619 controllers
= reset_controllers
= NULL
;
622 session
->tty
= strdup(tty
);
629 if (!isempty(display
)) {
630 session
->display
= strdup(display
);
631 if (!session
->display
) {
637 if (!isempty(remote_user
)) {
638 session
->remote_user
= strdup(remote_user
);
639 if (!session
->remote_user
) {
645 if (!isempty(remote_host
)) {
646 session
->remote_host
= strdup(remote_host
);
647 if (!session
->remote_host
) {
653 if (!isempty(service
)) {
654 session
->service
= strdup(service
);
655 if (!session
->service
) {
661 fifo_fd
= session_create_fifo(session
);
668 r
= seat_attach_session(seat
, session
);
673 r
= session_start(session
);
677 reply
= dbus_message_new_method_return(message
);
683 p
= session_bus_path(session
);
689 cseat
= seat
? seat
->id
: "";
691 b
= dbus_message_append_args(
693 DBUS_TYPE_STRING
, &session
->id
,
694 DBUS_TYPE_OBJECT_PATH
, &p
,
695 DBUS_TYPE_STRING
, &session
->user
->runtime_path
,
696 DBUS_TYPE_UNIX_FD
, &fifo_fd
,
697 DBUS_TYPE_STRING
, &cseat
,
698 DBUS_TYPE_UINT32
, &vtnr
,
699 DBUS_TYPE_BOOLEAN
, &exists
,
714 session_add_to_gc_queue(session
);
717 user_add_to_gc_queue(user
);
722 static int bus_manager_inhibit(
724 DBusConnection
*connection
,
725 DBusMessage
*message
,
727 DBusMessage
**_reply
) {
731 const char *who
, *why
, *what
, *mode
;
737 _cleanup_dbus_message_unref_ DBusMessage
*reply
= NULL
;
745 if (!dbus_message_get_args(
748 DBUS_TYPE_STRING
, &what
,
749 DBUS_TYPE_STRING
, &who
,
750 DBUS_TYPE_STRING
, &why
,
751 DBUS_TYPE_STRING
, &mode
,
752 DBUS_TYPE_INVALID
)) {
757 w
= inhibit_what_from_string(what
);
763 mm
= inhibit_mode_from_string(mode
);
769 /* Delay is only supported for shutdown/sleep */
770 if (mm
== INHIBIT_DELAY
&& (w
& ~(INHIBIT_SHUTDOWN
|INHIBIT_SLEEP
))) {
775 /* Don't allow taking delay locks while we are already
776 * executing the operation. We shouldn't create the impression
777 * that the lock was successful if the machine is about to go
778 * down/suspend any moment. */
779 if (m
->action_what
& w
) {
784 r
= verify_polkit(connection
, message
,
785 w
== INHIBIT_SHUTDOWN
? (mm
== INHIBIT_BLOCK
? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
786 w
== INHIBIT_SLEEP
? (mm
== INHIBIT_BLOCK
? "org.freedesktop.login1.inhibit-block-sleep" : "org.freedesktop.login1.inhibit-delay-sleep") :
787 w
== INHIBIT_IDLE
? "org.freedesktop.login1.inhibit-block-idle" :
788 w
== INHIBIT_HANDLE_POWER_KEY
? "org.freedesktop.login1.inhibit-handle-power-key" :
789 w
== INHIBIT_HANDLE_SUSPEND_KEY
? "org.freedesktop.login1.inhibit-handle-suspend-key" :
790 w
== INHIBIT_HANDLE_HIBERNATE_KEY
? "org.freedesktop.login1.inhibit-handle-hibernate-key" :
791 "org.freedesktop.login1.inhibit-handle-lid-switch",
796 ul
= dbus_bus_get_unix_user(connection
, dbus_message_get_sender(message
), error
);
797 if (ul
== (unsigned long) -1) {
802 pid
= bus_get_unix_process_id(connection
, dbus_message_get_sender(message
), error
);
812 if (asprintf(&id
, "%lu", ++m
->inhibit_counter
) < 0) {
816 } while (hashmap_get(m
->inhibitors
, id
));
818 r
= manager_add_inhibitor(m
, id
, &i
);
828 i
->why
= strdup(why
);
829 i
->who
= strdup(who
);
831 if (!i
->why
|| !i
->who
) {
836 fifo_fd
= inhibitor_create_fifo(i
);
842 reply
= dbus_message_new_method_return(message
);
848 if (!dbus_message_append_args(
850 DBUS_TYPE_UNIX_FD
, &fifo_fd
,
851 DBUS_TYPE_INVALID
)) {
856 close_nointr_nofail(fifo_fd
);
869 close_nointr_nofail(fifo_fd
);
874 static int trigger_device(Manager
*m
, struct udev_device
*d
) {
875 struct udev_enumerate
*e
;
876 struct udev_list_entry
*first
, *item
;
881 e
= udev_enumerate_new(m
->udev
);
888 if (udev_enumerate_add_match_parent(e
, d
) < 0) {
894 if (udev_enumerate_scan_devices(e
) < 0) {
899 first
= udev_enumerate_get_list_entry(e
);
900 udev_list_entry_foreach(item
, first
) {
904 p
= udev_list_entry_get_name(item
);
906 t
= strappend(p
, "/uevent");
912 write_string_file(t
, "change");
920 udev_enumerate_unref(e
);
925 static int attach_device(Manager
*m
, const char *seat
, const char *sysfs
) {
926 struct udev_device
*d
;
927 char _cleanup_free_
*rule
= NULL
, *file
= NULL
;
928 const char *id_for_seat
;
935 d
= udev_device_new_from_syspath(m
->udev
, sysfs
);
939 if (!udev_device_has_tag(d
, "seat")) {
944 id_for_seat
= udev_device_get_property_value(d
, "ID_FOR_SEAT");
950 if (asprintf(&file
, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat
) < 0) {
955 if (asprintf(&rule
, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat
, seat
) < 0) {
960 mkdir_p_label("/etc/udev/rules.d", 0755);
962 r
= write_string_file_atomic_label(file
, rule
);
966 r
= trigger_device(m
, d
);
970 udev_device_unref(d
);
975 static int flush_devices(Manager
*m
) {
976 DIR _cleanup_closedir_
*d
;
980 d
= opendir("/etc/udev/rules.d");
983 log_warning("Failed to open /etc/udev/rules.d: %m");
987 while ((de
= readdir(d
))) {
989 if (!dirent_is_file(de
))
992 if (!startswith(de
->d_name
, "72-seat-"))
995 if (!endswith(de
->d_name
, ".rules"))
998 if (unlinkat(dirfd(d
), de
->d_name
, 0) < 0)
999 log_warning("Failed to unlink %s: %m", de
->d_name
);
1003 return trigger_device(m
, NULL
);
1006 static int have_multiple_sessions(
1015 /* Check for other users' sessions. Greeter sessions do not
1016 * count, and non-login sessions do not count either. */
1017 HASHMAP_FOREACH(session
, m
->sessions
, i
)
1018 if (session
->class == SESSION_USER
&&
1019 session
->user
->uid
!= uid
)
1025 static int bus_manager_log_shutdown(
1028 const char *unit_name
) {
1035 if (w
!= INHIBIT_SHUTDOWN
)
1038 if (streq(unit_name
, SPECIAL_POWEROFF_TARGET
)) {
1039 p
= "MESSAGE=System is powering down.";
1040 q
= "SHUTDOWN=power-off";
1041 } else if (streq(unit_name
, SPECIAL_HALT_TARGET
)) {
1042 p
= "MESSAGE=System is halting.";
1043 q
= "SHUTDOWN=halt";
1044 } else if (streq(unit_name
, SPECIAL_REBOOT_TARGET
)) {
1045 p
= "MESSAGE=System is rebooting.";
1046 q
= "SHUTDOWN=reboot";
1047 } else if (streq(unit_name
, SPECIAL_KEXEC_TARGET
)) {
1048 p
= "MESSAGE=System is rebooting with kexec.";
1049 q
= "SHUTDOWN=kexec";
1051 p
= "MESSAGE=System is shutting down.";
1055 return log_struct(LOG_NOTICE
, MESSAGE_ID(SD_MESSAGE_SHUTDOWN
),
1060 static int execute_shutdown_or_sleep(
1063 const char *unit_name
,
1066 _cleanup_dbus_message_unref_ DBusMessage
*reply
= NULL
;
1067 const char *mode
= "replace-irreversibly", *p
;
1073 assert(w
< _INHIBIT_WHAT_MAX
);
1076 bus_manager_log_shutdown(m
, w
, unit_name
);
1078 r
= bus_method_call_with_reply(
1080 "org.freedesktop.systemd1",
1081 "/org/freedesktop/systemd1",
1082 "org.freedesktop.systemd1.Manager",
1086 DBUS_TYPE_STRING
, &unit_name
,
1087 DBUS_TYPE_STRING
, &mode
,
1092 if (!dbus_message_get_args(
1095 DBUS_TYPE_OBJECT_PATH
, &p
,
1103 m
->action_unit
= unit_name
;
1104 free(m
->action_job
);
1111 static int delay_shutdown_or_sleep(
1114 const char *unit_name
) {
1118 assert(w
< _INHIBIT_WHAT_MAX
);
1121 m
->action_timestamp
= now(CLOCK_MONOTONIC
);
1122 m
->action_unit
= unit_name
;
1128 static int bus_manager_can_shutdown_or_sleep(
1130 DBusConnection
*connection
,
1131 DBusMessage
*message
,
1134 const char *action_multiple_sessions
,
1135 const char *action_ignore_inhibit
,
1136 const char *sleep_type
,
1137 const char *sleep_disk_type
,
1139 DBusMessage
**_reply
) {
1141 bool multiple_sessions
, challenge
, blocked
, b
;
1143 _cleanup_dbus_message_unref_ DBusMessage
*reply
= NULL
;
1151 assert(w
<= _INHIBIT_WHAT_MAX
);
1153 assert(action_multiple_sessions
);
1154 assert(action_ignore_inhibit
);
1159 r
= can_sleep(sleep_type
);
1169 if (sleep_disk_type
) {
1170 r
= can_sleep_disk(sleep_disk_type
);
1180 ul
= dbus_bus_get_unix_user(connection
, dbus_message_get_sender(message
), error
);
1181 if (ul
== (unsigned long) -1)
1184 r
= have_multiple_sessions(m
, (uid_t
) ul
);
1188 multiple_sessions
= r
> 0;
1189 blocked
= manager_is_inhibited(m
, w
, INHIBIT_BLOCK
, NULL
, false, true, (uid_t
) ul
);
1191 if (multiple_sessions
) {
1192 r
= verify_polkit(connection
, message
, action_multiple_sessions
, false, &challenge
, error
);
1199 result
= "challenge";
1205 r
= verify_polkit(connection
, message
, action_ignore_inhibit
, false, &challenge
, error
);
1209 if (r
> 0 && !result
)
1211 else if (challenge
&& (!result
|| streq(result
, "yes")))
1212 result
= "challenge";
1217 if (!multiple_sessions
&& !blocked
) {
1218 /* If neither inhibit nor multiple sessions
1219 * apply then just check the normal policy */
1221 r
= verify_polkit(connection
, message
, action
, false, &challenge
, error
);
1228 result
= "challenge";
1234 reply
= dbus_message_new_method_return(message
);
1238 b
= dbus_message_append_args(
1240 DBUS_TYPE_STRING
, &result
,
1250 static int send_prepare_for(Manager
*m
, InhibitWhat w
, bool _active
) {
1251 static const char * const signal_name
[_INHIBIT_WHAT_MAX
] = {
1252 [INHIBIT_SHUTDOWN
] = "PrepareForShutdown",
1253 [INHIBIT_SLEEP
] = "PrepareForSleep"
1256 dbus_bool_t active
= _active
;
1257 _cleanup_dbus_message_unref_ DBusMessage
*message
= NULL
;
1261 assert(w
< _INHIBIT_WHAT_MAX
);
1262 assert(signal_name
[w
]);
1264 message
= dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name
[w
]);
1268 if (!dbus_message_append_args(message
, DBUS_TYPE_BOOLEAN
, &active
, DBUS_TYPE_INVALID
) ||
1269 !dbus_connection_send(m
->bus
, message
, NULL
))
1275 int bus_manager_shutdown_or_sleep_now_or_later(
1277 const char *unit_name
,
1287 assert(w
<= _INHIBIT_WHAT_MAX
);
1288 assert(!m
->action_job
);
1290 /* Tell everybody to prepare for shutdown/sleep */
1291 send_prepare_for(m
, w
, true);
1294 m
->inhibit_delay_max
> 0 &&
1295 manager_is_inhibited(m
, w
, INHIBIT_DELAY
, NULL
, false, false, 0);
1298 /* Shutdown is delayed, keep in mind what we
1299 * want to do, and start a timeout */
1300 r
= delay_shutdown_or_sleep(m
, w
, unit_name
);
1302 /* Shutdown is not delayed, execute it
1304 r
= execute_shutdown_or_sleep(m
, w
, unit_name
, error
);
1309 static int bus_manager_do_shutdown_or_sleep(
1311 DBusConnection
*connection
,
1312 DBusMessage
*message
,
1313 const char *unit_name
,
1316 const char *action_multiple_sessions
,
1317 const char *action_ignore_inhibit
,
1318 const char *sleep_type
,
1319 const char *sleep_disk_type
,
1321 DBusMessage
**_reply
) {
1323 dbus_bool_t interactive
;
1324 bool multiple_sessions
, blocked
;
1325 DBusMessage
*reply
= NULL
;
1334 assert(w
<= _INHIBIT_WHAT_MAX
);
1336 assert(action_multiple_sessions
);
1337 assert(action_ignore_inhibit
);
1341 /* Don't allow multiple jobs being executed at the same time */
1345 if (!dbus_message_get_args(
1348 DBUS_TYPE_BOOLEAN
, &interactive
,
1353 r
= can_sleep(sleep_type
);
1361 if (sleep_disk_type
) {
1362 r
= can_sleep_disk(sleep_disk_type
);
1370 ul
= dbus_bus_get_unix_user(connection
, dbus_message_get_sender(message
), error
);
1371 if (ul
== (unsigned long) -1)
1374 r
= have_multiple_sessions(m
, (uid_t
) ul
);
1378 multiple_sessions
= r
> 0;
1379 blocked
= manager_is_inhibited(m
, w
, INHIBIT_BLOCK
, NULL
, false, true, (uid_t
) ul
);
1381 if (multiple_sessions
) {
1382 r
= verify_polkit(connection
, message
, action_multiple_sessions
, interactive
, NULL
, error
);
1388 r
= verify_polkit(connection
, message
, action_ignore_inhibit
, interactive
, NULL
, error
);
1393 if (!multiple_sessions
&& !blocked
) {
1394 r
= verify_polkit(connection
, message
, action
, interactive
, NULL
, error
);
1399 r
= bus_manager_shutdown_or_sleep_now_or_later(m
, unit_name
, w
, error
);
1403 reply
= dbus_message_new_method_return(message
);
1411 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_action
, handle_action
, HandleAction
);
1413 static const BusProperty bus_login_manager_properties
[] = {
1414 { "ControlGroupHierarchy", bus_property_append_string
, "s", offsetof(Manager
, cgroup_path
), true },
1415 { "Controllers", bus_property_append_strv
, "as", offsetof(Manager
, controllers
), true },
1416 { "ResetControllers", bus_property_append_strv
, "as", offsetof(Manager
, reset_controllers
), true },
1417 { "NAutoVTs", bus_property_append_unsigned
, "u", offsetof(Manager
, n_autovts
) },
1418 { "KillOnlyUsers", bus_property_append_strv
, "as", offsetof(Manager
, kill_only_users
), true },
1419 { "KillExcludeUsers", bus_property_append_strv
, "as", offsetof(Manager
, kill_exclude_users
), true },
1420 { "KillUserProcesses", bus_property_append_bool
, "b", offsetof(Manager
, kill_user_processes
) },
1421 { "IdleHint", bus_manager_append_idle_hint
, "b", 0 },
1422 { "IdleSinceHint", bus_manager_append_idle_hint_since
, "t", 0 },
1423 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since
, "t", 0 },
1424 { "BlockInhibited", bus_manager_append_inhibited
, "s", 0 },
1425 { "DelayInhibited", bus_manager_append_inhibited
, "s", 0 },
1426 { "InhibitDelayMaxUSec", bus_property_append_usec
, "t", offsetof(Manager
, inhibit_delay_max
) },
1427 { "HandlePowerKey", bus_manager_append_handle_action
, "s", offsetof(Manager
, handle_power_key
) },
1428 { "HandleSuspendKey", bus_manager_append_handle_action
, "s", offsetof(Manager
, handle_suspend_key
) },
1429 { "HandleHibernateKey", bus_manager_append_handle_action
, "s", offsetof(Manager
, handle_hibernate_key
)},
1430 { "HandleLidSwitch", bus_manager_append_handle_action
, "s", offsetof(Manager
, handle_lid_switch
) },
1431 { "IdleAction", bus_manager_append_handle_action
, "s", offsetof(Manager
, idle_action
) },
1432 { "IdleActionUSec", bus_property_append_usec
, "t", offsetof(Manager
, idle_action_usec
) },
1433 { "PreparingForShutdown", bus_manager_append_preparing
, "b", 0 },
1434 { "PreparingForSleep", bus_manager_append_preparing
, "b", 0 },
1438 static DBusHandlerResult
manager_message_handler(
1439 DBusConnection
*connection
,
1440 DBusMessage
*message
,
1443 Manager
*m
= userdata
;
1446 _cleanup_dbus_message_unref_ DBusMessage
*reply
= NULL
;
1453 dbus_error_init(&error
);
1455 if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "GetSession")) {
1461 if (!dbus_message_get_args(
1464 DBUS_TYPE_STRING
, &name
,
1466 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1468 session
= hashmap_get(m
->sessions
, name
);
1470 return bus_send_error_reply(connection
, message
, &error
, -ENOENT
);
1472 reply
= dbus_message_new_method_return(message
);
1476 p
= session_bus_path(session
);
1480 b
= dbus_message_append_args(
1482 DBUS_TYPE_OBJECT_PATH
, &p
,
1489 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1495 if (!dbus_message_get_args(
1498 DBUS_TYPE_UINT32
, &pid
,
1500 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1502 r
= manager_get_session_by_pid(m
, pid
, &session
);
1504 return bus_send_error_reply(connection
, message
, NULL
, r
< 0 ? r
: -ENOENT
);
1506 reply
= dbus_message_new_method_return(message
);
1510 p
= session_bus_path(session
);
1514 b
= dbus_message_append_args(
1516 DBUS_TYPE_OBJECT_PATH
, &p
,
1523 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "GetUser")) {
1529 if (!dbus_message_get_args(
1532 DBUS_TYPE_UINT32
, &uid
,
1534 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1536 user
= hashmap_get(m
->users
, ULONG_TO_PTR((unsigned long) uid
));
1538 return bus_send_error_reply(connection
, message
, &error
, -ENOENT
);
1540 reply
= dbus_message_new_method_return(message
);
1544 p
= user_bus_path(user
);
1548 b
= dbus_message_append_args(
1550 DBUS_TYPE_OBJECT_PATH
, &p
,
1557 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "GetSeat")) {
1563 if (!dbus_message_get_args(
1566 DBUS_TYPE_STRING
, &name
,
1568 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1570 seat
= hashmap_get(m
->seats
, name
);
1572 return bus_send_error_reply(connection
, message
, &error
, -ENOENT
);
1574 reply
= dbus_message_new_method_return(message
);
1578 p
= seat_bus_path(seat
);
1582 b
= dbus_message_append_args(
1584 DBUS_TYPE_OBJECT_PATH
, &p
,
1591 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "ListSessions")) {
1595 DBusMessageIter iter
, sub
;
1596 const char *empty
= "";
1598 reply
= dbus_message_new_method_return(message
);
1602 dbus_message_iter_init_append(reply
, &iter
);
1604 if (!dbus_message_iter_open_container(&iter
, DBUS_TYPE_ARRAY
, "(susso)", &sub
))
1607 HASHMAP_FOREACH(session
, m
->sessions
, i
) {
1608 DBusMessageIter sub2
;
1611 if (!dbus_message_iter_open_container(&sub
, DBUS_TYPE_STRUCT
, NULL
, &sub2
))
1614 uid
= session
->user
->uid
;
1616 p
= session_bus_path(session
);
1620 if (!dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_STRING
, &session
->id
) ||
1621 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_UINT32
, &uid
) ||
1622 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_STRING
, &session
->user
->name
) ||
1623 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_STRING
, session
->seat
? (const char**) &session
->seat
->id
: &empty
) ||
1624 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_OBJECT_PATH
, &p
)) {
1631 if (!dbus_message_iter_close_container(&sub
, &sub2
))
1635 if (!dbus_message_iter_close_container(&iter
, &sub
))
1638 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "ListUsers")) {
1642 DBusMessageIter iter
, sub
;
1644 reply
= dbus_message_new_method_return(message
);
1648 dbus_message_iter_init_append(reply
, &iter
);
1650 if (!dbus_message_iter_open_container(&iter
, DBUS_TYPE_ARRAY
, "(uso)", &sub
))
1653 HASHMAP_FOREACH(user
, m
->users
, i
) {
1654 DBusMessageIter sub2
;
1657 if (!dbus_message_iter_open_container(&sub
, DBUS_TYPE_STRUCT
, NULL
, &sub2
))
1662 p
= user_bus_path(user
);
1666 if (!dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_UINT32
, &uid
) ||
1667 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_STRING
, &user
->name
) ||
1668 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_OBJECT_PATH
, &p
)) {
1675 if (!dbus_message_iter_close_container(&sub
, &sub2
))
1679 if (!dbus_message_iter_close_container(&iter
, &sub
))
1682 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "ListSeats")) {
1686 DBusMessageIter iter
, sub
;
1688 reply
= dbus_message_new_method_return(message
);
1692 dbus_message_iter_init_append(reply
, &iter
);
1694 if (!dbus_message_iter_open_container(&iter
, DBUS_TYPE_ARRAY
, "(so)", &sub
))
1697 HASHMAP_FOREACH(seat
, m
->seats
, i
) {
1698 DBusMessageIter sub2
;
1700 if (!dbus_message_iter_open_container(&sub
, DBUS_TYPE_STRUCT
, NULL
, &sub2
))
1703 p
= seat_bus_path(seat
);
1707 if (!dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_STRING
, &seat
->id
) ||
1708 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_OBJECT_PATH
, &p
)) {
1715 if (!dbus_message_iter_close_container(&sub
, &sub2
))
1719 if (!dbus_message_iter_close_container(&iter
, &sub
))
1722 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1723 Inhibitor
*inhibitor
;
1725 DBusMessageIter iter
, sub
;
1727 reply
= dbus_message_new_method_return(message
);
1731 dbus_message_iter_init_append(reply
, &iter
);
1733 if (!dbus_message_iter_open_container(&iter
, DBUS_TYPE_ARRAY
, "(ssssuu)", &sub
))
1736 HASHMAP_FOREACH(inhibitor
, m
->inhibitors
, i
) {
1737 DBusMessageIter sub2
;
1738 dbus_uint32_t uid
, pid
;
1739 const char *what
, *who
, *why
, *mode
;
1741 if (!dbus_message_iter_open_container(&sub
, DBUS_TYPE_STRUCT
, NULL
, &sub2
))
1744 what
= strempty(inhibit_what_to_string(inhibitor
->what
));
1745 who
= strempty(inhibitor
->who
);
1746 why
= strempty(inhibitor
->why
);
1747 mode
= strempty(inhibit_mode_to_string(inhibitor
->mode
));
1748 uid
= (dbus_uint32_t
) inhibitor
->uid
;
1749 pid
= (dbus_uint32_t
) inhibitor
->pid
;
1751 if (!dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_STRING
, &what
) ||
1752 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_STRING
, &who
) ||
1753 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_STRING
, &why
) ||
1754 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_STRING
, &mode
) ||
1755 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_UINT32
, &uid
) ||
1756 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_UINT32
, &pid
))
1759 if (!dbus_message_iter_close_container(&sub
, &sub2
))
1763 if (!dbus_message_iter_close_container(&iter
, &sub
))
1766 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "Inhibit")) {
1768 r
= bus_manager_inhibit(m
, connection
, message
, &error
, &reply
);
1771 return bus_send_error_reply(connection
, message
, &error
, r
);
1774 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "CreateSession")) {
1776 r
= bus_manager_create_session(m
, message
, &reply
);
1778 /* Don't delay the work on OOM here, since it might be
1779 * triggered by a low RLIMIT_NOFILE here (since we
1780 * send a dupped fd to the client), and we'd rather
1781 * see this fail quickly then be retried later */
1784 return bus_send_error_reply(connection
, message
, NULL
, r
);
1786 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1790 if (!dbus_message_get_args(
1793 DBUS_TYPE_STRING
, &name
,
1795 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1797 session
= hashmap_get(m
->sessions
, name
);
1799 return bus_send_error_reply(connection
, message
, &error
, -ENOENT
);
1801 /* We use the FIFO to detect stray sessions where the
1802 process invoking PAM dies abnormally. We need to make
1803 sure that that process is not killed if at the clean
1804 end of the session it closes the FIFO. Hence, with
1805 this call explicitly turn off the FIFO logic, so that
1806 the PAM code can finish clean up on its own */
1807 session_remove_fifo(session
);
1809 reply
= dbus_message_new_method_return(message
);
1813 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "ActivateSession")) {
1817 if (!dbus_message_get_args(
1820 DBUS_TYPE_STRING
, &name
,
1822 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1824 session
= hashmap_get(m
->sessions
, name
);
1826 return bus_send_error_reply(connection
, message
, &error
, -ENOENT
);
1828 r
= session_activate(session
);
1830 return bus_send_error_reply(connection
, message
, NULL
, r
);
1832 reply
= dbus_message_new_method_return(message
);
1836 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1837 const char *session_name
, *seat_name
;
1841 /* Same as ActivateSession() but refuses to work if
1842 * the seat doesn't match */
1844 if (!dbus_message_get_args(
1847 DBUS_TYPE_STRING
, &session_name
,
1848 DBUS_TYPE_STRING
, &seat_name
,
1850 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1852 session
= hashmap_get(m
->sessions
, session_name
);
1854 return bus_send_error_reply(connection
, message
, &error
, -ENOENT
);
1856 seat
= hashmap_get(m
->seats
, seat_name
);
1858 return bus_send_error_reply(connection
, message
, &error
, -ENOENT
);
1860 if (session
->seat
!= seat
)
1861 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1863 r
= session_activate(session
);
1865 return bus_send_error_reply(connection
, message
, NULL
, r
);
1867 reply
= dbus_message_new_method_return(message
);
1871 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "LockSession") ||
1872 dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "UnlockSession")) {
1876 if (!dbus_message_get_args(
1879 DBUS_TYPE_STRING
, &name
,
1881 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1883 session
= hashmap_get(m
->sessions
, name
);
1885 return bus_send_error_reply(connection
, message
, NULL
, -ENOENT
);
1887 if (session_send_lock(session
, streq(dbus_message_get_member(message
), "LockSession")) < 0)
1890 reply
= dbus_message_new_method_return(message
);
1894 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "LockSessions") ||
1895 dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "UnlockSessions")) {
1897 r
= session_send_lock_all(m
, streq(dbus_message_get_member(message
), "LockSessions"));
1899 bus_send_error_reply(connection
, message
, NULL
, r
);
1901 reply
= dbus_message_new_method_return(message
);
1905 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "KillSession")) {
1912 if (!dbus_message_get_args(
1915 DBUS_TYPE_STRING
, &name
,
1916 DBUS_TYPE_STRING
, &swho
,
1917 DBUS_TYPE_INT32
, &signo
,
1919 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1924 who
= kill_who_from_string(swho
);
1926 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1929 if (signo
<= 0 || signo
>= _NSIG
)
1930 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1932 session
= hashmap_get(m
->sessions
, name
);
1934 return bus_send_error_reply(connection
, message
, &error
, -ENOENT
);
1936 r
= session_kill(session
, who
, signo
);
1938 return bus_send_error_reply(connection
, message
, NULL
, r
);
1940 reply
= dbus_message_new_method_return(message
);
1944 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "KillUser")) {
1949 if (!dbus_message_get_args(
1952 DBUS_TYPE_UINT32
, &uid
,
1953 DBUS_TYPE_INT32
, &signo
,
1955 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1957 if (signo
<= 0 || signo
>= _NSIG
)
1958 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1960 user
= hashmap_get(m
->users
, ULONG_TO_PTR((unsigned long) uid
));
1962 return bus_send_error_reply(connection
, message
, &error
, -ENOENT
);
1964 r
= user_kill(user
, signo
);
1966 return bus_send_error_reply(connection
, message
, NULL
, r
);
1968 reply
= dbus_message_new_method_return(message
);
1972 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "TerminateSession")) {
1976 if (!dbus_message_get_args(
1979 DBUS_TYPE_STRING
, &name
,
1981 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1983 session
= hashmap_get(m
->sessions
, name
);
1985 return bus_send_error_reply(connection
, message
, &error
, -ENOENT
);
1987 r
= session_stop(session
);
1989 return bus_send_error_reply(connection
, message
, NULL
, r
);
1991 reply
= dbus_message_new_method_return(message
);
1995 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "TerminateUser")) {
1999 if (!dbus_message_get_args(
2002 DBUS_TYPE_UINT32
, &uid
,
2004 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
2006 user
= hashmap_get(m
->users
, ULONG_TO_PTR((unsigned long) uid
));
2008 return bus_send_error_reply(connection
, message
, &error
, -ENOENT
);
2010 r
= user_stop(user
);
2012 return bus_send_error_reply(connection
, message
, NULL
, r
);
2014 reply
= dbus_message_new_method_return(message
);
2018 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "TerminateSeat")) {
2022 if (!dbus_message_get_args(
2025 DBUS_TYPE_STRING
, &name
,
2027 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
2029 seat
= hashmap_get(m
->seats
, name
);
2031 return bus_send_error_reply(connection
, message
, &error
, -ENOENT
);
2033 r
= seat_stop_sessions(seat
);
2035 return bus_send_error_reply(connection
, message
, NULL
, r
);
2037 reply
= dbus_message_new_method_return(message
);
2041 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "SetUserLinger")) {
2044 dbus_bool_t b
, interactive
;
2047 if (!dbus_message_get_args(
2050 DBUS_TYPE_UINT32
, &uid
,
2051 DBUS_TYPE_BOOLEAN
, &b
,
2052 DBUS_TYPE_BOOLEAN
, &interactive
,
2054 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
2059 return bus_send_error_reply(connection
, message
, NULL
, errno
? -errno
: -EINVAL
);
2061 r
= verify_polkit(connection
, message
, "org.freedesktop.login1.set-user-linger", interactive
, NULL
, &error
);
2063 return bus_send_error_reply(connection
, message
, &error
, r
);
2065 mkdir_p_label("/var/lib/systemd", 0755);
2067 r
= mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
2069 return bus_send_error_reply(connection
, message
, &error
, r
);
2071 path
= strappend("/var/lib/systemd/linger/", pw
->pw_name
);
2082 return bus_send_error_reply(connection
, message
, &error
, r
);
2084 if (manager_add_user_by_uid(m
, uid
, &u
) >= 0)
2093 if (r
< 0 && errno
!= ENOENT
)
2094 return bus_send_error_reply(connection
, message
, &error
, -errno
);
2096 u
= hashmap_get(m
->users
, ULONG_TO_PTR((unsigned long) uid
));
2098 user_add_to_gc_queue(u
);
2101 reply
= dbus_message_new_method_return(message
);
2105 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "AttachDevice")) {
2106 const char *sysfs
, *seat
;
2107 dbus_bool_t interactive
;
2109 if (!dbus_message_get_args(
2112 DBUS_TYPE_STRING
, &seat
,
2113 DBUS_TYPE_STRING
, &sysfs
,
2114 DBUS_TYPE_BOOLEAN
, &interactive
,
2116 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
2118 if (!path_startswith(sysfs
, "/sys") || !seat_name_is_valid(seat
))
2119 return bus_send_error_reply(connection
, message
, NULL
, -EINVAL
);
2121 r
= verify_polkit(connection
, message
, "org.freedesktop.login1.attach-device", interactive
, NULL
, &error
);
2123 return bus_send_error_reply(connection
, message
, &error
, r
);
2125 r
= attach_device(m
, seat
, sysfs
);
2127 return bus_send_error_reply(connection
, message
, NULL
, -EINVAL
);
2129 reply
= dbus_message_new_method_return(message
);
2134 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "FlushDevices")) {
2135 dbus_bool_t interactive
;
2137 if (!dbus_message_get_args(
2140 DBUS_TYPE_BOOLEAN
, &interactive
,
2142 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
2144 r
= verify_polkit(connection
, message
, "org.freedesktop.login1.flush-devices", interactive
, NULL
, &error
);
2146 return bus_send_error_reply(connection
, message
, &error
, r
);
2148 r
= flush_devices(m
);
2150 return bus_send_error_reply(connection
, message
, NULL
, -EINVAL
);
2152 reply
= dbus_message_new_method_return(message
);
2156 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "PowerOff")) {
2158 r
= bus_manager_do_shutdown_or_sleep(
2159 m
, connection
, message
,
2160 SPECIAL_POWEROFF_TARGET
,
2162 "org.freedesktop.login1.power-off",
2163 "org.freedesktop.login1.power-off-multiple-sessions",
2164 "org.freedesktop.login1.power-off-ignore-inhibit",
2168 return bus_send_error_reply(connection
, message
, &error
, r
);
2169 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "Reboot")) {
2170 r
= bus_manager_do_shutdown_or_sleep(
2171 m
, connection
, message
,
2172 SPECIAL_REBOOT_TARGET
,
2174 "org.freedesktop.login1.reboot",
2175 "org.freedesktop.login1.reboot-multiple-sessions",
2176 "org.freedesktop.login1.reboot-ignore-inhibit",
2180 return bus_send_error_reply(connection
, message
, &error
, r
);
2182 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "Suspend")) {
2183 r
= bus_manager_do_shutdown_or_sleep(
2184 m
, connection
, message
,
2185 SPECIAL_SUSPEND_TARGET
,
2187 "org.freedesktop.login1.suspend",
2188 "org.freedesktop.login1.suspend-multiple-sessions",
2189 "org.freedesktop.login1.suspend-ignore-inhibit",
2193 return bus_send_error_reply(connection
, message
, &error
, r
);
2194 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "Hibernate")) {
2195 r
= bus_manager_do_shutdown_or_sleep(
2196 m
, connection
, message
,
2197 SPECIAL_HIBERNATE_TARGET
,
2199 "org.freedesktop.login1.hibernate",
2200 "org.freedesktop.login1.hibernate-multiple-sessions",
2201 "org.freedesktop.login1.hibernate-ignore-inhibit",
2205 return bus_send_error_reply(connection
, message
, &error
, r
);
2207 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "HybridSleep")) {
2208 r
= bus_manager_do_shutdown_or_sleep(
2209 m
, connection
, message
,
2210 SPECIAL_HYBRID_SLEEP_TARGET
,
2212 "org.freedesktop.login1.hibernate",
2213 "org.freedesktop.login1.hibernate-multiple-sessions",
2214 "org.freedesktop.login1.hibernate-ignore-inhibit",
2218 return bus_send_error_reply(connection
, message
, &error
, r
);
2220 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2222 r
= bus_manager_can_shutdown_or_sleep(
2223 m
, connection
, message
,
2225 "org.freedesktop.login1.power-off",
2226 "org.freedesktop.login1.power-off-multiple-sessions",
2227 "org.freedesktop.login1.power-off-ignore-inhibit",
2231 return bus_send_error_reply(connection
, message
, &error
, r
);
2232 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "CanReboot")) {
2233 r
= bus_manager_can_shutdown_or_sleep(
2234 m
, connection
, message
,
2236 "org.freedesktop.login1.reboot",
2237 "org.freedesktop.login1.reboot-multiple-sessions",
2238 "org.freedesktop.login1.reboot-ignore-inhibit",
2242 return bus_send_error_reply(connection
, message
, &error
, r
);
2244 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "CanSuspend")) {
2245 r
= bus_manager_can_shutdown_or_sleep(
2246 m
, connection
, message
,
2248 "org.freedesktop.login1.suspend",
2249 "org.freedesktop.login1.suspend-multiple-sessions",
2250 "org.freedesktop.login1.suspend-ignore-inhibit",
2254 return bus_send_error_reply(connection
, message
, &error
, r
);
2256 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "CanHibernate")) {
2257 r
= bus_manager_can_shutdown_or_sleep(
2258 m
, connection
, message
,
2260 "org.freedesktop.login1.hibernate",
2261 "org.freedesktop.login1.hibernate-multiple-sessions",
2262 "org.freedesktop.login1.hibernate-ignore-inhibit",
2266 return bus_send_error_reply(connection
, message
, &error
, r
);
2268 } else if (dbus_message_is_method_call(message
, "org.freedesktop.login1.Manager", "CanHybridSleep")) {
2269 r
= bus_manager_can_shutdown_or_sleep(
2270 m
, connection
, message
,
2272 "org.freedesktop.login1.hibernate",
2273 "org.freedesktop.login1.hibernate-multiple-sessions",
2274 "org.freedesktop.login1.hibernate-ignore-inhibit",
2278 return bus_send_error_reply(connection
, message
, &error
, r
);
2280 } else if (dbus_message_is_method_call(message
, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2281 char *introspection
= NULL
;
2290 if (!(reply
= dbus_message_new_method_return(message
)))
2293 /* We roll our own introspection code here, instead of
2294 * relying on bus_default_message_handler() because we
2295 * need to generate our introspection string
2298 if (!(f
= open_memstream(&introspection
, &size
)))
2301 fputs(INTROSPECTION_BEGIN
, f
);
2303 HASHMAP_FOREACH(seat
, m
->seats
, i
) {
2304 p
= bus_path_escape(seat
->id
);
2307 fprintf(f
, "<node name=\"seat/%s\"/>", p
);
2312 HASHMAP_FOREACH(user
, m
->users
, i
)
2313 fprintf(f
, "<node name=\"user/%llu\"/>", (unsigned long long) user
->uid
);
2315 HASHMAP_FOREACH(session
, m
->sessions
, i
) {
2316 p
= bus_path_escape(session
->id
);
2319 fprintf(f
, "<node name=\"session/%s\"/>", p
);
2324 fputs(INTROSPECTION_END
, f
);
2328 free(introspection
);
2337 if (!dbus_message_append_args(reply
, DBUS_TYPE_STRING
, &introspection
, DBUS_TYPE_INVALID
)) {
2338 free(introspection
);
2342 free(introspection
);
2344 const BusBoundProperties bps
[] = {
2345 { "org.freedesktop.login1.Manager", bus_login_manager_properties
, m
},
2348 return bus_default_message_handler(connection
, message
, NULL
, INTERFACES_LIST
, bps
);
2352 if (!bus_maybe_send_reply(connection
, message
, reply
))
2356 return DBUS_HANDLER_RESULT_HANDLED
;
2359 dbus_error_free(&error
);
2361 return DBUS_HANDLER_RESULT_NEED_MEMORY
;
2364 const DBusObjectPathVTable bus_manager_vtable
= {
2365 .message_function
= manager_message_handler
2368 DBusHandlerResult
bus_message_filter(
2369 DBusConnection
*connection
,
2370 DBusMessage
*message
,
2373 Manager
*m
= userdata
;
2380 dbus_error_init(&error
);
2382 if (dbus_message_is_signal(message
, "org.freedesktop.systemd1.Agent", "Released")) {
2385 if (!dbus_message_get_args(message
, &error
,
2386 DBUS_TYPE_STRING
, &cgroup
,
2388 log_error("Failed to parse Released message: %s", bus_error_message(&error
));
2390 manager_cgroup_notify_empty(m
, cgroup
);
2392 } else if (dbus_message_is_signal(message
, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
2394 const char *path
, *result
, *unit
;
2396 if (!dbus_message_get_args(message
, &error
,
2397 DBUS_TYPE_UINT32
, &id
,
2398 DBUS_TYPE_OBJECT_PATH
, &path
,
2399 DBUS_TYPE_STRING
, &unit
,
2400 DBUS_TYPE_STRING
, &result
,
2402 log_error("Failed to parse JobRemoved message: %s", bus_error_message(&error
));
2404 else if (m
->action_job
&& streq(m
->action_job
, path
)) {
2406 log_info("Operation finished.");
2408 /* Tell people that they now may take a lock again */
2409 send_prepare_for(m
, m
->action_what
, false);
2411 free(m
->action_job
);
2412 m
->action_job
= NULL
;
2413 m
->action_unit
= NULL
;
2418 dbus_error_free(&error
);
2420 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
2423 int manager_send_changed(Manager
*manager
, const char *properties
) {
2424 _cleanup_dbus_message_unref_ DBusMessage
*m
= NULL
;
2428 m
= bus_properties_changed_new("/org/freedesktop/login1",
2429 "org.freedesktop.login1.Manager",
2434 if (!dbus_connection_send(manager
->bus
, m
, NULL
))
2440 int manager_dispatch_delayed(Manager
*manager
) {
2446 if (!manager
->action_unit
|| manager
->action_job
)
2449 /* Continue delay? */
2450 if (manager_is_inhibited(manager
, manager
->action_what
, INHIBIT_DELAY
, NULL
, false, false, 0)) {
2452 if (manager
->action_timestamp
+ manager
->inhibit_delay_max
> now(CLOCK_MONOTONIC
))
2455 log_info("Delay lock is active but inhibitor timeout is reached.");
2458 /* Actually do the operation */
2459 dbus_error_init(&error
);
2460 r
= execute_shutdown_or_sleep(manager
, manager
->action_what
, manager
->action_unit
, &error
);
2462 log_warning("Failed to send delayed message: %s", bus_error_message_or_strerror(&error
, -r
));
2463 dbus_error_free(&error
);
2465 manager
->action_unit
= NULL
;
2466 manager
->action_what
= 0;