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