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