]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-dbus.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / login / logind-dbus.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
3f49d45a
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2011 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
3f49d45a
LP
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 15 Lesser General Public License for more details.
3f49d45a 16
5430f7f2 17 You should have received a copy of the GNU Lesser General Public License
3f49d45a
LP
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
a185c5aa 21#include <errno.h>
4f5dd394 22#include <pwd.h>
a185c5aa 23#include <string.h>
98a28fef 24#include <unistd.h>
a185c5aa 25
cc377381 26#include "sd-messages.h"
4f5dd394 27
b5efdb8a 28#include "alloc-util.h"
430f0182 29#include "audit-util.h"
96aad8d1 30#include "bus-common-errors.h"
4f5dd394
LP
31#include "bus-error.h"
32#include "bus-util.h"
a0956174 33#include "dirent-util.h"
5bdf2243 34#include "efivars.h"
4f5dd394 35#include "escape.h"
3ffd4af2 36#include "fd-util.h"
4f5dd394 37#include "fileio-label.h"
f97b34a6 38#include "format-util.h"
f4f15635 39#include "fs-util.h"
4f5dd394
LP
40#include "logind.h"
41#include "mkdir.h"
42#include "path-util.h"
0b452006 43#include "process-util.h"
4f5dd394
LP
44#include "selinux-util.h"
45#include "sleep-config.h"
46#include "special.h"
47#include "strv.h"
288a74cc 48#include "terminal-util.h"
4f5dd394
LP
49#include "udev-util.h"
50#include "unit-name.h"
b1d4f8e1 51#include "user-util.h"
e2fa5721 52#include "utmp-wtmp.h"
3f49d45a 53
aeb07570
AJ
54static int get_sender_session(Manager *m, sd_bus_message *message, sd_bus_error *error, Session **ret) {
55
4afd3348 56 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
aeb07570 57 const char *name;
309a29df
LP
58 Session *session;
59 int r;
60
7b33c622
AJ
61 /* Get client login session. This is not what you are looking for these days,
62 * as apps may instead belong to a user service unit. This includes terminal
63 * emulators and hence command-line apps. */
aeb07570
AJ
64 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds);
65 if (r < 0)
66 return r;
67
68 r = sd_bus_creds_get_session(creds, &name);
69 if (r == -ENXIO)
70 goto err_no_session;
71 if (r < 0)
72 return r;
73
74 session = hashmap_get(m->sessions, name);
75 if (!session)
76 goto err_no_session;
77
78 *ret = session;
79 return 0;
80
81err_no_session:
82 return sd_bus_error_setf(error, BUS_ERROR_NO_SESSION_FOR_PID,
83 "Caller does not belong to any known session");
84}
85
86int manager_get_session_from_creds(Manager *m, sd_bus_message *message, const char *name, sd_bus_error *error, Session **ret) {
87 Session *session;
88
309a29df
LP
89 assert(m);
90 assert(message);
91 assert(ret);
92
aeb07570
AJ
93 if (isempty(name))
94 return get_sender_session(m, message, error, ret);
309a29df
LP
95
96 session = hashmap_get(m->sessions, name);
97 if (!session)
98 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SESSION, "No session '%s' known", name);
99
100 *ret = session;
101 return 0;
102}
103
aeb07570
AJ
104static int get_sender_user(Manager *m, sd_bus_message *message, sd_bus_error *error, User **ret) {
105
106 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
107 uid_t uid;
309a29df
LP
108 User *user;
109 int r;
110
aeb07570
AJ
111 /* Note that we get the owner UID of the session, not the actual client UID here! */
112 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_OWNER_UID|SD_BUS_CREDS_AUGMENT, &creds);
113 if (r < 0)
114 return r;
115
116 r = sd_bus_creds_get_owner_uid(creds, &uid);
117 if (r == -ENXIO)
118 goto err_no_user;
119 if (r < 0)
120 return r;
121
122 user = hashmap_get(m->users, UID_TO_PTR(uid));
123 if (!user)
124 goto err_no_user;
125
126 *ret = user;
127 return 0;
128
129err_no_user:
095b8833 130 return sd_bus_error_setf(error, BUS_ERROR_NO_USER_FOR_PID, "Caller does not belong to any logged in user or lingering user");
aeb07570
AJ
131}
132
133int manager_get_user_from_creds(Manager *m, sd_bus_message *message, uid_t uid, sd_bus_error *error, User **ret) {
134 User *user;
135
309a29df
LP
136 assert(m);
137 assert(message);
138 assert(ret);
139
aeb07570
AJ
140 if (!uid_is_valid(uid))
141 return get_sender_user(m, message, error, ret);
309a29df 142
8cb4ab00 143 user = hashmap_get(m->users, UID_TO_PTR(uid));
309a29df 144 if (!user)
095b8833 145 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER, "User ID "UID_FMT" is not logged in or lingering", uid);
309a29df
LP
146
147 *ret = user;
148 return 0;
149}
150
151int manager_get_seat_from_creds(Manager *m, sd_bus_message *message, const char *name, sd_bus_error *error, Seat **ret) {
152 Seat *seat;
153 int r;
154
155 assert(m);
156 assert(message);
157 assert(ret);
158
159 if (isempty(name)) {
160 Session *session;
161
162 r = manager_get_session_from_creds(m, message, NULL, error, &session);
163 if (r < 0)
164 return r;
165
166 seat = session->seat;
309a29df
LP
167 if (!seat)
168 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SEAT, "Session has no seat.");
169 } else {
170 seat = hashmap_get(m->seats, name);
171 if (!seat)
172 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SEAT, "No seat '%s' known", name);
173 }
174
175 *ret = seat;
176 return 0;
177}
178
cc377381
LP
179static int property_get_idle_hint(
180 sd_bus *bus,
181 const char *path,
182 const char *interface,
183 const char *property,
184 sd_bus_message *reply,
ebcf1f97
LP
185 void *userdata,
186 sd_bus_error *error) {
a185c5aa 187
cc377381 188 Manager *m = userdata;
a185c5aa 189
cc377381
LP
190 assert(bus);
191 assert(reply);
192 assert(m);
193
194 return sd_bus_message_append(reply, "b", manager_get_idle_hint(m, NULL) > 0);
a185c5aa
LP
195}
196
cc377381
LP
197static int property_get_idle_since_hint(
198 sd_bus *bus,
199 const char *path,
200 const char *interface,
201 const char *property,
202 sd_bus_message *reply,
ebcf1f97
LP
203 void *userdata,
204 sd_bus_error *error) {
cc377381
LP
205
206 Manager *m = userdata;
5cb14b37 207 dual_timestamp t = DUAL_TIMESTAMP_NULL;
a185c5aa 208
cc377381
LP
209 assert(bus);
210 assert(reply);
a185c5aa
LP
211 assert(m);
212
213 manager_get_idle_hint(m, &t);
a185c5aa 214
cc377381 215 return sd_bus_message_append(reply, "t", streq(property, "IdleSinceHint") ? t.realtime : t.monotonic);
a185c5aa
LP
216}
217
cc377381
LP
218static int property_get_inhibited(
219 sd_bus *bus,
220 const char *path,
221 const char *interface,
222 const char *property,
223 sd_bus_message *reply,
ebcf1f97
LP
224 void *userdata,
225 sd_bus_error *error) {
cc377381
LP
226
227 Manager *m = userdata;
f8e2fb7b 228 InhibitWhat w;
f8e2fb7b 229
cc377381
LP
230 assert(bus);
231 assert(reply);
232 assert(m);
f8e2fb7b 233
cc377381 234 w = manager_inhibit_what(m, streq(property, "BlockInhibited") ? INHIBIT_BLOCK : INHIBIT_DELAY);
f8e2fb7b 235
cc377381 236 return sd_bus_message_append(reply, "s", inhibit_what_to_string(w));
f8e2fb7b
LP
237}
238
cc377381
LP
239static int property_get_preparing(
240 sd_bus *bus,
241 const char *path,
242 const char *interface,
243 const char *property,
244 sd_bus_message *reply,
ebcf1f97
LP
245 void *userdata,
246 sd_bus_error *error) {
cc377381
LP
247
248 Manager *m = userdata;
249 bool b;
5e4a79da 250
cc377381
LP
251 assert(bus);
252 assert(reply);
253 assert(m);
5e4a79da
LP
254
255 if (streq(property, "PreparingForShutdown"))
314b4b0a 256 b = !!(m->action_what & INHIBIT_SHUTDOWN);
5e4a79da 257 else
314b4b0a 258 b = !!(m->action_what & INHIBIT_SLEEP);
5e4a79da 259
cc377381 260 return sd_bus_message_append(reply, "b", b);
5e4a79da
LP
261}
262
8aaa023a
DM
263static int property_get_scheduled_shutdown(
264 sd_bus *bus,
265 const char *path,
266 const char *interface,
267 const char *property,
268 sd_bus_message *reply,
269 void *userdata,
270 sd_bus_error *error) {
271
272 Manager *m = userdata;
273 int r;
274
275 assert(bus);
276 assert(reply);
277 assert(m);
278
279 r = sd_bus_message_open_container(reply, 'r', "st");
280 if (r < 0)
281 return r;
282
283 r = sd_bus_message_append(reply, "st", m->scheduled_shutdown_type, m->scheduled_shutdown_timeout);
284 if (r < 0)
285 return r;
286
287 return sd_bus_message_close_container(reply);
288}
289
cc377381 290static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_handle_action, handle_action, HandleAction);
fb6becb4 291
14856079
LP
292static int property_get_docked(
293 sd_bus *bus,
294 const char *path,
295 const char *interface,
296 const char *property,
297 sd_bus_message *reply,
298 void *userdata,
299 sd_bus_error *error) {
300
301 Manager *m = userdata;
302
303 assert(bus);
304 assert(reply);
305 assert(m);
306
602a41c2 307 return sd_bus_message_append(reply, "b", manager_is_docked_or_external_displays(m));
14856079
LP
308}
309
183e0738
LP
310static int property_get_current_sessions(
311 sd_bus *bus,
312 const char *path,
313 const char *interface,
314 const char *property,
315 sd_bus_message *reply,
316 void *userdata,
317 sd_bus_error *error) {
318
319 Manager *m = userdata;
320
321 assert(bus);
322 assert(reply);
323 assert(m);
324
325 return sd_bus_message_append(reply, "t", (uint64_t) hashmap_size(m->sessions));
326}
327
c5a11ae2
LP
328static int property_get_current_inhibitors(
329 sd_bus *bus,
330 const char *path,
331 const char *interface,
332 const char *property,
333 sd_bus_message *reply,
334 void *userdata,
335 sd_bus_error *error) {
336
337 Manager *m = userdata;
338
339 assert(bus);
340 assert(reply);
341 assert(m);
342
343 return sd_bus_message_append(reply, "t", (uint64_t) hashmap_size(m->inhibitors));
344}
345
19070062 346static int method_get_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
347 _cleanup_free_ char *p = NULL;
348 Manager *m = userdata;
349 const char *name;
350 Session *session;
351 int r;
352
cc377381
LP
353 assert(message);
354 assert(m);
355
356 r = sd_bus_message_read(message, "s", &name);
357 if (r < 0)
ebcf1f97 358 return r;
cc377381 359
309a29df
LP
360 r = manager_get_session_from_creds(m, message, name, error, &session);
361 if (r < 0)
362 return r;
cc377381
LP
363
364 p = session_bus_path(session);
365 if (!p)
ebcf1f97 366 return -ENOMEM;
cc377381 367
df2d202e 368 return sd_bus_reply_method_return(message, "o", p);
cc377381
LP
369}
370
7b33c622
AJ
371/* Get login session of a process. This is not what you are looking for these days,
372 * as apps may instead belong to a user service unit. This includes terminal
373 * emulators and hence command-line apps. */
19070062 374static int method_get_session_by_pid(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381 375 _cleanup_free_ char *p = NULL;
954449b8 376 Session *session = NULL;
cc377381 377 Manager *m = userdata;
4e724d9c 378 pid_t pid;
cc377381
LP
379 int r;
380
cc377381
LP
381 assert(message);
382 assert(m);
383
4e724d9c
LP
384 assert_cc(sizeof(pid_t) == sizeof(uint32_t));
385
cc377381
LP
386 r = sd_bus_message_read(message, "u", &pid);
387 if (r < 0)
ebcf1f97 388 return r;
07b38ba5 389 if (pid < 0)
06820eaf 390 return -EINVAL;
cc377381 391
06820eaf 392 if (pid == 0) {
309a29df 393 r = manager_get_session_from_creds(m, message, NULL, error, &session);
5b12334d
LP
394 if (r < 0)
395 return r;
309a29df
LP
396 } else {
397 r = manager_get_session_by_pid(m, pid, &session);
4e724d9c 398 if (r < 0)
ebcf1f97 399 return r;
4e724d9c 400
309a29df
LP
401 if (!session)
402 return sd_bus_error_setf(error, BUS_ERROR_NO_SESSION_FOR_PID, "PID "PID_FMT" does not belong to any known session", pid);
403 }
cc377381
LP
404
405 p = session_bus_path(session);
406 if (!p)
ebcf1f97 407 return -ENOMEM;
cc377381 408
df2d202e 409 return sd_bus_reply_method_return(message, "o", p);
cc377381
LP
410}
411
19070062 412static int method_get_user(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
413 _cleanup_free_ char *p = NULL;
414 Manager *m = userdata;
415 uint32_t uid;
416 User *user;
417 int r;
418
cc377381
LP
419 assert(message);
420 assert(m);
421
422 r = sd_bus_message_read(message, "u", &uid);
423 if (r < 0)
ebcf1f97 424 return r;
cc377381 425
309a29df
LP
426 r = manager_get_user_from_creds(m, message, uid, error, &user);
427 if (r < 0)
428 return r;
cc377381
LP
429
430 p = user_bus_path(user);
431 if (!p)
ebcf1f97 432 return -ENOMEM;
cc377381 433
df2d202e 434 return sd_bus_reply_method_return(message, "o", p);
cc377381
LP
435}
436
19070062 437static int method_get_user_by_pid(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
438 _cleanup_free_ char *p = NULL;
439 Manager *m = userdata;
954449b8 440 User *user = NULL;
4e724d9c 441 pid_t pid;
fb6becb4 442 int r;
98a28fef 443
cc377381 444 assert(message);
98a28fef 445 assert(m);
cc377381 446
4e724d9c
LP
447 assert_cc(sizeof(pid_t) == sizeof(uint32_t));
448
cc377381
LP
449 r = sd_bus_message_read(message, "u", &pid);
450 if (r < 0)
ebcf1f97 451 return r;
07b38ba5 452 if (pid < 0)
06820eaf 453 return -EINVAL;
cc377381 454
06820eaf 455 if (pid == 0) {
309a29df 456 r = manager_get_user_from_creds(m, message, UID_INVALID, error, &user);
5b12334d
LP
457 if (r < 0)
458 return r;
309a29df
LP
459 } else {
460 r = manager_get_user_by_pid(m, pid, &user);
4e724d9c 461 if (r < 0)
ebcf1f97 462 return r;
309a29df 463 if (!user)
095b8833
AJ
464 return sd_bus_error_setf(error, BUS_ERROR_NO_USER_FOR_PID,
465 "PID "PID_FMT" does not belong to any logged in user or lingering user",
466 pid);
4e724d9c
LP
467 }
468
cc377381
LP
469 p = user_bus_path(user);
470 if (!p)
ebcf1f97 471 return -ENOMEM;
cc377381 472
df2d202e 473 return sd_bus_reply_method_return(message, "o", p);
cc377381
LP
474}
475
19070062 476static int method_get_seat(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
477 _cleanup_free_ char *p = NULL;
478 Manager *m = userdata;
479 const char *name;
480 Seat *seat;
481 int r;
482
98a28fef 483 assert(message);
cc377381 484 assert(m);
98a28fef 485
cc377381
LP
486 r = sd_bus_message_read(message, "s", &name);
487 if (r < 0)
ebcf1f97 488 return r;
98a28fef 489
309a29df
LP
490 r = manager_get_seat_from_creds(m, message, name, error, &seat);
491 if (r < 0)
492 return r;
98a28fef 493
cc377381
LP
494 p = seat_bus_path(seat);
495 if (!p)
ebcf1f97 496 return -ENOMEM;
98a28fef 497
df2d202e 498 return sd_bus_reply_method_return(message, "o", p);
cc377381 499}
98a28fef 500
19070062 501static int method_list_sessions(sd_bus_message *message, void *userdata, sd_bus_error *error) {
4afd3348 502 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
cc377381
LP
503 Manager *m = userdata;
504 Session *session;
505 Iterator i;
506 int r;
507
cc377381
LP
508 assert(message);
509 assert(m);
98a28fef 510
df2d202e 511 r = sd_bus_message_new_method_return(message, &reply);
cc377381 512 if (r < 0)
ebcf1f97 513 return r;
98a28fef 514
cc377381
LP
515 r = sd_bus_message_open_container(reply, 'a', "(susso)");
516 if (r < 0)
ebcf1f97 517 return r;
cc377381
LP
518
519 HASHMAP_FOREACH(session, m->sessions, i) {
520 _cleanup_free_ char *p = NULL;
521
522 p = session_bus_path(session);
523 if (!p)
ebcf1f97 524 return -ENOMEM;
cc377381
LP
525
526 r = sd_bus_message_append(reply, "(susso)",
527 session->id,
528 (uint32_t) session->user->uid,
529 session->user->name,
530 session->seat ? session->seat->id : "",
531 p);
532 if (r < 0)
ebcf1f97 533 return r;
cc377381
LP
534 }
535
536 r = sd_bus_message_close_container(reply);
537 if (r < 0)
ebcf1f97 538 return r;
cc377381 539
9030ca46 540 return sd_bus_send(NULL, reply, NULL);
cc377381
LP
541}
542
19070062 543static int method_list_users(sd_bus_message *message, void *userdata, sd_bus_error *error) {
4afd3348 544 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
cc377381
LP
545 Manager *m = userdata;
546 User *user;
547 Iterator i;
548 int r;
549
cc377381
LP
550 assert(message);
551 assert(m);
552
df2d202e 553 r = sd_bus_message_new_method_return(message, &reply);
cc377381 554 if (r < 0)
ebcf1f97 555 return r;
cc377381
LP
556
557 r = sd_bus_message_open_container(reply, 'a', "(uso)");
558 if (r < 0)
ebcf1f97 559 return r;
cc377381
LP
560
561 HASHMAP_FOREACH(user, m->users, i) {
562 _cleanup_free_ char *p = NULL;
563
564 p = user_bus_path(user);
565 if (!p)
ebcf1f97 566 return -ENOMEM;
cc377381
LP
567
568 r = sd_bus_message_append(reply, "(uso)",
569 (uint32_t) user->uid,
570 user->name,
571 p);
572 if (r < 0)
ebcf1f97 573 return r;
cc377381
LP
574 }
575
576 r = sd_bus_message_close_container(reply);
577 if (r < 0)
ebcf1f97 578 return r;
cc377381 579
9030ca46 580 return sd_bus_send(NULL, reply, NULL);
cc377381
LP
581}
582
19070062 583static int method_list_seats(sd_bus_message *message, void *userdata, sd_bus_error *error) {
4afd3348 584 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
cc377381
LP
585 Manager *m = userdata;
586 Seat *seat;
587 Iterator i;
588 int r;
589
cc377381
LP
590 assert(message);
591 assert(m);
592
df2d202e 593 r = sd_bus_message_new_method_return(message, &reply);
cc377381 594 if (r < 0)
ebcf1f97 595 return r;
cc377381
LP
596
597 r = sd_bus_message_open_container(reply, 'a', "(so)");
598 if (r < 0)
ebcf1f97 599 return r;
cc377381
LP
600
601 HASHMAP_FOREACH(seat, m->seats, i) {
602 _cleanup_free_ char *p = NULL;
603
604 p = seat_bus_path(seat);
605 if (!p)
ebcf1f97 606 return -ENOMEM;
cc377381 607
b8358bce 608 r = sd_bus_message_append(reply, "(so)", seat->id, p);
cc377381 609 if (r < 0)
ebcf1f97 610 return r;
cc377381
LP
611 }
612
613 r = sd_bus_message_close_container(reply);
614 if (r < 0)
ebcf1f97 615 return r;
cc377381 616
9030ca46 617 return sd_bus_send(NULL, reply, NULL);
cc377381
LP
618}
619
19070062 620static int method_list_inhibitors(sd_bus_message *message, void *userdata, sd_bus_error *error) {
4afd3348 621 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
cc377381
LP
622 Manager *m = userdata;
623 Inhibitor *inhibitor;
624 Iterator i;
625 int r;
626
19070062
LP
627 assert(message);
628 assert(m);
629
df2d202e 630 r = sd_bus_message_new_method_return(message, &reply);
cc377381 631 if (r < 0)
ebcf1f97 632 return r;
cc377381
LP
633
634 r = sd_bus_message_open_container(reply, 'a', "(ssssuu)");
635 if (r < 0)
ebcf1f97 636 return r;
cc377381
LP
637
638 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
639
dbfa3fbb 640 r = sd_bus_message_append(reply, "(ssssuu)",
cc377381
LP
641 strempty(inhibit_what_to_string(inhibitor->what)),
642 strempty(inhibitor->who),
643 strempty(inhibitor->why),
644 strempty(inhibit_mode_to_string(inhibitor->mode)),
645 (uint32_t) inhibitor->uid,
646 (uint32_t) inhibitor->pid);
647 if (r < 0)
ebcf1f97 648 return r;
cc377381
LP
649 }
650
651 r = sd_bus_message_close_container(reply);
652 if (r < 0)
ebcf1f97 653 return r;
cc377381 654
9030ca46 655 return sd_bus_send(NULL, reply, NULL);
cc377381
LP
656}
657
19070062 658static int method_create_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
a4cd87e9 659 const char *service, *type, *class, *cseat, *tty, *display, *remote_user, *remote_host, *desktop;
06820eaf 660 uint32_t audit_id = 0;
cc377381
LP
661 _cleanup_free_ char *id = NULL;
662 Session *session = NULL;
663 Manager *m = userdata;
664 User *user = NULL;
665 Seat *seat = NULL;
06820eaf
LP
666 pid_t leader;
667 uid_t uid;
cc377381
LP
668 int remote;
669 uint32_t vtnr = 0;
670 SessionType t;
671 SessionClass c;
672 int r;
673
cc377381
LP
674 assert(message);
675 assert(m);
676
06820eaf
LP
677 assert_cc(sizeof(pid_t) == sizeof(uint32_t));
678 assert_cc(sizeof(uid_t) == sizeof(uint32_t));
679
a4cd87e9 680 r = sd_bus_message_read(message, "uusssssussbss", &uid, &leader, &service, &type, &class, &desktop, &cseat, &vtnr, &tty, &display, &remote, &remote_user, &remote_host);
cc377381 681 if (r < 0)
ebcf1f97 682 return r;
cc377381 683
06820eaf
LP
684 if (!uid_is_valid(uid))
685 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid UID");
686 if (leader < 0 || leader == 1)
ebcf1f97 687 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
98a28fef 688
e2acb67b
LP
689 if (isempty(type))
690 t = _SESSION_TYPE_INVALID;
691 else {
692 t = session_type_from_string(type);
693 if (t < 0)
ebcf1f97 694 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid session type %s", type);
e2acb67b 695 }
98a28fef 696
55efac6c 697 if (isempty(class))
e2acb67b
LP
698 c = _SESSION_CLASS_INVALID;
699 else {
55efac6c 700 c = session_class_from_string(class);
e2acb67b 701 if (c < 0)
ebcf1f97 702 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid session class %s", class);
e2acb67b 703 }
55efac6c 704
a4cd87e9
LP
705 if (isempty(desktop))
706 desktop = NULL;
707 else {
708 if (!string_is_safe(desktop))
709 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid desktop string %s", desktop);
710 }
711
954449b8
LP
712 if (isempty(cseat))
713 seat = NULL;
98a28fef 714 else {
954449b8
LP
715 seat = hashmap_get(m->seats, cseat);
716 if (!seat)
d14ab08b 717 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SEAT, "No seat '%s' known", cseat);
98a28fef
LP
718 }
719
98a28fef 720 if (tty_is_vc(tty)) {
4d6d6518 721 int v;
98a28fef 722
954449b8 723 if (!seat)
92432fcc
DH
724 seat = m->seat0;
725 else if (seat != m->seat0)
d14ab08b 726 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "TTY %s is virtual console but seat %s is not seat0", tty, seat->id);
98a28fef 727
4d6d6518 728 v = vtnr_from_tty(tty);
4d6d6518 729 if (v <= 0)
ebcf1f97 730 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot determine VT number from virtual console TTY %s", tty);
98a28fef 731
92bd5ff3 732 if (!vtnr)
4d6d6518
LP
733 vtnr = (uint32_t) v;
734 else if (vtnr != (uint32_t) v)
ebcf1f97 735 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified TTY and VT number do not match");
cc377381 736
d1122ad5
LP
737 } else if (tty_is_console(tty)) {
738
954449b8 739 if (!seat)
92432fcc
DH
740 seat = m->seat0;
741 else if (seat != m->seat0)
ebcf1f97 742 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Console TTY specified but seat is not seat0");
d1122ad5
LP
743
744 if (vtnr != 0)
ebcf1f97 745 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Console TTY specified but VT number is not 0");
978cf3c7 746 }
98a28fef 747
954449b8 748 if (seat) {
bf7825ae 749 if (seat_has_vts(seat)) {
c506027a 750 if (!vtnr || vtnr > 63)
ebcf1f97 751 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "VT number out of range");
4d6d6518 752 } else {
d1122ad5 753 if (vtnr != 0)
ebcf1f97 754 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Seat has no VTs but VT number not 0");
4d6d6518
LP
755 }
756 }
757
cc377381
LP
758 r = sd_bus_message_enter_container(message, 'a', "(sv)");
759 if (r < 0)
ebcf1f97 760 return r;
98a28fef 761
e2acb67b
LP
762 if (t == _SESSION_TYPE_INVALID) {
763 if (!isempty(display))
764 t = SESSION_X11;
765 else if (!isempty(tty))
766 t = SESSION_TTY;
767 else
768 t = SESSION_UNSPECIFIED;
769 }
770
771 if (c == _SESSION_CLASS_INVALID) {
a4cd87e9 772 if (t == SESSION_UNSPECIFIED)
e2acb67b 773 c = SESSION_BACKGROUND;
a4cd87e9
LP
774 else
775 c = SESSION_USER;
e2acb67b
LP
776 }
777
06820eaf 778 if (leader == 0) {
4afd3348 779 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
5b12334d
LP
780
781 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
782 if (r < 0)
783 return r;
784
5b12334d 785 r = sd_bus_creds_get_pid(creds, (pid_t*) &leader);
cc377381 786 if (r < 0)
ebcf1f97 787 return r;
9444b1f2
LP
788 }
789
b80120c4
DH
790 r = manager_get_session_by_pid(m, leader, NULL);
791 if (r > 0)
792 return sd_bus_error_setf(error, BUS_ERROR_SESSION_BUSY, "Already running in a session");
793
794 /*
795 * Old gdm and lightdm start the user-session on the same VT as
796 * the greeter session. But they destroy the greeter session
797 * after the user-session and want the user-session to take
798 * over the VT. We need to support this for
799 * backwards-compatibility, so make sure we allow new sessions
cc85d562
DH
800 * on a VT that a greeter is running on. Furthermore, to allow
801 * re-logins, we have to allow a greeter to take over a used VT for
802 * the exact same reasons.
b80120c4 803 */
cc85d562
DH
804 if (c != SESSION_GREETER &&
805 vtnr > 0 &&
b80120c4
DH
806 vtnr < m->seat0->position_count &&
807 m->seat0->positions[vtnr] &&
808 m->seat0->positions[vtnr]->class != SESSION_GREETER)
809 return sd_bus_error_setf(error, BUS_ERROR_SESSION_BUSY, "Already occupied by a session");
21c390cc 810
183e0738
LP
811 if (hashmap_size(m->sessions) >= m->sessions_max)
812 return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Maximum number of sessions (%" PRIu64 ") reached, refusing further sessions.", m->sessions_max);
813
3a87a86e
LP
814 (void) audit_session_from_pid(leader, &audit_id);
815 if (audit_session_is_valid(audit_id)) {
954449b8 816 /* Keep our session IDs and the audit session IDs in sync */
21c390cc 817
de0671ee 818 if (asprintf(&id, "%"PRIu32, audit_id) < 0)
ebcf1f97 819 return -ENOMEM;
21c390cc 820
954449b8
LP
821 /* Wut? There's already a session by this name and we
822 * didn't find it above? Weird, then let's not trust
823 * the audit data and let's better register a new
824 * ID */
825 if (hashmap_get(m->sessions, id)) {
4b549144 826 log_warning("Existing logind session ID %s used by new audit session, ignoring", id);
3a87a86e 827 audit_id = AUDIT_SESSION_INVALID;
8ea913b2 828
97b11eed 829 id = mfree(id);
07714753 830 }
954449b8 831 }
07714753 832
954449b8 833 if (!id) {
07714753 834 do {
97b11eed 835 id = mfree(id);
07714753 836
cc377381 837 if (asprintf(&id, "c%lu", ++m->session_counter) < 0)
ebcf1f97 838 return -ENOMEM;
07714753
LP
839
840 } while (hashmap_get(m->sessions, id));
98a28fef
LP
841 }
842
954449b8 843 r = manager_add_user_by_uid(m, uid, &user);
ebcf1f97 844 if (r < 0)
954449b8
LP
845 goto fail;
846
9444b1f2 847 r = manager_add_session(m, id, &session);
ebcf1f97 848 if (r < 0)
98a28fef
LP
849 goto fail;
850
9444b1f2
LP
851 session_set_user(session, user);
852
98a28fef
LP
853 session->leader = leader;
854 session->audit_id = audit_id;
855 session->type = t;
55efac6c 856 session->class = c;
98a28fef 857 session->remote = remote;
98a28fef
LP
858 session->vtnr = vtnr;
859
98a28fef
LP
860 if (!isempty(tty)) {
861 session->tty = strdup(tty);
862 if (!session->tty) {
ebcf1f97 863 r = -ENOMEM;
98a28fef
LP
864 goto fail;
865 }
866 }
867
868 if (!isempty(display)) {
869 session->display = strdup(display);
870 if (!session->display) {
ebcf1f97 871 r = -ENOMEM;
98a28fef
LP
872 goto fail;
873 }
874 }
875
876 if (!isempty(remote_user)) {
877 session->remote_user = strdup(remote_user);
878 if (!session->remote_user) {
ebcf1f97 879 r = -ENOMEM;
98a28fef
LP
880 goto fail;
881 }
882 }
883
884 if (!isempty(remote_host)) {
885 session->remote_host = strdup(remote_host);
886 if (!session->remote_host) {
ebcf1f97 887 r = -ENOMEM;
98a28fef
LP
888 goto fail;
889 }
890 }
891
892 if (!isempty(service)) {
893 session->service = strdup(service);
894 if (!session->service) {
ebcf1f97 895 r = -ENOMEM;
98a28fef
LP
896 goto fail;
897 }
898 }
899
a4cd87e9
LP
900 if (!isempty(desktop)) {
901 session->desktop = strdup(desktop);
902 if (!session->desktop) {
903 r = -ENOMEM;
904 goto fail;
905 }
906 }
907
954449b8
LP
908 if (seat) {
909 r = seat_attach_session(seat, session);
ebcf1f97 910 if (r < 0)
98a28fef
LP
911 goto fail;
912 }
913
914 r = session_start(session);
ebcf1f97 915 if (r < 0)
98a28fef
LP
916 goto fail;
917
cc377381 918 session->create_message = sd_bus_message_ref(message);
98a28fef 919
cba38758
LP
920 /* Now, let's wait until the slice unit and stuff got
921 * created. We send the reply back from
f7340ab2 922 * session_send_create_reply(). */
cba38758 923
cc377381 924 return 1;
98a28fef
LP
925
926fail:
98a28fef
LP
927 if (session)
928 session_add_to_gc_queue(session);
929
930 if (user)
931 user_add_to_gc_queue(user);
932
98a28fef
LP
933 return r;
934}
935
19070062 936static int method_release_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
937 Manager *m = userdata;
938 Session *session;
939 const char *name;
940 int r;
314b4b0a 941
cc377381
LP
942 assert(message);
943 assert(m);
944
945 r = sd_bus_message_read(message, "s", &name);
946 if (r < 0)
ebcf1f97 947 return r;
cc377381 948
309a29df
LP
949 r = manager_get_session_from_creds(m, message, name, error, &session);
950 if (r < 0)
951 return r;
cc377381 952
ad8780c9
ZJS
953 r = session_release(session);
954 if (r < 0)
955 return r;
cc377381 956
df2d202e 957 return sd_bus_reply_method_return(message, NULL);
cc377381
LP
958}
959
19070062 960static int method_activate_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
961 Manager *m = userdata;
962 Session *session;
963 const char *name;
964 int r;
f8e2fb7b 965
cc377381 966 assert(message);
f8e2fb7b 967 assert(m);
cc377381
LP
968
969 r = sd_bus_message_read(message, "s", &name);
970 if (r < 0)
ebcf1f97 971 return r;
cc377381 972
309a29df
LP
973 r = manager_get_session_from_creds(m, message, name, error, &session);
974 if (r < 0)
975 return r;
cc377381 976
19070062 977 return bus_session_method_activate(message, session, error);
cc377381
LP
978}
979
19070062 980static int method_activate_session_on_seat(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
981 const char *session_name, *seat_name;
982 Manager *m = userdata;
983 Session *session;
984 Seat *seat;
985 int r;
986
f8e2fb7b 987 assert(message);
cc377381 988 assert(m);
f8e2fb7b 989
cc377381
LP
990 /* Same as ActivateSession() but refuses to work if
991 * the seat doesn't match */
f8e2fb7b 992
cc377381
LP
993 r = sd_bus_message_read(message, "ss", &session_name, &seat_name);
994 if (r < 0)
ebcf1f97 995 return r;
eecd1362 996
309a29df
LP
997 r = manager_get_session_from_creds(m, message, session_name, error, &session);
998 if (r < 0)
999 return r;
beaafb2e 1000
309a29df
LP
1001 r = manager_get_seat_from_creds(m, message, seat_name, error, &seat);
1002 if (r < 0)
1003 return r;
314b4b0a 1004
cc377381 1005 if (session->seat != seat)
ebcf1f97 1006 return sd_bus_error_setf(error, BUS_ERROR_SESSION_NOT_ON_SEAT, "Session %s not on seat %s", session_name, seat_name);
cc377381
LP
1007
1008 r = session_activate(session);
f8e2fb7b 1009 if (r < 0)
ebcf1f97 1010 return r;
f8e2fb7b 1011
df2d202e 1012 return sd_bus_reply_method_return(message, NULL);
cc377381 1013}
f8e2fb7b 1014
19070062 1015static int method_lock_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
1016 Manager *m = userdata;
1017 Session *session;
1018 const char *name;
1019 int r;
f8e2fb7b 1020
cc377381
LP
1021 assert(message);
1022 assert(m);
f8e2fb7b 1023
cc377381
LP
1024 r = sd_bus_message_read(message, "s", &name);
1025 if (r < 0)
ebcf1f97 1026 return r;
f8e2fb7b 1027
309a29df
LP
1028 r = manager_get_session_from_creds(m, message, name, error, &session);
1029 if (r < 0)
1030 return r;
f8e2fb7b 1031
19070062 1032 return bus_session_method_lock(message, session, error);
cc377381 1033}
f8e2fb7b 1034
19070062 1035static int method_lock_sessions(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
1036 Manager *m = userdata;
1037 int r;
f8e2fb7b 1038
cc377381
LP
1039 assert(message);
1040 assert(m);
f8e2fb7b 1041
c529695e
LP
1042 r = bus_verify_polkit_async(
1043 message,
1044 CAP_SYS_ADMIN,
1045 "org.freedesktop.login1.lock-sessions",
403ed0e5 1046 NULL,
c529695e
LP
1047 false,
1048 UID_INVALID,
1049 &m->polkit_registry,
1050 error);
1051 if (r < 0)
1052 return r;
1053 if (r == 0)
1054 return 1; /* Will call us back */
1055
cc377381
LP
1056 r = session_send_lock_all(m, streq(sd_bus_message_get_member(message), "LockSessions"));
1057 if (r < 0)
ebcf1f97 1058 return r;
f8e2fb7b 1059
df2d202e 1060 return sd_bus_reply_method_return(message, NULL);
cc377381
LP
1061}
1062
19070062 1063static int method_kill_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
c529695e 1064 const char *name;
cc377381
LP
1065 Manager *m = userdata;
1066 Session *session;
cc377381
LP
1067 int r;
1068
cc377381
LP
1069 assert(message);
1070 assert(m);
1071
c529695e 1072 r = sd_bus_message_read(message, "s", &name);
cc377381 1073 if (r < 0)
ebcf1f97 1074 return r;
cc377381 1075
309a29df
LP
1076 r = manager_get_session_from_creds(m, message, name, error, &session);
1077 if (r < 0)
1078 return r;
f8e2fb7b 1079
19070062 1080 return bus_session_method_kill(message, session, error);
cc377381 1081}
f8e2fb7b 1082
19070062 1083static int method_kill_user(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
1084 Manager *m = userdata;
1085 uint32_t uid;
cc377381
LP
1086 User *user;
1087 int r;
f8e2fb7b 1088
cc377381
LP
1089 assert(message);
1090 assert(m);
1091
c529695e 1092 r = sd_bus_message_read(message, "u", &uid);
cc377381 1093 if (r < 0)
ebcf1f97 1094 return r;
cc377381 1095
309a29df
LP
1096 r = manager_get_user_from_creds(m, message, uid, error, &user);
1097 if (r < 0)
1098 return r;
cc377381 1099
19070062 1100 return bus_user_method_kill(message, user, error);
cc377381
LP
1101}
1102
19070062 1103static int method_terminate_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
1104 Manager *m = userdata;
1105 const char *name;
1106 Session *session;
1107 int r;
1108
cc377381
LP
1109 assert(message);
1110 assert(m);
1111
1112 r = sd_bus_message_read(message, "s", &name);
1113 if (r < 0)
ebcf1f97 1114 return r;
cc377381 1115
309a29df
LP
1116 r = manager_get_session_from_creds(m, message, name, error, &session);
1117 if (r < 0)
1118 return r;
cc377381 1119
19070062 1120 return bus_session_method_terminate(message, session, error);
cc377381
LP
1121}
1122
19070062 1123static int method_terminate_user(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
1124 Manager *m = userdata;
1125 uint32_t uid;
1126 User *user;
1127 int r;
1128
cc377381
LP
1129 assert(message);
1130 assert(m);
1131
1132 r = sd_bus_message_read(message, "u", &uid);
1133 if (r < 0)
ebcf1f97 1134 return r;
cc377381 1135
309a29df
LP
1136 r = manager_get_user_from_creds(m, message, uid, error, &user);
1137 if (r < 0)
1138 return r;
cc377381 1139
19070062 1140 return bus_user_method_terminate(message, user, error);
cc377381
LP
1141}
1142
19070062 1143static int method_terminate_seat(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
1144 Manager *m = userdata;
1145 const char *name;
1146 Seat *seat;
1147 int r;
1148
cc377381
LP
1149 assert(message);
1150 assert(m);
1151
1152 r = sd_bus_message_read(message, "s", &name);
1153 if (r < 0)
ebcf1f97 1154 return r;
cc377381 1155
309a29df
LP
1156 r = manager_get_seat_from_creds(m, message, name, error, &seat);
1157 if (r < 0)
1158 return r;
cc377381 1159
19070062 1160 return bus_seat_method_terminate(message, seat, error);
cc377381
LP
1161}
1162
19070062 1163static int method_set_user_linger(sd_bus_message *message, void *userdata, sd_bus_error *error) {
34160d91 1164 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
cc377381
LP
1165 _cleanup_free_ char *cc = NULL;
1166 Manager *m = userdata;
152199f2 1167 int r, b, interactive;
cc377381
LP
1168 struct passwd *pw;
1169 const char *path;
34160d91 1170 uint32_t uid, auth_uid;
cc377381 1171
cc377381
LP
1172 assert(message);
1173 assert(m);
1174
1175 r = sd_bus_message_read(message, "ubb", &uid, &b, &interactive);
1176 if (r < 0)
ebcf1f97 1177 return r;
cc377381 1178
34160d91
AJ
1179 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID |
1180 SD_BUS_CREDS_OWNER_UID|SD_BUS_CREDS_AUGMENT, &creds);
1181 if (r < 0)
1182 return r;
309a29df 1183
34160d91
AJ
1184 if (!uid_is_valid(uid)) {
1185 /* Note that we get the owner UID of the session or user unit,
1186 * not the actual client UID here! */
309a29df
LP
1187 r = sd_bus_creds_get_owner_uid(creds, &uid);
1188 if (r < 0)
1189 return r;
34160d91 1190 }
06820eaf 1191
34160d91
AJ
1192 /* owner_uid is racy, so for authorization we must use euid */
1193 r = sd_bus_creds_get_euid(creds, &auth_uid);
1194 if (r < 0)
1195 return r;
309a29df 1196
cc377381
LP
1197 errno = 0;
1198 pw = getpwuid(uid);
1199 if (!pw)
f5e5c28f 1200 return errno > 0 ? -errno : -ENOENT;
cc377381 1201
f3885791
LP
1202 r = bus_verify_polkit_async(
1203 message,
1204 CAP_SYS_ADMIN,
34160d91
AJ
1205 uid == auth_uid ? "org.freedesktop.login1.set-self-linger" :
1206 "org.freedesktop.login1.set-user-linger",
403ed0e5 1207 NULL,
f3885791 1208 interactive,
c529695e 1209 UID_INVALID,
f3885791
LP
1210 &m->polkit_registry,
1211 error);
cc377381 1212 if (r < 0)
ebcf1f97 1213 return r;
cc377381
LP
1214 if (r == 0)
1215 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1216
1217 mkdir_p_label("/var/lib/systemd", 0755);
1218
c31ad024 1219 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0, false);
cc377381 1220 if (r < 0)
ebcf1f97 1221 return r;
cc377381
LP
1222
1223 cc = cescape(pw->pw_name);
1224 if (!cc)
ebcf1f97 1225 return -ENOMEM;
cc377381 1226
63c372cb 1227 path = strjoina("/var/lib/systemd/linger/", cc);
cc377381
LP
1228 if (b) {
1229 User *u;
1230
1231 r = touch(path);
1232 if (r < 0)
ebcf1f97 1233 return r;
cc377381
LP
1234
1235 if (manager_add_user_by_uid(m, uid, &u) >= 0)
1236 user_start(u);
1237
1238 } else {
1239 User *u;
1240
1241 r = unlink(path);
1242 if (r < 0 && errno != ENOENT)
ebcf1f97 1243 return -errno;
cc377381 1244
8cb4ab00 1245 u = hashmap_get(m->users, UID_TO_PTR(uid));
cc377381
LP
1246 if (u)
1247 user_add_to_gc_queue(u);
1248 }
1249
df2d202e 1250 return sd_bus_reply_method_return(message, NULL);
f8e2fb7b
LP
1251}
1252
2eb916cd 1253static int trigger_device(Manager *m, struct udev_device *d) {
06acf2d4 1254 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
b668e064
LP
1255 struct udev_list_entry *first, *item;
1256 int r;
1257
1258 assert(m);
1259
1260 e = udev_enumerate_new(m->udev);
06acf2d4
LP
1261 if (!e)
1262 return -ENOMEM;
b668e064 1263
2eb916cd 1264 if (d) {
06acf2d4
LP
1265 r = udev_enumerate_add_match_parent(e, d);
1266 if (r < 0)
1267 return r;
2eb916cd
LP
1268 }
1269
06acf2d4
LP
1270 r = udev_enumerate_scan_devices(e);
1271 if (r < 0)
1272 return r;
b668e064
LP
1273
1274 first = udev_enumerate_get_list_entry(e);
1275 udev_list_entry_foreach(item, first) {
cc377381 1276 _cleanup_free_ char *t = NULL;
b668e064
LP
1277 const char *p;
1278
1279 p = udev_list_entry_get_name(item);
1280
b668e064 1281 t = strappend(p, "/uevent");
06acf2d4
LP
1282 if (!t)
1283 return -ENOMEM;
b668e064 1284
4c1fc3e4 1285 write_string_file(t, "change", WRITE_STRING_FILE_CREATE);
b668e064
LP
1286 }
1287
06acf2d4 1288 return 0;
b668e064
LP
1289}
1290
47a26690 1291static int attach_device(Manager *m, const char *seat, const char *sysfs) {
06acf2d4 1292 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
7fd1b19b 1293 _cleanup_free_ char *rule = NULL, *file = NULL;
c28fa3d3 1294 const char *id_for_seat;
47a26690
LP
1295 int r;
1296
1297 assert(m);
1298 assert(seat);
1299 assert(sysfs);
1300
1301 d = udev_device_new_from_syspath(m->udev, sysfs);
1302 if (!d)
1303 return -ENODEV;
1304
06acf2d4
LP
1305 if (!udev_device_has_tag(d, "seat"))
1306 return -ENODEV;
47a26690 1307
c28fa3d3 1308 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
06acf2d4
LP
1309 if (!id_for_seat)
1310 return -ENODEV;
47a26690 1311
06acf2d4
LP
1312 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0)
1313 return -ENOMEM;
47a26690 1314
06acf2d4
LP
1315 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0)
1316 return -ENOMEM;
47a26690 1317
d2e54fae 1318 mkdir_p_label("/etc/udev/rules.d", 0755);
574d5f2d 1319 r = write_string_file_atomic_label(file, rule);
a0a0c7f1 1320 if (r < 0)
06acf2d4 1321 return r;
47a26690 1322
06acf2d4 1323 return trigger_device(m, d);
47a26690
LP
1324}
1325
b668e064 1326static int flush_devices(Manager *m) {
7fd1b19b 1327 _cleanup_closedir_ DIR *d;
b668e064
LP
1328
1329 assert(m);
1330
1331 d = opendir("/etc/udev/rules.d");
1332 if (!d) {
1333 if (errno != ENOENT)
56f64d95 1334 log_warning_errno(errno, "Failed to open /etc/udev/rules.d: %m");
b668e064
LP
1335 } else {
1336 struct dirent *de;
1337
8fb3f009 1338 FOREACH_DIRENT_ALL(de, d, break) {
b668e064
LP
1339 if (!dirent_is_file(de))
1340 continue;
1341
1342 if (!startswith(de->d_name, "72-seat-"))
1343 continue;
1344
1345 if (!endswith(de->d_name, ".rules"))
1346 continue;
1347
1348 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
56f64d95 1349 log_warning_errno(errno, "Failed to unlink %s: %m", de->d_name);
b668e064 1350 }
b668e064
LP
1351 }
1352
1353 return trigger_device(m, NULL);
1354}
1355
19070062 1356static int method_attach_device(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
1357 const char *sysfs, *seat;
1358 Manager *m = userdata;
1359 int interactive, r;
1360
cc377381
LP
1361 assert(message);
1362 assert(m);
1363
1364 r = sd_bus_message_read(message, "ssb", &seat, &sysfs, &interactive);
1365 if (r < 0)
ebcf1f97 1366 return r;
cc377381
LP
1367
1368 if (!path_startswith(sysfs, "/sys"))
ebcf1f97 1369 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not in /sys", sysfs);
cc377381
LP
1370
1371 if (!seat_name_is_valid(seat))
ebcf1f97 1372 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Seat %s is not valid", seat);
cc377381 1373
f3885791
LP
1374 r = bus_verify_polkit_async(
1375 message,
1376 CAP_SYS_ADMIN,
1377 "org.freedesktop.login1.attach-device",
403ed0e5 1378 NULL,
f3885791 1379 interactive,
c529695e 1380 UID_INVALID,
f3885791
LP
1381 &m->polkit_registry,
1382 error);
cc377381 1383 if (r < 0)
ebcf1f97 1384 return r;
cc377381
LP
1385 if (r == 0)
1386 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1387
1388 r = attach_device(m, seat, sysfs);
1389 if (r < 0)
ebcf1f97 1390 return r;
cc377381 1391
df2d202e 1392 return sd_bus_reply_method_return(message, NULL);
cc377381
LP
1393}
1394
19070062 1395static int method_flush_devices(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
1396 Manager *m = userdata;
1397 int interactive, r;
1398
cc377381
LP
1399 assert(message);
1400 assert(m);
1401
1402 r = sd_bus_message_read(message, "b", &interactive);
1403 if (r < 0)
ebcf1f97 1404 return r;
cc377381 1405
f3885791
LP
1406 r = bus_verify_polkit_async(
1407 message,
1408 CAP_SYS_ADMIN,
1409 "org.freedesktop.login1.flush-devices",
403ed0e5 1410 NULL,
f3885791 1411 interactive,
c529695e 1412 UID_INVALID,
f3885791
LP
1413 &m->polkit_registry,
1414 error);
cc377381 1415 if (r < 0)
ebcf1f97 1416 return r;
cc377381
LP
1417 if (r == 0)
1418 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1419
1420 r = flush_devices(m);
1421 if (r < 0)
ebcf1f97 1422 return r;
cc377381 1423
df2d202e 1424 return sd_bus_reply_method_return(message, NULL);
cc377381
LP
1425}
1426
89f13440 1427static int have_multiple_sessions(
89f13440 1428 Manager *m,
409133be 1429 uid_t uid) {
89f13440 1430
2154761f
MS
1431 Session *session;
1432 Iterator i;
89f13440
LP
1433
1434 assert(m);
1435
1ca04b87
LP
1436 /* Check for other users' sessions. Greeter sessions do not
1437 * count, and non-login sessions do not count either. */
2154761f 1438 HASHMAP_FOREACH(session, m->sessions, i)
1ca04b87 1439 if (session->class == SESSION_USER &&
1ca04b87 1440 session->user->uid != uid)
2154761f 1441 return true;
89f13440
LP
1442
1443 return false;
1444}
1445
314b4b0a
LP
1446static int bus_manager_log_shutdown(
1447 Manager *m,
314b4b0a
LP
1448 const char *unit_name) {
1449
5744f59a 1450 const char *p, *q;
314b4b0a
LP
1451
1452 assert(m);
1453 assert(unit_name);
1454
314b4b0a 1455 if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
f868cb58 1456 p = "MESSAGE=System is powering down";
314b4b0a 1457 q = "SHUTDOWN=power-off";
314b4b0a 1458 } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
f868cb58 1459 p = "MESSAGE=System is rebooting";
314b4b0a 1460 q = "SHUTDOWN=reboot";
36b69c31
LP
1461 } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
1462 p = "MESSAGE=System is halting";
1463 q = "SHUTDOWN=halt";
314b4b0a 1464 } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
f868cb58 1465 p = "MESSAGE=System is rebooting with kexec";
314b4b0a
LP
1466 q = "SHUTDOWN=kexec";
1467 } else {
f868cb58 1468 p = "MESSAGE=System is shutting down";
314b4b0a
LP
1469 q = NULL;
1470 }
1471
f868cb58
ZJS
1472 if (isempty(m->wall_message))
1473 p = strjoina(p, ".");
1474 else
1475 p = strjoina(p, " (", m->wall_message, ").");
9ef15026 1476
e2cc6eca 1477 return log_struct(LOG_NOTICE,
2b044526 1478 "MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_STR,
314b4b0a 1479 p,
e2cc6eca
LP
1480 q,
1481 NULL);
314b4b0a
LP
1482}
1483
b5d3e168
KS
1484static int lid_switch_ignore_handler(sd_event_source *e, uint64_t usec, void *userdata) {
1485 Manager *m = userdata;
1486
1487 assert(e);
1488 assert(m);
1489
1490 m->lid_switch_ignore_event_source = sd_event_source_unref(m->lid_switch_ignore_event_source);
1491 return 0;
1492}
1493
1494int manager_set_lid_switch_ignore(Manager *m, usec_t until) {
1495 int r;
1496
1497 assert(m);
1498
1499 if (until <= now(CLOCK_MONOTONIC))
1500 return 0;
1501
1502 /* We want to ignore the lid switch for a while after each
1503 * suspend, and after boot-up. Hence let's install a timer for
1504 * this. As long as the event source exists we ignore the lid
1505 * switch. */
1506
1507 if (m->lid_switch_ignore_event_source) {
1508 usec_t u;
1509
1510 r = sd_event_source_get_time(m->lid_switch_ignore_event_source, &u);
1511 if (r < 0)
1512 return r;
1513
1514 if (until <= u)
1515 return 0;
1516
1517 r = sd_event_source_set_time(m->lid_switch_ignore_event_source, until);
1518 } else
6a0f1f6d
LP
1519 r = sd_event_add_time(
1520 m->event,
1521 &m->lid_switch_ignore_event_source,
1522 CLOCK_MONOTONIC,
1523 until, 0,
1524 lid_switch_ignore_handler, m);
b5d3e168
KS
1525
1526 return r;
1527}
1528
6d7f7fd4
AJ
1529static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
1530
1531 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
1532 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
1533 [INHIBIT_SLEEP] = "PrepareForSleep"
1534 };
1535
1536 int active = _active;
1537
1538 assert(m);
1539 assert(w >= 0);
1540 assert(w < _INHIBIT_WHAT_MAX);
1541 assert(signal_name[w]);
1542
1543 return sd_bus_emit_signal(m->bus,
1544 "/org/freedesktop/login1",
1545 "org.freedesktop.login1.Manager",
1546 signal_name[w],
1547 "b",
1548 active);
1549}
1550
314b4b0a
LP
1551static int execute_shutdown_or_sleep(
1552 Manager *m,
1553 InhibitWhat w,
1554 const char *unit_name,
cc377381 1555 sd_bus_error *error) {
314b4b0a 1556
4afd3348 1557 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1389f4b9 1558 char *c = NULL;
cc377381 1559 const char *p;
cc377381 1560 int r;
eecd1362 1561
af9792ac 1562 assert(m);
b61fa4e0 1563 assert(w > 0);
314b4b0a 1564 assert(w < _INHIBIT_WHAT_MAX);
d889a206 1565 assert(unit_name);
eecd1362 1566
df75a1a8
AJ
1567 if (w == INHIBIT_SHUTDOWN)
1568 bus_manager_log_shutdown(m, unit_name);
314b4b0a 1569
df75a1a8
AJ
1570 r = sd_bus_call_method(
1571 m->bus,
1572 "org.freedesktop.systemd1",
1573 "/org/freedesktop/systemd1",
1574 "org.freedesktop.systemd1.Manager",
1575 "StartUnit",
1576 error,
1577 &reply,
1578 "ss", unit_name, "replace-irreversibly");
1579 if (r < 0)
6d7f7fd4 1580 goto error;
af9792ac 1581
df75a1a8
AJ
1582 r = sd_bus_message_read(reply, "o", &p);
1583 if (r < 0)
6d7f7fd4 1584 goto error;
af9792ac 1585
df75a1a8 1586 c = strdup(p);
6d7f7fd4
AJ
1587 if (!c) {
1588 r = -ENOMEM;
1589 goto error;
1590 }
af9792ac 1591
314b4b0a 1592 m->action_unit = unit_name;
af9792ac
LP
1593 free(m->action_job);
1594 m->action_job = c;
314b4b0a 1595 m->action_what = w;
af9792ac 1596
f9cd6be1 1597 /* Make sure the lid switch is ignored for a while */
9d10cbee 1598 manager_set_lid_switch_ignore(m, now(CLOCK_MONOTONIC) + m->holdoff_timeout_usec);
f9cd6be1 1599
af9792ac 1600 return 0;
6d7f7fd4
AJ
1601
1602error:
1603 /* Tell people that they now may take a lock again */
1604 send_prepare_for(m, m->action_what, false);
1605
1606 return r;
eecd1362
LP
1607}
1608
418b22b8 1609int manager_dispatch_delayed(Manager *manager, bool timeout) {
c0f32805 1610
4afd3348 1611 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
c0f32805 1612 Inhibitor *offending = NULL;
c0f32805
DM
1613 int r;
1614
1615 assert(manager);
c0f32805
DM
1616
1617 if (manager->action_what == 0 || manager->action_job)
1618 return 0;
1619
1620 if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0, &offending)) {
1621 _cleanup_free_ char *comm = NULL, *u = NULL;
1622
418b22b8
DM
1623 if (!timeout)
1624 return 0;
1625
c0f32805
DM
1626 (void) get_process_comm(offending->pid, &comm);
1627 u = uid_to_name(offending->uid);
1628
1629 log_notice("Delay lock is active (UID "UID_FMT"/%s, PID "PID_FMT"/%s) but inhibitor timeout is reached.",
1630 offending->uid, strna(u),
1631 offending->pid, strna(comm));
1632 }
1633
1634 /* Actually do the operation */
1635 r = execute_shutdown_or_sleep(manager, manager->action_what, manager->action_unit, &error);
1636 if (r < 0) {
6d7f7fd4
AJ
1637 log_warning("Error during inhibitor-delayed operation (already returned success to client): %s",
1638 bus_error_message(&error, r));
c0f32805
DM
1639
1640 manager->action_unit = NULL;
1641 manager->action_what = 0;
418b22b8 1642 return r;
c0f32805
DM
1643 }
1644
418b22b8
DM
1645 return 1;
1646}
1647
1648static int manager_inhibit_timeout_handler(
1649 sd_event_source *s,
1650 uint64_t usec,
1651 void *userdata) {
1652
1653 Manager *manager = userdata;
1654 int r;
1655
1656 assert(manager);
1657 assert(manager->inhibit_timeout_source == s);
1658
1659 r = manager_dispatch_delayed(manager, true);
1660 return (r < 0) ? r : 0;
c0f32805
DM
1661}
1662
314b4b0a
LP
1663static int delay_shutdown_or_sleep(
1664 Manager *m,
1665 InhibitWhat w,
1666 const char *unit_name) {
eecd1362 1667
c0f32805
DM
1668 int r;
1669 usec_t timeout_val;
1670
eecd1362 1671 assert(m);
d889a206
LP
1672 assert(w >= 0);
1673 assert(w < _INHIBIT_WHAT_MAX);
314b4b0a 1674 assert(unit_name);
eecd1362 1675
c0f32805
DM
1676 timeout_val = now(CLOCK_MONOTONIC) + m->inhibit_delay_max;
1677
1678 if (m->inhibit_timeout_source) {
1679 r = sd_event_source_set_time(m->inhibit_timeout_source, timeout_val);
1680 if (r < 0)
c2a23db0 1681 return log_error_errno(r, "sd_event_source_set_time() failed: %m");
c0f32805
DM
1682
1683 r = sd_event_source_set_enabled(m->inhibit_timeout_source, SD_EVENT_ONESHOT);
1684 if (r < 0)
c2a23db0 1685 return log_error_errno(r, "sd_event_source_set_enabled() failed: %m");
c0f32805
DM
1686 } else {
1687 r = sd_event_add_time(m->event, &m->inhibit_timeout_source, CLOCK_MONOTONIC,
1688 timeout_val, 0, manager_inhibit_timeout_handler, m);
1689 if (r < 0)
1690 return r;
1691 }
1692
314b4b0a
LP
1693 m->action_unit = unit_name;
1694 m->action_what = w;
d889a206
LP
1695
1696 return 0;
1697}
1698
069cfc85
LP
1699int bus_manager_shutdown_or_sleep_now_or_later(
1700 Manager *m,
1701 const char *unit_name,
1702 InhibitWhat w,
cc377381 1703 sd_bus_error *error) {
069cfc85
LP
1704
1705 bool delayed;
1706 int r;
1707
1708 assert(m);
1709 assert(unit_name);
b61fa4e0 1710 assert(w > 0);
069cfc85 1711 assert(w <= _INHIBIT_WHAT_MAX);
af9792ac 1712 assert(!m->action_job);
069cfc85 1713
314b4b0a
LP
1714 /* Tell everybody to prepare for shutdown/sleep */
1715 send_prepare_for(m, w, true);
1716
069cfc85
LP
1717 delayed =
1718 m->inhibit_delay_max > 0 &&
85a428c6 1719 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0, NULL);
069cfc85
LP
1720
1721 if (delayed)
1722 /* Shutdown is delayed, keep in mind what we
1723 * want to do, and start a timeout */
1724 r = delay_shutdown_or_sleep(m, w, unit_name);
314b4b0a 1725 else
069cfc85
LP
1726 /* Shutdown is not delayed, execute it
1727 * immediately */
314b4b0a 1728 r = execute_shutdown_or_sleep(m, w, unit_name, error);
069cfc85
LP
1729
1730 return r;
1731}
1732
b7aa9589 1733static int verify_shutdown_creds(
d889a206 1734 Manager *m,
cc377381 1735 sd_bus_message *message,
d889a206 1736 InhibitWhat w,
b7aa9589 1737 bool interactive,
d889a206
LP
1738 const char *action,
1739 const char *action_multiple_sessions,
1740 const char *action_ignore_inhibit,
ebcf1f97 1741 sd_bus_error *error) {
d889a206 1742
4afd3348 1743 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
069cfc85 1744 bool multiple_sessions, blocked;
cc377381 1745 uid_t uid;
b7aa9589 1746 int r;
d889a206
LP
1747
1748 assert(m);
d889a206 1749 assert(message);
d889a206
LP
1750 assert(w >= 0);
1751 assert(w <= _INHIBIT_WHAT_MAX);
6524990f 1752
05bae4a6 1753 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
5b12334d
LP
1754 if (r < 0)
1755 return r;
1756
05bae4a6 1757 r = sd_bus_creds_get_euid(creds, &uid);
cc377381 1758 if (r < 0)
ebcf1f97 1759 return r;
409133be 1760
cc377381 1761 r = have_multiple_sessions(m, uid);
d889a206 1762 if (r < 0)
ebcf1f97 1763 return r;
d889a206
LP
1764
1765 multiple_sessions = r > 0;
85a428c6 1766 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, uid, NULL);
d889a206 1767
b7aa9589 1768 if (multiple_sessions && action_multiple_sessions) {
403ed0e5 1769 r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_multiple_sessions, NULL, interactive, UID_INVALID, &m->polkit_registry, error);
d889a206 1770 if (r < 0)
ebcf1f97 1771 return r;
055d4066
ZJS
1772 if (r == 0)
1773 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
d889a206
LP
1774 }
1775
b7aa9589 1776 if (blocked && action_ignore_inhibit) {
403ed0e5 1777 r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_ignore_inhibit, NULL, interactive, UID_INVALID, &m->polkit_registry, error);
d889a206 1778 if (r < 0)
ebcf1f97 1779 return r;
055d4066
ZJS
1780 if (r == 0)
1781 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
d889a206
LP
1782 }
1783
b7aa9589 1784 if (!multiple_sessions && !blocked && action) {
403ed0e5 1785 r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action, NULL, interactive, UID_INVALID, &m->polkit_registry, error);
d889a206 1786 if (r < 0)
ebcf1f97 1787 return r;
055d4066
ZJS
1788 if (r == 0)
1789 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
d889a206
LP
1790 }
1791
b7aa9589
DM
1792 return 0;
1793}
1794
1795static int method_do_shutdown_or_sleep(
1796 Manager *m,
1797 sd_bus_message *message,
1798 const char *unit_name,
1799 InhibitWhat w,
1800 const char *action,
1801 const char *action_multiple_sessions,
1802 const char *action_ignore_inhibit,
1803 const char *sleep_verb,
1804 sd_bus_error *error) {
1805
1806 int interactive, r;
1807
1808 assert(m);
1809 assert(message);
1810 assert(unit_name);
1811 assert(w >= 0);
1812 assert(w <= _INHIBIT_WHAT_MAX);
1813
1814 r = sd_bus_message_read(message, "b", &interactive);
1815 if (r < 0)
1816 return r;
1817
1818 /* Don't allow multiple jobs being executed at the same time */
1819 if (m->action_what)
1820 return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS, "There's already a shutdown or sleep operation in progress");
1821
1822 if (sleep_verb) {
1823 r = can_sleep(sleep_verb);
1824 if (r < 0)
1825 return r;
1826
1827 if (r == 0)
1828 return sd_bus_error_setf(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED, "Sleep verb not supported");
1829 }
1830
1831 r = verify_shutdown_creds(m, message, w, interactive, action, action_multiple_sessions,
1832 action_ignore_inhibit, error);
1833 if (r != 0)
1834 return r;
1835
ebcf1f97 1836 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
d889a206 1837 if (r < 0)
ebcf1f97 1838 return r;
d889a206 1839
df2d202e 1840 return sd_bus_reply_method_return(message, NULL);
eecd1362
LP
1841}
1842
19070062 1843static int method_poweroff(sd_bus_message *message, void *userdata, sd_bus_error *error) {
3f49d45a
LP
1844 Manager *m = userdata;
1845
cc377381
LP
1846 return method_do_shutdown_or_sleep(
1847 m, message,
1848 SPECIAL_POWEROFF_TARGET,
1849 INHIBIT_SHUTDOWN,
1850 "org.freedesktop.login1.power-off",
1851 "org.freedesktop.login1.power-off-multiple-sessions",
1852 "org.freedesktop.login1.power-off-ignore-inhibit",
1853 NULL,
ebcf1f97 1854 error);
cc377381 1855}
88e3dc90 1856
19070062 1857static int method_reboot(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381 1858 Manager *m = userdata;
88e3dc90 1859
cc377381
LP
1860 return method_do_shutdown_or_sleep(
1861 m, message,
1862 SPECIAL_REBOOT_TARGET,
1863 INHIBIT_SHUTDOWN,
1864 "org.freedesktop.login1.reboot",
1865 "org.freedesktop.login1.reboot-multiple-sessions",
1866 "org.freedesktop.login1.reboot-ignore-inhibit",
1867 NULL,
ebcf1f97 1868 error);
cc377381 1869}
88e3dc90 1870
36b69c31
LP
1871static int method_halt(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1872 Manager *m = userdata;
1873
1874 return method_do_shutdown_or_sleep(
1875 m, message,
1876 SPECIAL_HALT_TARGET,
1877 INHIBIT_SHUTDOWN,
1878 "org.freedesktop.login1.halt",
1879 "org.freedesktop.login1.halt-multiple-sessions",
1880 "org.freedesktop.login1.halt-ignore-inhibit",
1881 NULL,
1882 error);
1883}
1884
19070062 1885static int method_suspend(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381 1886 Manager *m = userdata;
88e3dc90 1887
cc377381
LP
1888 return method_do_shutdown_or_sleep(
1889 m, message,
1890 SPECIAL_SUSPEND_TARGET,
1891 INHIBIT_SLEEP,
1892 "org.freedesktop.login1.suspend",
1893 "org.freedesktop.login1.suspend-multiple-sessions",
1894 "org.freedesktop.login1.suspend-ignore-inhibit",
1895 "suspend",
ebcf1f97 1896 error);
cc377381 1897}
88e3dc90 1898
15e99a43
LP
1899static int method_hibernate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1900 Manager *m = userdata;
1901
1902 return method_do_shutdown_or_sleep(
1903 m, message,
1904 SPECIAL_HIBERNATE_TARGET,
1905 INHIBIT_SLEEP,
1906 "org.freedesktop.login1.hibernate",
1907 "org.freedesktop.login1.hibernate-multiple-sessions",
1908 "org.freedesktop.login1.hibernate-ignore-inhibit",
1909 "hibernate",
1910 error);
1911}
1912
1913static int method_hybrid_sleep(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1914 Manager *m = userdata;
1915
1916 return method_do_shutdown_or_sleep(
1917 m, message,
1918 SPECIAL_HYBRID_SLEEP_TARGET,
1919 INHIBIT_SLEEP,
1920 "org.freedesktop.login1.hibernate",
1921 "org.freedesktop.login1.hibernate-multiple-sessions",
1922 "org.freedesktop.login1.hibernate-ignore-inhibit",
1923 "hybrid-sleep",
1924 error);
1925}
1926
867c37f6
DM
1927static int nologin_timeout_handler(
1928 sd_event_source *s,
1929 uint64_t usec,
1930 void *userdata) {
1931
1932 Manager *m = userdata;
1933 int r;
1934
1935 log_info("Creating /run/nologin, blocking further logins...");
1936
716cff4b 1937 r = write_string_file_atomic_label("/run/nologin", "System is going down.");
867c37f6
DM
1938 if (r < 0)
1939 log_error_errno(r, "Failed to create /run/nologin: %m");
1940 else
1941 m->unlink_nologin = true;
1942
1943 return 0;
1944}
1945
1946static int update_schedule_file(Manager *m) {
91b3e7fb 1947 _cleanup_free_ char *temp_path = NULL;
867c37f6 1948 _cleanup_fclose_ FILE *f = NULL;
91b3e7fb 1949 int r;
867c37f6
DM
1950
1951 assert(m);
1952
c31ad024 1953 r = mkdir_safe_label("/run/systemd/shutdown", 0755, 0, 0, false);
867c37f6
DM
1954 if (r < 0)
1955 return log_error_errno(r, "Failed to create shutdown subdirectory: %m");
1956
867c37f6
DM
1957 r = fopen_temporary("/run/systemd/shutdown/scheduled", &f, &temp_path);
1958 if (r < 0)
1959 return log_error_errno(r, "Failed to save information about scheduled shutdowns: %m");
1960
1961 (void) fchmod(fileno(f), 0644);
1962
1963 fprintf(f,
1964 "USEC="USEC_FMT"\n"
1965 "WARN_WALL=%i\n"
1966 "MODE=%s\n",
1967 m->scheduled_shutdown_timeout,
1968 m->enable_wall_messages,
1969 m->scheduled_shutdown_type);
1970
91b3e7fb
LP
1971 if (!isempty(m->wall_message)) {
1972 _cleanup_free_ char *t;
1973
1974 t = cescape(m->wall_message);
1975 if (!t) {
1976 r = -ENOMEM;
1977 goto fail;
1978 }
1979
867c37f6 1980 fprintf(f, "WALL_MESSAGE=%s\n", t);
91b3e7fb 1981 }
867c37f6 1982
dacd6cee
LP
1983 r = fflush_and_check(f);
1984 if (r < 0)
1985 goto fail;
867c37f6 1986
dacd6cee 1987 if (rename(temp_path, "/run/systemd/shutdown/scheduled") < 0) {
867c37f6 1988 r = -errno;
dacd6cee 1989 goto fail;
867c37f6
DM
1990 }
1991
dacd6cee
LP
1992 return 0;
1993
1994fail:
1995 (void) unlink(temp_path);
1996 (void) unlink("/run/systemd/shutdown/scheduled");
1997
1998 return log_error_errno(r, "Failed to write information about scheduled shutdowns: %m");
867c37f6
DM
1999}
2000
df75a1a8 2001static void reset_scheduled_shutdown(Manager *m) {
36b69c31
LP
2002 assert(m);
2003
df75a1a8
AJ
2004 m->scheduled_shutdown_timeout_source = sd_event_source_unref(m->scheduled_shutdown_timeout_source);
2005 m->wall_message_timeout_source = sd_event_source_unref(m->wall_message_timeout_source);
2006 m->nologin_timeout_source = sd_event_source_unref(m->nologin_timeout_source);
36b69c31 2007
df75a1a8
AJ
2008 m->scheduled_shutdown_type = mfree(m->scheduled_shutdown_type);
2009 m->scheduled_shutdown_timeout = 0;
2010 m->shutdown_dry_run = false;
2011
2012 if (m->unlink_nologin) {
2013 (void) unlink("/run/nologin");
2014 m->unlink_nologin = false;
2015 }
36b69c31 2016
df75a1a8
AJ
2017 (void) unlink("/run/systemd/shutdown/scheduled");
2018}
2019
8aaa023a
DM
2020static int manager_scheduled_shutdown_handler(
2021 sd_event_source *s,
2022 uint64_t usec,
2023 void *userdata) {
2024
4afd3348 2025 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
8aaa023a
DM
2026 Manager *m = userdata;
2027 const char *target;
2028 int r;
2029
2030 assert(m);
2031
2032 if (isempty(m->scheduled_shutdown_type))
2033 return 0;
2034
36b69c31 2035 if (streq(m->scheduled_shutdown_type, "poweroff"))
8aaa023a 2036 target = SPECIAL_POWEROFF_TARGET;
36b69c31 2037 else if (streq(m->scheduled_shutdown_type, "reboot"))
8aaa023a 2038 target = SPECIAL_REBOOT_TARGET;
36b69c31
LP
2039 else if (streq(m->scheduled_shutdown_type, "halt"))
2040 target = SPECIAL_HALT_TARGET;
2041 else
2042 assert_not_reached("unexpected shutdown type");
8aaa023a 2043
b498d6ea
AJ
2044 /* Don't allow multiple jobs being executed at the same time */
2045 if (m->action_what) {
6d7f7fd4 2046 r = -EALREADY;
b498d6ea 2047 log_error("Scheduled shutdown to %s failed: shutdown or sleep operation already in progress", target);
6d7f7fd4 2048 goto error;
b498d6ea
AJ
2049 }
2050
df75a1a8
AJ
2051 if (m->shutdown_dry_run) {
2052 /* We do not process delay inhibitors here. Otherwise, we
2053 * would have to be considered "in progress" (like the check
2054 * above) for some seconds after our admin has seen the final
2055 * wall message. */
2056
2057 bus_manager_log_shutdown(m, target);
2058 log_info("Running in dry run, suppressing action.");
2059 reset_scheduled_shutdown(m);
2060
2061 return 0;
2062 }
2063
2064 r = bus_manager_shutdown_or_sleep_now_or_later(m, target, INHIBIT_SHUTDOWN, &error);
6d7f7fd4
AJ
2065 if (r < 0) {
2066 log_error_errno(r, "Scheduled shutdown to %s failed: %m", target);
2067 goto error;
2068 }
8aaa023a
DM
2069
2070 return 0;
6d7f7fd4
AJ
2071
2072error:
2073 reset_scheduled_shutdown(m);
2074 return r;
8aaa023a
DM
2075}
2076
19070062 2077static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_bus_error *error) {
8aaa023a 2078 Manager *m = userdata;
4afd3348 2079 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
8aaa023a
DM
2080 const char *action_multiple_sessions = NULL;
2081 const char *action_ignore_inhibit = NULL;
2082 const char *action = NULL;
2083 uint64_t elapse;
2084 char *type;
2085 int r;
d13f5e16 2086 bool dry_run = false;
8aaa023a
DM
2087
2088 assert(m);
2089 assert(message);
2090
2091 r = sd_bus_message_read(message, "st", &type, &elapse);
2092 if (r < 0)
2093 return r;
2094
1389f4b9
DM
2095 if (startswith(type, "dry-")) {
2096 type += 4;
d13f5e16 2097 dry_run = true;
1389f4b9
DM
2098 }
2099
36b69c31
LP
2100 if (streq(type, "poweroff")) {
2101 action = "org.freedesktop.login1.power-off";
2102 action_multiple_sessions = "org.freedesktop.login1.power-off-multiple-sessions";
2103 action_ignore_inhibit = "org.freedesktop.login1.power-off-ignore-inhibit";
2104 } else if (streq(type, "reboot")) {
8aaa023a
DM
2105 action = "org.freedesktop.login1.reboot";
2106 action_multiple_sessions = "org.freedesktop.login1.reboot-multiple-sessions";
2107 action_ignore_inhibit = "org.freedesktop.login1.reboot-ignore-inhibit";
2108 } else if (streq(type, "halt")) {
2109 action = "org.freedesktop.login1.halt";
2110 action_multiple_sessions = "org.freedesktop.login1.halt-multiple-sessions";
2111 action_ignore_inhibit = "org.freedesktop.login1.halt-ignore-inhibit";
8aaa023a
DM
2112 } else
2113 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unsupported shutdown type");
2114
2115 r = verify_shutdown_creds(m, message, INHIBIT_SHUTDOWN, false,
2116 action, action_multiple_sessions, action_ignore_inhibit, error);
2117 if (r != 0)
2118 return r;
2119
2120 if (m->scheduled_shutdown_timeout_source) {
2121 r = sd_event_source_set_time(m->scheduled_shutdown_timeout_source, elapse);
2122 if (r < 0)
c2a23db0 2123 return log_error_errno(r, "sd_event_source_set_time() failed: %m");
8aaa023a
DM
2124
2125 r = sd_event_source_set_enabled(m->scheduled_shutdown_timeout_source, SD_EVENT_ONESHOT);
2126 if (r < 0)
c2a23db0 2127 return log_error_errno(r, "sd_event_source_set_enabled() failed: %m");
8aaa023a
DM
2128 } else {
2129 r = sd_event_add_time(m->event, &m->scheduled_shutdown_timeout_source,
2130 CLOCK_REALTIME, elapse, 0, manager_scheduled_shutdown_handler, m);
2131 if (r < 0)
c2a23db0 2132 return log_error_errno(r, "sd_event_add_time() failed: %m");
8aaa023a
DM
2133 }
2134
2135 r = free_and_strdup(&m->scheduled_shutdown_type, type);
2136 if (r < 0) {
2137 m->scheduled_shutdown_timeout_source = sd_event_source_unref(m->scheduled_shutdown_timeout_source);
2138 return log_oom();
2139 }
2140
d13f5e16
LP
2141 m->shutdown_dry_run = dry_run;
2142
867c37f6
DM
2143 if (m->nologin_timeout_source) {
2144 r = sd_event_source_set_time(m->nologin_timeout_source, elapse);
2145 if (r < 0)
c2a23db0 2146 return log_error_errno(r, "sd_event_source_set_time() failed: %m");
867c37f6
DM
2147
2148 r = sd_event_source_set_enabled(m->nologin_timeout_source, SD_EVENT_ONESHOT);
2149 if (r < 0)
c2a23db0 2150 return log_error_errno(r, "sd_event_source_set_enabled() failed: %m");
867c37f6
DM
2151 } else {
2152 r = sd_event_add_time(m->event, &m->nologin_timeout_source,
2153 CLOCK_REALTIME, elapse - 5 * USEC_PER_MINUTE, 0, nologin_timeout_handler, m);
2154 if (r < 0)
c2a23db0 2155 return log_error_errno(r, "sd_event_add_time() failed: %m");
867c37f6
DM
2156 }
2157
8aaa023a
DM
2158 m->scheduled_shutdown_timeout = elapse;
2159
e2fa5721
DM
2160 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_AUGMENT|SD_BUS_CREDS_TTY|SD_BUS_CREDS_UID, &creds);
2161 if (r >= 0) {
011062f3 2162 const char *tty = NULL;
e2fa5721
DM
2163
2164 (void) sd_bus_creds_get_uid(creds, &m->scheduled_shutdown_uid);
2165 (void) sd_bus_creds_get_tty(creds, &tty);
2166
2167 r = free_and_strdup(&m->scheduled_shutdown_tty, tty);
2168 if (r < 0) {
2169 m->scheduled_shutdown_timeout_source = sd_event_source_unref(m->scheduled_shutdown_timeout_source);
2170 return log_oom();
2171 }
2172 }
2173
2174 r = manager_setup_wall_message_timer(m);
2175 if (r < 0)
2176 return r;
2177
f8169e62
AJ
2178 r = update_schedule_file(m);
2179 if (r < 0)
2180 return r;
867c37f6 2181
8aaa023a
DM
2182 return sd_bus_reply_method_return(message, NULL);
2183}
2184
19070062 2185static int method_cancel_scheduled_shutdown(sd_bus_message *message, void *userdata, sd_bus_error *error) {
8aaa023a
DM
2186 Manager *m = userdata;
2187 bool cancelled;
2188
2189 assert(m);
2190 assert(message);
2191
2192 cancelled = m->scheduled_shutdown_type != NULL;
1389f4b9 2193 reset_scheduled_shutdown(m);
fb91034c 2194
e2fa5721 2195 if (cancelled) {
4afd3348 2196 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
e2fa5721
DM
2197 const char *tty = NULL;
2198 uid_t uid = 0;
2199 int r;
2200
2201 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_AUGMENT|SD_BUS_CREDS_TTY|SD_BUS_CREDS_UID, &creds);
2202 if (r >= 0) {
2203 (void) sd_bus_creds_get_uid(creds, &uid);
2204 (void) sd_bus_creds_get_tty(creds, &tty);
2205 }
2206
2207 utmp_wall("The system shutdown has been cancelled",
d0260817 2208 uid_to_name(uid), tty, logind_wall_tty_filter, m);
e2fa5721
DM
2209 }
2210
8aaa023a
DM
2211 return sd_bus_reply_method_return(message, "b", cancelled);
2212}
2213
cc377381
LP
2214static int method_can_shutdown_or_sleep(
2215 Manager *m,
2216 sd_bus_message *message,
2217 InhibitWhat w,
2218 const char *action,
2219 const char *action_multiple_sessions,
2220 const char *action_ignore_inhibit,
ebcf1f97
LP
2221 const char *sleep_verb,
2222 sd_bus_error *error) {
de07ab16 2223
4afd3348 2224 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
cc377381
LP
2225 bool multiple_sessions, challenge, blocked;
2226 const char *result = NULL;
2227 uid_t uid;
2228 int r;
de07ab16 2229
cc377381
LP
2230 assert(m);
2231 assert(message);
2232 assert(w >= 0);
2233 assert(w <= _INHIBIT_WHAT_MAX);
2234 assert(action);
2235 assert(action_multiple_sessions);
2236 assert(action_ignore_inhibit);
de07ab16 2237
cc377381
LP
2238 if (sleep_verb) {
2239 r = can_sleep(sleep_verb);
de07ab16 2240 if (r < 0)
ebcf1f97 2241 return r;
cc377381 2242 if (r == 0)
df2d202e 2243 return sd_bus_reply_method_return(message, "s", "na");
cc377381 2244 }
de07ab16 2245
05bae4a6 2246 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
5b12334d
LP
2247 if (r < 0)
2248 return r;
2249
05bae4a6 2250 r = sd_bus_creds_get_euid(creds, &uid);
cc377381 2251 if (r < 0)
ebcf1f97 2252 return r;
de07ab16 2253
cc377381
LP
2254 r = have_multiple_sessions(m, uid);
2255 if (r < 0)
ebcf1f97 2256 return r;
de07ab16 2257
cc377381 2258 multiple_sessions = r > 0;
85a428c6 2259 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, uid, NULL);
de07ab16 2260
cc377381 2261 if (multiple_sessions) {
403ed0e5 2262 r = bus_test_polkit(message, CAP_SYS_BOOT, action_multiple_sessions, NULL, UID_INVALID, &challenge, error);
de07ab16 2263 if (r < 0)
ebcf1f97 2264 return r;
bef422ae 2265
cc377381
LP
2266 if (r > 0)
2267 result = "yes";
2268 else if (challenge)
2269 result = "challenge";
2270 else
2271 result = "no";
2272 }
bef422ae 2273
cc377381 2274 if (blocked) {
403ed0e5 2275 r = bus_test_polkit(message, CAP_SYS_BOOT, action_ignore_inhibit, NULL, UID_INVALID, &challenge, error);
bef422ae 2276 if (r < 0)
ebcf1f97 2277 return r;
bef422ae 2278
cc377381
LP
2279 if (r > 0 && !result)
2280 result = "yes";
2281 else if (challenge && (!result || streq(result, "yes")))
2282 result = "challenge";
2283 else
2284 result = "no";
2285 }
bef422ae 2286
cc377381
LP
2287 if (!multiple_sessions && !blocked) {
2288 /* If neither inhibit nor multiple sessions
2289 * apply then just check the normal policy */
bef422ae 2290
403ed0e5 2291 r = bus_test_polkit(message, CAP_SYS_BOOT, action, NULL, UID_INVALID, &challenge, error);
bef422ae 2292 if (r < 0)
ebcf1f97 2293 return r;
bef422ae 2294
cc377381
LP
2295 if (r > 0)
2296 result = "yes";
2297 else if (challenge)
2298 result = "challenge";
2299 else
2300 result = "no";
2301 }
bef422ae 2302
df2d202e 2303 return sd_bus_reply_method_return(message, "s", result);
cc377381 2304}
bef422ae 2305
19070062 2306static int method_can_poweroff(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381 2307 Manager *m = userdata;
bef422ae 2308
cc377381
LP
2309 return method_can_shutdown_or_sleep(
2310 m, message,
2311 INHIBIT_SHUTDOWN,
2312 "org.freedesktop.login1.power-off",
2313 "org.freedesktop.login1.power-off-multiple-sessions",
2314 "org.freedesktop.login1.power-off-ignore-inhibit",
ebcf1f97
LP
2315 NULL,
2316 error);
cc377381 2317}
bef422ae 2318
19070062 2319static int method_can_reboot(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381 2320 Manager *m = userdata;
bef422ae 2321
cc377381
LP
2322 return method_can_shutdown_or_sleep(
2323 m, message,
2324 INHIBIT_SHUTDOWN,
2325 "org.freedesktop.login1.reboot",
2326 "org.freedesktop.login1.reboot-multiple-sessions",
2327 "org.freedesktop.login1.reboot-ignore-inhibit",
ebcf1f97
LP
2328 NULL,
2329 error);
cc377381 2330}
bef422ae 2331
36b69c31
LP
2332static int method_can_halt(sd_bus_message *message, void *userdata, sd_bus_error *error) {
2333 Manager *m = userdata;
2334
2335 return method_can_shutdown_or_sleep(
2336 m, message,
2337 INHIBIT_SHUTDOWN,
2338 "org.freedesktop.login1.halt",
2339 "org.freedesktop.login1.halt-multiple-sessions",
2340 "org.freedesktop.login1.halt-ignore-inhibit",
2341 NULL,
2342 error);
2343}
2344
19070062 2345static int method_can_suspend(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381 2346 Manager *m = userdata;
7f7bb946 2347
cc377381
LP
2348 return method_can_shutdown_or_sleep(
2349 m, message,
2350 INHIBIT_SLEEP,
2351 "org.freedesktop.login1.suspend",
2352 "org.freedesktop.login1.suspend-multiple-sessions",
2353 "org.freedesktop.login1.suspend-ignore-inhibit",
ebcf1f97
LP
2354 "suspend",
2355 error);
cc377381 2356}
7f7bb946 2357
19070062 2358static int method_can_hibernate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381 2359 Manager *m = userdata;
02b16a19 2360
cc377381
LP
2361 return method_can_shutdown_or_sleep(
2362 m, message,
2363 INHIBIT_SLEEP,
2364 "org.freedesktop.login1.hibernate",
2365 "org.freedesktop.login1.hibernate-multiple-sessions",
2366 "org.freedesktop.login1.hibernate-ignore-inhibit",
ebcf1f97
LP
2367 "hibernate",
2368 error);
cc377381 2369}
7f7bb946 2370
19070062 2371static int method_can_hybrid_sleep(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381 2372 Manager *m = userdata;
7f7bb946 2373
cc377381
LP
2374 return method_can_shutdown_or_sleep(
2375 m, message,
2376 INHIBIT_SLEEP,
2377 "org.freedesktop.login1.hibernate",
2378 "org.freedesktop.login1.hibernate-multiple-sessions",
2379 "org.freedesktop.login1.hibernate-ignore-inhibit",
ebcf1f97
LP
2380 "hybrid-sleep",
2381 error);
cc377381 2382}
38f3fc7d 2383
5bdf2243
JJ
2384static int property_get_reboot_to_firmware_setup(
2385 sd_bus *bus,
2386 const char *path,
2387 const char *interface,
2388 const char *property,
2389 sd_bus_message *reply,
2390 void *userdata,
2391 sd_bus_error *error) {
2392 int r;
2393
2394 assert(bus);
2395 assert(reply);
2396 assert(userdata);
2397
2398 r = efi_get_reboot_to_firmware();
2399 if (r < 0 && r != -EOPNOTSUPP)
2400 return r;
2401
2402 return sd_bus_message_append(reply, "b", r > 0);
2403}
2404
2405static int method_set_reboot_to_firmware_setup(
5bdf2243
JJ
2406 sd_bus_message *message,
2407 void *userdata,
2408 sd_bus_error *error) {
2409
2410 int b, r;
5bdf2243
JJ
2411 Manager *m = userdata;
2412
5bdf2243
JJ
2413 assert(message);
2414 assert(m);
2415
889f25b2 2416 r = sd_bus_message_read(message, "b", &b);
5bdf2243
JJ
2417 if (r < 0)
2418 return r;
2419
2420 r = bus_verify_polkit_async(message,
2421 CAP_SYS_ADMIN,
2422 "org.freedesktop.login1.set-reboot-to-firmware-setup",
403ed0e5 2423 NULL,
889f25b2 2424 false,
5bdf2243
JJ
2425 UID_INVALID,
2426 &m->polkit_registry,
2427 error);
2428 if (r < 0)
2429 return r;
2430 if (r == 0)
2431 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
2432
2433 r = efi_set_reboot_to_firmware(b);
2434 if (r < 0)
2435 return r;
2436
2437 return sd_bus_reply_method_return(message, NULL);
2438}
2439
2440static int method_can_reboot_to_firmware_setup(
5bdf2243
JJ
2441 sd_bus_message *message,
2442 void *userdata,
2443 sd_bus_error *error) {
2444
2445 int r;
2446 bool challenge;
2447 const char *result;
2448 Manager *m = userdata;
2449
5bdf2243
JJ
2450 assert(message);
2451 assert(m);
2452
2453 r = efi_reboot_to_firmware_supported();
2454 if (r == -EOPNOTSUPP)
2455 return sd_bus_reply_method_return(message, "s", "na");
2456 else if (r < 0)
2457 return r;
2458
2459 r = bus_test_polkit(message,
2460 CAP_SYS_ADMIN,
2461 "org.freedesktop.login1.set-reboot-to-firmware-setup",
403ed0e5 2462 NULL,
5bdf2243
JJ
2463 UID_INVALID,
2464 &challenge,
2465 error);
2466 if (r < 0)
2467 return r;
2468
2469 if (r > 0)
2470 result = "yes";
2471 else if (challenge)
2472 result = "challenge";
2473 else
2474 result = "no";
2475
2476 return sd_bus_reply_method_return(message, "s", result);
2477}
2478
9ef15026
JS
2479static int method_set_wall_message(
2480 sd_bus_message *message,
2481 void *userdata,
2482 sd_bus_error *error) {
2483
2484 int r;
2485 Manager *m = userdata;
2486 char *wall_message;
2cf088b5 2487 int enable_wall_messages;
9ef15026
JS
2488
2489 assert(message);
2490 assert(m);
2491
2492 r = sd_bus_message_read(message, "sb", &wall_message, &enable_wall_messages);
2493 if (r < 0)
2494 return r;
2495
2496 r = bus_verify_polkit_async(message,
2497 CAP_SYS_ADMIN,
2498 "org.freedesktop.login1.set-wall-message",
403ed0e5 2499 NULL,
9ef15026
JS
2500 false,
2501 UID_INVALID,
2502 &m->polkit_registry,
2503 error);
9ef15026
JS
2504 if (r < 0)
2505 return r;
2506 if (r == 0)
2507 return 1; /* Will call us back */
2508
28a9ec44
ZJS
2509 r = free_and_strdup(&m->wall_message, empty_to_null(wall_message));
2510 if (r < 0)
2511 return log_oom();
5744f59a 2512
9ef15026
JS
2513 m->enable_wall_messages = enable_wall_messages;
2514
2515 return sd_bus_reply_method_return(message, NULL);
2516}
2517
19070062 2518static int method_inhibit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
4afd3348 2519 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
cc377381
LP
2520 const char *who, *why, *what, *mode;
2521 _cleanup_free_ char *id = NULL;
2522 _cleanup_close_ int fifo_fd = -1;
2523 Manager *m = userdata;
2524 Inhibitor *i = NULL;
2525 InhibitMode mm;
2526 InhibitWhat w;
2527 pid_t pid;
2528 uid_t uid;
2529 int r;
7f7bb946 2530
cc377381
LP
2531 assert(message);
2532 assert(m);
38f3fc7d 2533
cc377381
LP
2534 r = sd_bus_message_read(message, "ssss", &what, &who, &why, &mode);
2535 if (r < 0)
ebcf1f97 2536 return r;
38f3fc7d 2537
cc377381
LP
2538 w = inhibit_what_from_string(what);
2539 if (w <= 0)
ebcf1f97 2540 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid what specification %s", what);
38f3fc7d 2541
cc377381
LP
2542 mm = inhibit_mode_from_string(mode);
2543 if (mm < 0)
ebcf1f97 2544 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid mode specification %s", mode);
7f7bb946 2545
cc377381
LP
2546 /* Delay is only supported for shutdown/sleep */
2547 if (mm == INHIBIT_DELAY && (w & ~(INHIBIT_SHUTDOWN|INHIBIT_SLEEP)))
ebcf1f97 2548 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Delay inhibitors only supported for shutdown and sleep");
38f3fc7d 2549
cc377381
LP
2550 /* Don't allow taking delay locks while we are already
2551 * executing the operation. We shouldn't create the impression
2552 * that the lock was successful if the machine is about to go
2553 * down/suspend any moment. */
2554 if (m->action_what & w)
ebcf1f97 2555 return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS, "The operation inhibition has been requested for is already running");
cc377381 2556
c529695e
LP
2557 r = bus_verify_polkit_async(
2558 message,
2559 CAP_SYS_BOOT,
2560 w == INHIBIT_SHUTDOWN ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
2561 w == INHIBIT_SLEEP ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep" : "org.freedesktop.login1.inhibit-delay-sleep") :
2562 w == INHIBIT_IDLE ? "org.freedesktop.login1.inhibit-block-idle" :
2563 w == INHIBIT_HANDLE_POWER_KEY ? "org.freedesktop.login1.inhibit-handle-power-key" :
2564 w == INHIBIT_HANDLE_SUSPEND_KEY ? "org.freedesktop.login1.inhibit-handle-suspend-key" :
2565 w == INHIBIT_HANDLE_HIBERNATE_KEY ? "org.freedesktop.login1.inhibit-handle-hibernate-key" :
2566 "org.freedesktop.login1.inhibit-handle-lid-switch",
403ed0e5 2567 NULL,
c529695e
LP
2568 false,
2569 UID_INVALID,
2570 &m->polkit_registry,
2571 error);
cc377381 2572 if (r < 0)
ebcf1f97 2573 return r;
cc377381
LP
2574 if (r == 0)
2575 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
7f7bb946 2576
05bae4a6 2577 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID, &creds);
5b12334d
LP
2578 if (r < 0)
2579 return r;
2580
05bae4a6 2581 r = sd_bus_creds_get_euid(creds, &uid);
cc377381 2582 if (r < 0)
ebcf1f97 2583 return r;
7f7bb946 2584
5b12334d 2585 r = sd_bus_creds_get_pid(creds, &pid);
cc377381 2586 if (r < 0)
ebcf1f97 2587 return r;
47a26690 2588
c5a11ae2
LP
2589 if (hashmap_size(m->inhibitors) >= m->inhibitors_max)
2590 return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Maximum number of inhibitors (%" PRIu64 ") reached, refusing further inhibitors.", m->inhibitors_max);
2591
cc377381 2592 do {
97b11eed 2593 id = mfree(id);
47a26690 2594
cc377381 2595 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0)
ebcf1f97 2596 return -ENOMEM;
47a26690 2597
cc377381 2598 } while (hashmap_get(m->inhibitors, id));
47a26690 2599
cc377381
LP
2600 r = manager_add_inhibitor(m, id, &i);
2601 if (r < 0)
ebcf1f97 2602 return r;
47a26690 2603
cc377381
LP
2604 i->what = w;
2605 i->mode = mm;
2606 i->pid = pid;
2607 i->uid = uid;
2608 i->why = strdup(why);
2609 i->who = strdup(who);
7f7bb946 2610
cc377381 2611 if (!i->why || !i->who) {
ebcf1f97 2612 r = -ENOMEM;
cc377381
LP
2613 goto fail;
2614 }
b668e064 2615
cc377381
LP
2616 fifo_fd = inhibitor_create_fifo(i);
2617 if (fifo_fd < 0) {
ebcf1f97 2618 r = fifo_fd;
cc377381
LP
2619 goto fail;
2620 }
b668e064 2621
cc377381 2622 inhibitor_start(i);
b668e064 2623
df2d202e 2624 return sd_bus_reply_method_return(message, "h", fifo_fd);
b668e064 2625
cc377381
LP
2626fail:
2627 if (i)
2628 inhibitor_free(i);
89f13440 2629
cc377381
LP
2630 return r;
2631}
3f49d45a 2632
cc377381
LP
2633const sd_bus_vtable manager_vtable[] = {
2634 SD_BUS_VTABLE_START(0),
2635
e2fa5721
DM
2636 SD_BUS_WRITABLE_PROPERTY("EnableWallMessages", "b", NULL, NULL, offsetof(Manager, enable_wall_messages), 0),
2637 SD_BUS_WRITABLE_PROPERTY("WallMessage", "s", NULL, NULL, offsetof(Manager, wall_message), 0),
2638
556089dc
LP
2639 SD_BUS_PROPERTY("NAutoVTs", "u", NULL, offsetof(Manager, n_autovts), SD_BUS_VTABLE_PROPERTY_CONST),
2640 SD_BUS_PROPERTY("KillOnlyUsers", "as", NULL, offsetof(Manager, kill_only_users), SD_BUS_VTABLE_PROPERTY_CONST),
2641 SD_BUS_PROPERTY("KillExcludeUsers", "as", NULL, offsetof(Manager, kill_exclude_users), SD_BUS_VTABLE_PROPERTY_CONST),
2642 SD_BUS_PROPERTY("KillUserProcesses", "b", NULL, offsetof(Manager, kill_user_processes), SD_BUS_VTABLE_PROPERTY_CONST),
5bdf2243 2643 SD_BUS_PROPERTY("RebootToFirmwareSetup", "b", property_get_reboot_to_firmware_setup, 0, SD_BUS_VTABLE_PROPERTY_CONST),
cc377381
LP
2644 SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
2645 SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
2646 SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
2647 SD_BUS_PROPERTY("BlockInhibited", "s", property_get_inhibited, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
2648 SD_BUS_PROPERTY("DelayInhibited", "s", property_get_inhibited, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
556089dc
LP
2649 SD_BUS_PROPERTY("InhibitDelayMaxUSec", "t", NULL, offsetof(Manager, inhibit_delay_max), SD_BUS_VTABLE_PROPERTY_CONST),
2650 SD_BUS_PROPERTY("HandlePowerKey", "s", property_get_handle_action, offsetof(Manager, handle_power_key), SD_BUS_VTABLE_PROPERTY_CONST),
2651 SD_BUS_PROPERTY("HandleSuspendKey", "s", property_get_handle_action, offsetof(Manager, handle_suspend_key), SD_BUS_VTABLE_PROPERTY_CONST),
2652 SD_BUS_PROPERTY("HandleHibernateKey", "s", property_get_handle_action, offsetof(Manager, handle_hibernate_key), SD_BUS_VTABLE_PROPERTY_CONST),
2653 SD_BUS_PROPERTY("HandleLidSwitch", "s", property_get_handle_action, offsetof(Manager, handle_lid_switch), SD_BUS_VTABLE_PROPERTY_CONST),
3c56cab4 2654 SD_BUS_PROPERTY("HandleLidSwitchDocked", "s", property_get_handle_action, offsetof(Manager, handle_lid_switch_docked), SD_BUS_VTABLE_PROPERTY_CONST),
9d10cbee 2655 SD_BUS_PROPERTY("HoldoffTimeoutUSec", "t", NULL, offsetof(Manager, holdoff_timeout_usec), SD_BUS_VTABLE_PROPERTY_CONST),
556089dc
LP
2656 SD_BUS_PROPERTY("IdleAction", "s", property_get_handle_action, offsetof(Manager, idle_action), SD_BUS_VTABLE_PROPERTY_CONST),
2657 SD_BUS_PROPERTY("IdleActionUSec", "t", NULL, offsetof(Manager, idle_action_usec), SD_BUS_VTABLE_PROPERTY_CONST),
cc377381
LP
2658 SD_BUS_PROPERTY("PreparingForShutdown", "b", property_get_preparing, 0, 0),
2659 SD_BUS_PROPERTY("PreparingForSleep", "b", property_get_preparing, 0, 0),
8aaa023a 2660 SD_BUS_PROPERTY("ScheduledShutdown", "(st)", property_get_scheduled_shutdown, 0, 0),
14856079 2661 SD_BUS_PROPERTY("Docked", "b", property_get_docked, 0, 0),
6d97d3c6
LP
2662 SD_BUS_PROPERTY("RemoveIPC", "b", bus_property_get_bool, offsetof(Manager, remove_ipc), SD_BUS_VTABLE_PROPERTY_CONST),
2663 SD_BUS_PROPERTY("RuntimeDirectorySize", "t", bus_property_get_size, offsetof(Manager, runtime_dir_size), SD_BUS_VTABLE_PROPERTY_CONST),
c5a11ae2
LP
2664 SD_BUS_PROPERTY("InhibitorsMax", "t", NULL, offsetof(Manager, inhibitors_max), SD_BUS_VTABLE_PROPERTY_CONST),
2665 SD_BUS_PROPERTY("NCurrentInhibitors", "t", property_get_current_inhibitors, 0, 0),
183e0738
LP
2666 SD_BUS_PROPERTY("SessionsMax", "t", NULL, offsetof(Manager, sessions_max), SD_BUS_VTABLE_PROPERTY_CONST),
2667 SD_BUS_PROPERTY("NCurrentSessions", "t", property_get_current_sessions, 0, 0),
6d97d3c6 2668 SD_BUS_PROPERTY("UserTasksMax", "t", NULL, offsetof(Manager, user_tasks_max), SD_BUS_VTABLE_PROPERTY_CONST),
cc377381 2669
adacb957
LP
2670 SD_BUS_METHOD("GetSession", "s", "o", method_get_session, SD_BUS_VTABLE_UNPRIVILEGED),
2671 SD_BUS_METHOD("GetSessionByPID", "u", "o", method_get_session_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
2672 SD_BUS_METHOD("GetUser", "u", "o", method_get_user, SD_BUS_VTABLE_UNPRIVILEGED),
2673 SD_BUS_METHOD("GetUserByPID", "u", "o", method_get_user_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
2674 SD_BUS_METHOD("GetSeat", "s", "o", method_get_seat, SD_BUS_VTABLE_UNPRIVILEGED),
2675 SD_BUS_METHOD("ListSessions", NULL, "a(susso)", method_list_sessions, SD_BUS_VTABLE_UNPRIVILEGED),
2676 SD_BUS_METHOD("ListUsers", NULL, "a(uso)", method_list_users, SD_BUS_VTABLE_UNPRIVILEGED),
2677 SD_BUS_METHOD("ListSeats", NULL, "a(so)", method_list_seats, SD_BUS_VTABLE_UNPRIVILEGED),
2678 SD_BUS_METHOD("ListInhibitors", NULL, "a(ssssuu)", method_list_inhibitors, SD_BUS_VTABLE_UNPRIVILEGED),
a4cd87e9 2679 SD_BUS_METHOD("CreateSession", "uusssssussbssa(sv)", "soshusub", method_create_session, 0),
cc377381 2680 SD_BUS_METHOD("ReleaseSession", "s", NULL, method_release_session, 0),
adacb957
LP
2681 SD_BUS_METHOD("ActivateSession", "s", NULL, method_activate_session, SD_BUS_VTABLE_UNPRIVILEGED),
2682 SD_BUS_METHOD("ActivateSessionOnSeat", "ss", NULL, method_activate_session_on_seat, SD_BUS_VTABLE_UNPRIVILEGED),
c529695e
LP
2683 SD_BUS_METHOD("LockSession", "s", NULL, method_lock_session, SD_BUS_VTABLE_UNPRIVILEGED),
2684 SD_BUS_METHOD("UnlockSession", "s", NULL, method_lock_session, SD_BUS_VTABLE_UNPRIVILEGED),
2685 SD_BUS_METHOD("LockSessions", NULL, NULL, method_lock_sessions, SD_BUS_VTABLE_UNPRIVILEGED),
2686 SD_BUS_METHOD("UnlockSessions", NULL, NULL, method_lock_sessions, SD_BUS_VTABLE_UNPRIVILEGED),
2687 SD_BUS_METHOD("KillSession", "ssi", NULL, method_kill_session, SD_BUS_VTABLE_UNPRIVILEGED),
2688 SD_BUS_METHOD("KillUser", "ui", NULL, method_kill_user, SD_BUS_VTABLE_UNPRIVILEGED),
2689 SD_BUS_METHOD("TerminateSession", "s", NULL, method_terminate_session, SD_BUS_VTABLE_UNPRIVILEGED),
2690 SD_BUS_METHOD("TerminateUser", "u", NULL, method_terminate_user, SD_BUS_VTABLE_UNPRIVILEGED),
2691 SD_BUS_METHOD("TerminateSeat", "s", NULL, method_terminate_seat, SD_BUS_VTABLE_UNPRIVILEGED),
adacb957
LP
2692 SD_BUS_METHOD("SetUserLinger", "ubb", NULL, method_set_user_linger, SD_BUS_VTABLE_UNPRIVILEGED),
2693 SD_BUS_METHOD("AttachDevice", "ssb", NULL, method_attach_device, SD_BUS_VTABLE_UNPRIVILEGED),
2694 SD_BUS_METHOD("FlushDevices", "b", NULL, method_flush_devices, SD_BUS_VTABLE_UNPRIVILEGED),
2695 SD_BUS_METHOD("PowerOff", "b", NULL, method_poweroff, SD_BUS_VTABLE_UNPRIVILEGED),
2696 SD_BUS_METHOD("Reboot", "b", NULL, method_reboot, SD_BUS_VTABLE_UNPRIVILEGED),
36b69c31 2697 SD_BUS_METHOD("Halt", "b", NULL, method_halt, SD_BUS_VTABLE_UNPRIVILEGED),
adacb957
LP
2698 SD_BUS_METHOD("Suspend", "b", NULL, method_suspend, SD_BUS_VTABLE_UNPRIVILEGED),
2699 SD_BUS_METHOD("Hibernate", "b", NULL, method_hibernate, SD_BUS_VTABLE_UNPRIVILEGED),
2700 SD_BUS_METHOD("HybridSleep", "b", NULL, method_hybrid_sleep, SD_BUS_VTABLE_UNPRIVILEGED),
2701 SD_BUS_METHOD("CanPowerOff", NULL, "s", method_can_poweroff, SD_BUS_VTABLE_UNPRIVILEGED),
2702 SD_BUS_METHOD("CanReboot", NULL, "s", method_can_reboot, SD_BUS_VTABLE_UNPRIVILEGED),
36b69c31 2703 SD_BUS_METHOD("CanHalt", NULL, "s", method_can_halt, SD_BUS_VTABLE_UNPRIVILEGED),
adacb957
LP
2704 SD_BUS_METHOD("CanSuspend", NULL, "s", method_can_suspend, SD_BUS_VTABLE_UNPRIVILEGED),
2705 SD_BUS_METHOD("CanHibernate", NULL, "s", method_can_hibernate, SD_BUS_VTABLE_UNPRIVILEGED),
2706 SD_BUS_METHOD("CanHybridSleep", NULL, "s", method_can_hybrid_sleep, SD_BUS_VTABLE_UNPRIVILEGED),
559b5cc2
LP
2707 SD_BUS_METHOD("ScheduleShutdown", "st", NULL, method_schedule_shutdown, SD_BUS_VTABLE_UNPRIVILEGED),
2708 SD_BUS_METHOD("CancelScheduledShutdown", NULL, "b", method_cancel_scheduled_shutdown, SD_BUS_VTABLE_UNPRIVILEGED),
adacb957 2709 SD_BUS_METHOD("Inhibit", "ssss", "h", method_inhibit, SD_BUS_VTABLE_UNPRIVILEGED),
5bdf2243 2710 SD_BUS_METHOD("CanRebootToFirmwareSetup", NULL, "s", method_can_reboot_to_firmware_setup, SD_BUS_VTABLE_UNPRIVILEGED),
889f25b2 2711 SD_BUS_METHOD("SetRebootToFirmwareSetup", "b", NULL, method_set_reboot_to_firmware_setup, SD_BUS_VTABLE_UNPRIVILEGED),
9ef15026 2712 SD_BUS_METHOD("SetWallMessage", "sb", NULL, method_set_wall_message, SD_BUS_VTABLE_UNPRIVILEGED),
cc377381
LP
2713
2714 SD_BUS_SIGNAL("SessionNew", "so", 0),
2715 SD_BUS_SIGNAL("SessionRemoved", "so", 0),
2716 SD_BUS_SIGNAL("UserNew", "uo", 0),
2717 SD_BUS_SIGNAL("UserRemoved", "uo", 0),
2718 SD_BUS_SIGNAL("SeatNew", "so", 0),
2719 SD_BUS_SIGNAL("SeatRemoved", "so", 0),
2720 SD_BUS_SIGNAL("PrepareForShutdown", "b", 0),
2721 SD_BUS_SIGNAL("PrepareForSleep", "b", 0),
2722
2723 SD_BUS_VTABLE_END
2724};
3f49d45a 2725
99e7e392
DH
2726static int session_jobs_reply(Session *s, const char *unit, const char *result) {
2727 int r = 0;
2728
2729 assert(s);
2730 assert(unit);
2731
2732 if (!s->started)
2733 return r;
2734
2735 if (streq(result, "done"))
2736 r = session_send_create_reply(s, NULL);
2737 else {
4afd3348 2738 _cleanup_(sd_bus_error_free) sd_bus_error e = SD_BUS_ERROR_NULL;
99e7e392
DH
2739
2740 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
2741 r = session_send_create_reply(s, &e);
2742 }
2743
2744 return r;
2745}
2746
19070062 2747int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
2748 const char *path, *result, *unit;
2749 Manager *m = userdata;
2750 Session *session;
2751 uint32_t id;
2752 User *user;
2753 int r;
3f49d45a 2754
cc377381
LP
2755 assert(message);
2756 assert(m);
3f49d45a 2757
cc377381
LP
2758 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
2759 if (r < 0) {
ebcf1f97 2760 bus_log_parse_error(r);
65d73cf0 2761 return 0;
cc377381 2762 }
3f49d45a 2763
cc377381 2764 if (m->action_job && streq(m->action_job, path)) {
af4efb51 2765 log_info("Operation '%s' finished.", inhibit_what_to_string(m->action_what));
3f49d45a 2766
cc377381
LP
2767 /* Tell people that they now may take a lock again */
2768 send_prepare_for(m, m->action_what, false);
3f49d45a 2769
491ac9f2 2770 m->action_job = mfree(m->action_job);
cc377381
LP
2771 m->action_unit = NULL;
2772 m->action_what = 0;
2773 return 0;
2774 }
3f49d45a 2775
cc377381 2776 session = hashmap_get(m->session_units, unit);
2f157acd
DH
2777 if (session && streq_ptr(path, session->scope_job)) {
2778 session->scope_job = mfree(session->scope_job);
99e7e392 2779 session_jobs_reply(session, unit, result);
3f49d45a 2780
99e7e392 2781 session_save(session);
41dfeaa1 2782 user_save(session->user);
cc377381
LP
2783 session_add_to_gc_queue(session);
2784 }
3f49d45a 2785
cc377381 2786 user = hashmap_get(m->user_units, unit);
2f157acd
DH
2787 if (user &&
2788 (streq_ptr(path, user->service_job) ||
2789 streq_ptr(path, user->slice_job))) {
3f49d45a 2790
491ac9f2
LP
2791 if (streq_ptr(path, user->service_job))
2792 user->service_job = mfree(user->service_job);
3f49d45a 2793
491ac9f2
LP
2794 if (streq_ptr(path, user->slice_job))
2795 user->slice_job = mfree(user->slice_job);
3f49d45a 2796
491ac9f2 2797 LIST_FOREACH(sessions_by_user, session, user->sessions)
99e7e392 2798 session_jobs_reply(session, unit, result);
dd9b67aa 2799
cc377381
LP
2800 user_save(user);
2801 user_add_to_gc_queue(user);
3f49d45a
LP
2802 }
2803
cc377381 2804 return 0;
3f49d45a
LP
2805}
2806
19070062 2807int match_unit_removed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381 2808 const char *path, *unit;
1713813d 2809 Manager *m = userdata;
cc377381
LP
2810 Session *session;
2811 User *user;
2812 int r;
1713813d 2813
1713813d 2814 assert(message);
cc377381 2815 assert(m);
1713813d 2816
cc377381
LP
2817 r = sd_bus_message_read(message, "so", &unit, &path);
2818 if (r < 0) {
ebcf1f97 2819 bus_log_parse_error(r);
65d73cf0 2820 return 0;
cc377381 2821 }
fb6becb4 2822
cc377381
LP
2823 session = hashmap_get(m->session_units, unit);
2824 if (session)
2825 session_add_to_gc_queue(session);
fb6becb4 2826
cc377381
LP
2827 user = hashmap_get(m->user_units, unit);
2828 if (user)
2829 user_add_to_gc_queue(user);
fb6becb4 2830
cc377381
LP
2831 return 0;
2832}
fb6becb4 2833
19070062 2834int match_properties_changed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
2835 _cleanup_free_ char *unit = NULL;
2836 Manager *m = userdata;
2837 const char *path;
2838 Session *session;
2839 User *user;
ebcf1f97 2840 int r;
fb6becb4 2841
cc377381
LP
2842 assert(message);
2843 assert(m);
fb6becb4 2844
cc377381
LP
2845 path = sd_bus_message_get_path(message);
2846 if (!path)
2847 return 0;
fb6becb4 2848
ebcf1f97 2849 r = unit_name_from_dbus_path(path, &unit);
e5f5b5b9
LP
2850 if (r == -EINVAL) /* not a unit */
2851 return 0;
65d73cf0
LP
2852 if (r < 0) {
2853 log_oom();
2854 return 0;
2855 }
fb6becb4 2856
cc377381
LP
2857 session = hashmap_get(m->session_units, unit);
2858 if (session)
2859 session_add_to_gc_queue(session);
fb6becb4 2860
cc377381
LP
2861 user = hashmap_get(m->user_units, unit);
2862 if (user)
2863 user_add_to_gc_queue(user);
fb6becb4 2864
cc377381
LP
2865 return 0;
2866}
6fa48533 2867
19070062 2868int match_reloading(sd_bus_message *message, void *userdata, sd_bus_error *error) {
cc377381
LP
2869 Manager *m = userdata;
2870 Session *session;
2871 Iterator i;
2872 int b, r;
943aca8e 2873
19070062
LP
2874 assert(message);
2875 assert(m);
943aca8e 2876
cc377381
LP
2877 r = sd_bus_message_read(message, "b", &b);
2878 if (r < 0) {
ebcf1f97 2879 bus_log_parse_error(r);
65d73cf0 2880 return 0;
cc377381 2881 }
943aca8e 2882
cc377381
LP
2883 if (b)
2884 return 0;
943aca8e 2885
cc377381
LP
2886 /* systemd finished reloading, let's recheck all our sessions */
2887 log_debug("System manager has been reloaded, rechecking sessions...");
6797c324 2888
cc377381
LP
2889 HASHMAP_FOREACH(session, m->sessions, i)
2890 session_add_to_gc_queue(session);
6797c324 2891
cc377381
LP
2892 return 0;
2893}
943aca8e 2894
cc377381
LP
2895int manager_send_changed(Manager *manager, const char *property, ...) {
2896 char **l;
9418f147
LP
2897
2898 assert(manager);
2899
cc377381 2900 l = strv_from_stdarg_alloca(property);
9418f147 2901
cc377381
LP
2902 return sd_bus_emit_properties_changed_strv(
2903 manager->bus,
2904 "/org/freedesktop/login1",
2905 "org.freedesktop.login1.Manager",
2906 l);
9418f147 2907}
eecd1362 2908
2adae5ac
ZJS
2909static int strdup_job(sd_bus_message *reply, char **job) {
2910 const char *j;
2911 char *copy;
2912 int r;
2913
2914 r = sd_bus_message_read(reply, "o", &j);
2915 if (r < 0)
2916 return r;
2917
2918 copy = strdup(j);
2919 if (!copy)
2920 return -ENOMEM;
2921
2922 *job = copy;
2923 return 1;
2924}
2925
90558f31
LP
2926int manager_start_slice(
2927 Manager *manager,
2928 const char *slice,
2929 const char *description,
2930 const char *after,
2931 const char *after2,
2932 uint64_t tasks_max,
2933 sd_bus_error *error,
2934 char **job) {
2935
4afd3348 2936 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
90558f31
LP
2937 int r;
2938
2939 assert(manager);
2940 assert(slice);
2adae5ac 2941 assert(job);
90558f31
LP
2942
2943 r = sd_bus_message_new_method_call(
2944 manager->bus,
2945 &m,
2946 "org.freedesktop.systemd1",
2947 "/org/freedesktop/systemd1",
2948 "org.freedesktop.systemd1.Manager",
2949 "StartTransientUnit");
2950 if (r < 0)
2951 return r;
2952
2953 r = sd_bus_message_append(m, "ss", strempty(slice), "fail");
2954 if (r < 0)
2955 return r;
2956
2957 r = sd_bus_message_open_container(m, 'a', "(sv)");
2958 if (r < 0)
2959 return r;
2960
2961 if (!isempty(description)) {
2962 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
2963 if (r < 0)
2964 return r;
2965 }
2966
2967 if (!isempty(after)) {
2968 r = sd_bus_message_append(m, "(sv)", "After", "as", 1, after);
2969 if (r < 0)
2970 return r;
2971 }
2972
2973 if (!isempty(after2)) {
2974 r = sd_bus_message_append(m, "(sv)", "After", "as", 1, after2);
2975 if (r < 0)
2976 return r;
2977 }
2978
2979 r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", tasks_max);
2980 if (r < 0)
2981 return r;
2982
2983 r = sd_bus_message_close_container(m);
2984 if (r < 0)
2985 return r;
2986
2987 r = sd_bus_message_append(m, "a(sa(sv))", 0);
2988 if (r < 0)
2989 return r;
2990
2991 r = sd_bus_call(manager->bus, m, 0, error, &reply);
2992 if (r < 0)
2993 return r;
2994
2adae5ac 2995 return strdup_job(reply, job);
90558f31
LP
2996}
2997
fb6becb4
LP
2998int manager_start_scope(
2999 Manager *manager,
3000 const char *scope,
3001 pid_t pid,
3002 const char *slice,
3003 const char *description,
90558f31
LP
3004 const char *after,
3005 const char *after2,
3006 uint64_t tasks_max,
cc377381 3007 sd_bus_error *error,
fb6becb4
LP
3008 char **job) {
3009
4afd3348 3010 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
cc377381 3011 int r;
fb6becb4
LP
3012
3013 assert(manager);
3014 assert(scope);
3015 assert(pid > 1);
2adae5ac 3016 assert(job);
fb6becb4 3017
cc377381
LP
3018 r = sd_bus_message_new_method_call(
3019 manager->bus,
151b9b96 3020 &m,
fb6becb4
LP
3021 "org.freedesktop.systemd1",
3022 "/org/freedesktop/systemd1",
3023 "org.freedesktop.systemd1.Manager",
151b9b96 3024 "StartTransientUnit");
cc377381
LP
3025 if (r < 0)
3026 return r;
fb6becb4 3027
cc377381
LP
3028 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
3029 if (r < 0)
3030 return r;
fb6becb4 3031
cc377381
LP
3032 r = sd_bus_message_open_container(m, 'a', "(sv)");
3033 if (r < 0)
3034 return r;
fb6becb4
LP
3035
3036 if (!isempty(slice)) {
cc377381
LP
3037 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
3038 if (r < 0)
3039 return r;
fb6becb4
LP
3040 }
3041
3042 if (!isempty(description)) {
cc377381
LP
3043 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
3044 if (r < 0)
3045 return r;
fb6becb4
LP
3046 }
3047
ba4c5d93 3048 if (!isempty(after)) {
cc377381
LP
3049 r = sd_bus_message_append(m, "(sv)", "After", "as", 1, after);
3050 if (r < 0)
3051 return r;
7fb3ee51
LP
3052 }
3053
ba4c5d93
LP
3054 if (!isempty(after2)) {
3055 r = sd_bus_message_append(m, "(sv)", "After", "as", 1, after2);
3056 if (r < 0)
3057 return r;
3058 }
3059
fb6becb4
LP
3060 /* cgroup empty notification is not available in containers
3061 * currently. To make this less problematic, let's shorten the
3062 * stop timeout for sessions, so that we don't wait
3063 * forever. */
3064
743e8945
LP
3065 /* Make sure that the session shells are terminated with
3066 * SIGHUP since bash and friends tend to ignore SIGTERM */
cc377381
LP
3067 r = sd_bus_message_append(m, "(sv)", "SendSIGHUP", "b", true);
3068 if (r < 0)
3069 return r;
3070
3071 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
3072 if (r < 0)
3073 return r;
3074
90558f31
LP
3075 r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", tasks_max);
3076 if (r < 0)
3077 return r;
3078
cc377381
LP
3079 r = sd_bus_message_close_container(m);
3080 if (r < 0)
3081 return r;
86b8d289
LP
3082
3083 r = sd_bus_message_append(m, "a(sa(sv))", 0);
3084 if (r < 0)
3085 return r;
cc377381 3086
c49b30a2 3087 r = sd_bus_call(manager->bus, m, 0, error, &reply);
cc377381
LP
3088 if (r < 0)
3089 return r;
fb6becb4 3090
2adae5ac 3091 return strdup_job(reply, job);
fb6becb4
LP
3092}
3093
cc377381 3094int manager_start_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
4afd3348 3095 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
fb6becb4
LP
3096 int r;
3097
3098 assert(manager);
3099 assert(unit);
2adae5ac 3100 assert(job);
fb6becb4 3101
cc377381 3102 r = sd_bus_call_method(
fb6becb4
LP
3103 manager->bus,
3104 "org.freedesktop.systemd1",
3105 "/org/freedesktop/systemd1",
3106 "org.freedesktop.systemd1.Manager",
3107 "StartUnit",
fb6becb4 3108 error,
cc377381 3109 &reply,
79ee4ad1 3110 "ss", unit, "replace");
cc377381 3111 if (r < 0)
fb6becb4 3112 return r;
fb6becb4 3113
2adae5ac 3114 return strdup_job(reply, job);
fb6becb4
LP
3115}
3116
cc377381 3117int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
4afd3348 3118 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
fb6becb4
LP
3119 int r;
3120
3121 assert(manager);
3122 assert(unit);
2adae5ac 3123 assert(job);
fb6becb4 3124
cc377381 3125 r = sd_bus_call_method(
fb6becb4
LP
3126 manager->bus,
3127 "org.freedesktop.systemd1",
3128 "/org/freedesktop/systemd1",
3129 "org.freedesktop.systemd1.Manager",
3130 "StopUnit",
fb6becb4 3131 error,
cc377381
LP
3132 &reply,
3133 "ss", unit, "fail");
fb6becb4 3134 if (r < 0) {
cc377381
LP
3135 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
3136 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
6797c324 3137
2adae5ac 3138 *job = NULL;
cc377381 3139 sd_bus_error_free(error);
6797c324
LP
3140 return 0;
3141 }
3142
fb6becb4
LP
3143 return r;
3144 }
3145
2adae5ac 3146 return strdup_job(reply, job);
fb6becb4
LP
3147}
3148
5f41d1f1 3149int manager_abandon_scope(Manager *manager, const char *scope, sd_bus_error *error) {
5f41d1f1
LP
3150 _cleanup_free_ char *path = NULL;
3151 int r;
3152
3153 assert(manager);
3154 assert(scope);
3155
3156 path = unit_dbus_path_from_name(scope);
3157 if (!path)
3158 return -ENOMEM;
3159
3160 r = sd_bus_call_method(
3161 manager->bus,
3162 "org.freedesktop.systemd1",
3163 path,
3164 "org.freedesktop.systemd1.Scope",
3165 "Abandon",
3166 error,
3167 NULL,
3168 NULL);
3169 if (r < 0) {
3170 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
4e2f8d27
LP
3171 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED) ||
3172 sd_bus_error_has_name(error, BUS_ERROR_SCOPE_NOT_RUNNING)) {
5f41d1f1
LP
3173 sd_bus_error_free(error);
3174 return 0;
3175 }
3176
3177 return r;
3178 }
3179
3180 return 1;
3181}
3182
cc377381 3183int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, sd_bus_error *error) {
fb6becb4
LP
3184 assert(manager);
3185 assert(unit);
3186
cc377381 3187 return sd_bus_call_method(
fb6becb4
LP
3188 manager->bus,
3189 "org.freedesktop.systemd1",
3190 "/org/freedesktop/systemd1",
3191 "org.freedesktop.systemd1.Manager",
3192 "KillUnit",
fb6becb4 3193 error,
cc377381
LP
3194 NULL,
3195 "ssi", unit, who == KILL_LEADER ? "main" : "all", signo);
fb6becb4
LP
3196}
3197
3198int manager_unit_is_active(Manager *manager, const char *unit) {
4afd3348
LP
3199 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
3200 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
fb6becb4 3201 _cleanup_free_ char *path = NULL;
fb6becb4 3202 const char *state;
fb6becb4
LP
3203 int r;
3204
3205 assert(manager);
3206 assert(unit);
3207
fb6becb4
LP
3208 path = unit_dbus_path_from_name(unit);
3209 if (!path)
3210 return -ENOMEM;
3211
cc377381 3212 r = sd_bus_get_property(
fb6becb4
LP
3213 manager->bus,
3214 "org.freedesktop.systemd1",
3215 path,
cc377381
LP
3216 "org.freedesktop.systemd1.Unit",
3217 "ActiveState",
fb6becb4 3218 &error,
cc377381
LP
3219 &reply,
3220 "s");
fb6becb4 3221 if (r < 0) {
cc377381
LP
3222 /* systemd might have droppped off momentarily, let's
3223 * not make this an error */
3224 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
3225 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
6797c324 3226 return true;
6797c324 3227
cc377381
LP
3228 /* If the unit is already unloaded then it's not
3229 * active */
3230 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
3231 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
6797c324 3232 return false;
6797c324 3233
fb6becb4
LP
3234 return r;
3235 }
3236
cc377381
LP
3237 r = sd_bus_message_read(reply, "s", &state);
3238 if (r < 0)
fb6becb4 3239 return -EINVAL;
fb6becb4 3240
cc377381
LP
3241 return !streq(state, "inactive") && !streq(state, "failed");
3242}
3243
3244int manager_job_is_active(Manager *manager, const char *path) {
4afd3348
LP
3245 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
3246 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
cc377381
LP
3247 int r;
3248
3249 assert(manager);
3250 assert(path);
3251
3252 r = sd_bus_get_property(
3253 manager->bus,
3254 "org.freedesktop.systemd1",
3255 path,
3256 "org.freedesktop.systemd1.Job",
3257 "State",
3258 &error,
3259 &reply,
3260 "s");
3261 if (r < 0) {
3262 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
3263 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
3264 return true;
3265
3266 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
3267 return false;
3268
3269 return r;
fb6becb4
LP
3270 }
3271
cc377381
LP
3272 /* We don't actually care about the state really. The fact
3273 * that we could read the job state is enough for us */
fb6becb4 3274
cc377381 3275 return true;
fb6becb4 3276}