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