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