]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/logind-dbus.c
logind: fix introspection data
[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 General Public License as published by
10 the Free Software Foundation; either version 2 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 General Public License for more details.
17
18 You should have received a copy of the GNU 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 "polkit.h"
31 #include "special.h"
32
33 #define BUS_MANAGER_INTERFACE \
34 " <interface name=\"org.freedesktop.login1.Manager\">\n" \
35 " <method name=\"GetSession\">\n" \
36 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
37 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
38 " </method>\n" \
39 " <method name=\"GetSessionByPID\">\n" \
40 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
41 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
42 " </method>\n" \
43 " <method name=\"GetUser\">\n" \
44 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
45 " <arg name=\"user\" type=\"o\" direction=\"out\"/>\n" \
46 " </method>\n" \
47 " <method name=\"GetSeat\">\n" \
48 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
49 " <arg name=\"seat\" type=\"o\" direction=\"out\"/>\n" \
50 " </method>\n" \
51 " <method name=\"ListSessions\">\n" \
52 " <arg name=\"sessions\" type=\"a(susso)\" direction=\"out\"/>\n" \
53 " </method>\n" \
54 " <method name=\"ListUsers\">\n" \
55 " <arg name=\"users\" type=\"a(uso)\" direction=\"out\"/>\n" \
56 " </method>\n" \
57 " <method name=\"ListSeats\">\n" \
58 " <arg name=\"seats\" type=\"a(so)\" direction=\"out\"/>\n" \
59 " </method>\n" \
60 " <method name=\"CreateSession\">\n" \
61 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
62 " <arg name=\"leader\" type=\"u\" direction=\"in\"/>\n" \
63 " <arg name=\"sevice\" type=\"s\" direction=\"in\"/>\n" \
64 " <arg name=\"type\" type=\"s\" direction=\"in\"/>\n" \
65 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
66 " <arg name=\"vtnr\" type=\"u\" direction=\"in\"/>\n" \
67 " <arg name=\"tty\" type=\"s\" direction=\"in\"/>\n" \
68 " <arg name=\"display\" type=\"s\" direction=\"in\"/>\n" \
69 " <arg name=\"remote\" type=\"b\" direction=\"in\"/>\n" \
70 " <arg name=\"remote_user\" type=\"s\" direction=\"in\"/>\n" \
71 " <arg name=\"remote_host\" type=\"s\" direction=\"in\"/>\n" \
72 " <arg name=\"controllers\" type=\"as\" direction=\"in\"/>\n" \
73 " <arg name=\"reset_controllers\" type=\"as\" direction=\"in\"/>\n" \
74 " <arg name=\"kill_processes\" type=\"b\" direction=\"in\"/>\n" \
75 " <arg name=\"id\" type=\"s\" direction=\"out\"/>\n" \
76 " <arg name=\"path\" type=\"o\" direction=\"out\"/>\n" \
77 " <arg name=\"runtime_path\" type=\"o\" direction=\"out\"/>\n" \
78 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
79 " <arg name=\"seat\" type=\"s\" direction=\"out\"/>\n" \
80 " <arg name=\"vtnr\" type=\"u\" direction=\"out\"/>\n" \
81 " </method>\n" \
82 " <method name=\"ActivateSession\">\n" \
83 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
84 " </method>\n" \
85 " <method name=\"ActivateSessionOnSeat\">\n" \
86 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
87 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
88 " </method>\n" \
89 " <method name=\"LockSession\">\n" \
90 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
91 " </method>\n" \
92 " <method name=\"UnlockSession\">\n" \
93 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
94 " </method>\n" \
95 " <method name=\"KillSession\">\n" \
96 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
97 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
98 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
99 " </method>\n" \
100 " <method name=\"KillUser\">\n" \
101 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
102 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
103 " </method>\n" \
104 " <method name=\"TerminateSession\">\n" \
105 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
106 " </method>\n" \
107 " <method name=\"TerminateUser\">\n" \
108 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
109 " </method>\n" \
110 " <method name=\"TerminateSeat\">\n" \
111 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
112 " </method>\n" \
113 " <method name=\"SetUserLinger\">\n" \
114 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
115 " <arg name=\"b\" type=\"b\" direction=\"in\"/>\n" \
116 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
117 " </method>\n" \
118 " <method name=\"AttachDevice\">\n" \
119 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
120 " <arg name=\"sysfs\" type=\"s\" direction=\"in\"/>\n" \
121 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
122 " </method>\n" \
123 " <method name=\"FlushDevices\">\n" \
124 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
125 " </method>\n" \
126 " <method name=\"PowerOff\">\n" \
127 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
128 " </method>\n" \
129 " <method name=\"Reboot\">\n" \
130 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
131 " </method>\n" \
132 " <signal name=\"SessionNew\">\n" \
133 " <arg name=\"id\" type=\"s\"/>\n" \
134 " <arg name=\"path\" type=\"o\"/>\n" \
135 " </signal>\n" \
136 " <signal name=\"SessionRemoved\">\n" \
137 " <arg name=\"id\" type=\"s\"/>\n" \
138 " <arg name=\"path\" type=\"o\"/>\n" \
139 " </signal>\n" \
140 " <signal name=\"UserNew\">\n" \
141 " <arg name=\"uid\" type=\"u\"/>\n" \
142 " <arg name=\"path\" type=\"o\"/>\n" \
143 " </signal>\n" \
144 " <signal name=\"UserRemoved\">\n" \
145 " <arg name=\"uid\" type=\"u\"/>\n" \
146 " <arg name=\"path\" type=\"o\"/>\n" \
147 " </signal>\n" \
148 " <signal name=\"SeatNew\">\n" \
149 " <arg name=\"id\" type=\"s\"/>\n" \
150 " <arg name=\"path\" type=\"o\"/>\n" \
151 " </signal>\n" \
152 " <signal name=\"SeatRemoved\">\n" \
153 " <arg name=\"id\" type=\"s\"/>\n" \
154 " <arg name=\"path\" type=\"o\"/>\n" \
155 " </signal>\n" \
156 " <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
157 " <property name=\"Controllers\" type=\"as\" access=\"read\"/>\n" \
158 " <property name=\"ResetControllers\" type=\"as\" access=\"read\"/>\n" \
159 " <property name=\"NAutoVTs\" type=\"u\" access=\"read\"/>\n" \
160 " <property name=\"KillOnlyUsers\" type=\"as\" access=\"read\"/>\n" \
161 " <property name=\"KillExcludeUsers\" type=\"as\" access=\"read\"/>\n" \
162 " <property name=\"KillUserProcesses\" type=\"b\" access=\"read\"/>\n" \
163 " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
164 " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
165 " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
166 " </interface>\n"
167
168 #define INTROSPECTION_BEGIN \
169 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
170 "<node>\n" \
171 BUS_MANAGER_INTERFACE \
172 BUS_PROPERTIES_INTERFACE \
173 BUS_PEER_INTERFACE \
174 BUS_INTROSPECTABLE_INTERFACE
175
176 #define INTROSPECTION_END \
177 "</node>\n"
178
179 #define INTERFACES_LIST \
180 BUS_GENERIC_INTERFACES_LIST \
181 "org.freedesktop.login1.Manager\0"
182
183 static int bus_manager_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
184 Manager *m = data;
185 dbus_bool_t b;
186
187 assert(i);
188 assert(property);
189 assert(m);
190
191 b = manager_get_idle_hint(m, NULL) > 0;
192 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
193 return -ENOMEM;
194
195 return 0;
196 }
197
198 static int bus_manager_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
199 Manager *m = data;
200 dual_timestamp t;
201 uint64_t u;
202
203 assert(i);
204 assert(property);
205 assert(m);
206
207 manager_get_idle_hint(m, &t);
208 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
209
210 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
211 return -ENOMEM;
212
213 return 0;
214 }
215
216 static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMessage **_reply) {
217 Session *session = NULL;
218 User *user = NULL;
219 const char *type, *seat, *tty, *display, *remote_user, *remote_host, *service;
220 uint32_t uid, leader, audit_id = 0;
221 dbus_bool_t remote, kill_processes;
222 char **controllers = NULL, **reset_controllers = NULL;
223 SessionType t;
224 Seat *s;
225 DBusMessageIter iter;
226 int r;
227 char *id = NULL, *p;
228 uint32_t vtnr = 0;
229 int fifo_fd = -1;
230 DBusMessage *reply = NULL;
231 bool b;
232
233 assert(m);
234 assert(message);
235 assert(_reply);
236
237 if (!dbus_message_iter_init(message, &iter) ||
238 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
239 return -EINVAL;
240
241 dbus_message_iter_get_basic(&iter, &uid);
242
243 if (!dbus_message_iter_next(&iter) ||
244 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
245 return -EINVAL;
246
247 dbus_message_iter_get_basic(&iter, &leader);
248
249 if (leader <= 0 ||
250 !dbus_message_iter_next(&iter) ||
251 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
252 return -EINVAL;
253
254 dbus_message_iter_get_basic(&iter, &service);
255
256 if (!dbus_message_iter_next(&iter) ||
257 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
258 return -EINVAL;
259
260 dbus_message_iter_get_basic(&iter, &type);
261 t = session_type_from_string(type);
262
263 if (t < 0 ||
264 !dbus_message_iter_next(&iter) ||
265 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
266 return -EINVAL;
267
268 dbus_message_iter_get_basic(&iter, &seat);
269
270 if (isempty(seat))
271 s = NULL;
272 else {
273 s = hashmap_get(m->seats, seat);
274 if (!s)
275 return -ENOENT;
276 }
277
278 if (!dbus_message_iter_next(&iter) ||
279 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
280 return -EINVAL;
281
282 dbus_message_iter_get_basic(&iter, &vtnr);
283
284 if (!dbus_message_iter_next(&iter) ||
285 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
286 return -EINVAL;
287
288 dbus_message_iter_get_basic(&iter, &tty);
289
290 if (tty_is_vc(tty)) {
291 int v;
292
293 if (!s)
294 s = m->vtconsole;
295 else if (s != m->vtconsole)
296 return -EINVAL;
297
298 v = vtnr_from_tty(tty);
299
300 if (v <= 0)
301 return v < 0 ? v : -EINVAL;
302
303 if (vtnr <= 0)
304 vtnr = (uint32_t) v;
305 else if (vtnr != (uint32_t) v)
306 return -EINVAL;
307
308 } else if (!isempty(tty) && s && seat_is_vtconsole(s))
309 return -EINVAL;
310
311 if (s) {
312 if (seat_can_multi_session(s)) {
313 if (vtnr <= 0 || vtnr > 63)
314 return -EINVAL;
315 } else {
316 if (vtnr > 0)
317 return -EINVAL;
318 }
319 }
320
321 if (!dbus_message_iter_next(&iter) ||
322 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
323 return -EINVAL;
324
325 dbus_message_iter_get_basic(&iter, &display);
326
327 if (!dbus_message_iter_next(&iter) ||
328 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
329 return -EINVAL;
330
331 dbus_message_iter_get_basic(&iter, &remote);
332
333 if (!dbus_message_iter_next(&iter) ||
334 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
335 return -EINVAL;
336
337 dbus_message_iter_get_basic(&iter, &remote_user);
338
339 if (!dbus_message_iter_next(&iter) ||
340 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
341 return -EINVAL;
342
343 dbus_message_iter_get_basic(&iter, &remote_host);
344
345 if (!dbus_message_iter_next(&iter) ||
346 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
347 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
348 return -EINVAL;
349
350 r = bus_parse_strv_iter(&iter, &controllers);
351 if (r < 0)
352 return -EINVAL;
353
354 if (strv_contains(controllers, "systemd") ||
355 !dbus_message_iter_next(&iter) ||
356 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
357 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) {
358 r = -EINVAL;
359 goto fail;
360 }
361
362 r = bus_parse_strv_iter(&iter, &reset_controllers);
363 if (r < 0)
364 goto fail;
365
366 if (strv_contains(reset_controllers, "systemd") ||
367 !dbus_message_iter_next(&iter) ||
368 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) {
369 r = -EINVAL;
370 goto fail;
371 }
372
373 dbus_message_iter_get_basic(&iter, &kill_processes);
374
375 r = manager_add_user_by_uid(m, uid, &user);
376 if (r < 0)
377 goto fail;
378
379 audit_session_from_pid(leader, &audit_id);
380
381 if (audit_id > 0) {
382 asprintf(&id, "%lu", (unsigned long) audit_id);
383
384 if (!id) {
385 r = -ENOMEM;
386 goto fail;
387 }
388
389 session = hashmap_get(m->sessions, id);
390
391 if (session) {
392 free(id);
393
394 fifo_fd = session_create_fifo(session);
395 if (fifo_fd < 0) {
396 r = fifo_fd;
397 goto fail;
398 }
399
400 /* Session already exists, client is probably
401 * something like "su" which changes uid but
402 * is still the same audit session */
403
404 reply = dbus_message_new_method_return(message);
405 if (!reply) {
406 r = -ENOMEM;
407 goto fail;
408 }
409
410 p = session_bus_path(session);
411 if (!p) {
412 r = -ENOMEM;
413 goto fail;
414 }
415
416 seat = session->seat ? session->seat->id : "";
417 vtnr = session->vtnr;
418 b = dbus_message_append_args(
419 reply,
420 DBUS_TYPE_STRING, &session->id,
421 DBUS_TYPE_OBJECT_PATH, &p,
422 DBUS_TYPE_STRING, &session->user->runtime_path,
423 DBUS_TYPE_UNIX_FD, &fifo_fd,
424 DBUS_TYPE_STRING, &seat,
425 DBUS_TYPE_UINT32, &vtnr,
426 DBUS_TYPE_INVALID);
427 free(p);
428
429 if (!b) {
430 r = -ENOMEM;
431 goto fail;
432 }
433
434 close_nointr_nofail(fifo_fd);
435 *_reply = reply;
436
437 strv_free(controllers);
438 strv_free(reset_controllers);
439
440 return 0;
441 }
442
443 } else {
444 do {
445 free(id);
446 asprintf(&id, "c%lu", ++m->session_counter);
447
448 if (!id) {
449 r = -ENOMEM;
450 goto fail;
451 }
452
453 } while (hashmap_get(m->sessions, id));
454 }
455
456 r = manager_add_session(m, user, id, &session);
457 free(id);
458 if (r < 0)
459 goto fail;
460
461 session->leader = leader;
462 session->audit_id = audit_id;
463 session->type = t;
464 session->remote = remote;
465 session->controllers = controllers;
466 session->reset_controllers = reset_controllers;
467 session->kill_processes = kill_processes;
468 session->vtnr = vtnr;
469
470 controllers = reset_controllers = NULL;
471
472 if (!isempty(tty)) {
473 session->tty = strdup(tty);
474 if (!session->tty) {
475 r = -ENOMEM;
476 goto fail;
477 }
478 }
479
480 if (!isempty(display)) {
481 session->display = strdup(display);
482 if (!session->display) {
483 r = -ENOMEM;
484 goto fail;
485 }
486 }
487
488 if (!isempty(remote_user)) {
489 session->remote_user = strdup(remote_user);
490 if (!session->remote_user) {
491 r = -ENOMEM;
492 goto fail;
493 }
494 }
495
496 if (!isempty(remote_host)) {
497 session->remote_host = strdup(remote_host);
498 if (!session->remote_host) {
499 r = -ENOMEM;
500 goto fail;
501 }
502 }
503
504 if (!isempty(service)) {
505 session->service = strdup(service);
506 if (!session->service) {
507 r = -ENOMEM;
508 goto fail;
509 }
510 }
511
512 fifo_fd = session_create_fifo(session);
513 if (fifo_fd < 0) {
514 r = fifo_fd;
515 goto fail;
516 }
517
518 if (s) {
519 r = seat_attach_session(s, session);
520 if (r < 0)
521 goto fail;
522 }
523
524 r = session_start(session);
525 if (r < 0)
526 goto fail;
527
528 reply = dbus_message_new_method_return(message);
529 if (!reply) {
530 r = -ENOMEM;
531 goto fail;
532 }
533
534 p = session_bus_path(session);
535 if (!p) {
536 r = -ENOMEM;
537 goto fail;
538 }
539
540 seat = s ? s->id : "";
541 b = dbus_message_append_args(
542 reply,
543 DBUS_TYPE_STRING, &session->id,
544 DBUS_TYPE_OBJECT_PATH, &p,
545 DBUS_TYPE_STRING, &session->user->runtime_path,
546 DBUS_TYPE_UNIX_FD, &fifo_fd,
547 DBUS_TYPE_STRING, &seat,
548 DBUS_TYPE_UINT32, &vtnr,
549 DBUS_TYPE_INVALID);
550 free(p);
551
552 if (!b) {
553 r = -ENOMEM;
554 goto fail;
555 }
556
557 close_nointr_nofail(fifo_fd);
558 *_reply = reply;
559
560 return 0;
561
562 fail:
563 strv_free(controllers);
564 strv_free(reset_controllers);
565
566 if (session)
567 session_add_to_gc_queue(session);
568
569 if (user)
570 user_add_to_gc_queue(user);
571
572 if (fifo_fd >= 0)
573 close_nointr_nofail(fifo_fd);
574
575 if (reply)
576 dbus_message_unref(reply);
577
578 return r;
579 }
580
581 static int trigger_device(Manager *m, struct udev_device *d) {
582 struct udev_enumerate *e;
583 struct udev_list_entry *first, *item;
584 int r;
585
586 assert(m);
587
588 e = udev_enumerate_new(m->udev);
589 if (!e) {
590 r = -ENOMEM;
591 goto finish;
592 }
593
594 if (d) {
595 if (udev_enumerate_add_match_parent(e, d) < 0) {
596 r = -EIO;
597 goto finish;
598 }
599 }
600
601 if (udev_enumerate_scan_devices(e) < 0) {
602 r = -EIO;
603 goto finish;
604 }
605
606 first = udev_enumerate_get_list_entry(e);
607 udev_list_entry_foreach(item, first) {
608 char *t;
609 const char *p;
610
611 p = udev_list_entry_get_name(item);
612
613 t = strappend(p, "/uevent");
614 if (!t) {
615 r = -ENOMEM;
616 goto finish;
617 }
618
619 write_one_line_file(t, "change");
620 free(t);
621 }
622
623 r = 0;
624
625 finish:
626 if (e)
627 udev_enumerate_unref(e);
628
629 return r;
630 }
631
632 static int attach_device(Manager *m, const char *seat, const char *sysfs) {
633 struct udev_device *d;
634 char *rule = NULL, *file = NULL;
635 const char *id_for_seat;
636 int r;
637
638 assert(m);
639 assert(seat);
640 assert(sysfs);
641
642 d = udev_device_new_from_syspath(m->udev, sysfs);
643 if (!d)
644 return -ENODEV;
645
646 if (!udev_device_has_tag(d, "seat")) {
647 r = -ENODEV;
648 goto finish;
649 }
650
651 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
652 if (!id_for_seat) {
653 r = -ENODEV;
654 goto finish;
655 }
656
657 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
658 r = -ENOMEM;
659 goto finish;
660 }
661
662 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
663 r = -ENOMEM;
664 goto finish;
665 }
666
667 mkdir_p("/etc/udev/rules.d", 0755);
668 r = write_one_line_file_atomic(file, rule);
669 if (r < 0)
670 goto finish;
671
672 r = trigger_device(m, d);
673
674 finish:
675 free(rule);
676 free(file);
677
678 if (d)
679 udev_device_unref(d);
680
681 return r;
682 }
683
684 static int flush_devices(Manager *m) {
685 DIR *d;
686
687 assert(m);
688
689 d = opendir("/etc/udev/rules.d");
690 if (!d) {
691 if (errno != ENOENT)
692 log_warning("Failed to open /etc/udev/rules.d: %m");
693 } else {
694 struct dirent *de;
695
696 while ((de = readdir(d))) {
697
698 if (!dirent_is_file(de))
699 continue;
700
701 if (!startswith(de->d_name, "72-seat-"))
702 continue;
703
704 if (!endswith(de->d_name, ".rules"))
705 continue;
706
707 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
708 log_warning("Failed to unlink %s: %m", de->d_name);
709 }
710
711 closedir(d);
712 }
713
714 return trigger_device(m, NULL);
715 }
716
717 static const BusProperty bus_login_manager_properties[] = {
718 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_path), true },
719 { "Controllers", bus_property_append_strv, "as", offsetof(Manager, controllers), true },
720 { "ResetControllers", bus_property_append_strv, "as", offsetof(Manager, reset_controllers), true },
721 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
722 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
723 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
724 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
725 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
726 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
727 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
728 { NULL, }
729 };
730
731 static DBusHandlerResult manager_message_handler(
732 DBusConnection *connection,
733 DBusMessage *message,
734 void *userdata) {
735
736 Manager *m = userdata;
737
738 DBusError error;
739 DBusMessage *reply = NULL;
740 int r;
741
742 assert(connection);
743 assert(message);
744 assert(m);
745
746 dbus_error_init(&error);
747
748 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
749 const char *name;
750 char *p;
751 Session *session;
752 bool b;
753
754 if (!dbus_message_get_args(
755 message,
756 &error,
757 DBUS_TYPE_STRING, &name,
758 DBUS_TYPE_INVALID))
759 return bus_send_error_reply(connection, message, &error, -EINVAL);
760
761 session = hashmap_get(m->sessions, name);
762 if (!session)
763 return bus_send_error_reply(connection, message, &error, -ENOENT);
764
765 reply = dbus_message_new_method_return(message);
766 if (!reply)
767 goto oom;
768
769 p = session_bus_path(session);
770 if (!p)
771 goto oom;
772
773 b = dbus_message_append_args(
774 reply,
775 DBUS_TYPE_OBJECT_PATH, &p,
776 DBUS_TYPE_INVALID);
777 free(p);
778
779 if (!b)
780 goto oom;
781
782 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
783 uint32_t pid;
784 char *p;
785 Session *session;
786 bool b;
787
788 if (!dbus_message_get_args(
789 message,
790 &error,
791 DBUS_TYPE_UINT32, &pid,
792 DBUS_TYPE_INVALID))
793 return bus_send_error_reply(connection, message, &error, -EINVAL);
794
795 r = manager_get_session_by_pid(m, pid, &session);
796 if (r <= 0)
797 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
798
799 reply = dbus_message_new_method_return(message);
800 if (!reply)
801 goto oom;
802
803 p = session_bus_path(session);
804 if (!p)
805 goto oom;
806
807 b = dbus_message_append_args(
808 reply,
809 DBUS_TYPE_OBJECT_PATH, &p,
810 DBUS_TYPE_INVALID);
811 free(p);
812
813 if (!b)
814 goto oom;
815
816 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
817 uint32_t uid;
818 char *p;
819 User *user;
820 bool b;
821
822 if (!dbus_message_get_args(
823 message,
824 &error,
825 DBUS_TYPE_UINT32, &uid,
826 DBUS_TYPE_INVALID))
827 return bus_send_error_reply(connection, message, &error, -EINVAL);
828
829 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
830 if (!user)
831 return bus_send_error_reply(connection, message, &error, -ENOENT);
832
833 reply = dbus_message_new_method_return(message);
834 if (!reply)
835 goto oom;
836
837 p = user_bus_path(user);
838 if (!p)
839 goto oom;
840
841 b = dbus_message_append_args(
842 reply,
843 DBUS_TYPE_OBJECT_PATH, &p,
844 DBUS_TYPE_INVALID);
845 free(p);
846
847 if (!b)
848 goto oom;
849
850 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
851 const char *name;
852 char *p;
853 Seat *seat;
854 bool b;
855
856 if (!dbus_message_get_args(
857 message,
858 &error,
859 DBUS_TYPE_STRING, &name,
860 DBUS_TYPE_INVALID))
861 return bus_send_error_reply(connection, message, &error, -EINVAL);
862
863 seat = hashmap_get(m->seats, name);
864 if (!seat)
865 return bus_send_error_reply(connection, message, &error, -ENOENT);
866
867 reply = dbus_message_new_method_return(message);
868 if (!reply)
869 goto oom;
870
871 p = seat_bus_path(seat);
872 if (!p)
873 goto oom;
874
875 b = dbus_message_append_args(
876 reply,
877 DBUS_TYPE_OBJECT_PATH, &p,
878 DBUS_TYPE_INVALID);
879 free(p);
880
881 if (!b)
882 goto oom;
883
884 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
885 char *p;
886 Session *session;
887 Iterator i;
888 DBusMessageIter iter, sub;
889 const char *empty = "";
890
891 reply = dbus_message_new_method_return(message);
892 if (!reply)
893 goto oom;
894
895 dbus_message_iter_init_append(reply, &iter);
896
897 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
898 goto oom;
899
900 HASHMAP_FOREACH(session, m->sessions, i) {
901 DBusMessageIter sub2;
902 uint32_t uid;
903
904 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
905 goto oom;
906
907 uid = session->user->uid;
908
909 p = session_bus_path(session);
910 if (!p)
911 goto oom;
912
913 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
914 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
915 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
916 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
917 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
918 free(p);
919 goto oom;
920 }
921
922 free(p);
923
924 if (!dbus_message_iter_close_container(&sub, &sub2))
925 goto oom;
926 }
927
928 if (!dbus_message_iter_close_container(&iter, &sub))
929 goto oom;
930
931 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
932 char *p;
933 User *user;
934 Iterator i;
935 DBusMessageIter iter, sub;
936
937 reply = dbus_message_new_method_return(message);
938 if (!reply)
939 goto oom;
940
941 dbus_message_iter_init_append(reply, &iter);
942
943 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
944 goto oom;
945
946 HASHMAP_FOREACH(user, m->users, i) {
947 DBusMessageIter sub2;
948 uint32_t uid;
949
950 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
951 goto oom;
952
953 uid = user->uid;
954
955 p = user_bus_path(user);
956 if (!p)
957 goto oom;
958
959 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
960 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
961 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
962 free(p);
963 goto oom;
964 }
965
966 free(p);
967
968 if (!dbus_message_iter_close_container(&sub, &sub2))
969 goto oom;
970 }
971
972 if (!dbus_message_iter_close_container(&iter, &sub))
973 goto oom;
974
975 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
976 char *p;
977 Seat *seat;
978 Iterator i;
979 DBusMessageIter iter, sub;
980
981 reply = dbus_message_new_method_return(message);
982 if (!reply)
983 goto oom;
984
985 dbus_message_iter_init_append(reply, &iter);
986
987 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
988 goto oom;
989
990 HASHMAP_FOREACH(seat, m->seats, i) {
991 DBusMessageIter sub2;
992
993 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
994 goto oom;
995
996 p = seat_bus_path(seat);
997 if (!p)
998 goto oom;
999
1000 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1001 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1002 free(p);
1003 goto oom;
1004 }
1005
1006 free(p);
1007
1008 if (!dbus_message_iter_close_container(&sub, &sub2))
1009 goto oom;
1010 }
1011
1012 if (!dbus_message_iter_close_container(&iter, &sub))
1013 goto oom;
1014
1015 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1016
1017 r = bus_manager_create_session(m, message, &reply);
1018
1019 /* Don't delay the work on OOM here, since it might be
1020 * triggered by a low RLIMIT_NOFILE here (since we
1021 * send a dupped fd to the client), and we'd rather
1022 * see this fail quickly then be retried later */
1023
1024 if (r < 0)
1025 return bus_send_error_reply(connection, message, &error, r);
1026
1027 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1028 const char *name;
1029 Session *session;
1030
1031 if (!dbus_message_get_args(
1032 message,
1033 &error,
1034 DBUS_TYPE_STRING, &name,
1035 DBUS_TYPE_INVALID))
1036 return bus_send_error_reply(connection, message, &error, -EINVAL);
1037
1038 session = hashmap_get(m->sessions, name);
1039 if (!session)
1040 return bus_send_error_reply(connection, message, &error, -ENOENT);
1041
1042 r = session_activate(session);
1043 if (r < 0)
1044 return bus_send_error_reply(connection, message, NULL, r);
1045
1046 reply = dbus_message_new_method_return(message);
1047 if (!reply)
1048 goto oom;
1049
1050 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1051 const char *session_name, *seat_name;
1052 Session *session;
1053 Seat *seat;
1054
1055 /* Same as ActivateSession() but refuses to work if
1056 * the seat doesn't match */
1057
1058 if (!dbus_message_get_args(
1059 message,
1060 &error,
1061 DBUS_TYPE_STRING, &session_name,
1062 DBUS_TYPE_STRING, &seat_name,
1063 DBUS_TYPE_INVALID))
1064 return bus_send_error_reply(connection, message, &error, -EINVAL);
1065
1066 session = hashmap_get(m->sessions, session_name);
1067 if (!session)
1068 return bus_send_error_reply(connection, message, &error, -ENOENT);
1069
1070 seat = hashmap_get(m->seats, seat_name);
1071 if (!seat)
1072 return bus_send_error_reply(connection, message, &error, -ENOENT);
1073
1074 if (session->seat != seat)
1075 return bus_send_error_reply(connection, message, &error, -EINVAL);
1076
1077 r = session_activate(session);
1078 if (r < 0)
1079 return bus_send_error_reply(connection, message, NULL, r);
1080
1081 reply = dbus_message_new_method_return(message);
1082 if (!reply)
1083 goto oom;
1084
1085 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1086 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1087 const char *name;
1088 Session *session;
1089
1090 if (!dbus_message_get_args(
1091 message,
1092 &error,
1093 DBUS_TYPE_STRING, &name,
1094 DBUS_TYPE_INVALID))
1095 return bus_send_error_reply(connection, message, &error, -EINVAL);
1096
1097 session = hashmap_get(m->sessions, name);
1098 if (!session)
1099 return bus_send_error_reply(connection, message, &error, -ENOENT);
1100
1101 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1102 goto oom;
1103
1104 reply = dbus_message_new_method_return(message);
1105 if (!reply)
1106 goto oom;
1107
1108 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1109 const char *swho;
1110 int32_t signo;
1111 KillWho who;
1112 const char *name;
1113 Session *session;
1114
1115 if (!dbus_message_get_args(
1116 message,
1117 &error,
1118 DBUS_TYPE_STRING, &name,
1119 DBUS_TYPE_STRING, &swho,
1120 DBUS_TYPE_INT32, &signo,
1121 DBUS_TYPE_INVALID))
1122 return bus_send_error_reply(connection, message, &error, -EINVAL);
1123
1124 if (isempty(swho))
1125 who = KILL_ALL;
1126 else {
1127 who = kill_who_from_string(swho);
1128 if (who < 0)
1129 return bus_send_error_reply(connection, message, &error, -EINVAL);
1130 }
1131
1132 if (signo <= 0 || signo >= _NSIG)
1133 return bus_send_error_reply(connection, message, &error, -EINVAL);
1134
1135 session = hashmap_get(m->sessions, name);
1136 if (!session)
1137 return bus_send_error_reply(connection, message, &error, -ENOENT);
1138
1139 r = session_kill(session, who, signo);
1140 if (r < 0)
1141 return bus_send_error_reply(connection, message, NULL, r);
1142
1143 reply = dbus_message_new_method_return(message);
1144 if (!reply)
1145 goto oom;
1146
1147 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1148 uint32_t uid;
1149 User *user;
1150 int32_t signo;
1151
1152 if (!dbus_message_get_args(
1153 message,
1154 &error,
1155 DBUS_TYPE_UINT32, &uid,
1156 DBUS_TYPE_INT32, &signo,
1157 DBUS_TYPE_INVALID))
1158 return bus_send_error_reply(connection, message, &error, -EINVAL);
1159
1160 if (signo <= 0 || signo >= _NSIG)
1161 return bus_send_error_reply(connection, message, &error, -EINVAL);
1162
1163 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1164 if (!user)
1165 return bus_send_error_reply(connection, message, &error, -ENOENT);
1166
1167 r = user_kill(user, signo);
1168 if (r < 0)
1169 return bus_send_error_reply(connection, message, NULL, r);
1170
1171 reply = dbus_message_new_method_return(message);
1172 if (!reply)
1173 goto oom;
1174
1175 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1176 const char *name;
1177 Session *session;
1178
1179 if (!dbus_message_get_args(
1180 message,
1181 &error,
1182 DBUS_TYPE_STRING, &name,
1183 DBUS_TYPE_INVALID))
1184 return bus_send_error_reply(connection, message, &error, -EINVAL);
1185
1186 session = hashmap_get(m->sessions, name);
1187 if (!session)
1188 return bus_send_error_reply(connection, message, &error, -ENOENT);
1189
1190 r = session_stop(session);
1191 if (r < 0)
1192 return bus_send_error_reply(connection, message, NULL, r);
1193
1194 reply = dbus_message_new_method_return(message);
1195 if (!reply)
1196 goto oom;
1197
1198 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1199 uint32_t uid;
1200 User *user;
1201
1202 if (!dbus_message_get_args(
1203 message,
1204 &error,
1205 DBUS_TYPE_UINT32, &uid,
1206 DBUS_TYPE_INVALID))
1207 return bus_send_error_reply(connection, message, &error, -EINVAL);
1208
1209 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1210 if (!user)
1211 return bus_send_error_reply(connection, message, &error, -ENOENT);
1212
1213 r = user_stop(user);
1214 if (r < 0)
1215 return bus_send_error_reply(connection, message, NULL, r);
1216
1217 reply = dbus_message_new_method_return(message);
1218 if (!reply)
1219 goto oom;
1220
1221 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1222 const char *name;
1223 Seat *seat;
1224
1225 if (!dbus_message_get_args(
1226 message,
1227 &error,
1228 DBUS_TYPE_STRING, &name,
1229 DBUS_TYPE_INVALID))
1230 return bus_send_error_reply(connection, message, &error, -EINVAL);
1231
1232 seat = hashmap_get(m->seats, name);
1233 if (!seat)
1234 return bus_send_error_reply(connection, message, &error, -ENOENT);
1235
1236 r = seat_stop_sessions(seat);
1237 if (r < 0)
1238 return bus_send_error_reply(connection, message, NULL, r);
1239
1240 reply = dbus_message_new_method_return(message);
1241 if (!reply)
1242 goto oom;
1243
1244 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
1245 uint32_t uid;
1246 struct passwd *pw;
1247 dbus_bool_t b, interactive;
1248 char *path;
1249
1250 if (!dbus_message_get_args(
1251 message,
1252 &error,
1253 DBUS_TYPE_UINT32, &uid,
1254 DBUS_TYPE_BOOLEAN, &b,
1255 DBUS_TYPE_BOOLEAN, &interactive,
1256 DBUS_TYPE_INVALID))
1257 return bus_send_error_reply(connection, message, &error, -EINVAL);
1258
1259 errno = 0;
1260 pw = getpwuid(uid);
1261 if (!pw)
1262 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
1263
1264 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, &error);
1265 if (r < 0)
1266 return bus_send_error_reply(connection, message, &error, r);
1267
1268 mkdir_p("/var/lib/systemd", 0755);
1269
1270 r = safe_mkdir("/var/lib/systemd/linger", 0755, 0, 0);
1271 if (r < 0)
1272 return bus_send_error_reply(connection, message, &error, r);
1273
1274 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
1275 if (!path)
1276 goto oom;
1277
1278 if (b) {
1279 User *u;
1280
1281 r = touch(path);
1282 free(path);
1283
1284 if (r < 0)
1285 return bus_send_error_reply(connection, message, &error, r);
1286
1287 if (manager_add_user_by_uid(m, uid, &u) >= 0)
1288 user_start(u);
1289
1290 } else {
1291 User *u;
1292
1293 r = unlink(path);
1294 free(path);
1295
1296 if (r < 0 && errno != ENOENT)
1297 return bus_send_error_reply(connection, message, &error, -errno);
1298
1299 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1300 if (u)
1301 user_add_to_gc_queue(u);
1302 }
1303
1304 reply = dbus_message_new_method_return(message);
1305 if (!reply)
1306 goto oom;
1307
1308 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
1309 const char *sysfs, *seat;
1310 dbus_bool_t interactive;
1311
1312 if (!dbus_message_get_args(
1313 message,
1314 &error,
1315 DBUS_TYPE_STRING, &seat,
1316 DBUS_TYPE_STRING, &sysfs,
1317 DBUS_TYPE_BOOLEAN, &interactive,
1318 DBUS_TYPE_INVALID))
1319 return bus_send_error_reply(connection, message, &error, -EINVAL);
1320
1321 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
1322 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1323
1324 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, &error);
1325 if (r < 0)
1326 return bus_send_error_reply(connection, message, &error, r);
1327
1328 r = attach_device(m, seat, sysfs);
1329 if (r < 0)
1330 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1331
1332 reply = dbus_message_new_method_return(message);
1333 if (!reply)
1334 goto oom;
1335
1336
1337 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
1338 dbus_bool_t interactive;
1339
1340 if (!dbus_message_get_args(
1341 message,
1342 &error,
1343 DBUS_TYPE_BOOLEAN, &interactive,
1344 DBUS_TYPE_INVALID))
1345 return bus_send_error_reply(connection, message, &error, -EINVAL);
1346
1347 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, &error);
1348 if (r < 0)
1349 return bus_send_error_reply(connection, message, &error, r);
1350
1351 r = flush_devices(m);
1352 if (r < 0)
1353 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1354
1355 reply = dbus_message_new_method_return(message);
1356 if (!reply)
1357 goto oom;
1358
1359 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff") ||
1360 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
1361 dbus_bool_t interactive;
1362 bool multiple_sessions;
1363 DBusMessage *forward, *freply;
1364 const char *name;
1365 const char *mode = "replace";
1366 const char *action;
1367
1368 if (!dbus_message_get_args(
1369 message,
1370 &error,
1371 DBUS_TYPE_BOOLEAN, &interactive,
1372 DBUS_TYPE_INVALID))
1373 return bus_send_error_reply(connection, message, &error, -EINVAL);
1374
1375 multiple_sessions = hashmap_size(m->sessions) > 1;
1376
1377 if (!multiple_sessions) {
1378 Session *s;
1379
1380 /* Hmm, there's only one session, but let's
1381 * make sure it actually belongs to the user
1382 * who is asking. If not, better be safe than
1383 * sorry. */
1384
1385 s = hashmap_first(m->sessions);
1386 if (s) {
1387 unsigned long ul;
1388
1389 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), &error);
1390 if (ul == (unsigned long) -1)
1391 return bus_send_error_reply(connection, message, &error, -EIO);
1392
1393 multiple_sessions = s->user->uid != ul;
1394 }
1395 }
1396
1397 if (streq(dbus_message_get_member(message), "PowerOff")) {
1398 if (multiple_sessions)
1399 action = "org.freedesktop.login1.power-off-multiple-sessions";
1400 else
1401 action = "org.freedesktop.login1.power-off";
1402
1403 name = SPECIAL_POWEROFF_TARGET;
1404 } else {
1405 if (multiple_sessions)
1406 action = "org.freedesktop.login1.reboot-multiple-sessions";
1407 else
1408 action = "org.freedesktop.login1.reboot";
1409
1410 name = SPECIAL_REBOOT_TARGET;
1411 }
1412
1413 r = verify_polkit(connection, message, action, interactive, &error);
1414 if (r < 0)
1415 return bus_send_error_reply(connection, message, &error, r);
1416
1417 forward = dbus_message_new_method_call(
1418 "org.freedesktop.systemd1",
1419 "/org/freedesktop/systemd1",
1420 "org.freedesktop.systemd1.Manager",
1421 "StartUnit");
1422 if (!forward)
1423 return bus_send_error_reply(connection, message, NULL, -ENOMEM);
1424
1425 if (!dbus_message_append_args(forward,
1426 DBUS_TYPE_STRING, &name,
1427 DBUS_TYPE_STRING, &mode,
1428 DBUS_TYPE_INVALID)) {
1429 dbus_message_unref(forward);
1430 return bus_send_error_reply(connection, message, NULL, -ENOMEM);
1431 }
1432
1433 freply = dbus_connection_send_with_reply_and_block(connection, forward, -1, &error);
1434 dbus_message_unref(forward);
1435
1436 if (!freply)
1437 return bus_send_error_reply(connection, message, &error, -EIO);
1438
1439 dbus_message_unref(freply);
1440
1441 reply = dbus_message_new_method_return(message);
1442 if (!reply)
1443 goto oom;
1444
1445 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1446 char *introspection = NULL;
1447 FILE *f;
1448 Iterator i;
1449 Session *session;
1450 Seat *seat;
1451 User *user;
1452 size_t size;
1453 char *p;
1454
1455 if (!(reply = dbus_message_new_method_return(message)))
1456 goto oom;
1457
1458 /* We roll our own introspection code here, instead of
1459 * relying on bus_default_message_handler() because we
1460 * need to generate our introspection string
1461 * dynamically. */
1462
1463 if (!(f = open_memstream(&introspection, &size)))
1464 goto oom;
1465
1466 fputs(INTROSPECTION_BEGIN, f);
1467
1468 HASHMAP_FOREACH(seat, m->seats, i) {
1469 p = bus_path_escape(seat->id);
1470
1471 if (p) {
1472 fprintf(f, "<node name=\"seat/%s\"/>", p);
1473 free(p);
1474 }
1475 }
1476
1477 HASHMAP_FOREACH(user, m->users, i)
1478 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
1479
1480 HASHMAP_FOREACH(session, m->sessions, i) {
1481 p = bus_path_escape(session->id);
1482
1483 if (p) {
1484 fprintf(f, "<node name=\"session/%s\"/>", p);
1485 free(p);
1486 }
1487 }
1488
1489 fputs(INTROSPECTION_END, f);
1490
1491 if (ferror(f)) {
1492 fclose(f);
1493 free(introspection);
1494 goto oom;
1495 }
1496
1497 fclose(f);
1498
1499 if (!introspection)
1500 goto oom;
1501
1502 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
1503 free(introspection);
1504 goto oom;
1505 }
1506
1507 free(introspection);
1508 } else {
1509 const BusBoundProperties bps[] = {
1510 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
1511 { NULL, }
1512 };
1513 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
1514 }
1515
1516 if (reply) {
1517 if (!dbus_connection_send(connection, reply, NULL))
1518 goto oom;
1519
1520 dbus_message_unref(reply);
1521 }
1522
1523 return DBUS_HANDLER_RESULT_HANDLED;
1524
1525 oom:
1526 if (reply)
1527 dbus_message_unref(reply);
1528
1529 dbus_error_free(&error);
1530
1531 return DBUS_HANDLER_RESULT_NEED_MEMORY;
1532 }
1533
1534 const DBusObjectPathVTable bus_manager_vtable = {
1535 .message_function = manager_message_handler
1536 };
1537
1538 DBusHandlerResult bus_message_filter(
1539 DBusConnection *connection,
1540 DBusMessage *message,
1541 void *userdata) {
1542
1543 Manager *m = userdata;
1544 DBusError error;
1545
1546 assert(m);
1547 assert(connection);
1548 assert(message);
1549
1550 dbus_error_init(&error);
1551
1552 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
1553 const char *cgroup;
1554
1555 if (!dbus_message_get_args(message, &error,
1556 DBUS_TYPE_STRING, &cgroup,
1557 DBUS_TYPE_INVALID))
1558 log_error("Failed to parse Released message: %s", bus_error_message(&error));
1559 else
1560 manager_cgroup_notify_empty(m, cgroup);
1561 }
1562
1563 dbus_error_free(&error);
1564
1565 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1566 }
1567
1568 int manager_send_changed(Manager *manager, const char *properties) {
1569 DBusMessage *m;
1570 int r = -ENOMEM;
1571
1572 assert(manager);
1573
1574 m = bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties);
1575 if (!m)
1576 goto finish;
1577
1578 if (!dbus_connection_send(manager->bus, m, NULL))
1579 goto finish;
1580
1581 r = 0;
1582
1583 finish:
1584 if (m)
1585 dbus_message_unref(m);
1586
1587 return r;
1588 }