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