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