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