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