]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-dbus.c
transaction.c: do not point users to logs when unit not found
[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"
9444b1f2
LP
39#include "utf8.h"
40#include "unit-name.h"
fb6becb4
LP
41#include "bus-errors.h"
42#include "virt.h"
3f49d45a
LP
43
44#define BUS_MANAGER_INTERFACE \
45 " <interface name=\"org.freedesktop.login1.Manager\">\n" \
bef422ae 46 " <method name=\"GetSession\">\n" \
3f49d45a 47 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
bef422ae 48 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
3f49d45a 49 " </method>\n" \
c4aa65e7
LP
50 " <method name=\"GetSessionByPID\">\n" \
51 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
52 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
53 " </method>\n" \
3f49d45a 54 " <method name=\"GetUser\">\n" \
bef422ae 55 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
3f49d45a
LP
56 " <arg name=\"user\" type=\"o\" direction=\"out\"/>\n" \
57 " </method>\n" \
9444b1f2
LP
58 " <method name=\"GetUserByPID\">\n" \
59 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
60 " <arg name=\"user\" type=\"o\" direction=\"out\"/>\n" \
61 " </method>\n" \
bef422ae 62 " <method name=\"GetSeat\">\n" \
3f49d45a 63 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
bef422ae 64 " <arg name=\"seat\" type=\"o\" direction=\"out\"/>\n" \
3f49d45a 65 " </method>\n" \
bef422ae 66 " <method name=\"ListSessions\">\n" \
e1c9c2d5 67 " <arg name=\"sessions\" type=\"a(susso)\" direction=\"out\"/>\n" \
3f49d45a
LP
68 " </method>\n" \
69 " <method name=\"ListUsers\">\n" \
70 " <arg name=\"users\" type=\"a(uso)\" direction=\"out\"/>\n" \
71 " </method>\n" \
bef422ae
LP
72 " <method name=\"ListSeats\">\n" \
73 " <arg name=\"seats\" type=\"a(so)\" direction=\"out\"/>\n" \
3f49d45a
LP
74 " </method>\n" \
75 " <method name=\"CreateSession\">\n" \
76 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
77 " <arg name=\"leader\" type=\"u\" direction=\"in\"/>\n" \
ab06eef8 78 " <arg name=\"service\" type=\"s\" direction=\"in\"/>\n" \
3f49d45a 79 " <arg name=\"type\" type=\"s\" direction=\"in\"/>\n" \
55efac6c 80 " <arg name=\"class\" type=\"s\" direction=\"in\"/>\n" \
3f49d45a 81 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
4d6d6518 82 " <arg name=\"vtnr\" type=\"u\" direction=\"in\"/>\n" \
3f49d45a
LP
83 " <arg name=\"tty\" type=\"s\" direction=\"in\"/>\n" \
84 " <arg name=\"display\" type=\"s\" direction=\"in\"/>\n" \
85 " <arg name=\"remote\" type=\"b\" direction=\"in\"/>\n" \
86 " <arg name=\"remote_user\" type=\"s\" direction=\"in\"/>\n" \
87 " <arg name=\"remote_host\" type=\"s\" direction=\"in\"/>\n" \
fb6becb4 88 " <arg name=\"scope_properties\" type=\"a(sv)\" direction=\"in\"/>\n" \
3f49d45a
LP
89 " <arg name=\"id\" type=\"s\" direction=\"out\"/>\n" \
90 " <arg name=\"path\" type=\"o\" direction=\"out\"/>\n" \
98a28fef 91 " <arg name=\"runtime_path\" type=\"o\" direction=\"out\"/>\n" \
3f49d45a 92 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
bbc73283
LP
93 " <arg name=\"seat\" type=\"s\" direction=\"out\"/>\n" \
94 " <arg name=\"vtnr\" type=\"u\" direction=\"out\"/>\n" \
77085881 95 " <arg name=\"existing\" type=\"b\" direction=\"out\"/>\n" \
3f49d45a 96 " </method>\n" \
75c8e3cf
LP
97 " <method name=\"ReleaseSession\">\n" \
98 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
99 " </method>\n" \
a185c5aa
LP
100 " <method name=\"ActivateSession\">\n" \
101 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
102 " </method>\n" \
84c3361e
LP
103 " <method name=\"ActivateSessionOnSeat\">\n" \
104 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
105 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
106 " </method>\n" \
88e3dc90
LP
107 " <method name=\"LockSession\">\n" \
108 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
109 " </method>\n" \
110 " <method name=\"UnlockSession\">\n" \
111 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
112 " </method>\n" \
fa2b196d 113 " <method name=\"LockSessions\"/>\n" \
b6160029 114 " <method name=\"UnlockSessions\"/>\n" \
de07ab16
LP
115 " <method name=\"KillSession\">\n" \
116 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
cae5846b
LP
117 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
118 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
de07ab16
LP
119 " </method>\n" \
120 " <method name=\"KillUser\">\n" \
121 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
cae5846b 122 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
de07ab16 123 " </method>\n" \
3f49d45a
LP
124 " <method name=\"TerminateSession\">\n" \
125 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
126 " </method>\n" \
127 " <method name=\"TerminateUser\">\n" \
bef422ae 128 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
3f49d45a
LP
129 " </method>\n" \
130 " <method name=\"TerminateSeat\">\n" \
131 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
132 " </method>\n" \
7f7bb946
LP
133 " <method name=\"SetUserLinger\">\n" \
134 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
135 " <arg name=\"b\" type=\"b\" direction=\"in\"/>\n" \
136 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
137 " </method>\n" \
47a26690
LP
138 " <method name=\"AttachDevice\">\n" \
139 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
140 " <arg name=\"sysfs\" type=\"s\" direction=\"in\"/>\n" \
141 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
142 " </method>\n" \
b668e064
LP
143 " <method name=\"FlushDevices\">\n" \
144 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
145 " </method>\n" \
55af3897
LP
146 " <method name=\"PowerOff\">\n" \
147 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
148 " </method>\n" \
149 " <method name=\"Reboot\">\n" \
150 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
151 " </method>\n" \
d889a206
LP
152 " <method name=\"Suspend\">\n" \
153 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
154 " </method>\n" \
155 " <method name=\"Hibernate\">\n" \
156 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
157 " </method>\n" \
6524990f
LP
158 " <method name=\"HybridSleep\">\n" \
159 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
160 " </method>\n" \
89f13440
LP
161 " <method name=\"CanPowerOff\">\n" \
162 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
163 " </method>\n" \
164 " <method name=\"CanReboot\">\n" \
165 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
166 " </method>\n" \
d889a206
LP
167 " <method name=\"CanSuspend\">\n" \
168 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
169 " </method>\n" \
170 " <method name=\"CanHibernate\">\n" \
171 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
172 " </method>\n" \
6524990f
LP
173 " <method name=\"CanHybridSleep\">\n" \
174 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
175 " </method>\n" \
f8e2fb7b
LP
176 " <method name=\"Inhibit\">\n" \
177 " <arg name=\"what\" type=\"s\" direction=\"in\"/>\n" \
178 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
179 " <arg name=\"why\" type=\"s\" direction=\"in\"/>\n" \
eecd1362 180 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
f8e2fb7b
LP
181 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
182 " </method>\n" \
183 " <method name=\"ListInhibitors\">\n" \
eecd1362 184 " <arg name=\"inhibitors\" type=\"a(ssssuu)\" direction=\"out\"/>\n" \
f8e2fb7b 185 " </method>\n" \
3f49d45a
LP
186 " <signal name=\"SessionNew\">\n" \
187 " <arg name=\"id\" type=\"s\"/>\n" \
188 " <arg name=\"path\" type=\"o\"/>\n" \
189 " </signal>\n" \
190 " <signal name=\"SessionRemoved\">\n" \
191 " <arg name=\"id\" type=\"s\"/>\n" \
192 " <arg name=\"path\" type=\"o\"/>\n" \
193 " </signal>\n" \
194 " <signal name=\"UserNew\">\n" \
195 " <arg name=\"uid\" type=\"u\"/>\n" \
196 " <arg name=\"path\" type=\"o\"/>\n" \
197 " </signal>\n" \
198 " <signal name=\"UserRemoved\">\n" \
199 " <arg name=\"uid\" type=\"u\"/>\n" \
200 " <arg name=\"path\" type=\"o\"/>\n" \
201 " </signal>\n" \
202 " <signal name=\"SeatNew\">\n" \
203 " <arg name=\"id\" type=\"s\"/>\n" \
204 " <arg name=\"path\" type=\"o\"/>\n" \
205 " </signal>\n" \
206 " <signal name=\"SeatRemoved\">\n" \
207 " <arg name=\"id\" type=\"s\"/>\n" \
208 " <arg name=\"path\" type=\"o\"/>\n" \
209 " </signal>\n" \
eecd1362
LP
210 " <signal name=\"PrepareForShutdown\">\n" \
211 " <arg name=\"active\" type=\"b\"/>\n" \
212 " </signal>\n" \
d889a206
LP
213 " <signal name=\"PrepareForSleep\">\n" \
214 " <arg name=\"active\" type=\"b\"/>\n" \
215 " </signal>\n" \
3f49d45a
LP
216 " <property name=\"NAutoVTs\" type=\"u\" access=\"read\"/>\n" \
217 " <property name=\"KillOnlyUsers\" type=\"as\" access=\"read\"/>\n" \
218 " <property name=\"KillExcludeUsers\" type=\"as\" access=\"read\"/>\n" \
219 " <property name=\"KillUserProcesses\" type=\"b\" access=\"read\"/>\n" \
a185c5aa
LP
220 " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
221 " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
222 " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
eecd1362
LP
223 " <property name=\"BlockInhibited\" type=\"s\" access=\"read\"/>\n" \
224 " <property name=\"DelayInhibited\" type=\"s\" access=\"read\"/>\n" \
225 " <property name=\"InhibitDelayMaxUSec\" type=\"t\" access=\"read\"/>\n" \
069cfc85 226 " <property name=\"HandlePowerKey\" type=\"s\" access=\"read\"/>\n" \
8e7fd6ad
LP
227 " <property name=\"HandleSuspendKey\" type=\"s\" access=\"read\"/>\n" \
228 " <property name=\"HandleHibernateKey\" type=\"s\" access=\"read\"/>\n" \
069cfc85 229 " <property name=\"HandleLidSwitch\" type=\"s\" access=\"read\"/>\n" \
23406ce5
LP
230 " <property name=\"IdleAction\" type=\"s\" access=\"read\"/>\n" \
231 " <property name=\"IdleActionUSec\" type=\"t\" access=\"read\"/>\n" \
5e4a79da
LP
232 " <property name=\"PreparingForShutdown\" type=\"b\" access=\"read\"/>\n" \
233 " <property name=\"PreparingForSleep\" type=\"b\" access=\"read\"/>\n" \
3f49d45a
LP
234 " </interface>\n"
235
236#define INTROSPECTION_BEGIN \
237 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
238 "<node>\n" \
239 BUS_MANAGER_INTERFACE \
240 BUS_PROPERTIES_INTERFACE \
241 BUS_PEER_INTERFACE \
242 BUS_INTROSPECTABLE_INTERFACE
243
244#define INTROSPECTION_END \
245 "</node>\n"
246
247#define INTERFACES_LIST \
248 BUS_GENERIC_INTERFACES_LIST \
249 "org.freedesktop.login1.Manager\0"
250
a185c5aa
LP
251static int bus_manager_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
252 Manager *m = data;
77527da0 253 dbus_bool_t b;
a185c5aa
LP
254
255 assert(i);
256 assert(property);
257 assert(m);
258
77527da0 259 b = manager_get_idle_hint(m, NULL) > 0;
a185c5aa
LP
260 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
261 return -ENOMEM;
262
263 return 0;
264}
265
266static int bus_manager_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
267 Manager *m = data;
268 dual_timestamp t;
269 uint64_t u;
270
271 assert(i);
272 assert(property);
273 assert(m);
274
275 manager_get_idle_hint(m, &t);
276 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
277
278 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
279 return -ENOMEM;
280
281 return 0;
282}
283
f8e2fb7b
LP
284static int bus_manager_append_inhibited(DBusMessageIter *i, const char *property, void *data) {
285 Manager *m = data;
286 InhibitWhat w;
287 const char *p;
288
eecd1362 289 w = manager_inhibit_what(m, streq(property, "BlockInhibited") ? INHIBIT_BLOCK : INHIBIT_DELAY);
f8e2fb7b
LP
290 p = inhibit_what_to_string(w);
291
292 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &p))
293 return -ENOMEM;
294
295 return 0;
296}
297
5e4a79da
LP
298static int bus_manager_append_preparing(DBusMessageIter *i, const char *property, void *data) {
299 Manager *m = data;
300 dbus_bool_t b;
301
302 assert(i);
303 assert(property);
304
305 if (streq(property, "PreparingForShutdown"))
314b4b0a 306 b = !!(m->action_what & INHIBIT_SHUTDOWN);
5e4a79da 307 else
314b4b0a 308 b = !!(m->action_what & INHIBIT_SLEEP);
5e4a79da
LP
309
310 dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b);
311 return 0;
312}
313
fb6becb4
LP
314static int bus_manager_create_session(Manager *m, DBusMessage *message) {
315
954449b8 316 const char *type, *class, *cseat, *tty, *display, *remote_user, *remote_host, *service;
98a28fef 317 uint32_t uid, leader, audit_id = 0;
fb6becb4 318 _cleanup_free_ char *id = NULL;
954449b8
LP
319 Session *session = NULL;
320 User *user = NULL;
321 Seat *seat = NULL;
fb6becb4
LP
322 DBusMessageIter iter;
323 dbus_bool_t remote;
324 uint32_t vtnr = 0;
325 SessionType t;
326 SessionClass c;
98a28fef 327 bool b;
fb6becb4 328 int r;
98a28fef
LP
329
330 assert(m);
331 assert(message);
98a28fef
LP
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
9444b1f2 345 if (!dbus_message_iter_next(&iter) ||
98a28fef
LP
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
9444b1f2
LP
481 if (leader <= 0) {
482 leader = bus_get_unix_process_id(m->bus, dbus_message_get_sender(message), NULL);
483 if (leader == 0)
484 return -EINVAL;
485 }
486
fb6becb4
LP
487 r = manager_get_session_by_pid(m, leader, &session);
488 if (session) {
489 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
490 _cleanup_free_ char *path = NULL;
491 _cleanup_close_ int fifo_fd = -1;
8b6fe824 492 dbus_bool_t exists;
98a28fef 493
fb6becb4
LP
494 /* Session already exists, client is probably
495 * something like "su" which changes uid but is still
496 * the same session */
98a28fef 497
954449b8
LP
498 fifo_fd = session_create_fifo(session);
499 if (fifo_fd < 0) {
500 r = fifo_fd;
07714753
LP
501 goto fail;
502 }
98a28fef 503
fb6becb4
LP
504 path = session_bus_path(session);
505 if (!path) {
954449b8
LP
506 r = -ENOMEM;
507 goto fail;
508 }
21c390cc 509
fb6becb4
LP
510 reply = dbus_message_new_method_return(message);
511 if (!reply) {
954449b8
LP
512 r = -ENOMEM;
513 goto fail;
514 }
932e3ee7 515
954449b8
LP
516 cseat = session->seat ? session->seat->id : "";
517 vtnr = session->vtnr;
518 exists = true;
519
520 b = dbus_message_append_args(
521 reply,
522 DBUS_TYPE_STRING, &session->id,
fb6becb4 523 DBUS_TYPE_OBJECT_PATH, &path,
954449b8
LP
524 DBUS_TYPE_STRING, &session->user->runtime_path,
525 DBUS_TYPE_UNIX_FD, &fifo_fd,
526 DBUS_TYPE_STRING, &cseat,
527 DBUS_TYPE_UINT32, &vtnr,
528 DBUS_TYPE_BOOLEAN, &exists,
529 DBUS_TYPE_INVALID);
530 if (!b) {
531 r = -ENOMEM;
532 goto fail;
533 }
21c390cc 534
fb6becb4
LP
535 if (!dbus_connection_send(m->bus, reply, NULL)) {
536 r = -ENOMEM;
537 goto fail;
538 }
21c390cc 539
954449b8
LP
540 return 0;
541 }
21c390cc 542
954449b8
LP
543 audit_session_from_pid(leader, &audit_id);
544 if (audit_id > 0) {
545 /* Keep our session IDs and the audit session IDs in sync */
21c390cc 546
954449b8
LP
547 if (asprintf(&id, "%lu", (unsigned long) audit_id) < 0) {
548 r = -ENOMEM;
549 goto fail;
550 }
21c390cc 551
954449b8
LP
552 /* Wut? There's already a session by this name and we
553 * didn't find it above? Weird, then let's not trust
554 * the audit data and let's better register a new
555 * ID */
556 if (hashmap_get(m->sessions, id)) {
557 audit_id = 0;
8ea913b2 558
954449b8
LP
559 free(id);
560 id = NULL;
07714753 561 }
954449b8 562 }
07714753 563
954449b8 564 if (!id) {
07714753
LP
565 do {
566 free(id);
f8e2fb7b 567 id = NULL;
07714753 568
f8e2fb7b 569 if (asprintf(&id, "c%lu", ++m->session_counter) < 0) {
07714753
LP
570 r = -ENOMEM;
571 goto fail;
572 }
573
574 } while (hashmap_get(m->sessions, id));
98a28fef
LP
575 }
576
954449b8
LP
577 r = manager_add_user_by_uid(m, uid, &user);
578 if (r < 0)
579 goto fail;
580
9444b1f2 581 r = manager_add_session(m, id, &session);
98a28fef
LP
582 if (r < 0)
583 goto fail;
584
9444b1f2
LP
585 session_set_user(session, user);
586
98a28fef
LP
587 session->leader = leader;
588 session->audit_id = audit_id;
589 session->type = t;
55efac6c 590 session->class = c;
98a28fef 591 session->remote = remote;
98a28fef
LP
592 session->vtnr = vtnr;
593
98a28fef
LP
594 if (!isempty(tty)) {
595 session->tty = strdup(tty);
596 if (!session->tty) {
597 r = -ENOMEM;
598 goto fail;
599 }
600 }
601
602 if (!isempty(display)) {
603 session->display = strdup(display);
604 if (!session->display) {
605 r = -ENOMEM;
606 goto fail;
607 }
608 }
609
610 if (!isempty(remote_user)) {
611 session->remote_user = strdup(remote_user);
612 if (!session->remote_user) {
613 r = -ENOMEM;
614 goto fail;
615 }
616 }
617
618 if (!isempty(remote_host)) {
619 session->remote_host = strdup(remote_host);
620 if (!session->remote_host) {
621 r = -ENOMEM;
622 goto fail;
623 }
624 }
625
626 if (!isempty(service)) {
627 session->service = strdup(service);
628 if (!session->service) {
629 r = -ENOMEM;
630 goto fail;
631 }
632 }
633
954449b8
LP
634 if (seat) {
635 r = seat_attach_session(seat, session);
98a28fef
LP
636 if (r < 0)
637 goto fail;
638 }
639
640 r = session_start(session);
641 if (r < 0)
642 goto fail;
643
fb6becb4 644 session->create_message = dbus_message_ref(message);
98a28fef 645
cba38758
LP
646 /* Now, let's wait until the slice unit and stuff got
647 * created. We send the reply back from
648 * session_send_create_reply().*/
649
98a28fef
LP
650 return 0;
651
652fail:
98a28fef
LP
653 if (session)
654 session_add_to_gc_queue(session);
655
656 if (user)
657 user_add_to_gc_queue(user);
658
98a28fef
LP
659 return r;
660}
661
314b4b0a
LP
662static int bus_manager_inhibit(
663 Manager *m,
664 DBusConnection *connection,
665 DBusMessage *message,
666 DBusError *error,
667 DBusMessage **_reply) {
668
f8e2fb7b
LP
669 Inhibitor *i = NULL;
670 char *id = NULL;
eecd1362 671 const char *who, *why, *what, *mode;
f8e2fb7b
LP
672 pid_t pid;
673 InhibitWhat w;
eecd1362 674 InhibitMode mm;
f8e2fb7b
LP
675 unsigned long ul;
676 int r, fifo_fd = -1;
ce0fc5f5 677 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
f8e2fb7b
LP
678
679 assert(m);
680 assert(connection);
681 assert(message);
682 assert(error);
683 assert(_reply);
684
685 if (!dbus_message_get_args(
686 message,
687 error,
688 DBUS_TYPE_STRING, &what,
689 DBUS_TYPE_STRING, &who,
690 DBUS_TYPE_STRING, &why,
eecd1362 691 DBUS_TYPE_STRING, &mode,
f8e2fb7b
LP
692 DBUS_TYPE_INVALID)) {
693 r = -EIO;
694 goto fail;
695 }
696
697 w = inhibit_what_from_string(what);
698 if (w <= 0) {
699 r = -EINVAL;
700 goto fail;
701 }
702
eecd1362
LP
703 mm = inhibit_mode_from_string(mode);
704 if (mm < 0) {
705 r = -EINVAL;
706 goto fail;
707 }
708
beaafb2e
LP
709 /* Delay is only supported for shutdown/sleep */
710 if (mm == INHIBIT_DELAY && (w & ~(INHIBIT_SHUTDOWN|INHIBIT_SLEEP))) {
711 r = -EINVAL;
712 goto fail;
713 }
714
314b4b0a
LP
715 /* Don't allow taking delay locks while we are already
716 * executing the operation. We shouldn't create the impression
717 * that the lock was successful if the machine is about to go
718 * down/suspend any moment. */
719 if (m->action_what & w) {
720 r = -EALREADY;
721 goto fail;
722 }
723
eecd1362 724 r = verify_polkit(connection, message,
8e7fd6ad
LP
725 w == INHIBIT_SHUTDOWN ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
726 w == INHIBIT_SLEEP ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep" : "org.freedesktop.login1.inhibit-delay-sleep") :
727 w == INHIBIT_IDLE ? "org.freedesktop.login1.inhibit-block-idle" :
728 w == INHIBIT_HANDLE_POWER_KEY ? "org.freedesktop.login1.inhibit-handle-power-key" :
729 w == INHIBIT_HANDLE_SUSPEND_KEY ? "org.freedesktop.login1.inhibit-handle-suspend-key" :
730 w == INHIBIT_HANDLE_HIBERNATE_KEY ? "org.freedesktop.login1.inhibit-handle-hibernate-key" :
731 "org.freedesktop.login1.inhibit-handle-lid-switch",
b14eda96 732 false, NULL, error);
f8e2fb7b
LP
733 if (r < 0)
734 goto fail;
735
736 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
737 if (ul == (unsigned long) -1) {
738 r = -EIO;
739 goto fail;
740 }
741
742 pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
743 if (pid <= 0) {
744 r = -EIO;
745 goto fail;
746 }
747
748 do {
749 free(id);
750 id = NULL;
751
752 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
753 r = -ENOMEM;
754 goto fail;
755 }
756 } while (hashmap_get(m->inhibitors, id));
757
758 r = manager_add_inhibitor(m, id, &i);
759 free(id);
760
761 if (r < 0)
762 goto fail;
763
764 i->what = w;
eecd1362 765 i->mode = mm;
f8e2fb7b
LP
766 i->pid = pid;
767 i->uid = (uid_t) ul;
768 i->why = strdup(why);
769 i->who = strdup(who);
770
771 if (!i->why || !i->who) {
772 r = -ENOMEM;
773 goto fail;
774 }
775
776 fifo_fd = inhibitor_create_fifo(i);
777 if (fifo_fd < 0) {
778 r = fifo_fd;
779 goto fail;
780 }
781
782 reply = dbus_message_new_method_return(message);
783 if (!reply) {
784 r = -ENOMEM;
785 goto fail;
786 }
787
788 if (!dbus_message_append_args(
789 reply,
790 DBUS_TYPE_UNIX_FD, &fifo_fd,
791 DBUS_TYPE_INVALID)) {
792 r = -ENOMEM;
793 goto fail;
794 }
795
796 close_nointr_nofail(fifo_fd);
797 *_reply = reply;
ce0fc5f5 798 reply = NULL;
f8e2fb7b
LP
799
800 inhibitor_start(i);
801
802 return 0;
803
804fail:
805 if (i)
806 inhibitor_free(i);
807
808 if (fifo_fd >= 0)
809 close_nointr_nofail(fifo_fd);
810
f8e2fb7b
LP
811 return r;
812}
813
2eb916cd 814static int trigger_device(Manager *m, struct udev_device *d) {
b668e064
LP
815 struct udev_enumerate *e;
816 struct udev_list_entry *first, *item;
817 int r;
818
819 assert(m);
820
821 e = udev_enumerate_new(m->udev);
822 if (!e) {
823 r = -ENOMEM;
824 goto finish;
825 }
826
2eb916cd
LP
827 if (d) {
828 if (udev_enumerate_add_match_parent(e, d) < 0) {
829 r = -EIO;
830 goto finish;
831 }
832 }
833
b668e064
LP
834 if (udev_enumerate_scan_devices(e) < 0) {
835 r = -EIO;
836 goto finish;
837 }
838
839 first = udev_enumerate_get_list_entry(e);
840 udev_list_entry_foreach(item, first) {
841 char *t;
842 const char *p;
843
844 p = udev_list_entry_get_name(item);
845
b668e064
LP
846 t = strappend(p, "/uevent");
847 if (!t) {
848 r = -ENOMEM;
849 goto finish;
850 }
851
574d5f2d 852 write_string_file(t, "change");
b668e064
LP
853 free(t);
854 }
855
856 r = 0;
857
858finish:
859 if (e)
860 udev_enumerate_unref(e);
861
862 return r;
863}
864
47a26690
LP
865static int attach_device(Manager *m, const char *seat, const char *sysfs) {
866 struct udev_device *d;
7fd1b19b 867 _cleanup_free_ char *rule = NULL, *file = NULL;
c28fa3d3 868 const char *id_for_seat;
47a26690
LP
869 int r;
870
871 assert(m);
872 assert(seat);
873 assert(sysfs);
874
875 d = udev_device_new_from_syspath(m->udev, sysfs);
876 if (!d)
877 return -ENODEV;
878
309c2a2c 879 if (!udev_device_has_tag(d, "seat")) {
47a26690
LP
880 r = -ENODEV;
881 goto finish;
882 }
883
c28fa3d3
LP
884 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
885 if (!id_for_seat) {
47a26690
LP
886 r = -ENODEV;
887 goto finish;
888 }
889
c28fa3d3 890 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
47a26690
LP
891 r = -ENOMEM;
892 goto finish;
893 }
894
c28fa3d3 895 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
47a26690
LP
896 r = -ENOMEM;
897 goto finish;
898 }
899
d2e54fae 900 mkdir_p_label("/etc/udev/rules.d", 0755);
a5c32cff 901 label_init("/etc");
574d5f2d 902 r = write_string_file_atomic_label(file, rule);
a0a0c7f1
LP
903 if (r < 0)
904 goto finish;
905
2eb916cd 906 r = trigger_device(m, d);
47a26690
LP
907
908finish:
47a26690
LP
909 if (d)
910 udev_device_unref(d);
911
912 return r;
913}
914
b668e064 915static int flush_devices(Manager *m) {
7fd1b19b 916 _cleanup_closedir_ DIR *d;
b668e064
LP
917
918 assert(m);
919
920 d = opendir("/etc/udev/rules.d");
921 if (!d) {
922 if (errno != ENOENT)
923 log_warning("Failed to open /etc/udev/rules.d: %m");
924 } else {
925 struct dirent *de;
926
927 while ((de = readdir(d))) {
928
929 if (!dirent_is_file(de))
930 continue;
931
932 if (!startswith(de->d_name, "72-seat-"))
933 continue;
934
935 if (!endswith(de->d_name, ".rules"))
936 continue;
937
938 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
939 log_warning("Failed to unlink %s: %m", de->d_name);
940 }
b668e064
LP
941 }
942
943 return trigger_device(m, NULL);
944}
945
89f13440 946static int have_multiple_sessions(
89f13440 947 Manager *m,
409133be 948 uid_t uid) {
89f13440 949
2154761f
MS
950 Session *session;
951 Iterator i;
89f13440
LP
952
953 assert(m);
954
1ca04b87
LP
955 /* Check for other users' sessions. Greeter sessions do not
956 * count, and non-login sessions do not count either. */
2154761f 957 HASHMAP_FOREACH(session, m->sessions, i)
1ca04b87 958 if (session->class == SESSION_USER &&
1ca04b87 959 session->user->uid != uid)
2154761f 960 return true;
89f13440
LP
961
962 return false;
963}
964
314b4b0a
LP
965static int bus_manager_log_shutdown(
966 Manager *m,
967 InhibitWhat w,
968 const char *unit_name) {
969
970 const char *p, *q;
971
972 assert(m);
973 assert(unit_name);
974
975 if (w != INHIBIT_SHUTDOWN)
976 return 0;
977
978 if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
979 p = "MESSAGE=System is powering down.";
980 q = "SHUTDOWN=power-off";
981 } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
982 p = "MESSAGE=System is halting.";
983 q = "SHUTDOWN=halt";
984 } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
985 p = "MESSAGE=System is rebooting.";
986 q = "SHUTDOWN=reboot";
987 } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
988 p = "MESSAGE=System is rebooting with kexec.";
989 q = "SHUTDOWN=kexec";
990 } else {
991 p = "MESSAGE=System is shutting down.";
992 q = NULL;
993 }
994
995 return log_struct(LOG_NOTICE, MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
996 p,
997 q, NULL);
998}
999
1000static int execute_shutdown_or_sleep(
1001 Manager *m,
1002 InhibitWhat w,
1003 const char *unit_name,
1004 DBusError *error) {
1005
af9792ac 1006 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
b85bddda 1007 const char *mode = "replace-irreversibly", *p;
af9792ac
LP
1008 int r;
1009 char *c;
eecd1362 1010
af9792ac 1011 assert(m);
314b4b0a
LP
1012 assert(w >= 0);
1013 assert(w < _INHIBIT_WHAT_MAX);
d889a206 1014 assert(unit_name);
eecd1362 1015
314b4b0a
LP
1016 bus_manager_log_shutdown(m, w, unit_name);
1017
af9792ac
LP
1018 r = bus_method_call_with_reply(
1019 m->bus,
eecd1362
LP
1020 "org.freedesktop.systemd1",
1021 "/org/freedesktop/systemd1",
1022 "org.freedesktop.systemd1.Manager",
b9c26b41 1023 "StartUnit",
af9792ac
LP
1024 &reply,
1025 error,
b9c26b41
SP
1026 DBUS_TYPE_STRING, &unit_name,
1027 DBUS_TYPE_STRING, &mode,
1028 DBUS_TYPE_INVALID);
af9792ac
LP
1029 if (r < 0)
1030 return r;
1031
1032 if (!dbus_message_get_args(
1033 reply,
1034 error,
1035 DBUS_TYPE_OBJECT_PATH, &p,
1036 DBUS_TYPE_INVALID))
1037 return -EINVAL;
1038
1039 c = strdup(p);
1040 if (!c)
1041 return -ENOMEM;
1042
314b4b0a 1043 m->action_unit = unit_name;
af9792ac
LP
1044 free(m->action_job);
1045 m->action_job = c;
314b4b0a 1046 m->action_what = w;
af9792ac
LP
1047
1048 return 0;
eecd1362
LP
1049}
1050
314b4b0a
LP
1051static int delay_shutdown_or_sleep(
1052 Manager *m,
1053 InhibitWhat w,
1054 const char *unit_name) {
eecd1362 1055
eecd1362 1056 assert(m);
d889a206
LP
1057 assert(w >= 0);
1058 assert(w < _INHIBIT_WHAT_MAX);
314b4b0a 1059 assert(unit_name);
eecd1362 1060
314b4b0a
LP
1061 m->action_timestamp = now(CLOCK_MONOTONIC);
1062 m->action_unit = unit_name;
1063 m->action_what = w;
d889a206
LP
1064
1065 return 0;
1066}
1067
1068static int bus_manager_can_shutdown_or_sleep(
1069 Manager *m,
1070 DBusConnection *connection,
1071 DBusMessage *message,
1072 InhibitWhat w,
1073 const char *action,
1074 const char *action_multiple_sessions,
1075 const char *action_ignore_inhibit,
19adb8a3 1076 const char *sleep_verb,
d889a206
LP
1077 DBusError *error,
1078 DBusMessage **_reply) {
1079
1080 bool multiple_sessions, challenge, blocked, b;
7f643797 1081 const char *result = NULL;
ce0fc5f5 1082 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
d889a206 1083 int r;
409133be 1084 unsigned long ul;
d889a206
LP
1085
1086 assert(m);
1087 assert(connection);
1088 assert(message);
1089 assert(w >= 0);
1090 assert(w <= _INHIBIT_WHAT_MAX);
1091 assert(action);
1092 assert(action_multiple_sessions);
1093 assert(action_ignore_inhibit);
1094 assert(error);
1095 assert(_reply);
1096
19adb8a3
ZJS
1097 if (sleep_verb) {
1098 r = can_sleep(sleep_verb);
d889a206
LP
1099 if (r < 0)
1100 return r;
6524990f
LP
1101 if (r == 0) {
1102 result = "na";
1103 goto finish;
1104 }
1105 }
1106
409133be
LP
1107 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1108 if (ul == (unsigned long) -1)
1109 return -EIO;
1110
1111 r = have_multiple_sessions(m, (uid_t) ul);
d889a206
LP
1112 if (r < 0)
1113 return r;
1114
1115 multiple_sessions = r > 0;
409133be 1116 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
d889a206
LP
1117
1118 if (multiple_sessions) {
1119 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1120 if (r < 0)
1121 return r;
1122
1123 if (r > 0)
1124 result = "yes";
d5a745df
LP
1125 else if (challenge)
1126 result = "challenge";
1127 else
1128 result = "no";
1129 }
d889a206
LP
1130
1131 if (blocked) {
1132 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1133 if (r < 0)
1134 return r;
1135
1136 if (r > 0 && !result)
1137 result = "yes";
1138 else if (challenge && (!result || streq(result, "yes")))
1139 result = "challenge";
1140 else
1141 result = "no";
1142 }
1143
1144 if (!multiple_sessions && !blocked) {
1145 /* If neither inhibit nor multiple sessions
1146 * apply then just check the normal policy */
1147
1148 r = verify_polkit(connection, message, action, false, &challenge, error);
1149 if (r < 0)
1150 return r;
1151
1152 if (r > 0)
1153 result = "yes";
1154 else if (challenge)
1155 result = "challenge";
1156 else
1157 result = "no";
1158 }
1159
1160finish:
1161 reply = dbus_message_new_method_return(message);
1162 if (!reply)
1163 return -ENOMEM;
1164
1165 b = dbus_message_append_args(
1166 reply,
1167 DBUS_TYPE_STRING, &result,
1168 DBUS_TYPE_INVALID);
4654e558 1169 if (!b)
d889a206 1170 return -ENOMEM;
d889a206
LP
1171
1172 *_reply = reply;
ce0fc5f5 1173 reply = NULL;
d889a206
LP
1174 return 0;
1175}
1176
314b4b0a
LP
1177static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
1178 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
1179 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
1180 [INHIBIT_SLEEP] = "PrepareForSleep"
1181 };
877d54e9 1182
314b4b0a
LP
1183 dbus_bool_t active = _active;
1184 _cleanup_dbus_message_unref_ DBusMessage *message = NULL;
877d54e9
LP
1185
1186 assert(m);
314b4b0a
LP
1187 assert(w >= 0);
1188 assert(w < _INHIBIT_WHAT_MAX);
1189 assert(signal_name[w]);
877d54e9 1190
314b4b0a
LP
1191 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1192 if (!message)
1193 return -ENOMEM;
877d54e9 1194
314b4b0a
LP
1195 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1196 !dbus_connection_send(m->bus, message, NULL))
1197 return -ENOMEM;
877d54e9 1198
314b4b0a 1199 return 0;
877d54e9
LP
1200}
1201
069cfc85
LP
1202int bus_manager_shutdown_or_sleep_now_or_later(
1203 Manager *m,
1204 const char *unit_name,
1205 InhibitWhat w,
1206 DBusError *error) {
1207
1208 bool delayed;
1209 int r;
1210
1211 assert(m);
1212 assert(unit_name);
1213 assert(w >= 0);
1214 assert(w <= _INHIBIT_WHAT_MAX);
af9792ac 1215 assert(!m->action_job);
069cfc85 1216
314b4b0a
LP
1217 /* Tell everybody to prepare for shutdown/sleep */
1218 send_prepare_for(m, w, true);
1219
069cfc85
LP
1220 delayed =
1221 m->inhibit_delay_max > 0 &&
409133be 1222 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0);
069cfc85
LP
1223
1224 if (delayed)
1225 /* Shutdown is delayed, keep in mind what we
1226 * want to do, and start a timeout */
1227 r = delay_shutdown_or_sleep(m, w, unit_name);
314b4b0a 1228 else
069cfc85
LP
1229 /* Shutdown is not delayed, execute it
1230 * immediately */
314b4b0a 1231 r = execute_shutdown_or_sleep(m, w, unit_name, error);
069cfc85
LP
1232
1233 return r;
1234}
1235
d889a206
LP
1236static int bus_manager_do_shutdown_or_sleep(
1237 Manager *m,
1238 DBusConnection *connection,
1239 DBusMessage *message,
1240 const char *unit_name,
1241 InhibitWhat w,
1242 const char *action,
1243 const char *action_multiple_sessions,
1244 const char *action_ignore_inhibit,
19adb8a3 1245 const char *sleep_verb,
d889a206
LP
1246 DBusError *error,
1247 DBusMessage **_reply) {
1248
1249 dbus_bool_t interactive;
069cfc85 1250 bool multiple_sessions, blocked;
d889a206
LP
1251 DBusMessage *reply = NULL;
1252 int r;
409133be 1253 unsigned long ul;
d889a206
LP
1254
1255 assert(m);
1256 assert(connection);
1257 assert(message);
1258 assert(unit_name);
1259 assert(w >= 0);
1260 assert(w <= _INHIBIT_WHAT_MAX);
1261 assert(action);
1262 assert(action_multiple_sessions);
1263 assert(action_ignore_inhibit);
1264 assert(error);
1265 assert(_reply);
1266
314b4b0a
LP
1267 /* Don't allow multiple jobs being executed at the same time */
1268 if (m->action_what)
af9792ac
LP
1269 return -EALREADY;
1270
d889a206
LP
1271 if (!dbus_message_get_args(
1272 message,
1273 error,
1274 DBUS_TYPE_BOOLEAN, &interactive,
1275 DBUS_TYPE_INVALID))
1276 return -EINVAL;
1277
19adb8a3
ZJS
1278 if (sleep_verb) {
1279 r = can_sleep(sleep_verb);
6524990f
LP
1280 if (r < 0)
1281 return r;
1282
1283 if (r == 0)
1284 return -ENOTSUP;
1285 }
1286
409133be
LP
1287 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1288 if (ul == (unsigned long) -1)
1289 return -EIO;
1290
1291 r = have_multiple_sessions(m, (uid_t) ul);
d889a206
LP
1292 if (r < 0)
1293 return r;
1294
1295 multiple_sessions = r > 0;
409133be 1296 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
d889a206
LP
1297
1298 if (multiple_sessions) {
1299 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1300 if (r < 0)
1301 return r;
1302 }
1303
1304 if (blocked) {
1305 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1306 if (r < 0)
1307 return r;
1308 }
1309
1310 if (!multiple_sessions && !blocked) {
1311 r = verify_polkit(connection, message, action, interactive, NULL, error);
1312 if (r < 0)
1313 return r;
1314 }
1315
069cfc85 1316 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
d889a206
LP
1317 if (r < 0)
1318 return r;
1319
1320 reply = dbus_message_new_method_return(message);
1321 if (!reply)
1322 return -ENOMEM;
eecd1362 1323
d889a206 1324 *_reply = reply;
eecd1362
LP
1325 return 0;
1326}
1327
23406ce5 1328static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_action, handle_action, HandleAction);
069cfc85 1329
d200735e 1330static const BusProperty bus_login_manager_properties[] = {
d200735e
MS
1331 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1332 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1333 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1334 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1335 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1336 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1337 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
eecd1362
LP
1338 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1339 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1340 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
23406ce5
LP
1341 { "HandlePowerKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_power_key) },
1342 { "HandleSuspendKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_suspend_key) },
1343 { "HandleHibernateKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_hibernate_key)},
1344 { "HandleLidSwitch", bus_manager_append_handle_action, "s", offsetof(Manager, handle_lid_switch) },
1345 { "IdleAction", bus_manager_append_handle_action, "s", offsetof(Manager, idle_action) },
1346 { "IdleActionUSec", bus_property_append_usec, "t", offsetof(Manager, idle_action_usec) },
5e4a79da
LP
1347 { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
1348 { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
d200735e
MS
1349 { NULL, }
1350};
1351
3f49d45a
LP
1352static DBusHandlerResult manager_message_handler(
1353 DBusConnection *connection,
1354 DBusMessage *message,
1355 void *userdata) {
1356
1357 Manager *m = userdata;
1358
3f49d45a 1359 DBusError error;
ce0fc5f5 1360 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
bef422ae 1361 int r;
3f49d45a
LP
1362
1363 assert(connection);
1364 assert(message);
1365 assert(m);
1366
1367 dbus_error_init(&error);
1368
bef422ae
LP
1369 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1370 const char *name;
1371 char *p;
1372 Session *session;
1373 bool b;
1374
1375 if (!dbus_message_get_args(
1376 message,
1377 &error,
1378 DBUS_TYPE_STRING, &name,
1379 DBUS_TYPE_INVALID))
1380 return bus_send_error_reply(connection, message, &error, -EINVAL);
1381
1382 session = hashmap_get(m->sessions, name);
1383 if (!session)
1384 return bus_send_error_reply(connection, message, &error, -ENOENT);
1385
1386 reply = dbus_message_new_method_return(message);
1387 if (!reply)
1388 goto oom;
1389
1390 p = session_bus_path(session);
c4aa65e7
LP
1391 if (!p)
1392 goto oom;
1393
1394 b = dbus_message_append_args(
1395 reply,
1396 DBUS_TYPE_OBJECT_PATH, &p,
1397 DBUS_TYPE_INVALID);
1398 free(p);
1399
1400 if (!b)
1401 goto oom;
1402
1403 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1404 uint32_t pid;
1405 char *p;
1406 Session *session;
1407 bool b;
1408
1409 if (!dbus_message_get_args(
1410 message,
1411 &error,
1412 DBUS_TYPE_UINT32, &pid,
1413 DBUS_TYPE_INVALID))
1414 return bus_send_error_reply(connection, message, &error, -EINVAL);
1415
1416 r = manager_get_session_by_pid(m, pid, &session);
1417 if (r <= 0)
1418 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1419
1420 reply = dbus_message_new_method_return(message);
1421 if (!reply)
1422 goto oom;
1423
1424 p = session_bus_path(session);
bef422ae
LP
1425 if (!p)
1426 goto oom;
1427
1428 b = dbus_message_append_args(
1429 reply,
1430 DBUS_TYPE_OBJECT_PATH, &p,
1431 DBUS_TYPE_INVALID);
1432 free(p);
1433
1434 if (!b)
1435 goto oom;
1436
1437 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1438 uint32_t uid;
1439 char *p;
1440 User *user;
1441 bool b;
1442
1443 if (!dbus_message_get_args(
1444 message,
1445 &error,
1446 DBUS_TYPE_UINT32, &uid,
1447 DBUS_TYPE_INVALID))
1448 return bus_send_error_reply(connection, message, &error, -EINVAL);
1449
1450 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1451 if (!user)
1452 return bus_send_error_reply(connection, message, &error, -ENOENT);
1453
1454 reply = dbus_message_new_method_return(message);
1455 if (!reply)
1456 goto oom;
1457
1458 p = user_bus_path(user);
1459 if (!p)
1460 goto oom;
1461
1462 b = dbus_message_append_args(
1463 reply,
1464 DBUS_TYPE_OBJECT_PATH, &p,
1465 DBUS_TYPE_INVALID);
1466 free(p);
1467
1468 if (!b)
1469 goto oom;
1470
9444b1f2
LP
1471 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUserByPID")) {
1472 uint32_t pid;
1473 char *p;
1474 User *user;
1475 bool b;
1476
1477 if (!dbus_message_get_args(
1478 message,
1479 &error,
1480 DBUS_TYPE_UINT32, &pid,
1481 DBUS_TYPE_INVALID))
1482 return bus_send_error_reply(connection, message, &error, -EINVAL);
1483
1484 r = manager_get_user_by_pid(m, pid, &user);
1485 if (r <= 0)
1486 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1487
1488 reply = dbus_message_new_method_return(message);
1489 if (!reply)
1490 goto oom;
1491
1492 p = user_bus_path(user);
1493 if (!p)
1494 goto oom;
1495
1496 b = dbus_message_append_args(
1497 reply,
1498 DBUS_TYPE_OBJECT_PATH, &p,
1499 DBUS_TYPE_INVALID);
1500 free(p);
1501
9444b1f2
LP
1502 if (!b)
1503 goto oom;
1504
bef422ae
LP
1505 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1506 const char *name;
1507 char *p;
1508 Seat *seat;
1509 bool b;
1510
1511 if (!dbus_message_get_args(
1512 message,
1513 &error,
1514 DBUS_TYPE_STRING, &name,
1515 DBUS_TYPE_INVALID))
1516 return bus_send_error_reply(connection, message, &error, -EINVAL);
1517
1518 seat = hashmap_get(m->seats, name);
1519 if (!seat)
1520 return bus_send_error_reply(connection, message, &error, -ENOENT);
1521
1522 reply = dbus_message_new_method_return(message);
1523 if (!reply)
1524 goto oom;
1525
1526 p = seat_bus_path(seat);
1527 if (!p)
1528 goto oom;
1529
1530 b = dbus_message_append_args(
1531 reply,
1532 DBUS_TYPE_OBJECT_PATH, &p,
1533 DBUS_TYPE_INVALID);
1534 free(p);
1535
1536 if (!b)
1537 goto oom;
1538
e1c9c2d5
LP
1539 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1540 char *p;
1541 Session *session;
1542 Iterator i;
1543 DBusMessageIter iter, sub;
1544 const char *empty = "";
1545
1546 reply = dbus_message_new_method_return(message);
1547 if (!reply)
1548 goto oom;
1549
1550 dbus_message_iter_init_append(reply, &iter);
1551
dec15e92 1552 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
e1c9c2d5
LP
1553 goto oom;
1554
1555 HASHMAP_FOREACH(session, m->sessions, i) {
1556 DBusMessageIter sub2;
1557 uint32_t uid;
1558
1559 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1560 goto oom;
1561
1562 uid = session->user->uid;
1563
1564 p = session_bus_path(session);
1565 if (!p)
1566 goto oom;
1567
1568 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1569 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1570 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1571 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1572 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1573 free(p);
1574 goto oom;
1575 }
1576
1577 free(p);
1578
1579 if (!dbus_message_iter_close_container(&sub, &sub2))
1580 goto oom;
1581 }
1582
1583 if (!dbus_message_iter_close_container(&iter, &sub))
1584 goto oom;
1585
1586 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
e1c9c2d5
LP
1587 User *user;
1588 Iterator i;
1589 DBusMessageIter iter, sub;
1590
1591 reply = dbus_message_new_method_return(message);
1592 if (!reply)
1593 goto oom;
1594
1595 dbus_message_iter_init_append(reply, &iter);
1596
dec15e92 1597 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
e1c9c2d5
LP
1598 goto oom;
1599
1600 HASHMAP_FOREACH(user, m->users, i) {
9444b1f2 1601 _cleanup_free_ char *p = NULL;
e1c9c2d5
LP
1602 DBusMessageIter sub2;
1603 uint32_t uid;
1604
1605 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1606 goto oom;
1607
1608 uid = user->uid;
1609
1610 p = user_bus_path(user);
1611 if (!p)
1612 goto oom;
1613
1614 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1615 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1616 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1617 free(p);
1618 goto oom;
1619 }
1620
e1c9c2d5
LP
1621 if (!dbus_message_iter_close_container(&sub, &sub2))
1622 goto oom;
1623 }
1624
1625 if (!dbus_message_iter_close_container(&iter, &sub))
1626 goto oom;
1627
1628 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
e1c9c2d5
LP
1629 Seat *seat;
1630 Iterator i;
1631 DBusMessageIter iter, sub;
1632
1633 reply = dbus_message_new_method_return(message);
1634 if (!reply)
1635 goto oom;
1636
1637 dbus_message_iter_init_append(reply, &iter);
1638
dec15e92 1639 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
e1c9c2d5
LP
1640 goto oom;
1641
1642 HASHMAP_FOREACH(seat, m->seats, i) {
9444b1f2 1643 _cleanup_free_ char *p = NULL;
e1c9c2d5
LP
1644 DBusMessageIter sub2;
1645
1646 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1647 goto oom;
1648
1649 p = seat_bus_path(seat);
1650 if (!p)
1651 goto oom;
1652
1653 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1654 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1655 free(p);
1656 goto oom;
1657 }
1658
e1c9c2d5
LP
1659 if (!dbus_message_iter_close_container(&sub, &sub2))
1660 goto oom;
1661 }
1662
1663 if (!dbus_message_iter_close_container(&iter, &sub))
1664 goto oom;
1665
f8e2fb7b
LP
1666 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1667 Inhibitor *inhibitor;
1668 Iterator i;
1669 DBusMessageIter iter, sub;
1670
1671 reply = dbus_message_new_method_return(message);
1672 if (!reply)
1673 goto oom;
1674
1675 dbus_message_iter_init_append(reply, &iter);
1676
eecd1362 1677 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
f8e2fb7b
LP
1678 goto oom;
1679
1680 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1681 DBusMessageIter sub2;
1682 dbus_uint32_t uid, pid;
eecd1362 1683 const char *what, *who, *why, *mode;
f8e2fb7b
LP
1684
1685 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1686 goto oom;
1687
eecd1362 1688 what = strempty(inhibit_what_to_string(inhibitor->what));
f8e2fb7b
LP
1689 who = strempty(inhibitor->who);
1690 why = strempty(inhibitor->why);
eecd1362 1691 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
f8e2fb7b
LP
1692 uid = (dbus_uint32_t) inhibitor->uid;
1693 pid = (dbus_uint32_t) inhibitor->pid;
1694
1695 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1696 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1697 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
eecd1362 1698 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
f8e2fb7b
LP
1699 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1700 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1701 goto oom;
1702
1703 if (!dbus_message_iter_close_container(&sub, &sub2))
1704 goto oom;
1705 }
1706
1707 if (!dbus_message_iter_close_container(&iter, &sub))
1708 goto oom;
1709
9444b1f2 1710
f8e2fb7b
LP
1711 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1712
1713 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1714
1715 if (r < 0)
1716 return bus_send_error_reply(connection, message, &error, r);
1717
1718
98a28fef
LP
1719 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1720
fb6becb4 1721 r = bus_manager_create_session(m, message);
688c56ff
LP
1722
1723 /* Don't delay the work on OOM here, since it might be
1724 * triggered by a low RLIMIT_NOFILE here (since we
1725 * send a dupped fd to the client), and we'd rather
1726 * see this fail quickly then be retried later */
98a28fef
LP
1727
1728 if (r < 0)
f8e2fb7b 1729 return bus_send_error_reply(connection, message, NULL, r);
fb6becb4 1730
75c8e3cf
LP
1731 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1732 const char *name;
1733 Session *session;
1734
1735 if (!dbus_message_get_args(
1736 message,
1737 &error,
1738 DBUS_TYPE_STRING, &name,
1739 DBUS_TYPE_INVALID))
1740 return bus_send_error_reply(connection, message, &error, -EINVAL);
1741
1742 session = hashmap_get(m->sessions, name);
1743 if (!session)
1744 return bus_send_error_reply(connection, message, &error, -ENOENT);
1745
1746 /* We use the FIFO to detect stray sessions where the
1747 process invoking PAM dies abnormally. We need to make
1748 sure that that process is not killed if at the clean
1749 end of the session it closes the FIFO. Hence, with
1750 this call explicitly turn off the FIFO logic, so that
1751 the PAM code can finish clean up on its own */
1752 session_remove_fifo(session);
1753
1754 reply = dbus_message_new_method_return(message);
1755 if (!reply)
1756 goto oom;
1757
bef422ae
LP
1758 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1759 const char *name;
1760 Session *session;
1761
1762 if (!dbus_message_get_args(
1763 message,
1764 &error,
1765 DBUS_TYPE_STRING, &name,
1766 DBUS_TYPE_INVALID))
1767 return bus_send_error_reply(connection, message, &error, -EINVAL);
1768
1769 session = hashmap_get(m->sessions, name);
1770 if (!session)
1771 return bus_send_error_reply(connection, message, &error, -ENOENT);
1772
1773 r = session_activate(session);
1774 if (r < 0)
1775 return bus_send_error_reply(connection, message, NULL, r);
1776
1777 reply = dbus_message_new_method_return(message);
1778 if (!reply)
1779 goto oom;
1780
84c3361e
LP
1781 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1782 const char *session_name, *seat_name;
1783 Session *session;
1784 Seat *seat;
1785
1786 /* Same as ActivateSession() but refuses to work if
1787 * the seat doesn't match */
1788
1789 if (!dbus_message_get_args(
1790 message,
1791 &error,
1792 DBUS_TYPE_STRING, &session_name,
1793 DBUS_TYPE_STRING, &seat_name,
1794 DBUS_TYPE_INVALID))
1795 return bus_send_error_reply(connection, message, &error, -EINVAL);
1796
1797 session = hashmap_get(m->sessions, session_name);
1798 if (!session)
1799 return bus_send_error_reply(connection, message, &error, -ENOENT);
1800
1801 seat = hashmap_get(m->seats, seat_name);
1802 if (!seat)
1803 return bus_send_error_reply(connection, message, &error, -ENOENT);
1804
1805 if (session->seat != seat)
1806 return bus_send_error_reply(connection, message, &error, -EINVAL);
1807
1808 r = session_activate(session);
1809 if (r < 0)
1810 return bus_send_error_reply(connection, message, NULL, r);
1811
1812 reply = dbus_message_new_method_return(message);
1813 if (!reply)
1814 goto oom;
1815
88e3dc90
LP
1816 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1817 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1818 const char *name;
1819 Session *session;
1820
1821 if (!dbus_message_get_args(
1822 message,
1823 &error,
1824 DBUS_TYPE_STRING, &name,
1825 DBUS_TYPE_INVALID))
1826 return bus_send_error_reply(connection, message, &error, -EINVAL);
1827
1828 session = hashmap_get(m->sessions, name);
1829 if (!session)
7ba64386 1830 return bus_send_error_reply(connection, message, NULL, -ENOENT);
88e3dc90
LP
1831
1832 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1833 goto oom;
1834
1835 reply = dbus_message_new_method_return(message);
1836 if (!reply)
1837 goto oom;
1838
b6160029
LP
1839 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions") ||
1840 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSessions")) {
1841
1842 r = session_send_lock_all(m, streq(dbus_message_get_member(message), "LockSessions"));
7ba64386
LP
1843 if (r < 0)
1844 bus_send_error_reply(connection, message, NULL, r);
fa2b196d
LP
1845
1846 reply = dbus_message_new_method_return(message);
1847 if (!reply)
1848 goto oom;
1849
de07ab16
LP
1850 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1851 const char *swho;
1852 int32_t signo;
1853 KillWho who;
1854 const char *name;
1855 Session *session;
1856
1857 if (!dbus_message_get_args(
1858 message,
1859 &error,
1860 DBUS_TYPE_STRING, &name,
1861 DBUS_TYPE_STRING, &swho,
1862 DBUS_TYPE_INT32, &signo,
1863 DBUS_TYPE_INVALID))
1864 return bus_send_error_reply(connection, message, &error, -EINVAL);
1865
1866 if (isempty(swho))
1867 who = KILL_ALL;
1868 else {
1869 who = kill_who_from_string(swho);
1870 if (who < 0)
1871 return bus_send_error_reply(connection, message, &error, -EINVAL);
1872 }
1873
1874 if (signo <= 0 || signo >= _NSIG)
1875 return bus_send_error_reply(connection, message, &error, -EINVAL);
1876
1877 session = hashmap_get(m->sessions, name);
1878 if (!session)
1879 return bus_send_error_reply(connection, message, &error, -ENOENT);
1880
1881 r = session_kill(session, who, signo);
1882 if (r < 0)
1883 return bus_send_error_reply(connection, message, NULL, r);
1884
1885 reply = dbus_message_new_method_return(message);
1886 if (!reply)
1887 goto oom;
1888
1889 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1890 uint32_t uid;
1891 User *user;
1892 int32_t signo;
1893
1894 if (!dbus_message_get_args(
1895 message,
1896 &error,
1897 DBUS_TYPE_UINT32, &uid,
1898 DBUS_TYPE_INT32, &signo,
1899 DBUS_TYPE_INVALID))
1900 return bus_send_error_reply(connection, message, &error, -EINVAL);
1901
1902 if (signo <= 0 || signo >= _NSIG)
1903 return bus_send_error_reply(connection, message, &error, -EINVAL);
1904
1905 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1906 if (!user)
1907 return bus_send_error_reply(connection, message, &error, -ENOENT);
1908
1909 r = user_kill(user, signo);
1910 if (r < 0)
1911 return bus_send_error_reply(connection, message, NULL, r);
1912
1913 reply = dbus_message_new_method_return(message);
1914 if (!reply)
1915 goto oom;
1916
bef422ae
LP
1917 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1918 const char *name;
1919 Session *session;
1920
1921 if (!dbus_message_get_args(
1922 message,
1923 &error,
1924 DBUS_TYPE_STRING, &name,
1925 DBUS_TYPE_INVALID))
1926 return bus_send_error_reply(connection, message, &error, -EINVAL);
1927
1928 session = hashmap_get(m->sessions, name);
1929 if (!session)
1930 return bus_send_error_reply(connection, message, &error, -ENOENT);
1931
1932 r = session_stop(session);
1933 if (r < 0)
1934 return bus_send_error_reply(connection, message, NULL, r);
1935
1936 reply = dbus_message_new_method_return(message);
1937 if (!reply)
1938 goto oom;
1939
1940 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1941 uint32_t uid;
1942 User *user;
1943
1944 if (!dbus_message_get_args(
1945 message,
1946 &error,
1947 DBUS_TYPE_UINT32, &uid,
1948 DBUS_TYPE_INVALID))
1949 return bus_send_error_reply(connection, message, &error, -EINVAL);
1950
1951 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1952 if (!user)
1953 return bus_send_error_reply(connection, message, &error, -ENOENT);
1954
1955 r = user_stop(user);
1956 if (r < 0)
1957 return bus_send_error_reply(connection, message, NULL, r);
1958
1959 reply = dbus_message_new_method_return(message);
1960 if (!reply)
1961 goto oom;
1962
1963 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1964 const char *name;
1965 Seat *seat;
1966
1967 if (!dbus_message_get_args(
1968 message,
1969 &error,
1970 DBUS_TYPE_STRING, &name,
1971 DBUS_TYPE_INVALID))
1972 return bus_send_error_reply(connection, message, &error, -EINVAL);
1973
1974 seat = hashmap_get(m->seats, name);
1975 if (!seat)
1976 return bus_send_error_reply(connection, message, &error, -ENOENT);
1977
1978 r = seat_stop_sessions(seat);
1979 if (r < 0)
1980 return bus_send_error_reply(connection, message, NULL, r);
1981
1982 reply = dbus_message_new_method_return(message);
1983 if (!reply)
1984 goto oom;
1985
7f7bb946
LP
1986 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
1987 uint32_t uid;
1988 struct passwd *pw;
1989 dbus_bool_t b, interactive;
1990 char *path;
1991
1992 if (!dbus_message_get_args(
1993 message,
1994 &error,
1995 DBUS_TYPE_UINT32, &uid,
1996 DBUS_TYPE_BOOLEAN, &b,
1997 DBUS_TYPE_BOOLEAN, &interactive,
1998 DBUS_TYPE_INVALID))
1999 return bus_send_error_reply(connection, message, &error, -EINVAL);
2000
2001 errno = 0;
2002 pw = getpwuid(uid);
2003 if (!pw)
2004 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
2005
89f13440 2006 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
7f7bb946
LP
2007 if (r < 0)
2008 return bus_send_error_reply(connection, message, &error, r);
2009
d2e54fae 2010 mkdir_p_label("/var/lib/systemd", 0755);
02b16a19 2011
d2e54fae 2012 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
7f7bb946
LP
2013 if (r < 0)
2014 return bus_send_error_reply(connection, message, &error, r);
2015
2016 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
2017 if (!path)
2018 goto oom;
2019
2020 if (b) {
38f3fc7d
LP
2021 User *u;
2022
7f7bb946
LP
2023 r = touch(path);
2024 free(path);
2025
2026 if (r < 0)
2027 return bus_send_error_reply(connection, message, &error, r);
38f3fc7d
LP
2028
2029 if (manager_add_user_by_uid(m, uid, &u) >= 0)
2030 user_start(u);
2031
7f7bb946 2032 } else {
38f3fc7d
LP
2033 User *u;
2034
7f7bb946
LP
2035 r = unlink(path);
2036 free(path);
2037
2038 if (r < 0 && errno != ENOENT)
2039 return bus_send_error_reply(connection, message, &error, -errno);
38f3fc7d
LP
2040
2041 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
2042 if (u)
2043 user_add_to_gc_queue(u);
7f7bb946
LP
2044 }
2045
2046 reply = dbus_message_new_method_return(message);
2047 if (!reply)
2048 goto oom;
2049
47a26690
LP
2050 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
2051 const char *sysfs, *seat;
2052 dbus_bool_t interactive;
2053
2054 if (!dbus_message_get_args(
2055 message,
2056 &error,
2057 DBUS_TYPE_STRING, &seat,
2058 DBUS_TYPE_STRING, &sysfs,
2059 DBUS_TYPE_BOOLEAN, &interactive,
2060 DBUS_TYPE_INVALID))
2061 return bus_send_error_reply(connection, message, &error, -EINVAL);
2062
2063 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
2064 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2065
89f13440 2066 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
47a26690
LP
2067 if (r < 0)
2068 return bus_send_error_reply(connection, message, &error, r);
2069
2070 r = attach_device(m, seat, sysfs);
2071 if (r < 0)
2072 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2073
2074 reply = dbus_message_new_method_return(message);
2075 if (!reply)
2076 goto oom;
7f7bb946 2077
b668e064
LP
2078
2079 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
2080 dbus_bool_t interactive;
2081
2082 if (!dbus_message_get_args(
2083 message,
2084 &error,
2085 DBUS_TYPE_BOOLEAN, &interactive,
2086 DBUS_TYPE_INVALID))
2087 return bus_send_error_reply(connection, message, &error, -EINVAL);
2088
89f13440 2089 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
b668e064
LP
2090 if (r < 0)
2091 return bus_send_error_reply(connection, message, &error, r);
2092
2093 r = flush_devices(m);
2094 if (r < 0)
2095 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2096
2097 reply = dbus_message_new_method_return(message);
2098 if (!reply)
2099 goto oom;
2100
d889a206
LP
2101 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
2102
2103 r = bus_manager_do_shutdown_or_sleep(
2104 m, connection, message,
2105 SPECIAL_POWEROFF_TARGET,
2106 INHIBIT_SHUTDOWN,
2107 "org.freedesktop.login1.power-off",
2108 "org.freedesktop.login1.power-off-multiple-sessions",
2109 "org.freedesktop.login1.power-off-ignore-inhibit",
19adb8a3 2110 NULL,
d889a206 2111 &error, &reply);
89f13440
LP
2112 if (r < 0)
2113 return bus_send_error_reply(connection, message, &error, r);
d889a206
LP
2114 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
2115 r = bus_manager_do_shutdown_or_sleep(
2116 m, connection, message,
2117 SPECIAL_REBOOT_TARGET,
2118 INHIBIT_SHUTDOWN,
2119 "org.freedesktop.login1.reboot",
2120 "org.freedesktop.login1.reboot-multiple-sessions",
2121 "org.freedesktop.login1.reboot-ignore-inhibit",
19adb8a3 2122 NULL,
d889a206 2123 &error, &reply);
89f13440
LP
2124 if (r < 0)
2125 return bus_send_error_reply(connection, message, &error, r);
2126
d889a206
LP
2127 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2128 r = bus_manager_do_shutdown_or_sleep(
2129 m, connection, message,
2130 SPECIAL_SUSPEND_TARGET,
2131 INHIBIT_SLEEP,
2132 "org.freedesktop.login1.suspend",
2133 "org.freedesktop.login1.suspend-multiple-sessions",
2134 "org.freedesktop.login1.suspend-ignore-inhibit",
19adb8a3 2135 "suspend",
d889a206
LP
2136 &error, &reply);
2137 if (r < 0)
2138 return bus_send_error_reply(connection, message, &error, r);
2139 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2140 r = bus_manager_do_shutdown_or_sleep(
2141 m, connection, message,
2142 SPECIAL_HIBERNATE_TARGET,
2143 INHIBIT_SLEEP,
2144 "org.freedesktop.login1.hibernate",
2145 "org.freedesktop.login1.hibernate-multiple-sessions",
2146 "org.freedesktop.login1.hibernate-ignore-inhibit",
19adb8a3 2147 "hibernate",
6524990f
LP
2148 &error, &reply);
2149 if (r < 0)
2150 return bus_send_error_reply(connection, message, &error, r);
2151
2152 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "HybridSleep")) {
2153 r = bus_manager_do_shutdown_or_sleep(
2154 m, connection, message,
2155 SPECIAL_HYBRID_SLEEP_TARGET,
2156 INHIBIT_SLEEP,
2157 "org.freedesktop.login1.hibernate",
2158 "org.freedesktop.login1.hibernate-multiple-sessions",
2159 "org.freedesktop.login1.hibernate-ignore-inhibit",
19adb8a3 2160 "hybrid-sleep",
d889a206
LP
2161 &error, &reply);
2162 if (r < 0)
2163 return bus_send_error_reply(connection, message, &error, r);
f8e2fb7b 2164
d889a206 2165 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
f8e2fb7b 2166
d889a206
LP
2167 r = bus_manager_can_shutdown_or_sleep(
2168 m, connection, message,
2169 INHIBIT_SHUTDOWN,
2170 "org.freedesktop.login1.power-off",
2171 "org.freedesktop.login1.power-off-multiple-sessions",
2172 "org.freedesktop.login1.power-off-ignore-inhibit",
19adb8a3 2173 NULL,
d889a206
LP
2174 &error, &reply);
2175 if (r < 0)
2176 return bus_send_error_reply(connection, message, &error, r);
2177 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2178 r = bus_manager_can_shutdown_or_sleep(
2179 m, connection, message,
2180 INHIBIT_SHUTDOWN,
2181 "org.freedesktop.login1.reboot",
2182 "org.freedesktop.login1.reboot-multiple-sessions",
2183 "org.freedesktop.login1.reboot-ignore-inhibit",
19adb8a3 2184 NULL,
d889a206
LP
2185 &error, &reply);
2186 if (r < 0)
2187 return bus_send_error_reply(connection, message, &error, r);
89f13440 2188
d889a206
LP
2189 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2190 r = bus_manager_can_shutdown_or_sleep(
2191 m, connection, message,
2192 INHIBIT_SLEEP,
2193 "org.freedesktop.login1.suspend",
2194 "org.freedesktop.login1.suspend-multiple-sessions",
2195 "org.freedesktop.login1.suspend-ignore-inhibit",
19adb8a3 2196 "suspend",
d889a206
LP
2197 &error, &reply);
2198 if (r < 0)
2199 return bus_send_error_reply(connection, message, &error, r);
89f13440 2200
d889a206
LP
2201 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2202 r = bus_manager_can_shutdown_or_sleep(
2203 m, connection, message,
2204 INHIBIT_SLEEP,
2205 "org.freedesktop.login1.hibernate",
2206 "org.freedesktop.login1.hibernate-multiple-sessions",
2207 "org.freedesktop.login1.hibernate-ignore-inhibit",
19adb8a3 2208 "hibernate",
6524990f
LP
2209 &error, &reply);
2210 if (r < 0)
2211 return bus_send_error_reply(connection, message, &error, r);
2212
2213 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHybridSleep")) {
2214 r = bus_manager_can_shutdown_or_sleep(
2215 m, connection, message,
2216 INHIBIT_SLEEP,
2217 "org.freedesktop.login1.hibernate",
2218 "org.freedesktop.login1.hibernate-multiple-sessions",
2219 "org.freedesktop.login1.hibernate-ignore-inhibit",
19adb8a3 2220 "hybrid-sleep",
d889a206
LP
2221 &error, &reply);
2222 if (r < 0)
2223 return bus_send_error_reply(connection, message, &error, r);
89f13440 2224
bef422ae 2225 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
3f49d45a
LP
2226 char *introspection = NULL;
2227 FILE *f;
2228 Iterator i;
2229 Session *session;
2230 Seat *seat;
2231 User *user;
2232 size_t size;
2233 char *p;
2234
2235 if (!(reply = dbus_message_new_method_return(message)))
2236 goto oom;
2237
2238 /* We roll our own introspection code here, instead of
2239 * relying on bus_default_message_handler() because we
2240 * need to generate our introspection string
2241 * dynamically. */
2242
2243 if (!(f = open_memstream(&introspection, &size)))
2244 goto oom;
2245
2246 fputs(INTROSPECTION_BEGIN, f);
2247
2248 HASHMAP_FOREACH(seat, m->seats, i) {
2249 p = bus_path_escape(seat->id);
2250
2251 if (p) {
2252 fprintf(f, "<node name=\"seat/%s\"/>", p);
2253 free(p);
2254 }
2255 }
2256
2257 HASHMAP_FOREACH(user, m->users, i)
2258 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2259
2260 HASHMAP_FOREACH(session, m->sessions, i) {
2261 p = bus_path_escape(session->id);
2262
2263 if (p) {
2264 fprintf(f, "<node name=\"session/%s\"/>", p);
2265 free(p);
2266 }
2267 }
2268
2269 fputs(INTROSPECTION_END, f);
2270
2271 if (ferror(f)) {
2272 fclose(f);
2273 free(introspection);
2274 goto oom;
2275 }
2276
2277 fclose(f);
2278
2279 if (!introspection)
2280 goto oom;
2281
2282 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2283 free(introspection);
2284 goto oom;
2285 }
2286
2287 free(introspection);
d200735e
MS
2288 } else {
2289 const BusBoundProperties bps[] = {
2290 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2291 { NULL, }
2292 };
2293 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2294 }
3f49d45a
LP
2295
2296 if (reply) {
1a37b9b9 2297 if (!bus_maybe_send_reply(connection, message, reply))
fb6becb4 2298 goto oom;
3f49d45a
LP
2299 }
2300
2301 return DBUS_HANDLER_RESULT_HANDLED;
2302
2303oom:
3f49d45a
LP
2304 dbus_error_free(&error);
2305
2306 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2307}
2308
2309const DBusObjectPathVTable bus_manager_vtable = {
2310 .message_function = manager_message_handler
2311};
9418f147 2312
1713813d
LP
2313DBusHandlerResult bus_message_filter(
2314 DBusConnection *connection,
2315 DBusMessage *message,
2316 void *userdata) {
2317
2318 Manager *m = userdata;
2319 DBusError error;
2320
2321 assert(m);
2322 assert(connection);
2323 assert(message);
2324
2325 dbus_error_init(&error);
2326
fb6becb4 2327 log_debug("Got message: %s %s %s", strna(dbus_message_get_sender(message)), strna(dbus_message_get_interface(message)), strna(dbus_message_get_member(message)));
1713813d 2328
fb6becb4 2329 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
af9792ac 2330 const char *path, *result, *unit;
fb6becb4 2331 uint32_t id;
af9792ac
LP
2332
2333 if (!dbus_message_get_args(message, &error,
2334 DBUS_TYPE_UINT32, &id,
2335 DBUS_TYPE_OBJECT_PATH, &path,
2336 DBUS_TYPE_STRING, &unit,
2337 DBUS_TYPE_STRING, &result,
fb6becb4 2338 DBUS_TYPE_INVALID)) {
af9792ac 2339 log_error("Failed to parse JobRemoved message: %s", bus_error_message(&error));
fb6becb4
LP
2340 goto finish;
2341 }
314b4b0a 2342
fb6becb4 2343 if (m->action_job && streq(m->action_job, path)) {
314b4b0a 2344 log_info("Operation finished.");
ee17c928 2345
314b4b0a
LP
2346 /* Tell people that they now may take a lock again */
2347 send_prepare_for(m, m->action_what, false);
2348
2349 free(m->action_job);
2350 m->action_job = NULL;
2351 m->action_unit = NULL;
2352 m->action_what = 0;
fb6becb4
LP
2353
2354 } else {
fb6becb4
LP
2355 Session *s;
2356 User *u;
2357
2358 s = hashmap_get(m->session_units, unit);
2359 if (s) {
2360 if (streq_ptr(path, s->scope_job)) {
2361 free(s->scope_job);
2362 s->scope_job = NULL;
2363
2364 if (s->started) {
2365 if (streq(result, "done"))
2366 session_send_create_reply(s, NULL);
2367 else {
2368 dbus_set_error(&error, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
2369 session_send_create_reply(s, &error);
2370 }
76e66585
LP
2371 } else
2372 session_save(s);
fb6becb4
LP
2373 }
2374
2375 session_add_to_gc_queue(s);
2376 }
2377
2378 u = hashmap_get(m->user_units, unit);
2379 if (u) {
2380 if (streq_ptr(path, u->service_job)) {
2381 free(u->service_job);
2382 u->service_job = NULL;
2383 }
2384
2385 if (streq_ptr(path, u->slice_job)) {
2386 free(u->slice_job);
2387 u->slice_job = NULL;
2388 }
2389
8aec412f 2390 user_save(u);
fb6becb4
LP
2391 user_add_to_gc_queue(u);
2392 }
fb6becb4
LP
2393 }
2394
2395 } else if (dbus_message_is_signal(message, "org.freedesktop.DBus.Properties", "PropertiesChanged")) {
2396
2397 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2398 _cleanup_free_ char *unit = NULL;
2399 const char *path;
2400
2401 path = dbus_message_get_path(message);
2402 if (!path)
2403 goto finish;
2404
2405 unit_name_from_dbus_path(path, &unit);
2406 if (unit) {
fb6becb4
LP
2407 Session *s;
2408 User *u;
2409
2410 s = hashmap_get(m->session_units, unit);
2411 if (s)
2412 session_add_to_gc_queue(s);
2413
2414 u = hashmap_get(m->user_units, unit);
2415 if (u)
2416 user_add_to_gc_queue(u);
af9792ac 2417 }
6fa48533 2418
943aca8e
LP
2419 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "UnitRemoved")) {
2420
2421 const char *path, *unit;
2422 Session *session;
2423 User *user;
2424
2425 if (!dbus_message_get_args(message, &error,
2426 DBUS_TYPE_STRING, &unit,
2427 DBUS_TYPE_OBJECT_PATH, &path,
2428 DBUS_TYPE_INVALID)) {
2429 log_error("Failed to parse UnitRemoved message: %s", bus_error_message(&error));
2430 goto finish;
2431 }
2432
2433 session = hashmap_get(m->session_units, unit);
6797c324
LP
2434 if (session)
2435 session_add_to_gc_queue(session);
943aca8e 2436
6797c324
LP
2437 user = hashmap_get(m->user_units, unit);
2438 if (user)
2439 user_add_to_gc_queue(user);
2440
2441 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "Reloading")) {
2442 dbus_bool_t b;
2443
2444 if (!dbus_message_get_args(message, &error,
2445 DBUS_TYPE_BOOLEAN, &b,
2446 DBUS_TYPE_INVALID)) {
2447 log_error("Failed to parse Reloading message: %s", bus_error_message(&error));
2448 goto finish;
943aca8e
LP
2449 }
2450
6797c324
LP
2451 /* systemd finished reloading, let's recheck all our sessions */
2452 if (!b) {
2453 Session *session;
2454 Iterator i;
943aca8e 2455
6797c324
LP
2456 log_debug("System manager has been reloaded, rechecking sessions...");
2457
2458 HASHMAP_FOREACH(session, m->sessions, i)
2459 session_add_to_gc_queue(session);
943aca8e 2460 }
1713813d
LP
2461 }
2462
fb6becb4 2463finish:
1713813d
LP
2464 dbus_error_free(&error);
2465
2466 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2467}
2468
9418f147 2469int manager_send_changed(Manager *manager, const char *properties) {
ce0fc5f5 2470 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
9418f147
LP
2471
2472 assert(manager);
2473
4654e558
ZJS
2474 m = bus_properties_changed_new("/org/freedesktop/login1",
2475 "org.freedesktop.login1.Manager",
2476 properties);
9418f147 2477 if (!m)
4654e558 2478 return -ENOMEM;
9418f147
LP
2479
2480 if (!dbus_connection_send(manager->bus, m, NULL))
4654e558 2481 return -ENOMEM;
9418f147 2482
4654e558 2483 return 0;
9418f147 2484}
eecd1362 2485
d889a206 2486int manager_dispatch_delayed(Manager *manager) {
eecd1362 2487 DBusError error;
eecd1362
LP
2488 int r;
2489
2490 assert(manager);
2491
84286536 2492 if (manager->action_what == 0 || manager->action_job)
eecd1362
LP
2493 return 0;
2494
2495 /* Continue delay? */
314b4b0a 2496 if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0)) {
eecd1362 2497
314b4b0a
LP
2498 if (manager->action_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC))
2499 return 0;
af9792ac 2500
314b4b0a
LP
2501 log_info("Delay lock is active but inhibitor timeout is reached.");
2502 }
eecd1362 2503
314b4b0a 2504 /* Actually do the operation */
eecd1362 2505 dbus_error_init(&error);
314b4b0a 2506 r = execute_shutdown_or_sleep(manager, manager->action_what, manager->action_unit, &error);
eecd1362 2507 if (r < 0) {
449101fc 2508 log_warning("Failed to send delayed message: %s", bus_error(&error, r));
d889a206 2509 dbus_error_free(&error);
314b4b0a
LP
2510
2511 manager->action_unit = NULL;
2512 manager->action_what = 0;
eecd1362
LP
2513 return r;
2514 }
2515
eecd1362
LP
2516 return 1;
2517}
fb6becb4
LP
2518
2519int manager_start_scope(
2520 Manager *manager,
2521 const char *scope,
2522 pid_t pid,
2523 const char *slice,
2524 const char *description,
7fb3ee51 2525 const char *after,
405e0255 2526 const char *kill_mode,
fb6becb4
LP
2527 DBusError *error,
2528 char **job) {
2529
743e8945 2530 const char *timeout_stop_property = "TimeoutStopUSec", *send_sighup_property = "SendSIGHUP", *pids_property = "PIDs";
fb6becb4
LP
2531 _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
2532 DBusMessageIter iter, sub, sub2, sub3, sub4;
fb6becb4 2533 uint64_t timeout = 500 * USEC_PER_MSEC;
743e8945 2534 dbus_bool_t send_sighup = true;
fb6becb4
LP
2535 const char *fail = "fail";
2536 uint32_t u;
2537
2538 assert(manager);
2539 assert(scope);
2540 assert(pid > 1);
2541
2542 if (!slice)
2543 slice = "";
2544
2545 m = dbus_message_new_method_call(
2546 "org.freedesktop.systemd1",
2547 "/org/freedesktop/systemd1",
2548 "org.freedesktop.systemd1.Manager",
2549 "StartTransientUnit");
2550 if (!m)
2551 return log_oom();
2552
2553 dbus_message_iter_init_append(m, &iter);
2554
2555 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &scope) ||
2556 !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &fail) ||
2557 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sv)", &sub))
2558 return log_oom();
2559
2560 if (!isempty(slice)) {
2561 const char *slice_property = "Slice";
2562
2563 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2564 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &slice_property) ||
2565 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "s", &sub3) ||
2566 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &slice) ||
2567 !dbus_message_iter_close_container(&sub2, &sub3) ||
2568 !dbus_message_iter_close_container(&sub, &sub2))
2569 return log_oom();
2570 }
2571
2572 if (!isempty(description)) {
2573 const char *description_property = "Description";
2574
2575 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2576 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description_property) ||
2577 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "s", &sub3) ||
2578 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &description) ||
2579 !dbus_message_iter_close_container(&sub2, &sub3) ||
2580 !dbus_message_iter_close_container(&sub, &sub2))
2581 return log_oom();
2582 }
2583
7fb3ee51
LP
2584 if (!isempty(after)) {
2585 const char *after_property = "After";
2586
2587 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2588 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &after_property) ||
2589 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "as", &sub3) ||
2590 !dbus_message_iter_open_container(&sub3, DBUS_TYPE_ARRAY, "s", &sub4) ||
2591 !dbus_message_iter_append_basic(&sub4, DBUS_TYPE_STRING, &after) ||
2592 !dbus_message_iter_close_container(&sub3, &sub4) ||
2593 !dbus_message_iter_close_container(&sub2, &sub3) ||
2594 !dbus_message_iter_close_container(&sub, &sub2))
2595 return log_oom();
2596 }
2597
405e0255
LP
2598 if (!isempty(kill_mode)) {
2599 const char *kill_mode_property = "KillMode";
2600
2601 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2602 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &kill_mode_property) ||
2603 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "s", &sub3) ||
2604 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &kill_mode) ||
2605 !dbus_message_iter_close_container(&sub2, &sub3) ||
2606 !dbus_message_iter_close_container(&sub, &sub2))
2607 return log_oom();
2608 }
2609
fb6becb4
LP
2610 /* cgroup empty notification is not available in containers
2611 * currently. To make this less problematic, let's shorten the
2612 * stop timeout for sessions, so that we don't wait
2613 * forever. */
2614
2615 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2616 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &timeout_stop_property) ||
2617 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "t", &sub3) ||
2618 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_UINT64, &timeout) ||
2619 !dbus_message_iter_close_container(&sub2, &sub3) ||
2620 !dbus_message_iter_close_container(&sub, &sub2))
2621 return log_oom();
2622
743e8945
LP
2623 /* Make sure that the session shells are terminated with
2624 * SIGHUP since bash and friends tend to ignore SIGTERM */
2625 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2626 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &send_sighup_property) ||
2627 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "b", &sub3) ||
2628 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_BOOLEAN, &send_sighup) ||
2629 !dbus_message_iter_close_container(&sub2, &sub3) ||
2630 !dbus_message_iter_close_container(&sub, &sub2))
2631 return log_oom();
2632
fb6becb4
LP
2633 u = pid;
2634 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2635 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &pids_property) ||
2636 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "au", &sub3) ||
2637 !dbus_message_iter_open_container(&sub3, DBUS_TYPE_ARRAY, "u", &sub4) ||
2638 !dbus_message_iter_append_basic(&sub4, DBUS_TYPE_UINT32, &u) ||
2639 !dbus_message_iter_close_container(&sub3, &sub4) ||
2640 !dbus_message_iter_close_container(&sub2, &sub3) ||
743e8945
LP
2641 !dbus_message_iter_close_container(&sub, &sub2))
2642 return log_oom();
2643
2644 if (!dbus_message_iter_close_container(&iter, &sub))
fb6becb4
LP
2645 return log_oom();
2646
2647 reply = dbus_connection_send_with_reply_and_block(manager->bus, m, -1, error);
2648 if (!reply)
2649 return -EIO;
2650
2651 if (job) {
2652 const char *j;
2653 char *copy;
2654
2655 if (!dbus_message_get_args(reply, error, DBUS_TYPE_OBJECT_PATH, &j, DBUS_TYPE_INVALID))
2656 return -EIO;
2657
2658 copy = strdup(j);
2659 if (!copy)
2660 return -ENOMEM;
2661
2662 *job = copy;
2663 }
2664
2665 return 0;
2666}
2667
2668int manager_start_unit(Manager *manager, const char *unit, DBusError *error, char **job) {
2669 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2670 const char *fail = "fail";
2671 int r;
2672
2673 assert(manager);
2674 assert(unit);
2675
2676 r = bus_method_call_with_reply(
2677 manager->bus,
2678 "org.freedesktop.systemd1",
2679 "/org/freedesktop/systemd1",
2680 "org.freedesktop.systemd1.Manager",
2681 "StartUnit",
2682 &reply,
2683 error,
2684 DBUS_TYPE_STRING, &unit,
2685 DBUS_TYPE_STRING, &fail,
2686 DBUS_TYPE_INVALID);
2687 if (r < 0) {
2688 log_error("Failed to start unit %s: %s", unit, bus_error(error, r));
2689 return r;
2690 }
2691
2692 if (job) {
2693 const char *j;
2694 char *copy;
2695
2696 if (!dbus_message_get_args(reply, error,
2697 DBUS_TYPE_OBJECT_PATH, &j,
2698 DBUS_TYPE_INVALID)) {
2699 log_error("Failed to parse reply.");
2700 return -EIO;
2701 }
2702
2703 copy = strdup(j);
2704 if (!copy)
2705 return -ENOMEM;
2706
2707 *job = copy;
2708 }
2709
2710 return 0;
2711}
2712
2713int manager_stop_unit(Manager *manager, const char *unit, DBusError *error, char **job) {
2714 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2715 const char *fail = "fail";
2716 int r;
2717
2718 assert(manager);
2719 assert(unit);
2720
2721 r = bus_method_call_with_reply(
2722 manager->bus,
2723 "org.freedesktop.systemd1",
2724 "/org/freedesktop/systemd1",
2725 "org.freedesktop.systemd1.Manager",
2726 "StopUnit",
2727 &reply,
2728 error,
2729 DBUS_TYPE_STRING, &unit,
2730 DBUS_TYPE_STRING, &fail,
2731 DBUS_TYPE_INVALID);
2732 if (r < 0) {
6797c324
LP
2733 if (dbus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
2734 dbus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
2735
2736 if (job)
2737 *job = NULL;
2738
2739 dbus_error_free(error);
2740 return 0;
2741 }
2742
fb6becb4
LP
2743 log_error("Failed to stop unit %s: %s", unit, bus_error(error, r));
2744 return r;
2745 }
2746
2747 if (job) {
2748 const char *j;
2749 char *copy;
2750
2751 if (!dbus_message_get_args(reply, error,
2752 DBUS_TYPE_OBJECT_PATH, &j,
2753 DBUS_TYPE_INVALID)) {
2754 log_error("Failed to parse reply.");
2755 return -EIO;
2756 }
2757
2758 copy = strdup(j);
2759 if (!copy)
2760 return -ENOMEM;
2761
2762 *job = copy;
2763 }
2764
6797c324 2765 return 1;
fb6becb4
LP
2766}
2767
2768int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, DBusError *error) {
2769 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2770 const char *w;
2771 int r;
2772
2773 assert(manager);
2774 assert(unit);
2775
2776 w = who == KILL_LEADER ? "process" : "cgroup";
2777 assert_cc(sizeof(signo) == sizeof(int32_t));
2778
2779 r = bus_method_call_with_reply(
2780 manager->bus,
2781 "org.freedesktop.systemd1",
2782 "/org/freedesktop/systemd1",
2783 "org.freedesktop.systemd1.Manager",
2784 "KillUnit",
2785 &reply,
2786 error,
2787 DBUS_TYPE_STRING, &unit,
2788 DBUS_TYPE_STRING, &w,
2789 DBUS_TYPE_INT32, &signo,
2790 DBUS_TYPE_INVALID);
2791 if (r < 0) {
2792 log_error("Failed to stop unit %s: %s", unit, bus_error(error, r));
2793 return r;
2794 }
2795
2796 return 0;
2797}
2798
2799int manager_unit_is_active(Manager *manager, const char *unit) {
2800
2801 const char *interface = "org.freedesktop.systemd1.Unit";
2802 const char *property = "ActiveState";
2803 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2804 _cleanup_free_ char *path = NULL;
2805 DBusMessageIter iter, sub;
2806 const char *state;
2807 DBusError error;
2808 int r;
2809
2810 assert(manager);
2811 assert(unit);
2812
2813 dbus_error_init(&error);
2814
2815 path = unit_dbus_path_from_name(unit);
2816 if (!path)
2817 return -ENOMEM;
2818
2819 r = bus_method_call_with_reply(
2820 manager->bus,
2821 "org.freedesktop.systemd1",
2822 path,
2823 "org.freedesktop.DBus.Properties",
2824 "Get",
2825 &reply,
2826 &error,
2827 DBUS_TYPE_STRING, &interface,
2828 DBUS_TYPE_STRING, &property,
2829 DBUS_TYPE_INVALID);
fb6becb4 2830 if (r < 0) {
6797c324
LP
2831 if (dbus_error_has_name(&error, DBUS_ERROR_NO_REPLY) ||
2832 dbus_error_has_name(&error, DBUS_ERROR_DISCONNECTED)) {
2833 /* systemd might have droppped off
2834 * momentarily, let's not make this an
2835 * error */
2836
2837 dbus_error_free(&error);
2838 return true;
2839 }
2840
2841 if (dbus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
2842 dbus_error_has_name(&error, BUS_ERROR_LOAD_FAILED)) {
2843 /* If the unit is already unloaded then it's
2844 * not active */
2845
2846 dbus_error_free(&error);
2847 return false;
2848 }
2849
fb6becb4
LP
2850 log_error("Failed to query ActiveState: %s", bus_error(&error, r));
2851 dbus_error_free(&error);
2852 return r;
2853 }
2854
2855 if (!dbus_message_iter_init(reply, &iter) ||
2856 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
2857 log_error("Failed to parse reply.");
2858 return -EINVAL;
2859 }
2860
2861 dbus_message_iter_recurse(&iter, &sub);
2862 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
2863 log_error("Failed to parse reply.");
2864 return -EINVAL;
2865 }
2866
2867 dbus_message_iter_get_basic(&sub, &state);
2868
2869 return !streq(state, "inactive") && !streq(state, "failed");
2870}