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