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