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