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