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