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