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