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