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