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