]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-dbus.c
journal: when comparing two entries from separate files make sure we reposition the...
[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"
877d54e9
LP
34#include "systemd/sd-id128.h"
35#include "systemd/sd-messages.h"
3f49d45a
LP
36
37#define BUS_MANAGER_INTERFACE \
38 " <interface name=\"org.freedesktop.login1.Manager\">\n" \
bef422ae 39 " <method name=\"GetSession\">\n" \
3f49d45a 40 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
bef422ae 41 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
3f49d45a 42 " </method>\n" \
c4aa65e7
LP
43 " <method name=\"GetSessionByPID\">\n" \
44 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
45 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
46 " </method>\n" \
3f49d45a 47 " <method name=\"GetUser\">\n" \
bef422ae 48 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
3f49d45a
LP
49 " <arg name=\"user\" type=\"o\" direction=\"out\"/>\n" \
50 " </method>\n" \
bef422ae 51 " <method name=\"GetSeat\">\n" \
3f49d45a 52 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
bef422ae 53 " <arg name=\"seat\" type=\"o\" direction=\"out\"/>\n" \
3f49d45a 54 " </method>\n" \
bef422ae 55 " <method name=\"ListSessions\">\n" \
e1c9c2d5 56 " <arg name=\"sessions\" type=\"a(susso)\" direction=\"out\"/>\n" \
3f49d45a
LP
57 " </method>\n" \
58 " <method name=\"ListUsers\">\n" \
59 " <arg name=\"users\" type=\"a(uso)\" direction=\"out\"/>\n" \
60 " </method>\n" \
bef422ae
LP
61 " <method name=\"ListSeats\">\n" \
62 " <arg name=\"seats\" type=\"a(so)\" direction=\"out\"/>\n" \
3f49d45a
LP
63 " </method>\n" \
64 " <method name=\"CreateSession\">\n" \
65 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
66 " <arg name=\"leader\" type=\"u\" direction=\"in\"/>\n" \
4d6d6518 67 " <arg name=\"sevice\" type=\"s\" direction=\"in\"/>\n" \
3f49d45a 68 " <arg name=\"type\" type=\"s\" direction=\"in\"/>\n" \
55efac6c 69 " <arg name=\"class\" type=\"s\" direction=\"in\"/>\n" \
3f49d45a 70 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
4d6d6518 71 " <arg name=\"vtnr\" type=\"u\" direction=\"in\"/>\n" \
3f49d45a
LP
72 " <arg name=\"tty\" type=\"s\" direction=\"in\"/>\n" \
73 " <arg name=\"display\" type=\"s\" direction=\"in\"/>\n" \
74 " <arg name=\"remote\" type=\"b\" direction=\"in\"/>\n" \
75 " <arg name=\"remote_user\" type=\"s\" direction=\"in\"/>\n" \
76 " <arg name=\"remote_host\" type=\"s\" direction=\"in\"/>\n" \
77 " <arg name=\"controllers\" type=\"as\" direction=\"in\"/>\n" \
78 " <arg name=\"reset_controllers\" type=\"as\" direction=\"in\"/>\n" \
98a28fef 79 " <arg name=\"kill_processes\" type=\"b\" direction=\"in\"/>\n" \
3f49d45a
LP
80 " <arg name=\"id\" type=\"s\" direction=\"out\"/>\n" \
81 " <arg name=\"path\" type=\"o\" direction=\"out\"/>\n" \
98a28fef 82 " <arg name=\"runtime_path\" type=\"o\" direction=\"out\"/>\n" \
3f49d45a 83 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
bbc73283
LP
84 " <arg name=\"seat\" type=\"s\" direction=\"out\"/>\n" \
85 " <arg name=\"vtnr\" type=\"u\" direction=\"out\"/>\n" \
3f49d45a 86 " </method>\n" \
75c8e3cf
LP
87 " <method name=\"ReleaseSession\">\n" \
88 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
89 " </method>\n" \
a185c5aa
LP
90 " <method name=\"ActivateSession\">\n" \
91 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
92 " </method>\n" \
84c3361e
LP
93 " <method name=\"ActivateSessionOnSeat\">\n" \
94 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
95 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
96 " </method>\n" \
88e3dc90
LP
97 " <method name=\"LockSession\">\n" \
98 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
99 " </method>\n" \
100 " <method name=\"UnlockSession\">\n" \
101 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
102 " </method>\n" \
fa2b196d 103 " <method name=\"LockSessions\"/>\n" \
de07ab16
LP
104 " <method name=\"KillSession\">\n" \
105 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
cae5846b
LP
106 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
107 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
de07ab16
LP
108 " </method>\n" \
109 " <method name=\"KillUser\">\n" \
110 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
cae5846b 111 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
de07ab16 112 " </method>\n" \
3f49d45a
LP
113 " <method name=\"TerminateSession\">\n" \
114 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
115 " </method>\n" \
116 " <method name=\"TerminateUser\">\n" \
bef422ae 117 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
3f49d45a
LP
118 " </method>\n" \
119 " <method name=\"TerminateSeat\">\n" \
120 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
121 " </method>\n" \
7f7bb946
LP
122 " <method name=\"SetUserLinger\">\n" \
123 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
124 " <arg name=\"b\" type=\"b\" direction=\"in\"/>\n" \
125 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
126 " </method>\n" \
47a26690
LP
127 " <method name=\"AttachDevice\">\n" \
128 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
129 " <arg name=\"sysfs\" type=\"s\" direction=\"in\"/>\n" \
130 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
131 " </method>\n" \
b668e064
LP
132 " <method name=\"FlushDevices\">\n" \
133 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
134 " </method>\n" \
55af3897
LP
135 " <method name=\"PowerOff\">\n" \
136 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
137 " </method>\n" \
138 " <method name=\"Reboot\">\n" \
139 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
140 " </method>\n" \
d889a206
LP
141 " <method name=\"Suspend\">\n" \
142 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
143 " </method>\n" \
144 " <method name=\"Hibernate\">\n" \
145 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
146 " </method>\n" \
89f13440
LP
147 " <method name=\"CanPowerOff\">\n" \
148 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
149 " </method>\n" \
150 " <method name=\"CanReboot\">\n" \
151 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
152 " </method>\n" \
d889a206
LP
153 " <method name=\"CanSuspend\">\n" \
154 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
155 " </method>\n" \
156 " <method name=\"CanHibernate\">\n" \
157 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
158 " </method>\n" \
f8e2fb7b
LP
159 " <method name=\"Inhibit\">\n" \
160 " <arg name=\"what\" type=\"s\" direction=\"in\"/>\n" \
161 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
162 " <arg name=\"why\" type=\"s\" direction=\"in\"/>\n" \
eecd1362 163 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
f8e2fb7b
LP
164 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
165 " </method>\n" \
166 " <method name=\"ListInhibitors\">\n" \
eecd1362 167 " <arg name=\"inhibitors\" type=\"a(ssssuu)\" direction=\"out\"/>\n" \
f8e2fb7b 168 " </method>\n" \
3f49d45a
LP
169 " <signal name=\"SessionNew\">\n" \
170 " <arg name=\"id\" type=\"s\"/>\n" \
171 " <arg name=\"path\" type=\"o\"/>\n" \
172 " </signal>\n" \
173 " <signal name=\"SessionRemoved\">\n" \
174 " <arg name=\"id\" type=\"s\"/>\n" \
175 " <arg name=\"path\" type=\"o\"/>\n" \
176 " </signal>\n" \
177 " <signal name=\"UserNew\">\n" \
178 " <arg name=\"uid\" type=\"u\"/>\n" \
179 " <arg name=\"path\" type=\"o\"/>\n" \
180 " </signal>\n" \
181 " <signal name=\"UserRemoved\">\n" \
182 " <arg name=\"uid\" type=\"u\"/>\n" \
183 " <arg name=\"path\" type=\"o\"/>\n" \
184 " </signal>\n" \
185 " <signal name=\"SeatNew\">\n" \
186 " <arg name=\"id\" type=\"s\"/>\n" \
187 " <arg name=\"path\" type=\"o\"/>\n" \
188 " </signal>\n" \
189 " <signal name=\"SeatRemoved\">\n" \
190 " <arg name=\"id\" type=\"s\"/>\n" \
191 " <arg name=\"path\" type=\"o\"/>\n" \
192 " </signal>\n" \
eecd1362
LP
193 " <signal name=\"PrepareForShutdown\">\n" \
194 " <arg name=\"active\" type=\"b\"/>\n" \
195 " </signal>\n" \
d889a206
LP
196 " <signal name=\"PrepareForSleep\">\n" \
197 " <arg name=\"active\" type=\"b\"/>\n" \
198 " </signal>\n" \
3f49d45a
LP
199 " <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
200 " <property name=\"Controllers\" type=\"as\" access=\"read\"/>\n" \
201 " <property name=\"ResetControllers\" type=\"as\" access=\"read\"/>\n" \
202 " <property name=\"NAutoVTs\" type=\"u\" access=\"read\"/>\n" \
203 " <property name=\"KillOnlyUsers\" type=\"as\" access=\"read\"/>\n" \
204 " <property name=\"KillExcludeUsers\" type=\"as\" access=\"read\"/>\n" \
205 " <property name=\"KillUserProcesses\" type=\"b\" access=\"read\"/>\n" \
a185c5aa
LP
206 " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
207 " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
208 " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
eecd1362
LP
209 " <property name=\"BlockInhibited\" type=\"s\" access=\"read\"/>\n" \
210 " <property name=\"DelayInhibited\" type=\"s\" access=\"read\"/>\n" \
211 " <property name=\"InhibitDelayMaxUSec\" type=\"t\" access=\"read\"/>\n" \
069cfc85
LP
212 " <property name=\"HandlePowerKey\" type=\"s\" access=\"read\"/>\n" \
213 " <property name=\"HandleSleepKey\" type=\"s\" access=\"read\"/>\n" \
214 " <property name=\"HandleLidSwitch\" type=\"s\" access=\"read\"/>\n" \
5e4a79da
LP
215 " <property name=\"PreparingForShutdown\" type=\"b\" access=\"read\"/>\n" \
216 " <property name=\"PreparingForSleep\" type=\"b\" access=\"read\"/>\n" \
3f49d45a
LP
217 " </interface>\n"
218
219#define INTROSPECTION_BEGIN \
220 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
221 "<node>\n" \
222 BUS_MANAGER_INTERFACE \
223 BUS_PROPERTIES_INTERFACE \
224 BUS_PEER_INTERFACE \
225 BUS_INTROSPECTABLE_INTERFACE
226
227#define INTROSPECTION_END \
228 "</node>\n"
229
230#define INTERFACES_LIST \
231 BUS_GENERIC_INTERFACES_LIST \
232 "org.freedesktop.login1.Manager\0"
233
a185c5aa
LP
234static int bus_manager_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
235 Manager *m = data;
77527da0 236 dbus_bool_t b;
a185c5aa
LP
237
238 assert(i);
239 assert(property);
240 assert(m);
241
77527da0 242 b = manager_get_idle_hint(m, NULL) > 0;
a185c5aa
LP
243 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
244 return -ENOMEM;
245
246 return 0;
247}
248
249static int bus_manager_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
250 Manager *m = data;
251 dual_timestamp t;
252 uint64_t u;
253
254 assert(i);
255 assert(property);
256 assert(m);
257
258 manager_get_idle_hint(m, &t);
259 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
260
261 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
262 return -ENOMEM;
263
264 return 0;
265}
266
f8e2fb7b
LP
267static int bus_manager_append_inhibited(DBusMessageIter *i, const char *property, void *data) {
268 Manager *m = data;
269 InhibitWhat w;
270 const char *p;
271
eecd1362 272 w = manager_inhibit_what(m, streq(property, "BlockInhibited") ? INHIBIT_BLOCK : INHIBIT_DELAY);
f8e2fb7b
LP
273 p = inhibit_what_to_string(w);
274
275 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &p))
276 return -ENOMEM;
277
278 return 0;
279}
280
5e4a79da
LP
281static int bus_manager_append_preparing(DBusMessageIter *i, const char *property, void *data) {
282 Manager *m = data;
283 dbus_bool_t b;
284
285 assert(i);
286 assert(property);
287
288 if (streq(property, "PreparingForShutdown"))
289 b = !!(m->delayed_what & INHIBIT_SHUTDOWN);
290 else
291 b = !!(m->delayed_what & INHIBIT_SLEEP);
292
293 dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b);
294 return 0;
295}
296
98a28fef
LP
297static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMessage **_reply) {
298 Session *session = NULL;
299 User *user = NULL;
55efac6c 300 const char *type, *class, *seat, *tty, *display, *remote_user, *remote_host, *service;
98a28fef
LP
301 uint32_t uid, leader, audit_id = 0;
302 dbus_bool_t remote, kill_processes;
303 char **controllers = NULL, **reset_controllers = NULL;
304 SessionType t;
55efac6c 305 SessionClass c;
98a28fef
LP
306 Seat *s;
307 DBusMessageIter iter;
308 int r;
07714753 309 char *id = NULL, *p;
4d6d6518 310 uint32_t vtnr = 0;
932e3ee7 311 int fifo_fd = -1;
98a28fef
LP
312 DBusMessage *reply = NULL;
313 bool b;
314
315 assert(m);
316 assert(message);
317 assert(_reply);
318
319 if (!dbus_message_iter_init(message, &iter) ||
320 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
321 return -EINVAL;
322
323 dbus_message_iter_get_basic(&iter, &uid);
324
325 if (!dbus_message_iter_next(&iter) ||
326 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
327 return -EINVAL;
328
329 dbus_message_iter_get_basic(&iter, &leader);
330
331 if (leader <= 0 ||
332 !dbus_message_iter_next(&iter) ||
333 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
334 return -EINVAL;
335
336 dbus_message_iter_get_basic(&iter, &service);
337
338 if (!dbus_message_iter_next(&iter) ||
339 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
340 return -EINVAL;
341
342 dbus_message_iter_get_basic(&iter, &type);
343 t = session_type_from_string(type);
344
345 if (t < 0 ||
346 !dbus_message_iter_next(&iter) ||
347 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
348 return -EINVAL;
349
55efac6c
LP
350 dbus_message_iter_get_basic(&iter, &class);
351 if (isempty(class))
352 c = SESSION_USER;
353 else
354 c = session_class_from_string(class);
355
356 if (c < 0 ||
357 !dbus_message_iter_next(&iter) ||
358 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
359 return -EINVAL;
360
98a28fef
LP
361 dbus_message_iter_get_basic(&iter, &seat);
362
363 if (isempty(seat))
364 s = NULL;
365 else {
366 s = hashmap_get(m->seats, seat);
367 if (!s)
368 return -ENOENT;
369 }
370
4d6d6518
LP
371 if (!dbus_message_iter_next(&iter) ||
372 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
373 return -EINVAL;
374
375 dbus_message_iter_get_basic(&iter, &vtnr);
376
98a28fef
LP
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, &tty);
382
383 if (tty_is_vc(tty)) {
4d6d6518 384 int v;
98a28fef
LP
385
386 if (!s)
387 s = m->vtconsole;
388 else if (s != m->vtconsole)
389 return -EINVAL;
390
4d6d6518
LP
391 v = vtnr_from_tty(tty);
392
393 if (v <= 0)
394 return v < 0 ? v : -EINVAL;
98a28fef
LP
395
396 if (vtnr <= 0)
4d6d6518
LP
397 vtnr = (uint32_t) v;
398 else if (vtnr != (uint32_t) v)
399 return -EINVAL;
d1122ad5
LP
400 } else if (tty_is_console(tty)) {
401
402 if (!s)
403 s = m->vtconsole;
404 else if (s != m->vtconsole)
405 return -EINVAL;
406
407 if (vtnr != 0)
408 return -EINVAL;
98a28fef 409
bf100920 410 } else if (!isempty(tty) && s && seat_is_vtconsole(s))
98a28fef
LP
411 return -EINVAL;
412
4d6d6518 413 if (s) {
addedec4 414 if (seat_can_multi_session(s)) {
d1122ad5 415 if (vtnr > 63)
4d6d6518
LP
416 return -EINVAL;
417 } else {
d1122ad5 418 if (vtnr != 0)
4d6d6518
LP
419 return -EINVAL;
420 }
421 }
422
98a28fef
LP
423 if (!dbus_message_iter_next(&iter) ||
424 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
425 return -EINVAL;
426
427 dbus_message_iter_get_basic(&iter, &display);
428
429 if (!dbus_message_iter_next(&iter) ||
430 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
431 return -EINVAL;
432
433 dbus_message_iter_get_basic(&iter, &remote);
434
435 if (!dbus_message_iter_next(&iter) ||
436 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
437 return -EINVAL;
438
439 dbus_message_iter_get_basic(&iter, &remote_user);
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, &remote_host);
446
447 if (!dbus_message_iter_next(&iter) ||
448 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
449 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
450 return -EINVAL;
451
452 r = bus_parse_strv_iter(&iter, &controllers);
453 if (r < 0)
454 return -EINVAL;
455
25d93491
LP
456 if (strv_contains(controllers, "systemd") ||
457 !dbus_message_iter_next(&iter) ||
98a28fef
LP
458 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
459 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) {
460 r = -EINVAL;
461 goto fail;
462 }
463
464 r = bus_parse_strv_iter(&iter, &reset_controllers);
465 if (r < 0)
466 goto fail;
467
25d93491
LP
468 if (strv_contains(reset_controllers, "systemd") ||
469 !dbus_message_iter_next(&iter) ||
98a28fef
LP
470 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) {
471 r = -EINVAL;
472 goto fail;
473 }
474
475 dbus_message_iter_get_basic(&iter, &kill_processes);
476
477 r = manager_add_user_by_uid(m, uid, &user);
478 if (r < 0)
479 goto fail;
480
481 audit_session_from_pid(leader, &audit_id);
482
07714753 483 if (audit_id > 0) {
98a28fef 484 asprintf(&id, "%lu", (unsigned long) audit_id);
98a28fef 485
07714753
LP
486 if (!id) {
487 r = -ENOMEM;
488 goto fail;
489 }
98a28fef 490
21c390cc
LP
491 session = hashmap_get(m->sessions, id);
492
493 if (session) {
8ea913b2 494 free(id);
21c390cc 495
932e3ee7
LP
496 fifo_fd = session_create_fifo(session);
497 if (fifo_fd < 0) {
498 r = fifo_fd;
499 goto fail;
500 }
501
21c390cc
LP
502 /* Session already exists, client is probably
503 * something like "su" which changes uid but
504 * is still the same audit session */
505
506 reply = dbus_message_new_method_return(message);
507 if (!reply) {
508 r = -ENOMEM;
509 goto fail;
510 }
511
21c390cc
LP
512 p = session_bus_path(session);
513 if (!p) {
514 r = -ENOMEM;
515 goto fail;
516 }
517
3887b5ab
LP
518 seat = session->seat ? session->seat->id : "";
519 vtnr = session->vtnr;
21c390cc
LP
520 b = dbus_message_append_args(
521 reply,
522 DBUS_TYPE_STRING, &session->id,
523 DBUS_TYPE_OBJECT_PATH, &p,
524 DBUS_TYPE_STRING, &session->user->runtime_path,
932e3ee7 525 DBUS_TYPE_UNIX_FD, &fifo_fd,
3887b5ab
LP
526 DBUS_TYPE_STRING, &seat,
527 DBUS_TYPE_UINT32, &vtnr,
21c390cc
LP
528 DBUS_TYPE_INVALID);
529 free(p);
530
531 if (!b) {
532 r = -ENOMEM;
533 goto fail;
534 }
535
932e3ee7 536 close_nointr_nofail(fifo_fd);
21c390cc
LP
537 *_reply = reply;
538
8ea913b2
LP
539 strv_free(controllers);
540 strv_free(reset_controllers);
541
21c390cc 542 return 0;
07714753
LP
543 }
544
545 } else {
546 do {
547 free(id);
f8e2fb7b 548 id = NULL;
07714753 549
f8e2fb7b 550 if (asprintf(&id, "c%lu", ++m->session_counter) < 0) {
07714753
LP
551 r = -ENOMEM;
552 goto fail;
553 }
554
555 } while (hashmap_get(m->sessions, id));
98a28fef
LP
556 }
557
558 r = manager_add_session(m, user, id, &session);
559 free(id);
560 if (r < 0)
561 goto fail;
562
563 session->leader = leader;
564 session->audit_id = audit_id;
565 session->type = t;
55efac6c 566 session->class = c;
98a28fef
LP
567 session->remote = remote;
568 session->controllers = controllers;
569 session->reset_controllers = reset_controllers;
570 session->kill_processes = kill_processes;
571 session->vtnr = vtnr;
572
573 controllers = reset_controllers = NULL;
574
575 if (!isempty(tty)) {
576 session->tty = strdup(tty);
577 if (!session->tty) {
578 r = -ENOMEM;
579 goto fail;
580 }
581 }
582
583 if (!isempty(display)) {
584 session->display = strdup(display);
585 if (!session->display) {
586 r = -ENOMEM;
587 goto fail;
588 }
589 }
590
591 if (!isempty(remote_user)) {
592 session->remote_user = strdup(remote_user);
593 if (!session->remote_user) {
594 r = -ENOMEM;
595 goto fail;
596 }
597 }
598
599 if (!isempty(remote_host)) {
600 session->remote_host = strdup(remote_host);
601 if (!session->remote_host) {
602 r = -ENOMEM;
603 goto fail;
604 }
605 }
606
607 if (!isempty(service)) {
608 session->service = strdup(service);
609 if (!session->service) {
610 r = -ENOMEM;
611 goto fail;
612 }
613 }
614
932e3ee7
LP
615 fifo_fd = session_create_fifo(session);
616 if (fifo_fd < 0) {
617 r = fifo_fd;
98a28fef
LP
618 goto fail;
619 }
620
98a28fef
LP
621 if (s) {
622 r = seat_attach_session(s, session);
623 if (r < 0)
624 goto fail;
625 }
626
627 r = session_start(session);
628 if (r < 0)
629 goto fail;
630
631 reply = dbus_message_new_method_return(message);
632 if (!reply) {
633 r = -ENOMEM;
634 goto fail;
635 }
636
637 p = session_bus_path(session);
638 if (!p) {
639 r = -ENOMEM;
640 goto fail;
641 }
642
bbc73283 643 seat = s ? s->id : "";
98a28fef
LP
644 b = dbus_message_append_args(
645 reply,
646 DBUS_TYPE_STRING, &session->id,
647 DBUS_TYPE_OBJECT_PATH, &p,
648 DBUS_TYPE_STRING, &session->user->runtime_path,
932e3ee7 649 DBUS_TYPE_UNIX_FD, &fifo_fd,
bbc73283
LP
650 DBUS_TYPE_STRING, &seat,
651 DBUS_TYPE_UINT32, &vtnr,
98a28fef
LP
652 DBUS_TYPE_INVALID);
653 free(p);
654
655 if (!b) {
656 r = -ENOMEM;
657 goto fail;
658 }
659
932e3ee7 660 close_nointr_nofail(fifo_fd);
98a28fef
LP
661 *_reply = reply;
662
663 return 0;
664
665fail:
666 strv_free(controllers);
667 strv_free(reset_controllers);
668
669 if (session)
670 session_add_to_gc_queue(session);
671
672 if (user)
673 user_add_to_gc_queue(user);
674
932e3ee7
LP
675 if (fifo_fd >= 0)
676 close_nointr_nofail(fifo_fd);
98a28fef
LP
677
678 if (reply)
679 dbus_message_unref(reply);
680
681 return r;
682}
683
f8e2fb7b
LP
684static int bus_manager_inhibit(Manager *m, DBusConnection *connection, DBusMessage *message, DBusError *error, DBusMessage **_reply) {
685 Inhibitor *i = NULL;
686 char *id = NULL;
eecd1362 687 const char *who, *why, *what, *mode;
f8e2fb7b
LP
688 pid_t pid;
689 InhibitWhat w;
eecd1362 690 InhibitMode mm;
f8e2fb7b
LP
691 unsigned long ul;
692 int r, fifo_fd = -1;
693 DBusMessage *reply = NULL;
694
695 assert(m);
696 assert(connection);
697 assert(message);
698 assert(error);
699 assert(_reply);
700
701 if (!dbus_message_get_args(
702 message,
703 error,
704 DBUS_TYPE_STRING, &what,
705 DBUS_TYPE_STRING, &who,
706 DBUS_TYPE_STRING, &why,
eecd1362 707 DBUS_TYPE_STRING, &mode,
f8e2fb7b
LP
708 DBUS_TYPE_INVALID)) {
709 r = -EIO;
710 goto fail;
711 }
712
713 w = inhibit_what_from_string(what);
714 if (w <= 0) {
715 r = -EINVAL;
716 goto fail;
717 }
718
eecd1362
LP
719 mm = inhibit_mode_from_string(mode);
720 if (mm < 0) {
721 r = -EINVAL;
722 goto fail;
723 }
724
725 r = verify_polkit(connection, message,
b14eda96
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 (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-idle" : "org.freedesktop.login1.inhibit-delay-idle"),
729 false, NULL, error);
f8e2fb7b
LP
730 if (r < 0)
731 goto fail;
732
733 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
734 if (ul == (unsigned long) -1) {
735 r = -EIO;
736 goto fail;
737 }
738
739 pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
740 if (pid <= 0) {
741 r = -EIO;
742 goto fail;
743 }
744
745 do {
746 free(id);
747 id = NULL;
748
749 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
750 r = -ENOMEM;
751 goto fail;
752 }
753 } while (hashmap_get(m->inhibitors, id));
754
755 r = manager_add_inhibitor(m, id, &i);
756 free(id);
757
758 if (r < 0)
759 goto fail;
760
761 i->what = w;
eecd1362 762 i->mode = mm;
f8e2fb7b
LP
763 i->pid = pid;
764 i->uid = (uid_t) ul;
765 i->why = strdup(why);
766 i->who = strdup(who);
767
768 if (!i->why || !i->who) {
769 r = -ENOMEM;
770 goto fail;
771 }
772
773 fifo_fd = inhibitor_create_fifo(i);
774 if (fifo_fd < 0) {
775 r = fifo_fd;
776 goto fail;
777 }
778
779 reply = dbus_message_new_method_return(message);
780 if (!reply) {
781 r = -ENOMEM;
782 goto fail;
783 }
784
785 if (!dbus_message_append_args(
786 reply,
787 DBUS_TYPE_UNIX_FD, &fifo_fd,
788 DBUS_TYPE_INVALID)) {
789 r = -ENOMEM;
790 goto fail;
791 }
792
793 close_nointr_nofail(fifo_fd);
794 *_reply = reply;
795
796 inhibitor_start(i);
797
798 return 0;
799
800fail:
801 if (i)
802 inhibitor_free(i);
803
804 if (fifo_fd >= 0)
805 close_nointr_nofail(fifo_fd);
806
807 if (reply)
808 dbus_message_unref(reply);
809
810 return r;
811}
812
2eb916cd 813static int trigger_device(Manager *m, struct udev_device *d) {
b668e064
LP
814 struct udev_enumerate *e;
815 struct udev_list_entry *first, *item;
816 int r;
817
818 assert(m);
819
820 e = udev_enumerate_new(m->udev);
821 if (!e) {
822 r = -ENOMEM;
823 goto finish;
824 }
825
2eb916cd
LP
826 if (d) {
827 if (udev_enumerate_add_match_parent(e, d) < 0) {
828 r = -EIO;
829 goto finish;
830 }
831 }
832
b668e064
LP
833 if (udev_enumerate_scan_devices(e) < 0) {
834 r = -EIO;
835 goto finish;
836 }
837
838 first = udev_enumerate_get_list_entry(e);
839 udev_list_entry_foreach(item, first) {
840 char *t;
841 const char *p;
842
843 p = udev_list_entry_get_name(item);
844
b668e064
LP
845 t = strappend(p, "/uevent");
846 if (!t) {
847 r = -ENOMEM;
848 goto finish;
849 }
850
851 write_one_line_file(t, "change");
852 free(t);
853 }
854
855 r = 0;
856
857finish:
858 if (e)
859 udev_enumerate_unref(e);
860
861 return r;
862}
863
47a26690
LP
864static int attach_device(Manager *m, const char *seat, const char *sysfs) {
865 struct udev_device *d;
866 char *rule = NULL, *file = NULL;
c28fa3d3 867 const char *id_for_seat;
47a26690
LP
868 int r;
869
870 assert(m);
871 assert(seat);
872 assert(sysfs);
873
874 d = udev_device_new_from_syspath(m->udev, sysfs);
875 if (!d)
876 return -ENODEV;
877
309c2a2c 878 if (!udev_device_has_tag(d, "seat")) {
47a26690
LP
879 r = -ENODEV;
880 goto finish;
881 }
882
c28fa3d3
LP
883 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
884 if (!id_for_seat) {
47a26690
LP
885 r = -ENODEV;
886 goto finish;
887 }
888
c28fa3d3 889 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
47a26690
LP
890 r = -ENOMEM;
891 goto finish;
892 }
893
c28fa3d3 894 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
47a26690
LP
895 r = -ENOMEM;
896 goto finish;
897 }
898
d2e54fae 899 mkdir_p_label("/etc/udev/rules.d", 0755);
b5ef5549 900 r = write_one_line_file_atomic(file, rule);
a0a0c7f1
LP
901 if (r < 0)
902 goto finish;
903
2eb916cd 904 r = trigger_device(m, d);
47a26690
LP
905
906finish:
907 free(rule);
908 free(file);
909
910 if (d)
911 udev_device_unref(d);
912
913 return r;
914}
915
b668e064
LP
916static int flush_devices(Manager *m) {
917 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 closedir(d);
944 }
945
946 return trigger_device(m, NULL);
947}
948
89f13440
LP
949static int have_multiple_sessions(
950 DBusConnection *connection,
951 Manager *m,
952 DBusMessage *message,
953 DBusError *error) {
954
2154761f
MS
955 Session *session;
956 Iterator i;
957 unsigned long ul;
89f13440
LP
958
959 assert(m);
960
2154761f
MS
961 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
962 if (ul == (unsigned long) -1)
963 return -EIO;
89f13440 964
2154761f
MS
965 /* Check for other users' sessions. Greeter sessions do not count. */
966 HASHMAP_FOREACH(session, m->sessions, i)
967 if (session->class == SESSION_USER && session->user->uid != ul)
968 return true;
89f13440
LP
969
970 return false;
971}
972
d889a206 973static int send_start_unit(DBusConnection *connection, const char *unit_name, DBusError *error) {
eecd1362
LP
974 const char *mode = "replace";
975
d889a206 976 assert(unit_name);
eecd1362 977
b9c26b41
SP
978 return bus_method_call_with_reply (
979 connection,
eecd1362
LP
980 "org.freedesktop.systemd1",
981 "/org/freedesktop/systemd1",
982 "org.freedesktop.systemd1.Manager",
b9c26b41
SP
983 "StartUnit",
984 NULL,
985 NULL,
986 DBUS_TYPE_STRING, &unit_name,
987 DBUS_TYPE_STRING, &mode,
988 DBUS_TYPE_INVALID);
eecd1362
LP
989}
990
d889a206
LP
991static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
992 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
993 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
994 [INHIBIT_SLEEP] = "PrepareForSleep"
995 };
996
eecd1362
LP
997 dbus_bool_t active = _active;
998 DBusMessage *message;
999 int r = 0;
1000
1001 assert(m);
d889a206
LP
1002 assert(w >= 0);
1003 assert(w < _INHIBIT_WHAT_MAX);
1004 assert(signal_name[w]);
eecd1362 1005
d889a206 1006 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
eecd1362
LP
1007 if (!message)
1008 return -ENOMEM;
1009
1010 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1011 !dbus_connection_send(m->bus, message, NULL))
1012 r = -ENOMEM;
1013
1014 dbus_message_unref(message);
1015 return r;
1016}
1017
d889a206 1018static int delay_shutdown_or_sleep(Manager *m, InhibitWhat w, const char *unit_name) {
eecd1362 1019 assert(m);
d889a206
LP
1020 assert(w >= 0);
1021 assert(w < _INHIBIT_WHAT_MAX);
eecd1362 1022
d889a206
LP
1023 /* Tell everybody to prepare for shutdown/sleep */
1024 send_prepare_for(m, w, true);
eecd1362 1025
d889a206
LP
1026 /* Update timestamp for timeout */
1027 if (!m->delayed_unit)
1028 m->delayed_timestamp = now(CLOCK_MONOTONIC);
eecd1362
LP
1029
1030 /* Remember what we want to do, possibly overriding what kind
d889a206
LP
1031 * of unit we previously queued. */
1032 m->delayed_unit = unit_name;
1033 m->delayed_what = w;
1034
1035 return 0;
1036}
1037
1038static int bus_manager_can_shutdown_or_sleep(
1039 Manager *m,
1040 DBusConnection *connection,
1041 DBusMessage *message,
1042 InhibitWhat w,
1043 const char *action,
1044 const char *action_multiple_sessions,
1045 const char *action_ignore_inhibit,
1046 const char *sleep_type,
1047 DBusError *error,
1048 DBusMessage **_reply) {
1049
1050 bool multiple_sessions, challenge, blocked, b;
1051 const char *result;
1052 DBusMessage *reply = NULL;
1053 int r;
1054
1055 assert(m);
1056 assert(connection);
1057 assert(message);
1058 assert(w >= 0);
1059 assert(w <= _INHIBIT_WHAT_MAX);
1060 assert(action);
1061 assert(action_multiple_sessions);
1062 assert(action_ignore_inhibit);
1063 assert(error);
1064 assert(_reply);
1065
1066 if (sleep_type) {
1067 r = can_sleep(sleep_type);
1068 if (r < 0)
1069 return r;
1070
398f7c88
MC
1071 if (r == 0) {
1072 result = "na";
1073 goto finish;
1074 }
d889a206
LP
1075 }
1076
1077 r = have_multiple_sessions(connection, m, message, error);
1078 if (r < 0)
1079 return r;
1080
1081 multiple_sessions = r > 0;
1082 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL);
1083
1084 if (multiple_sessions) {
1085 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1086 if (r < 0)
1087 return r;
1088
1089 if (r > 0)
1090 result = "yes";
d5a745df
LP
1091 else if (challenge)
1092 result = "challenge";
1093 else
1094 result = "no";
1095 }
d889a206
LP
1096
1097 if (blocked) {
1098 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1099 if (r < 0)
1100 return r;
1101
1102 if (r > 0 && !result)
1103 result = "yes";
1104 else if (challenge && (!result || streq(result, "yes")))
1105 result = "challenge";
1106 else
1107 result = "no";
1108 }
1109
1110 if (!multiple_sessions && !blocked) {
1111 /* If neither inhibit nor multiple sessions
1112 * apply then just check the normal policy */
1113
1114 r = verify_polkit(connection, message, action, false, &challenge, error);
1115 if (r < 0)
1116 return r;
1117
1118 if (r > 0)
1119 result = "yes";
1120 else if (challenge)
1121 result = "challenge";
1122 else
1123 result = "no";
1124 }
1125
1126finish:
1127 reply = dbus_message_new_method_return(message);
1128 if (!reply)
1129 return -ENOMEM;
1130
1131 b = dbus_message_append_args(
1132 reply,
1133 DBUS_TYPE_STRING, &result,
1134 DBUS_TYPE_INVALID);
1135 if (!b) {
1136 dbus_message_unref(reply);
1137 return -ENOMEM;
1138 }
1139
1140 *_reply = reply;
1141 return 0;
1142}
1143
877d54e9
LP
1144static int bus_manager_log_shutdown(
1145 Manager *m,
1146 InhibitWhat w,
1147 const char *unit_name) {
1148
1149 const char *p, *q;
1150
1151 assert(m);
1152 assert(unit_name);
1153
1154 if (w != INHIBIT_SHUTDOWN)
1155 return 0;
1156
1157 if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
1158 p = "MESSAGE=System is powering down.";
1159 q = "SHUTDOWN=power-off";
1160 } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
1161 p = "MESSAGE=System is halting.";
1162 q = "SHUTDOWN=halt";
1163 } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
1164 p = "MESSAGE=System is rebooting.";
1165 q = "SHUTDOWN=reboot";
1166 } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
1167 p = "MESSAGE=System is rebooting with kexec.";
1168 q = "SHUTDOWN=kexec";
1169 } else {
1170 p = "MESSAGE=System is shutting down.";
1171 q = NULL;
1172 }
1173
1174 return log_struct(LOG_NOTICE,
1175 "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(SD_MESSAGE_SHUTDOWN),
1176 p,
1177 q, NULL);
1178}
1179
069cfc85
LP
1180int bus_manager_shutdown_or_sleep_now_or_later(
1181 Manager *m,
1182 const char *unit_name,
1183 InhibitWhat w,
1184 DBusError *error) {
1185
1186 bool delayed;
1187 int r;
1188
1189 assert(m);
1190 assert(unit_name);
1191 assert(w >= 0);
1192 assert(w <= _INHIBIT_WHAT_MAX);
1193
1194 delayed =
1195 m->inhibit_delay_max > 0 &&
1196 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL);
1197
1198 if (delayed)
1199 /* Shutdown is delayed, keep in mind what we
1200 * want to do, and start a timeout */
1201 r = delay_shutdown_or_sleep(m, w, unit_name);
877d54e9
LP
1202 else {
1203 bus_manager_log_shutdown(m, w, unit_name);
1204
069cfc85
LP
1205 /* Shutdown is not delayed, execute it
1206 * immediately */
1207 r = send_start_unit(m->bus, unit_name, error);
877d54e9 1208 }
069cfc85
LP
1209
1210 return r;
1211}
1212
d889a206
LP
1213static int bus_manager_do_shutdown_or_sleep(
1214 Manager *m,
1215 DBusConnection *connection,
1216 DBusMessage *message,
1217 const char *unit_name,
1218 InhibitWhat w,
1219 const char *action,
1220 const char *action_multiple_sessions,
1221 const char *action_ignore_inhibit,
1222 const char *sleep_type,
1223 DBusError *error,
1224 DBusMessage **_reply) {
1225
1226 dbus_bool_t interactive;
069cfc85 1227 bool multiple_sessions, blocked;
d889a206
LP
1228 DBusMessage *reply = NULL;
1229 int r;
1230
1231 assert(m);
1232 assert(connection);
1233 assert(message);
1234 assert(unit_name);
1235 assert(w >= 0);
1236 assert(w <= _INHIBIT_WHAT_MAX);
1237 assert(action);
1238 assert(action_multiple_sessions);
1239 assert(action_ignore_inhibit);
1240 assert(error);
1241 assert(_reply);
1242
1243 if (!dbus_message_get_args(
1244 message,
1245 error,
1246 DBUS_TYPE_BOOLEAN, &interactive,
1247 DBUS_TYPE_INVALID))
1248 return -EINVAL;
1249
1250 if (sleep_type) {
1251 r = can_sleep(sleep_type);
1252 if (r < 0)
1253 return r;
1254
1255 if (r == 0)
1256 return -ENOTSUP;
1257 }
1258
1259 r = have_multiple_sessions(connection, m, message, error);
1260 if (r < 0)
1261 return r;
1262
1263 multiple_sessions = r > 0;
1264 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL);
1265
1266 if (multiple_sessions) {
1267 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1268 if (r < 0)
1269 return r;
1270 }
1271
1272 if (blocked) {
1273 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1274 if (r < 0)
1275 return r;
1276 }
1277
1278 if (!multiple_sessions && !blocked) {
1279 r = verify_polkit(connection, message, action, interactive, NULL, error);
1280 if (r < 0)
1281 return r;
1282 }
1283
069cfc85 1284 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
d889a206
LP
1285 if (r < 0)
1286 return r;
1287
1288 reply = dbus_message_new_method_return(message);
1289 if (!reply)
1290 return -ENOMEM;
eecd1362 1291
d889a206 1292 *_reply = reply;
eecd1362
LP
1293 return 0;
1294}
1295
069cfc85
LP
1296static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_button, handle_button, HandleButton);
1297
d200735e
MS
1298static const BusProperty bus_login_manager_properties[] = {
1299 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_path), true },
1300 { "Controllers", bus_property_append_strv, "as", offsetof(Manager, controllers), true },
1301 { "ResetControllers", bus_property_append_strv, "as", offsetof(Manager, reset_controllers), true },
1302 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1303 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1304 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1305 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1306 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1307 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1308 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
eecd1362
LP
1309 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1310 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1311 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
069cfc85
LP
1312 { "HandlePowerKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_power_key) },
1313 { "HandleSleepKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_sleep_key) },
1314 { "HandleLidSwitch", bus_manager_append_handle_button, "s", offsetof(Manager, handle_lid_switch) },
5e4a79da
LP
1315 { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
1316 { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
d200735e
MS
1317 { NULL, }
1318};
1319
3f49d45a
LP
1320static DBusHandlerResult manager_message_handler(
1321 DBusConnection *connection,
1322 DBusMessage *message,
1323 void *userdata) {
1324
1325 Manager *m = userdata;
1326
3f49d45a
LP
1327 DBusError error;
1328 DBusMessage *reply = NULL;
bef422ae 1329 int r;
3f49d45a
LP
1330
1331 assert(connection);
1332 assert(message);
1333 assert(m);
1334
1335 dbus_error_init(&error);
1336
bef422ae
LP
1337 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1338 const char *name;
1339 char *p;
1340 Session *session;
1341 bool b;
1342
1343 if (!dbus_message_get_args(
1344 message,
1345 &error,
1346 DBUS_TYPE_STRING, &name,
1347 DBUS_TYPE_INVALID))
1348 return bus_send_error_reply(connection, message, &error, -EINVAL);
1349
1350 session = hashmap_get(m->sessions, name);
1351 if (!session)
1352 return bus_send_error_reply(connection, message, &error, -ENOENT);
1353
1354 reply = dbus_message_new_method_return(message);
1355 if (!reply)
1356 goto oom;
1357
1358 p = session_bus_path(session);
c4aa65e7
LP
1359 if (!p)
1360 goto oom;
1361
1362 b = dbus_message_append_args(
1363 reply,
1364 DBUS_TYPE_OBJECT_PATH, &p,
1365 DBUS_TYPE_INVALID);
1366 free(p);
1367
1368 if (!b)
1369 goto oom;
1370
1371 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1372 uint32_t pid;
1373 char *p;
1374 Session *session;
1375 bool b;
1376
1377 if (!dbus_message_get_args(
1378 message,
1379 &error,
1380 DBUS_TYPE_UINT32, &pid,
1381 DBUS_TYPE_INVALID))
1382 return bus_send_error_reply(connection, message, &error, -EINVAL);
1383
1384 r = manager_get_session_by_pid(m, pid, &session);
1385 if (r <= 0)
1386 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1387
1388 reply = dbus_message_new_method_return(message);
1389 if (!reply)
1390 goto oom;
1391
1392 p = session_bus_path(session);
bef422ae
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", "GetUser")) {
1406 uint32_t uid;
1407 char *p;
1408 User *user;
1409 bool b;
1410
1411 if (!dbus_message_get_args(
1412 message,
1413 &error,
1414 DBUS_TYPE_UINT32, &uid,
1415 DBUS_TYPE_INVALID))
1416 return bus_send_error_reply(connection, message, &error, -EINVAL);
1417
1418 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1419 if (!user)
1420 return bus_send_error_reply(connection, message, &error, -ENOENT);
1421
1422 reply = dbus_message_new_method_return(message);
1423 if (!reply)
1424 goto oom;
1425
1426 p = user_bus_path(user);
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", "GetSeat")) {
1440 const char *name;
1441 char *p;
1442 Seat *seat;
1443 bool b;
1444
1445 if (!dbus_message_get_args(
1446 message,
1447 &error,
1448 DBUS_TYPE_STRING, &name,
1449 DBUS_TYPE_INVALID))
1450 return bus_send_error_reply(connection, message, &error, -EINVAL);
1451
1452 seat = hashmap_get(m->seats, name);
1453 if (!seat)
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 = seat_bus_path(seat);
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
e1c9c2d5
LP
1473 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1474 char *p;
1475 Session *session;
1476 Iterator i;
1477 DBusMessageIter iter, sub;
1478 const char *empty = "";
1479
1480 reply = dbus_message_new_method_return(message);
1481 if (!reply)
1482 goto oom;
1483
1484 dbus_message_iter_init_append(reply, &iter);
1485
dec15e92 1486 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
e1c9c2d5
LP
1487 goto oom;
1488
1489 HASHMAP_FOREACH(session, m->sessions, i) {
1490 DBusMessageIter sub2;
1491 uint32_t uid;
1492
1493 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1494 goto oom;
1495
1496 uid = session->user->uid;
1497
1498 p = session_bus_path(session);
1499 if (!p)
1500 goto oom;
1501
1502 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1503 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1504 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1505 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1506 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1507 free(p);
1508 goto oom;
1509 }
1510
1511 free(p);
1512
1513 if (!dbus_message_iter_close_container(&sub, &sub2))
1514 goto oom;
1515 }
1516
1517 if (!dbus_message_iter_close_container(&iter, &sub))
1518 goto oom;
1519
1520 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1521 char *p;
1522 User *user;
1523 Iterator i;
1524 DBusMessageIter iter, sub;
1525
1526 reply = dbus_message_new_method_return(message);
1527 if (!reply)
1528 goto oom;
1529
1530 dbus_message_iter_init_append(reply, &iter);
1531
dec15e92 1532 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
e1c9c2d5
LP
1533 goto oom;
1534
1535 HASHMAP_FOREACH(user, m->users, i) {
1536 DBusMessageIter sub2;
1537 uint32_t uid;
1538
1539 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1540 goto oom;
1541
1542 uid = user->uid;
1543
1544 p = user_bus_path(user);
1545 if (!p)
1546 goto oom;
1547
1548 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1549 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1550 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1551 free(p);
1552 goto oom;
1553 }
1554
1555 free(p);
1556
1557 if (!dbus_message_iter_close_container(&sub, &sub2))
1558 goto oom;
1559 }
1560
1561 if (!dbus_message_iter_close_container(&iter, &sub))
1562 goto oom;
1563
1564 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1565 char *p;
1566 Seat *seat;
1567 Iterator i;
1568 DBusMessageIter iter, sub;
1569
1570 reply = dbus_message_new_method_return(message);
1571 if (!reply)
1572 goto oom;
1573
1574 dbus_message_iter_init_append(reply, &iter);
1575
dec15e92 1576 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
e1c9c2d5
LP
1577 goto oom;
1578
1579 HASHMAP_FOREACH(seat, m->seats, i) {
1580 DBusMessageIter sub2;
1581
1582 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1583 goto oom;
1584
1585 p = seat_bus_path(seat);
1586 if (!p)
1587 goto oom;
1588
1589 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1590 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1591 free(p);
1592 goto oom;
1593 }
1594
1595 free(p);
1596
1597 if (!dbus_message_iter_close_container(&sub, &sub2))
1598 goto oom;
1599 }
1600
1601 if (!dbus_message_iter_close_container(&iter, &sub))
1602 goto oom;
1603
f8e2fb7b
LP
1604 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1605 Inhibitor *inhibitor;
1606 Iterator i;
1607 DBusMessageIter iter, sub;
1608
1609 reply = dbus_message_new_method_return(message);
1610 if (!reply)
1611 goto oom;
1612
1613 dbus_message_iter_init_append(reply, &iter);
1614
eecd1362 1615 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
f8e2fb7b
LP
1616 goto oom;
1617
1618 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1619 DBusMessageIter sub2;
1620 dbus_uint32_t uid, pid;
eecd1362 1621 const char *what, *who, *why, *mode;
f8e2fb7b
LP
1622
1623 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1624 goto oom;
1625
eecd1362 1626 what = strempty(inhibit_what_to_string(inhibitor->what));
f8e2fb7b
LP
1627 who = strempty(inhibitor->who);
1628 why = strempty(inhibitor->why);
eecd1362 1629 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
f8e2fb7b
LP
1630 uid = (dbus_uint32_t) inhibitor->uid;
1631 pid = (dbus_uint32_t) inhibitor->pid;
1632
1633 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1634 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1635 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
eecd1362 1636 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
f8e2fb7b
LP
1637 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1638 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1639 goto oom;
1640
1641 if (!dbus_message_iter_close_container(&sub, &sub2))
1642 goto oom;
1643 }
1644
1645 if (!dbus_message_iter_close_container(&iter, &sub))
1646 goto oom;
1647
1648 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1649
1650 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1651
1652 if (r < 0)
1653 return bus_send_error_reply(connection, message, &error, r);
1654
1655
98a28fef
LP
1656 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1657
1658 r = bus_manager_create_session(m, message, &reply);
688c56ff
LP
1659
1660 /* Don't delay the work on OOM here, since it might be
1661 * triggered by a low RLIMIT_NOFILE here (since we
1662 * send a dupped fd to the client), and we'd rather
1663 * see this fail quickly then be retried later */
98a28fef
LP
1664
1665 if (r < 0)
f8e2fb7b 1666 return bus_send_error_reply(connection, message, NULL, r);
98a28fef 1667
75c8e3cf
LP
1668 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1669 const char *name;
1670 Session *session;
1671
1672 if (!dbus_message_get_args(
1673 message,
1674 &error,
1675 DBUS_TYPE_STRING, &name,
1676 DBUS_TYPE_INVALID))
1677 return bus_send_error_reply(connection, message, &error, -EINVAL);
1678
1679 session = hashmap_get(m->sessions, name);
1680 if (!session)
1681 return bus_send_error_reply(connection, message, &error, -ENOENT);
1682
1683 /* We use the FIFO to detect stray sessions where the
1684 process invoking PAM dies abnormally. We need to make
1685 sure that that process is not killed if at the clean
1686 end of the session it closes the FIFO. Hence, with
1687 this call explicitly turn off the FIFO logic, so that
1688 the PAM code can finish clean up on its own */
1689 session_remove_fifo(session);
1690
1691 reply = dbus_message_new_method_return(message);
1692 if (!reply)
1693 goto oom;
1694
bef422ae
LP
1695 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1696 const char *name;
1697 Session *session;
1698
1699 if (!dbus_message_get_args(
1700 message,
1701 &error,
1702 DBUS_TYPE_STRING, &name,
1703 DBUS_TYPE_INVALID))
1704 return bus_send_error_reply(connection, message, &error, -EINVAL);
1705
1706 session = hashmap_get(m->sessions, name);
1707 if (!session)
1708 return bus_send_error_reply(connection, message, &error, -ENOENT);
1709
1710 r = session_activate(session);
1711 if (r < 0)
1712 return bus_send_error_reply(connection, message, NULL, r);
1713
1714 reply = dbus_message_new_method_return(message);
1715 if (!reply)
1716 goto oom;
1717
84c3361e
LP
1718 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1719 const char *session_name, *seat_name;
1720 Session *session;
1721 Seat *seat;
1722
1723 /* Same as ActivateSession() but refuses to work if
1724 * the seat doesn't match */
1725
1726 if (!dbus_message_get_args(
1727 message,
1728 &error,
1729 DBUS_TYPE_STRING, &session_name,
1730 DBUS_TYPE_STRING, &seat_name,
1731 DBUS_TYPE_INVALID))
1732 return bus_send_error_reply(connection, message, &error, -EINVAL);
1733
1734 session = hashmap_get(m->sessions, session_name);
1735 if (!session)
1736 return bus_send_error_reply(connection, message, &error, -ENOENT);
1737
1738 seat = hashmap_get(m->seats, seat_name);
1739 if (!seat)
1740 return bus_send_error_reply(connection, message, &error, -ENOENT);
1741
1742 if (session->seat != seat)
1743 return bus_send_error_reply(connection, message, &error, -EINVAL);
1744
1745 r = session_activate(session);
1746 if (r < 0)
1747 return bus_send_error_reply(connection, message, NULL, r);
1748
1749 reply = dbus_message_new_method_return(message);
1750 if (!reply)
1751 goto oom;
1752
88e3dc90
LP
1753 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1754 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1755 const char *name;
1756 Session *session;
1757
1758 if (!dbus_message_get_args(
1759 message,
1760 &error,
1761 DBUS_TYPE_STRING, &name,
1762 DBUS_TYPE_INVALID))
1763 return bus_send_error_reply(connection, message, &error, -EINVAL);
1764
1765 session = hashmap_get(m->sessions, name);
1766 if (!session)
1767 return bus_send_error_reply(connection, message, &error, -ENOENT);
1768
1769 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1770 goto oom;
1771
1772 reply = dbus_message_new_method_return(message);
1773 if (!reply)
1774 goto oom;
1775
fa2b196d
LP
1776 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions")) {
1777 Session *session;
1778 Iterator i;
1779
1780 HASHMAP_FOREACH(session, m->sessions, i)
1781 if (session_send_lock(session, true) < 0)
1782 goto oom;
1783
1784 reply = dbus_message_new_method_return(message);
1785 if (!reply)
1786 goto oom;
1787
de07ab16
LP
1788 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1789 const char *swho;
1790 int32_t signo;
1791 KillWho who;
1792 const char *name;
1793 Session *session;
1794
1795 if (!dbus_message_get_args(
1796 message,
1797 &error,
1798 DBUS_TYPE_STRING, &name,
1799 DBUS_TYPE_STRING, &swho,
1800 DBUS_TYPE_INT32, &signo,
1801 DBUS_TYPE_INVALID))
1802 return bus_send_error_reply(connection, message, &error, -EINVAL);
1803
1804 if (isempty(swho))
1805 who = KILL_ALL;
1806 else {
1807 who = kill_who_from_string(swho);
1808 if (who < 0)
1809 return bus_send_error_reply(connection, message, &error, -EINVAL);
1810 }
1811
1812 if (signo <= 0 || signo >= _NSIG)
1813 return bus_send_error_reply(connection, message, &error, -EINVAL);
1814
1815 session = hashmap_get(m->sessions, name);
1816 if (!session)
1817 return bus_send_error_reply(connection, message, &error, -ENOENT);
1818
1819 r = session_kill(session, who, signo);
1820 if (r < 0)
1821 return bus_send_error_reply(connection, message, NULL, r);
1822
1823 reply = dbus_message_new_method_return(message);
1824 if (!reply)
1825 goto oom;
1826
1827 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1828 uint32_t uid;
1829 User *user;
1830 int32_t signo;
1831
1832 if (!dbus_message_get_args(
1833 message,
1834 &error,
1835 DBUS_TYPE_UINT32, &uid,
1836 DBUS_TYPE_INT32, &signo,
1837 DBUS_TYPE_INVALID))
1838 return bus_send_error_reply(connection, message, &error, -EINVAL);
1839
1840 if (signo <= 0 || signo >= _NSIG)
1841 return bus_send_error_reply(connection, message, &error, -EINVAL);
1842
1843 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1844 if (!user)
1845 return bus_send_error_reply(connection, message, &error, -ENOENT);
1846
1847 r = user_kill(user, signo);
1848 if (r < 0)
1849 return bus_send_error_reply(connection, message, NULL, r);
1850
1851 reply = dbus_message_new_method_return(message);
1852 if (!reply)
1853 goto oom;
1854
bef422ae
LP
1855 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
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_INVALID))
1864 return bus_send_error_reply(connection, message, &error, -EINVAL);
1865
1866 session = hashmap_get(m->sessions, name);
1867 if (!session)
1868 return bus_send_error_reply(connection, message, &error, -ENOENT);
1869
1870 r = session_stop(session);
1871 if (r < 0)
1872 return bus_send_error_reply(connection, message, NULL, r);
1873
1874 reply = dbus_message_new_method_return(message);
1875 if (!reply)
1876 goto oom;
1877
1878 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1879 uint32_t uid;
1880 User *user;
1881
1882 if (!dbus_message_get_args(
1883 message,
1884 &error,
1885 DBUS_TYPE_UINT32, &uid,
1886 DBUS_TYPE_INVALID))
1887 return bus_send_error_reply(connection, message, &error, -EINVAL);
1888
1889 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1890 if (!user)
1891 return bus_send_error_reply(connection, message, &error, -ENOENT);
1892
1893 r = user_stop(user);
1894 if (r < 0)
1895 return bus_send_error_reply(connection, message, NULL, r);
1896
1897 reply = dbus_message_new_method_return(message);
1898 if (!reply)
1899 goto oom;
1900
1901 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1902 const char *name;
1903 Seat *seat;
1904
1905 if (!dbus_message_get_args(
1906 message,
1907 &error,
1908 DBUS_TYPE_STRING, &name,
1909 DBUS_TYPE_INVALID))
1910 return bus_send_error_reply(connection, message, &error, -EINVAL);
1911
1912 seat = hashmap_get(m->seats, name);
1913 if (!seat)
1914 return bus_send_error_reply(connection, message, &error, -ENOENT);
1915
1916 r = seat_stop_sessions(seat);
1917 if (r < 0)
1918 return bus_send_error_reply(connection, message, NULL, r);
1919
1920 reply = dbus_message_new_method_return(message);
1921 if (!reply)
1922 goto oom;
1923
7f7bb946
LP
1924 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
1925 uint32_t uid;
1926 struct passwd *pw;
1927 dbus_bool_t b, interactive;
1928 char *path;
1929
1930 if (!dbus_message_get_args(
1931 message,
1932 &error,
1933 DBUS_TYPE_UINT32, &uid,
1934 DBUS_TYPE_BOOLEAN, &b,
1935 DBUS_TYPE_BOOLEAN, &interactive,
1936 DBUS_TYPE_INVALID))
1937 return bus_send_error_reply(connection, message, &error, -EINVAL);
1938
1939 errno = 0;
1940 pw = getpwuid(uid);
1941 if (!pw)
1942 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
1943
89f13440 1944 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
7f7bb946
LP
1945 if (r < 0)
1946 return bus_send_error_reply(connection, message, &error, r);
1947
d2e54fae 1948 mkdir_p_label("/var/lib/systemd", 0755);
02b16a19 1949
d2e54fae 1950 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
7f7bb946
LP
1951 if (r < 0)
1952 return bus_send_error_reply(connection, message, &error, r);
1953
1954 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
1955 if (!path)
1956 goto oom;
1957
1958 if (b) {
38f3fc7d
LP
1959 User *u;
1960
7f7bb946
LP
1961 r = touch(path);
1962 free(path);
1963
1964 if (r < 0)
1965 return bus_send_error_reply(connection, message, &error, r);
38f3fc7d
LP
1966
1967 if (manager_add_user_by_uid(m, uid, &u) >= 0)
1968 user_start(u);
1969
7f7bb946 1970 } else {
38f3fc7d
LP
1971 User *u;
1972
7f7bb946
LP
1973 r = unlink(path);
1974 free(path);
1975
1976 if (r < 0 && errno != ENOENT)
1977 return bus_send_error_reply(connection, message, &error, -errno);
38f3fc7d
LP
1978
1979 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1980 if (u)
1981 user_add_to_gc_queue(u);
7f7bb946
LP
1982 }
1983
1984 reply = dbus_message_new_method_return(message);
1985 if (!reply)
1986 goto oom;
1987
47a26690
LP
1988 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
1989 const char *sysfs, *seat;
1990 dbus_bool_t interactive;
1991
1992 if (!dbus_message_get_args(
1993 message,
1994 &error,
1995 DBUS_TYPE_STRING, &seat,
1996 DBUS_TYPE_STRING, &sysfs,
1997 DBUS_TYPE_BOOLEAN, &interactive,
1998 DBUS_TYPE_INVALID))
1999 return bus_send_error_reply(connection, message, &error, -EINVAL);
2000
2001 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
2002 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2003
89f13440 2004 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
47a26690
LP
2005 if (r < 0)
2006 return bus_send_error_reply(connection, message, &error, r);
2007
2008 r = attach_device(m, seat, sysfs);
2009 if (r < 0)
2010 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2011
2012 reply = dbus_message_new_method_return(message);
2013 if (!reply)
2014 goto oom;
7f7bb946 2015
b668e064
LP
2016
2017 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
2018 dbus_bool_t interactive;
2019
2020 if (!dbus_message_get_args(
2021 message,
2022 &error,
2023 DBUS_TYPE_BOOLEAN, &interactive,
2024 DBUS_TYPE_INVALID))
2025 return bus_send_error_reply(connection, message, &error, -EINVAL);
2026
89f13440 2027 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
b668e064
LP
2028 if (r < 0)
2029 return bus_send_error_reply(connection, message, &error, r);
2030
2031 r = flush_devices(m);
2032 if (r < 0)
2033 return bus_send_error_reply(connection, message, NULL, -EINVAL);
2034
2035 reply = dbus_message_new_method_return(message);
2036 if (!reply)
2037 goto oom;
2038
d889a206
LP
2039 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
2040
2041 r = bus_manager_do_shutdown_or_sleep(
2042 m, connection, message,
2043 SPECIAL_POWEROFF_TARGET,
2044 INHIBIT_SHUTDOWN,
2045 "org.freedesktop.login1.power-off",
2046 "org.freedesktop.login1.power-off-multiple-sessions",
2047 "org.freedesktop.login1.power-off-ignore-inhibit",
2048 NULL,
2049 &error, &reply);
89f13440
LP
2050 if (r < 0)
2051 return bus_send_error_reply(connection, message, &error, r);
d889a206
LP
2052 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
2053 r = bus_manager_do_shutdown_or_sleep(
2054 m, connection, message,
2055 SPECIAL_REBOOT_TARGET,
2056 INHIBIT_SHUTDOWN,
2057 "org.freedesktop.login1.reboot",
2058 "org.freedesktop.login1.reboot-multiple-sessions",
2059 "org.freedesktop.login1.reboot-ignore-inhibit",
2060 NULL,
2061 &error, &reply);
89f13440
LP
2062 if (r < 0)
2063 return bus_send_error_reply(connection, message, &error, r);
2064
d889a206
LP
2065 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2066 r = bus_manager_do_shutdown_or_sleep(
2067 m, connection, message,
2068 SPECIAL_SUSPEND_TARGET,
2069 INHIBIT_SLEEP,
2070 "org.freedesktop.login1.suspend",
2071 "org.freedesktop.login1.suspend-multiple-sessions",
2072 "org.freedesktop.login1.suspend-ignore-inhibit",
2073 "mem",
2074 &error, &reply);
2075 if (r < 0)
2076 return bus_send_error_reply(connection, message, &error, r);
2077 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2078 r = bus_manager_do_shutdown_or_sleep(
2079 m, connection, message,
2080 SPECIAL_HIBERNATE_TARGET,
2081 INHIBIT_SLEEP,
2082 "org.freedesktop.login1.hibernate",
2083 "org.freedesktop.login1.hibernate-multiple-sessions",
2084 "org.freedesktop.login1.hibernate-ignore-inhibit",
2085 "disk",
2086 &error, &reply);
2087 if (r < 0)
2088 return bus_send_error_reply(connection, message, &error, r);
f8e2fb7b 2089
d889a206 2090 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
f8e2fb7b 2091
d889a206
LP
2092 r = bus_manager_can_shutdown_or_sleep(
2093 m, connection, message,
2094 INHIBIT_SHUTDOWN,
2095 "org.freedesktop.login1.power-off",
2096 "org.freedesktop.login1.power-off-multiple-sessions",
2097 "org.freedesktop.login1.power-off-ignore-inhibit",
2098 NULL,
2099 &error, &reply);
2100 if (r < 0)
2101 return bus_send_error_reply(connection, message, &error, r);
2102 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2103 r = bus_manager_can_shutdown_or_sleep(
2104 m, connection, message,
2105 INHIBIT_SHUTDOWN,
2106 "org.freedesktop.login1.reboot",
2107 "org.freedesktop.login1.reboot-multiple-sessions",
2108 "org.freedesktop.login1.reboot-ignore-inhibit",
2109 NULL,
2110 &error, &reply);
2111 if (r < 0)
2112 return bus_send_error_reply(connection, message, &error, r);
89f13440 2113
d889a206
LP
2114 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2115 r = bus_manager_can_shutdown_or_sleep(
2116 m, connection, message,
2117 INHIBIT_SLEEP,
2118 "org.freedesktop.login1.suspend",
2119 "org.freedesktop.login1.suspend-multiple-sessions",
2120 "org.freedesktop.login1.suspend-ignore-inhibit",
2121 "mem",
2122 &error, &reply);
2123 if (r < 0)
2124 return bus_send_error_reply(connection, message, &error, r);
89f13440 2125
d889a206
LP
2126 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2127 r = bus_manager_can_shutdown_or_sleep(
2128 m, connection, message,
2129 INHIBIT_SLEEP,
2130 "org.freedesktop.login1.hibernate",
2131 "org.freedesktop.login1.hibernate-multiple-sessions",
2132 "org.freedesktop.login1.hibernate-ignore-inhibit",
2133 "disk",
2134 &error, &reply);
2135 if (r < 0)
2136 return bus_send_error_reply(connection, message, &error, r);
89f13440 2137
bef422ae 2138 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
3f49d45a
LP
2139 char *introspection = NULL;
2140 FILE *f;
2141 Iterator i;
2142 Session *session;
2143 Seat *seat;
2144 User *user;
2145 size_t size;
2146 char *p;
2147
2148 if (!(reply = dbus_message_new_method_return(message)))
2149 goto oom;
2150
2151 /* We roll our own introspection code here, instead of
2152 * relying on bus_default_message_handler() because we
2153 * need to generate our introspection string
2154 * dynamically. */
2155
2156 if (!(f = open_memstream(&introspection, &size)))
2157 goto oom;
2158
2159 fputs(INTROSPECTION_BEGIN, f);
2160
2161 HASHMAP_FOREACH(seat, m->seats, i) {
2162 p = bus_path_escape(seat->id);
2163
2164 if (p) {
2165 fprintf(f, "<node name=\"seat/%s\"/>", p);
2166 free(p);
2167 }
2168 }
2169
2170 HASHMAP_FOREACH(user, m->users, i)
2171 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2172
2173 HASHMAP_FOREACH(session, m->sessions, i) {
2174 p = bus_path_escape(session->id);
2175
2176 if (p) {
2177 fprintf(f, "<node name=\"session/%s\"/>", p);
2178 free(p);
2179 }
2180 }
2181
2182 fputs(INTROSPECTION_END, f);
2183
2184 if (ferror(f)) {
2185 fclose(f);
2186 free(introspection);
2187 goto oom;
2188 }
2189
2190 fclose(f);
2191
2192 if (!introspection)
2193 goto oom;
2194
2195 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2196 free(introspection);
2197 goto oom;
2198 }
2199
2200 free(introspection);
d200735e
MS
2201 } else {
2202 const BusBoundProperties bps[] = {
2203 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2204 { NULL, }
2205 };
2206 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2207 }
3f49d45a
LP
2208
2209 if (reply) {
2210 if (!dbus_connection_send(connection, reply, NULL))
2211 goto oom;
2212
2213 dbus_message_unref(reply);
2214 }
2215
2216 return DBUS_HANDLER_RESULT_HANDLED;
2217
2218oom:
2219 if (reply)
2220 dbus_message_unref(reply);
2221
2222 dbus_error_free(&error);
2223
2224 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2225}
2226
2227const DBusObjectPathVTable bus_manager_vtable = {
2228 .message_function = manager_message_handler
2229};
9418f147 2230
1713813d
LP
2231DBusHandlerResult bus_message_filter(
2232 DBusConnection *connection,
2233 DBusMessage *message,
2234 void *userdata) {
2235
2236 Manager *m = userdata;
2237 DBusError error;
2238
2239 assert(m);
2240 assert(connection);
2241 assert(message);
2242
2243 dbus_error_init(&error);
2244
2245 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
2246 const char *cgroup;
2247
2248 if (!dbus_message_get_args(message, &error,
2249 DBUS_TYPE_STRING, &cgroup,
2250 DBUS_TYPE_INVALID))
2251 log_error("Failed to parse Released message: %s", bus_error_message(&error));
2252 else
2253 manager_cgroup_notify_empty(m, cgroup);
2254 }
2255
2256 dbus_error_free(&error);
2257
2258 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2259}
2260
9418f147
LP
2261int manager_send_changed(Manager *manager, const char *properties) {
2262 DBusMessage *m;
2263 int r = -ENOMEM;
2264
2265 assert(manager);
2266
2267 m = bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties);
2268 if (!m)
2269 goto finish;
2270
2271 if (!dbus_connection_send(manager->bus, m, NULL))
2272 goto finish;
2273
2274 r = 0;
2275
2276finish:
2277 if (m)
2278 dbus_message_unref(m);
2279
2280 return r;
2281}
eecd1362 2282
d889a206
LP
2283int manager_dispatch_delayed(Manager *manager) {
2284 const char *unit_name;
eecd1362
LP
2285 DBusError error;
2286 bool delayed;
2287 int r;
2288
2289 assert(manager);
2290
d889a206 2291 if (!manager->delayed_unit)
eecd1362
LP
2292 return 0;
2293
2294 /* Continue delay? */
2295 delayed =
d889a206
LP
2296 manager->delayed_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC) &&
2297 manager_is_inhibited(manager, manager->delayed_what, INHIBIT_DELAY, NULL);
eecd1362
LP
2298 if (delayed)
2299 return 0;
2300
877d54e9
LP
2301 bus_manager_log_shutdown(manager, manager->delayed_what, manager->delayed_unit);
2302
eecd1362 2303 /* Reset delay data */
d889a206
LP
2304 unit_name = manager->delayed_unit;
2305 manager->delayed_unit = NULL;
eecd1362
LP
2306
2307 /* Actually do the shutdown */
2308 dbus_error_init(&error);
d889a206 2309 r = send_start_unit(manager->bus, unit_name, &error);
eecd1362 2310 if (r < 0) {
d889a206
LP
2311 log_warning("Failed to send delayed message: %s", bus_error_message_or_strerror(&error, -r));
2312 dbus_error_free(&error);
eecd1362
LP
2313 return r;
2314 }
2315
2316 /* Tell people about it */
d889a206 2317 send_prepare_for(manager, manager->delayed_what, false);
eecd1362
LP
2318
2319 return 1;
2320}