]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-dbus.c
localed: mark bus properties as change emitting
[thirdparty/systemd.git] / src / login / logind-dbus.c
CommitLineData
3f49d45a
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2011 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
3f49d45a
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
3f49d45a 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
3f49d45a
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
a185c5aa
LP
22#include <errno.h>
23#include <string.h>
98a28fef 24#include <unistd.h>
7f7bb946 25#include <pwd.h>
a185c5aa 26
3f49d45a
LP
27#include "logind.h"
28#include "dbus-common.h"
98a28fef 29#include "strv.h"
49e942b2 30#include "mkdir.h"
9eb977db 31#include "path-util.h"
7f7bb946 32#include "polkit.h"
55af3897 33#include "special.h"
19adb8a3 34#include "sleep-config.h"
877d54e9
LP
35#include "systemd/sd-id128.h"
36#include "systemd/sd-messages.h"
a5c32cff
HH
37#include "fileio-label.h"
38#include "label.h"
9444b1f2
LP
39#include "utf8.h"
40#include "unit-name.h"
fb6becb4
LP
41#include "bus-errors.h"
42#include "virt.h"
3f49d45a
LP
43
44#define BUS_MANAGER_INTERFACE \
45 " <interface name=\"org.freedesktop.login1.Manager\">\n" \
bef422ae 46 " <method name=\"GetSession\">\n" \
3f49d45a 47 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
bef422ae 48 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
3f49d45a 49 " </method>\n" \
c4aa65e7
LP
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" \
3f49d45a 54 " <method name=\"GetUser\">\n" \
bef422ae 55 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
3f49d45a
LP
56 " <arg name=\"user\" type=\"o\" direction=\"out\"/>\n" \
57 " </method>\n" \
9444b1f2
LP
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" \
bef422ae 62 " <method name=\"GetSeat\">\n" \
3f49d45a 63 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
bef422ae 64 " <arg name=\"seat\" type=\"o\" direction=\"out\"/>\n" \
3f49d45a 65 " </method>\n" \
bef422ae 66 " <method name=\"ListSessions\">\n" \
e1c9c2d5 67 " <arg name=\"sessions\" type=\"a(susso)\" direction=\"out\"/>\n" \
3f49d45a
LP
68 " </method>\n" \
69 " <method name=\"ListUsers\">\n" \
70 " <arg name=\"users\" type=\"a(uso)\" direction=\"out\"/>\n" \
71 " </method>\n" \
bef422ae
LP
72 " <method name=\"ListSeats\">\n" \
73 " <arg name=\"seats\" type=\"a(so)\" direction=\"out\"/>\n" \
3f49d45a
LP
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" \
ab06eef8 78 " <arg name=\"service\" type=\"s\" direction=\"in\"/>\n" \
3f49d45a 79 " <arg name=\"type\" type=\"s\" direction=\"in\"/>\n" \
55efac6c 80 " <arg name=\"class\" type=\"s\" direction=\"in\"/>\n" \
3f49d45a 81 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
4d6d6518 82 " <arg name=\"vtnr\" type=\"u\" direction=\"in\"/>\n" \
3f49d45a
LP
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" \
fb6becb4 88 " <arg name=\"scope_properties\" type=\"a(sv)\" direction=\"in\"/>\n" \
3f49d45a
LP
89 " <arg name=\"id\" type=\"s\" direction=\"out\"/>\n" \
90 " <arg name=\"path\" type=\"o\" direction=\"out\"/>\n" \
98a28fef 91 " <arg name=\"runtime_path\" type=\"o\" direction=\"out\"/>\n" \
3f49d45a 92 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
bbc73283
LP
93 " <arg name=\"seat\" type=\"s\" direction=\"out\"/>\n" \
94 " <arg name=\"vtnr\" type=\"u\" direction=\"out\"/>\n" \
77085881 95 " <arg name=\"existing\" type=\"b\" direction=\"out\"/>\n" \
3f49d45a 96 " </method>\n" \
75c8e3cf
LP
97 " <method name=\"ReleaseSession\">\n" \
98 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
99 " </method>\n" \
a185c5aa
LP
100 " <method name=\"ActivateSession\">\n" \
101 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
102 " </method>\n" \
84c3361e
LP
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" \
88e3dc90
LP
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" \
fa2b196d 113 " <method name=\"LockSessions\"/>\n" \
b6160029 114 " <method name=\"UnlockSessions\"/>\n" \
de07ab16
LP
115 " <method name=\"KillSession\">\n" \
116 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
cae5846b
LP
117 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
118 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
de07ab16
LP
119 " </method>\n" \
120 " <method name=\"KillUser\">\n" \
121 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
cae5846b 122 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
de07ab16 123 " </method>\n" \
3f49d45a
LP
124 " <method name=\"TerminateSession\">\n" \
125 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
126 " </method>\n" \
127 " <method name=\"TerminateUser\">\n" \
bef422ae 128 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
3f49d45a
LP
129 " </method>\n" \
130 " <method name=\"TerminateSeat\">\n" \
131 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
132 " </method>\n" \
7f7bb946
LP
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" \
47a26690
LP
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" \
b668e064
LP
143 " <method name=\"FlushDevices\">\n" \
144 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
145 " </method>\n" \
55af3897
LP
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" \
d889a206
LP
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" \
6524990f
LP
158 " <method name=\"HybridSleep\">\n" \
159 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
160 " </method>\n" \
89f13440
LP
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" \
d889a206
LP
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" \
6524990f
LP
173 " <method name=\"CanHybridSleep\">\n" \
174 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
175 " </method>\n" \
f8e2fb7b
LP
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" \
eecd1362 180 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
f8e2fb7b
LP
181 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
182 " </method>\n" \
183 " <method name=\"ListInhibitors\">\n" \
eecd1362 184 " <arg name=\"inhibitors\" type=\"a(ssssuu)\" direction=\"out\"/>\n" \
f8e2fb7b 185 " </method>\n" \
3f49d45a
LP
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" \
eecd1362
LP
210 " <signal name=\"PrepareForShutdown\">\n" \
211 " <arg name=\"active\" type=\"b\"/>\n" \
212 " </signal>\n" \
d889a206
LP
213 " <signal name=\"PrepareForSleep\">\n" \
214 " <arg name=\"active\" type=\"b\"/>\n" \
215 " </signal>\n" \
3f49d45a
LP
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" \
a185c5aa
LP
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" \
eecd1362
LP
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" \
069cfc85 226 " <property name=\"HandlePowerKey\" type=\"s\" access=\"read\"/>\n" \
8e7fd6ad
LP
227 " <property name=\"HandleSuspendKey\" type=\"s\" access=\"read\"/>\n" \
228 " <property name=\"HandleHibernateKey\" type=\"s\" access=\"read\"/>\n" \
069cfc85 229 " <property name=\"HandleLidSwitch\" type=\"s\" access=\"read\"/>\n" \
23406ce5
LP
230 " <property name=\"IdleAction\" type=\"s\" access=\"read\"/>\n" \
231 " <property name=\"IdleActionUSec\" type=\"t\" access=\"read\"/>\n" \
5e4a79da
LP
232 " <property name=\"PreparingForShutdown\" type=\"b\" access=\"read\"/>\n" \
233 " <property name=\"PreparingForSleep\" type=\"b\" access=\"read\"/>\n" \
3f49d45a
LP
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
a185c5aa
LP
251static int bus_manager_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
252 Manager *m = data;
77527da0 253 dbus_bool_t b;
a185c5aa
LP
254
255 assert(i);
256 assert(property);
257 assert(m);
258
77527da0 259 b = manager_get_idle_hint(m, NULL) > 0;
a185c5aa
LP
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
f8e2fb7b
LP
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
eecd1362 289 w = manager_inhibit_what(m, streq(property, "BlockInhibited") ? INHIBIT_BLOCK : INHIBIT_DELAY);
f8e2fb7b
LP
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
5e4a79da
LP
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"))
314b4b0a 306 b = !!(m->action_what & INHIBIT_SHUTDOWN);
5e4a79da 307 else
314b4b0a 308 b = !!(m->action_what & INHIBIT_SLEEP);
5e4a79da
LP
309
310 dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b);
311 return 0;
312}
313
fb6becb4
LP
314static int bus_manager_create_session(Manager *m, DBusMessage *message) {
315
954449b8 316 const char *type, *class, *cseat, *tty, *display, *remote_user, *remote_host, *service;
98a28fef 317 uint32_t uid, leader, audit_id = 0;
fb6becb4 318 _cleanup_free_ char *id = NULL;
954449b8
LP
319 Session *session = NULL;
320 User *user = NULL;
321 Seat *seat = NULL;
fb6becb4
LP
322 DBusMessageIter iter;
323 dbus_bool_t remote;
324 uint32_t vtnr = 0;
325 SessionType t;
326 SessionClass c;
98a28fef 327 bool b;
fb6becb4 328 int r;
98a28fef
LP
329
330 assert(m);
331 assert(message);
98a28fef
LP
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
9444b1f2 345 if (!dbus_message_iter_next(&iter) ||
98a28fef
LP
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);
e2acb67b
LP
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 }
98a28fef 363
e2acb67b 364 if (!dbus_message_iter_next(&iter) ||
98a28fef
LP
365 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
366 return -EINVAL;
367
55efac6c
LP
368 dbus_message_iter_get_basic(&iter, &class);
369 if (isempty(class))
e2acb67b
LP
370 c = _SESSION_CLASS_INVALID;
371 else {
55efac6c 372 c = session_class_from_string(class);
e2acb67b
LP
373 if (c < 0)
374 return -EINVAL;
375 }
55efac6c 376
e2acb67b 377 if (!dbus_message_iter_next(&iter) ||
55efac6c
LP
378 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
379 return -EINVAL;
380
954449b8 381 dbus_message_iter_get_basic(&iter, &cseat);
98a28fef 382
954449b8
LP
383 if (isempty(cseat))
384 seat = NULL;
98a28fef 385 else {
954449b8
LP
386 seat = hashmap_get(m->seats, cseat);
387 if (!seat)
98a28fef
LP
388 return -ENOENT;
389 }
390
4d6d6518
LP
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
98a28fef
LP
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)) {
4d6d6518 404 int v;
98a28fef 405
954449b8 406 if (!seat)
92432fcc
DH
407 seat = m->seat0;
408 else if (seat != m->seat0)
98a28fef
LP
409 return -EINVAL;
410
4d6d6518
LP
411 v = vtnr_from_tty(tty);
412
413 if (v <= 0)
414 return v < 0 ? v : -EINVAL;
98a28fef
LP
415
416 if (vtnr <= 0)
4d6d6518
LP
417 vtnr = (uint32_t) v;
418 else if (vtnr != (uint32_t) v)
419 return -EINVAL;
d1122ad5
LP
420 } else if (tty_is_console(tty)) {
421
954449b8 422 if (!seat)
92432fcc
DH
423 seat = m->seat0;
424 else if (seat != m->seat0)
d1122ad5
LP
425 return -EINVAL;
426
427 if (vtnr != 0)
428 return -EINVAL;
978cf3c7 429 }
98a28fef 430
954449b8 431 if (seat) {
bf7825ae 432 if (seat_has_vts(seat)) {
d1122ad5 433 if (vtnr > 63)
4d6d6518
LP
434 return -EINVAL;
435 } else {
d1122ad5 436 if (vtnr != 0)
4d6d6518
LP
437 return -EINVAL;
438 }
439 }
440
98a28fef
LP
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
e2acb67b
LP
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
98a28fef
LP
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
9444b1f2
LP
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
872c8faa 487 manager_get_session_by_pid(m, leader, &session);
fb6becb4
LP
488 if (session) {
489 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
490 _cleanup_free_ char *path = NULL;
491 _cleanup_close_ int fifo_fd = -1;
8b6fe824 492 dbus_bool_t exists;
98a28fef 493
fb6becb4
LP
494 /* Session already exists, client is probably
495 * something like "su" which changes uid but is still
496 * the same session */
98a28fef 497
954449b8
LP
498 fifo_fd = session_create_fifo(session);
499 if (fifo_fd < 0) {
500 r = fifo_fd;
07714753
LP
501 goto fail;
502 }
98a28fef 503
fb6becb4
LP
504 path = session_bus_path(session);
505 if (!path) {
954449b8
LP
506 r = -ENOMEM;
507 goto fail;
508 }
21c390cc 509
fb6becb4
LP
510 reply = dbus_message_new_method_return(message);
511 if (!reply) {
954449b8
LP
512 r = -ENOMEM;
513 goto fail;
514 }
932e3ee7 515
954449b8
LP
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,
fb6becb4 523 DBUS_TYPE_OBJECT_PATH, &path,
954449b8
LP
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 }
21c390cc 534
fb6becb4
LP
535 if (!dbus_connection_send(m->bus, reply, NULL)) {
536 r = -ENOMEM;
537 goto fail;
538 }
21c390cc 539
954449b8
LP
540 return 0;
541 }
21c390cc 542
954449b8
LP
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 */
21c390cc 546
954449b8
LP
547 if (asprintf(&id, "%lu", (unsigned long) audit_id) < 0) {
548 r = -ENOMEM;
549 goto fail;
550 }
21c390cc 551
954449b8
LP
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)) {
4b549144 557 log_warning("Existing logind session ID %s used by new audit session, ignoring", id);
954449b8 558 audit_id = 0;
8ea913b2 559
954449b8
LP
560 free(id);
561 id = NULL;
07714753 562 }
954449b8 563 }
07714753 564
954449b8 565 if (!id) {
07714753
LP
566 do {
567 free(id);
f8e2fb7b 568 id = NULL;
07714753 569
f8e2fb7b 570 if (asprintf(&id, "c%lu", ++m->session_counter) < 0) {
07714753
LP
571 r = -ENOMEM;
572 goto fail;
573 }
574
575 } while (hashmap_get(m->sessions, id));
98a28fef
LP
576 }
577
954449b8
LP
578 r = manager_add_user_by_uid(m, uid, &user);
579 if (r < 0)
580 goto fail;
581
9444b1f2 582 r = manager_add_session(m, id, &session);
98a28fef
LP
583 if (r < 0)
584 goto fail;
585
9444b1f2
LP
586 session_set_user(session, user);
587
98a28fef
LP
588 session->leader = leader;
589 session->audit_id = audit_id;
590 session->type = t;
55efac6c 591 session->class = c;
98a28fef 592 session->remote = remote;
98a28fef
LP
593 session->vtnr = vtnr;
594
98a28fef
LP
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
954449b8
LP
635 if (seat) {
636 r = seat_attach_session(seat, session);
98a28fef
LP
637 if (r < 0)
638 goto fail;
639 }
640
641 r = session_start(session);
642 if (r < 0)
643 goto fail;
644
fb6becb4 645 session->create_message = dbus_message_ref(message);
98a28fef 646
cba38758
LP
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
98a28fef
LP
651 return 0;
652
653fail:
98a28fef
LP
654 if (session)
655 session_add_to_gc_queue(session);
656
657 if (user)
658 user_add_to_gc_queue(user);
659
98a28fef
LP
660 return r;
661}
662
314b4b0a
LP
663static int bus_manager_inhibit(
664 Manager *m,
665 DBusConnection *connection,
666 DBusMessage *message,
667 DBusError *error,
668 DBusMessage **_reply) {
669
f8e2fb7b
LP
670 Inhibitor *i = NULL;
671 char *id = NULL;
eecd1362 672 const char *who, *why, *what, *mode;
f8e2fb7b
LP
673 pid_t pid;
674 InhibitWhat w;
eecd1362 675 InhibitMode mm;
f8e2fb7b
LP
676 unsigned long ul;
677 int r, fifo_fd = -1;
ce0fc5f5 678 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
f8e2fb7b
LP
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,
eecd1362 692 DBUS_TYPE_STRING, &mode,
f8e2fb7b
LP
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
eecd1362
LP
704 mm = inhibit_mode_from_string(mode);
705 if (mm < 0) {
706 r = -EINVAL;
707 goto fail;
708 }
709
beaafb2e
LP
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
314b4b0a
LP
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
eecd1362 725 r = verify_polkit(connection, message,
8e7fd6ad
LP
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",
b14eda96 733 false, NULL, error);
f8e2fb7b
LP
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;
eecd1362 766 i->mode = mm;
f8e2fb7b
LP
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;
ce0fc5f5 799 reply = NULL;
f8e2fb7b
LP
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
f8e2fb7b
LP
812 return r;
813}
814
2eb916cd 815static int trigger_device(Manager *m, struct udev_device *d) {
b668e064
LP
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
2eb916cd
LP
828 if (d) {
829 if (udev_enumerate_add_match_parent(e, d) < 0) {
830 r = -EIO;
831 goto finish;
832 }
833 }
834
b668e064
LP
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
b668e064
LP
847 t = strappend(p, "/uevent");
848 if (!t) {
849 r = -ENOMEM;
850 goto finish;
851 }
852
574d5f2d 853 write_string_file(t, "change");
b668e064
LP
854 free(t);
855 }
856
857 r = 0;
858
859finish:
860 if (e)
861 udev_enumerate_unref(e);
862
863 return r;
864}
865
47a26690
LP
866static int attach_device(Manager *m, const char *seat, const char *sysfs) {
867 struct udev_device *d;
7fd1b19b 868 _cleanup_free_ char *rule = NULL, *file = NULL;
c28fa3d3 869 const char *id_for_seat;
47a26690
LP
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
309c2a2c 880 if (!udev_device_has_tag(d, "seat")) {
47a26690
LP
881 r = -ENODEV;
882 goto finish;
883 }
884
c28fa3d3
LP
885 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
886 if (!id_for_seat) {
47a26690
LP
887 r = -ENODEV;
888 goto finish;
889 }
890
c28fa3d3 891 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
47a26690
LP
892 r = -ENOMEM;
893 goto finish;
894 }
895
c28fa3d3 896 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
47a26690
LP
897 r = -ENOMEM;
898 goto finish;
899 }
900
d2e54fae 901 mkdir_p_label("/etc/udev/rules.d", 0755);
a5c32cff 902 label_init("/etc");
574d5f2d 903 r = write_string_file_atomic_label(file, rule);
a0a0c7f1
LP
904 if (r < 0)
905 goto finish;
906
2eb916cd 907 r = trigger_device(m, d);
47a26690
LP
908
909finish:
47a26690
LP
910 if (d)
911 udev_device_unref(d);
912
913 return r;
914}
915
b668e064 916static int flush_devices(Manager *m) {
7fd1b19b 917 _cleanup_closedir_ DIR *d;
b668e064
LP
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 }
b668e064
LP
942 }
943
944 return trigger_device(m, NULL);
945}
946
89f13440 947static int have_multiple_sessions(
89f13440 948 Manager *m,
409133be 949 uid_t uid) {
89f13440 950
2154761f
MS
951 Session *session;
952 Iterator i;
89f13440
LP
953
954 assert(m);
955
1ca04b87
LP
956 /* Check for other users' sessions. Greeter sessions do not
957 * count, and non-login sessions do not count either. */
2154761f 958 HASHMAP_FOREACH(session, m->sessions, i)
1ca04b87 959 if (session->class == SESSION_USER &&
c68ba912 960 !session->closing &&
1ca04b87 961 session->user->uid != uid)
2154761f 962 return true;
89f13440
LP
963
964 return false;
965}
966
314b4b0a
LP
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
af9792ac 1008 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
b85bddda 1009 const char *mode = "replace-irreversibly", *p;
af9792ac
LP
1010 int r;
1011 char *c;
eecd1362 1012
af9792ac 1013 assert(m);
314b4b0a
LP
1014 assert(w >= 0);
1015 assert(w < _INHIBIT_WHAT_MAX);
d889a206 1016 assert(unit_name);
eecd1362 1017
314b4b0a
LP
1018 bus_manager_log_shutdown(m, w, unit_name);
1019
af9792ac
LP
1020 r = bus_method_call_with_reply(
1021 m->bus,
eecd1362
LP
1022 "org.freedesktop.systemd1",
1023 "/org/freedesktop/systemd1",
1024 "org.freedesktop.systemd1.Manager",
b9c26b41 1025 "StartUnit",
af9792ac
LP
1026 &reply,
1027 error,
b9c26b41
SP
1028 DBUS_TYPE_STRING, &unit_name,
1029 DBUS_TYPE_STRING, &mode,
1030 DBUS_TYPE_INVALID);
af9792ac
LP
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
314b4b0a 1045 m->action_unit = unit_name;
af9792ac
LP
1046 free(m->action_job);
1047 m->action_job = c;
314b4b0a 1048 m->action_what = w;
af9792ac
LP
1049
1050 return 0;
eecd1362
LP
1051}
1052
314b4b0a
LP
1053static int delay_shutdown_or_sleep(
1054 Manager *m,
1055 InhibitWhat w,
1056 const char *unit_name) {
eecd1362 1057
eecd1362 1058 assert(m);
d889a206
LP
1059 assert(w >= 0);
1060 assert(w < _INHIBIT_WHAT_MAX);
314b4b0a 1061 assert(unit_name);
eecd1362 1062
314b4b0a
LP
1063 m->action_timestamp = now(CLOCK_MONOTONIC);
1064 m->action_unit = unit_name;
1065 m->action_what = w;
d889a206
LP
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,
19adb8a3 1078 const char *sleep_verb,
d889a206
LP
1079 DBusError *error,
1080 DBusMessage **_reply) {
1081
1082 bool multiple_sessions, challenge, blocked, b;
7f643797 1083 const char *result = NULL;
ce0fc5f5 1084 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
d889a206 1085 int r;
409133be 1086 unsigned long ul;
d889a206
LP
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
19adb8a3
ZJS
1099 if (sleep_verb) {
1100 r = can_sleep(sleep_verb);
d889a206
LP
1101 if (r < 0)
1102 return r;
6524990f
LP
1103 if (r == 0) {
1104 result = "na";
1105 goto finish;
1106 }
1107 }
1108
409133be
LP
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);
d889a206
LP
1114 if (r < 0)
1115 return r;
1116
1117 multiple_sessions = r > 0;
409133be 1118 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
d889a206
LP
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";
d5a745df
LP
1127 else if (challenge)
1128 result = "challenge";
1129 else
1130 result = "no";
1131 }
d889a206
LP
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);
4654e558 1171 if (!b)
d889a206 1172 return -ENOMEM;
d889a206
LP
1173
1174 *_reply = reply;
ce0fc5f5 1175 reply = NULL;
d889a206
LP
1176 return 0;
1177}
1178
314b4b0a
LP
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 };
877d54e9 1184
314b4b0a
LP
1185 dbus_bool_t active = _active;
1186 _cleanup_dbus_message_unref_ DBusMessage *message = NULL;
877d54e9
LP
1187
1188 assert(m);
314b4b0a
LP
1189 assert(w >= 0);
1190 assert(w < _INHIBIT_WHAT_MAX);
1191 assert(signal_name[w]);
877d54e9 1192
314b4b0a
LP
1193 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1194 if (!message)
1195 return -ENOMEM;
877d54e9 1196
314b4b0a
LP
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;
877d54e9 1200
314b4b0a 1201 return 0;
877d54e9
LP
1202}
1203
069cfc85
LP
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);
af9792ac 1217 assert(!m->action_job);
069cfc85 1218
314b4b0a
LP
1219 /* Tell everybody to prepare for shutdown/sleep */
1220 send_prepare_for(m, w, true);
1221
069cfc85
LP
1222 delayed =
1223 m->inhibit_delay_max > 0 &&
409133be 1224 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0);
069cfc85
LP
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);
314b4b0a 1230 else
069cfc85
LP
1231 /* Shutdown is not delayed, execute it
1232 * immediately */
314b4b0a 1233 r = execute_shutdown_or_sleep(m, w, unit_name, error);
069cfc85
LP
1234
1235 return r;
1236}
1237
d889a206
LP
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,
19adb8a3 1247 const char *sleep_verb,
d889a206
LP
1248 DBusError *error,
1249 DBusMessage **_reply) {
1250
1251 dbus_bool_t interactive;
069cfc85 1252 bool multiple_sessions, blocked;
d889a206
LP
1253 DBusMessage *reply = NULL;
1254 int r;
409133be 1255 unsigned long ul;
d889a206
LP
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
314b4b0a
LP
1269 /* Don't allow multiple jobs being executed at the same time */
1270 if (m->action_what)
af9792ac
LP
1271 return -EALREADY;
1272
d889a206
LP
1273 if (!dbus_message_get_args(
1274 message,
1275 error,
1276 DBUS_TYPE_BOOLEAN, &interactive,
1277 DBUS_TYPE_INVALID))
1278 return -EINVAL;
1279
19adb8a3
ZJS
1280 if (sleep_verb) {
1281 r = can_sleep(sleep_verb);
6524990f
LP
1282 if (r < 0)
1283 return r;
1284
1285 if (r == 0)
1286 return -ENOTSUP;
1287 }
1288
409133be
LP
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);
d889a206
LP
1294 if (r < 0)
1295 return r;
1296
1297 multiple_sessions = r > 0;
409133be 1298 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
d889a206
LP
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
069cfc85 1318 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
d889a206
LP
1319 if (r < 0)
1320 return r;
1321
1322 reply = dbus_message_new_method_return(message);
1323 if (!reply)
1324 return -ENOMEM;
eecd1362 1325
d889a206 1326 *_reply = reply;
eecd1362
LP
1327 return 0;
1328}
1329
23406ce5 1330static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_action, handle_action, HandleAction);
069cfc85 1331
d200735e 1332static const BusProperty bus_login_manager_properties[] = {
d200735e
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 },
eecd1362
LP
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) },
23406ce5
LP
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) },
5e4a79da
LP
1349 { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
1350 { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
d200735e
MS
1351 { NULL, }
1352};
1353
3f49d45a
LP
1354static DBusHandlerResult manager_message_handler(
1355 DBusConnection *connection,
1356 DBusMessage *message,
1357 void *userdata) {
1358
1359 Manager *m = userdata;
1360
3f49d45a 1361 DBusError error;
ce0fc5f5 1362 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
bef422ae 1363 int r;
3f49d45a
LP
1364
1365 assert(connection);
1366 assert(message);
1367 assert(m);
1368
1369 dbus_error_init(&error);
1370
bef422ae
LP
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);
c4aa65e7
LP
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);
bef422ae
LP
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
9444b1f2
LP
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
9444b1f2
LP
1504 if (!b)
1505 goto oom;
1506
bef422ae
LP
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
e1c9c2d5
LP
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
dec15e92 1554 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
e1c9c2d5
LP
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")) {
e1c9c2d5
LP
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
dec15e92 1599 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
e1c9c2d5
LP
1600 goto oom;
1601
1602 HASHMAP_FOREACH(user, m->users, i) {
9444b1f2 1603 _cleanup_free_ char *p = NULL;
e1c9c2d5
LP
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
e1c9c2d5
LP
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")) {
e1c9c2d5
LP
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
dec15e92 1641 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
e1c9c2d5
LP
1642 goto oom;
1643
1644 HASHMAP_FOREACH(seat, m->seats, i) {
9444b1f2 1645 _cleanup_free_ char *p = NULL;
e1c9c2d5
LP
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
e1c9c2d5
LP
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
f8e2fb7b
LP
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
eecd1362 1679 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
f8e2fb7b
LP
1680 goto oom;
1681
1682 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1683 DBusMessageIter sub2;
1684 dbus_uint32_t uid, pid;
eecd1362 1685 const char *what, *who, *why, *mode;
f8e2fb7b
LP
1686
1687 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1688 goto oom;
1689
eecd1362 1690 what = strempty(inhibit_what_to_string(inhibitor->what));
f8e2fb7b
LP
1691 who = strempty(inhibitor->who);
1692 why = strempty(inhibitor->why);
eecd1362 1693 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
f8e2fb7b
LP
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) ||
eecd1362 1700 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
f8e2fb7b
LP
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
9444b1f2 1712
f8e2fb7b
LP
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
98a28fef
LP
1721 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1722
fb6becb4 1723 r = bus_manager_create_session(m, message);
688c56ff
LP
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 */
98a28fef
LP
1729
1730 if (r < 0)
f8e2fb7b 1731 return bus_send_error_reply(connection, message, NULL, r);
fb6becb4 1732
75c8e3cf
LP
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
bef422ae
LP
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
84c3361e
LP
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
88e3dc90
LP
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)
7ba64386 1832 return bus_send_error_reply(connection, message, NULL, -ENOENT);
88e3dc90
LP
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
b6160029
LP
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"));
7ba64386
LP
1845 if (r < 0)
1846 bus_send_error_reply(connection, message, NULL, r);
fa2b196d
LP
1847
1848 reply = dbus_message_new_method_return(message);
1849 if (!reply)
1850 goto oom;
1851
de07ab16
LP
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
bef422ae
LP
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
7f7bb946
LP
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
89f13440 2008 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
7f7bb946
LP
2009 if (r < 0)
2010 return bus_send_error_reply(connection, message, &error, r);
2011
d2e54fae 2012 mkdir_p_label("/var/lib/systemd", 0755);
02b16a19 2013
d2e54fae 2014 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
7f7bb946
LP
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) {
38f3fc7d
LP
2023 User *u;
2024
7f7bb946
LP
2025 r = touch(path);
2026 free(path);
2027
2028 if (r < 0)
2029 return bus_send_error_reply(connection, message, &error, r);
38f3fc7d
LP
2030
2031 if (manager_add_user_by_uid(m, uid, &u) >= 0)
2032 user_start(u);
2033
7f7bb946 2034 } else {
38f3fc7d
LP
2035 User *u;
2036
7f7bb946
LP
2037 r = unlink(path);
2038 free(path);
2039
2040 if (r < 0 && errno != ENOENT)
2041 return bus_send_error_reply(connection, message, &error, -errno);
38f3fc7d
LP
2042
2043 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
2044 if (u)
2045 user_add_to_gc_queue(u);
7f7bb946
LP
2046 }
2047
2048 reply = dbus_message_new_method_return(message);
2049 if (!reply)
2050 goto oom;
2051
47a26690
LP
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
89f13440 2068 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
47a26690
LP
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;
7f7bb946 2079
b668e064
LP
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
89f13440 2091 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
b668e064
LP
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
d889a206
LP
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",
19adb8a3 2112 NULL,
d889a206 2113 &error, &reply);
89f13440
LP
2114 if (r < 0)
2115 return bus_send_error_reply(connection, message, &error, r);
d889a206
LP
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",
19adb8a3 2124 NULL,
d889a206 2125 &error, &reply);
89f13440
LP
2126 if (r < 0)
2127 return bus_send_error_reply(connection, message, &error, r);
2128
d889a206
LP
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",
19adb8a3 2137 "suspend",
d889a206
LP
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",
19adb8a3 2149 "hibernate",
6524990f
LP
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",
19adb8a3 2162 "hybrid-sleep",
d889a206
LP
2163 &error, &reply);
2164 if (r < 0)
2165 return bus_send_error_reply(connection, message, &error, r);
f8e2fb7b 2166
d889a206 2167 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
f8e2fb7b 2168
d889a206
LP
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",
19adb8a3 2175 NULL,
d889a206
LP
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",
19adb8a3 2186 NULL,
d889a206
LP
2187 &error, &reply);
2188 if (r < 0)
2189 return bus_send_error_reply(connection, message, &error, r);
89f13440 2190
d889a206
LP
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",
19adb8a3 2198 "suspend",
d889a206
LP
2199 &error, &reply);
2200 if (r < 0)
2201 return bus_send_error_reply(connection, message, &error, r);
89f13440 2202
d889a206
LP
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",
19adb8a3 2210 "hibernate",
6524990f
LP
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",
19adb8a3 2222 "hybrid-sleep",
d889a206
LP
2223 &error, &reply);
2224 if (r < 0)
2225 return bus_send_error_reply(connection, message, &error, r);
89f13440 2226
bef422ae 2227 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
3f49d45a
LP
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)
6c605695 2260 fprintf(f, "<node name=\"user/_%llu\"/>", (unsigned long long) user->uid);
3f49d45a
LP
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);
d200735e
MS
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 }
3f49d45a
LP
2297
2298 if (reply) {
1a37b9b9 2299 if (!bus_maybe_send_reply(connection, message, reply))
fb6becb4 2300 goto oom;
3f49d45a
LP
2301 }
2302
2303 return DBUS_HANDLER_RESULT_HANDLED;
2304
2305oom:
3f49d45a
LP
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};
9418f147 2314
1713813d
LP
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
fb6becb4 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)));
1713813d 2330
fb6becb4 2331 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
af9792ac 2332 const char *path, *result, *unit;
fb6becb4 2333 uint32_t id;
af9792ac
LP
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,
fb6becb4 2340 DBUS_TYPE_INVALID)) {
af9792ac 2341 log_error("Failed to parse JobRemoved message: %s", bus_error_message(&error));
fb6becb4
LP
2342 goto finish;
2343 }
314b4b0a 2344
fb6becb4 2345 if (m->action_job && streq(m->action_job, path)) {
314b4b0a 2346 log_info("Operation finished.");
ee17c928 2347
314b4b0a
LP
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;
fb6becb4
LP
2355
2356 } else {
fb6becb4
LP
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 }
76e66585
LP
2373 } else
2374 session_save(s);
fb6becb4
LP
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
8aec412f 2392 user_save(u);
fb6becb4
LP
2393 user_add_to_gc_queue(u);
2394 }
fb6becb4
LP
2395 }
2396
2397 } else if (dbus_message_is_signal(message, "org.freedesktop.DBus.Properties", "PropertiesChanged")) {
2398
fb6becb4
LP
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) {
fb6becb4
LP
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);
af9792ac 2418 }
6fa48533 2419
943aca8e
LP
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);
6797c324
LP
2435 if (session)
2436 session_add_to_gc_queue(session);
943aca8e 2437
6797c324
LP
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;
943aca8e
LP
2450 }
2451
6797c324
LP
2452 /* systemd finished reloading, let's recheck all our sessions */
2453 if (!b) {
2454 Session *session;
2455 Iterator i;
943aca8e 2456
6797c324
LP
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);
943aca8e 2461 }
e8b212fe
DH
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
ae5e06bd 2476 /* drop all controllers owned by this name */
e8b212fe 2477 if (*old && !*new && (key = hashmap_remove(m->busnames, old))) {
ae5e06bd
DH
2478 Session *session;
2479 Iterator i;
2480
e8b212fe 2481 free(key);
ae5e06bd
DH
2482
2483 HASHMAP_FOREACH(session, m->sessions, i)
2484 if (session_is_controller(session, old))
2485 session_drop_controller(session);
e8b212fe 2486 }
1713813d
LP
2487 }
2488
fb6becb4 2489finish:
1713813d
LP
2490 dbus_error_free(&error);
2491
2492 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2493}
2494
9418f147 2495int manager_send_changed(Manager *manager, const char *properties) {
ce0fc5f5 2496 _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
9418f147
LP
2497
2498 assert(manager);
2499
4654e558
ZJS
2500 m = bus_properties_changed_new("/org/freedesktop/login1",
2501 "org.freedesktop.login1.Manager",
2502 properties);
9418f147 2503 if (!m)
4654e558 2504 return -ENOMEM;
9418f147
LP
2505
2506 if (!dbus_connection_send(manager->bus, m, NULL))
4654e558 2507 return -ENOMEM;
9418f147 2508
4654e558 2509 return 0;
9418f147 2510}
eecd1362 2511
d889a206 2512int manager_dispatch_delayed(Manager *manager) {
eecd1362 2513 DBusError error;
eecd1362
LP
2514 int r;
2515
2516 assert(manager);
2517
84286536 2518 if (manager->action_what == 0 || manager->action_job)
eecd1362
LP
2519 return 0;
2520
2521 /* Continue delay? */
314b4b0a 2522 if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0)) {
eecd1362 2523
314b4b0a
LP
2524 if (manager->action_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC))
2525 return 0;
af9792ac 2526
314b4b0a
LP
2527 log_info("Delay lock is active but inhibitor timeout is reached.");
2528 }
eecd1362 2529
314b4b0a 2530 /* Actually do the operation */
eecd1362 2531 dbus_error_init(&error);
314b4b0a 2532 r = execute_shutdown_or_sleep(manager, manager->action_what, manager->action_unit, &error);
eecd1362 2533 if (r < 0) {
449101fc 2534 log_warning("Failed to send delayed message: %s", bus_error(&error, r));
d889a206 2535 dbus_error_free(&error);
314b4b0a
LP
2536
2537 manager->action_unit = NULL;
2538 manager->action_what = 0;
eecd1362
LP
2539 return r;
2540 }
2541
eecd1362
LP
2542 return 1;
2543}
fb6becb4
LP
2544
2545int manager_start_scope(
2546 Manager *manager,
2547 const char *scope,
2548 pid_t pid,
2549 const char *slice,
2550 const char *description,
7fb3ee51 2551 const char *after,
405e0255 2552 const char *kill_mode,
fb6becb4
LP
2553 DBusError *error,
2554 char **job) {
2555
743e8945 2556 const char *timeout_stop_property = "TimeoutStopUSec", *send_sighup_property = "SendSIGHUP", *pids_property = "PIDs";
fb6becb4
LP
2557 _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
2558 DBusMessageIter iter, sub, sub2, sub3, sub4;
fb6becb4 2559 uint64_t timeout = 500 * USEC_PER_MSEC;
743e8945 2560 dbus_bool_t send_sighup = true;
fb6becb4
LP
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
7fb3ee51
LP
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
405e0255
LP
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
fb6becb4
LP
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
743e8945
LP
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
fb6becb4
LP
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) ||
743e8945
LP
2667 !dbus_message_iter_close_container(&sub, &sub2))
2668 return log_oom();
2669
2670 if (!dbus_message_iter_close_container(&iter, &sub))
fb6becb4
LP
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) {
6797c324
LP
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
fb6becb4
LP
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
6797c324 2791 return 1;
fb6becb4
LP
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);
fb6becb4 2856 if (r < 0) {
6797c324
LP
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
fb6becb4
LP
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}