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