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