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