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