]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-dbus.c
Fix spelling errors using 'codespell' tool
[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" \
ab06eef8 69 " <arg name=\"service\" 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);
e2acb67b
LP
356 if (isempty(type))
357 t = _SESSION_TYPE_INVALID;
358 else {
359 t = session_type_from_string(type);
360 if (t < 0)
361 return -EINVAL;
362 }
98a28fef 363
e2acb67b 364 if (!dbus_message_iter_next(&iter) ||
98a28fef
LP
365 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
366 return -EINVAL;
367
55efac6c
LP
368 dbus_message_iter_get_basic(&iter, &class);
369 if (isempty(class))
e2acb67b
LP
370 c = _SESSION_CLASS_INVALID;
371 else {
55efac6c 372 c = session_class_from_string(class);
e2acb67b
LP
373 if (c < 0)
374 return -EINVAL;
375 }
55efac6c 376
e2acb67b 377 if (!dbus_message_iter_next(&iter) ||
55efac6c
LP
378 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
379 return -EINVAL;
380
954449b8 381 dbus_message_iter_get_basic(&iter, &cseat);
98a28fef 382
954449b8
LP
383 if (isempty(cseat))
384 seat = NULL;
98a28fef 385 else {
954449b8
LP
386 seat = hashmap_get(m->seats, cseat);
387 if (!seat)
98a28fef
LP
388 return -ENOENT;
389 }
390
4d6d6518
LP
391 if (!dbus_message_iter_next(&iter) ||
392 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
393 return -EINVAL;
394
395 dbus_message_iter_get_basic(&iter, &vtnr);
396
98a28fef
LP
397 if (!dbus_message_iter_next(&iter) ||
398 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
399 return -EINVAL;
400
401 dbus_message_iter_get_basic(&iter, &tty);
402
403 if (tty_is_vc(tty)) {
4d6d6518 404 int v;
98a28fef 405
954449b8
LP
406 if (!seat)
407 seat = m->vtconsole;
408 else if (seat != m->vtconsole)
98a28fef
LP
409 return -EINVAL;
410
4d6d6518
LP
411 v = vtnr_from_tty(tty);
412
413 if (v <= 0)
414 return v < 0 ? v : -EINVAL;
98a28fef
LP
415
416 if (vtnr <= 0)
4d6d6518
LP
417 vtnr = (uint32_t) v;
418 else if (vtnr != (uint32_t) v)
419 return -EINVAL;
d1122ad5
LP
420 } else if (tty_is_console(tty)) {
421
954449b8
LP
422 if (!seat)
423 seat = m->vtconsole;
424 else if (seat != m->vtconsole)
d1122ad5
LP
425 return -EINVAL;
426
427 if (vtnr != 0)
428 return -EINVAL;
978cf3c7 429 }
98a28fef 430
954449b8
LP
431 if (seat) {
432 if (seat_can_multi_session(seat)) {
d1122ad5 433 if (vtnr > 63)
4d6d6518
LP
434 return -EINVAL;
435 } else {
d1122ad5 436 if (vtnr != 0)
4d6d6518
LP
437 return -EINVAL;
438 }
439 }
440
98a28fef
LP
441 if (!dbus_message_iter_next(&iter) ||
442 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
443 return -EINVAL;
444
445 dbus_message_iter_get_basic(&iter, &display);
446
447 if (!dbus_message_iter_next(&iter) ||
448 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
449 return -EINVAL;
450
e2acb67b
LP
451 if (t == _SESSION_TYPE_INVALID) {
452 if (!isempty(display))
453 t = SESSION_X11;
454 else if (!isempty(tty))
455 t = SESSION_TTY;
456 else
457 t = SESSION_UNSPECIFIED;
458 }
459
460 if (c == _SESSION_CLASS_INVALID) {
461 if (!isempty(display) || !isempty(tty))
462 c = SESSION_USER;
463 else
464 c = SESSION_BACKGROUND;
465 }
466
98a28fef
LP
467 dbus_message_iter_get_basic(&iter, &remote);
468
469 if (!dbus_message_iter_next(&iter) ||
470 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
471 return -EINVAL;
472
473 dbus_message_iter_get_basic(&iter, &remote_user);
474
475 if (!dbus_message_iter_next(&iter) ||
476 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
477 return -EINVAL;
478
479 dbus_message_iter_get_basic(&iter, &remote_host);
480
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)
484 return -EINVAL;
485
486 r = bus_parse_strv_iter(&iter, &controllers);
487 if (r < 0)
488 return -EINVAL;
489
25d93491
LP
490 if (strv_contains(controllers, "systemd") ||
491 !dbus_message_iter_next(&iter) ||
98a28fef
LP
492 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
493 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) {
494 r = -EINVAL;
495 goto fail;
496 }
497
498 r = bus_parse_strv_iter(&iter, &reset_controllers);
499 if (r < 0)
500 goto fail;
501
25d93491
LP
502 if (strv_contains(reset_controllers, "systemd") ||
503 !dbus_message_iter_next(&iter) ||
98a28fef
LP
504 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) {
505 r = -EINVAL;
506 goto fail;
507 }
508
509 dbus_message_iter_get_basic(&iter, &kill_processes);
510
954449b8 511 r = cg_pid_get_cgroup(leader, NULL, &cgroup);
98a28fef
LP
512 if (r < 0)
513 goto fail;
514
954449b8
LP
515 r = manager_get_session_by_cgroup(m, cgroup, &session);
516 if (r < 0)
517 goto fail;
98a28fef 518
954449b8
LP
519 if (session) {
520 fifo_fd = session_create_fifo(session);
521 if (fifo_fd < 0) {
522 r = fifo_fd;
07714753
LP
523 goto fail;
524 }
98a28fef 525
954449b8
LP
526 /* Session already exists, client is probably
527 * something like "su" which changes uid but
528 * is still the same audit session */
21c390cc 529
954449b8
LP
530 reply = dbus_message_new_method_return(message);
531 if (!reply) {
532 r = -ENOMEM;
533 goto fail;
534 }
21c390cc 535
954449b8
LP
536 p = session_bus_path(session);
537 if (!p) {
538 r = -ENOMEM;
539 goto fail;
540 }
932e3ee7 541
954449b8
LP
542 cseat = session->seat ? session->seat->id : "";
543 vtnr = session->vtnr;
544 exists = true;
545
546 b = dbus_message_append_args(
547 reply,
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,
555 DBUS_TYPE_INVALID);
556 if (!b) {
557 r = -ENOMEM;
558 goto fail;
559 }
21c390cc 560
954449b8 561 *_reply = reply;
ce0fc5f5 562 reply = NULL;
21c390cc 563
954449b8
LP
564 return 0;
565 }
21c390cc 566
954449b8
LP
567 audit_session_from_pid(leader, &audit_id);
568 if (audit_id > 0) {
569 /* Keep our session IDs and the audit session IDs in sync */
21c390cc 570
954449b8
LP
571 if (asprintf(&id, "%lu", (unsigned long) audit_id) < 0) {
572 r = -ENOMEM;
573 goto fail;
574 }
21c390cc 575
954449b8
LP
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
579 * ID */
580 if (hashmap_get(m->sessions, id)) {
581 audit_id = 0;
8ea913b2 582
954449b8
LP
583 free(id);
584 id = NULL;
07714753 585 }
954449b8 586 }
07714753 587
954449b8 588 if (!id) {
07714753
LP
589 do {
590 free(id);
f8e2fb7b 591 id = NULL;
07714753 592
f8e2fb7b 593 if (asprintf(&id, "c%lu", ++m->session_counter) < 0) {
07714753
LP
594 r = -ENOMEM;
595 goto fail;
596 }
597
598 } while (hashmap_get(m->sessions, id));
98a28fef
LP
599 }
600
954449b8
LP
601 r = manager_add_user_by_uid(m, uid, &user);
602 if (r < 0)
603 goto fail;
604
98a28fef 605 r = manager_add_session(m, user, id, &session);
98a28fef
LP
606 if (r < 0)
607 goto fail;
608
609 session->leader = leader;
610 session->audit_id = audit_id;
611 session->type = t;
55efac6c 612 session->class = c;
98a28fef
LP
613 session->remote = remote;
614 session->controllers = controllers;
615 session->reset_controllers = reset_controllers;
616 session->kill_processes = kill_processes;
617 session->vtnr = vtnr;
618
619 controllers = reset_controllers = NULL;
620
621 if (!isempty(tty)) {
622 session->tty = strdup(tty);
623 if (!session->tty) {
624 r = -ENOMEM;
625 goto fail;
626 }
627 }
628
629 if (!isempty(display)) {
630 session->display = strdup(display);
631 if (!session->display) {
632 r = -ENOMEM;
633 goto fail;
634 }
635 }
636
637 if (!isempty(remote_user)) {
638 session->remote_user = strdup(remote_user);
639 if (!session->remote_user) {
640 r = -ENOMEM;
641 goto fail;
642 }
643 }
644
645 if (!isempty(remote_host)) {
646 session->remote_host = strdup(remote_host);
647 if (!session->remote_host) {
648 r = -ENOMEM;
649 goto fail;
650 }
651 }
652
653 if (!isempty(service)) {
654 session->service = strdup(service);
655 if (!session->service) {
656 r = -ENOMEM;
657 goto fail;
658 }
659 }
660
932e3ee7
LP
661 fifo_fd = session_create_fifo(session);
662 if (fifo_fd < 0) {
663 r = fifo_fd;
98a28fef
LP
664 goto fail;
665 }
666
954449b8
LP
667 if (seat) {
668 r = seat_attach_session(seat, session);
98a28fef
LP
669 if (r < 0)
670 goto fail;
671 }
672
673 r = session_start(session);
674 if (r < 0)
675 goto fail;
676
677 reply = dbus_message_new_method_return(message);
678 if (!reply) {
679 r = -ENOMEM;
680 goto fail;
681 }
682
683 p = session_bus_path(session);
684 if (!p) {
685 r = -ENOMEM;
686 goto fail;
687 }
688
954449b8 689 cseat = seat ? seat->id : "";
77085881 690 exists = false;
98a28fef
LP
691 b = dbus_message_append_args(
692 reply,
693 DBUS_TYPE_STRING, &session->id,
694 DBUS_TYPE_OBJECT_PATH, &p,
695 DBUS_TYPE_STRING, &session->user->runtime_path,
932e3ee7 696 DBUS_TYPE_UNIX_FD, &fifo_fd,
954449b8 697 DBUS_TYPE_STRING, &cseat,
bbc73283 698 DBUS_TYPE_UINT32, &vtnr,
77085881 699 DBUS_TYPE_BOOLEAN, &exists,
98a28fef 700 DBUS_TYPE_INVALID);
98a28fef
LP
701
702 if (!b) {
703 r = -ENOMEM;
704 goto fail;
705 }
706
98a28fef 707 *_reply = reply;
ce0fc5f5 708 reply = NULL;
98a28fef
LP
709
710 return 0;
711
712fail:
98a28fef
LP
713 if (session)
714 session_add_to_gc_queue(session);
715
716 if (user)
717 user_add_to_gc_queue(user);
718
98a28fef
LP
719 return r;
720}
721
314b4b0a
LP
722static int bus_manager_inhibit(
723 Manager *m,
724 DBusConnection *connection,
725 DBusMessage *message,
726 DBusError *error,
727 DBusMessage **_reply) {
728
f8e2fb7b
LP
729 Inhibitor *i = NULL;
730 char *id = NULL;
eecd1362 731 const char *who, *why, *what, *mode;
f8e2fb7b
LP
732 pid_t pid;
733 InhibitWhat w;
eecd1362 734 InhibitMode mm;
f8e2fb7b
LP
735 unsigned long ul;
736 int r, fifo_fd = -1;
ce0fc5f5 737 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
f8e2fb7b
LP
738
739 assert(m);
740 assert(connection);
741 assert(message);
742 assert(error);
743 assert(_reply);
744
745 if (!dbus_message_get_args(
746 message,
747 error,
748 DBUS_TYPE_STRING, &what,
749 DBUS_TYPE_STRING, &who,
750 DBUS_TYPE_STRING, &why,
eecd1362 751 DBUS_TYPE_STRING, &mode,
f8e2fb7b
LP
752 DBUS_TYPE_INVALID)) {
753 r = -EIO;
754 goto fail;
755 }
756
757 w = inhibit_what_from_string(what);
758 if (w <= 0) {
759 r = -EINVAL;
760 goto fail;
761 }
762
eecd1362
LP
763 mm = inhibit_mode_from_string(mode);
764 if (mm < 0) {
765 r = -EINVAL;
766 goto fail;
767 }
768
beaafb2e
LP
769 /* Delay is only supported for shutdown/sleep */
770 if (mm == INHIBIT_DELAY && (w & ~(INHIBIT_SHUTDOWN|INHIBIT_SLEEP))) {
771 r = -EINVAL;
772 goto fail;
773 }
774
314b4b0a
LP
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) {
780 r = -EALREADY;
781 goto fail;
782 }
783
eecd1362 784 r = verify_polkit(connection, message,
8e7fd6ad
LP
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",
b14eda96 792 false, NULL, error);
f8e2fb7b
LP
793 if (r < 0)
794 goto fail;
795
796 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
797 if (ul == (unsigned long) -1) {
798 r = -EIO;
799 goto fail;
800 }
801
802 pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
803 if (pid <= 0) {
804 r = -EIO;
805 goto fail;
806 }
807
808 do {
809 free(id);
810 id = NULL;
811
812 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
813 r = -ENOMEM;
814 goto fail;
815 }
816 } while (hashmap_get(m->inhibitors, id));
817
818 r = manager_add_inhibitor(m, id, &i);
819 free(id);
820
821 if (r < 0)
822 goto fail;
823
824 i->what = w;
eecd1362 825 i->mode = mm;
f8e2fb7b
LP
826 i->pid = pid;
827 i->uid = (uid_t) ul;
828 i->why = strdup(why);
829 i->who = strdup(who);
830
831 if (!i->why || !i->who) {
832 r = -ENOMEM;
833 goto fail;
834 }
835
836 fifo_fd = inhibitor_create_fifo(i);
837 if (fifo_fd < 0) {
838 r = fifo_fd;
839 goto fail;
840 }
841
842 reply = dbus_message_new_method_return(message);
843 if (!reply) {
844 r = -ENOMEM;
845 goto fail;
846 }
847
848 if (!dbus_message_append_args(
849 reply,
850 DBUS_TYPE_UNIX_FD, &fifo_fd,
851 DBUS_TYPE_INVALID)) {
852 r = -ENOMEM;
853 goto fail;
854 }
855
856 close_nointr_nofail(fifo_fd);
857 *_reply = reply;
ce0fc5f5 858 reply = NULL;
f8e2fb7b
LP
859
860 inhibitor_start(i);
861
862 return 0;
863
864fail:
865 if (i)
866 inhibitor_free(i);
867
868 if (fifo_fd >= 0)
869 close_nointr_nofail(fifo_fd);
870
f8e2fb7b
LP
871 return r;
872}
873
2eb916cd 874static int trigger_device(Manager *m, struct udev_device *d) {
b668e064
LP
875 struct udev_enumerate *e;
876 struct udev_list_entry *first, *item;
877 int r;
878
879 assert(m);
880
881 e = udev_enumerate_new(m->udev);
882 if (!e) {
883 r = -ENOMEM;
884 goto finish;
885 }
886
2eb916cd
LP
887 if (d) {
888 if (udev_enumerate_add_match_parent(e, d) < 0) {
889 r = -EIO;
890 goto finish;
891 }
892 }
893
b668e064
LP
894 if (udev_enumerate_scan_devices(e) < 0) {
895 r = -EIO;
896 goto finish;
897 }
898
899 first = udev_enumerate_get_list_entry(e);
900 udev_list_entry_foreach(item, first) {
901 char *t;
902 const char *p;
903
904 p = udev_list_entry_get_name(item);
905
b668e064
LP
906 t = strappend(p, "/uevent");
907 if (!t) {
908 r = -ENOMEM;
909 goto finish;
910 }
911
574d5f2d 912 write_string_file(t, "change");
b668e064
LP
913 free(t);
914 }
915
916 r = 0;
917
918finish:
919 if (e)
920 udev_enumerate_unref(e);
921
922 return r;
923}
924
47a26690
LP
925static int attach_device(Manager *m, const char *seat, const char *sysfs) {
926 struct udev_device *d;
4654e558 927 char _cleanup_free_ *rule = NULL, *file = NULL;
c28fa3d3 928 const char *id_for_seat;
47a26690
LP
929 int r;
930
931 assert(m);
932 assert(seat);
933 assert(sysfs);
934
935 d = udev_device_new_from_syspath(m->udev, sysfs);
936 if (!d)
937 return -ENODEV;
938
309c2a2c 939 if (!udev_device_has_tag(d, "seat")) {
47a26690
LP
940 r = -ENODEV;
941 goto finish;
942 }
943
c28fa3d3
LP
944 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
945 if (!id_for_seat) {
47a26690
LP
946 r = -ENODEV;
947 goto finish;
948 }
949
c28fa3d3 950 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
47a26690
LP
951 r = -ENOMEM;
952 goto finish;
953 }
954
c28fa3d3 955 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
47a26690
LP
956 r = -ENOMEM;
957 goto finish;
958 }
959
d2e54fae 960 mkdir_p_label("/etc/udev/rules.d", 0755);
a5c32cff 961 label_init("/etc");
574d5f2d 962 r = write_string_file_atomic_label(file, rule);
a0a0c7f1
LP
963 if (r < 0)
964 goto finish;
965
2eb916cd 966 r = trigger_device(m, d);
47a26690
LP
967
968finish:
47a26690
LP
969 if (d)
970 udev_device_unref(d);
971
972 return r;
973}
974
b668e064 975static int flush_devices(Manager *m) {
4654e558 976 DIR _cleanup_closedir_ *d;
b668e064
LP
977
978 assert(m);
979
980 d = opendir("/etc/udev/rules.d");
981 if (!d) {
982 if (errno != ENOENT)
983 log_warning("Failed to open /etc/udev/rules.d: %m");
984 } else {
985 struct dirent *de;
986
987 while ((de = readdir(d))) {
988
989 if (!dirent_is_file(de))
990 continue;
991
992 if (!startswith(de->d_name, "72-seat-"))
993 continue;
994
995 if (!endswith(de->d_name, ".rules"))
996 continue;
997
998 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
999 log_warning("Failed to unlink %s: %m", de->d_name);
1000 }
b668e064
LP
1001 }
1002
1003 return trigger_device(m, NULL);
1004}
1005
89f13440 1006static int have_multiple_sessions(
89f13440 1007 Manager *m,
409133be 1008 uid_t uid) {
89f13440 1009
2154761f
MS
1010 Session *session;
1011 Iterator i;
89f13440
LP
1012
1013 assert(m);
1014
1ca04b87
LP
1015 /* Check for other users' sessions. Greeter sessions do not
1016 * count, and non-login sessions do not count either. */
2154761f 1017 HASHMAP_FOREACH(session, m->sessions, i)
1ca04b87 1018 if (session->class == SESSION_USER &&
1ca04b87 1019 session->user->uid != uid)
2154761f 1020 return true;
89f13440
LP
1021
1022 return false;
1023}
1024
314b4b0a
LP
1025static int bus_manager_log_shutdown(
1026 Manager *m,
1027 InhibitWhat w,
1028 const char *unit_name) {
1029
1030 const char *p, *q;
1031
1032 assert(m);
1033 assert(unit_name);
1034
1035 if (w != INHIBIT_SHUTDOWN)
1036 return 0;
1037
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";
1050 } else {
1051 p = "MESSAGE=System is shutting down.";
1052 q = NULL;
1053 }
1054
1055 return log_struct(LOG_NOTICE, MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
1056 p,
1057 q, NULL);
1058}
1059
1060static int execute_shutdown_or_sleep(
1061 Manager *m,
1062 InhibitWhat w,
1063 const char *unit_name,
1064 DBusError *error) {
1065
af9792ac 1066 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
b85bddda 1067 const char *mode = "replace-irreversibly", *p;
af9792ac
LP
1068 int r;
1069 char *c;
eecd1362 1070
af9792ac 1071 assert(m);
314b4b0a
LP
1072 assert(w >= 0);
1073 assert(w < _INHIBIT_WHAT_MAX);
d889a206 1074 assert(unit_name);
eecd1362 1075
314b4b0a
LP
1076 bus_manager_log_shutdown(m, w, unit_name);
1077
af9792ac
LP
1078 r = bus_method_call_with_reply(
1079 m->bus,
eecd1362
LP
1080 "org.freedesktop.systemd1",
1081 "/org/freedesktop/systemd1",
1082 "org.freedesktop.systemd1.Manager",
b9c26b41 1083 "StartUnit",
af9792ac
LP
1084 &reply,
1085 error,
b9c26b41
SP
1086 DBUS_TYPE_STRING, &unit_name,
1087 DBUS_TYPE_STRING, &mode,
1088 DBUS_TYPE_INVALID);
af9792ac
LP
1089 if (r < 0)
1090 return r;
1091
1092 if (!dbus_message_get_args(
1093 reply,
1094 error,
1095 DBUS_TYPE_OBJECT_PATH, &p,
1096 DBUS_TYPE_INVALID))
1097 return -EINVAL;
1098
1099 c = strdup(p);
1100 if (!c)
1101 return -ENOMEM;
1102
314b4b0a 1103 m->action_unit = unit_name;
af9792ac
LP
1104 free(m->action_job);
1105 m->action_job = c;
314b4b0a 1106 m->action_what = w;
af9792ac
LP
1107
1108 return 0;
eecd1362
LP
1109}
1110
314b4b0a
LP
1111static int delay_shutdown_or_sleep(
1112 Manager *m,
1113 InhibitWhat w,
1114 const char *unit_name) {
eecd1362 1115
eecd1362 1116 assert(m);
d889a206
LP
1117 assert(w >= 0);
1118 assert(w < _INHIBIT_WHAT_MAX);
314b4b0a 1119 assert(unit_name);
eecd1362 1120
314b4b0a
LP
1121 m->action_timestamp = now(CLOCK_MONOTONIC);
1122 m->action_unit = unit_name;
1123 m->action_what = w;
d889a206
LP
1124
1125 return 0;
1126}
1127
1128static int bus_manager_can_shutdown_or_sleep(
1129 Manager *m,
1130 DBusConnection *connection,
1131 DBusMessage *message,
1132 InhibitWhat w,
1133 const char *action,
1134 const char *action_multiple_sessions,
1135 const char *action_ignore_inhibit,
1136 const char *sleep_type,
6524990f 1137 const char *sleep_disk_type,
d889a206
LP
1138 DBusError *error,
1139 DBusMessage **_reply) {
1140
1141 bool multiple_sessions, challenge, blocked, b;
1142 const char *result;
ce0fc5f5 1143 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
d889a206 1144 int r;
409133be 1145 unsigned long ul;
d889a206
LP
1146
1147 assert(m);
1148 assert(connection);
1149 assert(message);
1150 assert(w >= 0);
1151 assert(w <= _INHIBIT_WHAT_MAX);
1152 assert(action);
1153 assert(action_multiple_sessions);
1154 assert(action_ignore_inhibit);
1155 assert(error);
1156 assert(_reply);
1157
1158 if (sleep_type) {
1159 r = can_sleep(sleep_type);
1160 if (r < 0)
1161 return r;
1162
398f7c88
MC
1163 if (r == 0) {
1164 result = "na";
1165 goto finish;
1166 }
d889a206
LP
1167 }
1168
6524990f
LP
1169 if (sleep_disk_type) {
1170 r = can_sleep_disk(sleep_disk_type);
1171 if (r < 0)
1172 return r;
1173
1174 if (r == 0) {
1175 result = "na";
1176 goto finish;
1177 }
1178 }
1179
409133be
LP
1180 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1181 if (ul == (unsigned long) -1)
1182 return -EIO;
1183
1184 r = have_multiple_sessions(m, (uid_t) ul);
d889a206
LP
1185 if (r < 0)
1186 return r;
1187
1188 multiple_sessions = r > 0;
409133be 1189 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
d889a206
LP
1190
1191 if (multiple_sessions) {
1192 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1193 if (r < 0)
1194 return r;
1195
1196 if (r > 0)
1197 result = "yes";
d5a745df
LP
1198 else if (challenge)
1199 result = "challenge";
1200 else
1201 result = "no";
1202 }
d889a206
LP
1203
1204 if (blocked) {
1205 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1206 if (r < 0)
1207 return r;
1208
1209 if (r > 0 && !result)
1210 result = "yes";
1211 else if (challenge && (!result || streq(result, "yes")))
1212 result = "challenge";
1213 else
1214 result = "no";
1215 }
1216
1217 if (!multiple_sessions && !blocked) {
1218 /* If neither inhibit nor multiple sessions
1219 * apply then just check the normal policy */
1220
1221 r = verify_polkit(connection, message, action, false, &challenge, error);
1222 if (r < 0)
1223 return r;
1224
1225 if (r > 0)
1226 result = "yes";
1227 else if (challenge)
1228 result = "challenge";
1229 else
1230 result = "no";
1231 }
1232
1233finish:
1234 reply = dbus_message_new_method_return(message);
1235 if (!reply)
1236 return -ENOMEM;
1237
1238 b = dbus_message_append_args(
1239 reply,
1240 DBUS_TYPE_STRING, &result,
1241 DBUS_TYPE_INVALID);
4654e558 1242 if (!b)
d889a206 1243 return -ENOMEM;
d889a206
LP
1244
1245 *_reply = reply;
ce0fc5f5 1246 reply = NULL;
d889a206
LP
1247 return 0;
1248}
1249
314b4b0a
LP
1250static 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"
1254 };
877d54e9 1255
314b4b0a
LP
1256 dbus_bool_t active = _active;
1257 _cleanup_dbus_message_unref_ DBusMessage *message = NULL;
877d54e9
LP
1258
1259 assert(m);
314b4b0a
LP
1260 assert(w >= 0);
1261 assert(w < _INHIBIT_WHAT_MAX);
1262 assert(signal_name[w]);
877d54e9 1263
314b4b0a
LP
1264 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1265 if (!message)
1266 return -ENOMEM;
877d54e9 1267
314b4b0a
LP
1268 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1269 !dbus_connection_send(m->bus, message, NULL))
1270 return -ENOMEM;
877d54e9 1271
314b4b0a 1272 return 0;
877d54e9
LP
1273}
1274
069cfc85
LP
1275int bus_manager_shutdown_or_sleep_now_or_later(
1276 Manager *m,
1277 const char *unit_name,
1278 InhibitWhat w,
1279 DBusError *error) {
1280
1281 bool delayed;
1282 int r;
1283
1284 assert(m);
1285 assert(unit_name);
1286 assert(w >= 0);
1287 assert(w <= _INHIBIT_WHAT_MAX);
af9792ac 1288 assert(!m->action_job);
069cfc85 1289
314b4b0a
LP
1290 /* Tell everybody to prepare for shutdown/sleep */
1291 send_prepare_for(m, w, true);
1292
069cfc85
LP
1293 delayed =
1294 m->inhibit_delay_max > 0 &&
409133be 1295 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0);
069cfc85
LP
1296
1297 if (delayed)
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);
314b4b0a 1301 else
069cfc85
LP
1302 /* Shutdown is not delayed, execute it
1303 * immediately */
314b4b0a 1304 r = execute_shutdown_or_sleep(m, w, unit_name, error);
069cfc85
LP
1305
1306 return r;
1307}
1308
d889a206
LP
1309static int bus_manager_do_shutdown_or_sleep(
1310 Manager *m,
1311 DBusConnection *connection,
1312 DBusMessage *message,
1313 const char *unit_name,
1314 InhibitWhat w,
1315 const char *action,
1316 const char *action_multiple_sessions,
1317 const char *action_ignore_inhibit,
1318 const char *sleep_type,
6524990f 1319 const char *sleep_disk_type,
d889a206
LP
1320 DBusError *error,
1321 DBusMessage **_reply) {
1322
1323 dbus_bool_t interactive;
069cfc85 1324 bool multiple_sessions, blocked;
d889a206
LP
1325 DBusMessage *reply = NULL;
1326 int r;
409133be 1327 unsigned long ul;
d889a206
LP
1328
1329 assert(m);
1330 assert(connection);
1331 assert(message);
1332 assert(unit_name);
1333 assert(w >= 0);
1334 assert(w <= _INHIBIT_WHAT_MAX);
1335 assert(action);
1336 assert(action_multiple_sessions);
1337 assert(action_ignore_inhibit);
1338 assert(error);
1339 assert(_reply);
1340
314b4b0a
LP
1341 /* Don't allow multiple jobs being executed at the same time */
1342 if (m->action_what)
af9792ac
LP
1343 return -EALREADY;
1344
d889a206
LP
1345 if (!dbus_message_get_args(
1346 message,
1347 error,
1348 DBUS_TYPE_BOOLEAN, &interactive,
1349 DBUS_TYPE_INVALID))
1350 return -EINVAL;
1351
1352 if (sleep_type) {
1353 r = can_sleep(sleep_type);
1354 if (r < 0)
1355 return r;
1356
1357 if (r == 0)
1358 return -ENOTSUP;
1359 }
1360
6524990f
LP
1361 if (sleep_disk_type) {
1362 r = can_sleep_disk(sleep_disk_type);
1363 if (r < 0)
1364 return r;
1365
1366 if (r == 0)
1367 return -ENOTSUP;
1368 }
1369
409133be
LP
1370 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1371 if (ul == (unsigned long) -1)
1372 return -EIO;
1373
1374 r = have_multiple_sessions(m, (uid_t) ul);
d889a206
LP
1375 if (r < 0)
1376 return r;
1377
1378 multiple_sessions = r > 0;
409133be 1379 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
d889a206
LP
1380
1381 if (multiple_sessions) {
1382 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1383 if (r < 0)
1384 return r;
1385 }
1386
1387 if (blocked) {
1388 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1389 if (r < 0)
1390 return r;
1391 }
1392
1393 if (!multiple_sessions && !blocked) {
1394 r = verify_polkit(connection, message, action, interactive, NULL, error);
1395 if (r < 0)
1396 return r;
1397 }
1398
069cfc85 1399 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
d889a206
LP
1400 if (r < 0)
1401 return r;
1402
1403 reply = dbus_message_new_method_return(message);
1404 if (!reply)
1405 return -ENOMEM;
eecd1362 1406
d889a206 1407 *_reply = reply;
eecd1362
LP
1408 return 0;
1409}
1410
23406ce5 1411static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_action, handle_action, HandleAction);
069cfc85 1412
d200735e
MS
1413static 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 },
eecd1362
LP
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) },
23406ce5
LP
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) },
5e4a79da
LP
1433 { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
1434 { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
d200735e
MS
1435 { NULL, }
1436};
1437
3f49d45a
LP
1438static DBusHandlerResult manager_message_handler(
1439 DBusConnection *connection,
1440 DBusMessage *message,
1441 void *userdata) {
1442
1443 Manager *m = userdata;
1444
3f49d45a 1445 DBusError error;
ce0fc5f5 1446 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
bef422ae 1447 int r;
3f49d45a
LP
1448
1449 assert(connection);
1450 assert(message);
1451 assert(m);
1452
1453 dbus_error_init(&error);
1454
bef422ae
LP
1455 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1456 const char *name;
1457 char *p;
1458 Session *session;
1459 bool b;
1460
1461 if (!dbus_message_get_args(
1462 message,
1463 &error,
1464 DBUS_TYPE_STRING, &name,
1465 DBUS_TYPE_INVALID))
1466 return bus_send_error_reply(connection, message, &error, -EINVAL);
1467
1468 session = hashmap_get(m->sessions, name);
1469 if (!session)
1470 return bus_send_error_reply(connection, message, &error, -ENOENT);
1471
1472 reply = dbus_message_new_method_return(message);
1473 if (!reply)
1474 goto oom;
1475
1476 p = session_bus_path(session);
c4aa65e7
LP
1477 if (!p)
1478 goto oom;
1479
1480 b = dbus_message_append_args(
1481 reply,
1482 DBUS_TYPE_OBJECT_PATH, &p,
1483 DBUS_TYPE_INVALID);
1484 free(p);
1485
1486 if (!b)
1487 goto oom;
1488
1489 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1490 uint32_t pid;
1491 char *p;
1492 Session *session;
1493 bool b;
1494
1495 if (!dbus_message_get_args(
1496 message,
1497 &error,
1498 DBUS_TYPE_UINT32, &pid,
1499 DBUS_TYPE_INVALID))
1500 return bus_send_error_reply(connection, message, &error, -EINVAL);
1501
1502 r = manager_get_session_by_pid(m, pid, &session);
1503 if (r <= 0)
1504 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1505
1506 reply = dbus_message_new_method_return(message);
1507 if (!reply)
1508 goto oom;
1509
1510 p = session_bus_path(session);
bef422ae
LP
1511 if (!p)
1512 goto oom;
1513
1514 b = dbus_message_append_args(
1515 reply,
1516 DBUS_TYPE_OBJECT_PATH, &p,
1517 DBUS_TYPE_INVALID);
1518 free(p);
1519
1520 if (!b)
1521 goto oom;
1522
1523 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1524 uint32_t uid;
1525 char *p;
1526 User *user;
1527 bool b;
1528
1529 if (!dbus_message_get_args(
1530 message,
1531 &error,
1532 DBUS_TYPE_UINT32, &uid,
1533 DBUS_TYPE_INVALID))
1534 return bus_send_error_reply(connection, message, &error, -EINVAL);
1535
1536 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1537 if (!user)
1538 return bus_send_error_reply(connection, message, &error, -ENOENT);
1539
1540 reply = dbus_message_new_method_return(message);
1541 if (!reply)
1542 goto oom;
1543
1544 p = user_bus_path(user);
1545 if (!p)
1546 goto oom;
1547
1548 b = dbus_message_append_args(
1549 reply,
1550 DBUS_TYPE_OBJECT_PATH, &p,
1551 DBUS_TYPE_INVALID);
1552 free(p);
1553
1554 if (!b)
1555 goto oom;
1556
1557 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1558 const char *name;
1559 char *p;
1560 Seat *seat;
1561 bool b;
1562
1563 if (!dbus_message_get_args(
1564 message,
1565 &error,
1566 DBUS_TYPE_STRING, &name,
1567 DBUS_TYPE_INVALID))
1568 return bus_send_error_reply(connection, message, &error, -EINVAL);
1569
1570 seat = hashmap_get(m->seats, name);
1571 if (!seat)
1572 return bus_send_error_reply(connection, message, &error, -ENOENT);
1573
1574 reply = dbus_message_new_method_return(message);
1575 if (!reply)
1576 goto oom;
1577
1578 p = seat_bus_path(seat);
1579 if (!p)
1580 goto oom;
1581
1582 b = dbus_message_append_args(
1583 reply,
1584 DBUS_TYPE_OBJECT_PATH, &p,
1585 DBUS_TYPE_INVALID);
1586 free(p);
1587
1588 if (!b)
1589 goto oom;
1590
e1c9c2d5
LP
1591 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1592 char *p;
1593 Session *session;
1594 Iterator i;
1595 DBusMessageIter iter, sub;
1596 const char *empty = "";
1597
1598 reply = dbus_message_new_method_return(message);
1599 if (!reply)
1600 goto oom;
1601
1602 dbus_message_iter_init_append(reply, &iter);
1603
dec15e92 1604 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
e1c9c2d5
LP
1605 goto oom;
1606
1607 HASHMAP_FOREACH(session, m->sessions, i) {
1608 DBusMessageIter sub2;
1609 uint32_t uid;
1610
1611 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1612 goto oom;
1613
1614 uid = session->user->uid;
1615
1616 p = session_bus_path(session);
1617 if (!p)
1618 goto oom;
1619
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)) {
1625 free(p);
1626 goto oom;
1627 }
1628
1629 free(p);
1630
1631 if (!dbus_message_iter_close_container(&sub, &sub2))
1632 goto oom;
1633 }
1634
1635 if (!dbus_message_iter_close_container(&iter, &sub))
1636 goto oom;
1637
1638 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1639 char *p;
1640 User *user;
1641 Iterator i;
1642 DBusMessageIter iter, sub;
1643
1644 reply = dbus_message_new_method_return(message);
1645 if (!reply)
1646 goto oom;
1647
1648 dbus_message_iter_init_append(reply, &iter);
1649
dec15e92 1650 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
e1c9c2d5
LP
1651 goto oom;
1652
1653 HASHMAP_FOREACH(user, m->users, i) {
1654 DBusMessageIter sub2;
1655 uint32_t uid;
1656
1657 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1658 goto oom;
1659
1660 uid = user->uid;
1661
1662 p = user_bus_path(user);
1663 if (!p)
1664 goto oom;
1665
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)) {
1669 free(p);
1670 goto oom;
1671 }
1672
1673 free(p);
1674
1675 if (!dbus_message_iter_close_container(&sub, &sub2))
1676 goto oom;
1677 }
1678
1679 if (!dbus_message_iter_close_container(&iter, &sub))
1680 goto oom;
1681
1682 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1683 char *p;
1684 Seat *seat;
1685 Iterator i;
1686 DBusMessageIter iter, sub;
1687
1688 reply = dbus_message_new_method_return(message);
1689 if (!reply)
1690 goto oom;
1691
1692 dbus_message_iter_init_append(reply, &iter);
1693
dec15e92 1694 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
e1c9c2d5
LP
1695 goto oom;
1696
1697 HASHMAP_FOREACH(seat, m->seats, i) {
1698 DBusMessageIter sub2;
1699
1700 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1701 goto oom;
1702
1703 p = seat_bus_path(seat);
1704 if (!p)
1705 goto oom;
1706
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)) {
1709 free(p);
1710 goto oom;
1711 }
1712
1713 free(p);
1714
1715 if (!dbus_message_iter_close_container(&sub, &sub2))
1716 goto oom;
1717 }
1718
1719 if (!dbus_message_iter_close_container(&iter, &sub))
1720 goto oom;
1721
f8e2fb7b
LP
1722 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1723 Inhibitor *inhibitor;
1724 Iterator i;
1725 DBusMessageIter iter, sub;
1726
1727 reply = dbus_message_new_method_return(message);
1728 if (!reply)
1729 goto oom;
1730
1731 dbus_message_iter_init_append(reply, &iter);
1732
eecd1362 1733 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
f8e2fb7b
LP
1734 goto oom;
1735
1736 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1737 DBusMessageIter sub2;
1738 dbus_uint32_t uid, pid;
eecd1362 1739 const char *what, *who, *why, *mode;
f8e2fb7b
LP
1740
1741 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1742 goto oom;
1743
eecd1362 1744 what = strempty(inhibit_what_to_string(inhibitor->what));
f8e2fb7b
LP
1745 who = strempty(inhibitor->who);
1746 why = strempty(inhibitor->why);
eecd1362 1747 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
f8e2fb7b
LP
1748 uid = (dbus_uint32_t) inhibitor->uid;
1749 pid = (dbus_uint32_t) inhibitor->pid;
1750
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) ||
eecd1362 1754 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
f8e2fb7b
LP
1755 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1756 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1757 goto oom;
1758
1759 if (!dbus_message_iter_close_container(&sub, &sub2))
1760 goto oom;
1761 }
1762
1763 if (!dbus_message_iter_close_container(&iter, &sub))
1764 goto oom;
1765
1766 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1767
1768 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1769
1770 if (r < 0)
1771 return bus_send_error_reply(connection, message, &error, r);
1772
1773
98a28fef
LP
1774 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1775
1776 r = bus_manager_create_session(m, message, &reply);
688c56ff
LP
1777
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 */
98a28fef
LP
1782
1783 if (r < 0)
f8e2fb7b 1784 return bus_send_error_reply(connection, message, NULL, r);
98a28fef 1785
75c8e3cf
LP
1786 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1787 const char *name;
1788 Session *session;
1789
1790 if (!dbus_message_get_args(
1791 message,
1792 &error,
1793 DBUS_TYPE_STRING, &name,
1794 DBUS_TYPE_INVALID))
1795 return bus_send_error_reply(connection, message, &error, -EINVAL);
1796
1797 session = hashmap_get(m->sessions, name);
1798 if (!session)
1799 return bus_send_error_reply(connection, message, &error, -ENOENT);
1800
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);
1808
1809 reply = dbus_message_new_method_return(message);
1810 if (!reply)
1811 goto oom;
1812
bef422ae
LP
1813 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1814 const char *name;
1815 Session *session;
1816
1817 if (!dbus_message_get_args(
1818 message,
1819 &error,
1820 DBUS_TYPE_STRING, &name,
1821 DBUS_TYPE_INVALID))
1822 return bus_send_error_reply(connection, message, &error, -EINVAL);
1823
1824 session = hashmap_get(m->sessions, name);
1825 if (!session)
1826 return bus_send_error_reply(connection, message, &error, -ENOENT);
1827
1828 r = session_activate(session);
1829 if (r < 0)
1830 return bus_send_error_reply(connection, message, NULL, r);
1831
1832 reply = dbus_message_new_method_return(message);
1833 if (!reply)
1834 goto oom;
1835
84c3361e
LP
1836 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1837 const char *session_name, *seat_name;
1838 Session *session;
1839 Seat *seat;
1840
1841 /* Same as ActivateSession() but refuses to work if
1842 * the seat doesn't match */
1843
1844 if (!dbus_message_get_args(
1845 message,
1846 &error,
1847 DBUS_TYPE_STRING, &session_name,
1848 DBUS_TYPE_STRING, &seat_name,
1849 DBUS_TYPE_INVALID))
1850 return bus_send_error_reply(connection, message, &error, -EINVAL);
1851
1852 session = hashmap_get(m->sessions, session_name);
1853 if (!session)
1854 return bus_send_error_reply(connection, message, &error, -ENOENT);
1855
1856 seat = hashmap_get(m->seats, seat_name);
1857 if (!seat)
1858 return bus_send_error_reply(connection, message, &error, -ENOENT);
1859
1860 if (session->seat != seat)
1861 return bus_send_error_reply(connection, message, &error, -EINVAL);
1862
1863 r = session_activate(session);
1864 if (r < 0)
1865 return bus_send_error_reply(connection, message, NULL, r);
1866
1867 reply = dbus_message_new_method_return(message);
1868 if (!reply)
1869 goto oom;
1870
88e3dc90
LP
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")) {
1873 const char *name;
1874 Session *session;
1875
1876 if (!dbus_message_get_args(
1877 message,
1878 &error,
1879 DBUS_TYPE_STRING, &name,
1880 DBUS_TYPE_INVALID))
1881 return bus_send_error_reply(connection, message, &error, -EINVAL);
1882
1883 session = hashmap_get(m->sessions, name);
1884 if (!session)
7ba64386 1885 return bus_send_error_reply(connection, message, NULL, -ENOENT);
88e3dc90
LP
1886
1887 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1888 goto oom;
1889
1890 reply = dbus_message_new_method_return(message);
1891 if (!reply)
1892 goto oom;
1893
b6160029
LP
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")) {
1896
1897 r = session_send_lock_all(m, streq(dbus_message_get_member(message), "LockSessions"));
7ba64386
LP
1898 if (r < 0)
1899 bus_send_error_reply(connection, message, NULL, r);
fa2b196d
LP
1900
1901 reply = dbus_message_new_method_return(message);
1902 if (!reply)
1903 goto oom;
1904
de07ab16
LP
1905 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1906 const char *swho;
1907 int32_t signo;
1908 KillWho who;
1909 const char *name;
1910 Session *session;
1911
1912 if (!dbus_message_get_args(
1913 message,
1914 &error,
1915 DBUS_TYPE_STRING, &name,
1916 DBUS_TYPE_STRING, &swho,
1917 DBUS_TYPE_INT32, &signo,
1918 DBUS_TYPE_INVALID))
1919 return bus_send_error_reply(connection, message, &error, -EINVAL);
1920
1921 if (isempty(swho))
1922 who = KILL_ALL;
1923 else {
1924 who = kill_who_from_string(swho);
1925 if (who < 0)
1926 return bus_send_error_reply(connection, message, &error, -EINVAL);
1927 }
1928
1929 if (signo <= 0 || signo >= _NSIG)
1930 return bus_send_error_reply(connection, message, &error, -EINVAL);
1931
1932 session = hashmap_get(m->sessions, name);
1933 if (!session)
1934 return bus_send_error_reply(connection, message, &error, -ENOENT);
1935
1936 r = session_kill(session, who, signo);
1937 if (r < 0)
1938 return bus_send_error_reply(connection, message, NULL, r);
1939
1940 reply = dbus_message_new_method_return(message);
1941 if (!reply)
1942 goto oom;
1943
1944 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1945 uint32_t uid;
1946 User *user;
1947 int32_t signo;
1948
1949 if (!dbus_message_get_args(
1950 message,
1951 &error,
1952 DBUS_TYPE_UINT32, &uid,
1953 DBUS_TYPE_INT32, &signo,
1954 DBUS_TYPE_INVALID))
1955 return bus_send_error_reply(connection, message, &error, -EINVAL);
1956
1957 if (signo <= 0 || signo >= _NSIG)
1958 return bus_send_error_reply(connection, message, &error, -EINVAL);
1959
1960 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1961 if (!user)
1962 return bus_send_error_reply(connection, message, &error, -ENOENT);
1963
1964 r = user_kill(user, signo);
1965 if (r < 0)
1966 return bus_send_error_reply(connection, message, NULL, r);
1967
1968 reply = dbus_message_new_method_return(message);
1969 if (!reply)
1970 goto oom;
1971
bef422ae
LP
1972 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1973 const char *name;
1974 Session *session;
1975
1976 if (!dbus_message_get_args(
1977 message,
1978 &error,
1979 DBUS_TYPE_STRING, &name,
1980 DBUS_TYPE_INVALID))
1981 return bus_send_error_reply(connection, message, &error, -EINVAL);
1982
1983 session = hashmap_get(m->sessions, name);
1984 if (!session)
1985 return bus_send_error_reply(connection, message, &error, -ENOENT);
1986
1987 r = session_stop(session);
1988 if (r < 0)
1989 return bus_send_error_reply(connection, message, NULL, r);
1990
1991 reply = dbus_message_new_method_return(message);
1992 if (!reply)
1993 goto oom;
1994
1995 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1996 uint32_t uid;
1997 User *user;
1998
1999 if (!dbus_message_get_args(
2000 message,
2001 &error,
2002 DBUS_TYPE_UINT32, &uid,
2003 DBUS_TYPE_INVALID))
2004 return bus_send_error_reply(connection, message, &error, -EINVAL);
2005
2006 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
2007 if (!user)
2008 return bus_send_error_reply(connection, message, &error, -ENOENT);
2009
2010 r = user_stop(user);
2011 if (r < 0)
2012 return bus_send_error_reply(connection, message, NULL, r);
2013
2014 reply = dbus_message_new_method_return(message);
2015 if (!reply)
2016 goto oom;
2017
2018 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
2019 const char *name;
2020 Seat *seat;
2021
2022 if (!dbus_message_get_args(
2023 message,
2024 &error,
2025 DBUS_TYPE_STRING, &name,
2026 DBUS_TYPE_INVALID))
2027 return bus_send_error_reply(connection, message, &error, -EINVAL);
2028
2029 seat = hashmap_get(m->seats, name);
2030 if (!seat)
2031 return bus_send_error_reply(connection, message, &error, -ENOENT);
2032
2033 r = seat_stop_sessions(seat);
2034 if (r < 0)
2035 return bus_send_error_reply(connection, message, NULL, r);
2036
2037 reply = dbus_message_new_method_return(message);
2038 if (!reply)
2039 goto oom;
2040
7f7bb946
LP
2041 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
2042 uint32_t uid;
2043 struct passwd *pw;
2044 dbus_bool_t b, interactive;
2045 char *path;
2046
2047 if (!dbus_message_get_args(
2048 message,
2049 &error,
2050 DBUS_TYPE_UINT32, &uid,
2051 DBUS_TYPE_BOOLEAN, &b,
2052 DBUS_TYPE_BOOLEAN, &interactive,
2053 DBUS_TYPE_INVALID))
2054 return bus_send_error_reply(connection, message, &error, -EINVAL);
2055
2056 errno = 0;
2057 pw = getpwuid(uid);
2058 if (!pw)
2059 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
2060
89f13440 2061 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
7f7bb946
LP
2062 if (r < 0)
2063 return bus_send_error_reply(connection, message, &error, r);
2064
d2e54fae 2065 mkdir_p_label("/var/lib/systemd", 0755);
02b16a19 2066
d2e54fae 2067 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
7f7bb946
LP
2068 if (r < 0)
2069 return bus_send_error_reply(connection, message, &error, r);
2070
2071 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
2072 if (!path)
2073 goto oom;
2074
2075 if (b) {
38f3fc7d
LP
2076 User *u;
2077
7f7bb946
LP
2078 r = touch(path);
2079 free(path);
2080
2081 if (r < 0)
2082 return bus_send_error_reply(connection, message, &error, r);
38f3fc7d
LP
2083
2084 if (manager_add_user_by_uid(m, uid, &u) >= 0)
2085 user_start(u);
2086
7f7bb946 2087 } else {
38f3fc7d
LP
2088 User *u;
2089
7f7bb946
LP
2090 r = unlink(path);
2091 free(path);
2092
2093 if (r < 0 && errno != ENOENT)
2094 return bus_send_error_reply(connection, message, &error, -errno);
38f3fc7d
LP
2095
2096 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
2097 if (u)
2098 user_add_to_gc_queue(u);
7f7bb946
LP
2099 }
2100
2101 reply = dbus_message_new_method_return(message);
2102 if (!reply)
2103 goto oom;
2104
47a26690
LP
2105 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
2106 const char *sysfs, *seat;
2107 dbus_bool_t interactive;
2108
2109 if (!dbus_message_get_args(
2110 message,
2111 &error,
2112 DBUS_TYPE_STRING, &seat,
2113 DBUS_TYPE_STRING, &sysfs,
2114 DBUS_TYPE_BOOLEAN, &interactive,
2115 DBUS_TYPE_INVALID))
2116 return bus_send_error_reply(connection, message, &error, -EINVAL);
2117
2118 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
2119 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2120
89f13440 2121 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
47a26690
LP
2122 if (r < 0)
2123 return bus_send_error_reply(connection, message, &error, r);
2124
2125 r = attach_device(m, seat, sysfs);
2126 if (r < 0)
2127 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2128
2129 reply = dbus_message_new_method_return(message);
2130 if (!reply)
2131 goto oom;
7f7bb946 2132
b668e064
LP
2133
2134 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
2135 dbus_bool_t interactive;
2136
2137 if (!dbus_message_get_args(
2138 message,
2139 &error,
2140 DBUS_TYPE_BOOLEAN, &interactive,
2141 DBUS_TYPE_INVALID))
2142 return bus_send_error_reply(connection, message, &error, -EINVAL);
2143
89f13440 2144 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
b668e064
LP
2145 if (r < 0)
2146 return bus_send_error_reply(connection, message, &error, r);
2147
2148 r = flush_devices(m);
2149 if (r < 0)
2150 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2151
2152 reply = dbus_message_new_method_return(message);
2153 if (!reply)
2154 goto oom;
2155
d889a206
LP
2156 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
2157
2158 r = bus_manager_do_shutdown_or_sleep(
2159 m, connection, message,
2160 SPECIAL_POWEROFF_TARGET,
2161 INHIBIT_SHUTDOWN,
2162 "org.freedesktop.login1.power-off",
2163 "org.freedesktop.login1.power-off-multiple-sessions",
2164 "org.freedesktop.login1.power-off-ignore-inhibit",
6524990f 2165 NULL, NULL,
d889a206 2166 &error, &reply);
89f13440
LP
2167 if (r < 0)
2168 return bus_send_error_reply(connection, message, &error, r);
d889a206
LP
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,
2173 INHIBIT_SHUTDOWN,
2174 "org.freedesktop.login1.reboot",
2175 "org.freedesktop.login1.reboot-multiple-sessions",
2176 "org.freedesktop.login1.reboot-ignore-inhibit",
6524990f 2177 NULL, NULL,
d889a206 2178 &error, &reply);
89f13440
LP
2179 if (r < 0)
2180 return bus_send_error_reply(connection, message, &error, r);
2181
d889a206
LP
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,
2186 INHIBIT_SLEEP,
2187 "org.freedesktop.login1.suspend",
2188 "org.freedesktop.login1.suspend-multiple-sessions",
2189 "org.freedesktop.login1.suspend-ignore-inhibit",
6524990f 2190 "mem", NULL,
d889a206
LP
2191 &error, &reply);
2192 if (r < 0)
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,
2198 INHIBIT_SLEEP,
2199 "org.freedesktop.login1.hibernate",
2200 "org.freedesktop.login1.hibernate-multiple-sessions",
2201 "org.freedesktop.login1.hibernate-ignore-inhibit",
6524990f
LP
2202 "disk", NULL,
2203 &error, &reply);
2204 if (r < 0)
2205 return bus_send_error_reply(connection, message, &error, r);
2206
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,
2211 INHIBIT_SLEEP,
2212 "org.freedesktop.login1.hibernate",
2213 "org.freedesktop.login1.hibernate-multiple-sessions",
2214 "org.freedesktop.login1.hibernate-ignore-inhibit",
2215 "disk", "suspend",
d889a206
LP
2216 &error, &reply);
2217 if (r < 0)
2218 return bus_send_error_reply(connection, message, &error, r);
f8e2fb7b 2219
d889a206 2220 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
f8e2fb7b 2221
d889a206
LP
2222 r = bus_manager_can_shutdown_or_sleep(
2223 m, connection, message,
2224 INHIBIT_SHUTDOWN,
2225 "org.freedesktop.login1.power-off",
2226 "org.freedesktop.login1.power-off-multiple-sessions",
2227 "org.freedesktop.login1.power-off-ignore-inhibit",
6524990f 2228 NULL, NULL,
d889a206
LP
2229 &error, &reply);
2230 if (r < 0)
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,
2235 INHIBIT_SHUTDOWN,
2236 "org.freedesktop.login1.reboot",
2237 "org.freedesktop.login1.reboot-multiple-sessions",
2238 "org.freedesktop.login1.reboot-ignore-inhibit",
6524990f 2239 NULL, NULL,
d889a206
LP
2240 &error, &reply);
2241 if (r < 0)
2242 return bus_send_error_reply(connection, message, &error, r);
89f13440 2243
d889a206
LP
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,
2247 INHIBIT_SLEEP,
2248 "org.freedesktop.login1.suspend",
2249 "org.freedesktop.login1.suspend-multiple-sessions",
2250 "org.freedesktop.login1.suspend-ignore-inhibit",
6524990f 2251 "mem", NULL,
d889a206
LP
2252 &error, &reply);
2253 if (r < 0)
2254 return bus_send_error_reply(connection, message, &error, r);
89f13440 2255
d889a206
LP
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,
2259 INHIBIT_SLEEP,
2260 "org.freedesktop.login1.hibernate",
2261 "org.freedesktop.login1.hibernate-multiple-sessions",
2262 "org.freedesktop.login1.hibernate-ignore-inhibit",
6524990f
LP
2263 "disk", NULL,
2264 &error, &reply);
2265 if (r < 0)
2266 return bus_send_error_reply(connection, message, &error, r);
2267
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,
2271 INHIBIT_SLEEP,
2272 "org.freedesktop.login1.hibernate",
2273 "org.freedesktop.login1.hibernate-multiple-sessions",
2274 "org.freedesktop.login1.hibernate-ignore-inhibit",
2275 "disk", "suspend",
d889a206
LP
2276 &error, &reply);
2277 if (r < 0)
2278 return bus_send_error_reply(connection, message, &error, r);
89f13440 2279
bef422ae 2280 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
3f49d45a
LP
2281 char *introspection = NULL;
2282 FILE *f;
2283 Iterator i;
2284 Session *session;
2285 Seat *seat;
2286 User *user;
2287 size_t size;
2288 char *p;
2289
2290 if (!(reply = dbus_message_new_method_return(message)))
2291 goto oom;
2292
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
2296 * dynamically. */
2297
2298 if (!(f = open_memstream(&introspection, &size)))
2299 goto oom;
2300
2301 fputs(INTROSPECTION_BEGIN, f);
2302
2303 HASHMAP_FOREACH(seat, m->seats, i) {
2304 p = bus_path_escape(seat->id);
2305
2306 if (p) {
2307 fprintf(f, "<node name=\"seat/%s\"/>", p);
2308 free(p);
2309 }
2310 }
2311
2312 HASHMAP_FOREACH(user, m->users, i)
2313 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2314
2315 HASHMAP_FOREACH(session, m->sessions, i) {
2316 p = bus_path_escape(session->id);
2317
2318 if (p) {
2319 fprintf(f, "<node name=\"session/%s\"/>", p);
2320 free(p);
2321 }
2322 }
2323
2324 fputs(INTROSPECTION_END, f);
2325
2326 if (ferror(f)) {
2327 fclose(f);
2328 free(introspection);
2329 goto oom;
2330 }
2331
2332 fclose(f);
2333
2334 if (!introspection)
2335 goto oom;
2336
2337 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2338 free(introspection);
2339 goto oom;
2340 }
2341
2342 free(introspection);
d200735e
MS
2343 } else {
2344 const BusBoundProperties bps[] = {
2345 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2346 { NULL, }
2347 };
2348 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2349 }
3f49d45a
LP
2350
2351 if (reply) {
1a37b9b9
CW
2352 if (!bus_maybe_send_reply(connection, message, reply))
2353 goto oom;
3f49d45a
LP
2354 }
2355
2356 return DBUS_HANDLER_RESULT_HANDLED;
2357
2358oom:
3f49d45a
LP
2359 dbus_error_free(&error);
2360
2361 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2362}
2363
2364const DBusObjectPathVTable bus_manager_vtable = {
2365 .message_function = manager_message_handler
2366};
9418f147 2367
1713813d
LP
2368DBusHandlerResult bus_message_filter(
2369 DBusConnection *connection,
2370 DBusMessage *message,
2371 void *userdata) {
2372
2373 Manager *m = userdata;
2374 DBusError error;
2375
2376 assert(m);
2377 assert(connection);
2378 assert(message);
2379
2380 dbus_error_init(&error);
2381
2382 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
2383 const char *cgroup;
2384
2385 if (!dbus_message_get_args(message, &error,
2386 DBUS_TYPE_STRING, &cgroup,
2387 DBUS_TYPE_INVALID))
2388 log_error("Failed to parse Released message: %s", bus_error_message(&error));
2389 else
2390 manager_cgroup_notify_empty(m, cgroup);
af9792ac
LP
2391
2392 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
2393 uint32_t id;
2394 const char *path, *result, *unit;
2395
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,
2401 DBUS_TYPE_INVALID))
2402 log_error("Failed to parse JobRemoved message: %s", bus_error_message(&error));
314b4b0a 2403
af9792ac 2404 else if (m->action_job && streq(m->action_job, path)) {
ee17c928 2405
314b4b0a 2406 log_info("Operation finished.");
ee17c928 2407
314b4b0a
LP
2408 /* Tell people that they now may take a lock again */
2409 send_prepare_for(m, m->action_what, false);
2410
2411 free(m->action_job);
2412 m->action_job = NULL;
2413 m->action_unit = NULL;
2414 m->action_what = 0;
af9792ac 2415 }
1713813d
LP
2416 }
2417
2418 dbus_error_free(&error);
2419
2420 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2421}
2422
9418f147 2423int manager_send_changed(Manager *manager, const char *properties) {
ce0fc5f5 2424 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
9418f147
LP
2425
2426 assert(manager);
2427
4654e558
ZJS
2428 m = bus_properties_changed_new("/org/freedesktop/login1",
2429 "org.freedesktop.login1.Manager",
2430 properties);
9418f147 2431 if (!m)
4654e558 2432 return -ENOMEM;
9418f147
LP
2433
2434 if (!dbus_connection_send(manager->bus, m, NULL))
4654e558 2435 return -ENOMEM;
9418f147 2436
4654e558 2437 return 0;
9418f147 2438}
eecd1362 2439
d889a206 2440int manager_dispatch_delayed(Manager *manager) {
eecd1362 2441 DBusError error;
eecd1362
LP
2442 int r;
2443
2444 assert(manager);
2445
314b4b0a 2446 if (!manager->action_unit || manager->action_job)
eecd1362
LP
2447 return 0;
2448
2449 /* Continue delay? */
314b4b0a 2450 if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0)) {
eecd1362 2451
314b4b0a
LP
2452 if (manager->action_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC))
2453 return 0;
af9792ac 2454
314b4b0a
LP
2455 log_info("Delay lock is active but inhibitor timeout is reached.");
2456 }
eecd1362 2457
314b4b0a 2458 /* Actually do the operation */
eecd1362 2459 dbus_error_init(&error);
314b4b0a 2460 r = execute_shutdown_or_sleep(manager, manager->action_what, manager->action_unit, &error);
eecd1362 2461 if (r < 0) {
d889a206
LP
2462 log_warning("Failed to send delayed message: %s", bus_error_message_or_strerror(&error, -r));
2463 dbus_error_free(&error);
314b4b0a
LP
2464
2465 manager->action_unit = NULL;
2466 manager->action_what = 0;
eecd1362
LP
2467 return r;
2468 }
2469
eecd1362
LP
2470 return 1;
2471}