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