]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-dbus.c
container: spawn a getty instead of a sulogin in a container
[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"
7f7bb946 31#include "polkit.h"
55af3897 32#include "special.h"
3f49d45a
LP
33
34#define BUS_MANAGER_INTERFACE \
35 " <interface name=\"org.freedesktop.login1.Manager\">\n" \
bef422ae 36 " <method name=\"GetSession\">\n" \
3f49d45a 37 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
bef422ae 38 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
3f49d45a 39 " </method>\n" \
c4aa65e7
LP
40 " <method name=\"GetSessionByPID\">\n" \
41 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
42 " <arg name=\"session\" type=\"o\" direction=\"out\"/>\n" \
43 " </method>\n" \
3f49d45a 44 " <method name=\"GetUser\">\n" \
bef422ae 45 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
3f49d45a
LP
46 " <arg name=\"user\" type=\"o\" direction=\"out\"/>\n" \
47 " </method>\n" \
bef422ae 48 " <method name=\"GetSeat\">\n" \
3f49d45a 49 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
bef422ae 50 " <arg name=\"seat\" type=\"o\" direction=\"out\"/>\n" \
3f49d45a 51 " </method>\n" \
bef422ae 52 " <method name=\"ListSessions\">\n" \
e1c9c2d5 53 " <arg name=\"sessions\" type=\"a(susso)\" direction=\"out\"/>\n" \
3f49d45a
LP
54 " </method>\n" \
55 " <method name=\"ListUsers\">\n" \
56 " <arg name=\"users\" type=\"a(uso)\" direction=\"out\"/>\n" \
57 " </method>\n" \
bef422ae
LP
58 " <method name=\"ListSeats\">\n" \
59 " <arg name=\"seats\" type=\"a(so)\" direction=\"out\"/>\n" \
3f49d45a
LP
60 " </method>\n" \
61 " <method name=\"CreateSession\">\n" \
62 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
63 " <arg name=\"leader\" type=\"u\" direction=\"in\"/>\n" \
4d6d6518 64 " <arg name=\"sevice\" type=\"s\" direction=\"in\"/>\n" \
3f49d45a 65 " <arg name=\"type\" type=\"s\" direction=\"in\"/>\n" \
55efac6c 66 " <arg name=\"class\" type=\"s\" direction=\"in\"/>\n" \
3f49d45a 67 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
4d6d6518 68 " <arg name=\"vtnr\" type=\"u\" direction=\"in\"/>\n" \
3f49d45a
LP
69 " <arg name=\"tty\" type=\"s\" direction=\"in\"/>\n" \
70 " <arg name=\"display\" type=\"s\" direction=\"in\"/>\n" \
71 " <arg name=\"remote\" type=\"b\" direction=\"in\"/>\n" \
72 " <arg name=\"remote_user\" type=\"s\" direction=\"in\"/>\n" \
73 " <arg name=\"remote_host\" type=\"s\" direction=\"in\"/>\n" \
74 " <arg name=\"controllers\" type=\"as\" direction=\"in\"/>\n" \
75 " <arg name=\"reset_controllers\" type=\"as\" direction=\"in\"/>\n" \
98a28fef 76 " <arg name=\"kill_processes\" type=\"b\" direction=\"in\"/>\n" \
3f49d45a
LP
77 " <arg name=\"id\" type=\"s\" direction=\"out\"/>\n" \
78 " <arg name=\"path\" type=\"o\" direction=\"out\"/>\n" \
98a28fef 79 " <arg name=\"runtime_path\" type=\"o\" direction=\"out\"/>\n" \
3f49d45a 80 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
bbc73283
LP
81 " <arg name=\"seat\" type=\"s\" direction=\"out\"/>\n" \
82 " <arg name=\"vtnr\" type=\"u\" direction=\"out\"/>\n" \
3f49d45a 83 " </method>\n" \
75c8e3cf
LP
84 " <method name=\"ReleaseSession\">\n" \
85 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
86 " </method>\n" \
a185c5aa
LP
87 " <method name=\"ActivateSession\">\n" \
88 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
89 " </method>\n" \
84c3361e
LP
90 " <method name=\"ActivateSessionOnSeat\">\n" \
91 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
92 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
93 " </method>\n" \
88e3dc90
LP
94 " <method name=\"LockSession\">\n" \
95 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
96 " </method>\n" \
97 " <method name=\"UnlockSession\">\n" \
98 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
99 " </method>\n" \
de07ab16
LP
100 " <method name=\"KillSession\">\n" \
101 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
cae5846b
LP
102 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
103 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
de07ab16
LP
104 " </method>\n" \
105 " <method name=\"KillUser\">\n" \
106 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
cae5846b 107 " <arg name=\"signal\" type=\"s\" direction=\"in\"/>\n" \
de07ab16 108 " </method>\n" \
3f49d45a
LP
109 " <method name=\"TerminateSession\">\n" \
110 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
111 " </method>\n" \
112 " <method name=\"TerminateUser\">\n" \
bef422ae 113 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
3f49d45a
LP
114 " </method>\n" \
115 " <method name=\"TerminateSeat\">\n" \
116 " <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
117 " </method>\n" \
7f7bb946
LP
118 " <method name=\"SetUserLinger\">\n" \
119 " <arg name=\"uid\" type=\"u\" direction=\"in\"/>\n" \
120 " <arg name=\"b\" type=\"b\" direction=\"in\"/>\n" \
121 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
122 " </method>\n" \
47a26690
LP
123 " <method name=\"AttachDevice\">\n" \
124 " <arg name=\"seat\" type=\"s\" direction=\"in\"/>\n" \
125 " <arg name=\"sysfs\" type=\"s\" direction=\"in\"/>\n" \
126 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
127 " </method>\n" \
b668e064
LP
128 " <method name=\"FlushDevices\">\n" \
129 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
130 " </method>\n" \
55af3897
LP
131 " <method name=\"PowerOff\">\n" \
132 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
133 " </method>\n" \
134 " <method name=\"Reboot\">\n" \
135 " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
136 " </method>\n" \
89f13440
LP
137 " <method name=\"CanPowerOff\">\n" \
138 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
139 " </method>\n" \
140 " <method name=\"CanReboot\">\n" \
141 " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
142 " </method>\n" \
f8e2fb7b
LP
143 " <method name=\"Inhibit\">\n" \
144 " <arg name=\"what\" type=\"s\" direction=\"in\"/>\n" \
145 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
146 " <arg name=\"why\" type=\"s\" direction=\"in\"/>\n" \
147 " <arg name=\"fd\" type=\"h\" direction=\"out\"/>\n" \
148 " </method>\n" \
149 " <method name=\"ListInhibitors\">\n" \
150 " <arg name=\"inhibitors\" type=\"a(sssuu)\" direction=\"out\"/>\n" \
151 " </method>\n" \
3f49d45a
LP
152 " <signal name=\"SessionNew\">\n" \
153 " <arg name=\"id\" type=\"s\"/>\n" \
154 " <arg name=\"path\" type=\"o\"/>\n" \
155 " </signal>\n" \
156 " <signal name=\"SessionRemoved\">\n" \
157 " <arg name=\"id\" type=\"s\"/>\n" \
158 " <arg name=\"path\" type=\"o\"/>\n" \
159 " </signal>\n" \
160 " <signal name=\"UserNew\">\n" \
161 " <arg name=\"uid\" type=\"u\"/>\n" \
162 " <arg name=\"path\" type=\"o\"/>\n" \
163 " </signal>\n" \
164 " <signal name=\"UserRemoved\">\n" \
165 " <arg name=\"uid\" type=\"u\"/>\n" \
166 " <arg name=\"path\" type=\"o\"/>\n" \
167 " </signal>\n" \
168 " <signal name=\"SeatNew\">\n" \
169 " <arg name=\"id\" type=\"s\"/>\n" \
170 " <arg name=\"path\" type=\"o\"/>\n" \
171 " </signal>\n" \
172 " <signal name=\"SeatRemoved\">\n" \
173 " <arg name=\"id\" type=\"s\"/>\n" \
174 " <arg name=\"path\" type=\"o\"/>\n" \
175 " </signal>\n" \
176 " <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
177 " <property name=\"Controllers\" type=\"as\" access=\"read\"/>\n" \
178 " <property name=\"ResetControllers\" type=\"as\" access=\"read\"/>\n" \
179 " <property name=\"NAutoVTs\" type=\"u\" access=\"read\"/>\n" \
180 " <property name=\"KillOnlyUsers\" type=\"as\" access=\"read\"/>\n" \
181 " <property name=\"KillExcludeUsers\" type=\"as\" access=\"read\"/>\n" \
182 " <property name=\"KillUserProcesses\" type=\"b\" access=\"read\"/>\n" \
a185c5aa
LP
183 " <property name=\"IdleHint\" type=\"b\" access=\"read\"/>\n" \
184 " <property name=\"IdleSinceHint\" type=\"t\" access=\"read\"/>\n" \
185 " <property name=\"IdleSinceHintMonotonic\" type=\"t\" access=\"read\"/>\n" \
f8e2fb7b 186 " <property name=\"Inhibited\" type=\"s\" access=\"read\"/>\n" \
3f49d45a
LP
187 " </interface>\n"
188
189#define INTROSPECTION_BEGIN \
190 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
191 "<node>\n" \
192 BUS_MANAGER_INTERFACE \
193 BUS_PROPERTIES_INTERFACE \
194 BUS_PEER_INTERFACE \
195 BUS_INTROSPECTABLE_INTERFACE
196
197#define INTROSPECTION_END \
198 "</node>\n"
199
200#define INTERFACES_LIST \
201 BUS_GENERIC_INTERFACES_LIST \
202 "org.freedesktop.login1.Manager\0"
203
a185c5aa
LP
204static int bus_manager_append_idle_hint(DBusMessageIter *i, const char *property, void *data) {
205 Manager *m = data;
77527da0 206 dbus_bool_t b;
a185c5aa
LP
207
208 assert(i);
209 assert(property);
210 assert(m);
211
77527da0 212 b = manager_get_idle_hint(m, NULL) > 0;
a185c5aa
LP
213 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
214 return -ENOMEM;
215
216 return 0;
217}
218
219static int bus_manager_append_idle_hint_since(DBusMessageIter *i, const char *property, void *data) {
220 Manager *m = data;
221 dual_timestamp t;
222 uint64_t u;
223
224 assert(i);
225 assert(property);
226 assert(m);
227
228 manager_get_idle_hint(m, &t);
229 u = streq(property, "IdleSinceHint") ? t.realtime : t.monotonic;
230
231 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
232 return -ENOMEM;
233
234 return 0;
235}
236
f8e2fb7b
LP
237static int bus_manager_append_inhibited(DBusMessageIter *i, const char *property, void *data) {
238 Manager *m = data;
239 InhibitWhat w;
240 const char *p;
241
242 w = manager_inhibit_what(m);
243 p = inhibit_what_to_string(w);
244
245 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &p))
246 return -ENOMEM;
247
248 return 0;
249}
250
98a28fef
LP
251static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMessage **_reply) {
252 Session *session = NULL;
253 User *user = NULL;
55efac6c 254 const char *type, *class, *seat, *tty, *display, *remote_user, *remote_host, *service;
98a28fef
LP
255 uint32_t uid, leader, audit_id = 0;
256 dbus_bool_t remote, kill_processes;
257 char **controllers = NULL, **reset_controllers = NULL;
258 SessionType t;
55efac6c 259 SessionClass c;
98a28fef
LP
260 Seat *s;
261 DBusMessageIter iter;
262 int r;
07714753 263 char *id = NULL, *p;
4d6d6518 264 uint32_t vtnr = 0;
932e3ee7 265 int fifo_fd = -1;
98a28fef
LP
266 DBusMessage *reply = NULL;
267 bool b;
268
269 assert(m);
270 assert(message);
271 assert(_reply);
272
273 if (!dbus_message_iter_init(message, &iter) ||
274 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
275 return -EINVAL;
276
277 dbus_message_iter_get_basic(&iter, &uid);
278
279 if (!dbus_message_iter_next(&iter) ||
280 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
281 return -EINVAL;
282
283 dbus_message_iter_get_basic(&iter, &leader);
284
285 if (leader <= 0 ||
286 !dbus_message_iter_next(&iter) ||
287 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
288 return -EINVAL;
289
290 dbus_message_iter_get_basic(&iter, &service);
291
292 if (!dbus_message_iter_next(&iter) ||
293 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
294 return -EINVAL;
295
296 dbus_message_iter_get_basic(&iter, &type);
297 t = session_type_from_string(type);
298
299 if (t < 0 ||
300 !dbus_message_iter_next(&iter) ||
301 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
302 return -EINVAL;
303
55efac6c
LP
304 dbus_message_iter_get_basic(&iter, &class);
305 if (isempty(class))
306 c = SESSION_USER;
307 else
308 c = session_class_from_string(class);
309
310 if (c < 0 ||
311 !dbus_message_iter_next(&iter) ||
312 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
313 return -EINVAL;
314
98a28fef
LP
315 dbus_message_iter_get_basic(&iter, &seat);
316
317 if (isempty(seat))
318 s = NULL;
319 else {
320 s = hashmap_get(m->seats, seat);
321 if (!s)
322 return -ENOENT;
323 }
324
4d6d6518
LP
325 if (!dbus_message_iter_next(&iter) ||
326 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
327 return -EINVAL;
328
329 dbus_message_iter_get_basic(&iter, &vtnr);
330
98a28fef
LP
331 if (!dbus_message_iter_next(&iter) ||
332 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
333 return -EINVAL;
334
335 dbus_message_iter_get_basic(&iter, &tty);
336
337 if (tty_is_vc(tty)) {
4d6d6518 338 int v;
98a28fef
LP
339
340 if (!s)
341 s = m->vtconsole;
342 else if (s != m->vtconsole)
343 return -EINVAL;
344
4d6d6518
LP
345 v = vtnr_from_tty(tty);
346
347 if (v <= 0)
348 return v < 0 ? v : -EINVAL;
98a28fef
LP
349
350 if (vtnr <= 0)
4d6d6518
LP
351 vtnr = (uint32_t) v;
352 else if (vtnr != (uint32_t) v)
353 return -EINVAL;
98a28fef 354
bf100920 355 } else if (!isempty(tty) && s && seat_is_vtconsole(s))
98a28fef
LP
356 return -EINVAL;
357
4d6d6518 358 if (s) {
addedec4 359 if (seat_can_multi_session(s)) {
4d6d6518
LP
360 if (vtnr <= 0 || vtnr > 63)
361 return -EINVAL;
362 } else {
363 if (vtnr > 0)
364 return -EINVAL;
365 }
366 }
367
98a28fef
LP
368 if (!dbus_message_iter_next(&iter) ||
369 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
370 return -EINVAL;
371
372 dbus_message_iter_get_basic(&iter, &display);
373
374 if (!dbus_message_iter_next(&iter) ||
375 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
376 return -EINVAL;
377
378 dbus_message_iter_get_basic(&iter, &remote);
379
380 if (!dbus_message_iter_next(&iter) ||
381 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
382 return -EINVAL;
383
384 dbus_message_iter_get_basic(&iter, &remote_user);
385
386 if (!dbus_message_iter_next(&iter) ||
387 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
388 return -EINVAL;
389
390 dbus_message_iter_get_basic(&iter, &remote_host);
391
392 if (!dbus_message_iter_next(&iter) ||
393 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
394 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
395 return -EINVAL;
396
397 r = bus_parse_strv_iter(&iter, &controllers);
398 if (r < 0)
399 return -EINVAL;
400
25d93491
LP
401 if (strv_contains(controllers, "systemd") ||
402 !dbus_message_iter_next(&iter) ||
98a28fef
LP
403 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
404 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING) {
405 r = -EINVAL;
406 goto fail;
407 }
408
409 r = bus_parse_strv_iter(&iter, &reset_controllers);
410 if (r < 0)
411 goto fail;
412
25d93491
LP
413 if (strv_contains(reset_controllers, "systemd") ||
414 !dbus_message_iter_next(&iter) ||
98a28fef
LP
415 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN) {
416 r = -EINVAL;
417 goto fail;
418 }
419
420 dbus_message_iter_get_basic(&iter, &kill_processes);
421
422 r = manager_add_user_by_uid(m, uid, &user);
423 if (r < 0)
424 goto fail;
425
426 audit_session_from_pid(leader, &audit_id);
427
07714753 428 if (audit_id > 0) {
98a28fef 429 asprintf(&id, "%lu", (unsigned long) audit_id);
98a28fef 430
07714753
LP
431 if (!id) {
432 r = -ENOMEM;
433 goto fail;
434 }
98a28fef 435
21c390cc
LP
436 session = hashmap_get(m->sessions, id);
437
438 if (session) {
8ea913b2 439 free(id);
21c390cc 440
932e3ee7
LP
441 fifo_fd = session_create_fifo(session);
442 if (fifo_fd < 0) {
443 r = fifo_fd;
444 goto fail;
445 }
446
21c390cc
LP
447 /* Session already exists, client is probably
448 * something like "su" which changes uid but
449 * is still the same audit session */
450
451 reply = dbus_message_new_method_return(message);
452 if (!reply) {
453 r = -ENOMEM;
454 goto fail;
455 }
456
21c390cc
LP
457 p = session_bus_path(session);
458 if (!p) {
459 r = -ENOMEM;
460 goto fail;
461 }
462
3887b5ab
LP
463 seat = session->seat ? session->seat->id : "";
464 vtnr = session->vtnr;
21c390cc
LP
465 b = dbus_message_append_args(
466 reply,
467 DBUS_TYPE_STRING, &session->id,
468 DBUS_TYPE_OBJECT_PATH, &p,
469 DBUS_TYPE_STRING, &session->user->runtime_path,
932e3ee7 470 DBUS_TYPE_UNIX_FD, &fifo_fd,
3887b5ab
LP
471 DBUS_TYPE_STRING, &seat,
472 DBUS_TYPE_UINT32, &vtnr,
21c390cc
LP
473 DBUS_TYPE_INVALID);
474 free(p);
475
476 if (!b) {
477 r = -ENOMEM;
478 goto fail;
479 }
480
932e3ee7 481 close_nointr_nofail(fifo_fd);
21c390cc
LP
482 *_reply = reply;
483
8ea913b2
LP
484 strv_free(controllers);
485 strv_free(reset_controllers);
486
21c390cc 487 return 0;
07714753
LP
488 }
489
490 } else {
491 do {
492 free(id);
f8e2fb7b 493 id = NULL;
07714753 494
f8e2fb7b 495 if (asprintf(&id, "c%lu", ++m->session_counter) < 0) {
07714753
LP
496 r = -ENOMEM;
497 goto fail;
498 }
499
500 } while (hashmap_get(m->sessions, id));
98a28fef
LP
501 }
502
503 r = manager_add_session(m, user, id, &session);
504 free(id);
505 if (r < 0)
506 goto fail;
507
508 session->leader = leader;
509 session->audit_id = audit_id;
510 session->type = t;
55efac6c 511 session->class = c;
98a28fef
LP
512 session->remote = remote;
513 session->controllers = controllers;
514 session->reset_controllers = reset_controllers;
515 session->kill_processes = kill_processes;
516 session->vtnr = vtnr;
517
518 controllers = reset_controllers = NULL;
519
520 if (!isempty(tty)) {
521 session->tty = strdup(tty);
522 if (!session->tty) {
523 r = -ENOMEM;
524 goto fail;
525 }
526 }
527
528 if (!isempty(display)) {
529 session->display = strdup(display);
530 if (!session->display) {
531 r = -ENOMEM;
532 goto fail;
533 }
534 }
535
536 if (!isempty(remote_user)) {
537 session->remote_user = strdup(remote_user);
538 if (!session->remote_user) {
539 r = -ENOMEM;
540 goto fail;
541 }
542 }
543
544 if (!isempty(remote_host)) {
545 session->remote_host = strdup(remote_host);
546 if (!session->remote_host) {
547 r = -ENOMEM;
548 goto fail;
549 }
550 }
551
552 if (!isempty(service)) {
553 session->service = strdup(service);
554 if (!session->service) {
555 r = -ENOMEM;
556 goto fail;
557 }
558 }
559
932e3ee7
LP
560 fifo_fd = session_create_fifo(session);
561 if (fifo_fd < 0) {
562 r = fifo_fd;
98a28fef
LP
563 goto fail;
564 }
565
98a28fef
LP
566 if (s) {
567 r = seat_attach_session(s, session);
568 if (r < 0)
569 goto fail;
570 }
571
572 r = session_start(session);
573 if (r < 0)
574 goto fail;
575
576 reply = dbus_message_new_method_return(message);
577 if (!reply) {
578 r = -ENOMEM;
579 goto fail;
580 }
581
582 p = session_bus_path(session);
583 if (!p) {
584 r = -ENOMEM;
585 goto fail;
586 }
587
bbc73283 588 seat = s ? s->id : "";
98a28fef
LP
589 b = dbus_message_append_args(
590 reply,
591 DBUS_TYPE_STRING, &session->id,
592 DBUS_TYPE_OBJECT_PATH, &p,
593 DBUS_TYPE_STRING, &session->user->runtime_path,
932e3ee7 594 DBUS_TYPE_UNIX_FD, &fifo_fd,
bbc73283
LP
595 DBUS_TYPE_STRING, &seat,
596 DBUS_TYPE_UINT32, &vtnr,
98a28fef
LP
597 DBUS_TYPE_INVALID);
598 free(p);
599
600 if (!b) {
601 r = -ENOMEM;
602 goto fail;
603 }
604
932e3ee7 605 close_nointr_nofail(fifo_fd);
98a28fef
LP
606 *_reply = reply;
607
608 return 0;
609
610fail:
611 strv_free(controllers);
612 strv_free(reset_controllers);
613
614 if (session)
615 session_add_to_gc_queue(session);
616
617 if (user)
618 user_add_to_gc_queue(user);
619
932e3ee7
LP
620 if (fifo_fd >= 0)
621 close_nointr_nofail(fifo_fd);
98a28fef
LP
622
623 if (reply)
624 dbus_message_unref(reply);
625
626 return r;
627}
628
f8e2fb7b
LP
629static int bus_manager_inhibit(Manager *m, DBusConnection *connection, DBusMessage *message, DBusError *error, DBusMessage **_reply) {
630 Inhibitor *i = NULL;
631 char *id = NULL;
632 const char *who, *why, *what;
633 pid_t pid;
634 InhibitWhat w;
635 unsigned long ul;
636 int r, fifo_fd = -1;
637 DBusMessage *reply = NULL;
638
639 assert(m);
640 assert(connection);
641 assert(message);
642 assert(error);
643 assert(_reply);
644
645 if (!dbus_message_get_args(
646 message,
647 error,
648 DBUS_TYPE_STRING, &what,
649 DBUS_TYPE_STRING, &who,
650 DBUS_TYPE_STRING, &why,
651 DBUS_TYPE_INVALID)) {
652 r = -EIO;
653 goto fail;
654 }
655
656 w = inhibit_what_from_string(what);
657 if (w <= 0) {
658 r = -EINVAL;
659 goto fail;
660 }
661
662 r = verify_polkit(connection, message, "org.freedesktop.login1.inhibit", false, NULL, error);
663 if (r < 0)
664 goto fail;
665
666 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
667 if (ul == (unsigned long) -1) {
668 r = -EIO;
669 goto fail;
670 }
671
672 pid = bus_get_unix_process_id(connection, dbus_message_get_sender(message), error);
673 if (pid <= 0) {
674 r = -EIO;
675 goto fail;
676 }
677
678 do {
679 free(id);
680 id = NULL;
681
682 if (asprintf(&id, "%lu", ++m->inhibit_counter) < 0) {
683 r = -ENOMEM;
684 goto fail;
685 }
686 } while (hashmap_get(m->inhibitors, id));
687
688 r = manager_add_inhibitor(m, id, &i);
689 free(id);
690
691 if (r < 0)
692 goto fail;
693
694 i->what = w;
695 i->pid = pid;
696 i->uid = (uid_t) ul;
697 i->why = strdup(why);
698 i->who = strdup(who);
699
700 if (!i->why || !i->who) {
701 r = -ENOMEM;
702 goto fail;
703 }
704
705 fifo_fd = inhibitor_create_fifo(i);
706 if (fifo_fd < 0) {
707 r = fifo_fd;
708 goto fail;
709 }
710
711 reply = dbus_message_new_method_return(message);
712 if (!reply) {
713 r = -ENOMEM;
714 goto fail;
715 }
716
717 if (!dbus_message_append_args(
718 reply,
719 DBUS_TYPE_UNIX_FD, &fifo_fd,
720 DBUS_TYPE_INVALID)) {
721 r = -ENOMEM;
722 goto fail;
723 }
724
725 close_nointr_nofail(fifo_fd);
726 *_reply = reply;
727
728 inhibitor_start(i);
729
730 return 0;
731
732fail:
733 if (i)
734 inhibitor_free(i);
735
736 if (fifo_fd >= 0)
737 close_nointr_nofail(fifo_fd);
738
739 if (reply)
740 dbus_message_unref(reply);
741
742 return r;
743}
744
2eb916cd 745static int trigger_device(Manager *m, struct udev_device *d) {
b668e064
LP
746 struct udev_enumerate *e;
747 struct udev_list_entry *first, *item;
748 int r;
749
750 assert(m);
751
752 e = udev_enumerate_new(m->udev);
753 if (!e) {
754 r = -ENOMEM;
755 goto finish;
756 }
757
2eb916cd
LP
758 if (d) {
759 if (udev_enumerate_add_match_parent(e, d) < 0) {
760 r = -EIO;
761 goto finish;
762 }
763 }
764
b668e064
LP
765 if (udev_enumerate_scan_devices(e) < 0) {
766 r = -EIO;
767 goto finish;
768 }
769
770 first = udev_enumerate_get_list_entry(e);
771 udev_list_entry_foreach(item, first) {
772 char *t;
773 const char *p;
774
775 p = udev_list_entry_get_name(item);
776
b668e064
LP
777 t = strappend(p, "/uevent");
778 if (!t) {
779 r = -ENOMEM;
780 goto finish;
781 }
782
783 write_one_line_file(t, "change");
784 free(t);
785 }
786
787 r = 0;
788
789finish:
790 if (e)
791 udev_enumerate_unref(e);
792
793 return r;
794}
795
47a26690
LP
796static int attach_device(Manager *m, const char *seat, const char *sysfs) {
797 struct udev_device *d;
798 char *rule = NULL, *file = NULL;
c28fa3d3 799 const char *id_for_seat;
47a26690
LP
800 int r;
801
802 assert(m);
803 assert(seat);
804 assert(sysfs);
805
806 d = udev_device_new_from_syspath(m->udev, sysfs);
807 if (!d)
808 return -ENODEV;
809
309c2a2c 810 if (!udev_device_has_tag(d, "seat")) {
47a26690
LP
811 r = -ENODEV;
812 goto finish;
813 }
814
c28fa3d3
LP
815 id_for_seat = udev_device_get_property_value(d, "ID_FOR_SEAT");
816 if (!id_for_seat) {
47a26690
LP
817 r = -ENODEV;
818 goto finish;
819 }
820
c28fa3d3 821 if (asprintf(&file, "/etc/udev/rules.d/72-seat-%s.rules", id_for_seat) < 0) {
47a26690
LP
822 r = -ENOMEM;
823 goto finish;
824 }
825
c28fa3d3 826 if (asprintf(&rule, "TAG==\"seat\", ENV{ID_FOR_SEAT}==\"%s\", ENV{ID_SEAT}=\"%s\"", id_for_seat, seat) < 0) {
47a26690
LP
827 r = -ENOMEM;
828 goto finish;
829 }
830
c28fa3d3 831 mkdir_p("/etc/udev/rules.d", 0755);
b5ef5549 832 r = write_one_line_file_atomic(file, rule);
a0a0c7f1
LP
833 if (r < 0)
834 goto finish;
835
2eb916cd 836 r = trigger_device(m, d);
47a26690
LP
837
838finish:
839 free(rule);
840 free(file);
841
842 if (d)
843 udev_device_unref(d);
844
845 return r;
846}
847
b668e064
LP
848static int flush_devices(Manager *m) {
849 DIR *d;
850
851 assert(m);
852
853 d = opendir("/etc/udev/rules.d");
854 if (!d) {
855 if (errno != ENOENT)
856 log_warning("Failed to open /etc/udev/rules.d: %m");
857 } else {
858 struct dirent *de;
859
860 while ((de = readdir(d))) {
861
862 if (!dirent_is_file(de))
863 continue;
864
865 if (!startswith(de->d_name, "72-seat-"))
866 continue;
867
868 if (!endswith(de->d_name, ".rules"))
869 continue;
870
871 if (unlinkat(dirfd(d), de->d_name, 0) < 0)
872 log_warning("Failed to unlink %s: %m", de->d_name);
873 }
874
875 closedir(d);
876 }
877
878 return trigger_device(m, NULL);
879}
880
89f13440
LP
881static int have_multiple_sessions(
882 DBusConnection *connection,
883 Manager *m,
884 DBusMessage *message,
885 DBusError *error) {
886
887 Session *s;
888
889 assert(m);
890
891 if (hashmap_size(m->sessions) > 1)
892 return true;
893
894 /* Hmm, there's only one session, but let's make sure it
895 * actually belongs to the user who is asking. If not, better
896 * be safe than sorry. */
897
898 s = hashmap_first(m->sessions);
899 if (s) {
900 unsigned long ul;
901
902 ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
903 if (ul == (unsigned long) -1)
904 return -EIO;
905
906 return s->user->uid != ul;
907 }
908
909 return false;
910}
911
d200735e
MS
912static const BusProperty bus_login_manager_properties[] = {
913 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_path), true },
914 { "Controllers", bus_property_append_strv, "as", offsetof(Manager, controllers), true },
915 { "ResetControllers", bus_property_append_strv, "as", offsetof(Manager, reset_controllers), true },
916 { "NAutoVTs", bus_property_append_unsigned, "u", offsetof(Manager, n_autovts) },
917 { "KillOnlyUsers", bus_property_append_strv, "as", offsetof(Manager, kill_only_users), true },
918 { "KillExcludeUsers", bus_property_append_strv, "as", offsetof(Manager, kill_exclude_users), true },
919 { "KillUserProcesses", bus_property_append_bool, "b", offsetof(Manager, kill_user_processes) },
920 { "IdleHint", bus_manager_append_idle_hint, "b", 0 },
921 { "IdleSinceHint", bus_manager_append_idle_hint_since, "t", 0 },
922 { "IdleSinceHintMonotonic", bus_manager_append_idle_hint_since, "t", 0 },
f8e2fb7b 923 { "Inhibited", bus_manager_append_inhibited, "s", 0 },
d200735e
MS
924 { NULL, }
925};
926
3f49d45a
LP
927static DBusHandlerResult manager_message_handler(
928 DBusConnection *connection,
929 DBusMessage *message,
930 void *userdata) {
931
932 Manager *m = userdata;
933
3f49d45a
LP
934 DBusError error;
935 DBusMessage *reply = NULL;
bef422ae 936 int r;
3f49d45a
LP
937
938 assert(connection);
939 assert(message);
940 assert(m);
941
942 dbus_error_init(&error);
943
bef422ae
LP
944 if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSession")) {
945 const char *name;
946 char *p;
947 Session *session;
948 bool b;
949
950 if (!dbus_message_get_args(
951 message,
952 &error,
953 DBUS_TYPE_STRING, &name,
954 DBUS_TYPE_INVALID))
955 return bus_send_error_reply(connection, message, &error, -EINVAL);
956
957 session = hashmap_get(m->sessions, name);
958 if (!session)
959 return bus_send_error_reply(connection, message, &error, -ENOENT);
960
961 reply = dbus_message_new_method_return(message);
962 if (!reply)
963 goto oom;
964
965 p = session_bus_path(session);
c4aa65e7
LP
966 if (!p)
967 goto oom;
968
969 b = dbus_message_append_args(
970 reply,
971 DBUS_TYPE_OBJECT_PATH, &p,
972 DBUS_TYPE_INVALID);
973 free(p);
974
975 if (!b)
976 goto oom;
977
978 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSessionByPID")) {
979 uint32_t pid;
980 char *p;
981 Session *session;
982 bool b;
983
984 if (!dbus_message_get_args(
985 message,
986 &error,
987 DBUS_TYPE_UINT32, &pid,
988 DBUS_TYPE_INVALID))
989 return bus_send_error_reply(connection, message, &error, -EINVAL);
990
991 r = manager_get_session_by_pid(m, pid, &session);
992 if (r <= 0)
993 return bus_send_error_reply(connection, message, NULL, r < 0 ? r : -ENOENT);
994
995 reply = dbus_message_new_method_return(message);
996 if (!reply)
997 goto oom;
998
999 p = session_bus_path(session);
bef422ae
LP
1000 if (!p)
1001 goto oom;
1002
1003 b = dbus_message_append_args(
1004 reply,
1005 DBUS_TYPE_OBJECT_PATH, &p,
1006 DBUS_TYPE_INVALID);
1007 free(p);
1008
1009 if (!b)
1010 goto oom;
1011
1012 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetUser")) {
1013 uint32_t uid;
1014 char *p;
1015 User *user;
1016 bool b;
1017
1018 if (!dbus_message_get_args(
1019 message,
1020 &error,
1021 DBUS_TYPE_UINT32, &uid,
1022 DBUS_TYPE_INVALID))
1023 return bus_send_error_reply(connection, message, &error, -EINVAL);
1024
1025 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1026 if (!user)
1027 return bus_send_error_reply(connection, message, &error, -ENOENT);
1028
1029 reply = dbus_message_new_method_return(message);
1030 if (!reply)
1031 goto oom;
1032
1033 p = user_bus_path(user);
1034 if (!p)
1035 goto oom;
1036
1037 b = dbus_message_append_args(
1038 reply,
1039 DBUS_TYPE_OBJECT_PATH, &p,
1040 DBUS_TYPE_INVALID);
1041 free(p);
1042
1043 if (!b)
1044 goto oom;
1045
1046 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "GetSeat")) {
1047 const char *name;
1048 char *p;
1049 Seat *seat;
1050 bool b;
1051
1052 if (!dbus_message_get_args(
1053 message,
1054 &error,
1055 DBUS_TYPE_STRING, &name,
1056 DBUS_TYPE_INVALID))
1057 return bus_send_error_reply(connection, message, &error, -EINVAL);
1058
1059 seat = hashmap_get(m->seats, name);
1060 if (!seat)
1061 return bus_send_error_reply(connection, message, &error, -ENOENT);
1062
1063 reply = dbus_message_new_method_return(message);
1064 if (!reply)
1065 goto oom;
1066
1067 p = seat_bus_path(seat);
1068 if (!p)
1069 goto oom;
1070
1071 b = dbus_message_append_args(
1072 reply,
1073 DBUS_TYPE_OBJECT_PATH, &p,
1074 DBUS_TYPE_INVALID);
1075 free(p);
1076
1077 if (!b)
1078 goto oom;
1079
e1c9c2d5
LP
1080 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSessions")) {
1081 char *p;
1082 Session *session;
1083 Iterator i;
1084 DBusMessageIter iter, sub;
1085 const char *empty = "";
1086
1087 reply = dbus_message_new_method_return(message);
1088 if (!reply)
1089 goto oom;
1090
1091 dbus_message_iter_init_append(reply, &iter);
1092
dec15e92 1093 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(susso)", &sub))
e1c9c2d5
LP
1094 goto oom;
1095
1096 HASHMAP_FOREACH(session, m->sessions, i) {
1097 DBusMessageIter sub2;
1098 uint32_t uid;
1099
1100 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1101 goto oom;
1102
1103 uid = session->user->uid;
1104
1105 p = session_bus_path(session);
1106 if (!p)
1107 goto oom;
1108
1109 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->id) ||
1110 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1111 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &session->user->name) ||
1112 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, session->seat ? (const char**) &session->seat->id : &empty) ||
1113 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1114 free(p);
1115 goto oom;
1116 }
1117
1118 free(p);
1119
1120 if (!dbus_message_iter_close_container(&sub, &sub2))
1121 goto oom;
1122 }
1123
1124 if (!dbus_message_iter_close_container(&iter, &sub))
1125 goto oom;
1126
1127 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListUsers")) {
1128 char *p;
1129 User *user;
1130 Iterator i;
1131 DBusMessageIter iter, sub;
1132
1133 reply = dbus_message_new_method_return(message);
1134 if (!reply)
1135 goto oom;
1136
1137 dbus_message_iter_init_append(reply, &iter);
1138
dec15e92 1139 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(uso)", &sub))
e1c9c2d5
LP
1140 goto oom;
1141
1142 HASHMAP_FOREACH(user, m->users, i) {
1143 DBusMessageIter sub2;
1144 uint32_t uid;
1145
1146 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1147 goto oom;
1148
1149 uid = user->uid;
1150
1151 p = user_bus_path(user);
1152 if (!p)
1153 goto oom;
1154
1155 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1156 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &user->name) ||
1157 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1158 free(p);
1159 goto oom;
1160 }
1161
1162 free(p);
1163
1164 if (!dbus_message_iter_close_container(&sub, &sub2))
1165 goto oom;
1166 }
1167
1168 if (!dbus_message_iter_close_container(&iter, &sub))
1169 goto oom;
1170
1171 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListSeats")) {
1172 char *p;
1173 Seat *seat;
1174 Iterator i;
1175 DBusMessageIter iter, sub;
1176
1177 reply = dbus_message_new_method_return(message);
1178 if (!reply)
1179 goto oom;
1180
1181 dbus_message_iter_init_append(reply, &iter);
1182
dec15e92 1183 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(so)", &sub))
e1c9c2d5
LP
1184 goto oom;
1185
1186 HASHMAP_FOREACH(seat, m->seats, i) {
1187 DBusMessageIter sub2;
1188
1189 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1190 goto oom;
1191
1192 p = seat_bus_path(seat);
1193 if (!p)
1194 goto oom;
1195
1196 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &seat->id) ||
1197 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &p)) {
1198 free(p);
1199 goto oom;
1200 }
1201
1202 free(p);
1203
1204 if (!dbus_message_iter_close_container(&sub, &sub2))
1205 goto oom;
1206 }
1207
1208 if (!dbus_message_iter_close_container(&iter, &sub))
1209 goto oom;
1210
f8e2fb7b
LP
1211 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ListInhibitors")) {
1212 Inhibitor *inhibitor;
1213 Iterator i;
1214 DBusMessageIter iter, sub;
1215
1216 reply = dbus_message_new_method_return(message);
1217 if (!reply)
1218 goto oom;
1219
1220 dbus_message_iter_init_append(reply, &iter);
1221
1222 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sssuu)", &sub))
1223 goto oom;
1224
1225 HASHMAP_FOREACH(inhibitor, m->inhibitors, i) {
1226 DBusMessageIter sub2;
1227 dbus_uint32_t uid, pid;
1228 const char *what, *who, *why;
1229
1230 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1231 goto oom;
1232
1233 what = inhibit_what_to_string(inhibitor->what);
1234 who = strempty(inhibitor->who);
1235 why = strempty(inhibitor->why);
1236 uid = (dbus_uint32_t) inhibitor->uid;
1237 pid = (dbus_uint32_t) inhibitor->pid;
1238
1239 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &what) ||
1240 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &who) ||
1241 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &why) ||
1242 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &uid) ||
1243 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid))
1244 goto oom;
1245
1246 if (!dbus_message_iter_close_container(&sub, &sub2))
1247 goto oom;
1248 }
1249
1250 if (!dbus_message_iter_close_container(&iter, &sub))
1251 goto oom;
1252
1253 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Inhibit")) {
1254
1255 r = bus_manager_inhibit(m, connection, message, &error, &reply);
1256
1257 if (r < 0)
1258 return bus_send_error_reply(connection, message, &error, r);
1259
1260
98a28fef
LP
1261 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
1262
1263 r = bus_manager_create_session(m, message, &reply);
688c56ff
LP
1264
1265 /* Don't delay the work on OOM here, since it might be
1266 * triggered by a low RLIMIT_NOFILE here (since we
1267 * send a dupped fd to the client), and we'd rather
1268 * see this fail quickly then be retried later */
98a28fef
LP
1269
1270 if (r < 0)
f8e2fb7b 1271 return bus_send_error_reply(connection, message, NULL, r);
98a28fef 1272
75c8e3cf
LP
1273 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ReleaseSession")) {
1274 const char *name;
1275 Session *session;
1276
1277 if (!dbus_message_get_args(
1278 message,
1279 &error,
1280 DBUS_TYPE_STRING, &name,
1281 DBUS_TYPE_INVALID))
1282 return bus_send_error_reply(connection, message, &error, -EINVAL);
1283
1284 session = hashmap_get(m->sessions, name);
1285 if (!session)
1286 return bus_send_error_reply(connection, message, &error, -ENOENT);
1287
1288 /* We use the FIFO to detect stray sessions where the
1289 process invoking PAM dies abnormally. We need to make
1290 sure that that process is not killed if at the clean
1291 end of the session it closes the FIFO. Hence, with
1292 this call explicitly turn off the FIFO logic, so that
1293 the PAM code can finish clean up on its own */
1294 session_remove_fifo(session);
1295
1296 reply = dbus_message_new_method_return(message);
1297 if (!reply)
1298 goto oom;
1299
bef422ae
LP
1300 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSession")) {
1301 const char *name;
1302 Session *session;
1303
1304 if (!dbus_message_get_args(
1305 message,
1306 &error,
1307 DBUS_TYPE_STRING, &name,
1308 DBUS_TYPE_INVALID))
1309 return bus_send_error_reply(connection, message, &error, -EINVAL);
1310
1311 session = hashmap_get(m->sessions, name);
1312 if (!session)
1313 return bus_send_error_reply(connection, message, &error, -ENOENT);
1314
1315 r = session_activate(session);
1316 if (r < 0)
1317 return bus_send_error_reply(connection, message, NULL, r);
1318
1319 reply = dbus_message_new_method_return(message);
1320 if (!reply)
1321 goto oom;
1322
84c3361e
LP
1323 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "ActivateSessionOnSeat")) {
1324 const char *session_name, *seat_name;
1325 Session *session;
1326 Seat *seat;
1327
1328 /* Same as ActivateSession() but refuses to work if
1329 * the seat doesn't match */
1330
1331 if (!dbus_message_get_args(
1332 message,
1333 &error,
1334 DBUS_TYPE_STRING, &session_name,
1335 DBUS_TYPE_STRING, &seat_name,
1336 DBUS_TYPE_INVALID))
1337 return bus_send_error_reply(connection, message, &error, -EINVAL);
1338
1339 session = hashmap_get(m->sessions, session_name);
1340 if (!session)
1341 return bus_send_error_reply(connection, message, &error, -ENOENT);
1342
1343 seat = hashmap_get(m->seats, seat_name);
1344 if (!seat)
1345 return bus_send_error_reply(connection, message, &error, -ENOENT);
1346
1347 if (session->seat != seat)
1348 return bus_send_error_reply(connection, message, &error, -EINVAL);
1349
1350 r = session_activate(session);
1351 if (r < 0)
1352 return bus_send_error_reply(connection, message, NULL, r);
1353
1354 reply = dbus_message_new_method_return(message);
1355 if (!reply)
1356 goto oom;
1357
88e3dc90
LP
1358 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSession") ||
1359 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "UnlockSession")) {
1360 const char *name;
1361 Session *session;
1362
1363 if (!dbus_message_get_args(
1364 message,
1365 &error,
1366 DBUS_TYPE_STRING, &name,
1367 DBUS_TYPE_INVALID))
1368 return bus_send_error_reply(connection, message, &error, -EINVAL);
1369
1370 session = hashmap_get(m->sessions, name);
1371 if (!session)
1372 return bus_send_error_reply(connection, message, &error, -ENOENT);
1373
1374 if (session_send_lock(session, streq(dbus_message_get_member(message), "LockSession")) < 0)
1375 goto oom;
1376
1377 reply = dbus_message_new_method_return(message);
1378 if (!reply)
1379 goto oom;
1380
de07ab16
LP
1381 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
1382 const char *swho;
1383 int32_t signo;
1384 KillWho who;
1385 const char *name;
1386 Session *session;
1387
1388 if (!dbus_message_get_args(
1389 message,
1390 &error,
1391 DBUS_TYPE_STRING, &name,
1392 DBUS_TYPE_STRING, &swho,
1393 DBUS_TYPE_INT32, &signo,
1394 DBUS_TYPE_INVALID))
1395 return bus_send_error_reply(connection, message, &error, -EINVAL);
1396
1397 if (isempty(swho))
1398 who = KILL_ALL;
1399 else {
1400 who = kill_who_from_string(swho);
1401 if (who < 0)
1402 return bus_send_error_reply(connection, message, &error, -EINVAL);
1403 }
1404
1405 if (signo <= 0 || signo >= _NSIG)
1406 return bus_send_error_reply(connection, message, &error, -EINVAL);
1407
1408 session = hashmap_get(m->sessions, name);
1409 if (!session)
1410 return bus_send_error_reply(connection, message, &error, -ENOENT);
1411
1412 r = session_kill(session, who, signo);
1413 if (r < 0)
1414 return bus_send_error_reply(connection, message, NULL, r);
1415
1416 reply = dbus_message_new_method_return(message);
1417 if (!reply)
1418 goto oom;
1419
1420 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillUser")) {
1421 uint32_t uid;
1422 User *user;
1423 int32_t signo;
1424
1425 if (!dbus_message_get_args(
1426 message,
1427 &error,
1428 DBUS_TYPE_UINT32, &uid,
1429 DBUS_TYPE_INT32, &signo,
1430 DBUS_TYPE_INVALID))
1431 return bus_send_error_reply(connection, message, &error, -EINVAL);
1432
1433 if (signo <= 0 || signo >= _NSIG)
1434 return bus_send_error_reply(connection, message, &error, -EINVAL);
1435
1436 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1437 if (!user)
1438 return bus_send_error_reply(connection, message, &error, -ENOENT);
1439
1440 r = user_kill(user, signo);
1441 if (r < 0)
1442 return bus_send_error_reply(connection, message, NULL, r);
1443
1444 reply = dbus_message_new_method_return(message);
1445 if (!reply)
1446 goto oom;
1447
bef422ae
LP
1448 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSession")) {
1449 const char *name;
1450 Session *session;
1451
1452 if (!dbus_message_get_args(
1453 message,
1454 &error,
1455 DBUS_TYPE_STRING, &name,
1456 DBUS_TYPE_INVALID))
1457 return bus_send_error_reply(connection, message, &error, -EINVAL);
1458
1459 session = hashmap_get(m->sessions, name);
1460 if (!session)
1461 return bus_send_error_reply(connection, message, &error, -ENOENT);
1462
1463 r = session_stop(session);
1464 if (r < 0)
1465 return bus_send_error_reply(connection, message, NULL, r);
1466
1467 reply = dbus_message_new_method_return(message);
1468 if (!reply)
1469 goto oom;
1470
1471 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateUser")) {
1472 uint32_t uid;
1473 User *user;
1474
1475 if (!dbus_message_get_args(
1476 message,
1477 &error,
1478 DBUS_TYPE_UINT32, &uid,
1479 DBUS_TYPE_INVALID))
1480 return bus_send_error_reply(connection, message, &error, -EINVAL);
1481
1482 user = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1483 if (!user)
1484 return bus_send_error_reply(connection, message, &error, -ENOENT);
1485
1486 r = user_stop(user);
1487 if (r < 0)
1488 return bus_send_error_reply(connection, message, NULL, r);
1489
1490 reply = dbus_message_new_method_return(message);
1491 if (!reply)
1492 goto oom;
1493
1494 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "TerminateSeat")) {
1495 const char *name;
1496 Seat *seat;
1497
1498 if (!dbus_message_get_args(
1499 message,
1500 &error,
1501 DBUS_TYPE_STRING, &name,
1502 DBUS_TYPE_INVALID))
1503 return bus_send_error_reply(connection, message, &error, -EINVAL);
1504
1505 seat = hashmap_get(m->seats, name);
1506 if (!seat)
1507 return bus_send_error_reply(connection, message, &error, -ENOENT);
1508
1509 r = seat_stop_sessions(seat);
1510 if (r < 0)
1511 return bus_send_error_reply(connection, message, NULL, r);
1512
1513 reply = dbus_message_new_method_return(message);
1514 if (!reply)
1515 goto oom;
1516
7f7bb946
LP
1517 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "SetUserLinger")) {
1518 uint32_t uid;
1519 struct passwd *pw;
1520 dbus_bool_t b, interactive;
1521 char *path;
1522
1523 if (!dbus_message_get_args(
1524 message,
1525 &error,
1526 DBUS_TYPE_UINT32, &uid,
1527 DBUS_TYPE_BOOLEAN, &b,
1528 DBUS_TYPE_BOOLEAN, &interactive,
1529 DBUS_TYPE_INVALID))
1530 return bus_send_error_reply(connection, message, &error, -EINVAL);
1531
1532 errno = 0;
1533 pw = getpwuid(uid);
1534 if (!pw)
1535 return bus_send_error_reply(connection, message, NULL, errno ? -errno : -EINVAL);
1536
89f13440 1537 r = verify_polkit(connection, message, "org.freedesktop.login1.set-user-linger", interactive, NULL, &error);
7f7bb946
LP
1538 if (r < 0)
1539 return bus_send_error_reply(connection, message, &error, r);
1540
02b16a19
LP
1541 mkdir_p("/var/lib/systemd", 0755);
1542
7f7bb946
LP
1543 r = safe_mkdir("/var/lib/systemd/linger", 0755, 0, 0);
1544 if (r < 0)
1545 return bus_send_error_reply(connection, message, &error, r);
1546
1547 path = strappend("/var/lib/systemd/linger/", pw->pw_name);
1548 if (!path)
1549 goto oom;
1550
1551 if (b) {
38f3fc7d
LP
1552 User *u;
1553
7f7bb946
LP
1554 r = touch(path);
1555 free(path);
1556
1557 if (r < 0)
1558 return bus_send_error_reply(connection, message, &error, r);
38f3fc7d
LP
1559
1560 if (manager_add_user_by_uid(m, uid, &u) >= 0)
1561 user_start(u);
1562
7f7bb946 1563 } else {
38f3fc7d
LP
1564 User *u;
1565
7f7bb946
LP
1566 r = unlink(path);
1567 free(path);
1568
1569 if (r < 0 && errno != ENOENT)
1570 return bus_send_error_reply(connection, message, &error, -errno);
38f3fc7d
LP
1571
1572 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
1573 if (u)
1574 user_add_to_gc_queue(u);
7f7bb946
LP
1575 }
1576
1577 reply = dbus_message_new_method_return(message);
1578 if (!reply)
1579 goto oom;
1580
47a26690
LP
1581 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "AttachDevice")) {
1582 const char *sysfs, *seat;
1583 dbus_bool_t interactive;
1584
1585 if (!dbus_message_get_args(
1586 message,
1587 &error,
1588 DBUS_TYPE_STRING, &seat,
1589 DBUS_TYPE_STRING, &sysfs,
1590 DBUS_TYPE_BOOLEAN, &interactive,
1591 DBUS_TYPE_INVALID))
1592 return bus_send_error_reply(connection, message, &error, -EINVAL);
1593
1594 if (!path_startswith(sysfs, "/sys") || !seat_name_is_valid(seat))
1595 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1596
89f13440 1597 r = verify_polkit(connection, message, "org.freedesktop.login1.attach-device", interactive, NULL, &error);
47a26690
LP
1598 if (r < 0)
1599 return bus_send_error_reply(connection, message, &error, r);
1600
1601 r = attach_device(m, seat, sysfs);
1602 if (r < 0)
1603 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1604
1605 reply = dbus_message_new_method_return(message);
1606 if (!reply)
1607 goto oom;
7f7bb946 1608
b668e064
LP
1609
1610 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "FlushDevices")) {
1611 dbus_bool_t interactive;
1612
1613 if (!dbus_message_get_args(
1614 message,
1615 &error,
1616 DBUS_TYPE_BOOLEAN, &interactive,
1617 DBUS_TYPE_INVALID))
1618 return bus_send_error_reply(connection, message, &error, -EINVAL);
1619
89f13440 1620 r = verify_polkit(connection, message, "org.freedesktop.login1.flush-devices", interactive, NULL, &error);
b668e064
LP
1621 if (r < 0)
1622 return bus_send_error_reply(connection, message, &error, r);
1623
1624 r = flush_devices(m);
1625 if (r < 0)
1626 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1627
1628 reply = dbus_message_new_method_return(message);
1629 if (!reply)
1630 goto oom;
1631
55af3897
LP
1632 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "PowerOff") ||
1633 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "Reboot")) {
1634 dbus_bool_t interactive;
f8e2fb7b 1635 bool multiple_sessions, inhibit;
55af3897 1636 DBusMessage *forward, *freply;
f8e2fb7b 1637 const char *name, *action;
55af3897 1638 const char *mode = "replace";
55af3897
LP
1639
1640 if (!dbus_message_get_args(
1641 message,
1642 &error,
1643 DBUS_TYPE_BOOLEAN, &interactive,
1644 DBUS_TYPE_INVALID))
1645 return bus_send_error_reply(connection, message, &error, -EINVAL);
1646
89f13440
LP
1647 r = have_multiple_sessions(connection, m, message, &error);
1648 if (r < 0)
1649 return bus_send_error_reply(connection, message, &error, r);
55af3897 1650
89f13440 1651 multiple_sessions = r > 0;
c7b5eb98 1652 inhibit = manager_is_inhibited(m, INHIBIT_SHUTDOWN, NULL);
55af3897 1653
f8e2fb7b
LP
1654 if (multiple_sessions) {
1655 action = streq(dbus_message_get_member(message), "PowerOff") ?
1656 "org.freedesktop.login1.power-off-multiple-sessions" :
1657 "org.freedesktop.login1.reboot-multiple-sessions";
55af3897 1658
f8e2fb7b
LP
1659 r = verify_polkit(connection, message, action, interactive, NULL, &error);
1660 if (r < 0)
1661 return bus_send_error_reply(connection, message, &error, r);
1662 }
1663
1664 if (inhibit) {
1665 action = streq(dbus_message_get_member(message), "PowerOff") ?
1666 "org.freedesktop.login1.power-off-ignore-inhibit" :
1667 "org.freedesktop.login1.reboot-ignore-inhibit";
55af3897 1668
f8e2fb7b
LP
1669 r = verify_polkit(connection, message, action, interactive, NULL, &error);
1670 if (r < 0)
1671 return bus_send_error_reply(connection, message, &error, r);
55af3897
LP
1672 }
1673
f8e2fb7b
LP
1674 if (!multiple_sessions && !inhibit) {
1675 action = streq(dbus_message_get_member(message), "PowerOff") ?
1676 "org.freedesktop.login1.power-off" :
1677 "org.freedesktop.login1.reboot";
1678
1679 r = verify_polkit(connection, message, action, interactive, NULL, &error);
1680 if (r < 0)
1681 return bus_send_error_reply(connection, message, &error, r);
1682 }
55af3897
LP
1683
1684 forward = dbus_message_new_method_call(
1685 "org.freedesktop.systemd1",
1686 "/org/freedesktop/systemd1",
1687 "org.freedesktop.systemd1.Manager",
1688 "StartUnit");
1689 if (!forward)
1690 return bus_send_error_reply(connection, message, NULL, -ENOMEM);
1691
f8e2fb7b
LP
1692 name = streq(dbus_message_get_member(message), "PowerOff") ?
1693 SPECIAL_POWEROFF_TARGET : SPECIAL_REBOOT_TARGET;
1694
55af3897
LP
1695 if (!dbus_message_append_args(forward,
1696 DBUS_TYPE_STRING, &name,
1697 DBUS_TYPE_STRING, &mode,
1698 DBUS_TYPE_INVALID)) {
1699 dbus_message_unref(forward);
1700 return bus_send_error_reply(connection, message, NULL, -ENOMEM);
1701 }
1702
1703 freply = dbus_connection_send_with_reply_and_block(connection, forward, -1, &error);
1704 dbus_message_unref(forward);
1705
1706 if (!freply)
1707 return bus_send_error_reply(connection, message, &error, -EIO);
1708
1709 dbus_message_unref(freply);
1710
1711 reply = dbus_message_new_method_return(message);
1712 if (!reply)
1713 goto oom;
1714
89f13440
LP
1715 } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanPowerOff") ||
1716 dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanReboot")) {
1717
f8e2fb7b
LP
1718 bool multiple_sessions, challenge, inhibit, b;
1719 const char *action, *result;
89f13440
LP
1720
1721 r = have_multiple_sessions(connection, m, message, &error);
1722 if (r < 0)
1723 return bus_send_error_reply(connection, message, &error, r);
1724
1725 multiple_sessions = r > 0;
c7b5eb98 1726 inhibit = manager_is_inhibited(m, INHIBIT_SHUTDOWN, NULL);
f8e2fb7b
LP
1727
1728 if (multiple_sessions) {
1729 action = streq(dbus_message_get_member(message), "CanPowerOff") ?
1730 "org.freedesktop.login1.power-off-multiple-sessions" :
1731 "org.freedesktop.login1.reboot-multiple-sessions";
89f13440 1732
f8e2fb7b
LP
1733 r = verify_polkit(connection, message, action, false, &challenge, &error);
1734 if (r < 0)
1735 return bus_send_error_reply(connection, message, &error, r);
1736
1737 if (r > 0)
1738 result = "yes";
1739 else if (challenge)
1740 result = "challenge";
89f13440 1741 else
f8e2fb7b
LP
1742 result = "no";
1743 }
89f13440 1744
f8e2fb7b
LP
1745 if (inhibit) {
1746 action = streq(dbus_message_get_member(message), "CanPowerOff") ?
1747 "org.freedesktop.login1.power-off-ignore-inhibit" :
1748 "org.freedesktop.login1.reboot-ignore-inhibit";
1749
1750 r = verify_polkit(connection, message, action, false, &challenge, &error);
1751 if (r < 0)
1752 return bus_send_error_reply(connection, message, &error, r);
1753
1754 if (r > 0 && !result)
1755 result = "yes";
1756 else if (challenge && (!result || streq(result, "yes")))
1757 result = "challenge";
89f13440 1758 else
f8e2fb7b 1759 result = "no";
89f13440
LP
1760 }
1761
f8e2fb7b
LP
1762 if (!multiple_sessions && !inhibit) {
1763 /* If neither inhibit nor multiple sessions
1764 * apply then just check the normal policy */
1765
1766 action = streq(dbus_message_get_member(message), "CanPowerOff") ?
1767 "org.freedesktop.login1.power-off" :
1768 "org.freedesktop.login1.reboot";
1769
1770 r = verify_polkit(connection, message, action, false, &challenge, &error);
1771 if (r < 0)
1772 return bus_send_error_reply(connection, message, &error, r);
1773
1774 if (r > 0)
1775 result = "yes";
1776 else if (challenge)
1777 result = "challenge";
1778 else
1779 result = "no";
1780 }
89f13440
LP
1781
1782 reply = dbus_message_new_method_return(message);
1783 if (!reply)
1784 goto oom;
1785
89f13440
LP
1786 b = dbus_message_append_args(
1787 reply,
f8e2fb7b 1788 DBUS_TYPE_STRING, &result,
89f13440
LP
1789 DBUS_TYPE_INVALID);
1790 if (!b)
1791 goto oom;
1792
bef422ae 1793 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
3f49d45a
LP
1794 char *introspection = NULL;
1795 FILE *f;
1796 Iterator i;
1797 Session *session;
1798 Seat *seat;
1799 User *user;
1800 size_t size;
1801 char *p;
1802
1803 if (!(reply = dbus_message_new_method_return(message)))
1804 goto oom;
1805
1806 /* We roll our own introspection code here, instead of
1807 * relying on bus_default_message_handler() because we
1808 * need to generate our introspection string
1809 * dynamically. */
1810
1811 if (!(f = open_memstream(&introspection, &size)))
1812 goto oom;
1813
1814 fputs(INTROSPECTION_BEGIN, f);
1815
1816 HASHMAP_FOREACH(seat, m->seats, i) {
1817 p = bus_path_escape(seat->id);
1818
1819 if (p) {
1820 fprintf(f, "<node name=\"seat/%s\"/>", p);
1821 free(p);
1822 }
1823 }
1824
1825 HASHMAP_FOREACH(user, m->users, i)
1826 fprintf(f, "<node name=\"user/%llu\"/>", (unsigned long long) user->uid);
1827
1828 HASHMAP_FOREACH(session, m->sessions, i) {
1829 p = bus_path_escape(session->id);
1830
1831 if (p) {
1832 fprintf(f, "<node name=\"session/%s\"/>", p);
1833 free(p);
1834 }
1835 }
1836
1837 fputs(INTROSPECTION_END, f);
1838
1839 if (ferror(f)) {
1840 fclose(f);
1841 free(introspection);
1842 goto oom;
1843 }
1844
1845 fclose(f);
1846
1847 if (!introspection)
1848 goto oom;
1849
1850 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
1851 free(introspection);
1852 goto oom;
1853 }
1854
1855 free(introspection);
d200735e
MS
1856 } else {
1857 const BusBoundProperties bps[] = {
1858 { "org.freedesktop.login1.Manager", bus_login_manager_properties, m },
1859 { NULL, }
1860 };
1861 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
1862 }
3f49d45a
LP
1863
1864 if (reply) {
1865 if (!dbus_connection_send(connection, reply, NULL))
1866 goto oom;
1867
1868 dbus_message_unref(reply);
1869 }
1870
1871 return DBUS_HANDLER_RESULT_HANDLED;
1872
1873oom:
1874 if (reply)
1875 dbus_message_unref(reply);
1876
1877 dbus_error_free(&error);
1878
1879 return DBUS_HANDLER_RESULT_NEED_MEMORY;
1880}
1881
1882const DBusObjectPathVTable bus_manager_vtable = {
1883 .message_function = manager_message_handler
1884};
9418f147 1885
1713813d
LP
1886DBusHandlerResult bus_message_filter(
1887 DBusConnection *connection,
1888 DBusMessage *message,
1889 void *userdata) {
1890
1891 Manager *m = userdata;
1892 DBusError error;
1893
1894 assert(m);
1895 assert(connection);
1896 assert(message);
1897
1898 dbus_error_init(&error);
1899
1900 if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
1901 const char *cgroup;
1902
1903 if (!dbus_message_get_args(message, &error,
1904 DBUS_TYPE_STRING, &cgroup,
1905 DBUS_TYPE_INVALID))
1906 log_error("Failed to parse Released message: %s", bus_error_message(&error));
1907 else
1908 manager_cgroup_notify_empty(m, cgroup);
1909 }
1910
1911 dbus_error_free(&error);
1912
1913 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1914}
1915
9418f147
LP
1916int manager_send_changed(Manager *manager, const char *properties) {
1917 DBusMessage *m;
1918 int r = -ENOMEM;
1919
1920 assert(manager);
1921
1922 m = bus_properties_changed_new("/org/freedesktop/login1", "org.freedesktop.login1.Manager", properties);
1923 if (!m)
1924 goto finish;
1925
1926 if (!dbus_connection_send(manager->bus, m, NULL))
1927 goto finish;
1928
1929 r = 0;
1930
1931finish:
1932 if (m)
1933 dbus_message_unref(m);
1934
1935 return r;
1936}