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