]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-dbus.c
update TODO
[thirdparty/systemd.git] / src / login / logind-dbus.c
CommitLineData
3f49d45a
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2011 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
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
3f49d45a
LP
11 (at your option) any later version.
12
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
5430f7f2 16 Lesser General Public License for more details.
3f49d45a 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
3f49d45a
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
a185c5aa
LP
22#include <errno.h>
23#include <string.h>
98a28fef 24#include <unistd.h>
7f7bb946 25#include <pwd.h>
a185c5aa 26
3f49d45a
LP
27#include "logind.h"
28#include "dbus-common.h"
98a28fef 29#include "strv.h"
49e942b2 30#include "mkdir.h"
9eb977db 31#include "path-util.h"
7f7bb946 32#include "polkit.h"
55af3897 33#include "special.h"
877d54e9
LP
34#include "systemd/sd-id128.h"
35#include "systemd/sd-messages.h"
a5c32cff
HH
36#include "fileio-label.h"
37#include "label.h"
3f49d45a
LP
38
39#define BUS_MANAGER_INTERFACE \
40 " <interface name=\"org.freedesktop.login1.Manager\">\n" \
bef422ae 41 " <method name=\"GetSession\">\n" \
3f49d45a 42 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
bef422ae 43 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
3f49d45a 44 " </method>\n" \
c4aa65e7
LP
45 " <method name=\"GetSessionByPID\">\n" \
46 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
47 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
48 " </method>\n" \
3f49d45a 49 " <method name=\"GetUser\">\n" \
bef422ae 50 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
3f49d45a
LP
51 " <arg name=\"user\" type=\"o\" direction=\"out\"/>\n" \
52 " </method>\n" \
bef422ae 53 " <method name=\"GetSeat\">\n" \
3f49d45a 54 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
bef422ae 55 " <arg name=\"seat\" type=\"o\" direction=\"out\"/>\n" \
3f49d45a 56 " </method>\n" \
bef422ae 57 " <method name=\"ListSessions\">\n" \
e1c9c2d5 58 " <arg name=\"sessions\" type=\"a(susso)\" direction=\"out\"/>\n" \
3f49d45a
LP
59 " </method>\n" \
60 " <method name=\"ListUsers\">\n" \
61 " <arg name=\"users\" type=\"a(uso)\" direction=\"out\"/>\n" \
62 " </method>\n" \
bef422ae
LP
63 " <method name=\"ListSeats\">\n" \
64 " <arg name=\"seats\" type=\"a(so)\" direction=\"out\"/>\n" \
3f49d45a
LP
65 " </method>\n" \
66 " <method name=\"CreateSession\">\n" \
67 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
68 " <arg name=\"leader\" type=\"u\" direction=\"in\"/>\n" \
4d6d6518 69 " <arg name=\"sevice\" type=\"s\" direction=\"in\"/>\n" \
3f49d45a 70 " <arg name=\"type\" type=\"s\" direction=\"in\"/>\n" \
55efac6c 71 " <arg name=\"class\" type=\"s\" direction=\"in\"/>\n" \
3f49d45a 72 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
4d6d6518 73 " <arg name=\"vtnr\" type=\"u\" direction=\"in\"/>\n" \
3f49d45a
LP
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" \
98a28fef 81 " <arg name=\"kill_processes\" type=\"b\" direction=\"in\"/>\n" \
3f49d45a
LP
82 " <arg name=\"id\" type=\"s\" direction=\"out\"/>\n" \
83 " <arg name=\"path\" type=\"o\" direction=\"out\"/>\n" \
98a28fef 84 " <arg name=\"runtime_path\" type=\"o\" direction=\"out\"/>\n" \
3f49d45a 85 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
bbc73283
LP
86 " <arg name=\"seat\" type=\"s\" direction=\"out\"/>\n" \
87 " <arg name=\"vtnr\" type=\"u\" direction=\"out\"/>\n" \
77085881 88 " <arg name=\"existing\" type=\"b\" direction=\"out\"/>\n" \
3f49d45a 89 " </method>\n" \
75c8e3cf
LP
90 " <method name=\"ReleaseSession\">\n" \
91 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
92 " </method>\n" \
a185c5aa
LP
93 " <method name=\"ActivateSession\">\n" \
94 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
95 " </method>\n" \
84c3361e
LP
96 " <method name=\"ActivateSessionOnSeat\">\n" \
97 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
98 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
99 " </method>\n" \
88e3dc90
LP
100 " <method name=\"LockSession\">\n" \
101 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
102 " </method>\n" \
103 " <method name=\"UnlockSession\">\n" \
104 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
105 " </method>\n" \
fa2b196d 106 " <method name=\"LockSessions\"/>\n" \
b6160029 107 " <method name=\"UnlockSessions\"/>\n" \
de07ab16
LP
108 " <method name=\"KillSession\">\n" \
109 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
cae5846b
LP
110 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
111 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
de07ab16
LP
112 " </method>\n" \
113 " <method name=\"KillUser\">\n" \
114 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
cae5846b 115 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
de07ab16 116 " </method>\n" \
3f49d45a
LP
117 " <method name=\"TerminateSession\">\n" \
118 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
119 " </method>\n" \
120 " <method name=\"TerminateUser\">\n" \
bef422ae 121 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
3f49d45a
LP
122 " </method>\n" \
123 " <method name=\"TerminateSeat\">\n" \
124 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
125 " </method>\n" \
7f7bb946
LP
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" \
130 " </method>\n" \
47a26690
LP
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" \
135 " </method>\n" \
b668e064
LP
136 " <method name=\"FlushDevices\">\n" \
137 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
138 " </method>\n" \
55af3897
LP
139 " <method name=\"PowerOff\">\n" \
140 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
141 " </method>\n" \
142 " <method name=\"Reboot\">\n" \
143 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
144 " </method>\n" \
d889a206
LP
145 " <method name=\"Suspend\">\n" \
146 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
147 " </method>\n" \
148 " <method name=\"Hibernate\">\n" \
149 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
150 " </method>\n" \
6524990f
LP
151 " <method name=\"HybridSleep\">\n" \
152 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
153 " </method>\n" \
89f13440
LP
154 " <method name=\"CanPowerOff\">\n" \
155 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
156 " </method>\n" \
157 " <method name=\"CanReboot\">\n" \
158 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
159 " </method>\n" \
d889a206
LP
160 " <method name=\"CanSuspend\">\n" \
161 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
162 " </method>\n" \
163 " <method name=\"CanHibernate\">\n" \
164 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
165 " </method>\n" \
6524990f
LP
166 " <method name=\"CanHybridSleep\">\n" \
167 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
168 " </method>\n" \
f8e2fb7b
LP
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" \
eecd1362 173 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
f8e2fb7b
LP
174 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
175 " </method>\n" \
176 " <method name=\"ListInhibitors\">\n" \
eecd1362 177 " <arg name=\"inhibitors\" type=\"a(ssssuu)\" direction=\"out\"/>\n" \
f8e2fb7b 178 " </method>\n" \
3f49d45a
LP
179 " <signal name=\"SessionNew\">\n" \
180 " <arg name=\"id\" type=\"s\"/>\n" \
181 " <arg name=\"path\" type=\"o\"/>\n" \
182 " </signal>\n" \
183 " <signal name=\"SessionRemoved\">\n" \
184 " <arg name=\"id\" type=\"s\"/>\n" \
185 " <arg name=\"path\" type=\"o\"/>\n" \
186 " </signal>\n" \
187 " <signal name=\"UserNew\">\n" \
188 " <arg name=\"uid\" type=\"u\"/>\n" \
189 " <arg name=\"path\" type=\"o\"/>\n" \
190 " </signal>\n" \
191 " <signal name=\"UserRemoved\">\n" \
192 " <arg name=\"uid\" type=\"u\"/>\n" \
193 " <arg name=\"path\" type=\"o\"/>\n" \
194 " </signal>\n" \
195 " <signal name=\"SeatNew\">\n" \
196 " <arg name=\"id\" type=\"s\"/>\n" \
197 " <arg name=\"path\" type=\"o\"/>\n" \
198 " </signal>\n" \
199 " <signal name=\"SeatRemoved\">\n" \
200 " <arg name=\"id\" type=\"s\"/>\n" \
201 " <arg name=\"path\" type=\"o\"/>\n" \
202 " </signal>\n" \
eecd1362
LP
203 " <signal name=\"PrepareForShutdown\">\n" \
204 " <arg name=\"active\" type=\"b\"/>\n" \
205 " </signal>\n" \
d889a206
LP
206 " <signal name=\"PrepareForSleep\">\n" \
207 " <arg name=\"active\" type=\"b\"/>\n" \
208 " </signal>\n" \
3f49d45a
LP
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" \
a185c5aa
LP
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" \
eecd1362
LP
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" \
069cfc85 222 " <property name=\"HandlePowerKey\" type=\"s\" access=\"read\"/>\n" \
8e7fd6ad
LP
223 " <property name=\"HandleSuspendKey\" type=\"s\" access=\"read\"/>\n" \
224 " <property name=\"HandleHibernateKey\" type=\"s\" access=\"read\"/>\n" \
069cfc85 225 " <property name=\"HandleLidSwitch\" type=\"s\" access=\"read\"/>\n" \
23406ce5
LP
226 " <property name=\"IdleAction\" type=\"s\" access=\"read\"/>\n" \
227 " <property name=\"IdleActionUSec\" type=\"t\" access=\"read\"/>\n" \
5e4a79da
LP
228 " <property name=\"PreparingForShutdown\" type=\"b\" access=\"read\"/>\n" \
229 " <property name=\"PreparingForSleep\" type=\"b\" access=\"read\"/>\n" \
3f49d45a
LP
230 " </interface>\n"
231
232#define INTROSPECTION_BEGIN \
233 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
234 "<node>\n" \
235 BUS_MANAGER_INTERFACE \
236 BUS_PROPERTIES_INTERFACE \
237 BUS_PEER_INTERFACE \
238 BUS_INTROSPECTABLE_INTERFACE
239
240#define INTROSPECTION_END \
241 "</node>\n"
242
243#define INTERFACES_LIST \
244 BUS_GENERIC_INTERFACES_LIST \
245 "org.freedesktop.login1.Manager\0"
246
a185c5aa
LP
247static int bus_manager_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
248 Manager *m = data;
77527da0 249 dbus_bool_t b;
a185c5aa
LP
250
251 assert(i);
252 assert(property);
253 assert(m);
254
77527da0 255 b = manager_get_idle_hint(m, NULL) > 0;
a185c5aa
LP
256 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
257 return -ENOMEM;
258
259 return 0;
260}
261
262static int bus_manager_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
263 Manager *m = data;
264 dual_timestamp t;
265 uint64_t u;
266
267 assert(i);
268 assert(property);
269 assert(m);
270
271 manager_get_idle_hint(m, &t);
272 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
273
274 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
275 return -ENOMEM;
276
277 return 0;
278}
279
f8e2fb7b
LP
280static int bus_manager_append_inhibited(DBusMessageIter *i, const char *property, void *data) {
281 Manager *m = data;
282 InhibitWhat w;
283 const char *p;
284
eecd1362 285 w = manager_inhibit_what(m, streq(property, "BlockInhibited") ? INHIBIT_BLOCK : INHIBIT_DELAY);
f8e2fb7b
LP
286 p = inhibit_what_to_string(w);
287
288 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &p))
289 return -ENOMEM;
290
291 return 0;
292}
293
5e4a79da
LP
294static int bus_manager_append_preparing(DBusMessageIter *i, const char *property, void *data) {
295 Manager *m = data;
296 dbus_bool_t b;
297
298 assert(i);
299 assert(property);
300
301 if (streq(property, "PreparingForShutdown"))
314b4b0a 302 b = !!(m->action_what & INHIBIT_SHUTDOWN);
5e4a79da 303 else
314b4b0a 304 b = !!(m->action_what & INHIBIT_SLEEP);
5e4a79da
LP
305
306 dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b);
307 return 0;
308}
309
98a28fef 310static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMessage **_reply) {
954449b8 311 const char *type, *class, *cseat, *tty, *display, *remote_user, *remote_host, *service;
98a28fef 312 uint32_t uid, leader, audit_id = 0;
77085881 313 dbus_bool_t remote, kill_processes, exists;
954449b8
LP
314 _cleanup_strv_free_ char **controllers = NULL, **reset_controllers = NULL;
315 _cleanup_free_ char *cgroup = NULL, *id = NULL, *p = NULL;
98a28fef 316 SessionType t;
55efac6c 317 SessionClass c;
98a28fef
LP
318 DBusMessageIter iter;
319 int r;
4d6d6518 320 uint32_t vtnr = 0;
954449b8 321 _cleanup_close_ int fifo_fd = -1;
ce0fc5f5 322 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
954449b8
LP
323 Session *session = NULL;
324 User *user = NULL;
325 Seat *seat = NULL;
98a28fef
LP
326 bool b;
327
328 assert(m);
329 assert(message);
330 assert(_reply);
331
332 if (!dbus_message_iter_init(message, &iter) ||
333 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
334 return -EINVAL;
335
336 dbus_message_iter_get_basic(&iter, &uid);
337
338 if (!dbus_message_iter_next(&iter) ||
339 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
340 return -EINVAL;
341
342 dbus_message_iter_get_basic(&iter, &leader);
343
344 if (leader <= 0 ||
345 !dbus_message_iter_next(&iter) ||
346 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
347 return -EINVAL;
348
349 dbus_message_iter_get_basic(&iter, &service);
350
351 if (!dbus_message_iter_next(&iter) ||
352 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
353 return -EINVAL;
354
355 dbus_message_iter_get_basic(&iter, &type);
356 t = session_type_from_string(type);
357
358 if (t < 0 ||
359 !dbus_message_iter_next(&iter) ||
360 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
361 return -EINVAL;
362
55efac6c
LP
363 dbus_message_iter_get_basic(&iter, &class);
364 if (isempty(class))
365 c = SESSION_USER;
366 else
367 c = session_class_from_string(class);
368
369 if (c < 0 ||
370 !dbus_message_iter_next(&iter) ||
371 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
372 return -EINVAL;
373
954449b8 374 dbus_message_iter_get_basic(&iter, &cseat);
98a28fef 375
954449b8
LP
376 if (isempty(cseat))
377 seat = NULL;
98a28fef 378 else {
954449b8
LP
379 seat = hashmap_get(m->seats, cseat);
380 if (!seat)
98a28fef
LP
381 return -ENOENT;
382 }
383
4d6d6518
LP
384 if (!dbus_message_iter_next(&iter) ||
385 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
386 return -EINVAL;
387
388 dbus_message_iter_get_basic(&iter, &vtnr);
389
98a28fef
LP
390 if (!dbus_message_iter_next(&iter) ||
391 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
392 return -EINVAL;
393
394 dbus_message_iter_get_basic(&iter, &tty);
395
396 if (tty_is_vc(tty)) {
4d6d6518 397 int v;
98a28fef 398
954449b8
LP
399 if (!seat)
400 seat = m->vtconsole;
401 else if (seat != m->vtconsole)
98a28fef
LP
402 return -EINVAL;
403
4d6d6518
LP
404 v = vtnr_from_tty(tty);
405
406 if (v <= 0)
407 return v < 0 ? v : -EINVAL;
98a28fef
LP
408
409 if (vtnr <= 0)
4d6d6518
LP
410 vtnr = (uint32_t) v;
411 else if (vtnr != (uint32_t) v)
412 return -EINVAL;
d1122ad5
LP
413 } else if (tty_is_console(tty)) {
414
954449b8
LP
415 if (!seat)
416 seat = m->vtconsole;
417 else if (seat != m->vtconsole)
d1122ad5
LP
418 return -EINVAL;
419
420 if (vtnr != 0)
421 return -EINVAL;
978cf3c7 422 }
98a28fef 423
954449b8
LP
424 if (seat) {
425 if (seat_can_multi_session(seat)) {
d1122ad5 426 if (vtnr > 63)
4d6d6518
LP
427 return -EINVAL;
428 } else {
d1122ad5 429 if (vtnr != 0)
4d6d6518
LP
430 return -EINVAL;
431 }
432 }
433
98a28fef
LP
434 if (!dbus_message_iter_next(&iter) ||
435 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
436 return -EINVAL;
437
438 dbus_message_iter_get_basic(&iter, &display);
439
440 if (!dbus_message_iter_next(&iter) ||
441 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
442 return -EINVAL;
443
444 dbus_message_iter_get_basic(&iter, &remote);
445
446 if (!dbus_message_iter_next(&iter) ||
447 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
448 return -EINVAL;
449
450 dbus_message_iter_get_basic(&iter, &remote_user);
451
452 if (!dbus_message_iter_next(&iter) ||
453 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
454 return -EINVAL;
455
456 dbus_message_iter_get_basic(&iter, &remote_host);
457
458 if (!dbus_message_iter_next(&iter) ||
459 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
460 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
461 return -EINVAL;
462
463 r = bus_parse_strv_iter(&iter, &controllers);
464 if (r < 0)
465 return -EINVAL;
466
25d93491
LP
467 if (strv_contains(controllers, "systemd") ||
468 !dbus_message_iter_next(&iter) ||
98a28fef
LP
469 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
470 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) {
471 r = -EINVAL;
472 goto fail;
473 }
474
475 r = bus_parse_strv_iter(&iter, &reset_controllers);
476 if (r < 0)
477 goto fail;
478
25d93491
LP
479 if (strv_contains(reset_controllers, "systemd") ||
480 !dbus_message_iter_next(&iter) ||
98a28fef
LP
481 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) {
482 r = -EINVAL;
483 goto fail;
484 }
485
486 dbus_message_iter_get_basic(&iter, &kill_processes);
487
954449b8 488 r = cg_pid_get_cgroup(leader, NULL, &cgroup);
98a28fef
LP
489 if (r < 0)
490 goto fail;
491
954449b8
LP
492 r = manager_get_session_by_cgroup(m, cgroup, &session);
493 if (r < 0)
494 goto fail;
98a28fef 495
954449b8
LP
496 if (session) {
497 fifo_fd = session_create_fifo(session);
498 if (fifo_fd < 0) {
499 r = fifo_fd;
07714753
LP
500 goto fail;
501 }
98a28fef 502
954449b8
LP
503 /* Session already exists, client is probably
504 * something like "su" which changes uid but
505 * is still the same audit session */
21c390cc 506
954449b8
LP
507 reply = dbus_message_new_method_return(message);
508 if (!reply) {
509 r = -ENOMEM;
510 goto fail;
511 }
21c390cc 512
954449b8
LP
513 p = session_bus_path(session);
514 if (!p) {
515 r = -ENOMEM;
516 goto fail;
517 }
932e3ee7 518
954449b8
LP
519 cseat = session->seat ? session->seat->id : "";
520 vtnr = session->vtnr;
521 exists = true;
522
523 b = dbus_message_append_args(
524 reply,
525 DBUS_TYPE_STRING, &session->id,
526 DBUS_TYPE_OBJECT_PATH, &p,
527 DBUS_TYPE_STRING, &session->user->runtime_path,
528 DBUS_TYPE_UNIX_FD, &fifo_fd,
529 DBUS_TYPE_STRING, &cseat,
530 DBUS_TYPE_UINT32, &vtnr,
531 DBUS_TYPE_BOOLEAN, &exists,
532 DBUS_TYPE_INVALID);
533 if (!b) {
534 r = -ENOMEM;
535 goto fail;
536 }
21c390cc 537
954449b8 538 *_reply = reply;
ce0fc5f5 539 reply = NULL;
21c390cc 540
954449b8
LP
541 return 0;
542 }
21c390cc 543
954449b8
LP
544 audit_session_from_pid(leader, &audit_id);
545 if (audit_id > 0) {
546 /* Keep our session IDs and the audit session IDs in sync */
21c390cc 547
954449b8
LP
548 if (asprintf(&id, "%lu", (unsigned long) audit_id) < 0) {
549 r = -ENOMEM;
550 goto fail;
551 }
21c390cc 552
954449b8
LP
553 /* Wut? There's already a session by this name and we
554 * didn't find it above? Weird, then let's not trust
555 * the audit data and let's better register a new
556 * ID */
557 if (hashmap_get(m->sessions, id)) {
558 audit_id = 0;
8ea913b2 559
954449b8
LP
560 free(id);
561 id = NULL;
07714753 562 }
954449b8 563 }
07714753 564
954449b8 565 if (!id) {
07714753
LP
566 do {
567 free(id);
f8e2fb7b 568 id = NULL;
07714753 569
f8e2fb7b 570 if (asprintf(&id, "c%lu", ++m->session_counter) < 0) {
07714753
LP
571 r = -ENOMEM;
572 goto fail;
573 }
574
575 } while (hashmap_get(m->sessions, id));
98a28fef
LP
576 }
577
954449b8
LP
578 r = manager_add_user_by_uid(m, uid, &user);
579 if (r < 0)
580 goto fail;
581
98a28fef 582 r = manager_add_session(m, user, id, &session);
98a28fef
LP
583 if (r < 0)
584 goto fail;
585
586 session->leader = leader;
587 session->audit_id = audit_id;
588 session->type = t;
55efac6c 589 session->class = c;
98a28fef
LP
590 session->remote = remote;
591 session->controllers = controllers;
592 session->reset_controllers = reset_controllers;
593 session->kill_processes = kill_processes;
594 session->vtnr = vtnr;
595
596 controllers = reset_controllers = NULL;
597
598 if (!isempty(tty)) {
599 session->tty = strdup(tty);
600 if (!session->tty) {
601 r = -ENOMEM;
602 goto fail;
603 }
604 }
605
606 if (!isempty(display)) {
607 session->display = strdup(display);
608 if (!session->display) {
609 r = -ENOMEM;
610 goto fail;
611 }
612 }
613
614 if (!isempty(remote_user)) {
615 session->remote_user = strdup(remote_user);
616 if (!session->remote_user) {
617 r = -ENOMEM;
618 goto fail;
619 }
620 }
621
622 if (!isempty(remote_host)) {
623 session->remote_host = strdup(remote_host);
624 if (!session->remote_host) {
625 r = -ENOMEM;
626 goto fail;
627 }
628 }
629
630 if (!isempty(service)) {
631 session->service = strdup(service);
632 if (!session->service) {
633 r = -ENOMEM;
634 goto fail;
635 }
636 }
637
932e3ee7
LP
638 fifo_fd = session_create_fifo(session);
639 if (fifo_fd < 0) {
640 r = fifo_fd;
98a28fef
LP
641 goto fail;
642 }
643
954449b8
LP
644 if (seat) {
645 r = seat_attach_session(seat, session);
98a28fef
LP
646 if (r < 0)
647 goto fail;
648 }
649
650 r = session_start(session);
651 if (r < 0)
652 goto fail;
653
654 reply = dbus_message_new_method_return(message);
655 if (!reply) {
656 r = -ENOMEM;
657 goto fail;
658 }
659
660 p = session_bus_path(session);
661 if (!p) {
662 r = -ENOMEM;
663 goto fail;
664 }
665
954449b8 666 cseat = seat ? seat->id : "";
77085881 667 exists = false;
98a28fef
LP
668 b = dbus_message_append_args(
669 reply,
670 DBUS_TYPE_STRING, &session->id,
671 DBUS_TYPE_OBJECT_PATH, &p,
672 DBUS_TYPE_STRING, &session->user->runtime_path,
932e3ee7 673 DBUS_TYPE_UNIX_FD, &fifo_fd,
954449b8 674 DBUS_TYPE_STRING, &cseat,
bbc73283 675 DBUS_TYPE_UINT32, &vtnr,
77085881 676 DBUS_TYPE_BOOLEAN, &exists,
98a28fef 677 DBUS_TYPE_INVALID);
98a28fef
LP
678
679 if (!b) {
680 r = -ENOMEM;
681 goto fail;
682 }
683
98a28fef 684 *_reply = reply;
ce0fc5f5 685 reply = NULL;
98a28fef
LP
686
687 return 0;
688
689fail:
98a28fef
LP
690 if (session)
691 session_add_to_gc_queue(session);
692
693 if (user)
694 user_add_to_gc_queue(user);
695
98a28fef
LP
696 return r;
697}
698
314b4b0a
LP
699static int bus_manager_inhibit(
700 Manager *m,
701 DBusConnection *connection,
702 DBusMessage *message,
703 DBusError *error,
704 DBusMessage **_reply) {
705
f8e2fb7b
LP
706 Inhibitor *i = NULL;
707 char *id = NULL;
eecd1362 708 const char *who, *why, *what, *mode;
f8e2fb7b
LP
709 pid_t pid;
710 InhibitWhat w;
eecd1362 711 InhibitMode mm;
f8e2fb7b
LP
712 unsigned long ul;
713 int r, fifo_fd = -1;
ce0fc5f5 714 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
f8e2fb7b
LP
715
716 assert(m);
717 assert(connection);
718 assert(message);
719 assert(error);
720 assert(_reply);
721
722 if (!dbus_message_get_args(
723 message,
724 error,
725 DBUS_TYPE_STRING, &what,
726 DBUS_TYPE_STRING, &who,
727 DBUS_TYPE_STRING, &why,
eecd1362 728 DBUS_TYPE_STRING, &mode,
f8e2fb7b
LP
729 DBUS_TYPE_INVALID)) {
730 r = -EIO;
731 goto fail;
732 }
733
734 w = inhibit_what_from_string(what);
735 if (w <= 0) {
736 r = -EINVAL;
737 goto fail;
738 }
739
eecd1362
LP
740 mm = inhibit_mode_from_string(mode);
741 if (mm < 0) {
742 r = -EINVAL;
743 goto fail;
744 }
745
beaafb2e
LP
746 /* Delay is only supported for shutdown/sleep */
747 if (mm == INHIBIT_DELAY && (w & ~(INHIBIT_SHUTDOWN|INHIBIT_SLEEP))) {
748 r = -EINVAL;
749 goto fail;
750 }
751
314b4b0a
LP
752 /* Don't allow taking delay locks while we are already
753 * executing the operation. We shouldn't create the impression
754 * that the lock was successful if the machine is about to go
755 * down/suspend any moment. */
756 if (m->action_what & w) {
757 r = -EALREADY;
758 goto fail;
759 }
760
eecd1362 761 r = verify_polkit(connection, message,
8e7fd6ad
LP
762 w == INHIBIT_SHUTDOWN ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
763 w == INHIBIT_SLEEP ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep" : "org.freedesktop.login1.inhibit-delay-sleep") :
764 w == INHIBIT_IDLE ? "org.freedesktop.login1.inhibit-block-idle" :
765 w == INHIBIT_HANDLE_POWER_KEY ? "org.freedesktop.login1.inhibit-handle-power-key" :
766 w == INHIBIT_HANDLE_SUSPEND_KEY ? "org.freedesktop.login1.inhibit-handle-suspend-key" :
767 w == INHIBIT_HANDLE_HIBERNATE_KEY ? "org.freedesktop.login1.inhibit-handle-hibernate-key" :
768 "org.freedesktop.login1.inhibit-handle-lid-switch",
b14eda96 769 false, NULL, error);
f8e2fb7b
LP
770 if (r < 0)
771 goto fail;
772
773 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
774 if (ul == (unsigned long) -1) {
775 r = -EIO;
776 goto fail;
777 }
778
779 pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
780 if (pid <= 0) {
781 r = -EIO;
782 goto fail;
783 }
784
785 do {
786 free(id);
787 id = NULL;
788
789 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
790 r = -ENOMEM;
791 goto fail;
792 }
793 } while (hashmap_get(m->inhibitors, id));
794
795 r = manager_add_inhibitor(m, id, &i);
796 free(id);
797
798 if (r < 0)
799 goto fail;
800
801 i->what = w;
eecd1362 802 i->mode = mm;
f8e2fb7b
LP
803 i->pid = pid;
804 i->uid = (uid_t) ul;
805 i->why = strdup(why);
806 i->who = strdup(who);
807
808 if (!i->why || !i->who) {
809 r = -ENOMEM;
810 goto fail;
811 }
812
813 fifo_fd = inhibitor_create_fifo(i);
814 if (fifo_fd < 0) {
815 r = fifo_fd;
816 goto fail;
817 }
818
819 reply = dbus_message_new_method_return(message);
820 if (!reply) {
821 r = -ENOMEM;
822 goto fail;
823 }
824
825 if (!dbus_message_append_args(
826 reply,
827 DBUS_TYPE_UNIX_FD, &fifo_fd,
828 DBUS_TYPE_INVALID)) {
829 r = -ENOMEM;
830 goto fail;
831 }
832
833 close_nointr_nofail(fifo_fd);
834 *_reply = reply;
ce0fc5f5 835 reply = NULL;
f8e2fb7b
LP
836
837 inhibitor_start(i);
838
839 return 0;
840
841fail:
842 if (i)
843 inhibitor_free(i);
844
845 if (fifo_fd >= 0)
846 close_nointr_nofail(fifo_fd);
847
f8e2fb7b
LP
848 return r;
849}
850
2eb916cd 851static int trigger_device(Manager *m, struct udev_device *d) {
b668e064
LP
852 struct udev_enumerate *e;
853 struct udev_list_entry *first, *item;
854 int r;
855
856 assert(m);
857
858 e = udev_enumerate_new(m->udev);
859 if (!e) {
860 r = -ENOMEM;
861 goto finish;
862 }
863
2eb916cd
LP
864 if (d) {
865 if (udev_enumerate_add_match_parent(e, d) < 0) {
866 r = -EIO;
867 goto finish;
868 }
869 }
870
b668e064
LP
871 if (udev_enumerate_scan_devices(e) < 0) {
872 r = -EIO;
873 goto finish;
874 }
875
876 first = udev_enumerate_get_list_entry(e);
877 udev_list_entry_foreach(item, first) {
878 char *t;
879 const char *p;
880
881 p = udev_list_entry_get_name(item);
882
b668e064
LP
883 t = strappend(p, "/uevent");
884 if (!t) {
885 r = -ENOMEM;
886 goto finish;
887 }
888
574d5f2d 889 write_string_file(t, "change");
b668e064
LP
890 free(t);
891 }
892
893 r = 0;
894
895finish:
896 if (e)
897 udev_enumerate_unref(e);
898
899 return r;
900}
901
47a26690
LP
902static int attach_device(Manager *m, const char *seat, const char *sysfs) {
903 struct udev_device *d;
4654e558 904 char _cleanup_free_ *rule = NULL, *file = NULL;
c28fa3d3 905 const char *id_for_seat;
47a26690
LP
906 int r;
907
908 assert(m);
909 assert(seat);
910 assert(sysfs);
911
912 d = udev_device_new_from_syspath(m->udev, sysfs);
913 if (!d)
914 return -ENODEV;
915
309c2a2c 916 if (!udev_device_has_tag(d, "seat")) {
47a26690
LP
917 r = -ENODEV;
918 goto finish;
919 }
920
c28fa3d3
LP
921 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
922 if (!id_for_seat) {
47a26690
LP
923 r = -ENODEV;
924 goto finish;
925 }
926
c28fa3d3 927 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
47a26690
LP
928 r = -ENOMEM;
929 goto finish;
930 }
931
c28fa3d3 932 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
47a26690
LP
933 r = -ENOMEM;
934 goto finish;
935 }
936
d2e54fae 937 mkdir_p_label("/etc/udev/rules.d", 0755);
a5c32cff 938 label_init("/etc");
574d5f2d 939 r = write_string_file_atomic_label(file, rule);
a0a0c7f1
LP
940 if (r < 0)
941 goto finish;
942
2eb916cd 943 r = trigger_device(m, d);
47a26690
LP
944
945finish:
47a26690
LP
946 if (d)
947 udev_device_unref(d);
948
949 return r;
950}
951
b668e064 952static int flush_devices(Manager *m) {
4654e558 953 DIR _cleanup_closedir_ *d;
b668e064
LP
954
955 assert(m);
956
957 d = opendir("/etc/udev/rules.d");
958 if (!d) {
959 if (errno != ENOENT)
960 log_warning("Failed to open /etc/udev/rules.d: %m");
961 } else {
962 struct dirent *de;
963
964 while ((de = readdir(d))) {
965
966 if (!dirent_is_file(de))
967 continue;
968
969 if (!startswith(de->d_name, "72-seat-"))
970 continue;
971
972 if (!endswith(de->d_name, ".rules"))
973 continue;
974
975 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
976 log_warning("Failed to unlink %s: %m", de->d_name);
977 }
b668e064
LP
978 }
979
980 return trigger_device(m, NULL);
981}
982
89f13440 983static int have_multiple_sessions(
89f13440 984 Manager *m,
409133be 985 uid_t uid) {
89f13440 986
2154761f
MS
987 Session *session;
988 Iterator i;
89f13440
LP
989
990 assert(m);
991
1ca04b87
LP
992 /* Check for other users' sessions. Greeter sessions do not
993 * count, and non-login sessions do not count either. */
2154761f 994 HASHMAP_FOREACH(session, m->sessions, i)
1ca04b87
LP
995 if (session->class == SESSION_USER &&
996 (session->type == SESSION_TTY || session->type == SESSION_X11) &&
997 session->user->uid != uid)
2154761f 998 return true;
89f13440
LP
999
1000 return false;
1001}
1002
314b4b0a
LP
1003static int bus_manager_log_shutdown(
1004 Manager *m,
1005 InhibitWhat w,
1006 const char *unit_name) {
1007
1008 const char *p, *q;
1009
1010 assert(m);
1011 assert(unit_name);
1012
1013 if (w != INHIBIT_SHUTDOWN)
1014 return 0;
1015
1016 if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
1017 p = "MESSAGE=System is powering down.";
1018 q = "SHUTDOWN=power-off";
1019 } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
1020 p = "MESSAGE=System is halting.";
1021 q = "SHUTDOWN=halt";
1022 } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
1023 p = "MESSAGE=System is rebooting.";
1024 q = "SHUTDOWN=reboot";
1025 } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
1026 p = "MESSAGE=System is rebooting with kexec.";
1027 q = "SHUTDOWN=kexec";
1028 } else {
1029 p = "MESSAGE=System is shutting down.";
1030 q = NULL;
1031 }
1032
1033 return log_struct(LOG_NOTICE, MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
1034 p,
1035 q, NULL);
1036}
1037
1038static int execute_shutdown_or_sleep(
1039 Manager *m,
1040 InhibitWhat w,
1041 const char *unit_name,
1042 DBusError *error) {
1043
af9792ac 1044 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
b85bddda 1045 const char *mode = "replace-irreversibly", *p;
af9792ac
LP
1046 int r;
1047 char *c;
eecd1362 1048
af9792ac 1049 assert(m);
314b4b0a
LP
1050 assert(w >= 0);
1051 assert(w < _INHIBIT_WHAT_MAX);
d889a206 1052 assert(unit_name);
eecd1362 1053
314b4b0a
LP
1054 bus_manager_log_shutdown(m, w, unit_name);
1055
af9792ac
LP
1056 r = bus_method_call_with_reply(
1057 m->bus,
eecd1362
LP
1058 "org.freedesktop.systemd1",
1059 "/org/freedesktop/systemd1",
1060 "org.freedesktop.systemd1.Manager",
b9c26b41 1061 "StartUnit",
af9792ac
LP
1062 &reply,
1063 error,
b9c26b41
SP
1064 DBUS_TYPE_STRING, &unit_name,
1065 DBUS_TYPE_STRING, &mode,
1066 DBUS_TYPE_INVALID);
af9792ac
LP
1067 if (r < 0)
1068 return r;
1069
1070 if (!dbus_message_get_args(
1071 reply,
1072 error,
1073 DBUS_TYPE_OBJECT_PATH, &p,
1074 DBUS_TYPE_INVALID))
1075 return -EINVAL;
1076
1077 c = strdup(p);
1078 if (!c)
1079 return -ENOMEM;
1080
314b4b0a 1081 m->action_unit = unit_name;
af9792ac
LP
1082 free(m->action_job);
1083 m->action_job = c;
314b4b0a 1084 m->action_what = w;
af9792ac
LP
1085
1086 return 0;
eecd1362
LP
1087}
1088
314b4b0a
LP
1089static int delay_shutdown_or_sleep(
1090 Manager *m,
1091 InhibitWhat w,
1092 const char *unit_name) {
eecd1362 1093
eecd1362 1094 assert(m);
d889a206
LP
1095 assert(w >= 0);
1096 assert(w < _INHIBIT_WHAT_MAX);
314b4b0a 1097 assert(unit_name);
eecd1362 1098
314b4b0a
LP
1099 m->action_timestamp = now(CLOCK_MONOTONIC);
1100 m->action_unit = unit_name;
1101 m->action_what = w;
d889a206
LP
1102
1103 return 0;
1104}
1105
1106static int bus_manager_can_shutdown_or_sleep(
1107 Manager *m,
1108 DBusConnection *connection,
1109 DBusMessage *message,
1110 InhibitWhat w,
1111 const char *action,
1112 const char *action_multiple_sessions,
1113 const char *action_ignore_inhibit,
1114 const char *sleep_type,
6524990f 1115 const char *sleep_disk_type,
d889a206
LP
1116 DBusError *error,
1117 DBusMessage **_reply) {
1118
1119 bool multiple_sessions, challenge, blocked, b;
1120 const char *result;
ce0fc5f5 1121 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
d889a206 1122 int r;
409133be 1123 unsigned long ul;
d889a206
LP
1124
1125 assert(m);
1126 assert(connection);
1127 assert(message);
1128 assert(w >= 0);
1129 assert(w <= _INHIBIT_WHAT_MAX);
1130 assert(action);
1131 assert(action_multiple_sessions);
1132 assert(action_ignore_inhibit);
1133 assert(error);
1134 assert(_reply);
1135
1136 if (sleep_type) {
1137 r = can_sleep(sleep_type);
1138 if (r < 0)
1139 return r;
1140
398f7c88
MC
1141 if (r == 0) {
1142 result = "na";
1143 goto finish;
1144 }
d889a206
LP
1145 }
1146
6524990f
LP
1147 if (sleep_disk_type) {
1148 r = can_sleep_disk(sleep_disk_type);
1149 if (r < 0)
1150 return r;
1151
1152 if (r == 0) {
1153 result = "na";
1154 goto finish;
1155 }
1156 }
1157
409133be
LP
1158 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1159 if (ul == (unsigned long) -1)
1160 return -EIO;
1161
1162 r = have_multiple_sessions(m, (uid_t) ul);
d889a206
LP
1163 if (r < 0)
1164 return r;
1165
1166 multiple_sessions = r > 0;
409133be 1167 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
d889a206
LP
1168
1169 if (multiple_sessions) {
1170 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1171 if (r < 0)
1172 return r;
1173
1174 if (r > 0)
1175 result = "yes";
d5a745df
LP
1176 else if (challenge)
1177 result = "challenge";
1178 else
1179 result = "no";
1180 }
d889a206
LP
1181
1182 if (blocked) {
1183 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1184 if (r < 0)
1185 return r;
1186
1187 if (r > 0 && !result)
1188 result = "yes";
1189 else if (challenge && (!result || streq(result, "yes")))
1190 result = "challenge";
1191 else
1192 result = "no";
1193 }
1194
1195 if (!multiple_sessions && !blocked) {
1196 /* If neither inhibit nor multiple sessions
1197 * apply then just check the normal policy */
1198
1199 r = verify_polkit(connection, message, action, false, &challenge, error);
1200 if (r < 0)
1201 return r;
1202
1203 if (r > 0)
1204 result = "yes";
1205 else if (challenge)
1206 result = "challenge";
1207 else
1208 result = "no";
1209 }
1210
1211finish:
1212 reply = dbus_message_new_method_return(message);
1213 if (!reply)
1214 return -ENOMEM;
1215
1216 b = dbus_message_append_args(
1217 reply,
1218 DBUS_TYPE_STRING, &result,
1219 DBUS_TYPE_INVALID);
4654e558 1220 if (!b)
d889a206 1221 return -ENOMEM;
d889a206
LP
1222
1223 *_reply = reply;
ce0fc5f5 1224 reply = NULL;
d889a206
LP
1225 return 0;
1226}
1227
314b4b0a
LP
1228static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
1229 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
1230 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
1231 [INHIBIT_SLEEP] = "PrepareForSleep"
1232 };
877d54e9 1233
314b4b0a
LP
1234 dbus_bool_t active = _active;
1235 _cleanup_dbus_message_unref_ DBusMessage *message = NULL;
877d54e9
LP
1236
1237 assert(m);
314b4b0a
LP
1238 assert(w >= 0);
1239 assert(w < _INHIBIT_WHAT_MAX);
1240 assert(signal_name[w]);
877d54e9 1241
314b4b0a
LP
1242 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1243 if (!message)
1244 return -ENOMEM;
877d54e9 1245
314b4b0a
LP
1246 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1247 !dbus_connection_send(m->bus, message, NULL))
1248 return -ENOMEM;
877d54e9 1249
314b4b0a 1250 return 0;
877d54e9
LP
1251}
1252
069cfc85
LP
1253int bus_manager_shutdown_or_sleep_now_or_later(
1254 Manager *m,
1255 const char *unit_name,
1256 InhibitWhat w,
1257 DBusError *error) {
1258
1259 bool delayed;
1260 int r;
1261
1262 assert(m);
1263 assert(unit_name);
1264 assert(w >= 0);
1265 assert(w <= _INHIBIT_WHAT_MAX);
af9792ac 1266 assert(!m->action_job);
069cfc85 1267
314b4b0a
LP
1268 /* Tell everybody to prepare for shutdown/sleep */
1269 send_prepare_for(m, w, true);
1270
069cfc85
LP
1271 delayed =
1272 m->inhibit_delay_max > 0 &&
409133be 1273 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0);
069cfc85
LP
1274
1275 if (delayed)
1276 /* Shutdown is delayed, keep in mind what we
1277 * want to do, and start a timeout */
1278 r = delay_shutdown_or_sleep(m, w, unit_name);
314b4b0a 1279 else
069cfc85
LP
1280 /* Shutdown is not delayed, execute it
1281 * immediately */
314b4b0a 1282 r = execute_shutdown_or_sleep(m, w, unit_name, error);
069cfc85
LP
1283
1284 return r;
1285}
1286
d889a206
LP
1287static int bus_manager_do_shutdown_or_sleep(
1288 Manager *m,
1289 DBusConnection *connection,
1290 DBusMessage *message,
1291 const char *unit_name,
1292 InhibitWhat w,
1293 const char *action,
1294 const char *action_multiple_sessions,
1295 const char *action_ignore_inhibit,
1296 const char *sleep_type,
6524990f 1297 const char *sleep_disk_type,
d889a206
LP
1298 DBusError *error,
1299 DBusMessage **_reply) {
1300
1301 dbus_bool_t interactive;
069cfc85 1302 bool multiple_sessions, blocked;
d889a206
LP
1303 DBusMessage *reply = NULL;
1304 int r;
409133be 1305 unsigned long ul;
d889a206
LP
1306
1307 assert(m);
1308 assert(connection);
1309 assert(message);
1310 assert(unit_name);
1311 assert(w >= 0);
1312 assert(w <= _INHIBIT_WHAT_MAX);
1313 assert(action);
1314 assert(action_multiple_sessions);
1315 assert(action_ignore_inhibit);
1316 assert(error);
1317 assert(_reply);
1318
314b4b0a
LP
1319 /* Don't allow multiple jobs being executed at the same time */
1320 if (m->action_what)
af9792ac
LP
1321 return -EALREADY;
1322
d889a206
LP
1323 if (!dbus_message_get_args(
1324 message,
1325 error,
1326 DBUS_TYPE_BOOLEAN, &interactive,
1327 DBUS_TYPE_INVALID))
1328 return -EINVAL;
1329
1330 if (sleep_type) {
1331 r = can_sleep(sleep_type);
1332 if (r < 0)
1333 return r;
1334
1335 if (r == 0)
1336 return -ENOTSUP;
1337 }
1338
6524990f
LP
1339 if (sleep_disk_type) {
1340 r = can_sleep_disk(sleep_disk_type);
1341 if (r < 0)
1342 return r;
1343
1344 if (r == 0)
1345 return -ENOTSUP;
1346 }
1347
409133be
LP
1348 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1349 if (ul == (unsigned long) -1)
1350 return -EIO;
1351
1352 r = have_multiple_sessions(m, (uid_t) ul);
d889a206
LP
1353 if (r < 0)
1354 return r;
1355
1356 multiple_sessions = r > 0;
409133be 1357 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
d889a206
LP
1358
1359 if (multiple_sessions) {
1360 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1361 if (r < 0)
1362 return r;
1363 }
1364
1365 if (blocked) {
1366 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1367 if (r < 0)
1368 return r;
1369 }
1370
1371 if (!multiple_sessions && !blocked) {
1372 r = verify_polkit(connection, message, action, interactive, NULL, error);
1373 if (r < 0)
1374 return r;
1375 }
1376
069cfc85 1377 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
d889a206
LP
1378 if (r < 0)
1379 return r;
1380
1381 reply = dbus_message_new_method_return(message);
1382 if (!reply)
1383 return -ENOMEM;
eecd1362 1384
d889a206 1385 *_reply = reply;
eecd1362
LP
1386 return 0;
1387}
1388
23406ce5 1389static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_action, handle_action, HandleAction);
069cfc85 1390
d200735e
MS
1391static const BusProperty bus_login_manager_properties[] = {
1392 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_path), true },
1393 { "Controllers", bus_property_append_strv, "as", offsetof(Manager, controllers), true },
1394 { "ResetControllers", bus_property_append_strv, "as", offsetof(Manager, reset_controllers), true },
1395 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1396 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1397 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1398 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1399 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1400 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1401 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
eecd1362
LP
1402 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1403 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1404 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
23406ce5
LP
1405 { "HandlePowerKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_power_key) },
1406 { "HandleSuspendKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_suspend_key) },
1407 { "HandleHibernateKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_hibernate_key)},
1408 { "HandleLidSwitch", bus_manager_append_handle_action, "s", offsetof(Manager, handle_lid_switch) },
1409 { "IdleAction", bus_manager_append_handle_action, "s", offsetof(Manager, idle_action) },
1410 { "IdleActionUSec", bus_property_append_usec, "t", offsetof(Manager, idle_action_usec) },
5e4a79da
LP
1411 { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
1412 { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
d200735e
MS
1413 { NULL, }
1414};
1415
3f49d45a
LP
1416static DBusHandlerResult manager_message_handler(
1417 DBusConnection *connection,
1418 DBusMessage *message,
1419 void *userdata) {
1420
1421 Manager *m = userdata;
1422
3f49d45a 1423 DBusError error;
ce0fc5f5 1424 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
bef422ae 1425 int r;
3f49d45a
LP
1426
1427 assert(connection);
1428 assert(message);
1429 assert(m);
1430
1431 dbus_error_init(&error);
1432
bef422ae
LP
1433 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1434 const char *name;
1435 char *p;
1436 Session *session;
1437 bool b;
1438
1439 if (!dbus_message_get_args(
1440 message,
1441 &error,
1442 DBUS_TYPE_STRING, &name,
1443 DBUS_TYPE_INVALID))
1444 return bus_send_error_reply(connection, message, &error, -EINVAL);
1445
1446 session = hashmap_get(m->sessions, name);
1447 if (!session)
1448 return bus_send_error_reply(connection, message, &error, -ENOENT);
1449
1450 reply = dbus_message_new_method_return(message);
1451 if (!reply)
1452 goto oom;
1453
1454 p = session_bus_path(session);
c4aa65e7
LP
1455 if (!p)
1456 goto oom;
1457
1458 b = dbus_message_append_args(
1459 reply,
1460 DBUS_TYPE_OBJECT_PATH, &p,
1461 DBUS_TYPE_INVALID);
1462 free(p);
1463
1464 if (!b)
1465 goto oom;
1466
1467 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1468 uint32_t pid;
1469 char *p;
1470 Session *session;
1471 bool b;
1472
1473 if (!dbus_message_get_args(
1474 message,
1475 &error,
1476 DBUS_TYPE_UINT32, &pid,
1477 DBUS_TYPE_INVALID))
1478 return bus_send_error_reply(connection, message, &error, -EINVAL);
1479
1480 r = manager_get_session_by_pid(m, pid, &session);
1481 if (r <= 0)
1482 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1483
1484 reply = dbus_message_new_method_return(message);
1485 if (!reply)
1486 goto oom;
1487
1488 p = session_bus_path(session);
bef422ae
LP
1489 if (!p)
1490 goto oom;
1491
1492 b = dbus_message_append_args(
1493 reply,
1494 DBUS_TYPE_OBJECT_PATH, &p,
1495 DBUS_TYPE_INVALID);
1496 free(p);
1497
1498 if (!b)
1499 goto oom;
1500
1501 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1502 uint32_t uid;
1503 char *p;
1504 User *user;
1505 bool b;
1506
1507 if (!dbus_message_get_args(
1508 message,
1509 &error,
1510 DBUS_TYPE_UINT32, &uid,
1511 DBUS_TYPE_INVALID))
1512 return bus_send_error_reply(connection, message, &error, -EINVAL);
1513
1514 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1515 if (!user)
1516 return bus_send_error_reply(connection, message, &error, -ENOENT);
1517
1518 reply = dbus_message_new_method_return(message);
1519 if (!reply)
1520 goto oom;
1521
1522 p = user_bus_path(user);
1523 if (!p)
1524 goto oom;
1525
1526 b = dbus_message_append_args(
1527 reply,
1528 DBUS_TYPE_OBJECT_PATH, &p,
1529 DBUS_TYPE_INVALID);
1530 free(p);
1531
1532 if (!b)
1533 goto oom;
1534
1535 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1536 const char *name;
1537 char *p;
1538 Seat *seat;
1539 bool b;
1540
1541 if (!dbus_message_get_args(
1542 message,
1543 &error,
1544 DBUS_TYPE_STRING, &name,
1545 DBUS_TYPE_INVALID))
1546 return bus_send_error_reply(connection, message, &error, -EINVAL);
1547
1548 seat = hashmap_get(m->seats, name);
1549 if (!seat)
1550 return bus_send_error_reply(connection, message, &error, -ENOENT);
1551
1552 reply = dbus_message_new_method_return(message);
1553 if (!reply)
1554 goto oom;
1555
1556 p = seat_bus_path(seat);
1557 if (!p)
1558 goto oom;
1559
1560 b = dbus_message_append_args(
1561 reply,
1562 DBUS_TYPE_OBJECT_PATH, &p,
1563 DBUS_TYPE_INVALID);
1564 free(p);
1565
1566 if (!b)
1567 goto oom;
1568
e1c9c2d5
LP
1569 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1570 char *p;
1571 Session *session;
1572 Iterator i;
1573 DBusMessageIter iter, sub;
1574 const char *empty = "";
1575
1576 reply = dbus_message_new_method_return(message);
1577 if (!reply)
1578 goto oom;
1579
1580 dbus_message_iter_init_append(reply, &iter);
1581
dec15e92 1582 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
e1c9c2d5
LP
1583 goto oom;
1584
1585 HASHMAP_FOREACH(session, m->sessions, i) {
1586 DBusMessageIter sub2;
1587 uint32_t uid;
1588
1589 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1590 goto oom;
1591
1592 uid = session->user->uid;
1593
1594 p = session_bus_path(session);
1595 if (!p)
1596 goto oom;
1597
1598 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1599 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1600 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1601 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1602 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1603 free(p);
1604 goto oom;
1605 }
1606
1607 free(p);
1608
1609 if (!dbus_message_iter_close_container(&sub, &sub2))
1610 goto oom;
1611 }
1612
1613 if (!dbus_message_iter_close_container(&iter, &sub))
1614 goto oom;
1615
1616 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1617 char *p;
1618 User *user;
1619 Iterator i;
1620 DBusMessageIter iter, sub;
1621
1622 reply = dbus_message_new_method_return(message);
1623 if (!reply)
1624 goto oom;
1625
1626 dbus_message_iter_init_append(reply, &iter);
1627
dec15e92 1628 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
e1c9c2d5
LP
1629 goto oom;
1630
1631 HASHMAP_FOREACH(user, m->users, i) {
1632 DBusMessageIter sub2;
1633 uint32_t uid;
1634
1635 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1636 goto oom;
1637
1638 uid = user->uid;
1639
1640 p = user_bus_path(user);
1641 if (!p)
1642 goto oom;
1643
1644 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1645 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1646 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1647 free(p);
1648 goto oom;
1649 }
1650
1651 free(p);
1652
1653 if (!dbus_message_iter_close_container(&sub, &sub2))
1654 goto oom;
1655 }
1656
1657 if (!dbus_message_iter_close_container(&iter, &sub))
1658 goto oom;
1659
1660 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1661 char *p;
1662 Seat *seat;
1663 Iterator i;
1664 DBusMessageIter iter, sub;
1665
1666 reply = dbus_message_new_method_return(message);
1667 if (!reply)
1668 goto oom;
1669
1670 dbus_message_iter_init_append(reply, &iter);
1671
dec15e92 1672 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
e1c9c2d5
LP
1673 goto oom;
1674
1675 HASHMAP_FOREACH(seat, m->seats, i) {
1676 DBusMessageIter sub2;
1677
1678 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1679 goto oom;
1680
1681 p = seat_bus_path(seat);
1682 if (!p)
1683 goto oom;
1684
1685 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1686 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1687 free(p);
1688 goto oom;
1689 }
1690
1691 free(p);
1692
1693 if (!dbus_message_iter_close_container(&sub, &sub2))
1694 goto oom;
1695 }
1696
1697 if (!dbus_message_iter_close_container(&iter, &sub))
1698 goto oom;
1699
f8e2fb7b
LP
1700 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1701 Inhibitor *inhibitor;
1702 Iterator i;
1703 DBusMessageIter iter, sub;
1704
1705 reply = dbus_message_new_method_return(message);
1706 if (!reply)
1707 goto oom;
1708
1709 dbus_message_iter_init_append(reply, &iter);
1710
eecd1362 1711 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
f8e2fb7b
LP
1712 goto oom;
1713
1714 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1715 DBusMessageIter sub2;
1716 dbus_uint32_t uid, pid;
eecd1362 1717 const char *what, *who, *why, *mode;
f8e2fb7b
LP
1718
1719 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1720 goto oom;
1721
eecd1362 1722 what = strempty(inhibit_what_to_string(inhibitor->what));
f8e2fb7b
LP
1723 who = strempty(inhibitor->who);
1724 why = strempty(inhibitor->why);
eecd1362 1725 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
f8e2fb7b
LP
1726 uid = (dbus_uint32_t) inhibitor->uid;
1727 pid = (dbus_uint32_t) inhibitor->pid;
1728
1729 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1730 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1731 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
eecd1362 1732 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
f8e2fb7b
LP
1733 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1734 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1735 goto oom;
1736
1737 if (!dbus_message_iter_close_container(&sub, &sub2))
1738 goto oom;
1739 }
1740
1741 if (!dbus_message_iter_close_container(&iter, &sub))
1742 goto oom;
1743
1744 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1745
1746 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1747
1748 if (r < 0)
1749 return bus_send_error_reply(connection, message, &error, r);
1750
1751
98a28fef
LP
1752 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1753
1754 r = bus_manager_create_session(m, message, &reply);
688c56ff
LP
1755
1756 /* Don't delay the work on OOM here, since it might be
1757 * triggered by a low RLIMIT_NOFILE here (since we
1758 * send a dupped fd to the client), and we'd rather
1759 * see this fail quickly then be retried later */
98a28fef
LP
1760
1761 if (r < 0)
f8e2fb7b 1762 return bus_send_error_reply(connection, message, NULL, r);
98a28fef 1763
75c8e3cf
LP
1764 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1765 const char *name;
1766 Session *session;
1767
1768 if (!dbus_message_get_args(
1769 message,
1770 &error,
1771 DBUS_TYPE_STRING, &name,
1772 DBUS_TYPE_INVALID))
1773 return bus_send_error_reply(connection, message, &error, -EINVAL);
1774
1775 session = hashmap_get(m->sessions, name);
1776 if (!session)
1777 return bus_send_error_reply(connection, message, &error, -ENOENT);
1778
1779 /* We use the FIFO to detect stray sessions where the
1780 process invoking PAM dies abnormally. We need to make
1781 sure that that process is not killed if at the clean
1782 end of the session it closes the FIFO. Hence, with
1783 this call explicitly turn off the FIFO logic, so that
1784 the PAM code can finish clean up on its own */
1785 session_remove_fifo(session);
1786
1787 reply = dbus_message_new_method_return(message);
1788 if (!reply)
1789 goto oom;
1790
bef422ae
LP
1791 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1792 const char *name;
1793 Session *session;
1794
1795 if (!dbus_message_get_args(
1796 message,
1797 &error,
1798 DBUS_TYPE_STRING, &name,
1799 DBUS_TYPE_INVALID))
1800 return bus_send_error_reply(connection, message, &error, -EINVAL);
1801
1802 session = hashmap_get(m->sessions, name);
1803 if (!session)
1804 return bus_send_error_reply(connection, message, &error, -ENOENT);
1805
1806 r = session_activate(session);
1807 if (r < 0)
1808 return bus_send_error_reply(connection, message, NULL, r);
1809
1810 reply = dbus_message_new_method_return(message);
1811 if (!reply)
1812 goto oom;
1813
84c3361e
LP
1814 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1815 const char *session_name, *seat_name;
1816 Session *session;
1817 Seat *seat;
1818
1819 /* Same as ActivateSession() but refuses to work if
1820 * the seat doesn't match */
1821
1822 if (!dbus_message_get_args(
1823 message,
1824 &error,
1825 DBUS_TYPE_STRING, &session_name,
1826 DBUS_TYPE_STRING, &seat_name,
1827 DBUS_TYPE_INVALID))
1828 return bus_send_error_reply(connection, message, &error, -EINVAL);
1829
1830 session = hashmap_get(m->sessions, session_name);
1831 if (!session)
1832 return bus_send_error_reply(connection, message, &error, -ENOENT);
1833
1834 seat = hashmap_get(m->seats, seat_name);
1835 if (!seat)
1836 return bus_send_error_reply(connection, message, &error, -ENOENT);
1837
1838 if (session->seat != seat)
1839 return bus_send_error_reply(connection, message, &error, -EINVAL);
1840
1841 r = session_activate(session);
1842 if (r < 0)
1843 return bus_send_error_reply(connection, message, NULL, r);
1844
1845 reply = dbus_message_new_method_return(message);
1846 if (!reply)
1847 goto oom;
1848
88e3dc90
LP
1849 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1850 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1851 const char *name;
1852 Session *session;
1853
1854 if (!dbus_message_get_args(
1855 message,
1856 &error,
1857 DBUS_TYPE_STRING, &name,
1858 DBUS_TYPE_INVALID))
1859 return bus_send_error_reply(connection, message, &error, -EINVAL);
1860
1861 session = hashmap_get(m->sessions, name);
1862 if (!session)
7ba64386 1863 return bus_send_error_reply(connection, message, NULL, -ENOENT);
88e3dc90
LP
1864
1865 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1866 goto oom;
1867
1868 reply = dbus_message_new_method_return(message);
1869 if (!reply)
1870 goto oom;
1871
b6160029
LP
1872 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions") ||
1873 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSessions")) {
1874
1875 r = session_send_lock_all(m, streq(dbus_message_get_member(message), "LockSessions"));
7ba64386
LP
1876 if (r < 0)
1877 bus_send_error_reply(connection, message, NULL, r);
fa2b196d
LP
1878
1879 reply = dbus_message_new_method_return(message);
1880 if (!reply)
1881 goto oom;
1882
de07ab16
LP
1883 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1884 const char *swho;
1885 int32_t signo;
1886 KillWho who;
1887 const char *name;
1888 Session *session;
1889
1890 if (!dbus_message_get_args(
1891 message,
1892 &error,
1893 DBUS_TYPE_STRING, &name,
1894 DBUS_TYPE_STRING, &swho,
1895 DBUS_TYPE_INT32, &signo,
1896 DBUS_TYPE_INVALID))
1897 return bus_send_error_reply(connection, message, &error, -EINVAL);
1898
1899 if (isempty(swho))
1900 who = KILL_ALL;
1901 else {
1902 who = kill_who_from_string(swho);
1903 if (who < 0)
1904 return bus_send_error_reply(connection, message, &error, -EINVAL);
1905 }
1906
1907 if (signo <= 0 || signo >= _NSIG)
1908 return bus_send_error_reply(connection, message, &error, -EINVAL);
1909
1910 session = hashmap_get(m->sessions, name);
1911 if (!session)
1912 return bus_send_error_reply(connection, message, &error, -ENOENT);
1913
1914 r = session_kill(session, who, signo);
1915 if (r < 0)
1916 return bus_send_error_reply(connection, message, NULL, r);
1917
1918 reply = dbus_message_new_method_return(message);
1919 if (!reply)
1920 goto oom;
1921
1922 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1923 uint32_t uid;
1924 User *user;
1925 int32_t signo;
1926
1927 if (!dbus_message_get_args(
1928 message,
1929 &error,
1930 DBUS_TYPE_UINT32, &uid,
1931 DBUS_TYPE_INT32, &signo,
1932 DBUS_TYPE_INVALID))
1933 return bus_send_error_reply(connection, message, &error, -EINVAL);
1934
1935 if (signo <= 0 || signo >= _NSIG)
1936 return bus_send_error_reply(connection, message, &error, -EINVAL);
1937
1938 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1939 if (!user)
1940 return bus_send_error_reply(connection, message, &error, -ENOENT);
1941
1942 r = user_kill(user, signo);
1943 if (r < 0)
1944 return bus_send_error_reply(connection, message, NULL, r);
1945
1946 reply = dbus_message_new_method_return(message);
1947 if (!reply)
1948 goto oom;
1949
bef422ae
LP
1950 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1951 const char *name;
1952 Session *session;
1953
1954 if (!dbus_message_get_args(
1955 message,
1956 &error,
1957 DBUS_TYPE_STRING, &name,
1958 DBUS_TYPE_INVALID))
1959 return bus_send_error_reply(connection, message, &error, -EINVAL);
1960
1961 session = hashmap_get(m->sessions, name);
1962 if (!session)
1963 return bus_send_error_reply(connection, message, &error, -ENOENT);
1964
1965 r = session_stop(session);
1966 if (r < 0)
1967 return bus_send_error_reply(connection, message, NULL, r);
1968
1969 reply = dbus_message_new_method_return(message);
1970 if (!reply)
1971 goto oom;
1972
1973 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1974 uint32_t uid;
1975 User *user;
1976
1977 if (!dbus_message_get_args(
1978 message,
1979 &error,
1980 DBUS_TYPE_UINT32, &uid,
1981 DBUS_TYPE_INVALID))
1982 return bus_send_error_reply(connection, message, &error, -EINVAL);
1983
1984 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1985 if (!user)
1986 return bus_send_error_reply(connection, message, &error, -ENOENT);
1987
1988 r = user_stop(user);
1989 if (r < 0)
1990 return bus_send_error_reply(connection, message, NULL, r);
1991
1992 reply = dbus_message_new_method_return(message);
1993 if (!reply)
1994 goto oom;
1995
1996 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1997 const char *name;
1998 Seat *seat;
1999
2000 if (!dbus_message_get_args(
2001 message,
2002 &error,
2003 DBUS_TYPE_STRING, &name,
2004 DBUS_TYPE_INVALID))
2005 return bus_send_error_reply(connection, message, &error, -EINVAL);
2006
2007 seat = hashmap_get(m->seats, name);
2008 if (!seat)
2009 return bus_send_error_reply(connection, message, &error, -ENOENT);
2010
2011 r = seat_stop_sessions(seat);
2012 if (r < 0)
2013 return bus_send_error_reply(connection, message, NULL, r);
2014
2015 reply = dbus_message_new_method_return(message);
2016 if (!reply)
2017 goto oom;
2018
7f7bb946
LP
2019 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
2020 uint32_t uid;
2021 struct passwd *pw;
2022 dbus_bool_t b, interactive;
2023 char *path;
2024
2025 if (!dbus_message_get_args(
2026 message,
2027 &error,
2028 DBUS_TYPE_UINT32, &uid,
2029 DBUS_TYPE_BOOLEAN, &b,
2030 DBUS_TYPE_BOOLEAN, &interactive,
2031 DBUS_TYPE_INVALID))
2032 return bus_send_error_reply(connection, message, &error, -EINVAL);
2033
2034 errno = 0;
2035 pw = getpwuid(uid);
2036 if (!pw)
2037 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
2038
89f13440 2039 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
7f7bb946
LP
2040 if (r < 0)
2041 return bus_send_error_reply(connection, message, &error, r);
2042
d2e54fae 2043 mkdir_p_label("/var/lib/systemd", 0755);
02b16a19 2044
d2e54fae 2045 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
7f7bb946
LP
2046 if (r < 0)
2047 return bus_send_error_reply(connection, message, &error, r);
2048
2049 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
2050 if (!path)
2051 goto oom;
2052
2053 if (b) {
38f3fc7d
LP
2054 User *u;
2055
7f7bb946
LP
2056 r = touch(path);
2057 free(path);
2058
2059 if (r < 0)
2060 return bus_send_error_reply(connection, message, &error, r);
38f3fc7d
LP
2061
2062 if (manager_add_user_by_uid(m, uid, &u) >= 0)
2063 user_start(u);
2064
7f7bb946 2065 } else {
38f3fc7d
LP
2066 User *u;
2067
7f7bb946
LP
2068 r = unlink(path);
2069 free(path);
2070
2071 if (r < 0 && errno != ENOENT)
2072 return bus_send_error_reply(connection, message, &error, -errno);
38f3fc7d
LP
2073
2074 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
2075 if (u)
2076 user_add_to_gc_queue(u);
7f7bb946
LP
2077 }
2078
2079 reply = dbus_message_new_method_return(message);
2080 if (!reply)
2081 goto oom;
2082
47a26690
LP
2083 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
2084 const char *sysfs, *seat;
2085 dbus_bool_t interactive;
2086
2087 if (!dbus_message_get_args(
2088 message,
2089 &error,
2090 DBUS_TYPE_STRING, &seat,
2091 DBUS_TYPE_STRING, &sysfs,
2092 DBUS_TYPE_BOOLEAN, &interactive,
2093 DBUS_TYPE_INVALID))
2094 return bus_send_error_reply(connection, message, &error, -EINVAL);
2095
2096 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
2097 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2098
89f13440 2099 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
47a26690
LP
2100 if (r < 0)
2101 return bus_send_error_reply(connection, message, &error, r);
2102
2103 r = attach_device(m, seat, sysfs);
2104 if (r < 0)
2105 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2106
2107 reply = dbus_message_new_method_return(message);
2108 if (!reply)
2109 goto oom;
7f7bb946 2110
b668e064
LP
2111
2112 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
2113 dbus_bool_t interactive;
2114
2115 if (!dbus_message_get_args(
2116 message,
2117 &error,
2118 DBUS_TYPE_BOOLEAN, &interactive,
2119 DBUS_TYPE_INVALID))
2120 return bus_send_error_reply(connection, message, &error, -EINVAL);
2121
89f13440 2122 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
b668e064
LP
2123 if (r < 0)
2124 return bus_send_error_reply(connection, message, &error, r);
2125
2126 r = flush_devices(m);
2127 if (r < 0)
2128 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2129
2130 reply = dbus_message_new_method_return(message);
2131 if (!reply)
2132 goto oom;
2133
d889a206
LP
2134 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
2135
2136 r = bus_manager_do_shutdown_or_sleep(
2137 m, connection, message,
2138 SPECIAL_POWEROFF_TARGET,
2139 INHIBIT_SHUTDOWN,
2140 "org.freedesktop.login1.power-off",
2141 "org.freedesktop.login1.power-off-multiple-sessions",
2142 "org.freedesktop.login1.power-off-ignore-inhibit",
6524990f 2143 NULL, NULL,
d889a206 2144 &error, &reply);
89f13440
LP
2145 if (r < 0)
2146 return bus_send_error_reply(connection, message, &error, r);
d889a206
LP
2147 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
2148 r = bus_manager_do_shutdown_or_sleep(
2149 m, connection, message,
2150 SPECIAL_REBOOT_TARGET,
2151 INHIBIT_SHUTDOWN,
2152 "org.freedesktop.login1.reboot",
2153 "org.freedesktop.login1.reboot-multiple-sessions",
2154 "org.freedesktop.login1.reboot-ignore-inhibit",
6524990f 2155 NULL, NULL,
d889a206 2156 &error, &reply);
89f13440
LP
2157 if (r < 0)
2158 return bus_send_error_reply(connection, message, &error, r);
2159
d889a206
LP
2160 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2161 r = bus_manager_do_shutdown_or_sleep(
2162 m, connection, message,
2163 SPECIAL_SUSPEND_TARGET,
2164 INHIBIT_SLEEP,
2165 "org.freedesktop.login1.suspend",
2166 "org.freedesktop.login1.suspend-multiple-sessions",
2167 "org.freedesktop.login1.suspend-ignore-inhibit",
6524990f 2168 "mem", NULL,
d889a206
LP
2169 &error, &reply);
2170 if (r < 0)
2171 return bus_send_error_reply(connection, message, &error, r);
2172 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2173 r = bus_manager_do_shutdown_or_sleep(
2174 m, connection, message,
2175 SPECIAL_HIBERNATE_TARGET,
2176 INHIBIT_SLEEP,
2177 "org.freedesktop.login1.hibernate",
2178 "org.freedesktop.login1.hibernate-multiple-sessions",
2179 "org.freedesktop.login1.hibernate-ignore-inhibit",
6524990f
LP
2180 "disk", NULL,
2181 &error, &reply);
2182 if (r < 0)
2183 return bus_send_error_reply(connection, message, &error, r);
2184
2185 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "HybridSleep")) {
2186 r = bus_manager_do_shutdown_or_sleep(
2187 m, connection, message,
2188 SPECIAL_HYBRID_SLEEP_TARGET,
2189 INHIBIT_SLEEP,
2190 "org.freedesktop.login1.hibernate",
2191 "org.freedesktop.login1.hibernate-multiple-sessions",
2192 "org.freedesktop.login1.hibernate-ignore-inhibit",
2193 "disk", "suspend",
d889a206
LP
2194 &error, &reply);
2195 if (r < 0)
2196 return bus_send_error_reply(connection, message, &error, r);
f8e2fb7b 2197
d889a206 2198 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
f8e2fb7b 2199
d889a206
LP
2200 r = bus_manager_can_shutdown_or_sleep(
2201 m, connection, message,
2202 INHIBIT_SHUTDOWN,
2203 "org.freedesktop.login1.power-off",
2204 "org.freedesktop.login1.power-off-multiple-sessions",
2205 "org.freedesktop.login1.power-off-ignore-inhibit",
6524990f 2206 NULL, NULL,
d889a206
LP
2207 &error, &reply);
2208 if (r < 0)
2209 return bus_send_error_reply(connection, message, &error, r);
2210 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2211 r = bus_manager_can_shutdown_or_sleep(
2212 m, connection, message,
2213 INHIBIT_SHUTDOWN,
2214 "org.freedesktop.login1.reboot",
2215 "org.freedesktop.login1.reboot-multiple-sessions",
2216 "org.freedesktop.login1.reboot-ignore-inhibit",
6524990f 2217 NULL, NULL,
d889a206
LP
2218 &error, &reply);
2219 if (r < 0)
2220 return bus_send_error_reply(connection, message, &error, r);
89f13440 2221
d889a206
LP
2222 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2223 r = bus_manager_can_shutdown_or_sleep(
2224 m, connection, message,
2225 INHIBIT_SLEEP,
2226 "org.freedesktop.login1.suspend",
2227 "org.freedesktop.login1.suspend-multiple-sessions",
2228 "org.freedesktop.login1.suspend-ignore-inhibit",
6524990f 2229 "mem", NULL,
d889a206
LP
2230 &error, &reply);
2231 if (r < 0)
2232 return bus_send_error_reply(connection, message, &error, r);
89f13440 2233
d889a206
LP
2234 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2235 r = bus_manager_can_shutdown_or_sleep(
2236 m, connection, message,
2237 INHIBIT_SLEEP,
2238 "org.freedesktop.login1.hibernate",
2239 "org.freedesktop.login1.hibernate-multiple-sessions",
2240 "org.freedesktop.login1.hibernate-ignore-inhibit",
6524990f
LP
2241 "disk", NULL,
2242 &error, &reply);
2243 if (r < 0)
2244 return bus_send_error_reply(connection, message, &error, r);
2245
2246 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHybridSleep")) {
2247 r = bus_manager_can_shutdown_or_sleep(
2248 m, connection, message,
2249 INHIBIT_SLEEP,
2250 "org.freedesktop.login1.hibernate",
2251 "org.freedesktop.login1.hibernate-multiple-sessions",
2252 "org.freedesktop.login1.hibernate-ignore-inhibit",
2253 "disk", "suspend",
d889a206
LP
2254 &error, &reply);
2255 if (r < 0)
2256 return bus_send_error_reply(connection, message, &error, r);
89f13440 2257
bef422ae 2258 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
3f49d45a
LP
2259 char *introspection = NULL;
2260 FILE *f;
2261 Iterator i;
2262 Session *session;
2263 Seat *seat;
2264 User *user;
2265 size_t size;
2266 char *p;
2267
2268 if (!(reply = dbus_message_new_method_return(message)))
2269 goto oom;
2270
2271 /* We roll our own introspection code here, instead of
2272 * relying on bus_default_message_handler() because we
2273 * need to generate our introspection string
2274 * dynamically. */
2275
2276 if (!(f = open_memstream(&introspection, &size)))
2277 goto oom;
2278
2279 fputs(INTROSPECTION_BEGIN, f);
2280
2281 HASHMAP_FOREACH(seat, m->seats, i) {
2282 p = bus_path_escape(seat->id);
2283
2284 if (p) {
2285 fprintf(f, "<node name=\"seat/%s\"/>", p);
2286 free(p);
2287 }
2288 }
2289
2290 HASHMAP_FOREACH(user, m->users, i)
2291 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2292
2293 HASHMAP_FOREACH(session, m->sessions, i) {
2294 p = bus_path_escape(session->id);
2295
2296 if (p) {
2297 fprintf(f, "<node name=\"session/%s\"/>", p);
2298 free(p);
2299 }
2300 }
2301
2302 fputs(INTROSPECTION_END, f);
2303
2304 if (ferror(f)) {
2305 fclose(f);
2306 free(introspection);
2307 goto oom;
2308 }
2309
2310 fclose(f);
2311
2312 if (!introspection)
2313 goto oom;
2314
2315 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2316 free(introspection);
2317 goto oom;
2318 }
2319
2320 free(introspection);
d200735e
MS
2321 } else {
2322 const BusBoundProperties bps[] = {
2323 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2324 { NULL, }
2325 };
2326 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2327 }
3f49d45a
LP
2328
2329 if (reply) {
1a37b9b9
CW
2330 if (!bus_maybe_send_reply(connection, message, reply))
2331 goto oom;
3f49d45a
LP
2332 }
2333
2334 return DBUS_HANDLER_RESULT_HANDLED;
2335
2336oom:
3f49d45a
LP
2337 dbus_error_free(&error);
2338
2339 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2340}
2341
2342const DBusObjectPathVTable bus_manager_vtable = {
2343 .message_function = manager_message_handler
2344};
9418f147 2345
1713813d
LP
2346DBusHandlerResult bus_message_filter(
2347 DBusConnection *connection,
2348 DBusMessage *message,
2349 void *userdata) {
2350
2351 Manager *m = userdata;
2352 DBusError error;
2353
2354 assert(m);
2355 assert(connection);
2356 assert(message);
2357
2358 dbus_error_init(&error);
2359
2360 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
2361 const char *cgroup;
2362
2363 if (!dbus_message_get_args(message, &error,
2364 DBUS_TYPE_STRING, &cgroup,
2365 DBUS_TYPE_INVALID))
2366 log_error("Failed to parse Released message: %s", bus_error_message(&error));
2367 else
2368 manager_cgroup_notify_empty(m, cgroup);
af9792ac
LP
2369
2370 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
2371 uint32_t id;
2372 const char *path, *result, *unit;
2373
2374 if (!dbus_message_get_args(message, &error,
2375 DBUS_TYPE_UINT32, &id,
2376 DBUS_TYPE_OBJECT_PATH, &path,
2377 DBUS_TYPE_STRING, &unit,
2378 DBUS_TYPE_STRING, &result,
2379 DBUS_TYPE_INVALID))
2380 log_error("Failed to parse JobRemoved message: %s", bus_error_message(&error));
314b4b0a 2381
af9792ac 2382 else if (m->action_job && streq(m->action_job, path)) {
ee17c928 2383
314b4b0a 2384 log_info("Operation finished.");
ee17c928 2385
314b4b0a
LP
2386 /* Tell people that they now may take a lock again */
2387 send_prepare_for(m, m->action_what, false);
2388
2389 free(m->action_job);
2390 m->action_job = NULL;
2391 m->action_unit = NULL;
2392 m->action_what = 0;
af9792ac 2393 }
1713813d
LP
2394 }
2395
2396 dbus_error_free(&error);
2397
2398 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2399}
2400
9418f147 2401int manager_send_changed(Manager *manager, const char *properties) {
ce0fc5f5 2402 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
9418f147
LP
2403
2404 assert(manager);
2405
4654e558
ZJS
2406 m = bus_properties_changed_new("/org/freedesktop/login1",
2407 "org.freedesktop.login1.Manager",
2408 properties);
9418f147 2409 if (!m)
4654e558 2410 return -ENOMEM;
9418f147
LP
2411
2412 if (!dbus_connection_send(manager->bus, m, NULL))
4654e558 2413 return -ENOMEM;
9418f147 2414
4654e558 2415 return 0;
9418f147 2416}
eecd1362 2417
d889a206 2418int manager_dispatch_delayed(Manager *manager) {
eecd1362 2419 DBusError error;
eecd1362
LP
2420 int r;
2421
2422 assert(manager);
2423
314b4b0a 2424 if (!manager->action_unit || manager->action_job)
eecd1362
LP
2425 return 0;
2426
2427 /* Continue delay? */
314b4b0a 2428 if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0)) {
eecd1362 2429
314b4b0a
LP
2430 if (manager->action_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC))
2431 return 0;
af9792ac 2432
314b4b0a
LP
2433 log_info("Delay lock is active but inhibitor timeout is reached.");
2434 }
eecd1362 2435
314b4b0a 2436 /* Actually do the operation */
eecd1362 2437 dbus_error_init(&error);
314b4b0a 2438 r = execute_shutdown_or_sleep(manager, manager->action_what, manager->action_unit, &error);
eecd1362 2439 if (r < 0) {
d889a206
LP
2440 log_warning("Failed to send delayed message: %s", bus_error_message_or_strerror(&error, -r));
2441 dbus_error_free(&error);
314b4b0a
LP
2442
2443 manager->action_unit = NULL;
2444 manager->action_what = 0;
eecd1362
LP
2445 return r;
2446 }
2447
eecd1362
LP
2448 return 1;
2449}