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