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