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