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