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