]> git.ipfire.org Git - thirdparty/systemd.git/blame_incremental - src/login/logind-dbus.c
logind: add infrastructure to watch busnames
[thirdparty/systemd.git] / src / login / logind-dbus.c
... / ...
CommitLineData
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
251static 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
266static 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
284static 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
298static 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
314static 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 log_warning("Existing logind session ID %s used by new audit session, ignoring", id);
558 audit_id = 0;
559
560 free(id);
561 id = NULL;
562 }
563 }
564
565 if (!id) {
566 do {
567 free(id);
568 id = NULL;
569
570 if (asprintf(&id, "c%lu", ++m->session_counter) < 0) {
571 r = -ENOMEM;
572 goto fail;
573 }
574
575 } while (hashmap_get(m->sessions, id));
576 }
577
578 r = manager_add_user_by_uid(m, uid, &user);
579 if (r < 0)
580 goto fail;
581
582 r = manager_add_session(m, id, &session);
583 if (r < 0)
584 goto fail;
585
586 session_set_user(session, user);
587
588 session->leader = leader;
589 session->audit_id = audit_id;
590 session->type = t;
591 session->class = c;
592 session->remote = remote;
593 session->vtnr = vtnr;
594
595 if (!isempty(tty)) {
596 session->tty = strdup(tty);
597 if (!session->tty) {
598 r = -ENOMEM;
599 goto fail;
600 }
601 }
602
603 if (!isempty(display)) {
604 session->display = strdup(display);
605 if (!session->display) {
606 r = -ENOMEM;
607 goto fail;
608 }
609 }
610
611 if (!isempty(remote_user)) {
612 session->remote_user = strdup(remote_user);
613 if (!session->remote_user) {
614 r = -ENOMEM;
615 goto fail;
616 }
617 }
618
619 if (!isempty(remote_host)) {
620 session->remote_host = strdup(remote_host);
621 if (!session->remote_host) {
622 r = -ENOMEM;
623 goto fail;
624 }
625 }
626
627 if (!isempty(service)) {
628 session->service = strdup(service);
629 if (!session->service) {
630 r = -ENOMEM;
631 goto fail;
632 }
633 }
634
635 if (seat) {
636 r = seat_attach_session(seat, session);
637 if (r < 0)
638 goto fail;
639 }
640
641 r = session_start(session);
642 if (r < 0)
643 goto fail;
644
645 session->create_message = dbus_message_ref(message);
646
647 /* Now, let's wait until the slice unit and stuff got
648 * created. We send the reply back from
649 * session_send_create_reply().*/
650
651 return 0;
652
653fail:
654 if (session)
655 session_add_to_gc_queue(session);
656
657 if (user)
658 user_add_to_gc_queue(user);
659
660 return r;
661}
662
663static int bus_manager_inhibit(
664 Manager *m,
665 DBusConnection *connection,
666 DBusMessage *message,
667 DBusError *error,
668 DBusMessage **_reply) {
669
670 Inhibitor *i = NULL;
671 char *id = NULL;
672 const char *who, *why, *what, *mode;
673 pid_t pid;
674 InhibitWhat w;
675 InhibitMode mm;
676 unsigned long ul;
677 int r, fifo_fd = -1;
678 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
679
680 assert(m);
681 assert(connection);
682 assert(message);
683 assert(error);
684 assert(_reply);
685
686 if (!dbus_message_get_args(
687 message,
688 error,
689 DBUS_TYPE_STRING, &what,
690 DBUS_TYPE_STRING, &who,
691 DBUS_TYPE_STRING, &why,
692 DBUS_TYPE_STRING, &mode,
693 DBUS_TYPE_INVALID)) {
694 r = -EIO;
695 goto fail;
696 }
697
698 w = inhibit_what_from_string(what);
699 if (w <= 0) {
700 r = -EINVAL;
701 goto fail;
702 }
703
704 mm = inhibit_mode_from_string(mode);
705 if (mm < 0) {
706 r = -EINVAL;
707 goto fail;
708 }
709
710 /* Delay is only supported for shutdown/sleep */
711 if (mm == INHIBIT_DELAY && (w & ~(INHIBIT_SHUTDOWN|INHIBIT_SLEEP))) {
712 r = -EINVAL;
713 goto fail;
714 }
715
716 /* Don't allow taking delay locks while we are already
717 * executing the operation. We shouldn't create the impression
718 * that the lock was successful if the machine is about to go
719 * down/suspend any moment. */
720 if (m->action_what & w) {
721 r = -EALREADY;
722 goto fail;
723 }
724
725 r = verify_polkit(connection, message,
726 w == INHIBIT_SHUTDOWN ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
727 w == INHIBIT_SLEEP ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep" : "org.freedesktop.login1.inhibit-delay-sleep") :
728 w == INHIBIT_IDLE ? "org.freedesktop.login1.inhibit-block-idle" :
729 w == INHIBIT_HANDLE_POWER_KEY ? "org.freedesktop.login1.inhibit-handle-power-key" :
730 w == INHIBIT_HANDLE_SUSPEND_KEY ? "org.freedesktop.login1.inhibit-handle-suspend-key" :
731 w == INHIBIT_HANDLE_HIBERNATE_KEY ? "org.freedesktop.login1.inhibit-handle-hibernate-key" :
732 "org.freedesktop.login1.inhibit-handle-lid-switch",
733 false, NULL, error);
734 if (r < 0)
735 goto fail;
736
737 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
738 if (ul == (unsigned long) -1) {
739 r = -EIO;
740 goto fail;
741 }
742
743 pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
744 if (pid <= 0) {
745 r = -EIO;
746 goto fail;
747 }
748
749 do {
750 free(id);
751 id = NULL;
752
753 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
754 r = -ENOMEM;
755 goto fail;
756 }
757 } while (hashmap_get(m->inhibitors, id));
758
759 r = manager_add_inhibitor(m, id, &i);
760 free(id);
761
762 if (r < 0)
763 goto fail;
764
765 i->what = w;
766 i->mode = mm;
767 i->pid = pid;
768 i->uid = (uid_t) ul;
769 i->why = strdup(why);
770 i->who = strdup(who);
771
772 if (!i->why || !i->who) {
773 r = -ENOMEM;
774 goto fail;
775 }
776
777 fifo_fd = inhibitor_create_fifo(i);
778 if (fifo_fd < 0) {
779 r = fifo_fd;
780 goto fail;
781 }
782
783 reply = dbus_message_new_method_return(message);
784 if (!reply) {
785 r = -ENOMEM;
786 goto fail;
787 }
788
789 if (!dbus_message_append_args(
790 reply,
791 DBUS_TYPE_UNIX_FD, &fifo_fd,
792 DBUS_TYPE_INVALID)) {
793 r = -ENOMEM;
794 goto fail;
795 }
796
797 close_nointr_nofail(fifo_fd);
798 *_reply = reply;
799 reply = NULL;
800
801 inhibitor_start(i);
802
803 return 0;
804
805fail:
806 if (i)
807 inhibitor_free(i);
808
809 if (fifo_fd >= 0)
810 close_nointr_nofail(fifo_fd);
811
812 return r;
813}
814
815static int trigger_device(Manager *m, struct udev_device *d) {
816 struct udev_enumerate *e;
817 struct udev_list_entry *first, *item;
818 int r;
819
820 assert(m);
821
822 e = udev_enumerate_new(m->udev);
823 if (!e) {
824 r = -ENOMEM;
825 goto finish;
826 }
827
828 if (d) {
829 if (udev_enumerate_add_match_parent(e, d) < 0) {
830 r = -EIO;
831 goto finish;
832 }
833 }
834
835 if (udev_enumerate_scan_devices(e) < 0) {
836 r = -EIO;
837 goto finish;
838 }
839
840 first = udev_enumerate_get_list_entry(e);
841 udev_list_entry_foreach(item, first) {
842 char *t;
843 const char *p;
844
845 p = udev_list_entry_get_name(item);
846
847 t = strappend(p, "/uevent");
848 if (!t) {
849 r = -ENOMEM;
850 goto finish;
851 }
852
853 write_string_file(t, "change");
854 free(t);
855 }
856
857 r = 0;
858
859finish:
860 if (e)
861 udev_enumerate_unref(e);
862
863 return r;
864}
865
866static int attach_device(Manager *m, const char *seat, const char *sysfs) {
867 struct udev_device *d;
868 _cleanup_free_ char *rule = NULL, *file = NULL;
869 const char *id_for_seat;
870 int r;
871
872 assert(m);
873 assert(seat);
874 assert(sysfs);
875
876 d = udev_device_new_from_syspath(m->udev, sysfs);
877 if (!d)
878 return -ENODEV;
879
880 if (!udev_device_has_tag(d, "seat")) {
881 r = -ENODEV;
882 goto finish;
883 }
884
885 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
886 if (!id_for_seat) {
887 r = -ENODEV;
888 goto finish;
889 }
890
891 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
892 r = -ENOMEM;
893 goto finish;
894 }
895
896 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
897 r = -ENOMEM;
898 goto finish;
899 }
900
901 mkdir_p_label("/etc/udev/rules.d", 0755);
902 label_init("/etc");
903 r = write_string_file_atomic_label(file, rule);
904 if (r < 0)
905 goto finish;
906
907 r = trigger_device(m, d);
908
909finish:
910 if (d)
911 udev_device_unref(d);
912
913 return r;
914}
915
916static int flush_devices(Manager *m) {
917 _cleanup_closedir_ DIR *d;
918
919 assert(m);
920
921 d = opendir("/etc/udev/rules.d");
922 if (!d) {
923 if (errno != ENOENT)
924 log_warning("Failed to open /etc/udev/rules.d: %m");
925 } else {
926 struct dirent *de;
927
928 while ((de = readdir(d))) {
929
930 if (!dirent_is_file(de))
931 continue;
932
933 if (!startswith(de->d_name, "72-seat-"))
934 continue;
935
936 if (!endswith(de->d_name, ".rules"))
937 continue;
938
939 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
940 log_warning("Failed to unlink %s: %m", de->d_name);
941 }
942 }
943
944 return trigger_device(m, NULL);
945}
946
947static int have_multiple_sessions(
948 Manager *m,
949 uid_t uid) {
950
951 Session *session;
952 Iterator i;
953
954 assert(m);
955
956 /* Check for other users' sessions. Greeter sessions do not
957 * count, and non-login sessions do not count either. */
958 HASHMAP_FOREACH(session, m->sessions, i)
959 if (session->class == SESSION_USER &&
960 session->user->uid != uid)
961 return true;
962
963 return false;
964}
965
966static int bus_manager_log_shutdown(
967 Manager *m,
968 InhibitWhat w,
969 const char *unit_name) {
970
971 const char *p, *q;
972
973 assert(m);
974 assert(unit_name);
975
976 if (w != INHIBIT_SHUTDOWN)
977 return 0;
978
979 if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
980 p = "MESSAGE=System is powering down.";
981 q = "SHUTDOWN=power-off";
982 } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
983 p = "MESSAGE=System is halting.";
984 q = "SHUTDOWN=halt";
985 } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
986 p = "MESSAGE=System is rebooting.";
987 q = "SHUTDOWN=reboot";
988 } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
989 p = "MESSAGE=System is rebooting with kexec.";
990 q = "SHUTDOWN=kexec";
991 } else {
992 p = "MESSAGE=System is shutting down.";
993 q = NULL;
994 }
995
996 return log_struct(LOG_NOTICE, MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
997 p,
998 q, NULL);
999}
1000
1001static int execute_shutdown_or_sleep(
1002 Manager *m,
1003 InhibitWhat w,
1004 const char *unit_name,
1005 DBusError *error) {
1006
1007 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1008 const char *mode = "replace-irreversibly", *p;
1009 int r;
1010 char *c;
1011
1012 assert(m);
1013 assert(w >= 0);
1014 assert(w < _INHIBIT_WHAT_MAX);
1015 assert(unit_name);
1016
1017 bus_manager_log_shutdown(m, w, unit_name);
1018
1019 r = bus_method_call_with_reply(
1020 m->bus,
1021 "org.freedesktop.systemd1",
1022 "/org/freedesktop/systemd1",
1023 "org.freedesktop.systemd1.Manager",
1024 "StartUnit",
1025 &reply,
1026 error,
1027 DBUS_TYPE_STRING, &unit_name,
1028 DBUS_TYPE_STRING, &mode,
1029 DBUS_TYPE_INVALID);
1030 if (r < 0)
1031 return r;
1032
1033 if (!dbus_message_get_args(
1034 reply,
1035 error,
1036 DBUS_TYPE_OBJECT_PATH, &p,
1037 DBUS_TYPE_INVALID))
1038 return -EINVAL;
1039
1040 c = strdup(p);
1041 if (!c)
1042 return -ENOMEM;
1043
1044 m->action_unit = unit_name;
1045 free(m->action_job);
1046 m->action_job = c;
1047 m->action_what = w;
1048
1049 return 0;
1050}
1051
1052static int delay_shutdown_or_sleep(
1053 Manager *m,
1054 InhibitWhat w,
1055 const char *unit_name) {
1056
1057 assert(m);
1058 assert(w >= 0);
1059 assert(w < _INHIBIT_WHAT_MAX);
1060 assert(unit_name);
1061
1062 m->action_timestamp = now(CLOCK_MONOTONIC);
1063 m->action_unit = unit_name;
1064 m->action_what = w;
1065
1066 return 0;
1067}
1068
1069static int bus_manager_can_shutdown_or_sleep(
1070 Manager *m,
1071 DBusConnection *connection,
1072 DBusMessage *message,
1073 InhibitWhat w,
1074 const char *action,
1075 const char *action_multiple_sessions,
1076 const char *action_ignore_inhibit,
1077 const char *sleep_verb,
1078 DBusError *error,
1079 DBusMessage **_reply) {
1080
1081 bool multiple_sessions, challenge, blocked, b;
1082 const char *result = NULL;
1083 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1084 int r;
1085 unsigned long ul;
1086
1087 assert(m);
1088 assert(connection);
1089 assert(message);
1090 assert(w >= 0);
1091 assert(w <= _INHIBIT_WHAT_MAX);
1092 assert(action);
1093 assert(action_multiple_sessions);
1094 assert(action_ignore_inhibit);
1095 assert(error);
1096 assert(_reply);
1097
1098 if (sleep_verb) {
1099 r = can_sleep(sleep_verb);
1100 if (r < 0)
1101 return r;
1102 if (r == 0) {
1103 result = "na";
1104 goto finish;
1105 }
1106 }
1107
1108 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1109 if (ul == (unsigned long) -1)
1110 return -EIO;
1111
1112 r = have_multiple_sessions(m, (uid_t) ul);
1113 if (r < 0)
1114 return r;
1115
1116 multiple_sessions = r > 0;
1117 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1118
1119 if (multiple_sessions) {
1120 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1121 if (r < 0)
1122 return r;
1123
1124 if (r > 0)
1125 result = "yes";
1126 else if (challenge)
1127 result = "challenge";
1128 else
1129 result = "no";
1130 }
1131
1132 if (blocked) {
1133 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1134 if (r < 0)
1135 return r;
1136
1137 if (r > 0 && !result)
1138 result = "yes";
1139 else if (challenge && (!result || streq(result, "yes")))
1140 result = "challenge";
1141 else
1142 result = "no";
1143 }
1144
1145 if (!multiple_sessions && !blocked) {
1146 /* If neither inhibit nor multiple sessions
1147 * apply then just check the normal policy */
1148
1149 r = verify_polkit(connection, message, action, false, &challenge, error);
1150 if (r < 0)
1151 return r;
1152
1153 if (r > 0)
1154 result = "yes";
1155 else if (challenge)
1156 result = "challenge";
1157 else
1158 result = "no";
1159 }
1160
1161finish:
1162 reply = dbus_message_new_method_return(message);
1163 if (!reply)
1164 return -ENOMEM;
1165
1166 b = dbus_message_append_args(
1167 reply,
1168 DBUS_TYPE_STRING, &result,
1169 DBUS_TYPE_INVALID);
1170 if (!b)
1171 return -ENOMEM;
1172
1173 *_reply = reply;
1174 reply = NULL;
1175 return 0;
1176}
1177
1178static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
1179 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
1180 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
1181 [INHIBIT_SLEEP] = "PrepareForSleep"
1182 };
1183
1184 dbus_bool_t active = _active;
1185 _cleanup_dbus_message_unref_ DBusMessage *message = NULL;
1186
1187 assert(m);
1188 assert(w >= 0);
1189 assert(w < _INHIBIT_WHAT_MAX);
1190 assert(signal_name[w]);
1191
1192 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1193 if (!message)
1194 return -ENOMEM;
1195
1196 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1197 !dbus_connection_send(m->bus, message, NULL))
1198 return -ENOMEM;
1199
1200 return 0;
1201}
1202
1203int bus_manager_shutdown_or_sleep_now_or_later(
1204 Manager *m,
1205 const char *unit_name,
1206 InhibitWhat w,
1207 DBusError *error) {
1208
1209 bool delayed;
1210 int r;
1211
1212 assert(m);
1213 assert(unit_name);
1214 assert(w >= 0);
1215 assert(w <= _INHIBIT_WHAT_MAX);
1216 assert(!m->action_job);
1217
1218 /* Tell everybody to prepare for shutdown/sleep */
1219 send_prepare_for(m, w, true);
1220
1221 delayed =
1222 m->inhibit_delay_max > 0 &&
1223 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0);
1224
1225 if (delayed)
1226 /* Shutdown is delayed, keep in mind what we
1227 * want to do, and start a timeout */
1228 r = delay_shutdown_or_sleep(m, w, unit_name);
1229 else
1230 /* Shutdown is not delayed, execute it
1231 * immediately */
1232 r = execute_shutdown_or_sleep(m, w, unit_name, error);
1233
1234 return r;
1235}
1236
1237static int bus_manager_do_shutdown_or_sleep(
1238 Manager *m,
1239 DBusConnection *connection,
1240 DBusMessage *message,
1241 const char *unit_name,
1242 InhibitWhat w,
1243 const char *action,
1244 const char *action_multiple_sessions,
1245 const char *action_ignore_inhibit,
1246 const char *sleep_verb,
1247 DBusError *error,
1248 DBusMessage **_reply) {
1249
1250 dbus_bool_t interactive;
1251 bool multiple_sessions, blocked;
1252 DBusMessage *reply = NULL;
1253 int r;
1254 unsigned long ul;
1255
1256 assert(m);
1257 assert(connection);
1258 assert(message);
1259 assert(unit_name);
1260 assert(w >= 0);
1261 assert(w <= _INHIBIT_WHAT_MAX);
1262 assert(action);
1263 assert(action_multiple_sessions);
1264 assert(action_ignore_inhibit);
1265 assert(error);
1266 assert(_reply);
1267
1268 /* Don't allow multiple jobs being executed at the same time */
1269 if (m->action_what)
1270 return -EALREADY;
1271
1272 if (!dbus_message_get_args(
1273 message,
1274 error,
1275 DBUS_TYPE_BOOLEAN, &interactive,
1276 DBUS_TYPE_INVALID))
1277 return -EINVAL;
1278
1279 if (sleep_verb) {
1280 r = can_sleep(sleep_verb);
1281 if (r < 0)
1282 return r;
1283
1284 if (r == 0)
1285 return -ENOTSUP;
1286 }
1287
1288 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1289 if (ul == (unsigned long) -1)
1290 return -EIO;
1291
1292 r = have_multiple_sessions(m, (uid_t) ul);
1293 if (r < 0)
1294 return r;
1295
1296 multiple_sessions = r > 0;
1297 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1298
1299 if (multiple_sessions) {
1300 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1301 if (r < 0)
1302 return r;
1303 }
1304
1305 if (blocked) {
1306 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1307 if (r < 0)
1308 return r;
1309 }
1310
1311 if (!multiple_sessions && !blocked) {
1312 r = verify_polkit(connection, message, action, interactive, NULL, error);
1313 if (r < 0)
1314 return r;
1315 }
1316
1317 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
1318 if (r < 0)
1319 return r;
1320
1321 reply = dbus_message_new_method_return(message);
1322 if (!reply)
1323 return -ENOMEM;
1324
1325 *_reply = reply;
1326 return 0;
1327}
1328
1329static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_action, handle_action, HandleAction);
1330
1331static const BusProperty bus_login_manager_properties[] = {
1332 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1333 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1334 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1335 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1336 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1337 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1338 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
1339 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1340 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1341 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
1342 { "HandlePowerKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_power_key) },
1343 { "HandleSuspendKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_suspend_key) },
1344 { "HandleHibernateKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_hibernate_key)},
1345 { "HandleLidSwitch", bus_manager_append_handle_action, "s", offsetof(Manager, handle_lid_switch) },
1346 { "IdleAction", bus_manager_append_handle_action, "s", offsetof(Manager, idle_action) },
1347 { "IdleActionUSec", bus_property_append_usec, "t", offsetof(Manager, idle_action_usec) },
1348 { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
1349 { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
1350 { NULL, }
1351};
1352
1353static DBusHandlerResult manager_message_handler(
1354 DBusConnection *connection,
1355 DBusMessage *message,
1356 void *userdata) {
1357
1358 Manager *m = userdata;
1359
1360 DBusError error;
1361 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1362 int r;
1363
1364 assert(connection);
1365 assert(message);
1366 assert(m);
1367
1368 dbus_error_init(&error);
1369
1370 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1371 const char *name;
1372 char *p;
1373 Session *session;
1374 bool b;
1375
1376 if (!dbus_message_get_args(
1377 message,
1378 &error,
1379 DBUS_TYPE_STRING, &name,
1380 DBUS_TYPE_INVALID))
1381 return bus_send_error_reply(connection, message, &error, -EINVAL);
1382
1383 session = hashmap_get(m->sessions, name);
1384 if (!session)
1385 return bus_send_error_reply(connection, message, &error, -ENOENT);
1386
1387 reply = dbus_message_new_method_return(message);
1388 if (!reply)
1389 goto oom;
1390
1391 p = session_bus_path(session);
1392 if (!p)
1393 goto oom;
1394
1395 b = dbus_message_append_args(
1396 reply,
1397 DBUS_TYPE_OBJECT_PATH, &p,
1398 DBUS_TYPE_INVALID);
1399 free(p);
1400
1401 if (!b)
1402 goto oom;
1403
1404 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1405 uint32_t pid;
1406 char *p;
1407 Session *session;
1408 bool b;
1409
1410 if (!dbus_message_get_args(
1411 message,
1412 &error,
1413 DBUS_TYPE_UINT32, &pid,
1414 DBUS_TYPE_INVALID))
1415 return bus_send_error_reply(connection, message, &error, -EINVAL);
1416
1417 r = manager_get_session_by_pid(m, pid, &session);
1418 if (r <= 0)
1419 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1420
1421 reply = dbus_message_new_method_return(message);
1422 if (!reply)
1423 goto oom;
1424
1425 p = session_bus_path(session);
1426 if (!p)
1427 goto oom;
1428
1429 b = dbus_message_append_args(
1430 reply,
1431 DBUS_TYPE_OBJECT_PATH, &p,
1432 DBUS_TYPE_INVALID);
1433 free(p);
1434
1435 if (!b)
1436 goto oom;
1437
1438 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1439 uint32_t uid;
1440 char *p;
1441 User *user;
1442 bool b;
1443
1444 if (!dbus_message_get_args(
1445 message,
1446 &error,
1447 DBUS_TYPE_UINT32, &uid,
1448 DBUS_TYPE_INVALID))
1449 return bus_send_error_reply(connection, message, &error, -EINVAL);
1450
1451 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1452 if (!user)
1453 return bus_send_error_reply(connection, message, &error, -ENOENT);
1454
1455 reply = dbus_message_new_method_return(message);
1456 if (!reply)
1457 goto oom;
1458
1459 p = user_bus_path(user);
1460 if (!p)
1461 goto oom;
1462
1463 b = dbus_message_append_args(
1464 reply,
1465 DBUS_TYPE_OBJECT_PATH, &p,
1466 DBUS_TYPE_INVALID);
1467 free(p);
1468
1469 if (!b)
1470 goto oom;
1471
1472 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUserByPID")) {
1473 uint32_t pid;
1474 char *p;
1475 User *user;
1476 bool b;
1477
1478 if (!dbus_message_get_args(
1479 message,
1480 &error,
1481 DBUS_TYPE_UINT32, &pid,
1482 DBUS_TYPE_INVALID))
1483 return bus_send_error_reply(connection, message, &error, -EINVAL);
1484
1485 r = manager_get_user_by_pid(m, pid, &user);
1486 if (r <= 0)
1487 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1488
1489 reply = dbus_message_new_method_return(message);
1490 if (!reply)
1491 goto oom;
1492
1493 p = user_bus_path(user);
1494 if (!p)
1495 goto oom;
1496
1497 b = dbus_message_append_args(
1498 reply,
1499 DBUS_TYPE_OBJECT_PATH, &p,
1500 DBUS_TYPE_INVALID);
1501 free(p);
1502
1503 if (!b)
1504 goto oom;
1505
1506 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1507 const char *name;
1508 char *p;
1509 Seat *seat;
1510 bool b;
1511
1512 if (!dbus_message_get_args(
1513 message,
1514 &error,
1515 DBUS_TYPE_STRING, &name,
1516 DBUS_TYPE_INVALID))
1517 return bus_send_error_reply(connection, message, &error, -EINVAL);
1518
1519 seat = hashmap_get(m->seats, name);
1520 if (!seat)
1521 return bus_send_error_reply(connection, message, &error, -ENOENT);
1522
1523 reply = dbus_message_new_method_return(message);
1524 if (!reply)
1525 goto oom;
1526
1527 p = seat_bus_path(seat);
1528 if (!p)
1529 goto oom;
1530
1531 b = dbus_message_append_args(
1532 reply,
1533 DBUS_TYPE_OBJECT_PATH, &p,
1534 DBUS_TYPE_INVALID);
1535 free(p);
1536
1537 if (!b)
1538 goto oom;
1539
1540 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1541 char *p;
1542 Session *session;
1543 Iterator i;
1544 DBusMessageIter iter, sub;
1545 const char *empty = "";
1546
1547 reply = dbus_message_new_method_return(message);
1548 if (!reply)
1549 goto oom;
1550
1551 dbus_message_iter_init_append(reply, &iter);
1552
1553 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1554 goto oom;
1555
1556 HASHMAP_FOREACH(session, m->sessions, i) {
1557 DBusMessageIter sub2;
1558 uint32_t uid;
1559
1560 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1561 goto oom;
1562
1563 uid = session->user->uid;
1564
1565 p = session_bus_path(session);
1566 if (!p)
1567 goto oom;
1568
1569 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1570 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1571 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1572 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1573 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1574 free(p);
1575 goto oom;
1576 }
1577
1578 free(p);
1579
1580 if (!dbus_message_iter_close_container(&sub, &sub2))
1581 goto oom;
1582 }
1583
1584 if (!dbus_message_iter_close_container(&iter, &sub))
1585 goto oom;
1586
1587 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1588 User *user;
1589 Iterator i;
1590 DBusMessageIter iter, sub;
1591
1592 reply = dbus_message_new_method_return(message);
1593 if (!reply)
1594 goto oom;
1595
1596 dbus_message_iter_init_append(reply, &iter);
1597
1598 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1599 goto oom;
1600
1601 HASHMAP_FOREACH(user, m->users, i) {
1602 _cleanup_free_ char *p = NULL;
1603 DBusMessageIter sub2;
1604 uint32_t uid;
1605
1606 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1607 goto oom;
1608
1609 uid = user->uid;
1610
1611 p = user_bus_path(user);
1612 if (!p)
1613 goto oom;
1614
1615 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1616 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1617 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1618 free(p);
1619 goto oom;
1620 }
1621
1622 if (!dbus_message_iter_close_container(&sub, &sub2))
1623 goto oom;
1624 }
1625
1626 if (!dbus_message_iter_close_container(&iter, &sub))
1627 goto oom;
1628
1629 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1630 Seat *seat;
1631 Iterator i;
1632 DBusMessageIter iter, sub;
1633
1634 reply = dbus_message_new_method_return(message);
1635 if (!reply)
1636 goto oom;
1637
1638 dbus_message_iter_init_append(reply, &iter);
1639
1640 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1641 goto oom;
1642
1643 HASHMAP_FOREACH(seat, m->seats, i) {
1644 _cleanup_free_ char *p = NULL;
1645 DBusMessageIter sub2;
1646
1647 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1648 goto oom;
1649
1650 p = seat_bus_path(seat);
1651 if (!p)
1652 goto oom;
1653
1654 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1655 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1656 free(p);
1657 goto oom;
1658 }
1659
1660 if (!dbus_message_iter_close_container(&sub, &sub2))
1661 goto oom;
1662 }
1663
1664 if (!dbus_message_iter_close_container(&iter, &sub))
1665 goto oom;
1666
1667 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1668 Inhibitor *inhibitor;
1669 Iterator i;
1670 DBusMessageIter iter, sub;
1671
1672 reply = dbus_message_new_method_return(message);
1673 if (!reply)
1674 goto oom;
1675
1676 dbus_message_iter_init_append(reply, &iter);
1677
1678 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1679 goto oom;
1680
1681 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1682 DBusMessageIter sub2;
1683 dbus_uint32_t uid, pid;
1684 const char *what, *who, *why, *mode;
1685
1686 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1687 goto oom;
1688
1689 what = strempty(inhibit_what_to_string(inhibitor->what));
1690 who = strempty(inhibitor->who);
1691 why = strempty(inhibitor->why);
1692 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
1693 uid = (dbus_uint32_t) inhibitor->uid;
1694 pid = (dbus_uint32_t) inhibitor->pid;
1695
1696 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1697 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1698 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1699 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
1700 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1701 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1702 goto oom;
1703
1704 if (!dbus_message_iter_close_container(&sub, &sub2))
1705 goto oom;
1706 }
1707
1708 if (!dbus_message_iter_close_container(&iter, &sub))
1709 goto oom;
1710
1711
1712 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1713
1714 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1715
1716 if (r < 0)
1717 return bus_send_error_reply(connection, message, &error, r);
1718
1719
1720 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1721
1722 r = bus_manager_create_session(m, message);
1723
1724 /* Don't delay the work on OOM here, since it might be
1725 * triggered by a low RLIMIT_NOFILE here (since we
1726 * send a dupped fd to the client), and we'd rather
1727 * see this fail quickly then be retried later */
1728
1729 if (r < 0)
1730 return bus_send_error_reply(connection, message, NULL, r);
1731
1732 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1733 const char *name;
1734 Session *session;
1735
1736 if (!dbus_message_get_args(
1737 message,
1738 &error,
1739 DBUS_TYPE_STRING, &name,
1740 DBUS_TYPE_INVALID))
1741 return bus_send_error_reply(connection, message, &error, -EINVAL);
1742
1743 session = hashmap_get(m->sessions, name);
1744 if (!session)
1745 return bus_send_error_reply(connection, message, &error, -ENOENT);
1746
1747 /* We use the FIFO to detect stray sessions where the
1748 process invoking PAM dies abnormally. We need to make
1749 sure that that process is not killed if at the clean
1750 end of the session it closes the FIFO. Hence, with
1751 this call explicitly turn off the FIFO logic, so that
1752 the PAM code can finish clean up on its own */
1753 session_remove_fifo(session);
1754
1755 reply = dbus_message_new_method_return(message);
1756 if (!reply)
1757 goto oom;
1758
1759 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1760 const char *name;
1761 Session *session;
1762
1763 if (!dbus_message_get_args(
1764 message,
1765 &error,
1766 DBUS_TYPE_STRING, &name,
1767 DBUS_TYPE_INVALID))
1768 return bus_send_error_reply(connection, message, &error, -EINVAL);
1769
1770 session = hashmap_get(m->sessions, name);
1771 if (!session)
1772 return bus_send_error_reply(connection, message, &error, -ENOENT);
1773
1774 r = session_activate(session);
1775 if (r < 0)
1776 return bus_send_error_reply(connection, message, NULL, r);
1777
1778 reply = dbus_message_new_method_return(message);
1779 if (!reply)
1780 goto oom;
1781
1782 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1783 const char *session_name, *seat_name;
1784 Session *session;
1785 Seat *seat;
1786
1787 /* Same as ActivateSession() but refuses to work if
1788 * the seat doesn't match */
1789
1790 if (!dbus_message_get_args(
1791 message,
1792 &error,
1793 DBUS_TYPE_STRING, &session_name,
1794 DBUS_TYPE_STRING, &seat_name,
1795 DBUS_TYPE_INVALID))
1796 return bus_send_error_reply(connection, message, &error, -EINVAL);
1797
1798 session = hashmap_get(m->sessions, session_name);
1799 if (!session)
1800 return bus_send_error_reply(connection, message, &error, -ENOENT);
1801
1802 seat = hashmap_get(m->seats, seat_name);
1803 if (!seat)
1804 return bus_send_error_reply(connection, message, &error, -ENOENT);
1805
1806 if (session->seat != seat)
1807 return bus_send_error_reply(connection, message, &error, -EINVAL);
1808
1809 r = session_activate(session);
1810 if (r < 0)
1811 return bus_send_error_reply(connection, message, NULL, r);
1812
1813 reply = dbus_message_new_method_return(message);
1814 if (!reply)
1815 goto oom;
1816
1817 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1818 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1819 const char *name;
1820 Session *session;
1821
1822 if (!dbus_message_get_args(
1823 message,
1824 &error,
1825 DBUS_TYPE_STRING, &name,
1826 DBUS_TYPE_INVALID))
1827 return bus_send_error_reply(connection, message, &error, -EINVAL);
1828
1829 session = hashmap_get(m->sessions, name);
1830 if (!session)
1831 return bus_send_error_reply(connection, message, NULL, -ENOENT);
1832
1833 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1834 goto oom;
1835
1836 reply = dbus_message_new_method_return(message);
1837 if (!reply)
1838 goto oom;
1839
1840 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions") ||
1841 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSessions")) {
1842
1843 r = session_send_lock_all(m, streq(dbus_message_get_member(message), "LockSessions"));
1844 if (r < 0)
1845 bus_send_error_reply(connection, message, NULL, r);
1846
1847 reply = dbus_message_new_method_return(message);
1848 if (!reply)
1849 goto oom;
1850
1851 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1852 const char *swho;
1853 int32_t signo;
1854 KillWho who;
1855 const char *name;
1856 Session *session;
1857
1858 if (!dbus_message_get_args(
1859 message,
1860 &error,
1861 DBUS_TYPE_STRING, &name,
1862 DBUS_TYPE_STRING, &swho,
1863 DBUS_TYPE_INT32, &signo,
1864 DBUS_TYPE_INVALID))
1865 return bus_send_error_reply(connection, message, &error, -EINVAL);
1866
1867 if (isempty(swho))
1868 who = KILL_ALL;
1869 else {
1870 who = kill_who_from_string(swho);
1871 if (who < 0)
1872 return bus_send_error_reply(connection, message, &error, -EINVAL);
1873 }
1874
1875 if (signo <= 0 || signo >= _NSIG)
1876 return bus_send_error_reply(connection, message, &error, -EINVAL);
1877
1878 session = hashmap_get(m->sessions, name);
1879 if (!session)
1880 return bus_send_error_reply(connection, message, &error, -ENOENT);
1881
1882 r = session_kill(session, who, signo);
1883 if (r < 0)
1884 return bus_send_error_reply(connection, message, NULL, r);
1885
1886 reply = dbus_message_new_method_return(message);
1887 if (!reply)
1888 goto oom;
1889
1890 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1891 uint32_t uid;
1892 User *user;
1893 int32_t signo;
1894
1895 if (!dbus_message_get_args(
1896 message,
1897 &error,
1898 DBUS_TYPE_UINT32, &uid,
1899 DBUS_TYPE_INT32, &signo,
1900 DBUS_TYPE_INVALID))
1901 return bus_send_error_reply(connection, message, &error, -EINVAL);
1902
1903 if (signo <= 0 || signo >= _NSIG)
1904 return bus_send_error_reply(connection, message, &error, -EINVAL);
1905
1906 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1907 if (!user)
1908 return bus_send_error_reply(connection, message, &error, -ENOENT);
1909
1910 r = user_kill(user, signo);
1911 if (r < 0)
1912 return bus_send_error_reply(connection, message, NULL, r);
1913
1914 reply = dbus_message_new_method_return(message);
1915 if (!reply)
1916 goto oom;
1917
1918 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1919 const char *name;
1920 Session *session;
1921
1922 if (!dbus_message_get_args(
1923 message,
1924 &error,
1925 DBUS_TYPE_STRING, &name,
1926 DBUS_TYPE_INVALID))
1927 return bus_send_error_reply(connection, message, &error, -EINVAL);
1928
1929 session = hashmap_get(m->sessions, name);
1930 if (!session)
1931 return bus_send_error_reply(connection, message, &error, -ENOENT);
1932
1933 r = session_stop(session);
1934 if (r < 0)
1935 return bus_send_error_reply(connection, message, NULL, r);
1936
1937 reply = dbus_message_new_method_return(message);
1938 if (!reply)
1939 goto oom;
1940
1941 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1942 uint32_t uid;
1943 User *user;
1944
1945 if (!dbus_message_get_args(
1946 message,
1947 &error,
1948 DBUS_TYPE_UINT32, &uid,
1949 DBUS_TYPE_INVALID))
1950 return bus_send_error_reply(connection, message, &error, -EINVAL);
1951
1952 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1953 if (!user)
1954 return bus_send_error_reply(connection, message, &error, -ENOENT);
1955
1956 r = user_stop(user);
1957 if (r < 0)
1958 return bus_send_error_reply(connection, message, NULL, r);
1959
1960 reply = dbus_message_new_method_return(message);
1961 if (!reply)
1962 goto oom;
1963
1964 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1965 const char *name;
1966 Seat *seat;
1967
1968 if (!dbus_message_get_args(
1969 message,
1970 &error,
1971 DBUS_TYPE_STRING, &name,
1972 DBUS_TYPE_INVALID))
1973 return bus_send_error_reply(connection, message, &error, -EINVAL);
1974
1975 seat = hashmap_get(m->seats, name);
1976 if (!seat)
1977 return bus_send_error_reply(connection, message, &error, -ENOENT);
1978
1979 r = seat_stop_sessions(seat);
1980 if (r < 0)
1981 return bus_send_error_reply(connection, message, NULL, r);
1982
1983 reply = dbus_message_new_method_return(message);
1984 if (!reply)
1985 goto oom;
1986
1987 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
1988 uint32_t uid;
1989 struct passwd *pw;
1990 dbus_bool_t b, interactive;
1991 char *path;
1992
1993 if (!dbus_message_get_args(
1994 message,
1995 &error,
1996 DBUS_TYPE_UINT32, &uid,
1997 DBUS_TYPE_BOOLEAN, &b,
1998 DBUS_TYPE_BOOLEAN, &interactive,
1999 DBUS_TYPE_INVALID))
2000 return bus_send_error_reply(connection, message, &error, -EINVAL);
2001
2002 errno = 0;
2003 pw = getpwuid(uid);
2004 if (!pw)
2005 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
2006
2007 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
2008 if (r < 0)
2009 return bus_send_error_reply(connection, message, &error, r);
2010
2011 mkdir_p_label("/var/lib/systemd", 0755);
2012
2013 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
2014 if (r < 0)
2015 return bus_send_error_reply(connection, message, &error, r);
2016
2017 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
2018 if (!path)
2019 goto oom;
2020
2021 if (b) {
2022 User *u;
2023
2024 r = touch(path);
2025 free(path);
2026
2027 if (r < 0)
2028 return bus_send_error_reply(connection, message, &error, r);
2029
2030 if (manager_add_user_by_uid(m, uid, &u) >= 0)
2031 user_start(u);
2032
2033 } else {
2034 User *u;
2035
2036 r = unlink(path);
2037 free(path);
2038
2039 if (r < 0 && errno != ENOENT)
2040 return bus_send_error_reply(connection, message, &error, -errno);
2041
2042 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
2043 if (u)
2044 user_add_to_gc_queue(u);
2045 }
2046
2047 reply = dbus_message_new_method_return(message);
2048 if (!reply)
2049 goto oom;
2050
2051 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
2052 const char *sysfs, *seat;
2053 dbus_bool_t interactive;
2054
2055 if (!dbus_message_get_args(
2056 message,
2057 &error,
2058 DBUS_TYPE_STRING, &seat,
2059 DBUS_TYPE_STRING, &sysfs,
2060 DBUS_TYPE_BOOLEAN, &interactive,
2061 DBUS_TYPE_INVALID))
2062 return bus_send_error_reply(connection, message, &error, -EINVAL);
2063
2064 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
2065 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2066
2067 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
2068 if (r < 0)
2069 return bus_send_error_reply(connection, message, &error, r);
2070
2071 r = attach_device(m, seat, sysfs);
2072 if (r < 0)
2073 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2074
2075 reply = dbus_message_new_method_return(message);
2076 if (!reply)
2077 goto oom;
2078
2079
2080 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
2081 dbus_bool_t interactive;
2082
2083 if (!dbus_message_get_args(
2084 message,
2085 &error,
2086 DBUS_TYPE_BOOLEAN, &interactive,
2087 DBUS_TYPE_INVALID))
2088 return bus_send_error_reply(connection, message, &error, -EINVAL);
2089
2090 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
2091 if (r < 0)
2092 return bus_send_error_reply(connection, message, &error, r);
2093
2094 r = flush_devices(m);
2095 if (r < 0)
2096 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2097
2098 reply = dbus_message_new_method_return(message);
2099 if (!reply)
2100 goto oom;
2101
2102 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
2103
2104 r = bus_manager_do_shutdown_or_sleep(
2105 m, connection, message,
2106 SPECIAL_POWEROFF_TARGET,
2107 INHIBIT_SHUTDOWN,
2108 "org.freedesktop.login1.power-off",
2109 "org.freedesktop.login1.power-off-multiple-sessions",
2110 "org.freedesktop.login1.power-off-ignore-inhibit",
2111 NULL,
2112 &error, &reply);
2113 if (r < 0)
2114 return bus_send_error_reply(connection, message, &error, r);
2115 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
2116 r = bus_manager_do_shutdown_or_sleep(
2117 m, connection, message,
2118 SPECIAL_REBOOT_TARGET,
2119 INHIBIT_SHUTDOWN,
2120 "org.freedesktop.login1.reboot",
2121 "org.freedesktop.login1.reboot-multiple-sessions",
2122 "org.freedesktop.login1.reboot-ignore-inhibit",
2123 NULL,
2124 &error, &reply);
2125 if (r < 0)
2126 return bus_send_error_reply(connection, message, &error, r);
2127
2128 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2129 r = bus_manager_do_shutdown_or_sleep(
2130 m, connection, message,
2131 SPECIAL_SUSPEND_TARGET,
2132 INHIBIT_SLEEP,
2133 "org.freedesktop.login1.suspend",
2134 "org.freedesktop.login1.suspend-multiple-sessions",
2135 "org.freedesktop.login1.suspend-ignore-inhibit",
2136 "suspend",
2137 &error, &reply);
2138 if (r < 0)
2139 return bus_send_error_reply(connection, message, &error, r);
2140 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2141 r = bus_manager_do_shutdown_or_sleep(
2142 m, connection, message,
2143 SPECIAL_HIBERNATE_TARGET,
2144 INHIBIT_SLEEP,
2145 "org.freedesktop.login1.hibernate",
2146 "org.freedesktop.login1.hibernate-multiple-sessions",
2147 "org.freedesktop.login1.hibernate-ignore-inhibit",
2148 "hibernate",
2149 &error, &reply);
2150 if (r < 0)
2151 return bus_send_error_reply(connection, message, &error, r);
2152
2153 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "HybridSleep")) {
2154 r = bus_manager_do_shutdown_or_sleep(
2155 m, connection, message,
2156 SPECIAL_HYBRID_SLEEP_TARGET,
2157 INHIBIT_SLEEP,
2158 "org.freedesktop.login1.hibernate",
2159 "org.freedesktop.login1.hibernate-multiple-sessions",
2160 "org.freedesktop.login1.hibernate-ignore-inhibit",
2161 "hybrid-sleep",
2162 &error, &reply);
2163 if (r < 0)
2164 return bus_send_error_reply(connection, message, &error, r);
2165
2166 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2167
2168 r = bus_manager_can_shutdown_or_sleep(
2169 m, connection, message,
2170 INHIBIT_SHUTDOWN,
2171 "org.freedesktop.login1.power-off",
2172 "org.freedesktop.login1.power-off-multiple-sessions",
2173 "org.freedesktop.login1.power-off-ignore-inhibit",
2174 NULL,
2175 &error, &reply);
2176 if (r < 0)
2177 return bus_send_error_reply(connection, message, &error, r);
2178 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2179 r = bus_manager_can_shutdown_or_sleep(
2180 m, connection, message,
2181 INHIBIT_SHUTDOWN,
2182 "org.freedesktop.login1.reboot",
2183 "org.freedesktop.login1.reboot-multiple-sessions",
2184 "org.freedesktop.login1.reboot-ignore-inhibit",
2185 NULL,
2186 &error, &reply);
2187 if (r < 0)
2188 return bus_send_error_reply(connection, message, &error, r);
2189
2190 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2191 r = bus_manager_can_shutdown_or_sleep(
2192 m, connection, message,
2193 INHIBIT_SLEEP,
2194 "org.freedesktop.login1.suspend",
2195 "org.freedesktop.login1.suspend-multiple-sessions",
2196 "org.freedesktop.login1.suspend-ignore-inhibit",
2197 "suspend",
2198 &error, &reply);
2199 if (r < 0)
2200 return bus_send_error_reply(connection, message, &error, r);
2201
2202 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2203 r = bus_manager_can_shutdown_or_sleep(
2204 m, connection, message,
2205 INHIBIT_SLEEP,
2206 "org.freedesktop.login1.hibernate",
2207 "org.freedesktop.login1.hibernate-multiple-sessions",
2208 "org.freedesktop.login1.hibernate-ignore-inhibit",
2209 "hibernate",
2210 &error, &reply);
2211 if (r < 0)
2212 return bus_send_error_reply(connection, message, &error, r);
2213
2214 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHybridSleep")) {
2215 r = bus_manager_can_shutdown_or_sleep(
2216 m, connection, message,
2217 INHIBIT_SLEEP,
2218 "org.freedesktop.login1.hibernate",
2219 "org.freedesktop.login1.hibernate-multiple-sessions",
2220 "org.freedesktop.login1.hibernate-ignore-inhibit",
2221 "hybrid-sleep",
2222 &error, &reply);
2223 if (r < 0)
2224 return bus_send_error_reply(connection, message, &error, r);
2225
2226 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2227 char *introspection = NULL;
2228 FILE *f;
2229 Iterator i;
2230 Session *session;
2231 Seat *seat;
2232 User *user;
2233 size_t size;
2234 char *p;
2235
2236 if (!(reply = dbus_message_new_method_return(message)))
2237 goto oom;
2238
2239 /* We roll our own introspection code here, instead of
2240 * relying on bus_default_message_handler() because we
2241 * need to generate our introspection string
2242 * dynamically. */
2243
2244 if (!(f = open_memstream(&introspection, &size)))
2245 goto oom;
2246
2247 fputs(INTROSPECTION_BEGIN, f);
2248
2249 HASHMAP_FOREACH(seat, m->seats, i) {
2250 p = bus_path_escape(seat->id);
2251
2252 if (p) {
2253 fprintf(f, "<node name=\"seat/%s\"/>", p);
2254 free(p);
2255 }
2256 }
2257
2258 HASHMAP_FOREACH(user, m->users, i)
2259 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2260
2261 HASHMAP_FOREACH(session, m->sessions, i) {
2262 p = bus_path_escape(session->id);
2263
2264 if (p) {
2265 fprintf(f, "<node name=\"session/%s\"/>", p);
2266 free(p);
2267 }
2268 }
2269
2270 fputs(INTROSPECTION_END, f);
2271
2272 if (ferror(f)) {
2273 fclose(f);
2274 free(introspection);
2275 goto oom;
2276 }
2277
2278 fclose(f);
2279
2280 if (!introspection)
2281 goto oom;
2282
2283 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2284 free(introspection);
2285 goto oom;
2286 }
2287
2288 free(introspection);
2289 } else {
2290 const BusBoundProperties bps[] = {
2291 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2292 { NULL, }
2293 };
2294 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2295 }
2296
2297 if (reply) {
2298 if (!bus_maybe_send_reply(connection, message, reply))
2299 goto oom;
2300 }
2301
2302 return DBUS_HANDLER_RESULT_HANDLED;
2303
2304oom:
2305 dbus_error_free(&error);
2306
2307 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2308}
2309
2310const DBusObjectPathVTable bus_manager_vtable = {
2311 .message_function = manager_message_handler
2312};
2313
2314DBusHandlerResult bus_message_filter(
2315 DBusConnection *connection,
2316 DBusMessage *message,
2317 void *userdata) {
2318
2319 Manager *m = userdata;
2320 DBusError error;
2321
2322 assert(m);
2323 assert(connection);
2324 assert(message);
2325
2326 dbus_error_init(&error);
2327
2328 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)));
2329
2330 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
2331 const char *path, *result, *unit;
2332 uint32_t id;
2333
2334 if (!dbus_message_get_args(message, &error,
2335 DBUS_TYPE_UINT32, &id,
2336 DBUS_TYPE_OBJECT_PATH, &path,
2337 DBUS_TYPE_STRING, &unit,
2338 DBUS_TYPE_STRING, &result,
2339 DBUS_TYPE_INVALID)) {
2340 log_error("Failed to parse JobRemoved message: %s", bus_error_message(&error));
2341 goto finish;
2342 }
2343
2344 if (m->action_job && streq(m->action_job, path)) {
2345 log_info("Operation finished.");
2346
2347 /* Tell people that they now may take a lock again */
2348 send_prepare_for(m, m->action_what, false);
2349
2350 free(m->action_job);
2351 m->action_job = NULL;
2352 m->action_unit = NULL;
2353 m->action_what = 0;
2354
2355 } else {
2356 Session *s;
2357 User *u;
2358
2359 s = hashmap_get(m->session_units, unit);
2360 if (s) {
2361 if (streq_ptr(path, s->scope_job)) {
2362 free(s->scope_job);
2363 s->scope_job = NULL;
2364
2365 if (s->started) {
2366 if (streq(result, "done"))
2367 session_send_create_reply(s, NULL);
2368 else {
2369 dbus_set_error(&error, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
2370 session_send_create_reply(s, &error);
2371 }
2372 } else
2373 session_save(s);
2374 }
2375
2376 session_add_to_gc_queue(s);
2377 }
2378
2379 u = hashmap_get(m->user_units, unit);
2380 if (u) {
2381 if (streq_ptr(path, u->service_job)) {
2382 free(u->service_job);
2383 u->service_job = NULL;
2384 }
2385
2386 if (streq_ptr(path, u->slice_job)) {
2387 free(u->slice_job);
2388 u->slice_job = NULL;
2389 }
2390
2391 user_save(u);
2392 user_add_to_gc_queue(u);
2393 }
2394 }
2395
2396 } else if (dbus_message_is_signal(message, "org.freedesktop.DBus.Properties", "PropertiesChanged")) {
2397
2398 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2399 _cleanup_free_ char *unit = NULL;
2400 const char *path;
2401
2402 path = dbus_message_get_path(message);
2403 if (!path)
2404 goto finish;
2405
2406 unit_name_from_dbus_path(path, &unit);
2407 if (unit) {
2408 Session *s;
2409 User *u;
2410
2411 s = hashmap_get(m->session_units, unit);
2412 if (s)
2413 session_add_to_gc_queue(s);
2414
2415 u = hashmap_get(m->user_units, unit);
2416 if (u)
2417 user_add_to_gc_queue(u);
2418 }
2419
2420 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "UnitRemoved")) {
2421
2422 const char *path, *unit;
2423 Session *session;
2424 User *user;
2425
2426 if (!dbus_message_get_args(message, &error,
2427 DBUS_TYPE_STRING, &unit,
2428 DBUS_TYPE_OBJECT_PATH, &path,
2429 DBUS_TYPE_INVALID)) {
2430 log_error("Failed to parse UnitRemoved message: %s", bus_error_message(&error));
2431 goto finish;
2432 }
2433
2434 session = hashmap_get(m->session_units, unit);
2435 if (session)
2436 session_add_to_gc_queue(session);
2437
2438 user = hashmap_get(m->user_units, unit);
2439 if (user)
2440 user_add_to_gc_queue(user);
2441
2442 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "Reloading")) {
2443 dbus_bool_t b;
2444
2445 if (!dbus_message_get_args(message, &error,
2446 DBUS_TYPE_BOOLEAN, &b,
2447 DBUS_TYPE_INVALID)) {
2448 log_error("Failed to parse Reloading message: %s", bus_error_message(&error));
2449 goto finish;
2450 }
2451
2452 /* systemd finished reloading, let's recheck all our sessions */
2453 if (!b) {
2454 Session *session;
2455 Iterator i;
2456
2457 log_debug("System manager has been reloaded, rechecking sessions...");
2458
2459 HASHMAP_FOREACH(session, m->sessions, i)
2460 session_add_to_gc_queue(session);
2461 }
2462
2463 } else if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) {
2464 const char *name, *old, *new;
2465 char *key;
2466
2467 if (!dbus_message_get_args(message, &error,
2468 DBUS_TYPE_STRING, &name,
2469 DBUS_TYPE_STRING, &old,
2470 DBUS_TYPE_STRING, &new,
2471 DBUS_TYPE_INVALID)) {
2472 log_error("Failed to parse NameOwnerChanged message: %s", bus_error_message(&error));
2473 goto finish;
2474 }
2475
2476 if (*old && !*new && (key = hashmap_remove(m->busnames, old))) {
2477 free(key);
2478 }
2479 }
2480
2481finish:
2482 dbus_error_free(&error);
2483
2484 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2485}
2486
2487int manager_send_changed(Manager *manager, const char *properties) {
2488 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
2489
2490 assert(manager);
2491
2492 m = bus_properties_changed_new("/org/freedesktop/login1",
2493 "org.freedesktop.login1.Manager",
2494 properties);
2495 if (!m)
2496 return -ENOMEM;
2497
2498 if (!dbus_connection_send(manager->bus, m, NULL))
2499 return -ENOMEM;
2500
2501 return 0;
2502}
2503
2504int manager_dispatch_delayed(Manager *manager) {
2505 DBusError error;
2506 int r;
2507
2508 assert(manager);
2509
2510 if (manager->action_what == 0 || manager->action_job)
2511 return 0;
2512
2513 /* Continue delay? */
2514 if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0)) {
2515
2516 if (manager->action_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC))
2517 return 0;
2518
2519 log_info("Delay lock is active but inhibitor timeout is reached.");
2520 }
2521
2522 /* Actually do the operation */
2523 dbus_error_init(&error);
2524 r = execute_shutdown_or_sleep(manager, manager->action_what, manager->action_unit, &error);
2525 if (r < 0) {
2526 log_warning("Failed to send delayed message: %s", bus_error(&error, r));
2527 dbus_error_free(&error);
2528
2529 manager->action_unit = NULL;
2530 manager->action_what = 0;
2531 return r;
2532 }
2533
2534 return 1;
2535}
2536
2537int manager_start_scope(
2538 Manager *manager,
2539 const char *scope,
2540 pid_t pid,
2541 const char *slice,
2542 const char *description,
2543 const char *after,
2544 const char *kill_mode,
2545 DBusError *error,
2546 char **job) {
2547
2548 const char *timeout_stop_property = "TimeoutStopUSec", *send_sighup_property = "SendSIGHUP", *pids_property = "PIDs";
2549 _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
2550 DBusMessageIter iter, sub, sub2, sub3, sub4;
2551 uint64_t timeout = 500 * USEC_PER_MSEC;
2552 dbus_bool_t send_sighup = true;
2553 const char *fail = "fail";
2554 uint32_t u;
2555
2556 assert(manager);
2557 assert(scope);
2558 assert(pid > 1);
2559
2560 if (!slice)
2561 slice = "";
2562
2563 m = dbus_message_new_method_call(
2564 "org.freedesktop.systemd1",
2565 "/org/freedesktop/systemd1",
2566 "org.freedesktop.systemd1.Manager",
2567 "StartTransientUnit");
2568 if (!m)
2569 return log_oom();
2570
2571 dbus_message_iter_init_append(m, &iter);
2572
2573 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &scope) ||
2574 !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &fail) ||
2575 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sv)", &sub))
2576 return log_oom();
2577
2578 if (!isempty(slice)) {
2579 const char *slice_property = "Slice";
2580
2581 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2582 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &slice_property) ||
2583 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "s", &sub3) ||
2584 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &slice) ||
2585 !dbus_message_iter_close_container(&sub2, &sub3) ||
2586 !dbus_message_iter_close_container(&sub, &sub2))
2587 return log_oom();
2588 }
2589
2590 if (!isempty(description)) {
2591 const char *description_property = "Description";
2592
2593 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2594 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description_property) ||
2595 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "s", &sub3) ||
2596 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &description) ||
2597 !dbus_message_iter_close_container(&sub2, &sub3) ||
2598 !dbus_message_iter_close_container(&sub, &sub2))
2599 return log_oom();
2600 }
2601
2602 if (!isempty(after)) {
2603 const char *after_property = "After";
2604
2605 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2606 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &after_property) ||
2607 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "as", &sub3) ||
2608 !dbus_message_iter_open_container(&sub3, DBUS_TYPE_ARRAY, "s", &sub4) ||
2609 !dbus_message_iter_append_basic(&sub4, DBUS_TYPE_STRING, &after) ||
2610 !dbus_message_iter_close_container(&sub3, &sub4) ||
2611 !dbus_message_iter_close_container(&sub2, &sub3) ||
2612 !dbus_message_iter_close_container(&sub, &sub2))
2613 return log_oom();
2614 }
2615
2616 if (!isempty(kill_mode)) {
2617 const char *kill_mode_property = "KillMode";
2618
2619 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2620 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &kill_mode_property) ||
2621 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "s", &sub3) ||
2622 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &kill_mode) ||
2623 !dbus_message_iter_close_container(&sub2, &sub3) ||
2624 !dbus_message_iter_close_container(&sub, &sub2))
2625 return log_oom();
2626 }
2627
2628 /* cgroup empty notification is not available in containers
2629 * currently. To make this less problematic, let's shorten the
2630 * stop timeout for sessions, so that we don't wait
2631 * forever. */
2632
2633 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2634 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &timeout_stop_property) ||
2635 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "t", &sub3) ||
2636 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_UINT64, &timeout) ||
2637 !dbus_message_iter_close_container(&sub2, &sub3) ||
2638 !dbus_message_iter_close_container(&sub, &sub2))
2639 return log_oom();
2640
2641 /* Make sure that the session shells are terminated with
2642 * SIGHUP since bash and friends tend to ignore SIGTERM */
2643 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2644 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &send_sighup_property) ||
2645 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "b", &sub3) ||
2646 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_BOOLEAN, &send_sighup) ||
2647 !dbus_message_iter_close_container(&sub2, &sub3) ||
2648 !dbus_message_iter_close_container(&sub, &sub2))
2649 return log_oom();
2650
2651 u = pid;
2652 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2653 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &pids_property) ||
2654 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "au", &sub3) ||
2655 !dbus_message_iter_open_container(&sub3, DBUS_TYPE_ARRAY, "u", &sub4) ||
2656 !dbus_message_iter_append_basic(&sub4, DBUS_TYPE_UINT32, &u) ||
2657 !dbus_message_iter_close_container(&sub3, &sub4) ||
2658 !dbus_message_iter_close_container(&sub2, &sub3) ||
2659 !dbus_message_iter_close_container(&sub, &sub2))
2660 return log_oom();
2661
2662 if (!dbus_message_iter_close_container(&iter, &sub))
2663 return log_oom();
2664
2665 reply = dbus_connection_send_with_reply_and_block(manager->bus, m, -1, error);
2666 if (!reply)
2667 return -EIO;
2668
2669 if (job) {
2670 const char *j;
2671 char *copy;
2672
2673 if (!dbus_message_get_args(reply, error, DBUS_TYPE_OBJECT_PATH, &j, DBUS_TYPE_INVALID))
2674 return -EIO;
2675
2676 copy = strdup(j);
2677 if (!copy)
2678 return -ENOMEM;
2679
2680 *job = copy;
2681 }
2682
2683 return 0;
2684}
2685
2686int manager_start_unit(Manager *manager, const char *unit, DBusError *error, char **job) {
2687 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2688 const char *fail = "fail";
2689 int r;
2690
2691 assert(manager);
2692 assert(unit);
2693
2694 r = bus_method_call_with_reply(
2695 manager->bus,
2696 "org.freedesktop.systemd1",
2697 "/org/freedesktop/systemd1",
2698 "org.freedesktop.systemd1.Manager",
2699 "StartUnit",
2700 &reply,
2701 error,
2702 DBUS_TYPE_STRING, &unit,
2703 DBUS_TYPE_STRING, &fail,
2704 DBUS_TYPE_INVALID);
2705 if (r < 0) {
2706 log_error("Failed to start unit %s: %s", unit, bus_error(error, r));
2707 return r;
2708 }
2709
2710 if (job) {
2711 const char *j;
2712 char *copy;
2713
2714 if (!dbus_message_get_args(reply, error,
2715 DBUS_TYPE_OBJECT_PATH, &j,
2716 DBUS_TYPE_INVALID)) {
2717 log_error("Failed to parse reply.");
2718 return -EIO;
2719 }
2720
2721 copy = strdup(j);
2722 if (!copy)
2723 return -ENOMEM;
2724
2725 *job = copy;
2726 }
2727
2728 return 0;
2729}
2730
2731int manager_stop_unit(Manager *manager, const char *unit, DBusError *error, char **job) {
2732 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2733 const char *fail = "fail";
2734 int r;
2735
2736 assert(manager);
2737 assert(unit);
2738
2739 r = bus_method_call_with_reply(
2740 manager->bus,
2741 "org.freedesktop.systemd1",
2742 "/org/freedesktop/systemd1",
2743 "org.freedesktop.systemd1.Manager",
2744 "StopUnit",
2745 &reply,
2746 error,
2747 DBUS_TYPE_STRING, &unit,
2748 DBUS_TYPE_STRING, &fail,
2749 DBUS_TYPE_INVALID);
2750 if (r < 0) {
2751 if (dbus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
2752 dbus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
2753
2754 if (job)
2755 *job = NULL;
2756
2757 dbus_error_free(error);
2758 return 0;
2759 }
2760
2761 log_error("Failed to stop unit %s: %s", unit, bus_error(error, r));
2762 return r;
2763 }
2764
2765 if (job) {
2766 const char *j;
2767 char *copy;
2768
2769 if (!dbus_message_get_args(reply, error,
2770 DBUS_TYPE_OBJECT_PATH, &j,
2771 DBUS_TYPE_INVALID)) {
2772 log_error("Failed to parse reply.");
2773 return -EIO;
2774 }
2775
2776 copy = strdup(j);
2777 if (!copy)
2778 return -ENOMEM;
2779
2780 *job = copy;
2781 }
2782
2783 return 1;
2784}
2785
2786int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, DBusError *error) {
2787 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2788 const char *w;
2789 int r;
2790
2791 assert(manager);
2792 assert(unit);
2793
2794 w = who == KILL_LEADER ? "process" : "cgroup";
2795 assert_cc(sizeof(signo) == sizeof(int32_t));
2796
2797 r = bus_method_call_with_reply(
2798 manager->bus,
2799 "org.freedesktop.systemd1",
2800 "/org/freedesktop/systemd1",
2801 "org.freedesktop.systemd1.Manager",
2802 "KillUnit",
2803 &reply,
2804 error,
2805 DBUS_TYPE_STRING, &unit,
2806 DBUS_TYPE_STRING, &w,
2807 DBUS_TYPE_INT32, &signo,
2808 DBUS_TYPE_INVALID);
2809 if (r < 0) {
2810 log_error("Failed to stop unit %s: %s", unit, bus_error(error, r));
2811 return r;
2812 }
2813
2814 return 0;
2815}
2816
2817int manager_unit_is_active(Manager *manager, const char *unit) {
2818
2819 const char *interface = "org.freedesktop.systemd1.Unit";
2820 const char *property = "ActiveState";
2821 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2822 _cleanup_free_ char *path = NULL;
2823 DBusMessageIter iter, sub;
2824 const char *state;
2825 DBusError error;
2826 int r;
2827
2828 assert(manager);
2829 assert(unit);
2830
2831 dbus_error_init(&error);
2832
2833 path = unit_dbus_path_from_name(unit);
2834 if (!path)
2835 return -ENOMEM;
2836
2837 r = bus_method_call_with_reply(
2838 manager->bus,
2839 "org.freedesktop.systemd1",
2840 path,
2841 "org.freedesktop.DBus.Properties",
2842 "Get",
2843 &reply,
2844 &error,
2845 DBUS_TYPE_STRING, &interface,
2846 DBUS_TYPE_STRING, &property,
2847 DBUS_TYPE_INVALID);
2848 if (r < 0) {
2849 if (dbus_error_has_name(&error, DBUS_ERROR_NO_REPLY) ||
2850 dbus_error_has_name(&error, DBUS_ERROR_DISCONNECTED)) {
2851 /* systemd might have droppped off
2852 * momentarily, let's not make this an
2853 * error */
2854
2855 dbus_error_free(&error);
2856 return true;
2857 }
2858
2859 if (dbus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
2860 dbus_error_has_name(&error, BUS_ERROR_LOAD_FAILED)) {
2861 /* If the unit is already unloaded then it's
2862 * not active */
2863
2864 dbus_error_free(&error);
2865 return false;
2866 }
2867
2868 log_error("Failed to query ActiveState: %s", bus_error(&error, r));
2869 dbus_error_free(&error);
2870 return r;
2871 }
2872
2873 if (!dbus_message_iter_init(reply, &iter) ||
2874 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
2875 log_error("Failed to parse reply.");
2876 return -EINVAL;
2877 }
2878
2879 dbus_message_iter_recurse(&iter, &sub);
2880 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
2881 log_error("Failed to parse reply.");
2882 return -EINVAL;
2883 }
2884
2885 dbus_message_iter_get_basic(&sub, &state);
2886
2887 return !streq(state, "inactive") && !streq(state, "failed");
2888}