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