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