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