]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/dbus.c
sd-bus: introduce sd_bus_slot objects encapsulating callbacks or vtables attached...
[thirdparty/systemd.git] / src / core / dbus.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
ea430986 2
a7334b09
LP
3/***
4 This file is part of systemd.
5
6 Copyright 2010 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
a7334b09
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.
a7334b09 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
a7334b09
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
ea430986
LP
22#include <sys/epoll.h>
23#include <sys/timerfd.h>
24#include <errno.h>
25#include <unistd.h>
26
718db961 27#include "sd-bus.h"
ea430986
LP
28#include "log.h"
29#include "strv.h"
49e942b2 30#include "mkdir.h"
4db17f29 31#include "missing.h"
4139c1b2
LP
32#include "dbus-unit.h"
33#include "dbus-job.h"
34#include "dbus-manager.h"
718db961
LP
35#include "dbus-execute.h"
36#include "dbus-kill.h"
37#include "dbus-cgroup.h"
8f6df3fa 38#include "special.h"
718db961
LP
39#include "dbus.h"
40#include "bus-util.h"
41#include "bus-error.h"
42#include "bus-errors.h"
43#include "strxcpyx.h"
969987ea
LP
44#include "bus-internal.h"
45#include "selinux-access.h"
4288f619 46
417b1a62 47#define CONNECTIONS_MAX 512
5e8d1c9a 48
718db961
LP
49static void destroy_bus(Manager *m, sd_bus **bus);
50
51int bus_send_queued_message(Manager *m) {
52 int r;
8e274523 53
8e274523 54 assert(m);
2e317f52 55
718db961
LP
56 if (!m->queued_message)
57 return 0;
8e274523 58
718db961 59 assert(m->queued_message_bus);
8e274523 60
718db961
LP
61 /* If we cannot get rid of this message we won't dispatch any
62 * D-Bus messages, so that we won't end up wanting to queue
63 * another message. */
ea430986 64
718db961
LP
65 r = sd_bus_send(m->queued_message_bus, m->queued_message, NULL);
66 if (r < 0)
67 log_warning("Failed to send queued message: %s", strerror(-r));
ea430986 68
718db961
LP
69 m->queued_message = sd_bus_message_unref(m->queued_message);
70 m->queued_message_bus = sd_bus_unref(m->queued_message_bus);
ea430986 71
718db961 72 return 0;
ea430986
LP
73}
74
ebcf1f97 75static int signal_agent_released(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961
LP
76 Manager *m = userdata;
77 const char *cgroup;
78 int r;
ea430986 79
718db961
LP
80 assert(bus);
81 assert(message);
ea430986
LP
82 assert(m);
83
718db961
LP
84 r = sd_bus_message_read(message, "s", &cgroup);
85 if (r < 0) {
86 bus_log_parse_error(r);
87 return 0;
88 }
ea430986 89
718db961 90 manager_notify_cgroup_empty(m, cgroup);
ea430986 91
718db961
LP
92 if (m->running_as == SYSTEMD_SYSTEM && m->system_bus) {
93 /* If we are running as system manager, forward the
94 * message to the system bus */
ea430986 95
718db961
LP
96 r = sd_bus_send(m->system_bus, message, NULL);
97 if (r < 0)
98 log_warning("Failed to forward Released message: %s", strerror(-r));
99 }
ea430986 100
718db961
LP
101 return 0;
102}
ea430986 103
ebcf1f97 104static int signal_disconnected(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961 105 Manager *m = userdata;
ea430986 106
718db961
LP
107 assert(bus);
108 assert(message);
109 assert(m);
ea430986 110
718db961
LP
111 if (bus == m->api_bus)
112 destroy_bus(m, &m->api_bus);
113 if (bus == m->system_bus)
114 destroy_bus(m, &m->system_bus);
115 if (set_remove(m->private_buses, bus)) {
116 log_debug("Got disconnect on private connection.");
117 destroy_bus(m, &bus);
ea430986
LP
118 }
119
718db961 120 return 0;
ea430986
LP
121}
122
ebcf1f97 123static int signal_name_owner_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961
LP
124 const char *name, *old_owner, *new_owner;
125 Manager *m = userdata;
126 int r;
ea430986 127
718db961
LP
128 assert(bus);
129 assert(message);
ea430986
LP
130 assert(m);
131
718db961
LP
132 r = sd_bus_message_read(message, "sss", &name, &old_owner, &new_owner);
133 if (r < 0) {
134 bus_log_parse_error(r);
135 return 0;
136 }
ea430986 137
718db961
LP
138 manager_dispatch_bus_name_owner_changed(
139 m, name,
140 isempty(old_owner) ? NULL : old_owner,
141 isempty(new_owner) ? NULL : new_owner);
ea430986 142
718db961 143 return 0;
ea430986
LP
144}
145
ebcf1f97 146static int signal_activation_request(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
718db961
LP
147 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
148 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
149 Manager *m = userdata;
150 const char *name;
151 Unit *u;
152 int r;
ea430986 153
718db961
LP
154 assert(bus);
155 assert(message);
ea430986
LP
156 assert(m);
157
718db961
LP
158 r = sd_bus_message_read(message, "s", &name);
159 if (r < 0) {
160 bus_log_parse_error(r);
161 return 0;
162 }
ea430986 163
718db961
LP
164 if (manager_unit_inactive_or_pending(m, SPECIAL_DBUS_SERVICE) ||
165 manager_unit_inactive_or_pending(m, SPECIAL_DBUS_SOCKET)) {
166 r = sd_bus_error_setf(&error, BUS_ERROR_SHUTTING_DOWN, "Refusing activation, D-Bus is shutting down.");
167 goto failed;
168 }
ea430986 169
718db961
LP
170 r = manager_load_unit(m, name, NULL, &error, &u);
171 if (r < 0)
172 goto failed;
ea430986 173
718db961 174 if (u->refuse_manual_start) {
d14ab08b 175 r = sd_bus_error_setf(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, %s may be requested by dependency only.", u->id);
718db961 176 goto failed;
ea430986
LP
177 }
178
718db961
LP
179 r = manager_add_job(m, JOB_START, u, JOB_REPLACE, true, &error, NULL);
180 if (r < 0)
181 goto failed;
ea430986 182
718db961 183 /* Successfully queued, that's it for us */
ea430986 184 return 0;
ea430986 185
718db961
LP
186failed:
187 if (!sd_bus_error_is_set(&error))
188 sd_bus_error_set_errno(&error, r);
ea430986 189
718db961 190 log_debug("D-Bus activation failed for %s: %s", name, bus_error_message(&error, r));
ea430986 191
151b9b96 192 r = sd_bus_message_new_signal(bus, &reply, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Activator", "ActivationFailure");
718db961
LP
193 if (r < 0) {
194 bus_log_create_error(r);
195 return 0;
196 }
197
fa0fed49 198 r = sd_bus_message_append(reply, "sss", name, error.name, error.message);
718db961
LP
199 if (r < 0) {
200 bus_log_create_error(r);
201 return 0;
202 }
203
204 r = sd_bus_send_to(bus, reply, "org.freedesktop.DBus", NULL);
205 if (r < 0) {
206 log_error("Failed to respond with to bus activation request: %s", strerror(-r));
207 return r;
208 }
ea430986 209
718db961 210 return 0;
ea430986
LP
211}
212
ad5b215d 213#ifdef HAVE_SELINUX
969987ea
LP
214static int selinux_filter(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
215 Manager *m = userdata;
216 const char *verb, *path;
217 Unit *u = NULL;
218 Job *j;
219 int r;
220
221 assert(bus);
222 assert(message);
223
224 /* Our own method calls are all protected individually with
225 * selinux checks, but the built-in interfaces need to be
226 * protected too. */
227
228 if (sd_bus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Set"))
229 verb = "reload";
230 else if (sd_bus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", NULL) ||
231 sd_bus_message_is_method_call(message, "org.freedesktop.DBus.Properties", NULL) ||
232 sd_bus_message_is_method_call(message, "org.freedesktop.DBus.ObjectManager", NULL) ||
233 sd_bus_message_is_method_call(message, "org.freedesktop.DBus.Peer", NULL))
234 verb = "status";
235 else
236 return 0;
237
238 path = sd_bus_message_get_path(message);
239
240 if (object_path_startswith("/org/freedesktop/systemd1", path)) {
241
4f4f7036 242 r = selinux_access_check(message, verb, error);
969987ea
LP
243 if (r < 0)
244 return r;
245
246 return 0;
247 }
248
249 if (streq_ptr(path, "/org/freedesktop/systemd1/unit/self")) {
5b12334d 250 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
969987ea
LP
251 pid_t pid;
252
5b12334d
LP
253 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
254 if (r < 0)
255 return 0;
256
257 r = sd_bus_creds_get_pid(creds, &pid);
969987ea
LP
258 if (r < 0)
259 return 0;
260
261 u = manager_get_unit_by_pid(m, pid);
262 } else {
263 r = manager_get_job_from_dbus_path(m, path, &j);
264 if (r >= 0)
265 u = j->unit;
266 else
267 manager_load_unit_from_dbus_path(m, path, NULL, &u);
268 }
269
270 if (!u)
271 return 0;
272
4f4f7036 273 r = selinux_unit_access_check(u, message, verb, error);
969987ea
LP
274 if (r < 0)
275 return r;
276
277 return 0;
278}
ad5b215d 279#endif
969987ea 280
f00c3121 281static int bus_job_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
718db961
LP
282 Manager *m = userdata;
283 Job *j;
284 int r;
ea430986 285
718db961
LP
286 assert(bus);
287 assert(path);
288 assert(interface);
289 assert(found);
ea430986
LP
290 assert(m);
291
718db961
LP
292 r = manager_get_job_from_dbus_path(m, path, &j);
293 if (r < 0)
294 return 0;
ea430986 295
718db961
LP
296 *found = j;
297 return 1;
298}
ea430986 299
f00c3121 300static int find_unit(Manager *m, sd_bus *bus, const char *path, Unit **unit, sd_bus_error *error) {
718db961
LP
301 Unit *u;
302 int r;
ea430986 303
718db961
LP
304 assert(m);
305 assert(bus);
306 assert(path);
ea430986 307
718db961 308 if (streq_ptr(path, "/org/freedesktop/systemd1/unit/self")) {
5b12334d 309 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
718db961
LP
310 sd_bus_message *message;
311 pid_t pid;
ea430986 312
19befb2d 313 message = sd_bus_get_current_message(bus);
718db961 314 if (!message)
f00c3121 315 return 0;
ea430986 316
5b12334d 317 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
718db961 318 if (r < 0)
5b12334d
LP
319 return r;
320
321 r = sd_bus_creds_get_pid(creds, &pid);
322 if (r < 0)
323 return r;
ea430986 324
718db961
LP
325 u = manager_get_unit_by_pid(m, pid);
326 } else {
f00c3121 327 r = manager_load_unit_from_dbus_path(m, path, error, &u);
718db961 328 if (r < 0)
f00c3121 329 return 0;
718db961 330 }
ea430986 331
f00c3121
LP
332 if (!u)
333 return 0;
334
335 *unit = u;
336 return 1;
ea430986
LP
337}
338
f00c3121 339static int bus_unit_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
718db961 340 Manager *m = userdata;
ea430986 341
718db961
LP
342 assert(bus);
343 assert(path);
344 assert(interface);
345 assert(found);
ea430986
LP
346 assert(m);
347
f00c3121 348 return find_unit(m, bus, path, (Unit**) found, error);
ea430986
LP
349}
350
f00c3121 351static int bus_unit_interface_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
718db961
LP
352 Manager *m = userdata;
353 Unit *u;
f00c3121 354 int r;
ea430986 355
718db961
LP
356 assert(bus);
357 assert(path);
358 assert(interface);
359 assert(found);
ea430986
LP
360 assert(m);
361
f00c3121
LP
362 r = find_unit(m, bus, path, &u, error);
363 if (r <= 0)
364 return r;
3df5bf61 365
718db961
LP
366 if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface))
367 return 0;
ea430986 368
718db961
LP
369 *found = u;
370 return 1;
ea430986
LP
371}
372
f00c3121 373static int bus_unit_cgroup_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
718db961
LP
374 Manager *m = userdata;
375 Unit *u;
f00c3121 376 int r;
c1e1601e 377
718db961
LP
378 assert(bus);
379 assert(path);
380 assert(interface);
381 assert(found);
c1e1601e
LP
382 assert(m);
383
f00c3121
LP
384 r = find_unit(m, bus, path, &u, error);
385 if (r <= 0)
386 return r;
05e343b7 387
718db961
LP
388 if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface))
389 return 0;
05e343b7 390
718db961
LP
391 if (!unit_get_cgroup_context(u))
392 return 0;
0034c15c 393
718db961
LP
394 *found = u;
395 return 1;
396}
0034c15c 397
f00c3121 398static int bus_cgroup_context_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
718db961
LP
399 Manager *m = userdata;
400 CGroupContext *c;
401 Unit *u;
f00c3121 402 int r;
af25ec12 403
718db961
LP
404 assert(bus);
405 assert(path);
406 assert(interface);
407 assert(found);
408 assert(m);
0034c15c 409
f00c3121
LP
410 r = find_unit(m, bus, path, &u, error);
411 if (r <= 0)
412 return r;
0034c15c 413
718db961
LP
414 if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface))
415 return 0;
0034c15c 416
718db961
LP
417 c = unit_get_cgroup_context(u);
418 if (!c)
419 return 0;
c1e1601e 420
718db961
LP
421 *found = c;
422 return 1;
423}
0034c15c 424
f00c3121 425static int bus_exec_context_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
718db961
LP
426 Manager *m = userdata;
427 ExecContext *c;
428 Unit *u;
f00c3121 429 int r;
0034c15c 430
718db961
LP
431 assert(bus);
432 assert(path);
433 assert(interface);
434 assert(found);
435 assert(m);
0034c15c 436
f00c3121
LP
437 r = find_unit(m, bus, path, &u, error);
438 if (r <= 0)
439 return r;
0034c15c 440
718db961
LP
441 if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface))
442 return 0;
0034c15c 443
718db961
LP
444 c = unit_get_exec_context(u);
445 if (!c)
446 return 0;
0034c15c 447
718db961
LP
448 *found = c;
449 return 1;
c1e1601e
LP
450}
451
f00c3121 452static int bus_kill_context_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
718db961
LP
453 Manager *m = userdata;
454 KillContext *c;
455 Unit *u;
f00c3121 456 int r;
8e274523 457
718db961
LP
458 assert(bus);
459 assert(path);
460 assert(interface);
461 assert(found);
8e274523
LP
462 assert(m);
463
f00c3121
LP
464 r = find_unit(m, bus, path, &u, error);
465 if (r <= 0)
466 return r;
8e274523 467
718db961
LP
468 if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface))
469 return 0;
8e274523 470
718db961
LP
471 c = unit_get_kill_context(u);
472 if (!c)
473 return 0;
53c6a358 474
718db961
LP
475 *found = c;
476 return 1;
477}
8e274523 478
f00c3121 479static int bus_job_enumerate(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
718db961
LP
480 _cleanup_free_ char **l = NULL;
481 Manager *m = userdata;
482 unsigned k = 0;
483 Iterator i;
484 Job *j;
8e274523 485
718db961
LP
486 l = new0(char*, hashmap_size(m->jobs)+1);
487 if (!l)
488 return -ENOMEM;
8e274523 489
718db961
LP
490 HASHMAP_FOREACH(j, m->jobs, i) {
491 l[k] = job_dbus_path(j);
492 if (!l[k])
493 return -ENOMEM;
5e8d1c9a 494
718db961
LP
495 k++;
496 }
5e8d1c9a 497
718db961 498 assert(hashmap_size(m->jobs) == k);
3c661fad 499
718db961
LP
500 *nodes = l;
501 l = NULL;
5e8d1c9a 502
718db961
LP
503 return k;
504}
53c6a358 505
f00c3121 506static int bus_unit_enumerate(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
718db961
LP
507 _cleanup_free_ char **l = NULL;
508 Manager *m = userdata;
509 unsigned k = 0;
510 Iterator i;
511 Unit *u;
3c661fad 512
718db961
LP
513 l = new0(char*, hashmap_size(m->units)+1);
514 if (!l)
515 return -ENOMEM;
53c6a358 516
718db961
LP
517 HASHMAP_FOREACH(u, m->units, i) {
518 l[k] = unit_dbus_path(u);
519 if (!l[k])
520 return -ENOMEM;
53c6a358 521
718db961 522 k++;
3c661fad
LP
523 }
524
718db961
LP
525 *nodes = l;
526 l = NULL;
5e8d1c9a 527
718db961 528 return k;
5e8d1c9a
LP
529}
530
718db961
LP
531static int bus_setup_api_vtables(Manager *m, sd_bus *bus) {
532 UnitType t;
533 int r;
5e8d1c9a 534
ea430986 535 assert(m);
718db961 536 assert(bus);
ea430986 537
ad5b215d 538#ifdef HAVE_SELINUX
19befb2d 539 r = sd_bus_add_filter(bus, NULL, selinux_filter, m);
969987ea
LP
540 if (r < 0) {
541 log_error("Failed to add SELinux access filter: %s", strerror(-r));
542 return r;
543 }
ad5b215d 544#endif
969987ea 545
19befb2d 546 r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", bus_manager_vtable, m);
718db961
LP
547 if (r < 0) {
548 log_error("Failed to register Manager vtable: %s", strerror(-r));
549 return r;
a16e1123
LP
550 }
551
19befb2d 552 r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/job", "org.freedesktop.systemd1.Job", bus_job_vtable, bus_job_find, m);
718db961
LP
553 if (r < 0) {
554 log_error("Failed to register Job vtable: %s", strerror(-r));
555 return r;
fd18e1f4 556 }
c1e1601e 557
19befb2d 558 r = sd_bus_add_node_enumerator(bus, NULL, "/org/freedesktop/systemd1/job", bus_job_enumerate, m);
718db961
LP
559 if (r < 0) {
560 log_error("Failed to add job enumerator: %s", strerror(-r));
561 return r;
562 }
61902ea3 563
19befb2d 564 r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", "org.freedesktop.systemd1.Unit", bus_unit_vtable, bus_unit_find, m);
718db961
LP
565 if (r < 0) {
566 log_error("Failed to register Unit vtable: %s", strerror(-r));
567 return r;
568 }
61902ea3 569
19befb2d 570 r = sd_bus_add_node_enumerator(bus, NULL, "/org/freedesktop/systemd1/unit", bus_unit_enumerate, m);
718db961
LP
571 if (r < 0) {
572 log_error("Failed to add job enumerator: %s", strerror(-r));
573 return r;
574 }
61902ea3 575
718db961 576 for (t = 0; t < _UNIT_TYPE_MAX; t++) {
19befb2d 577 r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, unit_vtable[t]->bus_vtable, bus_unit_interface_find, m);
718db961
LP
578 if (r < 0) {
579 log_error("Failed to register type specific vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r));
580 return r;
581 }
61902ea3 582
718db961 583 if (unit_vtable[t]->cgroup_context_offset > 0) {
19befb2d 584 r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_unit_cgroup_vtable, bus_unit_cgroup_find, m);
718db961
LP
585 if (r < 0) {
586 log_error("Failed to register control group unit vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r));
587 return r;
588 }
61902ea3 589
19befb2d 590 r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_cgroup_vtable, bus_cgroup_context_find, m);
718db961
LP
591 if (r < 0) {
592 log_error("Failed to register control group vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r));
593 return r;
594 }
61902ea3
LP
595 }
596
718db961 597 if (unit_vtable[t]->exec_context_offset > 0) {
19befb2d 598 r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_exec_vtable, bus_exec_context_find, m);
718db961
LP
599 if (r < 0) {
600 log_error("Failed to register execute vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r));
601 return r;
602 }
603 }
61902ea3 604
718db961 605 if (unit_vtable[t]->kill_context_offset > 0) {
19befb2d 606 r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_kill_vtable, bus_kill_context_find, m);
718db961
LP
607 if (r < 0) {
608 log_error("Failed to register kill vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r));
609 return r;
610 }
611 }
61902ea3
LP
612 }
613
718db961 614 return 0;
61902ea3
LP
615}
616
718db961
LP
617static int bus_setup_disconnected_match(Manager *m, sd_bus *bus) {
618 int r;
61902ea3 619
718db961
LP
620 assert(m);
621 assert(bus);
61902ea3 622
718db961
LP
623 r = sd_bus_add_match(
624 bus,
19befb2d 625 NULL,
27fc65e1 626 "sender='org.freedesktop.DBus.Local',"
718db961
LP
627 "type='signal',"
628 "path='/org/freedesktop/DBus/Local',"
629 "interface='org.freedesktop.DBus.Local',"
630 "member='Disconnected'",
631 signal_disconnected, m);
05e343b7 632
718db961
LP
633 if (r < 0) {
634 log_error("Failed to register match for Disconnected message: %s", strerror(-r));
635 return r;
05e343b7
LP
636 }
637
718db961 638 return 0;
ea430986
LP
639}
640
718db961
LP
641static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
642 _cleanup_bus_unref_ sd_bus *bus = NULL;
643 _cleanup_close_ int nfd = -1;
6dded4c7 644 Manager *m = userdata;
718db961
LP
645 sd_id128_t id;
646 int r;
6dded4c7 647
718db961 648 assert(s);
6dded4c7
LP
649 assert(m);
650
718db961
LP
651 nfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
652 if (nfd < 0) {
653 log_warning("Failed to accept private connection, ignoring: %m");
654 return 0;
655 }
6dded4c7 656
718db961
LP
657 if (set_size(m->private_buses) >= CONNECTIONS_MAX) {
658 log_warning("Too many concurrent connections, refusing");
659 return 0;
660 }
6dded4c7 661
718db961
LP
662 r = set_ensure_allocated(&m->private_buses, trivial_hash_func, trivial_compare_func);
663 if (r < 0) {
664 log_oom();
665 return 0;
666 }
6dded4c7 667
718db961
LP
668 r = sd_bus_new(&bus);
669 if (r < 0) {
670 log_warning("Failed to allocate new private connection bus: %s", strerror(-r));
671 return 0;
672 }
6dded4c7 673
718db961
LP
674 r = sd_bus_set_fd(bus, nfd, nfd);
675 if (r < 0) {
676 log_warning("Failed to set fd on new connection bus: %s", strerror(-r));
677 return 0;
678 }
6dded4c7 679
718db961 680 nfd = -1;
6dded4c7 681
718db961
LP
682 r = bus_check_peercred(bus);
683 if (r < 0) {
684 log_warning("Incoming private connection from unprivileged client, refusing: %s", strerror(-r));
685 return 0;
686 }
6dded4c7 687
718db961 688 assert_se(sd_id128_randomize(&id) >= 0);
6dded4c7 689
718db961
LP
690 r = sd_bus_set_server(bus, 1, id);
691 if (r < 0) {
692 log_warning("Failed to enable server support for new connection bus: %s", strerror(-r));
693 return 0;
694 }
6dded4c7 695
718db961
LP
696 r = sd_bus_start(bus);
697 if (r < 0) {
698 log_warning("Failed to start new connection bus: %s", strerror(-r));
699 return 0;
6dded4c7
LP
700 }
701
718db961
LP
702 r = sd_bus_attach_event(bus, m->event, SD_EVENT_PRIORITY_NORMAL);
703 if (r < 0) {
704 log_warning("Failed to attach new connection bus to event loop: %s", strerror(-r));
705 return 0;
6dded4c7
LP
706 }
707
718db961
LP
708 if (m->running_as == SYSTEMD_SYSTEM) {
709 /* When we run as system instance we get the Released
710 * signal via a direct connection */
711
712 r = sd_bus_add_match(
713 bus,
19befb2d 714 NULL,
718db961
LP
715 "type='signal',"
716 "interface='org.freedesktop.systemd1.Agent',"
717 "member='Released',"
718 "path='/org/freedesktop/systemd1/agent'",
719 signal_agent_released, m);
720
721 if (r < 0) {
722 log_warning("Failed to register Released match on new connection bus: %s", strerror(-r));
723 return 0;
724 }
725 }
6dded4c7 726
718db961
LP
727 r = bus_setup_disconnected_match(m, bus);
728 if (r < 0)
729 return 0;
6dded4c7 730
718db961
LP
731 r = bus_setup_api_vtables(m, bus);
732 if (r < 0) {
733 log_warning("Failed to set up API vtables on new connection bus: %s", strerror(-r));
734 return 0;
735 }
6dded4c7 736
718db961
LP
737 r = set_put(m->private_buses, bus);
738 if (r < 0) {
739 log_warning("Failed to add new conenction bus to set: %s", strerror(-r));
740 return 0;
6dded4c7
LP
741 }
742
718db961 743 bus = NULL;
6dded4c7 744
718db961 745 log_debug("Accepted new private connection.");
6dded4c7 746
8e274523
LP
747 return 0;
748}
749
718db961 750static int bus_list_names(Manager *m, sd_bus *bus) {
0e7be129
LP
751 _cleanup_strv_free_ char **names = NULL;
752 char **i;
718db961 753 int r;
5e8d1c9a
LP
754
755 assert(m);
718db961 756 assert(bus);
5e8d1c9a 757
0e7be129 758 r = sd_bus_list_names(bus, &names, NULL);
718db961 759 if (r < 0) {
0e7be129 760 log_error("Failed to get initial list of names: %s", strerror(-r));
718db961 761 return r;
5e8d1c9a
LP
762 }
763
718db961
LP
764 /* This is a bit hacky, we say the owner of the name is the
765 * name itself, because we don't want the extra traffic to
766 * figure out the real owner. */
0e7be129
LP
767 STRV_FOREACH(i, names)
768 manager_dispatch_bus_name_owner_changed(m, *i, NULL, *i);
5e8d1c9a 769
718db961 770 return 0;
5e8d1c9a
LP
771}
772
718db961
LP
773static int bus_setup_api(Manager *m, sd_bus *bus) {
774 int r;
f278026d 775
718db961
LP
776 assert(m);
777 assert(bus);
c1e1601e 778
718db961
LP
779 r = bus_setup_api_vtables(m, bus);
780 if (r < 0)
781 return r;
cbd37330 782
718db961
LP
783 r = sd_bus_add_match(
784 bus,
19befb2d 785 NULL,
718db961
LP
786 "type='signal',"
787 "sender='org.freedesktop.DBus',"
788 "path='/org/freedesktop/DBus',"
789 "interface='org.freedesktop.DBus',"
790 "member='NameOwnerChanged'",
791 signal_name_owner_changed, m);
792 if (r < 0)
793 log_warning("Failed to subscribe to NameOwnerChanged signal: %s", strerror(-r));
794
795 r = sd_bus_add_match(
796 bus,
19befb2d 797 NULL,
718db961
LP
798 "type='signal',"
799 "sender='org.freedesktop.DBus',"
800 "path='/org/freedesktop/DBus',"
801 "interface='org.freedesktop.systemd1.Activator',"
802 "member='ActivationRequest'",
803 signal_activation_request, m);
804 if (r < 0)
805 log_warning("Failed to subscribe to activation signal: %s", strerror(-r));
cbd37330 806
718db961
LP
807 /* Allow replacing of our name, to ease implementation of
808 * reexecution, where we keep the old connection open until
809 * after the new connection is set up and the name installed
810 * to allow clients to synchronously wait for reexecution to
811 * finish */
29a07cdb 812 r = sd_bus_request_name(bus,"org.freedesktop.systemd1", SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_ALLOW_REPLACEMENT);
718db961
LP
813 if (r < 0) {
814 log_error("Failed to register name: %s", strerror(-r));
815 return r;
816 }
53c6a358 817
718db961 818 bus_list_names(m, bus);
f278026d 819
718db961 820 log_debug("Successfully connected to API bus.");
f278026d
LP
821 return 0;
822}
823
718db961
LP
824static int bus_init_api(Manager *m) {
825 _cleanup_bus_unref_ sd_bus *bus = NULL;
f278026d
LP
826 int r;
827
718db961
LP
828 if (m->api_bus)
829 return 0;
cbd37330 830
718db961
LP
831 /* The API and system bus is the same if we are running in system mode */
832 if (m->running_as == SYSTEMD_SYSTEM && m->system_bus)
833 bus = sd_bus_ref(m->system_bus);
834 else {
835 if (m->running_as == SYSTEMD_SYSTEM)
836 r = sd_bus_open_system(&bus);
837 else
838 r = sd_bus_open_user(&bus);
cbd37330 839
718db961
LP
840 if (r < 0) {
841 log_debug("Failed to connect to API bus, retrying later...");
842 return 0;
cbd37330
MS
843 }
844
718db961
LP
845 r = sd_bus_attach_event(bus, m->event, SD_EVENT_PRIORITY_NORMAL);
846 if (r < 0) {
847 log_error("Failed to attach API bus to event loop: %s", strerror(-r));
848 return 0;
cbd37330
MS
849 }
850
718db961
LP
851 r = bus_setup_disconnected_match(m, bus);
852 if (r < 0)
853 return 0;
cbd37330
MS
854 }
855
718db961 856 r = bus_setup_api(m, bus);
cbd37330 857 if (r < 0) {
718db961
LP
858 log_error("Failed to set up API bus: %s", strerror(-r));
859 return 0;
cbd37330 860 }
cbd37330 861
718db961
LP
862 m->api_bus = bus;
863 bus = NULL;
cbd37330
MS
864
865 return 0;
cbd37330
MS
866}
867
718db961
LP
868static int bus_setup_system(Manager *m, sd_bus *bus) {
869 int r;
cbd37330 870
718db961
LP
871 assert(m);
872 assert(bus);
cbd37330 873
718db961
LP
874 if (m->running_as == SYSTEMD_SYSTEM)
875 return 0;
cbd37330 876
718db961
LP
877 /* If we are a user instance we get the Released message via
878 * the system bus */
879 r = sd_bus_add_match(
880 bus,
19befb2d 881 NULL,
718db961
LP
882 "type='signal',"
883 "interface='org.freedesktop.systemd1.Agent',"
884 "member='Released',"
885 "path='/org/freedesktop/systemd1/agent'",
886 signal_agent_released, m);
4dd1de72 887
718db961
LP
888 if (r < 0)
889 log_warning("Failed to register Released match on system bus: %s", strerror(-r));
890
891 log_debug("Successfully connected to system bus.");
892 return 0;
cbd37330
MS
893}
894
895static int bus_init_system(Manager *m) {
718db961 896 _cleanup_bus_unref_ sd_bus *bus = NULL;
cbd37330
MS
897 int r;
898
899 if (m->system_bus)
900 return 0;
901
718db961
LP
902 /* The API and system bus is the same if we are running in system mode */
903 if (m->running_as == SYSTEMD_SYSTEM && m->api_bus) {
904 m->system_bus = sd_bus_ref(m->api_bus);
905 return 0;
9014a8bd 906 }
8e274523 907
718db961
LP
908 r = sd_bus_open_system(&bus);
909 if (r < 0) {
910 log_debug("Failed to connect to system bus, retrying later...");
911 return 0;
912 }
cbd37330 913
718db961 914 r = bus_setup_disconnected_match(m, bus);
cbd37330 915 if (r < 0)
cbd37330
MS
916 return 0;
917
718db961
LP
918 r = sd_bus_attach_event(bus, m->event, SD_EVENT_PRIORITY_NORMAL);
919 if (r < 0) {
920 log_error("Failed to attach system bus to event loop: %s", strerror(-r));
cbd37330
MS
921 return 0;
922 }
923
718db961
LP
924 r = bus_setup_system(m, bus);
925 if (r < 0) {
f2f426dd 926 log_error("Failed to set up system bus: %s", strerror(-r));
718db961 927 return 0;
cbd37330
MS
928 }
929
718db961
LP
930 m->system_bus = bus;
931 bus = NULL;
cbd37330
MS
932
933 return 0;
5e8d1c9a
LP
934}
935
936static int bus_init_private(Manager *m) {
718db961
LP
937 _cleanup_close_ int fd = -1;
938 union sockaddr_union sa = {
939 .un.sun_family = AF_UNIX
5e8d1c9a 940 };
718db961
LP
941 sd_event_source *s;
942 socklen_t salen;
943 int r;
5e8d1c9a
LP
944
945 assert(m);
946
718db961 947 if (m->private_listen_fd >= 0)
5e8d1c9a
LP
948 return 0;
949
a6aa8912
LP
950 /* We don't need the private socket if we have kdbus */
951 if (m->kdbus_fd >= 0)
952 return 0;
953
67445f4e 954 if (m->running_as == SYSTEMD_SYSTEM) {
be81bfc4
LP
955
956 /* We want the private bus only when running as init */
957 if (getpid() != 1)
958 return 0;
959
718db961 960 strcpy(sa.un.sun_path, "/run/systemd/private");
f8294e41 961 salen = offsetof(union sockaddr_union, un.sun_path) + strlen("/run/systemd/private");
be81bfc4 962 } else {
718db961
LP
963 size_t left = sizeof(sa.un.sun_path);
964 char *p = sa.un.sun_path;
be81bfc4 965 const char *e;
be81bfc4 966
4db17f29 967 e = secure_getenv("XDG_RUNTIME_DIR");
718db961
LP
968 if (!e) {
969 log_error("Failed to determine XDG_RUNTIME_DIR");
970 return -EHOSTDOWN;
be81bfc4
LP
971 }
972
718db961
LP
973 left = strpcpy(&p, left, e);
974 left = strpcpy(&p, left, "/systemd/private");
92f30349 975
718db961 976 salen = sizeof(sa.un) - left;
92f30349 977
718db961 978 mkdir_parents_label(sa.un.sun_path, 0755);
be81bfc4 979 }
5e8d1c9a 980
718db961
LP
981 unlink(sa.un.sun_path);
982
983 fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
984 if (fd < 0) {
985 log_error("Failed to allocate private socket: %m");
986 return -errno;
5e8d1c9a
LP
987 }
988
718db961
LP
989 r = bind(fd, &sa.sa, salen);
990 if (r < 0) {
991 log_error("Failed to bind private socket: %m");
992 return -errno;
5e8d1c9a
LP
993 }
994
718db961
LP
995 r = listen(fd, SOMAXCONN);
996 if (r < 0) {
997 log_error("Failed to make private socket listening: %m");
998 return -errno;
999 }
5e8d1c9a 1000
151b9b96 1001 r = sd_event_add_io(m->event, &s, fd, EPOLLIN, bus_on_connection, m);
718db961
LP
1002 if (r < 0) {
1003 log_error("Failed to allocate event source: %s", strerror(-r));
1004 return r;
1005 }
5e8d1c9a 1006
718db961
LP
1007 m->private_listen_fd = fd;
1008 m->private_listen_event_source = s;
1009 fd = -1;
5e8d1c9a 1010
718db961 1011 log_debug("Successfully created private D-Bus server.");
5e8d1c9a 1012
718db961 1013 return 0;
5e8d1c9a
LP
1014}
1015
3996fbe2 1016int bus_init(Manager *m, bool try_bus_connect) {
5e8d1c9a
LP
1017 int r;
1018
3996fbe2 1019 if (try_bus_connect) {
718db961
LP
1020 r = bus_init_system(m);
1021 if (r < 0)
1022 return r;
1023
1024 r = bus_init_api(m);
1025 if (r < 0)
3996fbe2
LP
1026 return r;
1027 }
1028
6fa48533
LP
1029 r = bus_init_private(m);
1030 if (r < 0)
5e8d1c9a 1031 return r;
f278026d 1032
ea430986
LP
1033 return 0;
1034}
1035
718db961 1036static void destroy_bus(Manager *m, sd_bus **bus) {
a567261a 1037 Iterator i;
718db961 1038 Job *j;
a567261a 1039
718db961
LP
1040 assert(m);
1041 assert(bus);
5e8d1c9a 1042
718db961 1043 if (!*bus)
cbd37330 1044 return;
f278026d 1045
718db961 1046 /* Get rid of tracked clients on this bus */
8f8f05a9
LP
1047 if (m->subscribed && sd_bus_track_get_bus(m->subscribed) == *bus)
1048 m->subscribed = sd_bus_track_unref(m->subscribed);
1049
718db961 1050 HASHMAP_FOREACH(j, m->jobs, i)
8f8f05a9
LP
1051 if (j->subscribed && sd_bus_track_get_bus(j->subscribed) == *bus)
1052 j->subscribed = sd_bus_track_unref(j->subscribed);
c1e1601e 1053
718db961
LP
1054 /* Get rid of queued message on this bus */
1055 if (m->queued_message_bus == *bus) {
1056 m->queued_message_bus = sd_bus_unref(m->queued_message_bus);
05e343b7 1057
718db961
LP
1058 if (m->queued_message)
1059 m->queued_message = sd_bus_message_unref(m->queued_message);
cbd37330 1060 }
f278026d 1061
718db961
LP
1062 /* Possibly flush unwritten data, but only if we are
1063 * unprivileged, since we don't want to sync here */
1064 if (m->running_as != SYSTEMD_SYSTEM)
1065 sd_bus_flush(*bus);
5e8d1c9a 1066
718db961
LP
1067 /* And destroy the object */
1068 sd_bus_close(*bus);
1069 *bus = sd_bus_unref(*bus);
5e8d1c9a
LP
1070}
1071
1072void bus_done(Manager *m) {
718db961 1073 sd_bus *b;
05e343b7
LP
1074
1075 assert(m);
05e343b7 1076
718db961
LP
1077 if (m->api_bus)
1078 destroy_bus(m, &m->api_bus);
1079 if (m->system_bus)
1080 destroy_bus(m, &m->system_bus);
1081 while ((b = set_steal_first(m->private_buses)))
1082 destroy_bus(m, &b);
05e343b7 1083
718db961 1084 set_free(m->private_buses);
8f8f05a9
LP
1085 m->private_buses = NULL;
1086
1087 m->subscribed = sd_bus_track_unref(m->subscribed);
1088 strv_free(m->deserialized_subscribed);
1089 m->deserialized_subscribed = NULL;
05e343b7 1090
718db961
LP
1091 if (m->private_listen_event_source)
1092 m->private_listen_event_source = sd_event_source_unref(m->private_listen_event_source);
05e343b7 1093
03e334a1 1094 m->private_listen_fd = safe_close(m->private_listen_fd);
a567261a 1095}
b23de6af
LP
1096
1097int bus_fdset_add_all(Manager *m, FDSet *fds) {
1098 Iterator i;
718db961
LP
1099 sd_bus *b;
1100 int fd;
b23de6af
LP
1101
1102 assert(m);
1103 assert(fds);
1104
1105 /* When we are about to reexecute we add all D-Bus fds to the
1106 * set to pass over to the newly executed systemd. They won't
718db961 1107 * be used there however, except thatt they are closed at the
b23de6af 1108 * very end of deserialization, those making it possible for
44143309 1109 * clients to synchronously wait for systemd to reexec by
b23de6af
LP
1110 * simply waiting for disconnection */
1111
718db961
LP
1112 if (m->api_bus) {
1113 fd = sd_bus_get_fd(m->api_bus);
1114 if (fd >= 0) {
b23de6af 1115 fd = fdset_put_dup(fds, fd);
b23de6af
LP
1116 if (fd < 0)
1117 return fd;
1118 }
1119 }
1120
718db961
LP
1121 SET_FOREACH(b, m->private_buses, i) {
1122 fd = sd_bus_get_fd(b);
1123 if (fd >= 0) {
b23de6af 1124 fd = fdset_put_dup(fds, fd);
b23de6af
LP
1125 if (fd < 0)
1126 return fd;
1127 }
1128 }
1129
718db961
LP
1130 /* We don't offer any APIs on the system bus (well, unless it
1131 * is the same as the API bus) hence we don't bother with it
1132 * here */
6fa48533 1133
718db961 1134 return 0;
6fa48533
LP
1135}
1136
8f8f05a9
LP
1137int bus_foreach_bus(
1138 Manager *m,
1139 sd_bus_track *subscribed2,
1140 int (*send_message)(sd_bus *bus, void *userdata),
1141 void *userdata) {
1142
1143 Iterator i;
1144 sd_bus *b;
1145 int r, ret = 0;
1146
1147 /* Send to all direct busses, unconditionally */
1148 SET_FOREACH(b, m->private_buses, i) {
1149 r = send_message(b, userdata);
1150 if (r < 0)
1151 ret = r;
1152 }
1153
1154 /* Send to API bus, but only if somebody is subscribed */
1155 if (sd_bus_track_count(m->subscribed) > 0 ||
1156 sd_bus_track_count(subscribed2) > 0) {
1157 r = send_message(m->api_bus, userdata);
1158 if (r < 0)
1159 ret = r;
1160 }
1161
1162 return ret;
1163}
1164
1165void bus_track_serialize(sd_bus_track *t, FILE *f) {
1166 const char *n;
1167
6fa48533
LP
1168 assert(f);
1169
8f8f05a9
LP
1170 for (n = sd_bus_track_first(t); n; n = sd_bus_track_next(t))
1171 fprintf(f, "subscribed=%s\n", n);
6fa48533
LP
1172}
1173
8f8f05a9
LP
1174int bus_track_deserialize_item(char ***l, const char *line) {
1175 const char *e;
1176
1177 assert(l);
6fa48533
LP
1178 assert(line);
1179
8f8f05a9
LP
1180 e = startswith(line, "subscribed=");
1181 if (!e)
1182 return 0;
1183
1184 return strv_extend(l, e);
1185}
1186
1187int bus_track_coldplug(Manager *m, sd_bus_track **t, char ***l) {
1188 int r = 0;
1189
1190 assert(m);
1191 assert(t);
1192 assert(l);
1193
1194 if (!strv_isempty(*l) && m->api_bus) {
1195 char **i;
1196
1197 if (!*t) {
1198 r = sd_bus_track_new(m->api_bus, t, NULL, NULL);
1199 if (r < 0)
1200 return r;
1201 }
1202
1203 r = 0;
1204 STRV_FOREACH(i, *l) {
1205 int k;
1206
1207 k = sd_bus_track_add_name(*t, *i);
1208 if (k < 0)
1209 r = k;
1210 }
1211 }
1212
1213 strv_free(*l);
1214 *l = NULL;
1215
1216 return r;
6fa48533 1217}