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