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