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