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