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