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