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