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