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