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