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