]> git.proxmox.com Git - systemd.git/blame - src/login/logind-dbus.c
Imported Upstream version 208
[systemd.git] / src / login / logind-dbus.c
CommitLineData
663996b3
MS
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"
14228c0d
MB
39#include "utf8.h"
40#include "unit-name.h"
41#include "bus-errors.h"
42#include "virt.h"
663996b3
MS
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" \
14228c0d
MB
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" \
663996b3
MS
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" \
14228c0d 88 " <arg name=\"scope_properties\" type=\"a(sv)\" direction=\"in\"/>\n" \
663996b3
MS
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" \
663996b3
MS
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
14228c0d
MB
314static int bus_manager_create_session(Manager *m, DBusMessage *message) {
315
663996b3
MS
316 const char *type, *class, *cseat, *tty, *display, *remote_user, *remote_host, *service;
317 uint32_t uid, leader, audit_id = 0;
14228c0d 318 _cleanup_free_ char *id = NULL;
663996b3
MS
319 Session *session = NULL;
320 User *user = NULL;
321 Seat *seat = NULL;
14228c0d
MB
322 DBusMessageIter iter;
323 dbus_bool_t remote;
324 uint32_t vtnr = 0;
325 SessionType t;
326 SessionClass c;
663996b3 327 bool b;
14228c0d 328 int r;
663996b3
MS
329
330 assert(m);
331 assert(message);
663996b3
MS
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
14228c0d 345 if (!dbus_message_iter_next(&iter) ||
663996b3
MS
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)
14228c0d
MB
407 seat = m->seat0;
408 else if (seat != m->seat0)
663996b3
MS
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)
14228c0d
MB
423 seat = m->seat0;
424 else if (seat != m->seat0)
663996b3
MS
425 return -EINVAL;
426
427 if (vtnr != 0)
428 return -EINVAL;
429 }
430
431 if (seat) {
14228c0d 432 if (seat_has_vts(seat)) {
663996b3
MS
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
14228c0d
MB
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;
663996b3
MS
485 }
486
14228c0d
MB
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;
663996b3 493
14228c0d
MB
494 /* Session already exists, client is probably
495 * something like "su" which changes uid but is still
496 * the same session */
663996b3 497
663996b3
MS
498 fifo_fd = session_create_fifo(session);
499 if (fifo_fd < 0) {
500 r = fifo_fd;
501 goto fail;
502 }
503
14228c0d
MB
504 path = session_bus_path(session);
505 if (!path) {
663996b3
MS
506 r = -ENOMEM;
507 goto fail;
508 }
509
14228c0d
MB
510 reply = dbus_message_new_method_return(message);
511 if (!reply) {
663996b3
MS
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,
14228c0d 523 DBUS_TYPE_OBJECT_PATH, &path,
663996b3
MS
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
14228c0d
MB
535 if (!dbus_connection_send(m->bus, reply, NULL)) {
536 r = -ENOMEM;
537 goto fail;
538 }
663996b3
MS
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)) {
14228c0d 557 log_warning("Existing logind session ID %s used by new audit session, ignoring", id);
663996b3
MS
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
14228c0d 582 r = manager_add_session(m, id, &session);
663996b3
MS
583 if (r < 0)
584 goto fail;
585
14228c0d
MB
586 session_set_user(session, user);
587
663996b3
MS
588 session->leader = leader;
589 session->audit_id = audit_id;
590 session->type = t;
591 session->class = c;
592 session->remote = remote;
663996b3
MS
593 session->vtnr = vtnr;
594
663996b3
MS
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
663996b3
MS
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
14228c0d 645 session->create_message = dbus_message_ref(message);
663996b3 646
14228c0d
MB
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().*/
663996b3
MS
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 &&
14228c0d 960 !session->closing &&
663996b3
MS
961 session->user->uid != uid)
962 return true;
963
964 return false;
965}
966
967static int bus_manager_log_shutdown(
968 Manager *m,
969 InhibitWhat w,
970 const char *unit_name) {
971
972 const char *p, *q;
973
974 assert(m);
975 assert(unit_name);
976
977 if (w != INHIBIT_SHUTDOWN)
978 return 0;
979
980 if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
981 p = "MESSAGE=System is powering down.";
982 q = "SHUTDOWN=power-off";
983 } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
984 p = "MESSAGE=System is halting.";
985 q = "SHUTDOWN=halt";
986 } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
987 p = "MESSAGE=System is rebooting.";
988 q = "SHUTDOWN=reboot";
989 } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
990 p = "MESSAGE=System is rebooting with kexec.";
991 q = "SHUTDOWN=kexec";
992 } else {
993 p = "MESSAGE=System is shutting down.";
994 q = NULL;
995 }
996
997 return log_struct(LOG_NOTICE, MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
998 p,
999 q, NULL);
1000}
1001
1002static int execute_shutdown_or_sleep(
1003 Manager *m,
1004 InhibitWhat w,
1005 const char *unit_name,
1006 DBusError *error) {
1007
1008 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1009 const char *mode = "replace-irreversibly", *p;
1010 int r;
1011 char *c;
1012
1013 assert(m);
1014 assert(w >= 0);
1015 assert(w < _INHIBIT_WHAT_MAX);
1016 assert(unit_name);
1017
1018 bus_manager_log_shutdown(m, w, unit_name);
1019
1020 r = bus_method_call_with_reply(
1021 m->bus,
1022 "org.freedesktop.systemd1",
1023 "/org/freedesktop/systemd1",
1024 "org.freedesktop.systemd1.Manager",
1025 "StartUnit",
1026 &reply,
1027 error,
1028 DBUS_TYPE_STRING, &unit_name,
1029 DBUS_TYPE_STRING, &mode,
1030 DBUS_TYPE_INVALID);
1031 if (r < 0)
1032 return r;
1033
1034 if (!dbus_message_get_args(
1035 reply,
1036 error,
1037 DBUS_TYPE_OBJECT_PATH, &p,
1038 DBUS_TYPE_INVALID))
1039 return -EINVAL;
1040
1041 c = strdup(p);
1042 if (!c)
1043 return -ENOMEM;
1044
1045 m->action_unit = unit_name;
1046 free(m->action_job);
1047 m->action_job = c;
1048 m->action_what = w;
1049
1050 return 0;
1051}
1052
1053static int delay_shutdown_or_sleep(
1054 Manager *m,
1055 InhibitWhat w,
1056 const char *unit_name) {
1057
1058 assert(m);
1059 assert(w >= 0);
1060 assert(w < _INHIBIT_WHAT_MAX);
1061 assert(unit_name);
1062
1063 m->action_timestamp = now(CLOCK_MONOTONIC);
1064 m->action_unit = unit_name;
1065 m->action_what = w;
1066
1067 return 0;
1068}
1069
1070static int bus_manager_can_shutdown_or_sleep(
1071 Manager *m,
1072 DBusConnection *connection,
1073 DBusMessage *message,
1074 InhibitWhat w,
1075 const char *action,
1076 const char *action_multiple_sessions,
1077 const char *action_ignore_inhibit,
1078 const char *sleep_verb,
1079 DBusError *error,
1080 DBusMessage **_reply) {
1081
1082 bool multiple_sessions, challenge, blocked, b;
1083 const char *result = NULL;
1084 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1085 int r;
1086 unsigned long ul;
1087
1088 assert(m);
1089 assert(connection);
1090 assert(message);
1091 assert(w >= 0);
1092 assert(w <= _INHIBIT_WHAT_MAX);
1093 assert(action);
1094 assert(action_multiple_sessions);
1095 assert(action_ignore_inhibit);
1096 assert(error);
1097 assert(_reply);
1098
1099 if (sleep_verb) {
1100 r = can_sleep(sleep_verb);
1101 if (r < 0)
1102 return r;
1103 if (r == 0) {
1104 result = "na";
1105 goto finish;
1106 }
1107 }
1108
1109 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1110 if (ul == (unsigned long) -1)
1111 return -EIO;
1112
1113 r = have_multiple_sessions(m, (uid_t) ul);
1114 if (r < 0)
1115 return r;
1116
1117 multiple_sessions = r > 0;
1118 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1119
1120 if (multiple_sessions) {
1121 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1122 if (r < 0)
1123 return r;
1124
1125 if (r > 0)
1126 result = "yes";
1127 else if (challenge)
1128 result = "challenge";
1129 else
1130 result = "no";
1131 }
1132
1133 if (blocked) {
1134 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1135 if (r < 0)
1136 return r;
1137
1138 if (r > 0 && !result)
1139 result = "yes";
1140 else if (challenge && (!result || streq(result, "yes")))
1141 result = "challenge";
1142 else
1143 result = "no";
1144 }
1145
1146 if (!multiple_sessions && !blocked) {
1147 /* If neither inhibit nor multiple sessions
1148 * apply then just check the normal policy */
1149
1150 r = verify_polkit(connection, message, action, false, &challenge, error);
1151 if (r < 0)
1152 return r;
1153
1154 if (r > 0)
1155 result = "yes";
1156 else if (challenge)
1157 result = "challenge";
1158 else
1159 result = "no";
1160 }
1161
1162finish:
1163 reply = dbus_message_new_method_return(message);
1164 if (!reply)
1165 return -ENOMEM;
1166
1167 b = dbus_message_append_args(
1168 reply,
1169 DBUS_TYPE_STRING, &result,
1170 DBUS_TYPE_INVALID);
1171 if (!b)
1172 return -ENOMEM;
1173
1174 *_reply = reply;
1175 reply = NULL;
1176 return 0;
1177}
1178
1179static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
1180 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
1181 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
1182 [INHIBIT_SLEEP] = "PrepareForSleep"
1183 };
1184
1185 dbus_bool_t active = _active;
1186 _cleanup_dbus_message_unref_ DBusMessage *message = NULL;
1187
1188 assert(m);
1189 assert(w >= 0);
1190 assert(w < _INHIBIT_WHAT_MAX);
1191 assert(signal_name[w]);
1192
1193 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1194 if (!message)
1195 return -ENOMEM;
1196
1197 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1198 !dbus_connection_send(m->bus, message, NULL))
1199 return -ENOMEM;
1200
1201 return 0;
1202}
1203
1204int bus_manager_shutdown_or_sleep_now_or_later(
1205 Manager *m,
1206 const char *unit_name,
1207 InhibitWhat w,
1208 DBusError *error) {
1209
1210 bool delayed;
1211 int r;
1212
1213 assert(m);
1214 assert(unit_name);
1215 assert(w >= 0);
1216 assert(w <= _INHIBIT_WHAT_MAX);
1217 assert(!m->action_job);
1218
1219 /* Tell everybody to prepare for shutdown/sleep */
1220 send_prepare_for(m, w, true);
1221
1222 delayed =
1223 m->inhibit_delay_max > 0 &&
1224 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0);
1225
1226 if (delayed)
1227 /* Shutdown is delayed, keep in mind what we
1228 * want to do, and start a timeout */
1229 r = delay_shutdown_or_sleep(m, w, unit_name);
1230 else
1231 /* Shutdown is not delayed, execute it
1232 * immediately */
1233 r = execute_shutdown_or_sleep(m, w, unit_name, error);
1234
1235 return r;
1236}
1237
1238static int bus_manager_do_shutdown_or_sleep(
1239 Manager *m,
1240 DBusConnection *connection,
1241 DBusMessage *message,
1242 const char *unit_name,
1243 InhibitWhat w,
1244 const char *action,
1245 const char *action_multiple_sessions,
1246 const char *action_ignore_inhibit,
1247 const char *sleep_verb,
1248 DBusError *error,
1249 DBusMessage **_reply) {
1250
1251 dbus_bool_t interactive;
1252 bool multiple_sessions, blocked;
1253 DBusMessage *reply = NULL;
1254 int r;
1255 unsigned long ul;
1256
1257 assert(m);
1258 assert(connection);
1259 assert(message);
1260 assert(unit_name);
1261 assert(w >= 0);
1262 assert(w <= _INHIBIT_WHAT_MAX);
1263 assert(action);
1264 assert(action_multiple_sessions);
1265 assert(action_ignore_inhibit);
1266 assert(error);
1267 assert(_reply);
1268
1269 /* Don't allow multiple jobs being executed at the same time */
1270 if (m->action_what)
1271 return -EALREADY;
1272
1273 if (!dbus_message_get_args(
1274 message,
1275 error,
1276 DBUS_TYPE_BOOLEAN, &interactive,
1277 DBUS_TYPE_INVALID))
1278 return -EINVAL;
1279
1280 if (sleep_verb) {
1281 r = can_sleep(sleep_verb);
1282 if (r < 0)
1283 return r;
1284
1285 if (r == 0)
1286 return -ENOTSUP;
1287 }
1288
1289 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1290 if (ul == (unsigned long) -1)
1291 return -EIO;
1292
1293 r = have_multiple_sessions(m, (uid_t) ul);
1294 if (r < 0)
1295 return r;
1296
1297 multiple_sessions = r > 0;
1298 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1299
1300 if (multiple_sessions) {
1301 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1302 if (r < 0)
1303 return r;
1304 }
1305
1306 if (blocked) {
1307 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1308 if (r < 0)
1309 return r;
1310 }
1311
1312 if (!multiple_sessions && !blocked) {
1313 r = verify_polkit(connection, message, action, interactive, NULL, error);
1314 if (r < 0)
1315 return r;
1316 }
1317
1318 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
1319 if (r < 0)
1320 return r;
1321
1322 reply = dbus_message_new_method_return(message);
1323 if (!reply)
1324 return -ENOMEM;
1325
1326 *_reply = reply;
1327 return 0;
1328}
1329
1330static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_action, handle_action, HandleAction);
1331
1332static const BusProperty bus_login_manager_properties[] = {
663996b3
MS
1333 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1334 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1335 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1336 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1337 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1338 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1339 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
1340 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1341 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1342 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
1343 { "HandlePowerKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_power_key) },
1344 { "HandleSuspendKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_suspend_key) },
1345 { "HandleHibernateKey", bus_manager_append_handle_action, "s", offsetof(Manager, handle_hibernate_key)},
1346 { "HandleLidSwitch", bus_manager_append_handle_action, "s", offsetof(Manager, handle_lid_switch) },
1347 { "IdleAction", bus_manager_append_handle_action, "s", offsetof(Manager, idle_action) },
1348 { "IdleActionUSec", bus_property_append_usec, "t", offsetof(Manager, idle_action_usec) },
1349 { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
1350 { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
1351 { NULL, }
1352};
1353
1354static DBusHandlerResult manager_message_handler(
1355 DBusConnection *connection,
1356 DBusMessage *message,
1357 void *userdata) {
1358
1359 Manager *m = userdata;
1360
1361 DBusError error;
1362 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1363 int r;
1364
1365 assert(connection);
1366 assert(message);
1367 assert(m);
1368
1369 dbus_error_init(&error);
1370
1371 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1372 const char *name;
1373 char *p;
1374 Session *session;
1375 bool b;
1376
1377 if (!dbus_message_get_args(
1378 message,
1379 &error,
1380 DBUS_TYPE_STRING, &name,
1381 DBUS_TYPE_INVALID))
1382 return bus_send_error_reply(connection, message, &error, -EINVAL);
1383
1384 session = hashmap_get(m->sessions, name);
1385 if (!session)
1386 return bus_send_error_reply(connection, message, &error, -ENOENT);
1387
1388 reply = dbus_message_new_method_return(message);
1389 if (!reply)
1390 goto oom;
1391
1392 p = session_bus_path(session);
1393 if (!p)
1394 goto oom;
1395
1396 b = dbus_message_append_args(
1397 reply,
1398 DBUS_TYPE_OBJECT_PATH, &p,
1399 DBUS_TYPE_INVALID);
1400 free(p);
1401
1402 if (!b)
1403 goto oom;
1404
1405 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1406 uint32_t pid;
1407 char *p;
1408 Session *session;
1409 bool b;
1410
1411 if (!dbus_message_get_args(
1412 message,
1413 &error,
1414 DBUS_TYPE_UINT32, &pid,
1415 DBUS_TYPE_INVALID))
1416 return bus_send_error_reply(connection, message, &error, -EINVAL);
1417
1418 r = manager_get_session_by_pid(m, pid, &session);
1419 if (r <= 0)
1420 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1421
1422 reply = dbus_message_new_method_return(message);
1423 if (!reply)
1424 goto oom;
1425
1426 p = session_bus_path(session);
1427 if (!p)
1428 goto oom;
1429
1430 b = dbus_message_append_args(
1431 reply,
1432 DBUS_TYPE_OBJECT_PATH, &p,
1433 DBUS_TYPE_INVALID);
1434 free(p);
1435
1436 if (!b)
1437 goto oom;
1438
1439 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1440 uint32_t uid;
1441 char *p;
1442 User *user;
1443 bool b;
1444
1445 if (!dbus_message_get_args(
1446 message,
1447 &error,
1448 DBUS_TYPE_UINT32, &uid,
1449 DBUS_TYPE_INVALID))
1450 return bus_send_error_reply(connection, message, &error, -EINVAL);
1451
1452 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1453 if (!user)
1454 return bus_send_error_reply(connection, message, &error, -ENOENT);
1455
1456 reply = dbus_message_new_method_return(message);
1457 if (!reply)
1458 goto oom;
1459
1460 p = user_bus_path(user);
1461 if (!p)
1462 goto oom;
1463
1464 b = dbus_message_append_args(
1465 reply,
1466 DBUS_TYPE_OBJECT_PATH, &p,
1467 DBUS_TYPE_INVALID);
1468 free(p);
1469
1470 if (!b)
1471 goto oom;
1472
14228c0d
MB
1473 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUserByPID")) {
1474 uint32_t pid;
1475 char *p;
1476 User *user;
1477 bool b;
1478
1479 if (!dbus_message_get_args(
1480 message,
1481 &error,
1482 DBUS_TYPE_UINT32, &pid,
1483 DBUS_TYPE_INVALID))
1484 return bus_send_error_reply(connection, message, &error, -EINVAL);
1485
1486 r = manager_get_user_by_pid(m, pid, &user);
1487 if (r <= 0)
1488 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1489
1490 reply = dbus_message_new_method_return(message);
1491 if (!reply)
1492 goto oom;
1493
1494 p = user_bus_path(user);
1495 if (!p)
1496 goto oom;
1497
1498 b = dbus_message_append_args(
1499 reply,
1500 DBUS_TYPE_OBJECT_PATH, &p,
1501 DBUS_TYPE_INVALID);
1502 free(p);
1503
1504 if (!b)
1505 goto oom;
1506
663996b3
MS
1507 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1508 const char *name;
1509 char *p;
1510 Seat *seat;
1511 bool b;
1512
1513 if (!dbus_message_get_args(
1514 message,
1515 &error,
1516 DBUS_TYPE_STRING, &name,
1517 DBUS_TYPE_INVALID))
1518 return bus_send_error_reply(connection, message, &error, -EINVAL);
1519
1520 seat = hashmap_get(m->seats, name);
1521 if (!seat)
1522 return bus_send_error_reply(connection, message, &error, -ENOENT);
1523
1524 reply = dbus_message_new_method_return(message);
1525 if (!reply)
1526 goto oom;
1527
1528 p = seat_bus_path(seat);
1529 if (!p)
1530 goto oom;
1531
1532 b = dbus_message_append_args(
1533 reply,
1534 DBUS_TYPE_OBJECT_PATH, &p,
1535 DBUS_TYPE_INVALID);
1536 free(p);
1537
1538 if (!b)
1539 goto oom;
1540
1541 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1542 char *p;
1543 Session *session;
1544 Iterator i;
1545 DBusMessageIter iter, sub;
1546 const char *empty = "";
1547
1548 reply = dbus_message_new_method_return(message);
1549 if (!reply)
1550 goto oom;
1551
1552 dbus_message_iter_init_append(reply, &iter);
1553
1554 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1555 goto oom;
1556
1557 HASHMAP_FOREACH(session, m->sessions, i) {
1558 DBusMessageIter sub2;
1559 uint32_t uid;
1560
1561 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1562 goto oom;
1563
1564 uid = session->user->uid;
1565
1566 p = session_bus_path(session);
1567 if (!p)
1568 goto oom;
1569
1570 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1571 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1572 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1573 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1574 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1575 free(p);
1576 goto oom;
1577 }
1578
1579 free(p);
1580
1581 if (!dbus_message_iter_close_container(&sub, &sub2))
1582 goto oom;
1583 }
1584
1585 if (!dbus_message_iter_close_container(&iter, &sub))
1586 goto oom;
1587
1588 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
663996b3
MS
1589 User *user;
1590 Iterator i;
1591 DBusMessageIter iter, sub;
1592
1593 reply = dbus_message_new_method_return(message);
1594 if (!reply)
1595 goto oom;
1596
1597 dbus_message_iter_init_append(reply, &iter);
1598
1599 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1600 goto oom;
1601
1602 HASHMAP_FOREACH(user, m->users, i) {
14228c0d 1603 _cleanup_free_ char *p = NULL;
663996b3
MS
1604 DBusMessageIter sub2;
1605 uint32_t uid;
1606
1607 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1608 goto oom;
1609
1610 uid = user->uid;
1611
1612 p = user_bus_path(user);
1613 if (!p)
1614 goto oom;
1615
1616 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1617 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1618 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1619 free(p);
1620 goto oom;
1621 }
1622
663996b3
MS
1623 if (!dbus_message_iter_close_container(&sub, &sub2))
1624 goto oom;
1625 }
1626
1627 if (!dbus_message_iter_close_container(&iter, &sub))
1628 goto oom;
1629
1630 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
663996b3
MS
1631 Seat *seat;
1632 Iterator i;
1633 DBusMessageIter iter, sub;
1634
1635 reply = dbus_message_new_method_return(message);
1636 if (!reply)
1637 goto oom;
1638
1639 dbus_message_iter_init_append(reply, &iter);
1640
1641 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1642 goto oom;
1643
1644 HASHMAP_FOREACH(seat, m->seats, i) {
14228c0d 1645 _cleanup_free_ char *p = NULL;
663996b3
MS
1646 DBusMessageIter sub2;
1647
1648 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1649 goto oom;
1650
1651 p = seat_bus_path(seat);
1652 if (!p)
1653 goto oom;
1654
1655 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1656 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1657 free(p);
1658 goto oom;
1659 }
1660
663996b3
MS
1661 if (!dbus_message_iter_close_container(&sub, &sub2))
1662 goto oom;
1663 }
1664
1665 if (!dbus_message_iter_close_container(&iter, &sub))
1666 goto oom;
1667
1668 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1669 Inhibitor *inhibitor;
1670 Iterator i;
1671 DBusMessageIter iter, sub;
1672
1673 reply = dbus_message_new_method_return(message);
1674 if (!reply)
1675 goto oom;
1676
1677 dbus_message_iter_init_append(reply, &iter);
1678
1679 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1680 goto oom;
1681
1682 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1683 DBusMessageIter sub2;
1684 dbus_uint32_t uid, pid;
1685 const char *what, *who, *why, *mode;
1686
1687 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1688 goto oom;
1689
1690 what = strempty(inhibit_what_to_string(inhibitor->what));
1691 who = strempty(inhibitor->who);
1692 why = strempty(inhibitor->why);
1693 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
1694 uid = (dbus_uint32_t) inhibitor->uid;
1695 pid = (dbus_uint32_t) inhibitor->pid;
1696
1697 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1698 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1699 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1700 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
1701 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1702 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1703 goto oom;
1704
1705 if (!dbus_message_iter_close_container(&sub, &sub2))
1706 goto oom;
1707 }
1708
1709 if (!dbus_message_iter_close_container(&iter, &sub))
1710 goto oom;
1711
14228c0d 1712
663996b3
MS
1713 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1714
1715 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1716
1717 if (r < 0)
1718 return bus_send_error_reply(connection, message, &error, r);
1719
1720
1721 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1722
14228c0d 1723 r = bus_manager_create_session(m, message);
663996b3
MS
1724
1725 /* Don't delay the work on OOM here, since it might be
1726 * triggered by a low RLIMIT_NOFILE here (since we
1727 * send a dupped fd to the client), and we'd rather
1728 * see this fail quickly then be retried later */
1729
1730 if (r < 0)
1731 return bus_send_error_reply(connection, message, NULL, r);
1732
1733 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1734 const char *name;
1735 Session *session;
1736
1737 if (!dbus_message_get_args(
1738 message,
1739 &error,
1740 DBUS_TYPE_STRING, &name,
1741 DBUS_TYPE_INVALID))
1742 return bus_send_error_reply(connection, message, &error, -EINVAL);
1743
1744 session = hashmap_get(m->sessions, name);
1745 if (!session)
1746 return bus_send_error_reply(connection, message, &error, -ENOENT);
1747
1748 /* We use the FIFO to detect stray sessions where the
1749 process invoking PAM dies abnormally. We need to make
1750 sure that that process is not killed if at the clean
1751 end of the session it closes the FIFO. Hence, with
1752 this call explicitly turn off the FIFO logic, so that
1753 the PAM code can finish clean up on its own */
1754 session_remove_fifo(session);
1755
1756 reply = dbus_message_new_method_return(message);
1757 if (!reply)
1758 goto oom;
1759
1760 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1761 const char *name;
1762 Session *session;
1763
1764 if (!dbus_message_get_args(
1765 message,
1766 &error,
1767 DBUS_TYPE_STRING, &name,
1768 DBUS_TYPE_INVALID))
1769 return bus_send_error_reply(connection, message, &error, -EINVAL);
1770
1771 session = hashmap_get(m->sessions, name);
1772 if (!session)
1773 return bus_send_error_reply(connection, message, &error, -ENOENT);
1774
1775 r = session_activate(session);
1776 if (r < 0)
1777 return bus_send_error_reply(connection, message, NULL, r);
1778
1779 reply = dbus_message_new_method_return(message);
1780 if (!reply)
1781 goto oom;
1782
1783 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1784 const char *session_name, *seat_name;
1785 Session *session;
1786 Seat *seat;
1787
1788 /* Same as ActivateSession() but refuses to work if
1789 * the seat doesn't match */
1790
1791 if (!dbus_message_get_args(
1792 message,
1793 &error,
1794 DBUS_TYPE_STRING, &session_name,
1795 DBUS_TYPE_STRING, &seat_name,
1796 DBUS_TYPE_INVALID))
1797 return bus_send_error_reply(connection, message, &error, -EINVAL);
1798
1799 session = hashmap_get(m->sessions, session_name);
1800 if (!session)
1801 return bus_send_error_reply(connection, message, &error, -ENOENT);
1802
1803 seat = hashmap_get(m->seats, seat_name);
1804 if (!seat)
1805 return bus_send_error_reply(connection, message, &error, -ENOENT);
1806
1807 if (session->seat != seat)
1808 return bus_send_error_reply(connection, message, &error, -EINVAL);
1809
1810 r = session_activate(session);
1811 if (r < 0)
1812 return bus_send_error_reply(connection, message, NULL, r);
1813
1814 reply = dbus_message_new_method_return(message);
1815 if (!reply)
1816 goto oom;
1817
1818 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1819 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1820 const char *name;
1821 Session *session;
1822
1823 if (!dbus_message_get_args(
1824 message,
1825 &error,
1826 DBUS_TYPE_STRING, &name,
1827 DBUS_TYPE_INVALID))
1828 return bus_send_error_reply(connection, message, &error, -EINVAL);
1829
1830 session = hashmap_get(m->sessions, name);
1831 if (!session)
1832 return bus_send_error_reply(connection, message, NULL, -ENOENT);
1833
1834 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1835 goto oom;
1836
1837 reply = dbus_message_new_method_return(message);
1838 if (!reply)
1839 goto oom;
1840
1841 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions") ||
1842 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSessions")) {
1843
1844 r = session_send_lock_all(m, streq(dbus_message_get_member(message), "LockSessions"));
1845 if (r < 0)
1846 bus_send_error_reply(connection, message, NULL, r);
1847
1848 reply = dbus_message_new_method_return(message);
1849 if (!reply)
1850 goto oom;
1851
1852 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1853 const char *swho;
1854 int32_t signo;
1855 KillWho who;
1856 const char *name;
1857 Session *session;
1858
1859 if (!dbus_message_get_args(
1860 message,
1861 &error,
1862 DBUS_TYPE_STRING, &name,
1863 DBUS_TYPE_STRING, &swho,
1864 DBUS_TYPE_INT32, &signo,
1865 DBUS_TYPE_INVALID))
1866 return bus_send_error_reply(connection, message, &error, -EINVAL);
1867
1868 if (isempty(swho))
1869 who = KILL_ALL;
1870 else {
1871 who = kill_who_from_string(swho);
1872 if (who < 0)
1873 return bus_send_error_reply(connection, message, &error, -EINVAL);
1874 }
1875
1876 if (signo <= 0 || signo >= _NSIG)
1877 return bus_send_error_reply(connection, message, &error, -EINVAL);
1878
1879 session = hashmap_get(m->sessions, name);
1880 if (!session)
1881 return bus_send_error_reply(connection, message, &error, -ENOENT);
1882
1883 r = session_kill(session, who, signo);
1884 if (r < 0)
1885 return bus_send_error_reply(connection, message, NULL, r);
1886
1887 reply = dbus_message_new_method_return(message);
1888 if (!reply)
1889 goto oom;
1890
1891 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1892 uint32_t uid;
1893 User *user;
1894 int32_t signo;
1895
1896 if (!dbus_message_get_args(
1897 message,
1898 &error,
1899 DBUS_TYPE_UINT32, &uid,
1900 DBUS_TYPE_INT32, &signo,
1901 DBUS_TYPE_INVALID))
1902 return bus_send_error_reply(connection, message, &error, -EINVAL);
1903
1904 if (signo <= 0 || signo >= _NSIG)
1905 return bus_send_error_reply(connection, message, &error, -EINVAL);
1906
1907 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1908 if (!user)
1909 return bus_send_error_reply(connection, message, &error, -ENOENT);
1910
1911 r = user_kill(user, signo);
1912 if (r < 0)
1913 return bus_send_error_reply(connection, message, NULL, r);
1914
1915 reply = dbus_message_new_method_return(message);
1916 if (!reply)
1917 goto oom;
1918
1919 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1920 const char *name;
1921 Session *session;
1922
1923 if (!dbus_message_get_args(
1924 message,
1925 &error,
1926 DBUS_TYPE_STRING, &name,
1927 DBUS_TYPE_INVALID))
1928 return bus_send_error_reply(connection, message, &error, -EINVAL);
1929
1930 session = hashmap_get(m->sessions, name);
1931 if (!session)
1932 return bus_send_error_reply(connection, message, &error, -ENOENT);
1933
1934 r = session_stop(session);
1935 if (r < 0)
1936 return bus_send_error_reply(connection, message, NULL, r);
1937
1938 reply = dbus_message_new_method_return(message);
1939 if (!reply)
1940 goto oom;
1941
1942 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1943 uint32_t uid;
1944 User *user;
1945
1946 if (!dbus_message_get_args(
1947 message,
1948 &error,
1949 DBUS_TYPE_UINT32, &uid,
1950 DBUS_TYPE_INVALID))
1951 return bus_send_error_reply(connection, message, &error, -EINVAL);
1952
1953 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1954 if (!user)
1955 return bus_send_error_reply(connection, message, &error, -ENOENT);
1956
1957 r = user_stop(user);
1958 if (r < 0)
1959 return bus_send_error_reply(connection, message, NULL, r);
1960
1961 reply = dbus_message_new_method_return(message);
1962 if (!reply)
1963 goto oom;
1964
1965 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1966 const char *name;
1967 Seat *seat;
1968
1969 if (!dbus_message_get_args(
1970 message,
1971 &error,
1972 DBUS_TYPE_STRING, &name,
1973 DBUS_TYPE_INVALID))
1974 return bus_send_error_reply(connection, message, &error, -EINVAL);
1975
1976 seat = hashmap_get(m->seats, name);
1977 if (!seat)
1978 return bus_send_error_reply(connection, message, &error, -ENOENT);
1979
1980 r = seat_stop_sessions(seat);
1981 if (r < 0)
1982 return bus_send_error_reply(connection, message, NULL, r);
1983
1984 reply = dbus_message_new_method_return(message);
1985 if (!reply)
1986 goto oom;
1987
1988 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
1989 uint32_t uid;
1990 struct passwd *pw;
1991 dbus_bool_t b, interactive;
1992 char *path;
1993
1994 if (!dbus_message_get_args(
1995 message,
1996 &error,
1997 DBUS_TYPE_UINT32, &uid,
1998 DBUS_TYPE_BOOLEAN, &b,
1999 DBUS_TYPE_BOOLEAN, &interactive,
2000 DBUS_TYPE_INVALID))
2001 return bus_send_error_reply(connection, message, &error, -EINVAL);
2002
2003 errno = 0;
2004 pw = getpwuid(uid);
2005 if (!pw)
2006 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
2007
2008 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
2009 if (r < 0)
2010 return bus_send_error_reply(connection, message, &error, r);
2011
2012 mkdir_p_label("/var/lib/systemd", 0755);
2013
2014 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
2015 if (r < 0)
2016 return bus_send_error_reply(connection, message, &error, r);
2017
2018 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
2019 if (!path)
2020 goto oom;
2021
2022 if (b) {
2023 User *u;
2024
2025 r = touch(path);
2026 free(path);
2027
2028 if (r < 0)
2029 return bus_send_error_reply(connection, message, &error, r);
2030
2031 if (manager_add_user_by_uid(m, uid, &u) >= 0)
2032 user_start(u);
2033
2034 } else {
2035 User *u;
2036
2037 r = unlink(path);
2038 free(path);
2039
2040 if (r < 0 && errno != ENOENT)
2041 return bus_send_error_reply(connection, message, &error, -errno);
2042
2043 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
2044 if (u)
2045 user_add_to_gc_queue(u);
2046 }
2047
2048 reply = dbus_message_new_method_return(message);
2049 if (!reply)
2050 goto oom;
2051
2052 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
2053 const char *sysfs, *seat;
2054 dbus_bool_t interactive;
2055
2056 if (!dbus_message_get_args(
2057 message,
2058 &error,
2059 DBUS_TYPE_STRING, &seat,
2060 DBUS_TYPE_STRING, &sysfs,
2061 DBUS_TYPE_BOOLEAN, &interactive,
2062 DBUS_TYPE_INVALID))
2063 return bus_send_error_reply(connection, message, &error, -EINVAL);
2064
2065 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
2066 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2067
2068 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
2069 if (r < 0)
2070 return bus_send_error_reply(connection, message, &error, r);
2071
2072 r = attach_device(m, seat, sysfs);
2073 if (r < 0)
2074 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2075
2076 reply = dbus_message_new_method_return(message);
2077 if (!reply)
2078 goto oom;
2079
2080
2081 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
2082 dbus_bool_t interactive;
2083
2084 if (!dbus_message_get_args(
2085 message,
2086 &error,
2087 DBUS_TYPE_BOOLEAN, &interactive,
2088 DBUS_TYPE_INVALID))
2089 return bus_send_error_reply(connection, message, &error, -EINVAL);
2090
2091 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
2092 if (r < 0)
2093 return bus_send_error_reply(connection, message, &error, r);
2094
2095 r = flush_devices(m);
2096 if (r < 0)
2097 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2098
2099 reply = dbus_message_new_method_return(message);
2100 if (!reply)
2101 goto oom;
2102
2103 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
2104
2105 r = bus_manager_do_shutdown_or_sleep(
2106 m, connection, message,
2107 SPECIAL_POWEROFF_TARGET,
2108 INHIBIT_SHUTDOWN,
2109 "org.freedesktop.login1.power-off",
2110 "org.freedesktop.login1.power-off-multiple-sessions",
2111 "org.freedesktop.login1.power-off-ignore-inhibit",
2112 NULL,
2113 &error, &reply);
2114 if (r < 0)
2115 return bus_send_error_reply(connection, message, &error, r);
2116 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
2117 r = bus_manager_do_shutdown_or_sleep(
2118 m, connection, message,
2119 SPECIAL_REBOOT_TARGET,
2120 INHIBIT_SHUTDOWN,
2121 "org.freedesktop.login1.reboot",
2122 "org.freedesktop.login1.reboot-multiple-sessions",
2123 "org.freedesktop.login1.reboot-ignore-inhibit",
2124 NULL,
2125 &error, &reply);
2126 if (r < 0)
2127 return bus_send_error_reply(connection, message, &error, r);
2128
2129 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2130 r = bus_manager_do_shutdown_or_sleep(
2131 m, connection, message,
2132 SPECIAL_SUSPEND_TARGET,
2133 INHIBIT_SLEEP,
2134 "org.freedesktop.login1.suspend",
2135 "org.freedesktop.login1.suspend-multiple-sessions",
2136 "org.freedesktop.login1.suspend-ignore-inhibit",
2137 "suspend",
2138 &error, &reply);
2139 if (r < 0)
2140 return bus_send_error_reply(connection, message, &error, r);
2141 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2142 r = bus_manager_do_shutdown_or_sleep(
2143 m, connection, message,
2144 SPECIAL_HIBERNATE_TARGET,
2145 INHIBIT_SLEEP,
2146 "org.freedesktop.login1.hibernate",
2147 "org.freedesktop.login1.hibernate-multiple-sessions",
2148 "org.freedesktop.login1.hibernate-ignore-inhibit",
2149 "hibernate",
2150 &error, &reply);
2151 if (r < 0)
2152 return bus_send_error_reply(connection, message, &error, r);
2153
2154 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "HybridSleep")) {
2155 r = bus_manager_do_shutdown_or_sleep(
2156 m, connection, message,
2157 SPECIAL_HYBRID_SLEEP_TARGET,
2158 INHIBIT_SLEEP,
2159 "org.freedesktop.login1.hibernate",
2160 "org.freedesktop.login1.hibernate-multiple-sessions",
2161 "org.freedesktop.login1.hibernate-ignore-inhibit",
2162 "hybrid-sleep",
2163 &error, &reply);
2164 if (r < 0)
2165 return bus_send_error_reply(connection, message, &error, r);
2166
2167 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2168
2169 r = bus_manager_can_shutdown_or_sleep(
2170 m, connection, message,
2171 INHIBIT_SHUTDOWN,
2172 "org.freedesktop.login1.power-off",
2173 "org.freedesktop.login1.power-off-multiple-sessions",
2174 "org.freedesktop.login1.power-off-ignore-inhibit",
2175 NULL,
2176 &error, &reply);
2177 if (r < 0)
2178 return bus_send_error_reply(connection, message, &error, r);
2179 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2180 r = bus_manager_can_shutdown_or_sleep(
2181 m, connection, message,
2182 INHIBIT_SHUTDOWN,
2183 "org.freedesktop.login1.reboot",
2184 "org.freedesktop.login1.reboot-multiple-sessions",
2185 "org.freedesktop.login1.reboot-ignore-inhibit",
2186 NULL,
2187 &error, &reply);
2188 if (r < 0)
2189 return bus_send_error_reply(connection, message, &error, r);
2190
2191 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2192 r = bus_manager_can_shutdown_or_sleep(
2193 m, connection, message,
2194 INHIBIT_SLEEP,
2195 "org.freedesktop.login1.suspend",
2196 "org.freedesktop.login1.suspend-multiple-sessions",
2197 "org.freedesktop.login1.suspend-ignore-inhibit",
2198 "suspend",
2199 &error, &reply);
2200 if (r < 0)
2201 return bus_send_error_reply(connection, message, &error, r);
2202
2203 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2204 r = bus_manager_can_shutdown_or_sleep(
2205 m, connection, message,
2206 INHIBIT_SLEEP,
2207 "org.freedesktop.login1.hibernate",
2208 "org.freedesktop.login1.hibernate-multiple-sessions",
2209 "org.freedesktop.login1.hibernate-ignore-inhibit",
2210 "hibernate",
2211 &error, &reply);
2212 if (r < 0)
2213 return bus_send_error_reply(connection, message, &error, r);
2214
2215 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHybridSleep")) {
2216 r = bus_manager_can_shutdown_or_sleep(
2217 m, connection, message,
2218 INHIBIT_SLEEP,
2219 "org.freedesktop.login1.hibernate",
2220 "org.freedesktop.login1.hibernate-multiple-sessions",
2221 "org.freedesktop.login1.hibernate-ignore-inhibit",
2222 "hybrid-sleep",
2223 &error, &reply);
2224 if (r < 0)
2225 return bus_send_error_reply(connection, message, &error, r);
2226
2227 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2228 char *introspection = NULL;
2229 FILE *f;
2230 Iterator i;
2231 Session *session;
2232 Seat *seat;
2233 User *user;
2234 size_t size;
2235 char *p;
2236
2237 if (!(reply = dbus_message_new_method_return(message)))
2238 goto oom;
2239
2240 /* We roll our own introspection code here, instead of
2241 * relying on bus_default_message_handler() because we
2242 * need to generate our introspection string
2243 * dynamically. */
2244
2245 if (!(f = open_memstream(&introspection, &size)))
2246 goto oom;
2247
2248 fputs(INTROSPECTION_BEGIN, f);
2249
2250 HASHMAP_FOREACH(seat, m->seats, i) {
2251 p = bus_path_escape(seat->id);
2252
2253 if (p) {
2254 fprintf(f, "<node name=\"seat/%s\"/>", p);
2255 free(p);
2256 }
2257 }
2258
2259 HASHMAP_FOREACH(user, m->users, i)
14228c0d 2260 fprintf(f, "<node name=\"user/_%llu\"/>", (unsigned long long) user->uid);
663996b3
MS
2261
2262 HASHMAP_FOREACH(session, m->sessions, i) {
2263 p = bus_path_escape(session->id);
2264
2265 if (p) {
2266 fprintf(f, "<node name=\"session/%s\"/>", p);
2267 free(p);
2268 }
2269 }
2270
2271 fputs(INTROSPECTION_END, f);
2272
2273 if (ferror(f)) {
2274 fclose(f);
2275 free(introspection);
2276 goto oom;
2277 }
2278
2279 fclose(f);
2280
2281 if (!introspection)
2282 goto oom;
2283
2284 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2285 free(introspection);
2286 goto oom;
2287 }
2288
2289 free(introspection);
2290 } else {
2291 const BusBoundProperties bps[] = {
2292 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2293 { NULL, }
2294 };
2295 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2296 }
2297
2298 if (reply) {
2299 if (!bus_maybe_send_reply(connection, message, reply))
14228c0d 2300 goto oom;
663996b3
MS
2301 }
2302
2303 return DBUS_HANDLER_RESULT_HANDLED;
2304
2305oom:
2306 dbus_error_free(&error);
2307
2308 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2309}
2310
2311const DBusObjectPathVTable bus_manager_vtable = {
2312 .message_function = manager_message_handler
2313};
2314
2315DBusHandlerResult bus_message_filter(
2316 DBusConnection *connection,
2317 DBusMessage *message,
2318 void *userdata) {
2319
2320 Manager *m = userdata;
2321 DBusError error;
2322
2323 assert(m);
2324 assert(connection);
2325 assert(message);
2326
2327 dbus_error_init(&error);
2328
14228c0d 2329 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)));
663996b3 2330
14228c0d 2331 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
663996b3 2332 const char *path, *result, *unit;
14228c0d 2333 uint32_t id;
663996b3
MS
2334
2335 if (!dbus_message_get_args(message, &error,
2336 DBUS_TYPE_UINT32, &id,
2337 DBUS_TYPE_OBJECT_PATH, &path,
2338 DBUS_TYPE_STRING, &unit,
2339 DBUS_TYPE_STRING, &result,
14228c0d 2340 DBUS_TYPE_INVALID)) {
663996b3 2341 log_error("Failed to parse JobRemoved message: %s", bus_error_message(&error));
14228c0d
MB
2342 goto finish;
2343 }
663996b3 2344
14228c0d 2345 if (m->action_job && streq(m->action_job, path)) {
663996b3
MS
2346 log_info("Operation finished.");
2347
2348 /* Tell people that they now may take a lock again */
2349 send_prepare_for(m, m->action_what, false);
2350
2351 free(m->action_job);
2352 m->action_job = NULL;
2353 m->action_unit = NULL;
2354 m->action_what = 0;
14228c0d
MB
2355
2356 } else {
2357 Session *s;
2358 User *u;
2359
2360 s = hashmap_get(m->session_units, unit);
2361 if (s) {
2362 if (streq_ptr(path, s->scope_job)) {
2363 free(s->scope_job);
2364 s->scope_job = NULL;
2365
2366 if (s->started) {
2367 if (streq(result, "done"))
2368 session_send_create_reply(s, NULL);
2369 else {
2370 dbus_set_error(&error, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
2371 session_send_create_reply(s, &error);
2372 }
2373 } else
2374 session_save(s);
2375 }
2376
2377 session_add_to_gc_queue(s);
2378 }
2379
2380 u = hashmap_get(m->user_units, unit);
2381 if (u) {
2382 if (streq_ptr(path, u->service_job)) {
2383 free(u->service_job);
2384 u->service_job = NULL;
2385 }
2386
2387 if (streq_ptr(path, u->slice_job)) {
2388 free(u->slice_job);
2389 u->slice_job = NULL;
2390 }
2391
2392 user_save(u);
2393 user_add_to_gc_queue(u);
2394 }
2395 }
2396
2397 } else if (dbus_message_is_signal(message, "org.freedesktop.DBus.Properties", "PropertiesChanged")) {
2398
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 /* drop all controllers owned by this name */
2477 if (*old && !*new && (key = hashmap_remove(m->busnames, old))) {
2478 Session *session;
2479 Iterator i;
2480
2481 free(key);
2482
2483 HASHMAP_FOREACH(session, m->sessions, i)
2484 if (session_is_controller(session, old))
2485 session_drop_controller(session);
663996b3
MS
2486 }
2487 }
2488
14228c0d 2489finish:
663996b3
MS
2490 dbus_error_free(&error);
2491
2492 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2493}
2494
2495int manager_send_changed(Manager *manager, const char *properties) {
2496 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
2497
2498 assert(manager);
2499
2500 m = bus_properties_changed_new("/org/freedesktop/login1",
2501 "org.freedesktop.login1.Manager",
2502 properties);
2503 if (!m)
2504 return -ENOMEM;
2505
2506 if (!dbus_connection_send(manager->bus, m, NULL))
2507 return -ENOMEM;
2508
2509 return 0;
2510}
2511
2512int manager_dispatch_delayed(Manager *manager) {
2513 DBusError error;
2514 int r;
2515
2516 assert(manager);
2517
2518 if (manager->action_what == 0 || manager->action_job)
2519 return 0;
2520
2521 /* Continue delay? */
2522 if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0)) {
2523
2524 if (manager->action_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC))
2525 return 0;
2526
2527 log_info("Delay lock is active but inhibitor timeout is reached.");
2528 }
2529
2530 /* Actually do the operation */
2531 dbus_error_init(&error);
2532 r = execute_shutdown_or_sleep(manager, manager->action_what, manager->action_unit, &error);
2533 if (r < 0) {
2534 log_warning("Failed to send delayed message: %s", bus_error(&error, r));
2535 dbus_error_free(&error);
2536
2537 manager->action_unit = NULL;
2538 manager->action_what = 0;
2539 return r;
2540 }
2541
2542 return 1;
2543}
14228c0d
MB
2544
2545int manager_start_scope(
2546 Manager *manager,
2547 const char *scope,
2548 pid_t pid,
2549 const char *slice,
2550 const char *description,
2551 const char *after,
2552 const char *kill_mode,
2553 DBusError *error,
2554 char **job) {
2555
2556 const char *timeout_stop_property = "TimeoutStopUSec", *send_sighup_property = "SendSIGHUP", *pids_property = "PIDs";
2557 _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
2558 DBusMessageIter iter, sub, sub2, sub3, sub4;
2559 uint64_t timeout = 500 * USEC_PER_MSEC;
2560 dbus_bool_t send_sighup = true;
2561 const char *fail = "fail";
2562 uint32_t u;
2563
2564 assert(manager);
2565 assert(scope);
2566 assert(pid > 1);
2567
2568 if (!slice)
2569 slice = "";
2570
2571 m = dbus_message_new_method_call(
2572 "org.freedesktop.systemd1",
2573 "/org/freedesktop/systemd1",
2574 "org.freedesktop.systemd1.Manager",
2575 "StartTransientUnit");
2576 if (!m)
2577 return log_oom();
2578
2579 dbus_message_iter_init_append(m, &iter);
2580
2581 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &scope) ||
2582 !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &fail) ||
2583 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sv)", &sub))
2584 return log_oom();
2585
2586 if (!isempty(slice)) {
2587 const char *slice_property = "Slice";
2588
2589 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2590 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &slice_property) ||
2591 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "s", &sub3) ||
2592 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &slice) ||
2593 !dbus_message_iter_close_container(&sub2, &sub3) ||
2594 !dbus_message_iter_close_container(&sub, &sub2))
2595 return log_oom();
2596 }
2597
2598 if (!isempty(description)) {
2599 const char *description_property = "Description";
2600
2601 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2602 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description_property) ||
2603 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "s", &sub3) ||
2604 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &description) ||
2605 !dbus_message_iter_close_container(&sub2, &sub3) ||
2606 !dbus_message_iter_close_container(&sub, &sub2))
2607 return log_oom();
2608 }
2609
2610 if (!isempty(after)) {
2611 const char *after_property = "After";
2612
2613 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2614 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &after_property) ||
2615 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "as", &sub3) ||
2616 !dbus_message_iter_open_container(&sub3, DBUS_TYPE_ARRAY, "s", &sub4) ||
2617 !dbus_message_iter_append_basic(&sub4, DBUS_TYPE_STRING, &after) ||
2618 !dbus_message_iter_close_container(&sub3, &sub4) ||
2619 !dbus_message_iter_close_container(&sub2, &sub3) ||
2620 !dbus_message_iter_close_container(&sub, &sub2))
2621 return log_oom();
2622 }
2623
2624 if (!isempty(kill_mode)) {
2625 const char *kill_mode_property = "KillMode";
2626
2627 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2628 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &kill_mode_property) ||
2629 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "s", &sub3) ||
2630 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &kill_mode) ||
2631 !dbus_message_iter_close_container(&sub2, &sub3) ||
2632 !dbus_message_iter_close_container(&sub, &sub2))
2633 return log_oom();
2634 }
2635
2636 /* cgroup empty notification is not available in containers
2637 * currently. To make this less problematic, let's shorten the
2638 * stop timeout for sessions, so that we don't wait
2639 * forever. */
2640
2641 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2642 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &timeout_stop_property) ||
2643 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "t", &sub3) ||
2644 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_UINT64, &timeout) ||
2645 !dbus_message_iter_close_container(&sub2, &sub3) ||
2646 !dbus_message_iter_close_container(&sub, &sub2))
2647 return log_oom();
2648
2649 /* Make sure that the session shells are terminated with
2650 * SIGHUP since bash and friends tend to ignore SIGTERM */
2651 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2652 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &send_sighup_property) ||
2653 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "b", &sub3) ||
2654 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_BOOLEAN, &send_sighup) ||
2655 !dbus_message_iter_close_container(&sub2, &sub3) ||
2656 !dbus_message_iter_close_container(&sub, &sub2))
2657 return log_oom();
2658
2659 u = pid;
2660 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2661 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &pids_property) ||
2662 !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "au", &sub3) ||
2663 !dbus_message_iter_open_container(&sub3, DBUS_TYPE_ARRAY, "u", &sub4) ||
2664 !dbus_message_iter_append_basic(&sub4, DBUS_TYPE_UINT32, &u) ||
2665 !dbus_message_iter_close_container(&sub3, &sub4) ||
2666 !dbus_message_iter_close_container(&sub2, &sub3) ||
2667 !dbus_message_iter_close_container(&sub, &sub2))
2668 return log_oom();
2669
2670 if (!dbus_message_iter_close_container(&iter, &sub))
2671 return log_oom();
2672
2673 reply = dbus_connection_send_with_reply_and_block(manager->bus, m, -1, error);
2674 if (!reply)
2675 return -EIO;
2676
2677 if (job) {
2678 const char *j;
2679 char *copy;
2680
2681 if (!dbus_message_get_args(reply, error, DBUS_TYPE_OBJECT_PATH, &j, DBUS_TYPE_INVALID))
2682 return -EIO;
2683
2684 copy = strdup(j);
2685 if (!copy)
2686 return -ENOMEM;
2687
2688 *job = copy;
2689 }
2690
2691 return 0;
2692}
2693
2694int manager_start_unit(Manager *manager, const char *unit, DBusError *error, char **job) {
2695 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2696 const char *fail = "fail";
2697 int r;
2698
2699 assert(manager);
2700 assert(unit);
2701
2702 r = bus_method_call_with_reply(
2703 manager->bus,
2704 "org.freedesktop.systemd1",
2705 "/org/freedesktop/systemd1",
2706 "org.freedesktop.systemd1.Manager",
2707 "StartUnit",
2708 &reply,
2709 error,
2710 DBUS_TYPE_STRING, &unit,
2711 DBUS_TYPE_STRING, &fail,
2712 DBUS_TYPE_INVALID);
2713 if (r < 0) {
2714 log_error("Failed to start unit %s: %s", unit, bus_error(error, r));
2715 return r;
2716 }
2717
2718 if (job) {
2719 const char *j;
2720 char *copy;
2721
2722 if (!dbus_message_get_args(reply, error,
2723 DBUS_TYPE_OBJECT_PATH, &j,
2724 DBUS_TYPE_INVALID)) {
2725 log_error("Failed to parse reply.");
2726 return -EIO;
2727 }
2728
2729 copy = strdup(j);
2730 if (!copy)
2731 return -ENOMEM;
2732
2733 *job = copy;
2734 }
2735
2736 return 0;
2737}
2738
2739int manager_stop_unit(Manager *manager, const char *unit, DBusError *error, char **job) {
2740 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2741 const char *fail = "fail";
2742 int r;
2743
2744 assert(manager);
2745 assert(unit);
2746
2747 r = bus_method_call_with_reply(
2748 manager->bus,
2749 "org.freedesktop.systemd1",
2750 "/org/freedesktop/systemd1",
2751 "org.freedesktop.systemd1.Manager",
2752 "StopUnit",
2753 &reply,
2754 error,
2755 DBUS_TYPE_STRING, &unit,
2756 DBUS_TYPE_STRING, &fail,
2757 DBUS_TYPE_INVALID);
2758 if (r < 0) {
2759 if (dbus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
2760 dbus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
2761
2762 if (job)
2763 *job = NULL;
2764
2765 dbus_error_free(error);
2766 return 0;
2767 }
2768
2769 log_error("Failed to stop unit %s: %s", unit, bus_error(error, r));
2770 return r;
2771 }
2772
2773 if (job) {
2774 const char *j;
2775 char *copy;
2776
2777 if (!dbus_message_get_args(reply, error,
2778 DBUS_TYPE_OBJECT_PATH, &j,
2779 DBUS_TYPE_INVALID)) {
2780 log_error("Failed to parse reply.");
2781 return -EIO;
2782 }
2783
2784 copy = strdup(j);
2785 if (!copy)
2786 return -ENOMEM;
2787
2788 *job = copy;
2789 }
2790
2791 return 1;
2792}
2793
2794int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, DBusError *error) {
2795 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2796 const char *w;
2797 int r;
2798
2799 assert(manager);
2800 assert(unit);
2801
2802 w = who == KILL_LEADER ? "process" : "cgroup";
2803 assert_cc(sizeof(signo) == sizeof(int32_t));
2804
2805 r = bus_method_call_with_reply(
2806 manager->bus,
2807 "org.freedesktop.systemd1",
2808 "/org/freedesktop/systemd1",
2809 "org.freedesktop.systemd1.Manager",
2810 "KillUnit",
2811 &reply,
2812 error,
2813 DBUS_TYPE_STRING, &unit,
2814 DBUS_TYPE_STRING, &w,
2815 DBUS_TYPE_INT32, &signo,
2816 DBUS_TYPE_INVALID);
2817 if (r < 0) {
2818 log_error("Failed to stop unit %s: %s", unit, bus_error(error, r));
2819 return r;
2820 }
2821
2822 return 0;
2823}
2824
2825int manager_unit_is_active(Manager *manager, const char *unit) {
2826
2827 const char *interface = "org.freedesktop.systemd1.Unit";
2828 const char *property = "ActiveState";
2829 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2830 _cleanup_free_ char *path = NULL;
2831 DBusMessageIter iter, sub;
2832 const char *state;
2833 DBusError error;
2834 int r;
2835
2836 assert(manager);
2837 assert(unit);
2838
2839 dbus_error_init(&error);
2840
2841 path = unit_dbus_path_from_name(unit);
2842 if (!path)
2843 return -ENOMEM;
2844
2845 r = bus_method_call_with_reply(
2846 manager->bus,
2847 "org.freedesktop.systemd1",
2848 path,
2849 "org.freedesktop.DBus.Properties",
2850 "Get",
2851 &reply,
2852 &error,
2853 DBUS_TYPE_STRING, &interface,
2854 DBUS_TYPE_STRING, &property,
2855 DBUS_TYPE_INVALID);
2856 if (r < 0) {
2857 if (dbus_error_has_name(&error, DBUS_ERROR_NO_REPLY) ||
2858 dbus_error_has_name(&error, DBUS_ERROR_DISCONNECTED)) {
2859 /* systemd might have droppped off
2860 * momentarily, let's not make this an
2861 * error */
2862
2863 dbus_error_free(&error);
2864 return true;
2865 }
2866
2867 if (dbus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
2868 dbus_error_has_name(&error, BUS_ERROR_LOAD_FAILED)) {
2869 /* If the unit is already unloaded then it's
2870 * not active */
2871
2872 dbus_error_free(&error);
2873 return false;
2874 }
2875
2876 log_error("Failed to query ActiveState: %s", bus_error(&error, r));
2877 dbus_error_free(&error);
2878 return r;
2879 }
2880
2881 if (!dbus_message_iter_init(reply, &iter) ||
2882 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
2883 log_error("Failed to parse reply.");
2884 return -EINVAL;
2885 }
2886
2887 dbus_message_iter_recurse(&iter, &sub);
2888 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
2889 log_error("Failed to parse reply.");
2890 return -EINVAL;
2891 }
2892
2893 dbus_message_iter_get_basic(&sub, &state);
2894
2895 return !streq(state, "inactive") && !streq(state, "failed");
2896}