]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-dbus.c
shared: in code that might get called from suid programs use __secure_getenv() rather...
[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 const char *mode = "replace";
972
d889a206 973 assert(unit_name);
eecd1362 974
b9c26b41
SP
975 return bus_method_call_with_reply (
976 connection,
eecd1362
LP
977 "org.freedesktop.systemd1",
978 "/org/freedesktop/systemd1",
979 "org.freedesktop.systemd1.Manager",
b9c26b41
SP
980 "StartUnit",
981 NULL,
982 NULL,
983 DBUS_TYPE_STRING, &unit_name,
984 DBUS_TYPE_STRING, &mode,
985 DBUS_TYPE_INVALID);
eecd1362
LP
986}
987
d889a206
LP
988static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
989 static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
990 [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
991 [INHIBIT_SLEEP] = "PrepareForSleep"
992 };
993
eecd1362
LP
994 dbus_bool_t active = _active;
995 DBusMessage *message;
996 int r = 0;
997
998 assert(m);
d889a206
LP
999 assert(w >= 0);
1000 assert(w < _INHIBIT_WHAT_MAX);
1001 assert(signal_name[w]);
eecd1362 1002
d889a206 1003 message = dbus_message_new_signal("/org/freedesktop/login1", "org.freedesktop.login1.Manager", signal_name[w]);
eecd1362
LP
1004 if (!message)
1005 return -ENOMEM;
1006
1007 if (!dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &active, DBUS_TYPE_INVALID) ||
1008 !dbus_connection_send(m->bus, message, NULL))
1009 r = -ENOMEM;
1010
1011 dbus_message_unref(message);
1012 return r;
1013}
1014
d889a206 1015static int delay_shutdown_or_sleep(Manager *m, InhibitWhat w, const char *unit_name) {
eecd1362 1016 assert(m);
d889a206
LP
1017 assert(w >= 0);
1018 assert(w < _INHIBIT_WHAT_MAX);
eecd1362 1019
d889a206
LP
1020 /* Tell everybody to prepare for shutdown/sleep */
1021 send_prepare_for(m, w, true);
eecd1362 1022
d889a206
LP
1023 /* Update timestamp for timeout */
1024 if (!m->delayed_unit)
1025 m->delayed_timestamp = now(CLOCK_MONOTONIC);
eecd1362
LP
1026
1027 /* Remember what we want to do, possibly overriding what kind
d889a206
LP
1028 * of unit we previously queued. */
1029 m->delayed_unit = unit_name;
1030 m->delayed_what = w;
1031
1032 return 0;
1033}
1034
1035static int bus_manager_can_shutdown_or_sleep(
1036 Manager *m,
1037 DBusConnection *connection,
1038 DBusMessage *message,
1039 InhibitWhat w,
1040 const char *action,
1041 const char *action_multiple_sessions,
1042 const char *action_ignore_inhibit,
1043 const char *sleep_type,
1044 DBusError *error,
1045 DBusMessage **_reply) {
1046
1047 bool multiple_sessions, challenge, blocked, b;
1048 const char *result;
1049 DBusMessage *reply = NULL;
1050 int r;
1051
1052 assert(m);
1053 assert(connection);
1054 assert(message);
1055 assert(w >= 0);
1056 assert(w <= _INHIBIT_WHAT_MAX);
1057 assert(action);
1058 assert(action_multiple_sessions);
1059 assert(action_ignore_inhibit);
1060 assert(error);
1061 assert(_reply);
1062
1063 if (sleep_type) {
1064 r = can_sleep(sleep_type);
1065 if (r < 0)
1066 return r;
1067
398f7c88
MC
1068 if (r == 0) {
1069 result = "na";
1070 goto finish;
1071 }
d889a206
LP
1072 }
1073
1074 r = have_multiple_sessions(connection, m, message, error);
1075 if (r < 0)
1076 return r;
1077
1078 multiple_sessions = r > 0;
1079 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL);
1080
1081 if (multiple_sessions) {
1082 r = verify_polkit(connection, message, action_multiple_sessions, false, &challenge, error);
1083 if (r < 0)
1084 return r;
1085
1086 if (r > 0)
1087 result = "yes";
d5a745df
LP
1088 else if (challenge)
1089 result = "challenge";
1090 else
1091 result = "no";
1092 }
d889a206
LP
1093
1094 if (blocked) {
1095 r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
1096 if (r < 0)
1097 return r;
1098
1099 if (r > 0 && !result)
1100 result = "yes";
1101 else if (challenge && (!result || streq(result, "yes")))
1102 result = "challenge";
1103 else
1104 result = "no";
1105 }
1106
1107 if (!multiple_sessions && !blocked) {
1108 /* If neither inhibit nor multiple sessions
1109 * apply then just check the normal policy */
1110
1111 r = verify_polkit(connection, message, action, false, &challenge, error);
1112 if (r < 0)
1113 return r;
1114
1115 if (r > 0)
1116 result = "yes";
1117 else if (challenge)
1118 result = "challenge";
1119 else
1120 result = "no";
1121 }
1122
1123finish:
1124 reply = dbus_message_new_method_return(message);
1125 if (!reply)
1126 return -ENOMEM;
1127
1128 b = dbus_message_append_args(
1129 reply,
1130 DBUS_TYPE_STRING, &result,
1131 DBUS_TYPE_INVALID);
1132 if (!b) {
1133 dbus_message_unref(reply);
1134 return -ENOMEM;
1135 }
1136
1137 *_reply = reply;
1138 return 0;
1139}
1140
069cfc85
LP
1141int bus_manager_shutdown_or_sleep_now_or_later(
1142 Manager *m,
1143 const char *unit_name,
1144 InhibitWhat w,
1145 DBusError *error) {
1146
1147 bool delayed;
1148 int r;
1149
1150 assert(m);
1151 assert(unit_name);
1152 assert(w >= 0);
1153 assert(w <= _INHIBIT_WHAT_MAX);
1154
1155 delayed =
1156 m->inhibit_delay_max > 0 &&
1157 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL);
1158
1159 if (delayed)
1160 /* Shutdown is delayed, keep in mind what we
1161 * want to do, and start a timeout */
1162 r = delay_shutdown_or_sleep(m, w, unit_name);
1163 else
1164 /* Shutdown is not delayed, execute it
1165 * immediately */
1166 r = send_start_unit(m->bus, unit_name, error);
1167
1168 return r;
1169}
1170
d889a206
LP
1171static int bus_manager_do_shutdown_or_sleep(
1172 Manager *m,
1173 DBusConnection *connection,
1174 DBusMessage *message,
1175 const char *unit_name,
1176 InhibitWhat w,
1177 const char *action,
1178 const char *action_multiple_sessions,
1179 const char *action_ignore_inhibit,
1180 const char *sleep_type,
1181 DBusError *error,
1182 DBusMessage **_reply) {
1183
1184 dbus_bool_t interactive;
069cfc85 1185 bool multiple_sessions, blocked;
d889a206
LP
1186 DBusMessage *reply = NULL;
1187 int r;
1188
1189 assert(m);
1190 assert(connection);
1191 assert(message);
1192 assert(unit_name);
1193 assert(w >= 0);
1194 assert(w <= _INHIBIT_WHAT_MAX);
1195 assert(action);
1196 assert(action_multiple_sessions);
1197 assert(action_ignore_inhibit);
1198 assert(error);
1199 assert(_reply);
1200
1201 if (!dbus_message_get_args(
1202 message,
1203 error,
1204 DBUS_TYPE_BOOLEAN, &interactive,
1205 DBUS_TYPE_INVALID))
1206 return -EINVAL;
1207
1208 if (sleep_type) {
1209 r = can_sleep(sleep_type);
1210 if (r < 0)
1211 return r;
1212
1213 if (r == 0)
1214 return -ENOTSUP;
1215 }
1216
1217 r = have_multiple_sessions(connection, m, message, error);
1218 if (r < 0)
1219 return r;
1220
1221 multiple_sessions = r > 0;
1222 blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL);
1223
1224 if (multiple_sessions) {
1225 r = verify_polkit(connection, message, action_multiple_sessions, interactive, NULL, error);
1226 if (r < 0)
1227 return r;
1228 }
1229
1230 if (blocked) {
1231 r = verify_polkit(connection, message, action_ignore_inhibit, interactive, NULL, error);
1232 if (r < 0)
1233 return r;
1234 }
1235
1236 if (!multiple_sessions && !blocked) {
1237 r = verify_polkit(connection, message, action, interactive, NULL, error);
1238 if (r < 0)
1239 return r;
1240 }
1241
069cfc85 1242 r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
d889a206
LP
1243 if (r < 0)
1244 return r;
1245
1246 reply = dbus_message_new_method_return(message);
1247 if (!reply)
1248 return -ENOMEM;
eecd1362 1249
d889a206 1250 *_reply = reply;
eecd1362
LP
1251 return 0;
1252}
1253
069cfc85
LP
1254static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_button, handle_button, HandleButton);
1255
d200735e
MS
1256static const BusProperty bus_login_manager_properties[] = {
1257 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_path), true },
1258 { "Controllers", bus_property_append_strv, "as", offsetof(Manager, controllers), true },
1259 { "ResetControllers", bus_property_append_strv, "as", offsetof(Manager, reset_controllers), true },
1260 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
1261 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
1262 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
1263 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
1264 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
1265 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
1266 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
eecd1362
LP
1267 { "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
1268 { "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
1269 { "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
069cfc85
LP
1270 { "HandlePowerKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_power_key) },
1271 { "HandleSleepKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_sleep_key) },
1272 { "HandleLidSwitch", bus_manager_append_handle_button, "s", offsetof(Manager, handle_lid_switch) },
5e4a79da
LP
1273 { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
1274 { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
d200735e
MS
1275 { NULL, }
1276};
1277
3f49d45a
LP
1278static DBusHandlerResult manager_message_handler(
1279 DBusConnection *connection,
1280 DBusMessage *message,
1281 void *userdata) {
1282
1283 Manager *m = userdata;
1284
3f49d45a
LP
1285 DBusError error;
1286 DBusMessage *reply = NULL;
bef422ae 1287 int r;
3f49d45a
LP
1288
1289 assert(connection);
1290 assert(message);
1291 assert(m);
1292
1293 dbus_error_init(&error);
1294
bef422ae
LP
1295 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
1296 const char *name;
1297 char *p;
1298 Session *session;
1299 bool b;
1300
1301 if (!dbus_message_get_args(
1302 message,
1303 &error,
1304 DBUS_TYPE_STRING, &name,
1305 DBUS_TYPE_INVALID))
1306 return bus_send_error_reply(connection, message, &error, -EINVAL);
1307
1308 session = hashmap_get(m->sessions, name);
1309 if (!session)
1310 return bus_send_error_reply(connection, message, &error, -ENOENT);
1311
1312 reply = dbus_message_new_method_return(message);
1313 if (!reply)
1314 goto oom;
1315
1316 p = session_bus_path(session);
c4aa65e7
LP
1317 if (!p)
1318 goto oom;
1319
1320 b = dbus_message_append_args(
1321 reply,
1322 DBUS_TYPE_OBJECT_PATH, &p,
1323 DBUS_TYPE_INVALID);
1324 free(p);
1325
1326 if (!b)
1327 goto oom;
1328
1329 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
1330 uint32_t pid;
1331 char *p;
1332 Session *session;
1333 bool b;
1334
1335 if (!dbus_message_get_args(
1336 message,
1337 &error,
1338 DBUS_TYPE_UINT32, &pid,
1339 DBUS_TYPE_INVALID))
1340 return bus_send_error_reply(connection, message, &error, -EINVAL);
1341
1342 r = manager_get_session_by_pid(m, pid, &session);
1343 if (r <= 0)
1344 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
1345
1346 reply = dbus_message_new_method_return(message);
1347 if (!reply)
1348 goto oom;
1349
1350 p = session_bus_path(session);
bef422ae
LP
1351 if (!p)
1352 goto oom;
1353
1354 b = dbus_message_append_args(
1355 reply,
1356 DBUS_TYPE_OBJECT_PATH, &p,
1357 DBUS_TYPE_INVALID);
1358 free(p);
1359
1360 if (!b)
1361 goto oom;
1362
1363 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1364 uint32_t uid;
1365 char *p;
1366 User *user;
1367 bool b;
1368
1369 if (!dbus_message_get_args(
1370 message,
1371 &error,
1372 DBUS_TYPE_UINT32, &uid,
1373 DBUS_TYPE_INVALID))
1374 return bus_send_error_reply(connection, message, &error, -EINVAL);
1375
1376 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1377 if (!user)
1378 return bus_send_error_reply(connection, message, &error, -ENOENT);
1379
1380 reply = dbus_message_new_method_return(message);
1381 if (!reply)
1382 goto oom;
1383
1384 p = user_bus_path(user);
1385 if (!p)
1386 goto oom;
1387
1388 b = dbus_message_append_args(
1389 reply,
1390 DBUS_TYPE_OBJECT_PATH, &p,
1391 DBUS_TYPE_INVALID);
1392 free(p);
1393
1394 if (!b)
1395 goto oom;
1396
1397 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1398 const char *name;
1399 char *p;
1400 Seat *seat;
1401 bool b;
1402
1403 if (!dbus_message_get_args(
1404 message,
1405 &error,
1406 DBUS_TYPE_STRING, &name,
1407 DBUS_TYPE_INVALID))
1408 return bus_send_error_reply(connection, message, &error, -EINVAL);
1409
1410 seat = hashmap_get(m->seats, name);
1411 if (!seat)
1412 return bus_send_error_reply(connection, message, &error, -ENOENT);
1413
1414 reply = dbus_message_new_method_return(message);
1415 if (!reply)
1416 goto oom;
1417
1418 p = seat_bus_path(seat);
1419 if (!p)
1420 goto oom;
1421
1422 b = dbus_message_append_args(
1423 reply,
1424 DBUS_TYPE_OBJECT_PATH, &p,
1425 DBUS_TYPE_INVALID);
1426 free(p);
1427
1428 if (!b)
1429 goto oom;
1430
e1c9c2d5
LP
1431 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1432 char *p;
1433 Session *session;
1434 Iterator i;
1435 DBusMessageIter iter, sub;
1436 const char *empty = "";
1437
1438 reply = dbus_message_new_method_return(message);
1439 if (!reply)
1440 goto oom;
1441
1442 dbus_message_iter_init_append(reply, &iter);
1443
dec15e92 1444 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
e1c9c2d5
LP
1445 goto oom;
1446
1447 HASHMAP_FOREACH(session, m->sessions, i) {
1448 DBusMessageIter sub2;
1449 uint32_t uid;
1450
1451 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1452 goto oom;
1453
1454 uid = session->user->uid;
1455
1456 p = session_bus_path(session);
1457 if (!p)
1458 goto oom;
1459
1460 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1461 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1462 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1463 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1464 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1465 free(p);
1466 goto oom;
1467 }
1468
1469 free(p);
1470
1471 if (!dbus_message_iter_close_container(&sub, &sub2))
1472 goto oom;
1473 }
1474
1475 if (!dbus_message_iter_close_container(&iter, &sub))
1476 goto oom;
1477
1478 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1479 char *p;
1480 User *user;
1481 Iterator i;
1482 DBusMessageIter iter, sub;
1483
1484 reply = dbus_message_new_method_return(message);
1485 if (!reply)
1486 goto oom;
1487
1488 dbus_message_iter_init_append(reply, &iter);
1489
dec15e92 1490 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
e1c9c2d5
LP
1491 goto oom;
1492
1493 HASHMAP_FOREACH(user, m->users, i) {
1494 DBusMessageIter sub2;
1495 uint32_t uid;
1496
1497 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1498 goto oom;
1499
1500 uid = user->uid;
1501
1502 p = user_bus_path(user);
1503 if (!p)
1504 goto oom;
1505
1506 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1507 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1508 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1509 free(p);
1510 goto oom;
1511 }
1512
1513 free(p);
1514
1515 if (!dbus_message_iter_close_container(&sub, &sub2))
1516 goto oom;
1517 }
1518
1519 if (!dbus_message_iter_close_container(&iter, &sub))
1520 goto oom;
1521
1522 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1523 char *p;
1524 Seat *seat;
1525 Iterator i;
1526 DBusMessageIter iter, sub;
1527
1528 reply = dbus_message_new_method_return(message);
1529 if (!reply)
1530 goto oom;
1531
1532 dbus_message_iter_init_append(reply, &iter);
1533
dec15e92 1534 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
e1c9c2d5
LP
1535 goto oom;
1536
1537 HASHMAP_FOREACH(seat, m->seats, i) {
1538 DBusMessageIter sub2;
1539
1540 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1541 goto oom;
1542
1543 p = seat_bus_path(seat);
1544 if (!p)
1545 goto oom;
1546
1547 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1548 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1549 free(p);
1550 goto oom;
1551 }
1552
1553 free(p);
1554
1555 if (!dbus_message_iter_close_container(&sub, &sub2))
1556 goto oom;
1557 }
1558
1559 if (!dbus_message_iter_close_container(&iter, &sub))
1560 goto oom;
1561
f8e2fb7b
LP
1562 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1563 Inhibitor *inhibitor;
1564 Iterator i;
1565 DBusMessageIter iter, sub;
1566
1567 reply = dbus_message_new_method_return(message);
1568 if (!reply)
1569 goto oom;
1570
1571 dbus_message_iter_init_append(reply, &iter);
1572
eecd1362 1573 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssuu)", &sub))
f8e2fb7b
LP
1574 goto oom;
1575
1576 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1577 DBusMessageIter sub2;
1578 dbus_uint32_t uid, pid;
eecd1362 1579 const char *what, *who, *why, *mode;
f8e2fb7b
LP
1580
1581 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1582 goto oom;
1583
eecd1362 1584 what = strempty(inhibit_what_to_string(inhibitor->what));
f8e2fb7b
LP
1585 who = strempty(inhibitor->who);
1586 why = strempty(inhibitor->why);
eecd1362 1587 mode = strempty(inhibit_mode_to_string(inhibitor->mode));
f8e2fb7b
LP
1588 uid = (dbus_uint32_t) inhibitor->uid;
1589 pid = (dbus_uint32_t) inhibitor->pid;
1590
1591 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1592 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1593 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
eecd1362 1594 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &mode) ||
f8e2fb7b
LP
1595 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1596 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1597 goto oom;
1598
1599 if (!dbus_message_iter_close_container(&sub, &sub2))
1600 goto oom;
1601 }
1602
1603 if (!dbus_message_iter_close_container(&iter, &sub))
1604 goto oom;
1605
1606 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1607
1608 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1609
1610 if (r < 0)
1611 return bus_send_error_reply(connection, message, &error, r);
1612
1613
98a28fef
LP
1614 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1615
1616 r = bus_manager_create_session(m, message, &reply);
688c56ff
LP
1617
1618 /* Don't delay the work on OOM here, since it might be
1619 * triggered by a low RLIMIT_NOFILE here (since we
1620 * send a dupped fd to the client), and we'd rather
1621 * see this fail quickly then be retried later */
98a28fef
LP
1622
1623 if (r < 0)
f8e2fb7b 1624 return bus_send_error_reply(connection, message, NULL, r);
98a28fef 1625
75c8e3cf
LP
1626 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1627 const char *name;
1628 Session *session;
1629
1630 if (!dbus_message_get_args(
1631 message,
1632 &error,
1633 DBUS_TYPE_STRING, &name,
1634 DBUS_TYPE_INVALID))
1635 return bus_send_error_reply(connection, message, &error, -EINVAL);
1636
1637 session = hashmap_get(m->sessions, name);
1638 if (!session)
1639 return bus_send_error_reply(connection, message, &error, -ENOENT);
1640
1641 /* We use the FIFO to detect stray sessions where the
1642 process invoking PAM dies abnormally. We need to make
1643 sure that that process is not killed if at the clean
1644 end of the session it closes the FIFO. Hence, with
1645 this call explicitly turn off the FIFO logic, so that
1646 the PAM code can finish clean up on its own */
1647 session_remove_fifo(session);
1648
1649 reply = dbus_message_new_method_return(message);
1650 if (!reply)
1651 goto oom;
1652
bef422ae
LP
1653 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1654 const char *name;
1655 Session *session;
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 r = session_activate(session);
1669 if (r < 0)
1670 return bus_send_error_reply(connection, message, NULL, r);
1671
1672 reply = dbus_message_new_method_return(message);
1673 if (!reply)
1674 goto oom;
1675
84c3361e
LP
1676 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1677 const char *session_name, *seat_name;
1678 Session *session;
1679 Seat *seat;
1680
1681 /* Same as ActivateSession() but refuses to work if
1682 * the seat doesn't match */
1683
1684 if (!dbus_message_get_args(
1685 message,
1686 &error,
1687 DBUS_TYPE_STRING, &session_name,
1688 DBUS_TYPE_STRING, &seat_name,
1689 DBUS_TYPE_INVALID))
1690 return bus_send_error_reply(connection, message, &error, -EINVAL);
1691
1692 session = hashmap_get(m->sessions, session_name);
1693 if (!session)
1694 return bus_send_error_reply(connection, message, &error, -ENOENT);
1695
1696 seat = hashmap_get(m->seats, seat_name);
1697 if (!seat)
1698 return bus_send_error_reply(connection, message, &error, -ENOENT);
1699
1700 if (session->seat != seat)
1701 return bus_send_error_reply(connection, message, &error, -EINVAL);
1702
1703 r = session_activate(session);
1704 if (r < 0)
1705 return bus_send_error_reply(connection, message, NULL, r);
1706
1707 reply = dbus_message_new_method_return(message);
1708 if (!reply)
1709 goto oom;
1710
88e3dc90
LP
1711 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1712 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1713 const char *name;
1714 Session *session;
1715
1716 if (!dbus_message_get_args(
1717 message,
1718 &error,
1719 DBUS_TYPE_STRING, &name,
1720 DBUS_TYPE_INVALID))
1721 return bus_send_error_reply(connection, message, &error, -EINVAL);
1722
1723 session = hashmap_get(m->sessions, name);
1724 if (!session)
1725 return bus_send_error_reply(connection, message, &error, -ENOENT);
1726
1727 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1728 goto oom;
1729
1730 reply = dbus_message_new_method_return(message);
1731 if (!reply)
1732 goto oom;
1733
fa2b196d
LP
1734 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions")) {
1735 Session *session;
1736 Iterator i;
1737
1738 HASHMAP_FOREACH(session, m->sessions, i)
1739 if (session_send_lock(session, true) < 0)
1740 goto oom;
1741
1742 reply = dbus_message_new_method_return(message);
1743 if (!reply)
1744 goto oom;
1745
de07ab16
LP
1746 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1747 const char *swho;
1748 int32_t signo;
1749 KillWho who;
1750 const char *name;
1751 Session *session;
1752
1753 if (!dbus_message_get_args(
1754 message,
1755 &error,
1756 DBUS_TYPE_STRING, &name,
1757 DBUS_TYPE_STRING, &swho,
1758 DBUS_TYPE_INT32, &signo,
1759 DBUS_TYPE_INVALID))
1760 return bus_send_error_reply(connection, message, &error, -EINVAL);
1761
1762 if (isempty(swho))
1763 who = KILL_ALL;
1764 else {
1765 who = kill_who_from_string(swho);
1766 if (who < 0)
1767 return bus_send_error_reply(connection, message, &error, -EINVAL);
1768 }
1769
1770 if (signo <= 0 || signo >= _NSIG)
1771 return bus_send_error_reply(connection, message, &error, -EINVAL);
1772
1773 session = hashmap_get(m->sessions, name);
1774 if (!session)
1775 return bus_send_error_reply(connection, message, &error, -ENOENT);
1776
1777 r = session_kill(session, who, signo);
1778 if (r < 0)
1779 return bus_send_error_reply(connection, message, NULL, r);
1780
1781 reply = dbus_message_new_method_return(message);
1782 if (!reply)
1783 goto oom;
1784
1785 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1786 uint32_t uid;
1787 User *user;
1788 int32_t signo;
1789
1790 if (!dbus_message_get_args(
1791 message,
1792 &error,
1793 DBUS_TYPE_UINT32, &uid,
1794 DBUS_TYPE_INT32, &signo,
1795 DBUS_TYPE_INVALID))
1796 return bus_send_error_reply(connection, message, &error, -EINVAL);
1797
1798 if (signo <= 0 || signo >= _NSIG)
1799 return bus_send_error_reply(connection, message, &error, -EINVAL);
1800
1801 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1802 if (!user)
1803 return bus_send_error_reply(connection, message, &error, -ENOENT);
1804
1805 r = user_kill(user, signo);
1806 if (r < 0)
1807 return bus_send_error_reply(connection, message, NULL, r);
1808
1809 reply = dbus_message_new_method_return(message);
1810 if (!reply)
1811 goto oom;
1812
bef422ae
LP
1813 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1814 const char *name;
1815 Session *session;
1816
1817 if (!dbus_message_get_args(
1818 message,
1819 &error,
1820 DBUS_TYPE_STRING, &name,
1821 DBUS_TYPE_INVALID))
1822 return bus_send_error_reply(connection, message, &error, -EINVAL);
1823
1824 session = hashmap_get(m->sessions, name);
1825 if (!session)
1826 return bus_send_error_reply(connection, message, &error, -ENOENT);
1827
1828 r = session_stop(session);
1829 if (r < 0)
1830 return bus_send_error_reply(connection, message, NULL, r);
1831
1832 reply = dbus_message_new_method_return(message);
1833 if (!reply)
1834 goto oom;
1835
1836 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1837 uint32_t uid;
1838 User *user;
1839
1840 if (!dbus_message_get_args(
1841 message,
1842 &error,
1843 DBUS_TYPE_UINT32, &uid,
1844 DBUS_TYPE_INVALID))
1845 return bus_send_error_reply(connection, message, &error, -EINVAL);
1846
1847 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1848 if (!user)
1849 return bus_send_error_reply(connection, message, &error, -ENOENT);
1850
1851 r = user_stop(user);
1852 if (r < 0)
1853 return bus_send_error_reply(connection, message, NULL, r);
1854
1855 reply = dbus_message_new_method_return(message);
1856 if (!reply)
1857 goto oom;
1858
1859 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1860 const char *name;
1861 Seat *seat;
1862
1863 if (!dbus_message_get_args(
1864 message,
1865 &error,
1866 DBUS_TYPE_STRING, &name,
1867 DBUS_TYPE_INVALID))
1868 return bus_send_error_reply(connection, message, &error, -EINVAL);
1869
1870 seat = hashmap_get(m->seats, name);
1871 if (!seat)
1872 return bus_send_error_reply(connection, message, &error, -ENOENT);
1873
1874 r = seat_stop_sessions(seat);
1875 if (r < 0)
1876 return bus_send_error_reply(connection, message, NULL, r);
1877
1878 reply = dbus_message_new_method_return(message);
1879 if (!reply)
1880 goto oom;
1881
7f7bb946
LP
1882 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
1883 uint32_t uid;
1884 struct passwd *pw;
1885 dbus_bool_t b, interactive;
1886 char *path;
1887
1888 if (!dbus_message_get_args(
1889 message,
1890 &error,
1891 DBUS_TYPE_UINT32, &uid,
1892 DBUS_TYPE_BOOLEAN, &b,
1893 DBUS_TYPE_BOOLEAN, &interactive,
1894 DBUS_TYPE_INVALID))
1895 return bus_send_error_reply(connection, message, &error, -EINVAL);
1896
1897 errno = 0;
1898 pw = getpwuid(uid);
1899 if (!pw)
1900 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
1901
89f13440 1902 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
7f7bb946
LP
1903 if (r < 0)
1904 return bus_send_error_reply(connection, message, &error, r);
1905
d2e54fae 1906 mkdir_p_label("/var/lib/systemd", 0755);
02b16a19 1907
d2e54fae 1908 r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
7f7bb946
LP
1909 if (r < 0)
1910 return bus_send_error_reply(connection, message, &error, r);
1911
1912 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
1913 if (!path)
1914 goto oom;
1915
1916 if (b) {
38f3fc7d
LP
1917 User *u;
1918
7f7bb946
LP
1919 r = touch(path);
1920 free(path);
1921
1922 if (r < 0)
1923 return bus_send_error_reply(connection, message, &error, r);
38f3fc7d
LP
1924
1925 if (manager_add_user_by_uid(m, uid, &u) >= 0)
1926 user_start(u);
1927
7f7bb946 1928 } else {
38f3fc7d
LP
1929 User *u;
1930
7f7bb946
LP
1931 r = unlink(path);
1932 free(path);
1933
1934 if (r < 0 && errno != ENOENT)
1935 return bus_send_error_reply(connection, message, &error, -errno);
38f3fc7d
LP
1936
1937 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1938 if (u)
1939 user_add_to_gc_queue(u);
7f7bb946
LP
1940 }
1941
1942 reply = dbus_message_new_method_return(message);
1943 if (!reply)
1944 goto oom;
1945
47a26690
LP
1946 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
1947 const char *sysfs, *seat;
1948 dbus_bool_t interactive;
1949
1950 if (!dbus_message_get_args(
1951 message,
1952 &error,
1953 DBUS_TYPE_STRING, &seat,
1954 DBUS_TYPE_STRING, &sysfs,
1955 DBUS_TYPE_BOOLEAN, &interactive,
1956 DBUS_TYPE_INVALID))
1957 return bus_send_error_reply(connection, message, &error, -EINVAL);
1958
1959 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
1960 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1961
89f13440 1962 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
47a26690
LP
1963 if (r < 0)
1964 return bus_send_error_reply(connection, message, &error, r);
1965
1966 r = attach_device(m, seat, sysfs);
1967 if (r < 0)
1968 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1969
1970 reply = dbus_message_new_method_return(message);
1971 if (!reply)
1972 goto oom;
7f7bb946 1973
b668e064
LP
1974
1975 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
1976 dbus_bool_t interactive;
1977
1978 if (!dbus_message_get_args(
1979 message,
1980 &error,
1981 DBUS_TYPE_BOOLEAN, &interactive,
1982 DBUS_TYPE_INVALID))
1983 return bus_send_error_reply(connection, message, &error, -EINVAL);
1984
89f13440 1985 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
b668e064
LP
1986 if (r < 0)
1987 return bus_send_error_reply(connection, message, &error, r);
1988
1989 r = flush_devices(m);
1990 if (r < 0)
1991 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1992
1993 reply = dbus_message_new_method_return(message);
1994 if (!reply)
1995 goto oom;
1996
d889a206
LP
1997 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff")) {
1998
1999 r = bus_manager_do_shutdown_or_sleep(
2000 m, connection, message,
2001 SPECIAL_POWEROFF_TARGET,
2002 INHIBIT_SHUTDOWN,
2003 "org.freedesktop.login1.power-off",
2004 "org.freedesktop.login1.power-off-multiple-sessions",
2005 "org.freedesktop.login1.power-off-ignore-inhibit",
2006 NULL,
2007 &error, &reply);
89f13440
LP
2008 if (r < 0)
2009 return bus_send_error_reply(connection, message, &error, r);
d889a206
LP
2010 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
2011 r = bus_manager_do_shutdown_or_sleep(
2012 m, connection, message,
2013 SPECIAL_REBOOT_TARGET,
2014 INHIBIT_SHUTDOWN,
2015 "org.freedesktop.login1.reboot",
2016 "org.freedesktop.login1.reboot-multiple-sessions",
2017 "org.freedesktop.login1.reboot-ignore-inhibit",
2018 NULL,
2019 &error, &reply);
89f13440
LP
2020 if (r < 0)
2021 return bus_send_error_reply(connection, message, &error, r);
2022
d889a206
LP
2023 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Suspend")) {
2024 r = bus_manager_do_shutdown_or_sleep(
2025 m, connection, message,
2026 SPECIAL_SUSPEND_TARGET,
2027 INHIBIT_SLEEP,
2028 "org.freedesktop.login1.suspend",
2029 "org.freedesktop.login1.suspend-multiple-sessions",
2030 "org.freedesktop.login1.suspend-ignore-inhibit",
2031 "mem",
2032 &error, &reply);
2033 if (r < 0)
2034 return bus_send_error_reply(connection, message, &error, r);
2035 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Hibernate")) {
2036 r = bus_manager_do_shutdown_or_sleep(
2037 m, connection, message,
2038 SPECIAL_HIBERNATE_TARGET,
2039 INHIBIT_SLEEP,
2040 "org.freedesktop.login1.hibernate",
2041 "org.freedesktop.login1.hibernate-multiple-sessions",
2042 "org.freedesktop.login1.hibernate-ignore-inhibit",
2043 "disk",
2044 &error, &reply);
2045 if (r < 0)
2046 return bus_send_error_reply(connection, message, &error, r);
f8e2fb7b 2047
d889a206 2048 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff")) {
f8e2fb7b 2049
d889a206
LP
2050 r = bus_manager_can_shutdown_or_sleep(
2051 m, connection, message,
2052 INHIBIT_SHUTDOWN,
2053 "org.freedesktop.login1.power-off",
2054 "org.freedesktop.login1.power-off-multiple-sessions",
2055 "org.freedesktop.login1.power-off-ignore-inhibit",
2056 NULL,
2057 &error, &reply);
2058 if (r < 0)
2059 return bus_send_error_reply(connection, message, &error, r);
2060 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
2061 r = bus_manager_can_shutdown_or_sleep(
2062 m, connection, message,
2063 INHIBIT_SHUTDOWN,
2064 "org.freedesktop.login1.reboot",
2065 "org.freedesktop.login1.reboot-multiple-sessions",
2066 "org.freedesktop.login1.reboot-ignore-inhibit",
2067 NULL,
2068 &error, &reply);
2069 if (r < 0)
2070 return bus_send_error_reply(connection, message, &error, r);
89f13440 2071
d889a206
LP
2072 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanSuspend")) {
2073 r = bus_manager_can_shutdown_or_sleep(
2074 m, connection, message,
2075 INHIBIT_SLEEP,
2076 "org.freedesktop.login1.suspend",
2077 "org.freedesktop.login1.suspend-multiple-sessions",
2078 "org.freedesktop.login1.suspend-ignore-inhibit",
2079 "mem",
2080 &error, &reply);
2081 if (r < 0)
2082 return bus_send_error_reply(connection, message, &error, r);
89f13440 2083
d889a206
LP
2084 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHibernate")) {
2085 r = bus_manager_can_shutdown_or_sleep(
2086 m, connection, message,
2087 INHIBIT_SLEEP,
2088 "org.freedesktop.login1.hibernate",
2089 "org.freedesktop.login1.hibernate-multiple-sessions",
2090 "org.freedesktop.login1.hibernate-ignore-inhibit",
2091 "disk",
2092 &error, &reply);
2093 if (r < 0)
2094 return bus_send_error_reply(connection, message, &error, r);
89f13440 2095
bef422ae 2096 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
3f49d45a
LP
2097 char *introspection = NULL;
2098 FILE *f;
2099 Iterator i;
2100 Session *session;
2101 Seat *seat;
2102 User *user;
2103 size_t size;
2104 char *p;
2105
2106 if (!(reply = dbus_message_new_method_return(message)))
2107 goto oom;
2108
2109 /* We roll our own introspection code here, instead of
2110 * relying on bus_default_message_handler() because we
2111 * need to generate our introspection string
2112 * dynamically. */
2113
2114 if (!(f = open_memstream(&introspection, &size)))
2115 goto oom;
2116
2117 fputs(INTROSPECTION_BEGIN, f);
2118
2119 HASHMAP_FOREACH(seat, m->seats, i) {
2120 p = bus_path_escape(seat->id);
2121
2122 if (p) {
2123 fprintf(f, "<node name=\"seat/%s\"/>", p);
2124 free(p);
2125 }
2126 }
2127
2128 HASHMAP_FOREACH(user, m->users, i)
2129 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
2130
2131 HASHMAP_FOREACH(session, m->sessions, i) {
2132 p = bus_path_escape(session->id);
2133
2134 if (p) {
2135 fprintf(f, "<node name=\"session/%s\"/>", p);
2136 free(p);
2137 }
2138 }
2139
2140 fputs(INTROSPECTION_END, f);
2141
2142 if (ferror(f)) {
2143 fclose(f);
2144 free(introspection);
2145 goto oom;
2146 }
2147
2148 fclose(f);
2149
2150 if (!introspection)
2151 goto oom;
2152
2153 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
2154 free(introspection);
2155 goto oom;
2156 }
2157
2158 free(introspection);
d200735e
MS
2159 } else {
2160 const BusBoundProperties bps[] = {
2161 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
2162 { NULL, }
2163 };
2164 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
2165 }
3f49d45a
LP
2166
2167 if (reply) {
2168 if (!dbus_connection_send(connection, reply, NULL))
2169 goto oom;
2170
2171 dbus_message_unref(reply);
2172 }
2173
2174 return DBUS_HANDLER_RESULT_HANDLED;
2175
2176oom:
2177 if (reply)
2178 dbus_message_unref(reply);
2179
2180 dbus_error_free(&error);
2181
2182 return DBUS_HANDLER_RESULT_NEED_MEMORY;
2183}
2184
2185const DBusObjectPathVTable bus_manager_vtable = {
2186 .message_function = manager_message_handler
2187};
9418f147 2188
1713813d
LP
2189DBusHandlerResult bus_message_filter(
2190 DBusConnection *connection,
2191 DBusMessage *message,
2192 void *userdata) {
2193
2194 Manager *m = userdata;
2195 DBusError error;
2196
2197 assert(m);
2198 assert(connection);
2199 assert(message);
2200
2201 dbus_error_init(&error);
2202
2203 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
2204 const char *cgroup;
2205
2206 if (!dbus_message_get_args(message, &error,
2207 DBUS_TYPE_STRING, &cgroup,
2208 DBUS_TYPE_INVALID))
2209 log_error("Failed to parse Released message: %s", bus_error_message(&error));
2210 else
2211 manager_cgroup_notify_empty(m, cgroup);
2212 }
2213
2214 dbus_error_free(&error);
2215
2216 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2217}
2218
9418f147
LP
2219int manager_send_changed(Manager *manager, const char *properties) {
2220 DBusMessage *m;
2221 int r = -ENOMEM;
2222
2223 assert(manager);
2224
2225 m = bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties);
2226 if (!m)
2227 goto finish;
2228
2229 if (!dbus_connection_send(manager->bus, m, NULL))
2230 goto finish;
2231
2232 r = 0;
2233
2234finish:
2235 if (m)
2236 dbus_message_unref(m);
2237
2238 return r;
2239}
eecd1362 2240
d889a206
LP
2241int manager_dispatch_delayed(Manager *manager) {
2242 const char *unit_name;
eecd1362
LP
2243 DBusError error;
2244 bool delayed;
2245 int r;
2246
2247 assert(manager);
2248
d889a206 2249 if (!manager->delayed_unit)
eecd1362
LP
2250 return 0;
2251
2252 /* Continue delay? */
2253 delayed =
d889a206
LP
2254 manager->delayed_timestamp + manager->inhibit_delay_max > now(CLOCK_MONOTONIC) &&
2255 manager_is_inhibited(manager, manager->delayed_what, INHIBIT_DELAY, NULL);
eecd1362
LP
2256 if (delayed)
2257 return 0;
2258
2259 /* Reset delay data */
d889a206
LP
2260 unit_name = manager->delayed_unit;
2261 manager->delayed_unit = NULL;
eecd1362
LP
2262
2263 /* Actually do the shutdown */
2264 dbus_error_init(&error);
d889a206 2265 r = send_start_unit(manager->bus, unit_name, &error);
eecd1362 2266 if (r < 0) {
d889a206
LP
2267 log_warning("Failed to send delayed message: %s", bus_error_message_or_strerror(&error, -r));
2268 dbus_error_free(&error);
eecd1362
LP
2269 return r;
2270 }
2271
2272 /* Tell people about it */
d889a206 2273 send_prepare_for(manager, manager->delayed_what, false);
eecd1362
LP
2274
2275 return 1;
2276}