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