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