chiark / gitweb /
cbf43fe0a0df8e37e98c6a576be688d9d6071808
[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,
1184                           "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(SD_MESSAGE_SHUTDOWN),
1185                           p,
1186                           q, NULL);
1187 }
1188
1189 int bus_manager_shutdown_or_sleep_now_or_later(
1190                 Manager *m,
1191                 const char *unit_name,
1192                 InhibitWhat w,
1193                 DBusError *error) {
1194
1195         bool delayed;
1196         int r;
1197
1198         assert(m);
1199         assert(unit_name);
1200         assert(w >= 0);
1201         assert(w <= _INHIBIT_WHAT_MAX);
1202
1203         delayed =
1204                 m->inhibit_delay_max > 0 &&
1205                 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0);
1206
1207         if (delayed)
1208                 /* Shutdown is delayed, keep in mind what we
1209                  * want to do, and start a timeout */
1210                 r = delay_shutdown_or_sleep(m, w, unit_name);
1211         else {
1212                 bus_manager_log_shutdown(m, w, unit_name);
1213
1214                 /* Shutdown is not delayed, execute it
1215                  * immediately */
1216                 r = send_start_unit(m->bus, unit_name, error);
1217         }
1218
1219         return r;
1220 }
1221
1222 static int bus_manager_do_shutdown_or_sleep(
1223                 Manager *m,
1224                 DBusConnection *connection,
1225                 DBusMessage *message,
1226                 const char *unit_name,
1227                 InhibitWhat w,
1228                 const char *action,
1229                 const char *action_multiple_sessions,
1230                 const char *action_ignore_inhibit,
1231                 const char *sleep_type,
1232                 DBusError *error,
1233                 DBusMessage **_reply) {
1234
1235         dbus_bool_t interactive;
1236         bool multiple_sessions, blocked;
1237         DBusMessage *reply = NULL;
1238         int r;
1239         unsigned long ul;
1240
1241         assert(m);
1242         assert(connection);
1243         assert(message);
1244         assert(unit_name);
1245         assert(w >= 0);
1246         assert(w <= _INHIBIT_WHAT_MAX);
1247         assert(action);
1248         assert(action_multiple_sessions);
1249         assert(action_ignore_inhibit);
1250         assert(error);
1251         assert(_reply);
1252
1253         if (!dbus_message_get_args(
1254                             message,
1255                             error,
1256                             DBUS_TYPE_BOOLEAN, &interactive,
1257                             DBUS_TYPE_INVALID))
1258                 return -EINVAL;
1259
1260         if (sleep_type) {
1261                 r = can_sleep(sleep_type);
1262                 if (r < 0)
1263                         return r;
1264
1265                 if (r == 0)
1266                         return -ENOTSUP;
1267         }
1268
1269         ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
1270         if (ul == (unsigned long) -1)
1271                 return -EIO;
1272
1273         r = have_multiple_sessions(m, (uid_t) ul);
1274         if (r < 0)
1275                 return r;
1276
1277         multiple_sessions = r > 0;
1278         blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, (uid_t) ul);
1279
1280         if (multiple_sessions) {
1281                 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1282                 if (r < 0)
1283                         return r;
1284         }
1285
1286         if (blocked) {
1287                 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1288                 if (r < 0)
1289                         return r;
1290         }
1291
1292         if (!multiple_sessions && !blocked) {
1293                 r = verify_polkit(connection, message, action, interactive, NULL, error);
1294                 if (r < 0)
1295                         return r;
1296         }
1297
1298         r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
1299         if (r < 0)
1300                 return r;
1301
1302         reply = dbus_message_new_method_return(message);
1303         if (!reply)
1304                 return -ENOMEM;
1305
1306         *_reply = reply;
1307         return 0;
1308 }
1309
1310 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_button, handle_button, HandleButton);
1311
1312 static const BusProperty bus_login_manager_properties[] = {
1313         { "ControlGroupHierarchy",  bus_property_append_string,         "s",  offsetof(Manager, cgroup_path),        true },
1314         { "Controllers",            bus_property_append_strv,           "as", offsetof(Manager, controllers),        true },
1315         { "ResetControllers",       bus_property_append_strv,           "as", offsetof(Manager, reset_controllers),  true },
1316         { "NAutoVTs",               bus_property_append_unsigned,       "u",  offsetof(Manager, n_autovts)           },
1317         { "KillOnlyUsers",          bus_property_append_strv,           "as", offsetof(Manager, kill_only_users),    true },
1318         { "KillExcludeUsers",       bus_property_append_strv,           "as", offsetof(Manager, kill_exclude_users), true },
1319         { "KillUserProcesses",      bus_property_append_bool,           "b",  offsetof(Manager, kill_user_processes) },
1320         { "IdleHint",               bus_manager_append_idle_hint,       "b",  0 },
1321         { "IdleSinceHint",          bus_manager_append_idle_hint_since, "t",  0 },
1322         { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t",  0 },
1323         { "BlockInhibited",         bus_manager_append_inhibited,       "s",  0 },
1324         { "DelayInhibited",         bus_manager_append_inhibited,       "s",  0 },
1325         { "InhibitDelayMaxUSec",    bus_property_append_usec,           "t",  offsetof(Manager, inhibit_delay_max)   },
1326         { "HandlePowerKey",         bus_manager_append_handle_button,   "s",  offsetof(Manager, handle_power_key)    },
1327         { "HandleSuspendKey",       bus_manager_append_handle_button,   "s",  offsetof(Manager, handle_suspend_key)  },
1328         { "HandleHibernateKey",     bus_manager_append_handle_button,   "s",  offsetof(Manager, handle_hibernate_key)},
1329         { "HandleLidSwitch",        bus_manager_append_handle_button,   "s",  offsetof(Manager, handle_lid_switch)   },
1330         { "PreparingForShutdown",   bus_manager_append_preparing,       "b",  0 },
1331         { "PreparingForSleep",      bus_manager_append_preparing,       "b",  0 },
1332         { NULL, }
1333 };
1334
1335 static DBusHandlerResult manager_message_handler(
1336                 DBusConnection *connection,
1337                 DBusMessage *message,
1338                 void *userdata) {
1339
1340         Manager *m = userdata;
1341
1342         DBusError error;
1343         DBusMessage *reply = NULL;
1344         int r;
1345
1346         assert(connection);
1347         assert(message);
1348         assert(m);
1349
1350         dbus_error_init(&error);
1351
1352         if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1353                 const char *name;
1354                 char *p;
1355                 Session *session;
1356                 bool b;
1357
1358                 if (!dbus_message_get_args(
1359                                     message,
1360                                     &error,
1361                                     DBUS_TYPE_STRING, &name,
1362                                     DBUS_TYPE_INVALID))
1363                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1364
1365                 session = hashmap_get(m->sessions, name);
1366                 if (!session)
1367                         return bus_send_error_reply(connection, message, &error, -ENOENT);
1368
1369                 reply = dbus_message_new_method_return(message);
1370                 if (!reply)
1371                         goto oom;
1372
1373                 p = session_bus_path(session);
1374                 if (!p)
1375                         goto oom;
1376
1377                 b = dbus_message_append_args(
1378                                 reply,
1379                                 DBUS_TYPE_OBJECT_PATH, &p,
1380                                 DBUS_TYPE_INVALID);
1381                 free(p);
1382
1383                 if (!b)
1384                         goto oom;
1385
1386         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1387                 uint32_t pid;
1388                 char *p;
1389                 Session *session;
1390                 bool b;
1391
1392                 if (!dbus_message_get_args(
1393                                     message,
1394                                     &error,
1395                                     DBUS_TYPE_UINT32, &pid,
1396                                     DBUS_TYPE_INVALID))
1397                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1398
1399                 r = manager_get_session_by_pid(m, pid, &session);
1400                 if (r <= 0)
1401                         return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1402
1403                 reply = dbus_message_new_method_return(message);
1404                 if (!reply)
1405                         goto oom;
1406
1407                 p = session_bus_path(session);
1408                 if (!p)
1409                         goto oom;
1410
1411                 b = dbus_message_append_args(
1412                                 reply,
1413                                 DBUS_TYPE_OBJECT_PATH, &p,
1414                                 DBUS_TYPE_INVALID);
1415                 free(p);
1416
1417                 if (!b)
1418                         goto oom;
1419
1420         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1421                 uint32_t uid;
1422                 char *p;
1423                 User *user;
1424                 bool b;
1425
1426                 if (!dbus_message_get_args(
1427                                     message,
1428                                     &error,
1429                                     DBUS_TYPE_UINT32, &uid,
1430                                     DBUS_TYPE_INVALID))
1431                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1432
1433                 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1434                 if (!user)
1435                         return bus_send_error_reply(connection, message, &error, -ENOENT);
1436
1437                 reply = dbus_message_new_method_return(message);
1438                 if (!reply)
1439                         goto oom;
1440
1441                 p = user_bus_path(user);
1442                 if (!p)
1443                         goto oom;
1444
1445                 b = dbus_message_append_args(
1446                                 reply,
1447                                 DBUS_TYPE_OBJECT_PATH, &p,
1448                                 DBUS_TYPE_INVALID);
1449                 free(p);
1450
1451                 if (!b)
1452                         goto oom;
1453
1454         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1455                 const char *name;
1456                 char *p;
1457                 Seat *seat;
1458                 bool b;
1459
1460                 if (!dbus_message_get_args(
1461                                     message,
1462                                     &error,
1463                                     DBUS_TYPE_STRING, &name,
1464                                     DBUS_TYPE_INVALID))
1465                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1466
1467                 seat = hashmap_get(m->seats, name);
1468                 if (!seat)
1469                         return bus_send_error_reply(connection, message, &error, -ENOENT);
1470
1471                 reply = dbus_message_new_method_return(message);
1472                 if (!reply)
1473                         goto oom;
1474
1475                 p = seat_bus_path(seat);
1476                 if (!p)
1477                         goto oom;
1478
1479                 b = dbus_message_append_args(
1480                                 reply,
1481                                 DBUS_TYPE_OBJECT_PATH, &p,
1482                                 DBUS_TYPE_INVALID);
1483                 free(p);
1484
1485                 if (!b)
1486                         goto oom;
1487
1488         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1489                 char *p;
1490                 Session *session;
1491                 Iterator i;
1492                 DBusMessageIter iter, sub;
1493                 const char *empty = "";
1494
1495                 reply = dbus_message_new_method_return(message);
1496                 if (!reply)
1497                         goto oom;
1498
1499                 dbus_message_iter_init_append(reply, &iter);
1500
1501                 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1502                         goto oom;
1503
1504                 HASHMAP_FOREACH(session, m->sessions, i) {
1505                         DBusMessageIter sub2;
1506                         uint32_t uid;
1507
1508                         if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1509                                 goto oom;
1510
1511                         uid = session->user->uid;
1512
1513                         p = session_bus_path(session);
1514                         if (!p)
1515                                 goto oom;
1516
1517                         if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1518                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1519                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1520                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1521                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1522                                 free(p);
1523                                 goto oom;
1524                         }
1525
1526                         free(p);
1527
1528                         if (!dbus_message_iter_close_container(&sub, &sub2))
1529                                 goto oom;
1530                 }
1531
1532                 if (!dbus_message_iter_close_container(&iter, &sub))
1533                         goto oom;
1534
1535         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1536                 char *p;
1537                 User *user;
1538                 Iterator i;
1539                 DBusMessageIter iter, sub;
1540
1541                 reply = dbus_message_new_method_return(message);
1542                 if (!reply)
1543                         goto oom;
1544
1545                 dbus_message_iter_init_append(reply, &iter);
1546
1547                 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1548                         goto oom;
1549
1550                 HASHMAP_FOREACH(user, m->users, i) {
1551                         DBusMessageIter sub2;
1552                         uint32_t uid;
1553
1554                         if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1555                                 goto oom;
1556
1557                         uid = user->uid;
1558
1559                         p = user_bus_path(user);
1560                         if (!p)
1561                                 goto oom;
1562
1563                         if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1564                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1565                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1566                                 free(p);
1567                                 goto oom;
1568                         }
1569
1570                         free(p);
1571
1572                         if (!dbus_message_iter_close_container(&sub, &sub2))
1573                                 goto oom;
1574                 }
1575
1576                 if (!dbus_message_iter_close_container(&iter, &sub))
1577                         goto oom;
1578
1579         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1580                 char *p;
1581                 Seat *seat;
1582                 Iterator i;
1583                 DBusMessageIter iter, sub;
1584
1585                 reply = dbus_message_new_method_return(message);
1586                 if (!reply)
1587                         goto oom;
1588
1589                 dbus_message_iter_init_append(reply, &iter);
1590
1591                 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1592                         goto oom;
1593
1594                 HASHMAP_FOREACH(seat, m->seats, i) {
1595                         DBusMessageIter sub2;
1596
1597                         if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1598                                 goto oom;
1599
1600                         p = seat_bus_path(seat);
1601                         if (!p)
1602                                 goto oom;
1603
1604                         if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1605                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1606                                 free(p);
1607                                 goto oom;
1608                         }
1609
1610                         free(p);
1611
1612                         if (!dbus_message_iter_close_container(&sub, &sub2))
1613                                 goto oom;
1614                 }
1615
1616                 if (!dbus_message_iter_close_container(&iter, &sub))
1617                         goto oom;
1618
1619         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1620                 Inhibitor *inhibitor;
1621                 Iterator i;
1622                 DBusMessageIter iter, sub;
1623
1624                 reply = dbus_message_new_method_return(message);
1625                 if (!reply)
1626                         goto oom;
1627
1628                 dbus_message_iter_init_append(reply, &iter);
1629
1630                 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1631                         goto oom;
1632
1633                 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1634                         DBusMessageIter sub2;
1635                         dbus_uint32_t uid, pid;
1636                         const char *what, *who, *why, *mode;
1637
1638                         if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1639                                 goto oom;
1640
1641                         what = strempty(inhibit_what_to_string(inhibitor->what));
1642                         who = strempty(inhibitor->who);
1643                         why = strempty(inhibitor->why);
1644                         mode = strempty(inhibit_mode_to_string(inhibitor->mode));
1645                         uid = (dbus_uint32_t) inhibitor->uid;
1646                         pid = (dbus_uint32_t) inhibitor->pid;
1647
1648                         if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1649                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1650                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1651                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
1652                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1653                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1654                                 goto oom;
1655
1656                         if (!dbus_message_iter_close_container(&sub, &sub2))
1657                                 goto oom;
1658                 }
1659
1660                 if (!dbus_message_iter_close_container(&iter, &sub))
1661                         goto oom;
1662
1663         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1664
1665                 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1666
1667                 if (r < 0)
1668                         return bus_send_error_reply(connection, message, &error, r);
1669
1670
1671         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1672
1673                 r = bus_manager_create_session(m, message, &reply);
1674
1675                 /* Don't delay the work on OOM here, since it might be
1676                  * triggered by a low RLIMIT_NOFILE here (since we
1677                  * send a dupped fd to the client), and we'd rather
1678                  * see this fail quickly then be retried later */
1679
1680                 if (r < 0)
1681                         return bus_send_error_reply(connection, message, NULL, r);
1682
1683         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1684                 const char *name;
1685                 Session *session;
1686
1687                 if (!dbus_message_get_args(
1688                                     message,
1689                                     &error,
1690                                     DBUS_TYPE_STRING, &name,
1691                                     DBUS_TYPE_INVALID))
1692                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1693
1694                 session = hashmap_get(m->sessions, name);
1695                 if (!session)
1696                         return bus_send_error_reply(connection, message, &error, -ENOENT);
1697
1698                 /* We use the FIFO to detect stray sessions where the
1699                 process invoking PAM dies abnormally. We need to make
1700                 sure that that process is not killed if at the clean
1701                 end of the session it closes the FIFO. Hence, with
1702                 this call explicitly turn off the FIFO logic, so that
1703                 the PAM code can finish clean up on its own */
1704                 session_remove_fifo(session);
1705
1706                 reply = dbus_message_new_method_return(message);
1707                 if (!reply)
1708                         goto oom;
1709
1710         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1711                 const char *name;
1712                 Session *session;
1713
1714                 if (!dbus_message_get_args(
1715                                     message,
1716                                     &error,
1717                                     DBUS_TYPE_STRING, &name,
1718                                     DBUS_TYPE_INVALID))
1719                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1720
1721                 session = hashmap_get(m->sessions, name);
1722                 if (!session)
1723                         return bus_send_error_reply(connection, message, &error, -ENOENT);
1724
1725                 r = session_activate(session);
1726                 if (r < 0)
1727                         return bus_send_error_reply(connection, message, NULL, r);
1728
1729                 reply = dbus_message_new_method_return(message);
1730                 if (!reply)
1731                         goto oom;
1732
1733         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1734                 const char *session_name, *seat_name;
1735                 Session *session;
1736                 Seat *seat;
1737
1738                 /* Same as ActivateSession() but refuses to work if
1739                  * the seat doesn't match */
1740
1741                 if (!dbus_message_get_args(
1742                                     message,
1743                                     &error,
1744                                     DBUS_TYPE_STRING, &session_name,
1745                                     DBUS_TYPE_STRING, &seat_name,
1746                                     DBUS_TYPE_INVALID))
1747                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1748
1749                 session = hashmap_get(m->sessions, session_name);
1750                 if (!session)
1751                         return bus_send_error_reply(connection, message, &error, -ENOENT);
1752
1753                 seat = hashmap_get(m->seats, seat_name);
1754                 if (!seat)
1755                         return bus_send_error_reply(connection, message, &error, -ENOENT);
1756
1757                 if (session->seat != seat)
1758                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1759
1760                 r = session_activate(session);
1761                 if (r < 0)
1762                         return bus_send_error_reply(connection, message, NULL, r);
1763
1764                 reply = dbus_message_new_method_return(message);
1765                 if (!reply)
1766                         goto oom;
1767
1768         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1769                    dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1770                 const char *name;
1771                 Session *session;
1772
1773                 if (!dbus_message_get_args(
1774                                     message,
1775                                     &error,
1776                                     DBUS_TYPE_STRING, &name,
1777                                     DBUS_TYPE_INVALID))
1778                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1779
1780                 session = hashmap_get(m->sessions, name);
1781                 if (!session)
1782                         return bus_send_error_reply(connection, message, &error, -ENOENT);
1783
1784                 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1785                         goto oom;
1786
1787                 reply = dbus_message_new_method_return(message);
1788                 if (!reply)
1789                         goto oom;
1790
1791         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions")) {
1792                 Session *session;
1793                 Iterator i;
1794
1795                 HASHMAP_FOREACH(session, m->sessions, i)
1796                         if (session_send_lock(session, true) < 0)
1797                                 goto oom;
1798
1799                 reply = dbus_message_new_method_return(message);
1800                 if (!reply)
1801                         goto oom;
1802
1803         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1804                 const char *swho;
1805                 int32_t signo;
1806                 KillWho who;
1807                 const char *name;
1808                 Session *session;
1809
1810                 if (!dbus_message_get_args(
1811                                     message,
1812                                     &error,
1813                                     DBUS_TYPE_STRING, &name,
1814                                     DBUS_TYPE_STRING, &swho,
1815                                     DBUS_TYPE_INT32, &signo,
1816                                     DBUS_TYPE_INVALID))
1817                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1818
1819                 if (isempty(swho))
1820                         who = KILL_ALL;
1821                 else {
1822                         who = kill_who_from_string(swho);
1823                         if (who < 0)
1824                                 return bus_send_error_reply(connection, message, &error, -EINVAL);
1825                 }
1826
1827                 if (signo <= 0 || signo >= _NSIG)
1828                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1829
1830                 session = hashmap_get(m->sessions, name);
1831                 if (!session)
1832                         return bus_send_error_reply(connection, message, &error, -ENOENT);
1833
1834                 r = session_kill(session, who, signo);
1835                 if (r < 0)
1836                         return bus_send_error_reply(connection, message, NULL, r);
1837
1838                 reply = dbus_message_new_method_return(message);
1839                 if (!reply)
1840                         goto oom;
1841
1842         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1843                 uint32_t uid;
1844                 User *user;
1845                 int32_t signo;
1846
1847                 if (!dbus_message_get_args(
1848                                     message,
1849                                     &error,
1850                                     DBUS_TYPE_UINT32, &uid,
1851                                     DBUS_TYPE_INT32, &signo,
1852                                     DBUS_TYPE_INVALID))
1853                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1854
1855                 if (signo <= 0 || signo >= _NSIG)
1856                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1857
1858                 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1859                 if (!user)
1860                         return bus_send_error_reply(connection, message, &error, -ENOENT);
1861
1862                 r = user_kill(user, signo);
1863                 if (r < 0)
1864                         return bus_send_error_reply(connection, message, NULL, r);
1865
1866                 reply = dbus_message_new_method_return(message);
1867                 if (!reply)
1868                         goto oom;
1869
1870         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1871                 const char *name;
1872                 Session *session;
1873
1874                 if (!dbus_message_get_args(
1875                                     message,
1876                                     &error,
1877                                     DBUS_TYPE_STRING, &name,
1878                                     DBUS_TYPE_INVALID))
1879                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1880
1881                 session = hashmap_get(m->sessions, name);
1882                 if (!session)
1883                         return bus_send_error_reply(connection, message, &error, -ENOENT);
1884
1885                 r = session_stop(session);
1886                 if (r < 0)
1887                         return bus_send_error_reply(connection, message, NULL, r);
1888
1889                 reply = dbus_message_new_method_return(message);
1890                 if (!reply)
1891                         goto oom;
1892
1893         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1894                 uint32_t uid;
1895                 User *user;
1896
1897                 if (!dbus_message_get_args(
1898                                     message,
1899                                     &error,
1900                                     DBUS_TYPE_UINT32, &uid,
1901                                     DBUS_TYPE_INVALID))
1902                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1903
1904                 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1905                 if (!user)
1906                         return bus_send_error_reply(connection, message, &error, -ENOENT);
1907
1908                 r = user_stop(user);
1909                 if (r < 0)
1910                         return bus_send_error_reply(connection, message, NULL, r);
1911
1912                 reply = dbus_message_new_method_return(message);
1913                 if (!reply)
1914                         goto oom;
1915
1916         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1917                 const char *name;
1918                 Seat *seat;
1919
1920                 if (!dbus_message_get_args(
1921                                     message,
1922                                     &error,
1923                                     DBUS_TYPE_STRING, &name,
1924                                     DBUS_TYPE_INVALID))
1925                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1926
1927                 seat = hashmap_get(m->seats, name);
1928                 if (!seat)
1929                         return bus_send_error_reply(connection, message, &error, -ENOENT);
1930
1931                 r = seat_stop_sessions(seat);
1932                 if (r < 0)
1933                         return bus_send_error_reply(connection, message, NULL, r);
1934
1935                 reply = dbus_message_new_method_return(message);
1936                 if (!reply)
1937                         goto oom;
1938
1939         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
1940                 uint32_t uid;
1941                 struct passwd *pw;
1942                 dbus_bool_t b, interactive;
1943                 char *path;
1944
1945                 if (!dbus_message_get_args(
1946                                     message,
1947                                     &error,
1948                                     DBUS_TYPE_UINT32, &uid,
1949                                     DBUS_TYPE_BOOLEAN, &b,
1950                                     DBUS_TYPE_BOOLEAN, &interactive,
1951                                     DBUS_TYPE_INVALID))
1952                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1953
1954                 errno = 0;
1955                 pw = getpwuid(uid);
1956                 if (!pw)
1957                         return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
1958
1959                 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
1960                 if (r < 0)
1961                         return bus_send_error_reply(connection, message, &error, r);
1962
1963                 mkdir_p_label("/var/lib/systemd", 0755);
1964
1965                 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
1966                 if (r < 0)
1967                         return bus_send_error_reply(connection, message, &error, r);
1968
1969                 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
1970                 if (!path)
1971                         goto oom;
1972
1973                 if (b) {
1974                         User *u;
1975
1976                         r = touch(path);
1977                         free(path);
1978
1979                         if (r < 0)
1980                                 return bus_send_error_reply(connection, message, &error, r);
1981
1982                         if (manager_add_user_by_uid(m, uid, &u) >= 0)
1983                                 user_start(u);
1984
1985                 } else {
1986                         User *u;
1987
1988                         r = unlink(path);
1989                         free(path);
1990
1991                         if (r < 0 && errno != ENOENT)
1992                                 return bus_send_error_reply(connection, message, &error, -errno);
1993
1994                         u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1995                         if (u)
1996                                 user_add_to_gc_queue(u);
1997                 }
1998
1999                 reply = dbus_message_new_method_return(message);
2000                 if (!reply)
2001                         goto oom;
2002
2003         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
2004                 const char *sysfs, *seat;
2005                 dbus_bool_t interactive;
2006
2007                 if (!dbus_message_get_args(
2008                                     message,
2009                                     &error,
2010                                     DBUS_TYPE_STRING, &seat,
2011                                     DBUS_TYPE_STRING, &sysfs,
2012                                     DBUS_TYPE_BOOLEAN, &interactive,
2013                                     DBUS_TYPE_INVALID))
2014                         return bus_send_error_reply(connection, message, &error, -EINVAL);
2015
2016                 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
2017                         return bus_send_error_reply(connection, message, NULL, -EINVAL);
2018
2019                 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
2020                 if (r < 0)
2021                         return bus_send_error_reply(connection, message, &error, r);
2022
2023                 r = attach_device(m, seat, sysfs);
2024                 if (r < 0)
2025                         return bus_send_error_reply(connection, message, NULL, -EINVAL);
2026
2027                 reply = dbus_message_new_method_return(message);
2028                 if (!reply)
2029                         goto oom;
2030
2031
2032         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
2033                 dbus_bool_t interactive;
2034
2035                 if (!dbus_message_get_args(
2036                                     message,
2037                                     &error,
2038                                     DBUS_TYPE_BOOLEAN, &interactive,
2039                                     DBUS_TYPE_INVALID))
2040                         return bus_send_error_reply(connection, message, &error, -EINVAL);
2041
2042                 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
2043                 if (r < 0)
2044                         return bus_send_error_reply(connection, message, &error, r);
2045
2046                 r = flush_devices(m);
2047                 if (r < 0)
2048                         return bus_send_error_reply(connection, message, NULL, -EINVAL);
2049
2050                 reply = dbus_message_new_method_return(message);
2051                 if (!reply)
2052                         goto oom;
2053
2054         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
2055
2056                 r = bus_manager_do_shutdown_or_sleep(
2057                                 m, connection, message,
2058                                 SPECIAL_POWEROFF_TARGET,
2059                                 INHIBIT_SHUTDOWN,
2060                                 "org.freedesktop.login1.power-off",
2061                                 "org.freedesktop.login1.power-off-multiple-sessions",
2062                                 "org.freedesktop.login1.power-off-ignore-inhibit",
2063                                 NULL,
2064                                 &error, &reply);
2065                 if (r < 0)
2066                         return bus_send_error_reply(connection, message, &error, r);
2067         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
2068                 r = bus_manager_do_shutdown_or_sleep(
2069                                 m, connection, message,
2070                                 SPECIAL_REBOOT_TARGET,
2071                                 INHIBIT_SHUTDOWN,
2072                                 "org.freedesktop.login1.reboot",
2073                                 "org.freedesktop.login1.reboot-multiple-sessions",
2074                                 "org.freedesktop.login1.reboot-ignore-inhibit",
2075                                 NULL,
2076                                 &error, &reply);
2077                 if (r < 0)
2078                         return bus_send_error_reply(connection, message, &error, r);
2079
2080         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2081                 r = bus_manager_do_shutdown_or_sleep(
2082                                 m, connection, message,
2083                                 SPECIAL_SUSPEND_TARGET,
2084                                 INHIBIT_SLEEP,
2085                                 "org.freedesktop.login1.suspend",
2086                                 "org.freedesktop.login1.suspend-multiple-sessions",
2087                                 "org.freedesktop.login1.suspend-ignore-inhibit",
2088                                 "mem",
2089                                 &error, &reply);
2090                 if (r < 0)
2091                         return bus_send_error_reply(connection, message, &error, r);
2092         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2093                 r = bus_manager_do_shutdown_or_sleep(
2094                                 m, connection, message,
2095                                 SPECIAL_HIBERNATE_TARGET,
2096                                 INHIBIT_SLEEP,
2097                                 "org.freedesktop.login1.hibernate",
2098                                 "org.freedesktop.login1.hibernate-multiple-sessions",
2099                                 "org.freedesktop.login1.hibernate-ignore-inhibit",
2100                                 "disk",
2101                                 &error, &reply);
2102                 if (r < 0)
2103                         return bus_send_error_reply(connection, message, &error, r);
2104
2105         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2106
2107                 r = bus_manager_can_shutdown_or_sleep(
2108                                 m, connection, message,
2109                                 INHIBIT_SHUTDOWN,
2110                                 "org.freedesktop.login1.power-off",
2111                                 "org.freedesktop.login1.power-off-multiple-sessions",
2112                                 "org.freedesktop.login1.power-off-ignore-inhibit",
2113                                 NULL,
2114                                 &error, &reply);
2115                 if (r < 0)
2116                         return bus_send_error_reply(connection, message, &error, r);
2117         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2118                 r = bus_manager_can_shutdown_or_sleep(
2119                                 m, connection, message,
2120                                 INHIBIT_SHUTDOWN,
2121                                 "org.freedesktop.login1.reboot",
2122                                 "org.freedesktop.login1.reboot-multiple-sessions",
2123                                 "org.freedesktop.login1.reboot-ignore-inhibit",
2124                                 NULL,
2125                                 &error, &reply);
2126                 if (r < 0)
2127                         return bus_send_error_reply(connection, message, &error, r);
2128
2129         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2130                 r = bus_manager_can_shutdown_or_sleep(
2131                                 m, connection, message,
2132                                 INHIBIT_SLEEP,
2133                                 "org.freedesktop.login1.suspend",
2134                                 "org.freedesktop.login1.suspend-multiple-sessions",
2135                                 "org.freedesktop.login1.suspend-ignore-inhibit",
2136                                 "mem",
2137                                 &error, &reply);
2138                 if (r < 0)
2139                         return bus_send_error_reply(connection, message, &error, r);
2140
2141         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2142                 r = bus_manager_can_shutdown_or_sleep(
2143                                 m, connection, message,
2144                                 INHIBIT_SLEEP,
2145                                 "org.freedesktop.login1.hibernate",
2146                                 "org.freedesktop.login1.hibernate-multiple-sessions",
2147                                 "org.freedesktop.login1.hibernate-ignore-inhibit",
2148                                 "disk",
2149                                 &error, &reply);
2150                 if (r < 0)
2151                         return bus_send_error_reply(connection, message, &error, r);
2152
2153         } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2154                 char *introspection = NULL;
2155                 FILE *f;
2156                 Iterator i;
2157                 Session *session;
2158                 Seat *seat;
2159                 User *user;
2160                 size_t size;
2161                 char *p;
2162
2163                 if (!(reply = dbus_message_new_method_return(message)))
2164                         goto oom;
2165
2166                 /* We roll our own introspection code here, instead of
2167                  * relying on bus_default_message_handler() because we
2168                  * need to generate our introspection string
2169                  * dynamically. */
2170
2171                 if (!(f = open_memstream(&introspection, &size)))
2172                         goto oom;
2173
2174                 fputs(INTROSPECTION_BEGIN, f);
2175
2176                 HASHMAP_FOREACH(seat, m->seats, i) {
2177                         p = bus_path_escape(seat->id);
2178
2179                         if (p) {
2180                                 fprintf(f, "<node name=\"seat/%s\"/>", p);
2181                                 free(p);
2182                         }
2183                 }
2184
2185                 HASHMAP_FOREACH(user, m->users, i)
2186                         fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2187
2188                 HASHMAP_FOREACH(session, m->sessions, i) {
2189                         p = bus_path_escape(session->id);
2190
2191                         if (p) {
2192                                 fprintf(f, "<node name=\"session/%s\"/>", p);
2193                                 free(p);
2194                         }
2195                 }
2196
2197                 fputs(INTROSPECTION_END, f);
2198
2199                 if (ferror(f)) {
2200                         fclose(f);
2201                         free(introspection);
2202                         goto oom;
2203                 }
2204
2205                 fclose(f);
2206
2207                 if (!introspection)
2208                         goto oom;
2209
2210                 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2211                         free(introspection);
2212                         goto oom;
2213                 }
2214
2215                 free(introspection);
2216         } else {
2217                 const BusBoundProperties bps[] = {
2218                         { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2219                         { NULL, }
2220                 };
2221                 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2222         }
2223
2224         if (reply) {
2225                 if (!dbus_connection_send(connection, reply, NULL))
2226                         goto oom;
2227
2228                 dbus_message_unref(reply);
2229         }
2230
2231         return DBUS_HANDLER_RESULT_HANDLED;
2232
2233 oom:
2234         if (reply)
2235                 dbus_message_unref(reply);
2236
2237         dbus_error_free(&error);
2238
2239         return DBUS_HANDLER_RESULT_NEED_MEMORY;
2240 }
2241
2242 const DBusObjectPathVTable bus_manager_vtable = {
2243         .message_function = manager_message_handler
2244 };
2245
2246 DBusHandlerResult bus_message_filter(
2247                 DBusConnection *connection,
2248                 DBusMessage *message,
2249                 void *userdata) {
2250
2251         Manager *m = userdata;
2252         DBusError error;
2253
2254         assert(m);
2255         assert(connection);
2256         assert(message);
2257
2258         dbus_error_init(&error);
2259
2260         if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
2261                 const char *cgroup;
2262
2263                 if (!dbus_message_get_args(message, &error,
2264                                            DBUS_TYPE_STRING, &cgroup,
2265                                            DBUS_TYPE_INVALID))
2266                         log_error("Failed to parse Released message: %s", bus_error_message(&error));
2267                 else
2268                         manager_cgroup_notify_empty(m, cgroup);
2269         }
2270
2271         dbus_error_free(&error);
2272
2273         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2274 }
2275
2276 int manager_send_changed(Manager *manager, const char *properties) {
2277         DBusMessage *m;
2278         int r = -ENOMEM;
2279
2280         assert(manager);
2281
2282         m = bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties);
2283         if (!m)
2284                 goto finish;
2285
2286         if (!dbus_connection_send(manager->bus, m, NULL))
2287                 goto finish;
2288
2289         r = 0;
2290
2291 finish:
2292         if (m)
2293                 dbus_message_unref(m);
2294
2295         return r;
2296 }
2297
2298 int manager_dispatch_delayed(Manager *manager) {
2299         const char *unit_name;
2300         DBusError error;
2301         bool delayed;
2302         int r;
2303
2304         assert(manager);
2305
2306         if (!manager->delayed_unit)
2307                 return 0;
2308
2309         /* Continue delay? */
2310         delayed =
2311                 manager->delayed_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC) &&
2312                 manager_is_inhibited(manager, manager->delayed_what, INHIBIT_DELAY, NULL, false, false, 0);
2313         if (delayed)
2314                 return 0;
2315
2316         bus_manager_log_shutdown(manager, manager->delayed_what, manager->delayed_unit);
2317
2318         /* Reset delay data */
2319         unit_name = manager->delayed_unit;
2320         manager->delayed_unit = NULL;
2321
2322         /* Actually do the shutdown */
2323         dbus_error_init(&error);
2324         r = send_start_unit(manager->bus, unit_name, &error);
2325         if (r < 0) {
2326                 log_warning("Failed to send delayed message: %s", bus_error_message_or_strerror(&error, -r));
2327                 dbus_error_free(&error);
2328                 return r;
2329         }
2330
2331         /* Tell people about it */
2332         send_prepare_for(manager, manager->delayed_what, false);
2333
2334         return 1;
2335 }