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