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