chiark / gitweb /
update TODO
[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         /* Delay is only supported for shutdown/sleep */
726         if (mm == INHIBIT_DELAY && (w & ~(INHIBIT_SHUTDOWN|INHIBIT_SLEEP))) {
727                 r = -EINVAL;
728                 goto fail;
729         }
730
731         r = verify_polkit(connection, message,
732                           w == INHIBIT_SHUTDOWN         ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-shutdown" : "org.freedesktop.login1.inhibit-delay-shutdown") :
733                           w == INHIBIT_SLEEP            ? (mm == INHIBIT_BLOCK ? "org.freedesktop.login1.inhibit-block-sleep"    : "org.freedesktop.login1.inhibit-delay-sleep") :
734                           w == INHIBIT_IDLE             ? "org.freedesktop.login1.inhibit-block-idle" :
735                           w == INHIBIT_HANDLE_POWER_KEY ? "org.freedesktop.login1.inhibit-handle-power-key" :
736                           w == INHIBIT_HANDLE_SLEEP_KEY ? "org.freedesktop.login1.inhibit-handle-sleep-key" :
737                                                           "org.freedesktop.login1.inhibit-handle-lid-switch",
738                           false, NULL, error);
739         if (r < 0)
740                 goto fail;
741
742         ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
743         if (ul == (unsigned long) -1) {
744                 r = -EIO;
745                 goto fail;
746         }
747
748         pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
749         if (pid <= 0) {
750                 r = -EIO;
751                 goto fail;
752         }
753
754         do {
755                 free(id);
756                 id = NULL;
757
758                 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
759                         r = -ENOMEM;
760                         goto fail;
761                 }
762         } while (hashmap_get(m->inhibitors, id));
763
764         r = manager_add_inhibitor(m, id, &i);
765         free(id);
766
767         if (r < 0)
768                 goto fail;
769
770         i->what = w;
771         i->mode = mm;
772         i->pid = pid;
773         i->uid = (uid_t) ul;
774         i->why = strdup(why);
775         i->who = strdup(who);
776
777         if (!i->why || !i->who) {
778                 r = -ENOMEM;
779                 goto fail;
780         }
781
782         fifo_fd = inhibitor_create_fifo(i);
783         if (fifo_fd < 0) {
784                 r = fifo_fd;
785                 goto fail;
786         }
787
788         reply = dbus_message_new_method_return(message);
789         if (!reply) {
790                 r = -ENOMEM;
791                 goto fail;
792         }
793
794         if (!dbus_message_append_args(
795                             reply,
796                             DBUS_TYPE_UNIX_FD, &fifo_fd,
797                             DBUS_TYPE_INVALID)) {
798                 r = -ENOMEM;
799                 goto fail;
800         }
801
802         close_nointr_nofail(fifo_fd);
803         *_reply = reply;
804
805         inhibitor_start(i);
806
807         return 0;
808
809 fail:
810         if (i)
811                 inhibitor_free(i);
812
813         if (fifo_fd >= 0)
814                 close_nointr_nofail(fifo_fd);
815
816         if (reply)
817                 dbus_message_unref(reply);
818
819         return r;
820 }
821
822 static int trigger_device(Manager *m, struct udev_device *d) {
823         struct udev_enumerate *e;
824         struct udev_list_entry *first, *item;
825         int r;
826
827         assert(m);
828
829         e = udev_enumerate_new(m->udev);
830         if (!e) {
831                 r = -ENOMEM;
832                 goto finish;
833         }
834
835         if (d) {
836                 if (udev_enumerate_add_match_parent(e, d) < 0) {
837                         r = -EIO;
838                         goto finish;
839                 }
840         }
841
842         if (udev_enumerate_scan_devices(e) < 0) {
843                 r = -EIO;
844                 goto finish;
845         }
846
847         first = udev_enumerate_get_list_entry(e);
848         udev_list_entry_foreach(item, first) {
849                 char *t;
850                 const char *p;
851
852                 p = udev_list_entry_get_name(item);
853
854                 t = strappend(p, "/uevent");
855                 if (!t) {
856                         r = -ENOMEM;
857                         goto finish;
858                 }
859
860                 write_one_line_file(t, "change");
861                 free(t);
862         }
863
864         r = 0;
865
866 finish:
867         if (e)
868                 udev_enumerate_unref(e);
869
870         return r;
871 }
872
873 static int attach_device(Manager *m, const char *seat, const char *sysfs) {
874         struct udev_device *d;
875         char *rule = NULL, *file = NULL;
876         const char *id_for_seat;
877         int r;
878
879         assert(m);
880         assert(seat);
881         assert(sysfs);
882
883         d = udev_device_new_from_syspath(m->udev, sysfs);
884         if (!d)
885                 return -ENODEV;
886
887         if (!udev_device_has_tag(d, "seat")) {
888                 r = -ENODEV;
889                 goto finish;
890         }
891
892         id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
893         if (!id_for_seat) {
894                 r = -ENODEV;
895                 goto finish;
896         }
897
898         if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
899                 r = -ENOMEM;
900                 goto finish;
901         }
902
903         if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
904                 r = -ENOMEM;
905                 goto finish;
906         }
907
908         mkdir_p_label("/etc/udev/rules.d", 0755);
909         r = write_one_line_file_atomic(file, rule);
910         if (r < 0)
911                 goto finish;
912
913         r = trigger_device(m, d);
914
915 finish:
916         free(rule);
917         free(file);
918
919         if (d)
920                 udev_device_unref(d);
921
922         return r;
923 }
924
925 static int flush_devices(Manager *m) {
926         DIR *d;
927
928         assert(m);
929
930         d = opendir("/etc/udev/rules.d");
931         if (!d) {
932                 if (errno != ENOENT)
933                         log_warning("Failed to open /etc/udev/rules.d: %m");
934         } else {
935                 struct dirent *de;
936
937                 while ((de = readdir(d))) {
938
939                         if (!dirent_is_file(de))
940                                 continue;
941
942                         if (!startswith(de->d_name, "72-seat-"))
943                                 continue;
944
945                         if (!endswith(de->d_name, ".rules"))
946                                 continue;
947
948                         if (unlinkat(dirfd(d), de->d_name, 0) < 0)
949                                 log_warning("Failed to unlink %s: %m", de->d_name);
950                 }
951
952                 closedir(d);
953         }
954
955         return trigger_device(m, NULL);
956 }
957
958 static int have_multiple_sessions(
959                 DBusConnection *connection,
960                 Manager *m,
961                 DBusMessage *message,
962                 DBusError *error) {
963
964         Session *session;
965         Iterator i;
966         unsigned long ul;
967
968         assert(m);
969
970         ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
971         if (ul == (unsigned long) -1)
972                 return -EIO;
973
974         /* Check for other users' sessions. Greeter sessions do not count. */
975         HASHMAP_FOREACH(session, m->sessions, i)
976                 if (session->class == SESSION_USER && session->user->uid != ul)
977                         return true;
978
979         return false;
980 }
981
982 static int send_start_unit(DBusConnection *connection, const char *unit_name, DBusError *error) {
983         const char *mode = "replace";
984
985         assert(unit_name);
986
987         return bus_method_call_with_reply (
988                         connection,
989                         "org.freedesktop.systemd1",
990                         "/org/freedesktop/systemd1",
991                         "org.freedesktop.systemd1.Manager",
992                         "StartUnit",
993                         NULL,
994                         NULL,
995                         DBUS_TYPE_STRING, &unit_name,
996                         DBUS_TYPE_STRING, &mode,
997                         DBUS_TYPE_INVALID);
998 }
999
1000 static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
1001         static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
1002                 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
1003                 [INHIBIT_SLEEP] = "PrepareForSleep"
1004         };
1005
1006         dbus_bool_t active = _active;
1007         DBusMessage *message;
1008         int r = 0;
1009
1010         assert(m);
1011         assert(w >= 0);
1012         assert(w < _INHIBIT_WHAT_MAX);
1013         assert(signal_name[w]);
1014
1015         message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
1016         if (!message)
1017                 return -ENOMEM;
1018
1019         if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1020             !dbus_connection_send(m->bus, message, NULL))
1021                 r = -ENOMEM;
1022
1023         dbus_message_unref(message);
1024         return r;
1025 }
1026
1027 static int delay_shutdown_or_sleep(Manager *m, InhibitWhat w, const char *unit_name) {
1028         assert(m);
1029         assert(w >= 0);
1030         assert(w < _INHIBIT_WHAT_MAX);
1031
1032         /* Tell everybody to prepare for shutdown/sleep */
1033         send_prepare_for(m, w, true);
1034
1035         /* Update timestamp for timeout */
1036         if (!m->delayed_unit)
1037                 m->delayed_timestamp = now(CLOCK_MONOTONIC);
1038
1039         /* Remember what we want to do, possibly overriding what kind
1040          * of unit we previously queued. */
1041         m->delayed_unit = unit_name;
1042         m->delayed_what = w;
1043
1044         return 0;
1045 }
1046
1047 static int bus_manager_can_shutdown_or_sleep(
1048                 Manager *m,
1049                 DBusConnection *connection,
1050                 DBusMessage *message,
1051                 InhibitWhat w,
1052                 const char *action,
1053                 const char *action_multiple_sessions,
1054                 const char *action_ignore_inhibit,
1055                 const char *sleep_type,
1056                 DBusError *error,
1057                 DBusMessage **_reply) {
1058
1059         bool multiple_sessions, challenge, blocked, b;
1060         const char *result;
1061         DBusMessage *reply = NULL;
1062         int r;
1063
1064         assert(m);
1065         assert(connection);
1066         assert(message);
1067         assert(w >= 0);
1068         assert(w <= _INHIBIT_WHAT_MAX);
1069         assert(action);
1070         assert(action_multiple_sessions);
1071         assert(action_ignore_inhibit);
1072         assert(error);
1073         assert(_reply);
1074
1075         if (sleep_type) {
1076                 r = can_sleep(sleep_type);
1077                 if (r < 0)
1078                         return r;
1079
1080                 if (r == 0) {
1081                         result = "na";
1082                         goto finish;
1083                 }
1084         }
1085
1086         r = have_multiple_sessions(connection, m, message, error);
1087         if (r < 0)
1088                 return r;
1089
1090         multiple_sessions = r > 0;
1091         blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false);
1092
1093         if (multiple_sessions) {
1094                 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1095                 if (r < 0)
1096                         return r;
1097
1098                 if (r > 0)
1099                         result = "yes";
1100                 else if (challenge)
1101                         result = "challenge";
1102                 else
1103                         result = "no";
1104         }
1105
1106         if (blocked) {
1107                 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1108                 if (r < 0)
1109                         return r;
1110
1111                 if (r > 0 && !result)
1112                         result = "yes";
1113                 else if (challenge && (!result || streq(result, "yes")))
1114                         result = "challenge";
1115                 else
1116                         result = "no";
1117         }
1118
1119         if (!multiple_sessions && !blocked) {
1120                 /* If neither inhibit nor multiple sessions
1121                  * apply then just check the normal policy */
1122
1123                 r = verify_polkit(connection, message, action, false, &challenge, error);
1124                 if (r < 0)
1125                         return r;
1126
1127                 if (r > 0)
1128                         result = "yes";
1129                 else if (challenge)
1130                         result = "challenge";
1131                 else
1132                         result = "no";
1133         }
1134
1135 finish:
1136         reply = dbus_message_new_method_return(message);
1137         if (!reply)
1138                 return -ENOMEM;
1139
1140         b = dbus_message_append_args(
1141                         reply,
1142                         DBUS_TYPE_STRING, &result,
1143                         DBUS_TYPE_INVALID);
1144         if (!b) {
1145                 dbus_message_unref(reply);
1146                 return -ENOMEM;
1147         }
1148
1149         *_reply = reply;
1150         return 0;
1151 }
1152
1153 static int bus_manager_log_shutdown(
1154                 Manager *m,
1155                 InhibitWhat w,
1156                 const char *unit_name) {
1157
1158         const char *p, *q;
1159
1160         assert(m);
1161         assert(unit_name);
1162
1163         if (w != INHIBIT_SHUTDOWN)
1164                 return 0;
1165
1166         if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
1167                 p = "MESSAGE=System is powering down.";
1168                 q = "SHUTDOWN=power-off";
1169         } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
1170                 p = "MESSAGE=System is halting.";
1171                 q = "SHUTDOWN=halt";
1172         } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
1173                 p = "MESSAGE=System is rebooting.";
1174                 q = "SHUTDOWN=reboot";
1175         } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
1176                 p = "MESSAGE=System is rebooting with kexec.";
1177                 q = "SHUTDOWN=kexec";
1178         } else {
1179                 p = "MESSAGE=System is shutting down.";
1180                 q = NULL;
1181         }
1182
1183         return log_struct(LOG_NOTICE,
1184                           "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(SD_MESSAGE_SHUTDOWN),
1185                           p,
1186                           q, NULL);
1187 }
1188
1189 int bus_manager_shutdown_or_sleep_now_or_later(
1190                 Manager *m,
1191                 const char *unit_name,
1192                 InhibitWhat w,
1193                 DBusError *error) {
1194
1195         bool delayed;
1196         int r;
1197
1198         assert(m);
1199         assert(unit_name);
1200         assert(w >= 0);
1201         assert(w <= _INHIBIT_WHAT_MAX);
1202
1203         delayed =
1204                 m->inhibit_delay_max > 0 &&
1205                 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false);
1206
1207         if (delayed)
1208                 /* Shutdown is delayed, keep in mind what we
1209                  * want to do, and start a timeout */
1210                 r = delay_shutdown_or_sleep(m, w, unit_name);
1211         else {
1212                 bus_manager_log_shutdown(m, w, unit_name);
1213
1214                 /* Shutdown is not delayed, execute it
1215                  * immediately */
1216                 r = send_start_unit(m->bus, unit_name, error);
1217         }
1218
1219         return r;
1220 }
1221
1222 static int bus_manager_do_shutdown_or_sleep(
1223                 Manager *m,
1224                 DBusConnection *connection,
1225                 DBusMessage *message,
1226                 const char *unit_name,
1227                 InhibitWhat w,
1228                 const char *action,
1229                 const char *action_multiple_sessions,
1230                 const char *action_ignore_inhibit,
1231                 const char *sleep_type,
1232                 DBusError *error,
1233                 DBusMessage **_reply) {
1234
1235         dbus_bool_t interactive;
1236         bool multiple_sessions, blocked;
1237         DBusMessage *reply = NULL;
1238         int r;
1239
1240         assert(m);
1241         assert(connection);
1242         assert(message);
1243         assert(unit_name);
1244         assert(w >= 0);
1245         assert(w <= _INHIBIT_WHAT_MAX);
1246         assert(action);
1247         assert(action_multiple_sessions);
1248         assert(action_ignore_inhibit);
1249         assert(error);
1250         assert(_reply);
1251
1252         if (!dbus_message_get_args(
1253                             message,
1254                             error,
1255                             DBUS_TYPE_BOOLEAN, &interactive,
1256                             DBUS_TYPE_INVALID))
1257                 return -EINVAL;
1258
1259         if (sleep_type) {
1260                 r = can_sleep(sleep_type);
1261                 if (r < 0)
1262                         return r;
1263
1264                 if (r == 0)
1265                         return -ENOTSUP;
1266         }
1267
1268         r = have_multiple_sessions(connection, m, message, error);
1269         if (r < 0)
1270                 return r;
1271
1272         multiple_sessions = r > 0;
1273         blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false);
1274
1275         if (multiple_sessions) {
1276                 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1277                 if (r < 0)
1278                         return r;
1279         }
1280
1281         if (blocked) {
1282                 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1283                 if (r < 0)
1284                         return r;
1285         }
1286
1287         if (!multiple_sessions && !blocked) {
1288                 r = verify_polkit(connection, message, action, interactive, NULL, error);
1289                 if (r < 0)
1290                         return r;
1291         }
1292
1293         r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
1294         if (r < 0)
1295                 return r;
1296
1297         reply = dbus_message_new_method_return(message);
1298         if (!reply)
1299                 return -ENOMEM;
1300
1301         *_reply = reply;
1302         return 0;
1303 }
1304
1305 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_button, handle_button, HandleButton);
1306
1307 static const BusProperty bus_login_manager_properties[] = {
1308         { "ControlGroupHierarchy",  bus_property_append_string,         "s",  offsetof(Manager, cgroup_path),        true },
1309         { "Controllers",            bus_property_append_strv,           "as", offsetof(Manager, controllers),        true },
1310         { "ResetControllers",       bus_property_append_strv,           "as", offsetof(Manager, reset_controllers),  true },
1311         { "NAutoVTs",               bus_property_append_unsigned,       "u",  offsetof(Manager, n_autovts)           },
1312         { "KillOnlyUsers",          bus_property_append_strv,           "as", offsetof(Manager, kill_only_users),    true },
1313         { "KillExcludeUsers",       bus_property_append_strv,           "as", offsetof(Manager, kill_exclude_users), true },
1314         { "KillUserProcesses",      bus_property_append_bool,           "b",  offsetof(Manager, kill_user_processes) },
1315         { "IdleHint",               bus_manager_append_idle_hint,       "b",  0 },
1316         { "IdleSinceHint",          bus_manager_append_idle_hint_since, "t",  0 },
1317         { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t",  0 },
1318         { "BlockInhibited",         bus_manager_append_inhibited,       "s",  0 },
1319         { "DelayInhibited",         bus_manager_append_inhibited,       "s",  0 },
1320         { "InhibitDelayMaxUSec",    bus_property_append_usec,           "t",  offsetof(Manager, inhibit_delay_max)   },
1321         { "HandlePowerKey",         bus_manager_append_handle_button,   "s",  offsetof(Manager, handle_power_key)    },
1322         { "HandleSleepKey",         bus_manager_append_handle_button,   "s",  offsetof(Manager, handle_sleep_key)    },
1323         { "HandleLidSwitch",        bus_manager_append_handle_button,   "s",  offsetof(Manager, handle_lid_switch)   },
1324         { "PreparingForShutdown",   bus_manager_append_preparing,       "b",  0 },
1325         { "PreparingForSleep",      bus_manager_append_preparing,       "b",  0 },
1326         { NULL, }
1327 };
1328
1329 static DBusHandlerResult manager_message_handler(
1330                 DBusConnection *connection,
1331                 DBusMessage *message,
1332                 void *userdata) {
1333
1334         Manager *m = userdata;
1335
1336         DBusError error;
1337         DBusMessage *reply = NULL;
1338         int r;
1339
1340         assert(connection);
1341         assert(message);
1342         assert(m);
1343
1344         dbus_error_init(&error);
1345
1346         if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1347                 const char *name;
1348                 char *p;
1349                 Session *session;
1350                 bool b;
1351
1352                 if (!dbus_message_get_args(
1353                                     message,
1354                                     &error,
1355                                     DBUS_TYPE_STRING, &name,
1356                                     DBUS_TYPE_INVALID))
1357                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1358
1359                 session = hashmap_get(m->sessions, name);
1360                 if (!session)
1361                         return bus_send_error_reply(connection, message, &error, -ENOENT);
1362
1363                 reply = dbus_message_new_method_return(message);
1364                 if (!reply)
1365                         goto oom;
1366
1367                 p = session_bus_path(session);
1368                 if (!p)
1369                         goto oom;
1370
1371                 b = dbus_message_append_args(
1372                                 reply,
1373                                 DBUS_TYPE_OBJECT_PATH, &p,
1374                                 DBUS_TYPE_INVALID);
1375                 free(p);
1376
1377                 if (!b)
1378                         goto oom;
1379
1380         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1381                 uint32_t pid;
1382                 char *p;
1383                 Session *session;
1384                 bool b;
1385
1386                 if (!dbus_message_get_args(
1387                                     message,
1388                                     &error,
1389                                     DBUS_TYPE_UINT32, &pid,
1390                                     DBUS_TYPE_INVALID))
1391                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1392
1393                 r = manager_get_session_by_pid(m, pid, &session);
1394                 if (r <= 0)
1395                         return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1396
1397                 reply = dbus_message_new_method_return(message);
1398                 if (!reply)
1399                         goto oom;
1400
1401                 p = session_bus_path(session);
1402                 if (!p)
1403                         goto oom;
1404
1405                 b = dbus_message_append_args(
1406                                 reply,
1407                                 DBUS_TYPE_OBJECT_PATH, &p,
1408                                 DBUS_TYPE_INVALID);
1409                 free(p);
1410
1411                 if (!b)
1412                         goto oom;
1413
1414         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1415                 uint32_t uid;
1416                 char *p;
1417                 User *user;
1418                 bool b;
1419
1420                 if (!dbus_message_get_args(
1421                                     message,
1422                                     &error,
1423                                     DBUS_TYPE_UINT32, &uid,
1424                                     DBUS_TYPE_INVALID))
1425                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1426
1427                 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1428                 if (!user)
1429                         return bus_send_error_reply(connection, message, &error, -ENOENT);
1430
1431                 reply = dbus_message_new_method_return(message);
1432                 if (!reply)
1433                         goto oom;
1434
1435                 p = user_bus_path(user);
1436                 if (!p)
1437                         goto oom;
1438
1439                 b = dbus_message_append_args(
1440                                 reply,
1441                                 DBUS_TYPE_OBJECT_PATH, &p,
1442                                 DBUS_TYPE_INVALID);
1443                 free(p);
1444
1445                 if (!b)
1446                         goto oom;
1447
1448         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1449                 const char *name;
1450                 char *p;
1451                 Seat *seat;
1452                 bool b;
1453
1454                 if (!dbus_message_get_args(
1455                                     message,
1456                                     &error,
1457                                     DBUS_TYPE_STRING, &name,
1458                                     DBUS_TYPE_INVALID))
1459                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1460
1461                 seat = hashmap_get(m->seats, name);
1462                 if (!seat)
1463                         return bus_send_error_reply(connection, message, &error, -ENOENT);
1464
1465                 reply = dbus_message_new_method_return(message);
1466                 if (!reply)
1467                         goto oom;
1468
1469                 p = seat_bus_path(seat);
1470                 if (!p)
1471                         goto oom;
1472
1473                 b = dbus_message_append_args(
1474                                 reply,
1475                                 DBUS_TYPE_OBJECT_PATH, &p,
1476                                 DBUS_TYPE_INVALID);
1477                 free(p);
1478
1479                 if (!b)
1480                         goto oom;
1481
1482         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1483                 char *p;
1484                 Session *session;
1485                 Iterator i;
1486                 DBusMessageIter iter, sub;
1487                 const char *empty = "";
1488
1489                 reply = dbus_message_new_method_return(message);
1490                 if (!reply)
1491                         goto oom;
1492
1493                 dbus_message_iter_init_append(reply, &iter);
1494
1495                 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
1496                         goto oom;
1497
1498                 HASHMAP_FOREACH(session, m->sessions, i) {
1499                         DBusMessageIter sub2;
1500                         uint32_t uid;
1501
1502                         if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1503                                 goto oom;
1504
1505                         uid = session->user->uid;
1506
1507                         p = session_bus_path(session);
1508                         if (!p)
1509                                 goto oom;
1510
1511                         if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1512                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1513                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1514                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1515                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1516                                 free(p);
1517                                 goto oom;
1518                         }
1519
1520                         free(p);
1521
1522                         if (!dbus_message_iter_close_container(&sub, &sub2))
1523                                 goto oom;
1524                 }
1525
1526                 if (!dbus_message_iter_close_container(&iter, &sub))
1527                         goto oom;
1528
1529         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1530                 char *p;
1531                 User *user;
1532                 Iterator i;
1533                 DBusMessageIter iter, sub;
1534
1535                 reply = dbus_message_new_method_return(message);
1536                 if (!reply)
1537                         goto oom;
1538
1539                 dbus_message_iter_init_append(reply, &iter);
1540
1541                 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
1542                         goto oom;
1543
1544                 HASHMAP_FOREACH(user, m->users, i) {
1545                         DBusMessageIter sub2;
1546                         uint32_t uid;
1547
1548                         if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1549                                 goto oom;
1550
1551                         uid = user->uid;
1552
1553                         p = user_bus_path(user);
1554                         if (!p)
1555                                 goto oom;
1556
1557                         if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1558                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1559                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1560                                 free(p);
1561                                 goto oom;
1562                         }
1563
1564                         free(p);
1565
1566                         if (!dbus_message_iter_close_container(&sub, &sub2))
1567                                 goto oom;
1568                 }
1569
1570                 if (!dbus_message_iter_close_container(&iter, &sub))
1571                         goto oom;
1572
1573         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1574                 char *p;
1575                 Seat *seat;
1576                 Iterator i;
1577                 DBusMessageIter iter, sub;
1578
1579                 reply = dbus_message_new_method_return(message);
1580                 if (!reply)
1581                         goto oom;
1582
1583                 dbus_message_iter_init_append(reply, &iter);
1584
1585                 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
1586                         goto oom;
1587
1588                 HASHMAP_FOREACH(seat, m->seats, i) {
1589                         DBusMessageIter sub2;
1590
1591                         if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1592                                 goto oom;
1593
1594                         p = seat_bus_path(seat);
1595                         if (!p)
1596                                 goto oom;
1597
1598                         if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1599                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1600                                 free(p);
1601                                 goto oom;
1602                         }
1603
1604                         free(p);
1605
1606                         if (!dbus_message_iter_close_container(&sub, &sub2))
1607                                 goto oom;
1608                 }
1609
1610                 if (!dbus_message_iter_close_container(&iter, &sub))
1611                         goto oom;
1612
1613         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1614                 Inhibitor *inhibitor;
1615                 Iterator i;
1616                 DBusMessageIter iter, sub;
1617
1618                 reply = dbus_message_new_method_return(message);
1619                 if (!reply)
1620                         goto oom;
1621
1622                 dbus_message_iter_init_append(reply, &iter);
1623
1624                 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
1625                         goto oom;
1626
1627                 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1628                         DBusMessageIter sub2;
1629                         dbus_uint32_t uid, pid;
1630                         const char *what, *who, *why, *mode;
1631
1632                         if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1633                                 goto oom;
1634
1635                         what = strempty(inhibit_what_to_string(inhibitor->what));
1636                         who = strempty(inhibitor->who);
1637                         why = strempty(inhibitor->why);
1638                         mode = strempty(inhibit_mode_to_string(inhibitor->mode));
1639                         uid = (dbus_uint32_t) inhibitor->uid;
1640                         pid = (dbus_uint32_t) inhibitor->pid;
1641
1642                         if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1643                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1644                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1645                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
1646                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1647                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1648                                 goto oom;
1649
1650                         if (!dbus_message_iter_close_container(&sub, &sub2))
1651                                 goto oom;
1652                 }
1653
1654                 if (!dbus_message_iter_close_container(&iter, &sub))
1655                         goto oom;
1656
1657         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1658
1659                 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1660
1661                 if (r < 0)
1662                         return bus_send_error_reply(connection, message, &error, r);
1663
1664
1665         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1666
1667                 r = bus_manager_create_session(m, message, &reply);
1668
1669                 /* Don't delay the work on OOM here, since it might be
1670                  * triggered by a low RLIMIT_NOFILE here (since we
1671                  * send a dupped fd to the client), and we'd rather
1672                  * see this fail quickly then be retried later */
1673
1674                 if (r < 0)
1675                         return bus_send_error_reply(connection, message, NULL, r);
1676
1677         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1678                 const char *name;
1679                 Session *session;
1680
1681                 if (!dbus_message_get_args(
1682                                     message,
1683                                     &error,
1684                                     DBUS_TYPE_STRING, &name,
1685                                     DBUS_TYPE_INVALID))
1686                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1687
1688                 session = hashmap_get(m->sessions, name);
1689                 if (!session)
1690                         return bus_send_error_reply(connection, message, &error, -ENOENT);
1691
1692                 /* We use the FIFO to detect stray sessions where the
1693                 process invoking PAM dies abnormally. We need to make
1694                 sure that that process is not killed if at the clean
1695                 end of the session it closes the FIFO. Hence, with
1696                 this call explicitly turn off the FIFO logic, so that
1697                 the PAM code can finish clean up on its own */
1698                 session_remove_fifo(session);
1699
1700                 reply = dbus_message_new_method_return(message);
1701                 if (!reply)
1702                         goto oom;
1703
1704         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1705                 const char *name;
1706                 Session *session;
1707
1708                 if (!dbus_message_get_args(
1709                                     message,
1710                                     &error,
1711                                     DBUS_TYPE_STRING, &name,
1712                                     DBUS_TYPE_INVALID))
1713                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1714
1715                 session = hashmap_get(m->sessions, name);
1716                 if (!session)
1717                         return bus_send_error_reply(connection, message, &error, -ENOENT);
1718
1719                 r = session_activate(session);
1720                 if (r < 0)
1721                         return bus_send_error_reply(connection, message, NULL, r);
1722
1723                 reply = dbus_message_new_method_return(message);
1724                 if (!reply)
1725                         goto oom;
1726
1727         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1728                 const char *session_name, *seat_name;
1729                 Session *session;
1730                 Seat *seat;
1731
1732                 /* Same as ActivateSession() but refuses to work if
1733                  * the seat doesn't match */
1734
1735                 if (!dbus_message_get_args(
1736                                     message,
1737                                     &error,
1738                                     DBUS_TYPE_STRING, &session_name,
1739                                     DBUS_TYPE_STRING, &seat_name,
1740                                     DBUS_TYPE_INVALID))
1741                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1742
1743                 session = hashmap_get(m->sessions, session_name);
1744                 if (!session)
1745                         return bus_send_error_reply(connection, message, &error, -ENOENT);
1746
1747                 seat = hashmap_get(m->seats, seat_name);
1748                 if (!seat)
1749                         return bus_send_error_reply(connection, message, &error, -ENOENT);
1750
1751                 if (session->seat != seat)
1752                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1753
1754                 r = session_activate(session);
1755                 if (r < 0)
1756                         return bus_send_error_reply(connection, message, NULL, r);
1757
1758                 reply = dbus_message_new_method_return(message);
1759                 if (!reply)
1760                         goto oom;
1761
1762         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1763                    dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1764                 const char *name;
1765                 Session *session;
1766
1767                 if (!dbus_message_get_args(
1768                                     message,
1769                                     &error,
1770                                     DBUS_TYPE_STRING, &name,
1771                                     DBUS_TYPE_INVALID))
1772                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1773
1774                 session = hashmap_get(m->sessions, name);
1775                 if (!session)
1776                         return bus_send_error_reply(connection, message, &error, -ENOENT);
1777
1778                 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1779                         goto oom;
1780
1781                 reply = dbus_message_new_method_return(message);
1782                 if (!reply)
1783                         goto oom;
1784
1785         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions")) {
1786                 Session *session;
1787                 Iterator i;
1788
1789                 HASHMAP_FOREACH(session, m->sessions, i)
1790                         if (session_send_lock(session, true) < 0)
1791                                 goto oom;
1792
1793                 reply = dbus_message_new_method_return(message);
1794                 if (!reply)
1795                         goto oom;
1796
1797         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1798                 const char *swho;
1799                 int32_t signo;
1800                 KillWho who;
1801                 const char *name;
1802                 Session *session;
1803
1804                 if (!dbus_message_get_args(
1805                                     message,
1806                                     &error,
1807                                     DBUS_TYPE_STRING, &name,
1808                                     DBUS_TYPE_STRING, &swho,
1809                                     DBUS_TYPE_INT32, &signo,
1810                                     DBUS_TYPE_INVALID))
1811                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1812
1813                 if (isempty(swho))
1814                         who = KILL_ALL;
1815                 else {
1816                         who = kill_who_from_string(swho);
1817                         if (who < 0)
1818                                 return bus_send_error_reply(connection, message, &error, -EINVAL);
1819                 }
1820
1821                 if (signo <= 0 || signo >= _NSIG)
1822                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1823
1824                 session = hashmap_get(m->sessions, name);
1825                 if (!session)
1826                         return bus_send_error_reply(connection, message, &error, -ENOENT);
1827
1828                 r = session_kill(session, who, signo);
1829                 if (r < 0)
1830                         return bus_send_error_reply(connection, message, NULL, r);
1831
1832                 reply = dbus_message_new_method_return(message);
1833                 if (!reply)
1834                         goto oom;
1835
1836         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1837                 uint32_t uid;
1838                 User *user;
1839                 int32_t signo;
1840
1841                 if (!dbus_message_get_args(
1842                                     message,
1843                                     &error,
1844                                     DBUS_TYPE_UINT32, &uid,
1845                                     DBUS_TYPE_INT32, &signo,
1846                                     DBUS_TYPE_INVALID))
1847                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1848
1849                 if (signo <= 0 || signo >= _NSIG)
1850                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1851
1852                 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1853                 if (!user)
1854                         return bus_send_error_reply(connection, message, &error, -ENOENT);
1855
1856                 r = user_kill(user, signo);
1857                 if (r < 0)
1858                         return bus_send_error_reply(connection, message, NULL, r);
1859
1860                 reply = dbus_message_new_method_return(message);
1861                 if (!reply)
1862                         goto oom;
1863
1864         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1865                 const char *name;
1866                 Session *session;
1867
1868                 if (!dbus_message_get_args(
1869                                     message,
1870                                     &error,
1871                                     DBUS_TYPE_STRING, &name,
1872                                     DBUS_TYPE_INVALID))
1873                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1874
1875                 session = hashmap_get(m->sessions, name);
1876                 if (!session)
1877                         return bus_send_error_reply(connection, message, &error, -ENOENT);
1878
1879                 r = session_stop(session);
1880                 if (r < 0)
1881                         return bus_send_error_reply(connection, message, NULL, r);
1882
1883                 reply = dbus_message_new_method_return(message);
1884                 if (!reply)
1885                         goto oom;
1886
1887         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1888                 uint32_t uid;
1889                 User *user;
1890
1891                 if (!dbus_message_get_args(
1892                                     message,
1893                                     &error,
1894                                     DBUS_TYPE_UINT32, &uid,
1895                                     DBUS_TYPE_INVALID))
1896                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1897
1898                 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1899                 if (!user)
1900                         return bus_send_error_reply(connection, message, &error, -ENOENT);
1901
1902                 r = user_stop(user);
1903                 if (r < 0)
1904                         return bus_send_error_reply(connection, message, NULL, r);
1905
1906                 reply = dbus_message_new_method_return(message);
1907                 if (!reply)
1908                         goto oom;
1909
1910         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1911                 const char *name;
1912                 Seat *seat;
1913
1914                 if (!dbus_message_get_args(
1915                                     message,
1916                                     &error,
1917                                     DBUS_TYPE_STRING, &name,
1918                                     DBUS_TYPE_INVALID))
1919                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1920
1921                 seat = hashmap_get(m->seats, name);
1922                 if (!seat)
1923                         return bus_send_error_reply(connection, message, &error, -ENOENT);
1924
1925                 r = seat_stop_sessions(seat);
1926                 if (r < 0)
1927                         return bus_send_error_reply(connection, message, NULL, r);
1928
1929                 reply = dbus_message_new_method_return(message);
1930                 if (!reply)
1931                         goto oom;
1932
1933         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
1934                 uint32_t uid;
1935                 struct passwd *pw;
1936                 dbus_bool_t b, interactive;
1937                 char *path;
1938
1939                 if (!dbus_message_get_args(
1940                                     message,
1941                                     &error,
1942                                     DBUS_TYPE_UINT32, &uid,
1943                                     DBUS_TYPE_BOOLEAN, &b,
1944                                     DBUS_TYPE_BOOLEAN, &interactive,
1945                                     DBUS_TYPE_INVALID))
1946                         return bus_send_error_reply(connection, message, &error, -EINVAL);
1947
1948                 errno = 0;
1949                 pw = getpwuid(uid);
1950                 if (!pw)
1951                         return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
1952
1953                 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
1954                 if (r < 0)
1955                         return bus_send_error_reply(connection, message, &error, r);
1956
1957                 mkdir_p_label("/var/lib/systemd", 0755);
1958
1959                 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
1960                 if (r < 0)
1961                         return bus_send_error_reply(connection, message, &error, r);
1962
1963                 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
1964                 if (!path)
1965                         goto oom;
1966
1967                 if (b) {
1968                         User *u;
1969
1970                         r = touch(path);
1971                         free(path);
1972
1973                         if (r < 0)
1974                                 return bus_send_error_reply(connection, message, &error, r);
1975
1976                         if (manager_add_user_by_uid(m, uid, &u) >= 0)
1977                                 user_start(u);
1978
1979                 } else {
1980                         User *u;
1981
1982                         r = unlink(path);
1983                         free(path);
1984
1985                         if (r < 0 && errno != ENOENT)
1986                                 return bus_send_error_reply(connection, message, &error, -errno);
1987
1988                         u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1989                         if (u)
1990                                 user_add_to_gc_queue(u);
1991                 }
1992
1993                 reply = dbus_message_new_method_return(message);
1994                 if (!reply)
1995                         goto oom;
1996
1997         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
1998                 const char *sysfs, *seat;
1999                 dbus_bool_t interactive;
2000
2001                 if (!dbus_message_get_args(
2002                                     message,
2003                                     &error,
2004                                     DBUS_TYPE_STRING, &seat,
2005                                     DBUS_TYPE_STRING, &sysfs,
2006                                     DBUS_TYPE_BOOLEAN, &interactive,
2007                                     DBUS_TYPE_INVALID))
2008                         return bus_send_error_reply(connection, message, &error, -EINVAL);
2009
2010                 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
2011                         return bus_send_error_reply(connection, message, NULL, -EINVAL);
2012
2013                 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
2014                 if (r < 0)
2015                         return bus_send_error_reply(connection, message, &error, r);
2016
2017                 r = attach_device(m, seat, sysfs);
2018                 if (r < 0)
2019                         return bus_send_error_reply(connection, message, NULL, -EINVAL);
2020
2021                 reply = dbus_message_new_method_return(message);
2022                 if (!reply)
2023                         goto oom;
2024
2025
2026         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
2027                 dbus_bool_t interactive;
2028
2029                 if (!dbus_message_get_args(
2030                                     message,
2031                                     &error,
2032                                     DBUS_TYPE_BOOLEAN, &interactive,
2033                                     DBUS_TYPE_INVALID))
2034                         return bus_send_error_reply(connection, message, &error, -EINVAL);
2035
2036                 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
2037                 if (r < 0)
2038                         return bus_send_error_reply(connection, message, &error, r);
2039
2040                 r = flush_devices(m);
2041                 if (r < 0)
2042                         return bus_send_error_reply(connection, message, NULL, -EINVAL);
2043
2044                 reply = dbus_message_new_method_return(message);
2045                 if (!reply)
2046                         goto oom;
2047
2048         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
2049
2050                 r = bus_manager_do_shutdown_or_sleep(
2051                                 m, connection, message,
2052                                 SPECIAL_POWEROFF_TARGET,
2053                                 INHIBIT_SHUTDOWN,
2054                                 "org.freedesktop.login1.power-off",
2055                                 "org.freedesktop.login1.power-off-multiple-sessions",
2056                                 "org.freedesktop.login1.power-off-ignore-inhibit",
2057                                 NULL,
2058                                 &error, &reply);
2059                 if (r < 0)
2060                         return bus_send_error_reply(connection, message, &error, r);
2061         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
2062                 r = bus_manager_do_shutdown_or_sleep(
2063                                 m, connection, message,
2064                                 SPECIAL_REBOOT_TARGET,
2065                                 INHIBIT_SHUTDOWN,
2066                                 "org.freedesktop.login1.reboot",
2067                                 "org.freedesktop.login1.reboot-multiple-sessions",
2068                                 "org.freedesktop.login1.reboot-ignore-inhibit",
2069                                 NULL,
2070                                 &error, &reply);
2071                 if (r < 0)
2072                         return bus_send_error_reply(connection, message, &error, r);
2073
2074         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2075                 r = bus_manager_do_shutdown_or_sleep(
2076                                 m, connection, message,
2077                                 SPECIAL_SUSPEND_TARGET,
2078                                 INHIBIT_SLEEP,
2079                                 "org.freedesktop.login1.suspend",
2080                                 "org.freedesktop.login1.suspend-multiple-sessions",
2081                                 "org.freedesktop.login1.suspend-ignore-inhibit",
2082                                 "mem",
2083                                 &error, &reply);
2084                 if (r < 0)
2085                         return bus_send_error_reply(connection, message, &error, r);
2086         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2087                 r = bus_manager_do_shutdown_or_sleep(
2088                                 m, connection, message,
2089                                 SPECIAL_HIBERNATE_TARGET,
2090                                 INHIBIT_SLEEP,
2091                                 "org.freedesktop.login1.hibernate",
2092                                 "org.freedesktop.login1.hibernate-multiple-sessions",
2093                                 "org.freedesktop.login1.hibernate-ignore-inhibit",
2094                                 "disk",
2095                                 &error, &reply);
2096                 if (r < 0)
2097                         return bus_send_error_reply(connection, message, &error, r);
2098
2099         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
2100
2101                 r = bus_manager_can_shutdown_or_sleep(
2102                                 m, connection, message,
2103                                 INHIBIT_SHUTDOWN,
2104                                 "org.freedesktop.login1.power-off",
2105                                 "org.freedesktop.login1.power-off-multiple-sessions",
2106                                 "org.freedesktop.login1.power-off-ignore-inhibit",
2107                                 NULL,
2108                                 &error, &reply);
2109                 if (r < 0)
2110                         return bus_send_error_reply(connection, message, &error, r);
2111         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2112                 r = bus_manager_can_shutdown_or_sleep(
2113                                 m, connection, message,
2114                                 INHIBIT_SHUTDOWN,
2115                                 "org.freedesktop.login1.reboot",
2116                                 "org.freedesktop.login1.reboot-multiple-sessions",
2117                                 "org.freedesktop.login1.reboot-ignore-inhibit",
2118                                 NULL,
2119                                 &error, &reply);
2120                 if (r < 0)
2121                         return bus_send_error_reply(connection, message, &error, r);
2122
2123         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2124                 r = bus_manager_can_shutdown_or_sleep(
2125                                 m, connection, message,
2126                                 INHIBIT_SLEEP,
2127                                 "org.freedesktop.login1.suspend",
2128                                 "org.freedesktop.login1.suspend-multiple-sessions",
2129                                 "org.freedesktop.login1.suspend-ignore-inhibit",
2130                                 "mem",
2131                                 &error, &reply);
2132                 if (r < 0)
2133                         return bus_send_error_reply(connection, message, &error, r);
2134
2135         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2136                 r = bus_manager_can_shutdown_or_sleep(
2137                                 m, connection, message,
2138                                 INHIBIT_SLEEP,
2139                                 "org.freedesktop.login1.hibernate",
2140                                 "org.freedesktop.login1.hibernate-multiple-sessions",
2141                                 "org.freedesktop.login1.hibernate-ignore-inhibit",
2142                                 "disk",
2143                                 &error, &reply);
2144                 if (r < 0)
2145                         return bus_send_error_reply(connection, message, &error, r);
2146
2147         } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2148                 char *introspection = NULL;
2149                 FILE *f;
2150                 Iterator i;
2151                 Session *session;
2152                 Seat *seat;
2153                 User *user;
2154                 size_t size;
2155                 char *p;
2156
2157                 if (!(reply = dbus_message_new_method_return(message)))
2158                         goto oom;
2159
2160                 /* We roll our own introspection code here, instead of
2161                  * relying on bus_default_message_handler() because we
2162                  * need to generate our introspection string
2163                  * dynamically. */
2164
2165                 if (!(f = open_memstream(&introspection, &size)))
2166                         goto oom;
2167
2168                 fputs(INTROSPECTION_BEGIN, f);
2169
2170                 HASHMAP_FOREACH(seat, m->seats, i) {
2171                         p = bus_path_escape(seat->id);
2172
2173                         if (p) {
2174                                 fprintf(f, "<node name=\"seat/%s\"/>", p);
2175                                 free(p);
2176                         }
2177                 }
2178
2179                 HASHMAP_FOREACH(user, m->users, i)
2180                         fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2181
2182                 HASHMAP_FOREACH(session, m->sessions, i) {
2183                         p = bus_path_escape(session->id);
2184
2185                         if (p) {
2186                                 fprintf(f, "<node name=\"session/%s\"/>", p);
2187                                 free(p);
2188                         }
2189                 }
2190
2191                 fputs(INTROSPECTION_END, f);
2192
2193                 if (ferror(f)) {
2194                         fclose(f);
2195                         free(introspection);
2196                         goto oom;
2197                 }
2198
2199                 fclose(f);
2200
2201                 if (!introspection)
2202                         goto oom;
2203
2204                 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2205                         free(introspection);
2206                         goto oom;
2207                 }
2208
2209                 free(introspection);
2210         } else {
2211                 const BusBoundProperties bps[] = {
2212                         { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2213                         { NULL, }
2214                 };
2215                 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2216         }
2217
2218         if (reply) {
2219                 if (!dbus_connection_send(connection, reply, NULL))
2220                         goto oom;
2221
2222                 dbus_message_unref(reply);
2223         }
2224
2225         return DBUS_HANDLER_RESULT_HANDLED;
2226
2227 oom:
2228         if (reply)
2229                 dbus_message_unref(reply);
2230
2231         dbus_error_free(&error);
2232
2233         return DBUS_HANDLER_RESULT_NEED_MEMORY;
2234 }
2235
2236 const DBusObjectPathVTable bus_manager_vtable = {
2237         .message_function = manager_message_handler
2238 };
2239
2240 DBusHandlerResult bus_message_filter(
2241                 DBusConnection *connection,
2242                 DBusMessage *message,
2243                 void *userdata) {
2244
2245         Manager *m = userdata;
2246         DBusError error;
2247
2248         assert(m);
2249         assert(connection);
2250         assert(message);
2251
2252         dbus_error_init(&error);
2253
2254         if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
2255                 const char *cgroup;
2256
2257                 if (!dbus_message_get_args(message, &error,
2258                                            DBUS_TYPE_STRING, &cgroup,
2259                                            DBUS_TYPE_INVALID))
2260                         log_error("Failed to parse Released message: %s", bus_error_message(&error));
2261                 else
2262                         manager_cgroup_notify_empty(m, cgroup);
2263         }
2264
2265         dbus_error_free(&error);
2266
2267         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2268 }
2269
2270 int manager_send_changed(Manager *manager, const char *properties) {
2271         DBusMessage *m;
2272         int r = -ENOMEM;
2273
2274         assert(manager);
2275
2276         m = bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties);
2277         if (!m)
2278                 goto finish;
2279
2280         if (!dbus_connection_send(manager->bus, m, NULL))
2281                 goto finish;
2282
2283         r = 0;
2284
2285 finish:
2286         if (m)
2287                 dbus_message_unref(m);
2288
2289         return r;
2290 }
2291
2292 int manager_dispatch_delayed(Manager *manager) {
2293         const char *unit_name;
2294         DBusError error;
2295         bool delayed;
2296         int r;
2297
2298         assert(manager);
2299
2300         if (!manager->delayed_unit)
2301                 return 0;
2302
2303         /* Continue delay? */
2304         delayed =
2305                 manager->delayed_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC) &&
2306                 manager_is_inhibited(manager, manager->delayed_what, INHIBIT_DELAY, NULL, false);
2307         if (delayed)
2308                 return 0;
2309
2310         bus_manager_log_shutdown(manager, manager->delayed_what, manager->delayed_unit);
2311
2312         /* Reset delay data */
2313         unit_name = manager->delayed_unit;
2314         manager->delayed_unit = NULL;
2315
2316         /* Actually do the shutdown */
2317         dbus_error_init(&error);
2318         r = send_start_unit(manager->bus, unit_name, &error);
2319         if (r < 0) {
2320                 log_warning("Failed to send delayed message: %s", bus_error_message_or_strerror(&error, -r));
2321                 dbus_error_free(&error);
2322                 return r;
2323         }
2324
2325         /* Tell people about it */
2326         send_prepare_for(manager, manager->delayed_what, false);
2327
2328         return 1;
2329 }