]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/logind-dbus.c
util: split-out path-util.[ch]
[thirdparty/systemd.git] / src / login / logind-dbus.c
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
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
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
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <pwd.h>
26
27 #include "logind.h"
28 #include "dbus-common.h"
29 #include "strv.h"
30 #include "mkdir.h"
31 #include "path-util.h"
32 #include "polkit.h"
33 #include "special.h"
34
35 #define BUS_MANAGER_INTERFACE \
36 " <interface name=\"org.freedesktop.login1.Manager\">\n" \
37 " <method name=\"GetSession\">\n" \
38 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
39 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
40 " </method>\n" \
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" \
45 " <method name=\"GetUser\">\n" \
46 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
47 " <arg name=\"user\" type=\"o\" direction=\"out\"/>\n" \
48 " </method>\n" \
49 " <method name=\"GetSeat\">\n" \
50 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
51 " <arg name=\"seat\" type=\"o\" direction=\"out\"/>\n" \
52 " </method>\n" \
53 " <method name=\"ListSessions\">\n" \
54 " <arg name=\"sessions\" type=\"a(susso)\" direction=\"out\"/>\n" \
55 " </method>\n" \
56 " <method name=\"ListUsers\">\n" \
57 " <arg name=\"users\" type=\"a(uso)\" direction=\"out\"/>\n" \
58 " </method>\n" \
59 " <method name=\"ListSeats\">\n" \
60 " <arg name=\"seats\" type=\"a(so)\" direction=\"out\"/>\n" \
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" \
65 " <arg name=\"sevice\" type=\"s\" direction=\"in\"/>\n" \
66 " <arg name=\"type\" type=\"s\" direction=\"in\"/>\n" \
67 " <arg name=\"class\" type=\"s\" direction=\"in\"/>\n" \
68 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
69 " <arg name=\"vtnr\" type=\"u\" direction=\"in\"/>\n" \
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" \
77 " <arg name=\"kill_processes\" type=\"b\" direction=\"in\"/>\n" \
78 " <arg name=\"id\" type=\"s\" direction=\"out\"/>\n" \
79 " <arg name=\"path\" type=\"o\" direction=\"out\"/>\n" \
80 " <arg name=\"runtime_path\" type=\"o\" direction=\"out\"/>\n" \
81 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
82 " <arg name=\"seat\" type=\"s\" direction=\"out\"/>\n" \
83 " <arg name=\"vtnr\" type=\"u\" direction=\"out\"/>\n" \
84 " </method>\n" \
85 " <method name=\"ReleaseSession\">\n" \
86 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
87 " </method>\n" \
88 " <method name=\"ActivateSession\">\n" \
89 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
90 " </method>\n" \
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" \
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" \
101 " <method name=\"KillSession\">\n" \
102 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
103 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
104 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
105 " </method>\n" \
106 " <method name=\"KillUser\">\n" \
107 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
108 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
109 " </method>\n" \
110 " <method name=\"TerminateSession\">\n" \
111 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
112 " </method>\n" \
113 " <method name=\"TerminateUser\">\n" \
114 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
115 " </method>\n" \
116 " <method name=\"TerminateSeat\">\n" \
117 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
118 " </method>\n" \
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" \
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" \
129 " <method name=\"FlushDevices\">\n" \
130 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
131 " </method>\n" \
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" \
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" \
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" \
148 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
149 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
150 " </method>\n" \
151 " <method name=\"ListInhibitors\">\n" \
152 " <arg name=\"inhibitors\" type=\"a(ssssuu)\" direction=\"out\"/>\n" \
153 " </method>\n" \
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" \
178 " <signal name=\"PrepareForShutdown\">\n" \
179 " <arg name=\"active\" type=\"b\"/>\n" \
180 " </signal>\n" \
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" \
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" \
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" \
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
211 static int bus_manager_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
212 Manager *m = data;
213 dbus_bool_t b;
214
215 assert(i);
216 assert(property);
217 assert(m);
218
219 b = manager_get_idle_hint(m, NULL) > 0;
220 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
221 return -ENOMEM;
222
223 return 0;
224 }
225
226 static 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
244 static int bus_manager_append_inhibited(DBusMessageIter *i, const char *property, void *data) {
245 Manager *m = data;
246 InhibitWhat w;
247 const char *p;
248
249 w = manager_inhibit_what(m, streq(property, "BlockInhibited") ? INHIBIT_BLOCK : INHIBIT_DELAY);
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
258 static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMessage **_reply) {
259 Session *session = NULL;
260 User *user = NULL;
261 const char *type, *class, *seat, *tty, *display, *remote_user, *remote_host, *service;
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;
266 SessionClass c;
267 Seat *s;
268 DBusMessageIter iter;
269 int r;
270 char *id = NULL, *p;
271 uint32_t vtnr = 0;
272 int fifo_fd = -1;
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
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
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
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
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)) {
345 int v;
346
347 if (!s)
348 s = m->vtconsole;
349 else if (s != m->vtconsole)
350 return -EINVAL;
351
352 v = vtnr_from_tty(tty);
353
354 if (v <= 0)
355 return v < 0 ? v : -EINVAL;
356
357 if (vtnr <= 0)
358 vtnr = (uint32_t) v;
359 else if (vtnr != (uint32_t) v)
360 return -EINVAL;
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;
370
371 } else if (!isempty(tty) && s && seat_is_vtconsole(s))
372 return -EINVAL;
373
374 if (s) {
375 if (seat_can_multi_session(s)) {
376 if (vtnr > 63)
377 return -EINVAL;
378 } else {
379 if (vtnr != 0)
380 return -EINVAL;
381 }
382 }
383
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
417 if (strv_contains(controllers, "systemd") ||
418 !dbus_message_iter_next(&iter) ||
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
429 if (strv_contains(reset_controllers, "systemd") ||
430 !dbus_message_iter_next(&iter) ||
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
444 if (audit_id > 0) {
445 asprintf(&id, "%lu", (unsigned long) audit_id);
446
447 if (!id) {
448 r = -ENOMEM;
449 goto fail;
450 }
451
452 session = hashmap_get(m->sessions, id);
453
454 if (session) {
455 free(id);
456
457 fifo_fd = session_create_fifo(session);
458 if (fifo_fd < 0) {
459 r = fifo_fd;
460 goto fail;
461 }
462
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
473 p = session_bus_path(session);
474 if (!p) {
475 r = -ENOMEM;
476 goto fail;
477 }
478
479 seat = session->seat ? session->seat->id : "";
480 vtnr = session->vtnr;
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,
486 DBUS_TYPE_UNIX_FD, &fifo_fd,
487 DBUS_TYPE_STRING, &seat,
488 DBUS_TYPE_UINT32, &vtnr,
489 DBUS_TYPE_INVALID);
490 free(p);
491
492 if (!b) {
493 r = -ENOMEM;
494 goto fail;
495 }
496
497 close_nointr_nofail(fifo_fd);
498 *_reply = reply;
499
500 strv_free(controllers);
501 strv_free(reset_controllers);
502
503 return 0;
504 }
505
506 } else {
507 do {
508 free(id);
509 id = NULL;
510
511 if (asprintf(&id, "c%lu", ++m->session_counter) < 0) {
512 r = -ENOMEM;
513 goto fail;
514 }
515
516 } while (hashmap_get(m->sessions, id));
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;
527 session->class = c;
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
576 fifo_fd = session_create_fifo(session);
577 if (fifo_fd < 0) {
578 r = fifo_fd;
579 goto fail;
580 }
581
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
604 seat = s ? s->id : "";
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,
610 DBUS_TYPE_UNIX_FD, &fifo_fd,
611 DBUS_TYPE_STRING, &seat,
612 DBUS_TYPE_UINT32, &vtnr,
613 DBUS_TYPE_INVALID);
614 free(p);
615
616 if (!b) {
617 r = -ENOMEM;
618 goto fail;
619 }
620
621 close_nointr_nofail(fifo_fd);
622 *_reply = reply;
623
624 return 0;
625
626 fail:
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
636 if (fifo_fd >= 0)
637 close_nointr_nofail(fifo_fd);
638
639 if (reply)
640 dbus_message_unref(reply);
641
642 return r;
643 }
644
645 static int bus_manager_inhibit(Manager *m, DBusConnection *connection, DBusMessage *message, DBusError *error, DBusMessage **_reply) {
646 Inhibitor *i = NULL;
647 char *id = NULL;
648 const char *who, *why, *what, *mode;
649 pid_t pid;
650 InhibitWhat w;
651 InhibitMode mm;
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,
668 DBUS_TYPE_STRING, &mode,
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
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);
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;
722 i->mode = mm;
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
760 fail:
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
773 static int trigger_device(Manager *m, struct udev_device *d) {
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
786 if (d) {
787 if (udev_enumerate_add_match_parent(e, d) < 0) {
788 r = -EIO;
789 goto finish;
790 }
791 }
792
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
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
817 finish:
818 if (e)
819 udev_enumerate_unref(e);
820
821 return r;
822 }
823
824 static int attach_device(Manager *m, const char *seat, const char *sysfs) {
825 struct udev_device *d;
826 char *rule = NULL, *file = NULL;
827 const char *id_for_seat;
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
838 if (!udev_device_has_tag(d, "seat")) {
839 r = -ENODEV;
840 goto finish;
841 }
842
843 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
844 if (!id_for_seat) {
845 r = -ENODEV;
846 goto finish;
847 }
848
849 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
850 r = -ENOMEM;
851 goto finish;
852 }
853
854 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
855 r = -ENOMEM;
856 goto finish;
857 }
858
859 mkdir_p("/etc/udev/rules.d", 0755);
860 r = write_one_line_file_atomic(file, rule);
861 if (r < 0)
862 goto finish;
863
864 r = trigger_device(m, d);
865
866 finish:
867 free(rule);
868 free(file);
869
870 if (d)
871 udev_device_unref(d);
872
873 return r;
874 }
875
876 static 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
909 static 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
940 static 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
973 static 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
992 static 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
1010 static 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 },
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) },
1024 { NULL, }
1025 };
1026
1027 static DBusHandlerResult manager_message_handler(
1028 DBusConnection *connection,
1029 DBusMessage *message,
1030 void *userdata) {
1031
1032 Manager *m = userdata;
1033
1034 DBusError error;
1035 DBusMessage *reply = NULL;
1036 int r;
1037
1038 assert(connection);
1039 assert(message);
1040 assert(m);
1041
1042 dbus_error_init(&error);
1043
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);
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);
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
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
1193 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
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
1239 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
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
1283 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
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
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
1322 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1323 goto oom;
1324
1325 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1326 DBusMessageIter sub2;
1327 dbus_uint32_t uid, pid;
1328 const char *what, *who, *why, *mode;
1329
1330 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1331 goto oom;
1332
1333 what = strempty(inhibit_what_to_string(inhibitor->what));
1334 who = strempty(inhibitor->who);
1335 why = strempty(inhibitor->why);
1336 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
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) ||
1343 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
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
1363 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1364
1365 r = bus_manager_create_session(m, message, &reply);
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 */
1371
1372 if (r < 0)
1373 return bus_send_error_reply(connection, message, NULL, r);
1374
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
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
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
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
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
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
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
1639 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
1640 if (r < 0)
1641 return bus_send_error_reply(connection, message, &error, r);
1642
1643 mkdir_p("/var/lib/systemd", 0755);
1644
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) {
1654 User *u;
1655
1656 r = touch(path);
1657 free(path);
1658
1659 if (r < 0)
1660 return bus_send_error_reply(connection, message, &error, r);
1661
1662 if (manager_add_user_by_uid(m, uid, &u) >= 0)
1663 user_start(u);
1664
1665 } else {
1666 User *u;
1667
1668 r = unlink(path);
1669 free(path);
1670
1671 if (r < 0 && errno != ENOENT)
1672 return bus_send_error_reply(connection, message, &error, -errno);
1673
1674 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1675 if (u)
1676 user_add_to_gc_queue(u);
1677 }
1678
1679 reply = dbus_message_new_method_return(message);
1680 if (!reply)
1681 goto oom;
1682
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
1699 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
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;
1710
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
1722 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
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
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;
1737 bool multiple_sessions, blocked, delayed;
1738 const char *name, *action;
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
1747 r = have_multiple_sessions(connection, m, message, &error);
1748 if (r < 0)
1749 return bus_send_error_reply(connection, message, &error, r);
1750
1751 multiple_sessions = r > 0;
1752 blocked = manager_is_inhibited(m, INHIBIT_SHUTDOWN, INHIBIT_BLOCK, NULL);
1753
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";
1758
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
1764 if (blocked) {
1765 action = streq(dbus_message_get_member(message), "PowerOff") ?
1766 "org.freedesktop.login1.power-off-ignore-inhibit" :
1767 "org.freedesktop.login1.reboot-ignore-inhibit";
1768
1769 r = verify_polkit(connection, message, action, interactive, NULL, &error);
1770 if (r < 0)
1771 return bus_send_error_reply(connection, message, &error, r);
1772 }
1773
1774 if (!multiple_sessions && !blocked) {
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 }
1783
1784 name = streq(dbus_message_get_member(message), "PowerOff") ?
1785 SPECIAL_POWEROFF_TARGET : SPECIAL_REBOOT_TARGET;
1786
1787 delayed =
1788 m->inhibit_delay_max > 0 &&
1789 manager_is_inhibited(m, INHIBIT_SHUTDOWN, INHIBIT_DELAY, NULL);
1790
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 }
1804
1805 reply = dbus_message_new_method_return(message);
1806 if (!reply)
1807 goto oom;
1808
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
1812 bool multiple_sessions, challenge, inhibit, b;
1813 const char *action, *result;
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;
1820 inhibit = manager_is_inhibited(m, INHIBIT_SHUTDOWN, INHIBIT_BLOCK, NULL);
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";
1826
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";
1835 else
1836 result = "no";
1837 }
1838
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";
1852 else
1853 result = "no";
1854 }
1855
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 }
1875
1876 reply = dbus_message_new_method_return(message);
1877 if (!reply)
1878 goto oom;
1879
1880 b = dbus_message_append_args(
1881 reply,
1882 DBUS_TYPE_STRING, &result,
1883 DBUS_TYPE_INVALID);
1884 if (!b)
1885 goto oom;
1886
1887 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
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);
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 }
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
1967 oom:
1968 if (reply)
1969 dbus_message_unref(reply);
1970
1971 dbus_error_free(&error);
1972
1973 return DBUS_HANDLER_RESULT_NEED_MEMORY;
1974 }
1975
1976 const DBusObjectPathVTable bus_manager_vtable = {
1977 .message_function = manager_message_handler
1978 };
1979
1980 DBusHandlerResult 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
2010 int 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
2025 finish:
2026 if (m)
2027 dbus_message_unref(m);
2028
2029 return r;
2030 }
2031
2032 int 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 }