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