]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/logind-dbus.c
build-sys: rename LEGACY to NOLEGACY to better reflect meaning
[thirdparty/systemd.git] / src / login / logind-dbus.c
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
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
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
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <pwd.h>
26
27 #include "logind.h"
28 #include "dbus-common.h"
29 #include "strv.h"
30 #include "mkdir.h"
31 #include "path-util.h"
32 #include "polkit.h"
33 #include "special.h"
34 #include "sleep-config.h"
35 #include "systemd/sd-id128.h"
36 #include "systemd/sd-messages.h"
37 #include "fileio-label.h"
38 #include "label.h"
39 #include "utf8.h"
40 #include "unit-name.h"
41 #include "bus-errors.h"
42 #include "virt.h"
43
44 #define BUS_MANAGER_INTERFACE \
45 " <interface name=\"org.freedesktop.login1.Manager\">\n" \
46 " <method name=\"GetSession\">\n" \
47 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
48 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
49 " </method>\n" \
50 " <method name=\"GetSessionByPID\">\n" \
51 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
52 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
53 " </method>\n" \
54 " <method name=\"GetUser\">\n" \
55 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
56 " <arg name=\"user\" type=\"o\" direction=\"out\"/>\n" \
57 " </method>\n" \
58 " <method name=\"GetUserByPID\">\n" \
59 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
60 " <arg name=\"user\" type=\"o\" direction=\"out\"/>\n" \
61 " </method>\n" \
62 " <method name=\"GetSeat\">\n" \
63 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
64 " <arg name=\"seat\" type=\"o\" direction=\"out\"/>\n" \
65 " </method>\n" \
66 " <method name=\"ListSessions\">\n" \
67 " <arg name=\"sessions\" type=\"a(susso)\" direction=\"out\"/>\n" \
68 " </method>\n" \
69 " <method name=\"ListUsers\">\n" \
70 " <arg name=\"users\" type=\"a(uso)\" direction=\"out\"/>\n" \
71 " </method>\n" \
72 " <method name=\"ListSeats\">\n" \
73 " <arg name=\"seats\" type=\"a(so)\" direction=\"out\"/>\n" \
74 " </method>\n" \
75 " <method name=\"CreateSession\">\n" \
76 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
77 " <arg name=\"leader\" type=\"u\" direction=\"in\"/>\n" \
78 " <arg name=\"service\" type=\"s\" direction=\"in\"/>\n" \
79 " <arg name=\"type\" type=\"s\" direction=\"in\"/>\n" \
80 " <arg name=\"class\" type=\"s\" direction=\"in\"/>\n" \
81 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
82 " <arg name=\"vtnr\" type=\"u\" direction=\"in\"/>\n" \
83 " <arg name=\"tty\" type=\"s\" direction=\"in\"/>\n" \
84 " <arg name=\"display\" type=\"s\" direction=\"in\"/>\n" \
85 " <arg name=\"remote\" type=\"b\" direction=\"in\"/>\n" \
86 " <arg name=\"remote_user\" type=\"s\" direction=\"in\"/>\n" \
87 " <arg name=\"remote_host\" type=\"s\" direction=\"in\"/>\n" \
88 " <arg name=\"scope_properties\" type=\"a(sv)\" direction=\"in\"/>\n" \
89 " <arg name=\"id\" type=\"s\" direction=\"out\"/>\n" \
90 " <arg name=\"path\" type=\"o\" direction=\"out\"/>\n" \
91 " <arg name=\"runtime_path\" type=\"o\" direction=\"out\"/>\n" \
92 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
93 " <arg name=\"seat\" type=\"s\" direction=\"out\"/>\n" \
94 " <arg name=\"vtnr\" type=\"u\" direction=\"out\"/>\n" \
95 " <arg name=\"existing\" type=\"b\" direction=\"out\"/>\n" \
96 " </method>\n" \
97 " <method name=\"ReleaseSession\">\n" \
98 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
99 " </method>\n" \
100 " <method name=\"ActivateSession\">\n" \
101 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
102 " </method>\n" \
103 " <method name=\"ActivateSessionOnSeat\">\n" \
104 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
105 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
106 " </method>\n" \
107 " <method name=\"LockSession\">\n" \
108 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
109 " </method>\n" \
110 " <method name=\"UnlockSession\">\n" \
111 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
112 " </method>\n" \
113 " <method name=\"LockSessions\"/>\n" \
114 " <method name=\"UnlockSessions\"/>\n" \
115 " <method name=\"KillSession\">\n" \
116 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
117 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
118 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
119 " </method>\n" \
120 " <method name=\"KillUser\">\n" \
121 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
122 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
123 " </method>\n" \
124 " <method name=\"TerminateSession\">\n" \
125 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
126 " </method>\n" \
127 " <method name=\"TerminateUser\">\n" \
128 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
129 " </method>\n" \
130 " <method name=\"TerminateSeat\">\n" \
131 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
132 " </method>\n" \
133 " <method name=\"SetUserLinger\">\n" \
134 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
135 " <arg name=\"b\" type=\"b\" direction=\"in\"/>\n" \
136 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
137 " </method>\n" \
138 " <method name=\"AttachDevice\">\n" \
139 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
140 " <arg name=\"sysfs\" type=\"s\" direction=\"in\"/>\n" \
141 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
142 " </method>\n" \
143 " <method name=\"FlushDevices\">\n" \
144 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
145 " </method>\n" \
146 " <method name=\"PowerOff\">\n" \
147 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
148 " </method>\n" \
149 " <method name=\"Reboot\">\n" \
150 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
151 " </method>\n" \
152 " <method name=\"Suspend\">\n" \
153 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
154 " </method>\n" \
155 " <method name=\"Hibernate\">\n" \
156 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
157 " </method>\n" \
158 " <method name=\"HybridSleep\">\n" \
159 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
160 " </method>\n" \
161 " <method name=\"CanPowerOff\">\n" \
162 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
163 " </method>\n" \
164 " <method name=\"CanReboot\">\n" \
165 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
166 " </method>\n" \
167 " <method name=\"CanSuspend\">\n" \
168 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
169 " </method>\n" \
170 " <method name=\"CanHibernate\">\n" \
171 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
172 " </method>\n" \
173 " <method name=\"CanHybridSleep\">\n" \
174 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
175 " </method>\n" \
176 " <method name=\"Inhibit\">\n" \
177 " <arg name=\"what\" type=\"s\" direction=\"in\"/>\n" \
178 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
179 " <arg name=\"why\" type=\"s\" direction=\"in\"/>\n" \
180 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
181 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
182 " </method>\n" \
183 " <method name=\"ListInhibitors\">\n" \
184 " <arg name=\"inhibitors\" type=\"a(ssssuu)\" direction=\"out\"/>\n" \
185 " </method>\n" \
186 " <signal name=\"SessionNew\">\n" \
187 " <arg name=\"id\" type=\"s\"/>\n" \
188 " <arg name=\"path\" type=\"o\"/>\n" \
189 " </signal>\n" \
190 " <signal name=\"SessionRemoved\">\n" \
191 " <arg name=\"id\" type=\"s\"/>\n" \
192 " <arg name=\"path\" type=\"o\"/>\n" \
193 " </signal>\n" \
194 " <signal name=\"UserNew\">\n" \
195 " <arg name=\"uid\" type=\"u\"/>\n" \
196 " <arg name=\"path\" type=\"o\"/>\n" \
197 " </signal>\n" \
198 " <signal name=\"UserRemoved\">\n" \
199 " <arg name=\"uid\" type=\"u\"/>\n" \
200 " <arg name=\"path\" type=\"o\"/>\n" \
201 " </signal>\n" \
202 " <signal name=\"SeatNew\">\n" \
203 " <arg name=\"id\" type=\"s\"/>\n" \
204 " <arg name=\"path\" type=\"o\"/>\n" \
205 " </signal>\n" \
206 " <signal name=\"SeatRemoved\">\n" \
207 " <arg name=\"id\" type=\"s\"/>\n" \
208 " <arg name=\"path\" type=\"o\"/>\n" \
209 " </signal>\n" \
210 " <signal name=\"PrepareForShutdown\">\n" \
211 " <arg name=\"active\" type=\"b\"/>\n" \
212 " </signal>\n" \
213 " <signal name=\"PrepareForSleep\">\n" \
214 " <arg name=\"active\" type=\"b\"/>\n" \
215 " </signal>\n" \
216 " <property name=\"NAutoVTs\" type=\"u\" access=\"read\"/>\n" \
217 " <property name=\"KillOnlyUsers\" type=\"as\" access=\"read\"/>\n" \
218 " <property name=\"KillExcludeUsers\" type=\"as\" access=\"read\"/>\n" \
219 " <property name=\"KillUserProcesses\" type=\"b\" access=\"read\"/>\n" \
220 " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
221 " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
222 " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
223 " <property name=\"BlockInhibited\" type=\"s\" access=\"read\"/>\n" \
224 " <property name=\"DelayInhibited\" type=\"s\" access=\"read\"/>\n" \
225 " <property name=\"InhibitDelayMaxUSec\" type=\"t\" access=\"read\"/>\n" \
226 " <property name=\"HandlePowerKey\" type=\"s\" access=\"read\"/>\n" \
227 " <property name=\"HandleSuspendKey\" type=\"s\" access=\"read\"/>\n" \
228 " <property name=\"HandleHibernateKey\" type=\"s\" access=\"read\"/>\n" \
229 " <property name=\"HandleLidSwitch\" type=\"s\" access=\"read\"/>\n" \
230 " <property name=\"IdleAction\" type=\"s\" access=\"read\"/>\n" \
231 " <property name=\"IdleActionUSec\" type=\"t\" access=\"read\"/>\n" \
232 " <property name=\"PreparingForShutdown\" type=\"b\" access=\"read\"/>\n" \
233 " <property name=\"PreparingForSleep\" type=\"b\" access=\"read\"/>\n" \
234 " </interface>\n"
235
236 #define INTROSPECTION_BEGIN \
237 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
238 "<node>\n" \
239 BUS_MANAGER_INTERFACE \
240 BUS_PROPERTIES_INTERFACE \
241 BUS_PEER_INTERFACE \
242 BUS_INTROSPECTABLE_INTERFACE
243
244 #define INTROSPECTION_END \
245 "</node>\n"
246
247 #define INTERFACES_LIST \
248 BUS_GENERIC_INTERFACES_LIST \
249 "org.freedesktop.login1.Manager\0"
250
251 static int bus_manager_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
252 Manager *m = data;
253 dbus_bool_t b;
254
255 assert(i);
256 assert(property);
257 assert(m);
258
259 b = manager_get_idle_hint(m, NULL) > 0;
260 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
261 return -ENOMEM;
262
263 return 0;
264 }
265
266 static int bus_manager_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
267 Manager *m = data;
268 dual_timestamp t;
269 uint64_t u;
270
271 assert(i);
272 assert(property);
273 assert(m);
274
275 manager_get_idle_hint(m, &t);
276 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
277
278 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
279 return -ENOMEM;
280
281 return 0;
282 }
283
284 static int bus_manager_append_inhibited(DBusMessageIter *i, const char *property, void *data) {
285 Manager *m = data;
286 InhibitWhat w;
287 const char *p;
288
289 w = manager_inhibit_what(m, streq(property, "BlockInhibited") ? INHIBIT_BLOCK : INHIBIT_DELAY);
290 p = inhibit_what_to_string(w);
291
292 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &p))
293 return -ENOMEM;
294
295 return 0;
296 }
297
298 static int bus_manager_append_preparing(DBusMessageIter *i, const char *property, void *data) {
299 Manager *m = data;
300 dbus_bool_t b;
301
302 assert(i);
303 assert(property);
304
305 if (streq(property, "PreparingForShutdown"))
306 b = !!(m->action_what & INHIBIT_SHUTDOWN);
307 else
308 b = !!(m->action_what & INHIBIT_SLEEP);
309
310 dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b);
311 return 0;
312 }
313
314 static int bus_manager_create_session(Manager *m, DBusMessage *message) {
315
316 const char *type, *class, *cseat, *tty, *display, *remote_user, *remote_host, *service;
317 uint32_t uid, leader, audit_id = 0;
318 _cleanup_free_ char *id = NULL;
319 Session *session = NULL;
320 User *user = NULL;
321 Seat *seat = NULL;
322 DBusMessageIter iter;
323 dbus_bool_t remote;
324 uint32_t vtnr = 0;
325 SessionType t;
326 SessionClass c;
327 bool b;
328 int r;
329
330 assert(m);
331 assert(message);
332
333 if (!dbus_message_iter_init(message, &iter) ||
334 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
335 return -EINVAL;
336
337 dbus_message_iter_get_basic(&iter, &uid);
338
339 if (!dbus_message_iter_next(&iter) ||
340 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
341 return -EINVAL;
342
343 dbus_message_iter_get_basic(&iter, &leader);
344
345 if (!dbus_message_iter_next(&iter) ||
346 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
347 return -EINVAL;
348
349 dbus_message_iter_get_basic(&iter, &service);
350
351 if (!dbus_message_iter_next(&iter) ||
352 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
353 return -EINVAL;
354
355 dbus_message_iter_get_basic(&iter, &type);
356 if (isempty(type))
357 t = _SESSION_TYPE_INVALID;
358 else {
359 t = session_type_from_string(type);
360 if (t < 0)
361 return -EINVAL;
362 }
363
364 if (!dbus_message_iter_next(&iter) ||
365 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
366 return -EINVAL;
367
368 dbus_message_iter_get_basic(&iter, &class);
369 if (isempty(class))
370 c = _SESSION_CLASS_INVALID;
371 else {
372 c = session_class_from_string(class);
373 if (c < 0)
374 return -EINVAL;
375 }
376
377 if (!dbus_message_iter_next(&iter) ||
378 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
379 return -EINVAL;
380
381 dbus_message_iter_get_basic(&iter, &cseat);
382
383 if (isempty(cseat))
384 seat = NULL;
385 else {
386 seat = hashmap_get(m->seats, cseat);
387 if (!seat)
388 return -ENOENT;
389 }
390
391 if (!dbus_message_iter_next(&iter) ||
392 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
393 return -EINVAL;
394
395 dbus_message_iter_get_basic(&iter, &vtnr);
396
397 if (!dbus_message_iter_next(&iter) ||
398 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
399 return -EINVAL;
400
401 dbus_message_iter_get_basic(&iter, &tty);
402
403 if (tty_is_vc(tty)) {
404 int v;
405
406 if (!seat)
407 seat = m->vtconsole;
408 else if (seat != m->vtconsole)
409 return -EINVAL;
410
411 v = vtnr_from_tty(tty);
412
413 if (v <= 0)
414 return v < 0 ? v : -EINVAL;
415
416 if (vtnr <= 0)
417 vtnr = (uint32_t) v;
418 else if (vtnr != (uint32_t) v)
419 return -EINVAL;
420 } else if (tty_is_console(tty)) {
421
422 if (!seat)
423 seat = m->vtconsole;
424 else if (seat != m->vtconsole)
425 return -EINVAL;
426
427 if (vtnr != 0)
428 return -EINVAL;
429 }
430
431 if (seat) {
432 if (seat_can_multi_session(seat)) {
433 if (vtnr > 63)
434 return -EINVAL;
435 } else {
436 if (vtnr != 0)
437 return -EINVAL;
438 }
439 }
440
441 if (!dbus_message_iter_next(&iter) ||
442 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
443 return -EINVAL;
444
445 dbus_message_iter_get_basic(&iter, &display);
446
447 if (!dbus_message_iter_next(&iter) ||
448 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
449 return -EINVAL;
450
451 if (t == _SESSION_TYPE_INVALID) {
452 if (!isempty(display))
453 t = SESSION_X11;
454 else if (!isempty(tty))
455 t = SESSION_TTY;
456 else
457 t = SESSION_UNSPECIFIED;
458 }
459
460 if (c == _SESSION_CLASS_INVALID) {
461 if (!isempty(display) || !isempty(tty))
462 c = SESSION_USER;
463 else
464 c = SESSION_BACKGROUND;
465 }
466
467 dbus_message_iter_get_basic(&iter, &remote);
468
469 if (!dbus_message_iter_next(&iter) ||
470 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
471 return -EINVAL;
472
473 dbus_message_iter_get_basic(&iter, &remote_user);
474
475 if (!dbus_message_iter_next(&iter) ||
476 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
477 return -EINVAL;
478
479 dbus_message_iter_get_basic(&iter, &remote_host);
480
481 if (leader <= 0) {
482 leader = bus_get_unix_process_id(m->bus, dbus_message_get_sender(message), NULL);
483 if (leader == 0)
484 return -EINVAL;
485 }
486
487 r = manager_get_session_by_pid(m, leader, &session);
488 if (session) {
489 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
490 _cleanup_free_ char *path = NULL;
491 _cleanup_close_ int fifo_fd = -1;
492 dbus_bool_t exists;
493
494 /* Session already exists, client is probably
495 * something like "su" which changes uid but is still
496 * the same session */
497
498 fifo_fd = session_create_fifo(session);
499 if (fifo_fd < 0) {
500 r = fifo_fd;
501 goto fail;
502 }
503
504 path = session_bus_path(session);
505 if (!path) {
506 r = -ENOMEM;
507 goto fail;
508 }
509
510 reply = dbus_message_new_method_return(message);
511 if (!reply) {
512 r = -ENOMEM;
513 goto fail;
514 }
515
516 cseat = session->seat ? session->seat->id : "";
517 vtnr = session->vtnr;
518 exists = true;
519
520 b = dbus_message_append_args(
521 reply,
522 DBUS_TYPE_STRING, &session->id,
523 DBUS_TYPE_OBJECT_PATH, &path,
524 DBUS_TYPE_STRING, &session->user->runtime_path,
525 DBUS_TYPE_UNIX_FD, &fifo_fd,
526 DBUS_TYPE_STRING, &cseat,
527 DBUS_TYPE_UINT32, &vtnr,
528 DBUS_TYPE_BOOLEAN, &exists,
529 DBUS_TYPE_INVALID);
530 if (!b) {
531 r = -ENOMEM;
532 goto fail;
533 }
534
535 if (!dbus_connection_send(m->bus, reply, NULL)) {
536 r = -ENOMEM;
537 goto fail;
538 }
539
540 return 0;
541 }
542
543 audit_session_from_pid(leader, &audit_id);
544 if (audit_id > 0) {
545 /* Keep our session IDs and the audit session IDs in sync */
546
547 if (asprintf(&id, "%lu", (unsigned long) audit_id) < 0) {
548 r = -ENOMEM;
549 goto fail;
550 }
551
552 /* Wut? There's already a session by this name and we
553 * didn't find it above? Weird, then let's not trust
554 * the audit data and let's better register a new
555 * ID */
556 if (hashmap_get(m->sessions, id)) {
557 audit_id = 0;
558
559 free(id);
560 id = NULL;
561 }
562 }
563
564 if (!id) {
565 do {
566 free(id);
567 id = NULL;
568
569 if (asprintf(&id, "c%lu", ++m->session_counter) < 0) {
570 r = -ENOMEM;
571 goto fail;
572 }
573
574 } while (hashmap_get(m->sessions, id));
575 }
576
577 r = manager_add_user_by_uid(m, uid, &user);
578 if (r < 0)
579 goto fail;
580
581 r = manager_add_session(m, id, &session);
582 if (r < 0)
583 goto fail;
584
585 session_set_user(session, user);
586
587 session->leader = leader;
588 session->audit_id = audit_id;
589 session->type = t;
590 session->class = c;
591 session->remote = remote;
592 session->vtnr = vtnr;
593
594 if (!isempty(tty)) {
595 session->tty = strdup(tty);
596 if (!session->tty) {
597 r = -ENOMEM;
598 goto fail;
599 }
600 }
601
602 if (!isempty(display)) {
603 session->display = strdup(display);
604 if (!session->display) {
605 r = -ENOMEM;
606 goto fail;
607 }
608 }
609
610 if (!isempty(remote_user)) {
611 session->remote_user = strdup(remote_user);
612 if (!session->remote_user) {
613 r = -ENOMEM;
614 goto fail;
615 }
616 }
617
618 if (!isempty(remote_host)) {
619 session->remote_host = strdup(remote_host);
620 if (!session->remote_host) {
621 r = -ENOMEM;
622 goto fail;
623 }
624 }
625
626 if (!isempty(service)) {
627 session->service = strdup(service);
628 if (!session->service) {
629 r = -ENOMEM;
630 goto fail;
631 }
632 }
633
634 if (seat) {
635 r = seat_attach_session(seat, session);
636 if (r < 0)
637 goto fail;
638 }
639
640 r = session_start(session);
641 if (r < 0)
642 goto fail;
643
644 session->create_message = dbus_message_ref(message);
645
646 return 0;
647
648 fail:
649 if (session)
650 session_add_to_gc_queue(session);
651
652 if (user)
653 user_add_to_gc_queue(user);
654
655 return r;
656 }
657
658 static int bus_manager_inhibit(
659 Manager *m,
660 DBusConnection *connection,
661 DBusMessage *message,
662 DBusError *error,
663 DBusMessage **_reply) {
664
665 Inhibitor *i = NULL;
666 char *id = NULL;
667 const char *who, *why, *what, *mode;
668 pid_t pid;
669 InhibitWhat w;
670 InhibitMode mm;
671 unsigned long ul;
672 int r, fifo_fd = -1;
673 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
674
675 assert(m);
676 assert(connection);
677 assert(message);
678 assert(error);
679 assert(_reply);
680
681 if (!dbus_message_get_args(
682 message,
683 error,
684 DBUS_TYPE_STRING, &what,
685 DBUS_TYPE_STRING, &who,
686 DBUS_TYPE_STRING, &why,
687 DBUS_TYPE_STRING, &mode,
688 DBUS_TYPE_INVALID)) {
689 r = -EIO;
690 goto fail;
691 }
692
693 w = inhibit_what_from_string(what);
694 if (w <= 0) {
695 r = -EINVAL;
696 goto fail;
697 }
698
699 mm = inhibit_mode_from_string(mode);
700 if (mm < 0) {
701 r = -EINVAL;
702 goto fail;
703 }
704
705 /* Delay is only supported for shutdown/sleep */
706 if (mm == INHIBIT_DELAY && (w & ~(INHIBIT_SHUTDOWN|INHIBIT_SLEEP))) {
707 r = -EINVAL;
708 goto fail;
709 }
710
711 /* Don't allow taking delay locks while we are already
712 * executing the operation. We shouldn't create the impression
713 * that the lock was successful if the machine is about to go
714 * down/suspend any moment. */
715 if (m->action_what & w) {
716 r = -EALREADY;
717 goto fail;
718 }
719
720 r = verify_polkit(connection, message,
721 w == INHIBIT_SHUTDOWN ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
722 w == INHIBIT_SLEEP ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep" : "org.freedesktop.login1.inhibit-delay-sleep") :
723 w == INHIBIT_IDLE ? "org.freedesktop.login1.inhibit-block-idle" :
724 w == INHIBIT_HANDLE_POWER_KEY ? "org.freedesktop.login1.inhibit-handle-power-key" :
725 w == INHIBIT_HANDLE_SUSPEND_KEY ? "org.freedesktop.login1.inhibit-handle-suspend-key" :
726 w == INHIBIT_HANDLE_HIBERNATE_KEY ? "org.freedesktop.login1.inhibit-handle-hibernate-key" :
727 "org.freedesktop.login1.inhibit-handle-lid-switch",
728 false, NULL, error);
729 if (r < 0)
730 goto fail;
731
732 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
733 if (ul == (unsigned long) -1) {
734 r = -EIO;
735 goto fail;
736 }
737
738 pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
739 if (pid <= 0) {
740 r = -EIO;
741 goto fail;
742 }
743
744 do {
745 free(id);
746 id = NULL;
747
748 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
749 r = -ENOMEM;
750 goto fail;
751 }
752 } while (hashmap_get(m->inhibitors, id));
753
754 r = manager_add_inhibitor(m, id, &i);
755 free(id);
756
757 if (r < 0)
758 goto fail;
759
760 i->what = w;
761 i->mode = mm;
762 i->pid = pid;
763 i->uid = (uid_t) ul;
764 i->why = strdup(why);
765 i->who = strdup(who);
766
767 if (!i->why || !i->who) {
768 r = -ENOMEM;
769 goto fail;
770 }
771
772 fifo_fd = inhibitor_create_fifo(i);
773 if (fifo_fd < 0) {
774 r = fifo_fd;
775 goto fail;
776 }
777
778 reply = dbus_message_new_method_return(message);
779 if (!reply) {
780 r = -ENOMEM;
781 goto fail;
782 }
783
784 if (!dbus_message_append_args(
785 reply,
786 DBUS_TYPE_UNIX_FD, &fifo_fd,
787 DBUS_TYPE_INVALID)) {
788 r = -ENOMEM;
789 goto fail;
790 }
791
792 close_nointr_nofail(fifo_fd);
793 *_reply = reply;
794 reply = NULL;
795
796 inhibitor_start(i);
797
798 return 0;
799
800 fail:
801 if (i)
802 inhibitor_free(i);
803
804 if (fifo_fd >= 0)
805 close_nointr_nofail(fifo_fd);
806
807 return r;
808 }
809
810 static int trigger_device(Manager *m, struct udev_device *d) {
811 struct udev_enumerate *e;
812 struct udev_list_entry *first, *item;
813 int r;
814
815 assert(m);
816
817 e = udev_enumerate_new(m->udev);
818 if (!e) {
819 r = -ENOMEM;
820 goto finish;
821 }
822
823 if (d) {
824 if (udev_enumerate_add_match_parent(e, d) < 0) {
825 r = -EIO;
826 goto finish;
827 }
828 }
829
830 if (udev_enumerate_scan_devices(e) < 0) {
831 r = -EIO;
832 goto finish;
833 }
834
835 first = udev_enumerate_get_list_entry(e);
836 udev_list_entry_foreach(item, first) {
837 char *t;
838 const char *p;
839
840 p = udev_list_entry_get_name(item);
841
842 t = strappend(p, "/uevent");
843 if (!t) {
844 r = -ENOMEM;
845 goto finish;
846 }
847
848 write_string_file(t, "change");
849 free(t);
850 }
851
852 r = 0;
853
854 finish:
855 if (e)
856 udev_enumerate_unref(e);
857
858 return r;
859 }
860
861 static int attach_device(Manager *m, const char *seat, const char *sysfs) {
862 struct udev_device *d;
863 _cleanup_free_ char *rule = NULL, *file = NULL;
864 const char *id_for_seat;
865 int r;
866
867 assert(m);
868 assert(seat);
869 assert(sysfs);
870
871 d = udev_device_new_from_syspath(m->udev, sysfs);
872 if (!d)
873 return -ENODEV;
874
875 if (!udev_device_has_tag(d, "seat")) {
876 r = -ENODEV;
877 goto finish;
878 }
879
880 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
881 if (!id_for_seat) {
882 r = -ENODEV;
883 goto finish;
884 }
885
886 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
887 r = -ENOMEM;
888 goto finish;
889 }
890
891 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
892 r = -ENOMEM;
893 goto finish;
894 }
895
896 mkdir_p_label("/etc/udev/rules.d", 0755);
897 label_init("/etc");
898 r = write_string_file_atomic_label(file, rule);
899 if (r < 0)
900 goto finish;
901
902 r = trigger_device(m, d);
903
904 finish:
905 if (d)
906 udev_device_unref(d);
907
908 return r;
909 }
910
911 static int flush_devices(Manager *m) {
912 _cleanup_closedir_ DIR *d;
913
914 assert(m);
915
916 d = opendir("/etc/udev/rules.d");
917 if (!d) {
918 if (errno != ENOENT)
919 log_warning("Failed to open /etc/udev/rules.d: %m");
920 } else {
921 struct dirent *de;
922
923 while ((de = readdir(d))) {
924
925 if (!dirent_is_file(de))
926 continue;
927
928 if (!startswith(de->d_name, "72-seat-"))
929 continue;
930
931 if (!endswith(de->d_name, ".rules"))
932 continue;
933
934 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
935 log_warning("Failed to unlink %s: %m", de->d_name);
936 }
937 }
938
939 return trigger_device(m, NULL);
940 }
941
942 static int have_multiple_sessions(
943 Manager *m,
944 uid_t uid) {
945
946 Session *session;
947 Iterator i;
948
949 assert(m);
950
951 /* Check for other users' sessions. Greeter sessions do not
952 * count, and non-login sessions do not count either. */
953 HASHMAP_FOREACH(session, m->sessions, i)
954 if (session->class == SESSION_USER &&
955 session->user->uid != uid)
956 return true;
957
958 return false;
959 }
960
961 static int bus_manager_log_shutdown(
962 Manager *m,
963 InhibitWhat w,
964 const char *unit_name) {
965
966 const char *p, *q;
967
968 assert(m);
969 assert(unit_name);
970
971 if (w != INHIBIT_SHUTDOWN)
972 return 0;
973
974 if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
975 p = "MESSAGE=System is powering down.";
976 q = "SHUTDOWN=power-off";
977 } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
978 p = "MESSAGE=System is halting.";
979 q = "SHUTDOWN=halt";
980 } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
981 p = "MESSAGE=System is rebooting.";
982 q = "SHUTDOWN=reboot";
983 } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
984 p = "MESSAGE=System is rebooting with kexec.";
985 q = "SHUTDOWN=kexec";
986 } else {
987 p = "MESSAGE=System is shutting down.";
988 q = NULL;
989 }
990
991 return log_struct(LOG_NOTICE, MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
992 p,
993 q, NULL);
994 }
995
996 static int execute_shutdown_or_sleep(
997 Manager *m,
998 InhibitWhat w,
999 const char *unit_name,
1000 DBusError *error) {
1001
1002 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1003 const char *mode = "replace-irreversibly", *p;
1004 int r;
1005 char *c;
1006
1007 assert(m);
1008 assert(w >= 0);
1009 assert(w < _INHIBIT_WHAT_MAX);
1010 assert(unit_name);
1011
1012 bus_manager_log_shutdown(m, w, unit_name);
1013
1014 r = bus_method_call_with_reply(
1015 m->bus,
1016 "org.freedesktop.systemd1",
1017 "/org/freedesktop/systemd1",
1018 "org.freedesktop.systemd1.Manager",
1019 "StartUnit",
1020 &reply,
1021 error,
1022 DBUS_TYPE_STRING, &unit_name,
1023 DBUS_TYPE_STRING, &mode,
1024 DBUS_TYPE_INVALID);
1025 if (r < 0)
1026 return r;
1027
1028 if (!dbus_message_get_args(
1029 reply,
1030 error,
1031 DBUS_TYPE_OBJECT_PATH, &p,
1032 DBUS_TYPE_INVALID))
1033 return -EINVAL;
1034
1035 c = strdup(p);
1036 if (!c)
1037 return -ENOMEM;
1038
1039 m->action_unit = unit_name;
1040 free(m->action_job);
1041 m->action_job = c;
1042 m->action_what = w;
1043
1044 return 0;
1045 }
1046
1047 static int delay_shutdown_or_sleep(
1048 Manager *m,
1049 InhibitWhat w,
1050 const char *unit_name) {
1051
1052 assert(m);
1053 assert(w >= 0);
1054 assert(w < _INHIBIT_WHAT_MAX);
1055 assert(unit_name);
1056
1057 m->action_timestamp = now(CLOCK_MONOTONIC);
1058 m->action_unit = unit_name;
1059 m->action_what = w;
1060
1061 return 0;
1062 }
1063
1064 static int bus_manager_can_shutdown_or_sleep(
1065 Manager *m,
1066 DBusConnection *connection,
1067 DBusMessage *message,
1068 InhibitWhat w,
1069 const char *action,
1070 const char *action_multiple_sessions,
1071 const char *action_ignore_inhibit,
1072 const char *sleep_verb,
1073 DBusError *error,
1074 DBusMessage **_reply) {
1075
1076 bool multiple_sessions, challenge, blocked, b;
1077 const char *result = NULL;
1078 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1079 int r;
1080 unsigned long ul;
1081
1082 assert(m);
1083 assert(connection);
1084 assert(message);
1085 assert(w >= 0);
1086 assert(w <= _INHIBIT_WHAT_MAX);
1087 assert(action);
1088 assert(action_multiple_sessions);
1089 assert(action_ignore_inhibit);
1090 assert(error);
1091 assert(_reply);
1092
1093 if (sleep_verb) {
1094 r = can_sleep(sleep_verb);
1095 if (r < 0)
1096 return r;
1097 if (r == 0) {
1098 result = "na";
1099 goto finish;
1100 }
1101 }
1102
1103 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1104 if (ul == (unsigned long) -1)
1105 return -EIO;
1106
1107 r = have_multiple_sessions(m, (uid_t) ul);
1108 if (r < 0)
1109 return r;
1110
1111 multiple_sessions = r > 0;
1112 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1113
1114 if (multiple_sessions) {
1115 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1116 if (r < 0)
1117 return r;
1118
1119 if (r > 0)
1120 result = "yes";
1121 else if (challenge)
1122 result = "challenge";
1123 else
1124 result = "no";
1125 }
1126
1127 if (blocked) {
1128 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1129 if (r < 0)
1130 return r;
1131
1132 if (r > 0 && !result)
1133 result = "yes";
1134 else if (challenge && (!result || streq(result, "yes")))
1135 result = "challenge";
1136 else
1137 result = "no";
1138 }
1139
1140 if (!multiple_sessions && !blocked) {
1141 /* If neither inhibit nor multiple sessions
1142 * apply then just check the normal policy */
1143
1144 r = verify_polkit(connection, message, action, false, &challenge, error);
1145 if (r < 0)
1146 return r;
1147
1148 if (r > 0)
1149 result = "yes";
1150 else if (challenge)
1151 result = "challenge";
1152 else
1153 result = "no";
1154 }
1155
1156 finish:
1157 reply = dbus_message_new_method_return(message);
1158 if (!reply)
1159 return -ENOMEM;
1160
1161 b = dbus_message_append_args(
1162 reply,
1163 DBUS_TYPE_STRING, &result,
1164 DBUS_TYPE_INVALID);
1165 if (!b)
1166 return -ENOMEM;
1167
1168 *_reply = reply;
1169 reply = NULL;
1170 return 0;
1171 }
1172
1173 static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
1174 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
1175 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
1176 [INHIBIT_SLEEP] = "PrepareForSleep"
1177 };
1178
1179 dbus_bool_t active = _active;
1180 _cleanup_dbus_message_unref_ DBusMessage *message = NULL;
1181
1182 assert(m);
1183 assert(w >= 0);
1184 assert(w < _INHIBIT_WHAT_MAX);
1185 assert(signal_name[w]);
1186
1187 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1188 if (!message)
1189 return -ENOMEM;
1190
1191 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1192 !dbus_connection_send(m->bus, message, NULL))
1193 return -ENOMEM;
1194
1195 return 0;
1196 }
1197
1198 int bus_manager_shutdown_or_sleep_now_or_later(
1199 Manager *m,
1200 const char *unit_name,
1201 InhibitWhat w,
1202 DBusError *error) {
1203
1204 bool delayed;
1205 int r;
1206
1207 assert(m);
1208 assert(unit_name);
1209 assert(w >= 0);
1210 assert(w <= _INHIBIT_WHAT_MAX);
1211 assert(!m->action_job);
1212
1213 /* Tell everybody to prepare for shutdown/sleep */
1214 send_prepare_for(m, w, true);
1215
1216 delayed =
1217 m->inhibit_delay_max > 0 &&
1218 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0);
1219
1220 if (delayed)
1221 /* Shutdown is delayed, keep in mind what we
1222 * want to do, and start a timeout */
1223 r = delay_shutdown_or_sleep(m, w, unit_name);
1224 else
1225 /* Shutdown is not delayed, execute it
1226 * immediately */
1227 r = execute_shutdown_or_sleep(m, w, unit_name, error);
1228
1229 return r;
1230 }
1231
1232 static int bus_manager_do_shutdown_or_sleep(
1233 Manager *m,
1234 DBusConnection *connection,
1235 DBusMessage *message,
1236 const char *unit_name,
1237 InhibitWhat w,
1238 const char *action,
1239 const char *action_multiple_sessions,
1240 const char *action_ignore_inhibit,
1241 const char *sleep_verb,
1242 DBusError *error,
1243 DBusMessage **_reply) {
1244
1245 dbus_bool_t interactive;
1246 bool multiple_sessions, blocked;
1247 DBusMessage *reply = NULL;
1248 int r;
1249 unsigned long ul;
1250
1251 assert(m);
1252 assert(connection);
1253 assert(message);
1254 assert(unit_name);
1255 assert(w >= 0);
1256 assert(w <= _INHIBIT_WHAT_MAX);
1257 assert(action);
1258 assert(action_multiple_sessions);
1259 assert(action_ignore_inhibit);
1260 assert(error);
1261 assert(_reply);
1262
1263 /* Don't allow multiple jobs being executed at the same time */
1264 if (m->action_what)
1265 return -EALREADY;
1266
1267 if (!dbus_message_get_args(
1268 message,
1269 error,
1270 DBUS_TYPE_BOOLEAN, &interactive,
1271 DBUS_TYPE_INVALID))
1272 return -EINVAL;
1273
1274 if (sleep_verb) {
1275 r = can_sleep(sleep_verb);
1276 if (r < 0)
1277 return r;
1278
1279 if (r == 0)
1280 return -ENOTSUP;
1281 }
1282
1283 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1284 if (ul == (unsigned long) -1)
1285 return -EIO;
1286
1287 r = have_multiple_sessions(m, (uid_t) ul);
1288 if (r < 0)
1289 return r;
1290
1291 multiple_sessions = r > 0;
1292 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1293
1294 if (multiple_sessions) {
1295 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1296 if (r < 0)
1297 return r;
1298 }
1299
1300 if (blocked) {
1301 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1302 if (r < 0)
1303 return r;
1304 }
1305
1306 if (!multiple_sessions && !blocked) {
1307 r = verify_polkit(connection, message, action, interactive, NULL, error);
1308 if (r < 0)
1309 return r;
1310 }
1311
1312 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
1313 if (r < 0)
1314 return r;
1315
1316 reply = dbus_message_new_method_return(message);
1317 if (!reply)
1318 return -ENOMEM;
1319
1320 *_reply = reply;
1321 return 0;
1322 }
1323
1324 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_action, handle_action, HandleAction);
1325
1326 static const BusProperty bus_login_manager_properties[] = {
1327 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1328 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1329 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1330 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1331 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1332 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1333 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
1334 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1335 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1336 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
1337 { "HandlePowerKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_power_key) },
1338 { "HandleSuspendKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_suspend_key) },
1339 { "HandleHibernateKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_hibernate_key)},
1340 { "HandleLidSwitch", bus_manager_append_handle_action, "s", offsetof(Manager, handle_lid_switch) },
1341 { "IdleAction", bus_manager_append_handle_action, "s", offsetof(Manager, idle_action) },
1342 { "IdleActionUSec", bus_property_append_usec, "t", offsetof(Manager, idle_action_usec) },
1343 { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
1344 { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
1345 { NULL, }
1346 };
1347
1348 static DBusHandlerResult manager_message_handler(
1349 DBusConnection *connection,
1350 DBusMessage *message,
1351 void *userdata) {
1352
1353 Manager *m = userdata;
1354
1355 DBusError error;
1356 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1357 int r;
1358
1359 assert(connection);
1360 assert(message);
1361 assert(m);
1362
1363 dbus_error_init(&error);
1364
1365 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1366 const char *name;
1367 char *p;
1368 Session *session;
1369 bool b;
1370
1371 if (!dbus_message_get_args(
1372 message,
1373 &error,
1374 DBUS_TYPE_STRING, &name,
1375 DBUS_TYPE_INVALID))
1376 return bus_send_error_reply(connection, message, &error, -EINVAL);
1377
1378 session = hashmap_get(m->sessions, name);
1379 if (!session)
1380 return bus_send_error_reply(connection, message, &error, -ENOENT);
1381
1382 reply = dbus_message_new_method_return(message);
1383 if (!reply)
1384 goto oom;
1385
1386 p = session_bus_path(session);
1387 if (!p)
1388 goto oom;
1389
1390 b = dbus_message_append_args(
1391 reply,
1392 DBUS_TYPE_OBJECT_PATH, &p,
1393 DBUS_TYPE_INVALID);
1394 free(p);
1395
1396 if (!b)
1397 goto oom;
1398
1399 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1400 uint32_t pid;
1401 char *p;
1402 Session *session;
1403 bool b;
1404
1405 if (!dbus_message_get_args(
1406 message,
1407 &error,
1408 DBUS_TYPE_UINT32, &pid,
1409 DBUS_TYPE_INVALID))
1410 return bus_send_error_reply(connection, message, &error, -EINVAL);
1411
1412 r = manager_get_session_by_pid(m, pid, &session);
1413 if (r <= 0)
1414 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1415
1416 reply = dbus_message_new_method_return(message);
1417 if (!reply)
1418 goto oom;
1419
1420 p = session_bus_path(session);
1421 if (!p)
1422 goto oom;
1423
1424 b = dbus_message_append_args(
1425 reply,
1426 DBUS_TYPE_OBJECT_PATH, &p,
1427 DBUS_TYPE_INVALID);
1428 free(p);
1429
1430 if (!b)
1431 goto oom;
1432
1433 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1434 uint32_t uid;
1435 char *p;
1436 User *user;
1437 bool b;
1438
1439 if (!dbus_message_get_args(
1440 message,
1441 &error,
1442 DBUS_TYPE_UINT32, &uid,
1443 DBUS_TYPE_INVALID))
1444 return bus_send_error_reply(connection, message, &error, -EINVAL);
1445
1446 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1447 if (!user)
1448 return bus_send_error_reply(connection, message, &error, -ENOENT);
1449
1450 reply = dbus_message_new_method_return(message);
1451 if (!reply)
1452 goto oom;
1453
1454 p = user_bus_path(user);
1455 if (!p)
1456 goto oom;
1457
1458 b = dbus_message_append_args(
1459 reply,
1460 DBUS_TYPE_OBJECT_PATH, &p,
1461 DBUS_TYPE_INVALID);
1462 free(p);
1463
1464 if (!b)
1465 goto oom;
1466
1467 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUserByPID")) {
1468 uint32_t pid;
1469 char *p;
1470 User *user;
1471 bool b;
1472
1473 if (!dbus_message_get_args(
1474 message,
1475 &error,
1476 DBUS_TYPE_UINT32, &pid,
1477 DBUS_TYPE_INVALID))
1478 return bus_send_error_reply(connection, message, &error, -EINVAL);
1479
1480 r = manager_get_user_by_pid(m, pid, &user);
1481 if (r <= 0)
1482 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1483
1484 reply = dbus_message_new_method_return(message);
1485 if (!reply)
1486 goto oom;
1487
1488 p = user_bus_path(user);
1489 if (!p)
1490 goto oom;
1491
1492 b = dbus_message_append_args(
1493 reply,
1494 DBUS_TYPE_OBJECT_PATH, &p,
1495 DBUS_TYPE_INVALID);
1496 free(p);
1497
1498 if (!b)
1499 goto oom;
1500
1501 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1502 const char *name;
1503 char *p;
1504 Seat *seat;
1505 bool b;
1506
1507 if (!dbus_message_get_args(
1508 message,
1509 &error,
1510 DBUS_TYPE_STRING, &name,
1511 DBUS_TYPE_INVALID))
1512 return bus_send_error_reply(connection, message, &error, -EINVAL);
1513
1514 seat = hashmap_get(m->seats, name);
1515 if (!seat)
1516 return bus_send_error_reply(connection, message, &error, -ENOENT);
1517
1518 reply = dbus_message_new_method_return(message);
1519 if (!reply)
1520 goto oom;
1521
1522 p = seat_bus_path(seat);
1523 if (!p)
1524 goto oom;
1525
1526 b = dbus_message_append_args(
1527 reply,
1528 DBUS_TYPE_OBJECT_PATH, &p,
1529 DBUS_TYPE_INVALID);
1530 free(p);
1531
1532 if (!b)
1533 goto oom;
1534
1535 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1536 char *p;
1537 Session *session;
1538 Iterator i;
1539 DBusMessageIter iter, sub;
1540 const char *empty = "";
1541
1542 reply = dbus_message_new_method_return(message);
1543 if (!reply)
1544 goto oom;
1545
1546 dbus_message_iter_init_append(reply, &iter);
1547
1548 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1549 goto oom;
1550
1551 HASHMAP_FOREACH(session, m->sessions, i) {
1552 DBusMessageIter sub2;
1553 uint32_t uid;
1554
1555 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1556 goto oom;
1557
1558 uid = session->user->uid;
1559
1560 p = session_bus_path(session);
1561 if (!p)
1562 goto oom;
1563
1564 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1565 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1566 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1567 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1568 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1569 free(p);
1570 goto oom;
1571 }
1572
1573 free(p);
1574
1575 if (!dbus_message_iter_close_container(&sub, &sub2))
1576 goto oom;
1577 }
1578
1579 if (!dbus_message_iter_close_container(&iter, &sub))
1580 goto oom;
1581
1582 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1583 User *user;
1584 Iterator i;
1585 DBusMessageIter iter, sub;
1586
1587 reply = dbus_message_new_method_return(message);
1588 if (!reply)
1589 goto oom;
1590
1591 dbus_message_iter_init_append(reply, &iter);
1592
1593 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1594 goto oom;
1595
1596 HASHMAP_FOREACH(user, m->users, i) {
1597 _cleanup_free_ char *p = NULL;
1598 DBusMessageIter sub2;
1599 uint32_t uid;
1600
1601 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1602 goto oom;
1603
1604 uid = user->uid;
1605
1606 p = user_bus_path(user);
1607 if (!p)
1608 goto oom;
1609
1610 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1611 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1612 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1613 free(p);
1614 goto oom;
1615 }
1616
1617 if (!dbus_message_iter_close_container(&sub, &sub2))
1618 goto oom;
1619 }
1620
1621 if (!dbus_message_iter_close_container(&iter, &sub))
1622 goto oom;
1623
1624 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1625 Seat *seat;
1626 Iterator i;
1627 DBusMessageIter iter, sub;
1628
1629 reply = dbus_message_new_method_return(message);
1630 if (!reply)
1631 goto oom;
1632
1633 dbus_message_iter_init_append(reply, &iter);
1634
1635 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1636 goto oom;
1637
1638 HASHMAP_FOREACH(seat, m->seats, i) {
1639 _cleanup_free_ char *p = NULL;
1640 DBusMessageIter sub2;
1641
1642 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1643 goto oom;
1644
1645 p = seat_bus_path(seat);
1646 if (!p)
1647 goto oom;
1648
1649 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1650 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1651 free(p);
1652 goto oom;
1653 }
1654
1655 if (!dbus_message_iter_close_container(&sub, &sub2))
1656 goto oom;
1657 }
1658
1659 if (!dbus_message_iter_close_container(&iter, &sub))
1660 goto oom;
1661
1662 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1663 Inhibitor *inhibitor;
1664 Iterator i;
1665 DBusMessageIter iter, sub;
1666
1667 reply = dbus_message_new_method_return(message);
1668 if (!reply)
1669 goto oom;
1670
1671 dbus_message_iter_init_append(reply, &iter);
1672
1673 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1674 goto oom;
1675
1676 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1677 DBusMessageIter sub2;
1678 dbus_uint32_t uid, pid;
1679 const char *what, *who, *why, *mode;
1680
1681 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1682 goto oom;
1683
1684 what = strempty(inhibit_what_to_string(inhibitor->what));
1685 who = strempty(inhibitor->who);
1686 why = strempty(inhibitor->why);
1687 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
1688 uid = (dbus_uint32_t) inhibitor->uid;
1689 pid = (dbus_uint32_t) inhibitor->pid;
1690
1691 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1692 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1693 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1694 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
1695 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1696 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1697 goto oom;
1698
1699 if (!dbus_message_iter_close_container(&sub, &sub2))
1700 goto oom;
1701 }
1702
1703 if (!dbus_message_iter_close_container(&iter, &sub))
1704 goto oom;
1705
1706
1707 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1708
1709 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1710
1711 if (r < 0)
1712 return bus_send_error_reply(connection, message, &error, r);
1713
1714
1715 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1716
1717 r = bus_manager_create_session(m, message);
1718
1719 /* Don't delay the work on OOM here, since it might be
1720 * triggered by a low RLIMIT_NOFILE here (since we
1721 * send a dupped fd to the client), and we'd rather
1722 * see this fail quickly then be retried later */
1723
1724 if (r < 0)
1725 return bus_send_error_reply(connection, message, NULL, r);
1726
1727 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1728 const char *name;
1729 Session *session;
1730
1731 if (!dbus_message_get_args(
1732 message,
1733 &error,
1734 DBUS_TYPE_STRING, &name,
1735 DBUS_TYPE_INVALID))
1736 return bus_send_error_reply(connection, message, &error, -EINVAL);
1737
1738 session = hashmap_get(m->sessions, name);
1739 if (!session)
1740 return bus_send_error_reply(connection, message, &error, -ENOENT);
1741
1742 /* We use the FIFO to detect stray sessions where the
1743 process invoking PAM dies abnormally. We need to make
1744 sure that that process is not killed if at the clean
1745 end of the session it closes the FIFO. Hence, with
1746 this call explicitly turn off the FIFO logic, so that
1747 the PAM code can finish clean up on its own */
1748 session_remove_fifo(session);
1749
1750 reply = dbus_message_new_method_return(message);
1751 if (!reply)
1752 goto oom;
1753
1754 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1755 const char *name;
1756 Session *session;
1757
1758 if (!dbus_message_get_args(
1759 message,
1760 &error,
1761 DBUS_TYPE_STRING, &name,
1762 DBUS_TYPE_INVALID))
1763 return bus_send_error_reply(connection, message, &error, -EINVAL);
1764
1765 session = hashmap_get(m->sessions, name);
1766 if (!session)
1767 return bus_send_error_reply(connection, message, &error, -ENOENT);
1768
1769 r = session_activate(session);
1770 if (r < 0)
1771 return bus_send_error_reply(connection, message, NULL, r);
1772
1773 reply = dbus_message_new_method_return(message);
1774 if (!reply)
1775 goto oom;
1776
1777 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1778 const char *session_name, *seat_name;
1779 Session *session;
1780 Seat *seat;
1781
1782 /* Same as ActivateSession() but refuses to work if
1783 * the seat doesn't match */
1784
1785 if (!dbus_message_get_args(
1786 message,
1787 &error,
1788 DBUS_TYPE_STRING, &session_name,
1789 DBUS_TYPE_STRING, &seat_name,
1790 DBUS_TYPE_INVALID))
1791 return bus_send_error_reply(connection, message, &error, -EINVAL);
1792
1793 session = hashmap_get(m->sessions, session_name);
1794 if (!session)
1795 return bus_send_error_reply(connection, message, &error, -ENOENT);
1796
1797 seat = hashmap_get(m->seats, seat_name);
1798 if (!seat)
1799 return bus_send_error_reply(connection, message, &error, -ENOENT);
1800
1801 if (session->seat != seat)
1802 return bus_send_error_reply(connection, message, &error, -EINVAL);
1803
1804 r = session_activate(session);
1805 if (r < 0)
1806 return bus_send_error_reply(connection, message, NULL, r);
1807
1808 reply = dbus_message_new_method_return(message);
1809 if (!reply)
1810 goto oom;
1811
1812 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1813 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1814 const char *name;
1815 Session *session;
1816
1817 if (!dbus_message_get_args(
1818 message,
1819 &error,
1820 DBUS_TYPE_STRING, &name,
1821 DBUS_TYPE_INVALID))
1822 return bus_send_error_reply(connection, message, &error, -EINVAL);
1823
1824 session = hashmap_get(m->sessions, name);
1825 if (!session)
1826 return bus_send_error_reply(connection, message, NULL, -ENOENT);
1827
1828 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1829 goto oom;
1830
1831 reply = dbus_message_new_method_return(message);
1832 if (!reply)
1833 goto oom;
1834
1835 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions") ||
1836 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSessions")) {
1837
1838 r = session_send_lock_all(m, streq(dbus_message_get_member(message), "LockSessions"));
1839 if (r < 0)
1840 bus_send_error_reply(connection, message, NULL, r);
1841
1842 reply = dbus_message_new_method_return(message);
1843 if (!reply)
1844 goto oom;
1845
1846 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1847 const char *swho;
1848 int32_t signo;
1849 KillWho who;
1850 const char *name;
1851 Session *session;
1852
1853 if (!dbus_message_get_args(
1854 message,
1855 &error,
1856 DBUS_TYPE_STRING, &name,
1857 DBUS_TYPE_STRING, &swho,
1858 DBUS_TYPE_INT32, &signo,
1859 DBUS_TYPE_INVALID))
1860 return bus_send_error_reply(connection, message, &error, -EINVAL);
1861
1862 if (isempty(swho))
1863 who = KILL_ALL;
1864 else {
1865 who = kill_who_from_string(swho);
1866 if (who < 0)
1867 return bus_send_error_reply(connection, message, &error, -EINVAL);
1868 }
1869
1870 if (signo <= 0 || signo >= _NSIG)
1871 return bus_send_error_reply(connection, message, &error, -EINVAL);
1872
1873 session = hashmap_get(m->sessions, name);
1874 if (!session)
1875 return bus_send_error_reply(connection, message, &error, -ENOENT);
1876
1877 r = session_kill(session, who, signo);
1878 if (r < 0)
1879 return bus_send_error_reply(connection, message, NULL, r);
1880
1881 reply = dbus_message_new_method_return(message);
1882 if (!reply)
1883 goto oom;
1884
1885 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1886 uint32_t uid;
1887 User *user;
1888 int32_t signo;
1889
1890 if (!dbus_message_get_args(
1891 message,
1892 &error,
1893 DBUS_TYPE_UINT32, &uid,
1894 DBUS_TYPE_INT32, &signo,
1895 DBUS_TYPE_INVALID))
1896 return bus_send_error_reply(connection, message, &error, -EINVAL);
1897
1898 if (signo <= 0 || signo >= _NSIG)
1899 return bus_send_error_reply(connection, message, &error, -EINVAL);
1900
1901 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1902 if (!user)
1903 return bus_send_error_reply(connection, message, &error, -ENOENT);
1904
1905 r = user_kill(user, signo);
1906 if (r < 0)
1907 return bus_send_error_reply(connection, message, NULL, r);
1908
1909 reply = dbus_message_new_method_return(message);
1910 if (!reply)
1911 goto oom;
1912
1913 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1914 const char *name;
1915 Session *session;
1916
1917 if (!dbus_message_get_args(
1918 message,
1919 &error,
1920 DBUS_TYPE_STRING, &name,
1921 DBUS_TYPE_INVALID))
1922 return bus_send_error_reply(connection, message, &error, -EINVAL);
1923
1924 session = hashmap_get(m->sessions, name);
1925 if (!session)
1926 return bus_send_error_reply(connection, message, &error, -ENOENT);
1927
1928 r = session_stop(session);
1929 if (r < 0)
1930 return bus_send_error_reply(connection, message, NULL, r);
1931
1932 reply = dbus_message_new_method_return(message);
1933 if (!reply)
1934 goto oom;
1935
1936 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1937 uint32_t uid;
1938 User *user;
1939
1940 if (!dbus_message_get_args(
1941 message,
1942 &error,
1943 DBUS_TYPE_UINT32, &uid,
1944 DBUS_TYPE_INVALID))
1945 return bus_send_error_reply(connection, message, &error, -EINVAL);
1946
1947 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1948 if (!user)
1949 return bus_send_error_reply(connection, message, &error, -ENOENT);
1950
1951 r = user_stop(user);
1952 if (r < 0)
1953 return bus_send_error_reply(connection, message, NULL, r);
1954
1955 reply = dbus_message_new_method_return(message);
1956 if (!reply)
1957 goto oom;
1958
1959 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1960 const char *name;
1961 Seat *seat;
1962
1963 if (!dbus_message_get_args(
1964 message,
1965 &error,
1966 DBUS_TYPE_STRING, &name,
1967 DBUS_TYPE_INVALID))
1968 return bus_send_error_reply(connection, message, &error, -EINVAL);
1969
1970 seat = hashmap_get(m->seats, name);
1971 if (!seat)
1972 return bus_send_error_reply(connection, message, &error, -ENOENT);
1973
1974 r = seat_stop_sessions(seat);
1975 if (r < 0)
1976 return bus_send_error_reply(connection, message, NULL, r);
1977
1978 reply = dbus_message_new_method_return(message);
1979 if (!reply)
1980 goto oom;
1981
1982 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
1983 uint32_t uid;
1984 struct passwd *pw;
1985 dbus_bool_t b, interactive;
1986 char *path;
1987
1988 if (!dbus_message_get_args(
1989 message,
1990 &error,
1991 DBUS_TYPE_UINT32, &uid,
1992 DBUS_TYPE_BOOLEAN, &b,
1993 DBUS_TYPE_BOOLEAN, &interactive,
1994 DBUS_TYPE_INVALID))
1995 return bus_send_error_reply(connection, message, &error, -EINVAL);
1996
1997 errno = 0;
1998 pw = getpwuid(uid);
1999 if (!pw)
2000 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
2001
2002 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
2003 if (r < 0)
2004 return bus_send_error_reply(connection, message, &error, r);
2005
2006 mkdir_p_label("/var/lib/systemd", 0755);
2007
2008 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
2009 if (r < 0)
2010 return bus_send_error_reply(connection, message, &error, r);
2011
2012 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
2013 if (!path)
2014 goto oom;
2015
2016 if (b) {
2017 User *u;
2018
2019 r = touch(path);
2020 free(path);
2021
2022 if (r < 0)
2023 return bus_send_error_reply(connection, message, &error, r);
2024
2025 if (manager_add_user_by_uid(m, uid, &u) >= 0)
2026 user_start(u);
2027
2028 } else {
2029 User *u;
2030
2031 r = unlink(path);
2032 free(path);
2033
2034 if (r < 0 && errno != ENOENT)
2035 return bus_send_error_reply(connection, message, &error, -errno);
2036
2037 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
2038 if (u)
2039 user_add_to_gc_queue(u);
2040 }
2041
2042 reply = dbus_message_new_method_return(message);
2043 if (!reply)
2044 goto oom;
2045
2046 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
2047 const char *sysfs, *seat;
2048 dbus_bool_t interactive;
2049
2050 if (!dbus_message_get_args(
2051 message,
2052 &error,
2053 DBUS_TYPE_STRING, &seat,
2054 DBUS_TYPE_STRING, &sysfs,
2055 DBUS_TYPE_BOOLEAN, &interactive,
2056 DBUS_TYPE_INVALID))
2057 return bus_send_error_reply(connection, message, &error, -EINVAL);
2058
2059 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
2060 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2061
2062 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
2063 if (r < 0)
2064 return bus_send_error_reply(connection, message, &error, r);
2065
2066 r = attach_device(m, seat, sysfs);
2067 if (r < 0)
2068 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2069
2070 reply = dbus_message_new_method_return(message);
2071 if (!reply)
2072 goto oom;
2073
2074
2075 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
2076 dbus_bool_t interactive;
2077
2078 if (!dbus_message_get_args(
2079 message,
2080 &error,
2081 DBUS_TYPE_BOOLEAN, &interactive,
2082 DBUS_TYPE_INVALID))
2083 return bus_send_error_reply(connection, message, &error, -EINVAL);
2084
2085 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
2086 if (r < 0)
2087 return bus_send_error_reply(connection, message, &error, r);
2088
2089 r = flush_devices(m);
2090 if (r < 0)
2091 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2092
2093 reply = dbus_message_new_method_return(message);
2094 if (!reply)
2095 goto oom;
2096
2097 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
2098
2099 r = bus_manager_do_shutdown_or_sleep(
2100 m, connection, message,
2101 SPECIAL_POWEROFF_TARGET,
2102 INHIBIT_SHUTDOWN,
2103 "org.freedesktop.login1.power-off",
2104 "org.freedesktop.login1.power-off-multiple-sessions",
2105 "org.freedesktop.login1.power-off-ignore-inhibit",
2106 NULL,
2107 &error, &reply);
2108 if (r < 0)
2109 return bus_send_error_reply(connection, message, &error, r);
2110 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
2111 r = bus_manager_do_shutdown_or_sleep(
2112 m, connection, message,
2113 SPECIAL_REBOOT_TARGET,
2114 INHIBIT_SHUTDOWN,
2115 "org.freedesktop.login1.reboot",
2116 "org.freedesktop.login1.reboot-multiple-sessions",
2117 "org.freedesktop.login1.reboot-ignore-inhibit",
2118 NULL,
2119 &error, &reply);
2120 if (r < 0)
2121 return bus_send_error_reply(connection, message, &error, r);
2122
2123 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2124 r = bus_manager_do_shutdown_or_sleep(
2125 m, connection, message,
2126 SPECIAL_SUSPEND_TARGET,
2127 INHIBIT_SLEEP,
2128 "org.freedesktop.login1.suspend",
2129 "org.freedesktop.login1.suspend-multiple-sessions",
2130 "org.freedesktop.login1.suspend-ignore-inhibit",
2131 "suspend",
2132 &error, &reply);
2133 if (r < 0)
2134 return bus_send_error_reply(connection, message, &error, r);
2135 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2136 r = bus_manager_do_shutdown_or_sleep(
2137 m, connection, message,
2138 SPECIAL_HIBERNATE_TARGET,
2139 INHIBIT_SLEEP,
2140 "org.freedesktop.login1.hibernate",
2141 "org.freedesktop.login1.hibernate-multiple-sessions",
2142 "org.freedesktop.login1.hibernate-ignore-inhibit",
2143 "hibernate",
2144 &error, &reply);
2145 if (r < 0)
2146 return bus_send_error_reply(connection, message, &error, r);
2147
2148 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "HybridSleep")) {
2149 r = bus_manager_do_shutdown_or_sleep(
2150 m, connection, message,
2151 SPECIAL_HYBRID_SLEEP_TARGET,
2152 INHIBIT_SLEEP,
2153 "org.freedesktop.login1.hibernate",
2154 "org.freedesktop.login1.hibernate-multiple-sessions",
2155 "org.freedesktop.login1.hibernate-ignore-inhibit",
2156 "hybrid-sleep",
2157 &error, &reply);
2158 if (r < 0)
2159 return bus_send_error_reply(connection, message, &error, r);
2160
2161 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2162
2163 r = bus_manager_can_shutdown_or_sleep(
2164 m, connection, message,
2165 INHIBIT_SHUTDOWN,
2166 "org.freedesktop.login1.power-off",
2167 "org.freedesktop.login1.power-off-multiple-sessions",
2168 "org.freedesktop.login1.power-off-ignore-inhibit",
2169 NULL,
2170 &error, &reply);
2171 if (r < 0)
2172 return bus_send_error_reply(connection, message, &error, r);
2173 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2174 r = bus_manager_can_shutdown_or_sleep(
2175 m, connection, message,
2176 INHIBIT_SHUTDOWN,
2177 "org.freedesktop.login1.reboot",
2178 "org.freedesktop.login1.reboot-multiple-sessions",
2179 "org.freedesktop.login1.reboot-ignore-inhibit",
2180 NULL,
2181 &error, &reply);
2182 if (r < 0)
2183 return bus_send_error_reply(connection, message, &error, r);
2184
2185 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2186 r = bus_manager_can_shutdown_or_sleep(
2187 m, connection, message,
2188 INHIBIT_SLEEP,
2189 "org.freedesktop.login1.suspend",
2190 "org.freedesktop.login1.suspend-multiple-sessions",
2191 "org.freedesktop.login1.suspend-ignore-inhibit",
2192 "suspend",
2193 &error, &reply);
2194 if (r < 0)
2195 return bus_send_error_reply(connection, message, &error, r);
2196
2197 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2198 r = bus_manager_can_shutdown_or_sleep(
2199 m, connection, message,
2200 INHIBIT_SLEEP,
2201 "org.freedesktop.login1.hibernate",
2202 "org.freedesktop.login1.hibernate-multiple-sessions",
2203 "org.freedesktop.login1.hibernate-ignore-inhibit",
2204 "hibernate",
2205 &error, &reply);
2206 if (r < 0)
2207 return bus_send_error_reply(connection, message, &error, r);
2208
2209 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHybridSleep")) {
2210 r = bus_manager_can_shutdown_or_sleep(
2211 m, connection, message,
2212 INHIBIT_SLEEP,
2213 "org.freedesktop.login1.hibernate",
2214 "org.freedesktop.login1.hibernate-multiple-sessions",
2215 "org.freedesktop.login1.hibernate-ignore-inhibit",
2216 "hybrid-sleep",
2217 &error, &reply);
2218 if (r < 0)
2219 return bus_send_error_reply(connection, message, &error, r);
2220
2221 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2222 char *introspection = NULL;
2223 FILE *f;
2224 Iterator i;
2225 Session *session;
2226 Seat *seat;
2227 User *user;
2228 size_t size;
2229 char *p;
2230
2231 if (!(reply = dbus_message_new_method_return(message)))
2232 goto oom;
2233
2234 /* We roll our own introspection code here, instead of
2235 * relying on bus_default_message_handler() because we
2236 * need to generate our introspection string
2237 * dynamically. */
2238
2239 if (!(f = open_memstream(&introspection, &size)))
2240 goto oom;
2241
2242 fputs(INTROSPECTION_BEGIN, f);
2243
2244 HASHMAP_FOREACH(seat, m->seats, i) {
2245 p = bus_path_escape(seat->id);
2246
2247 if (p) {
2248 fprintf(f, "<node name=\"seat/%s\"/>", p);
2249 free(p);
2250 }
2251 }
2252
2253 HASHMAP_FOREACH(user, m->users, i)
2254 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2255
2256 HASHMAP_FOREACH(session, m->sessions, i) {
2257 p = bus_path_escape(session->id);
2258
2259 if (p) {
2260 fprintf(f, "<node name=\"session/%s\"/>", p);
2261 free(p);
2262 }
2263 }
2264
2265 fputs(INTROSPECTION_END, f);
2266
2267 if (ferror(f)) {
2268 fclose(f);
2269 free(introspection);
2270 goto oom;
2271 }
2272
2273 fclose(f);
2274
2275 if (!introspection)
2276 goto oom;
2277
2278 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2279 free(introspection);
2280 goto oom;
2281 }
2282
2283 free(introspection);
2284 } else {
2285 const BusBoundProperties bps[] = {
2286 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2287 { NULL, }
2288 };
2289 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2290 }
2291
2292 if (reply) {
2293 if (!bus_maybe_send_reply(connection, message, reply))
2294 goto oom;
2295 }
2296
2297 return DBUS_HANDLER_RESULT_HANDLED;
2298
2299 oom:
2300 dbus_error_free(&error);
2301
2302 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2303 }
2304
2305 const DBusObjectPathVTable bus_manager_vtable = {
2306 .message_function = manager_message_handler
2307 };
2308
2309 DBusHandlerResult bus_message_filter(
2310 DBusConnection *connection,
2311 DBusMessage *message,
2312 void *userdata) {
2313
2314 Manager *m = userdata;
2315 DBusError error;
2316
2317 assert(m);
2318 assert(connection);
2319 assert(message);
2320
2321 dbus_error_init(&error);
2322
2323 log_debug("Got message: %s %s %s", strna(dbus_message_get_sender(message)), strna(dbus_message_get_interface(message)), strna(dbus_message_get_member(message)));
2324
2325 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
2326 const char *path, *result, *unit;
2327 uint32_t id;
2328
2329 if (!dbus_message_get_args(message, &error,
2330 DBUS_TYPE_UINT32, &id,
2331 DBUS_TYPE_OBJECT_PATH, &path,
2332 DBUS_TYPE_STRING, &unit,
2333 DBUS_TYPE_STRING, &result,
2334 DBUS_TYPE_INVALID)) {
2335 log_error("Failed to parse JobRemoved message: %s", bus_error_message(&error));
2336 goto finish;
2337 }
2338
2339 if (m->action_job && streq(m->action_job, path)) {
2340 log_info("Operation finished.");
2341
2342 /* Tell people that they now may take a lock again */
2343 send_prepare_for(m, m->action_what, false);
2344
2345 free(m->action_job);
2346 m->action_job = NULL;
2347 m->action_unit = NULL;
2348 m->action_what = 0;
2349
2350 } else {
2351 Session *s;
2352 User *u;
2353
2354 s = hashmap_get(m->session_units, unit);
2355 if (s) {
2356 if (streq_ptr(path, s->scope_job)) {
2357 free(s->scope_job);
2358 s->scope_job = NULL;
2359 session_save(s);
2360
2361 if (s->started) {
2362 if (streq(result, "done"))
2363 session_send_create_reply(s, NULL);
2364 else {
2365 dbus_set_error(&error, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
2366 session_send_create_reply(s, &error);
2367 }
2368 }
2369 }
2370
2371 session_add_to_gc_queue(s);
2372 }
2373
2374 u = hashmap_get(m->user_units, unit);
2375 if (u) {
2376 if (streq_ptr(path, u->service_job)) {
2377 free(u->service_job);
2378 u->service_job = NULL;
2379 }
2380
2381 if (streq_ptr(path, u->slice_job)) {
2382 free(u->slice_job);
2383 u->slice_job = NULL;
2384 }
2385
2386 user_save(u);
2387 user_add_to_gc_queue(u);
2388 }
2389 }
2390
2391 } else if (dbus_message_is_signal(message, "org.freedesktop.DBus.Properties", "PropertiesChanged")) {
2392
2393 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2394 _cleanup_free_ char *unit = NULL;
2395 const char *path;
2396
2397 path = dbus_message_get_path(message);
2398 if (!path)
2399 goto finish;
2400
2401 unit_name_from_dbus_path(path, &unit);
2402 if (unit) {
2403 Session *s;
2404 User *u;
2405
2406 s = hashmap_get(m->session_units, unit);
2407 if (s)
2408 session_add_to_gc_queue(s);
2409
2410 u = hashmap_get(m->user_units, unit);
2411 if (u)
2412 user_add_to_gc_queue(u);
2413 }
2414 }
2415
2416 finish:
2417 dbus_error_free(&error);
2418
2419 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2420 }
2421
2422 int manager_send_changed(Manager *manager, const char *properties) {
2423 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
2424
2425 assert(manager);
2426
2427 m = bus_properties_changed_new("/org/freedesktop/login1",
2428 "org.freedesktop.login1.Manager",
2429 properties);
2430 if (!m)
2431 return -ENOMEM;
2432
2433 if (!dbus_connection_send(manager->bus, m, NULL))
2434 return -ENOMEM;
2435
2436 return 0;
2437 }
2438
2439 int manager_dispatch_delayed(Manager *manager) {
2440 DBusError error;
2441 int r;
2442
2443 assert(manager);
2444
2445 if (manager->action_what == 0 || manager->action_job)
2446 return 0;
2447
2448 /* Continue delay? */
2449 if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0)) {
2450
2451 if (manager->action_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC))
2452 return 0;
2453
2454 log_info("Delay lock is active but inhibitor timeout is reached.");
2455 }
2456
2457 /* Actually do the operation */
2458 dbus_error_init(&error);
2459 r = execute_shutdown_or_sleep(manager, manager->action_what, manager->action_unit, &error);
2460 if (r < 0) {
2461 log_warning("Failed to send delayed message: %s", bus_error(&error, r));
2462 dbus_error_free(&error);
2463
2464 manager->action_unit = NULL;
2465 manager->action_what = 0;
2466 return r;
2467 }
2468
2469 return 1;
2470 }
2471
2472 int manager_start_scope(
2473 Manager *manager,
2474 const char *scope,
2475 pid_t pid,
2476 const char *slice,
2477 const char *description,
2478 DBusError *error,
2479 char **job) {
2480
2481 _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
2482 DBusMessageIter iter, sub, sub2, sub3, sub4;
2483 const char *timeout_stop_property = "TimeoutStopUSec";
2484 const char *pids_property = "PIDs";
2485 uint64_t timeout = 500 * USEC_PER_MSEC;
2486 const char *fail = "fail";
2487 uint32_t u;
2488
2489 assert(manager);
2490 assert(scope);
2491 assert(pid > 1);
2492
2493 if (!slice)
2494 slice = "";
2495
2496 m = dbus_message_new_method_call(
2497 "org.freedesktop.systemd1",
2498 "/org/freedesktop/systemd1",
2499 "org.freedesktop.systemd1.Manager",
2500 "StartTransientUnit");
2501 if (!m)
2502 return log_oom();
2503
2504 dbus_message_iter_init_append(m, &iter);
2505
2506 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &scope) ||
2507 !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &fail) ||
2508 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sv)", &sub))
2509 return log_oom();
2510
2511 if (!isempty(slice)) {
2512 const char *slice_property = "Slice";
2513
2514 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2515 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &slice_property) ||
2516 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "s", &sub3) ||
2517 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &slice) ||
2518 !dbus_message_iter_close_container(&sub2, &sub3) ||
2519 !dbus_message_iter_close_container(&sub, &sub2))
2520 return log_oom();
2521 }
2522
2523 if (!isempty(description)) {
2524 const char *description_property = "Description";
2525
2526 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2527 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description_property) ||
2528 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "s", &sub3) ||
2529 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &description) ||
2530 !dbus_message_iter_close_container(&sub2, &sub3) ||
2531 !dbus_message_iter_close_container(&sub, &sub2))
2532 return log_oom();
2533 }
2534
2535 /* cgroup empty notification is not available in containers
2536 * currently. To make this less problematic, let's shorten the
2537 * stop timeout for sessions, so that we don't wait
2538 * forever. */
2539
2540 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2541 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &timeout_stop_property) ||
2542 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "t", &sub3) ||
2543 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_UINT64, &timeout) ||
2544 !dbus_message_iter_close_container(&sub2, &sub3) ||
2545 !dbus_message_iter_close_container(&sub, &sub2))
2546 return log_oom();
2547
2548 u = pid;
2549 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2550 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &pids_property) ||
2551 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "au", &sub3) ||
2552 !dbus_message_iter_open_container(&sub3, DBUS_TYPE_ARRAY, "u", &sub4) ||
2553 !dbus_message_iter_append_basic(&sub4, DBUS_TYPE_UINT32, &u) ||
2554 !dbus_message_iter_close_container(&sub3, &sub4) ||
2555 !dbus_message_iter_close_container(&sub2, &sub3) ||
2556 !dbus_message_iter_close_container(&sub, &sub2) ||
2557 !dbus_message_iter_close_container(&iter, &sub))
2558 return log_oom();
2559
2560 reply = dbus_connection_send_with_reply_and_block(manager->bus, m, -1, error);
2561 if (!reply)
2562 return -EIO;
2563
2564 if (job) {
2565 const char *j;
2566 char *copy;
2567
2568 if (!dbus_message_get_args(reply, error, DBUS_TYPE_OBJECT_PATH, &j, DBUS_TYPE_INVALID))
2569 return -EIO;
2570
2571 copy = strdup(j);
2572 if (!copy)
2573 return -ENOMEM;
2574
2575 *job = copy;
2576 }
2577
2578 return 0;
2579 }
2580
2581 int manager_start_unit(Manager *manager, const char *unit, DBusError *error, char **job) {
2582 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2583 const char *fail = "fail";
2584 int r;
2585
2586 assert(manager);
2587 assert(unit);
2588
2589 r = bus_method_call_with_reply(
2590 manager->bus,
2591 "org.freedesktop.systemd1",
2592 "/org/freedesktop/systemd1",
2593 "org.freedesktop.systemd1.Manager",
2594 "StartUnit",
2595 &reply,
2596 error,
2597 DBUS_TYPE_STRING, &unit,
2598 DBUS_TYPE_STRING, &fail,
2599 DBUS_TYPE_INVALID);
2600 if (r < 0) {
2601 log_error("Failed to start unit %s: %s", unit, bus_error(error, r));
2602 return r;
2603 }
2604
2605 if (job) {
2606 const char *j;
2607 char *copy;
2608
2609 if (!dbus_message_get_args(reply, error,
2610 DBUS_TYPE_OBJECT_PATH, &j,
2611 DBUS_TYPE_INVALID)) {
2612 log_error("Failed to parse reply.");
2613 return -EIO;
2614 }
2615
2616 copy = strdup(j);
2617 if (!copy)
2618 return -ENOMEM;
2619
2620 *job = copy;
2621 }
2622
2623 return 0;
2624 }
2625
2626 int manager_stop_unit(Manager *manager, const char *unit, DBusError *error, char **job) {
2627 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2628 const char *fail = "fail";
2629 int r;
2630
2631 assert(manager);
2632 assert(unit);
2633
2634 r = bus_method_call_with_reply(
2635 manager->bus,
2636 "org.freedesktop.systemd1",
2637 "/org/freedesktop/systemd1",
2638 "org.freedesktop.systemd1.Manager",
2639 "StopUnit",
2640 &reply,
2641 error,
2642 DBUS_TYPE_STRING, &unit,
2643 DBUS_TYPE_STRING, &fail,
2644 DBUS_TYPE_INVALID);
2645 if (r < 0) {
2646 log_error("Failed to stop unit %s: %s", unit, bus_error(error, r));
2647 return r;
2648 }
2649
2650 if (job) {
2651 const char *j;
2652 char *copy;
2653
2654 if (!dbus_message_get_args(reply, error,
2655 DBUS_TYPE_OBJECT_PATH, &j,
2656 DBUS_TYPE_INVALID)) {
2657 log_error("Failed to parse reply.");
2658 return -EIO;
2659 }
2660
2661 copy = strdup(j);
2662 if (!copy)
2663 return -ENOMEM;
2664
2665 *job = copy;
2666 }
2667
2668 return 0;
2669 }
2670
2671 int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, DBusError *error) {
2672 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2673 const char *w;
2674 int r;
2675
2676 assert(manager);
2677 assert(unit);
2678
2679 w = who == KILL_LEADER ? "process" : "cgroup";
2680 assert_cc(sizeof(signo) == sizeof(int32_t));
2681
2682 r = bus_method_call_with_reply(
2683 manager->bus,
2684 "org.freedesktop.systemd1",
2685 "/org/freedesktop/systemd1",
2686 "org.freedesktop.systemd1.Manager",
2687 "KillUnit",
2688 &reply,
2689 error,
2690 DBUS_TYPE_STRING, &unit,
2691 DBUS_TYPE_STRING, &w,
2692 DBUS_TYPE_INT32, &signo,
2693 DBUS_TYPE_INVALID);
2694 if (r < 0) {
2695 log_error("Failed to stop unit %s: %s", unit, bus_error(error, r));
2696 return r;
2697 }
2698
2699 return 0;
2700 }
2701
2702 int manager_unit_is_active(Manager *manager, const char *unit) {
2703
2704 const char *interface = "org.freedesktop.systemd1.Unit";
2705 const char *property = "ActiveState";
2706 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2707 _cleanup_free_ char *path = NULL;
2708 DBusMessageIter iter, sub;
2709 const char *state;
2710 DBusError error;
2711 int r;
2712
2713 assert(manager);
2714 assert(unit);
2715
2716 dbus_error_init(&error);
2717
2718 path = unit_dbus_path_from_name(unit);
2719 if (!path)
2720 return -ENOMEM;
2721
2722 r = bus_method_call_with_reply(
2723 manager->bus,
2724 "org.freedesktop.systemd1",
2725 path,
2726 "org.freedesktop.DBus.Properties",
2727 "Get",
2728 &reply,
2729 &error,
2730 DBUS_TYPE_STRING, &interface,
2731 DBUS_TYPE_STRING, &property,
2732 DBUS_TYPE_INVALID);
2733
2734 if (r < 0) {
2735 log_error("Failed to query ActiveState: %s", bus_error(&error, r));
2736 dbus_error_free(&error);
2737 return r;
2738 }
2739
2740 if (!dbus_message_iter_init(reply, &iter) ||
2741 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
2742 log_error("Failed to parse reply.");
2743 return -EINVAL;
2744 }
2745
2746 dbus_message_iter_recurse(&iter, &sub);
2747 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
2748 log_error("Failed to parse reply.");
2749 return -EINVAL;
2750 }
2751
2752 dbus_message_iter_get_basic(&sub, &state);
2753
2754 return !streq(state, "inactive") && !streq(state, "failed");
2755 }