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