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