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