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