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