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