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