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