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