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