]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/dbus.c
bus: also add error parameter to object find and enumerator callbacks
[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"
44#include "dbus-client-track.h"
969987ea
LP
45#include "bus-internal.h"
46#include "selinux-access.h"
4288f619 47
417b1a62 48#define CONNECTIONS_MAX 512
5e8d1c9a 49
718db961
LP
50static void destroy_bus(Manager *m, sd_bus **bus);
51
52int bus_send_queued_message(Manager *m) {
53 int r;
8e274523 54
8e274523 55 assert(m);
2e317f52 56
718db961
LP
57 if (!m->queued_message)
58 return 0;
8e274523 59
718db961 60 assert(m->queued_message_bus);
8e274523 61
718db961
LP
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. */
ea430986 65
718db961
LP
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));
ea430986 69
718db961
LP
70 m->queued_message = sd_bus_message_unref(m->queued_message);
71 m->queued_message_bus = sd_bus_unref(m->queued_message_bus);
ea430986 72
718db961 73 return 0;
ea430986
LP
74}
75
ebcf1f97 76static int signal_agent_released(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961
LP
77 Manager *m = userdata;
78 const char *cgroup;
79 int r;
ea430986 80
718db961
LP
81 assert(bus);
82 assert(message);
ea430986
LP
83 assert(m);
84
718db961
LP
85 r = sd_bus_message_read(message, "s", &cgroup);
86 if (r < 0) {
87 bus_log_parse_error(r);
88 return 0;
89 }
ea430986 90
718db961 91 manager_notify_cgroup_empty(m, cgroup);
ea430986 92
718db961
LP
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 */
ea430986 96
718db961
LP
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 }
ea430986 101
718db961
LP
102 return 0;
103}
ea430986 104
ebcf1f97 105static int signal_disconnected(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961 106 Manager *m = userdata;
ea430986 107
718db961
LP
108 assert(bus);
109 assert(message);
110 assert(m);
ea430986 111
718db961
LP
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);
ea430986
LP
119 }
120
718db961 121 return 0;
ea430986
LP
122}
123
ebcf1f97 124static int signal_name_owner_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
718db961
LP
125 const char *name, *old_owner, *new_owner;
126 Manager *m = userdata;
127 int r;
ea430986 128
718db961
LP
129 assert(bus);
130 assert(message);
ea430986
LP
131 assert(m);
132
718db961
LP
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 }
ea430986 138
718db961
LP
139 manager_dispatch_bus_name_owner_changed(
140 m, name,
141 isempty(old_owner) ? NULL : old_owner,
142 isempty(new_owner) ? NULL : new_owner);
ea430986 143
718db961 144 return 0;
ea430986
LP
145}
146
ebcf1f97 147static int signal_activation_request(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
718db961
LP
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;
ea430986 154
718db961
LP
155 assert(bus);
156 assert(message);
ea430986
LP
157 assert(m);
158
718db961
LP
159 r = sd_bus_message_read(message, "s", &name);
160 if (r < 0) {
161 bus_log_parse_error(r);
162 return 0;
163 }
ea430986 164
718db961
LP
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 }
ea430986 170
718db961
LP
171 r = manager_load_unit(m, name, NULL, &error, &u);
172 if (r < 0)
173 goto failed;
ea430986 174
718db961
LP
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;
ea430986
LP
178 }
179
718db961
LP
180 r = manager_add_job(m, JOB_START, u, JOB_REPLACE, true, &error, NULL);
181 if (r < 0)
182 goto failed;
ea430986 183
718db961 184 /* Successfully queued, that's it for us */
ea430986 185 return 0;
ea430986 186
718db961
LP
187failed:
188 if (!sd_bus_error_is_set(&error))
189 sd_bus_error_set_errno(&error, r);
ea430986 190
718db961 191 log_debug("D-Bus activation failed for %s: %s", name, bus_error_message(&error, r));
ea430986 192
718db961
LP
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
fa0fed49 199 r = sd_bus_message_append(reply, "sss", name, error.name, error.message);
718db961
LP
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 }
ea430986 210
718db961 211 return 0;
ea430986
LP
212}
213
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
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
f00c3121 275static int bus_job_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
718db961
LP
276 Manager *m = userdata;
277 Job *j;
278 int r;
ea430986 279
718db961
LP
280 assert(bus);
281 assert(path);
282 assert(interface);
283 assert(found);
ea430986
LP
284 assert(m);
285
718db961
LP
286 r = manager_get_job_from_dbus_path(m, path, &j);
287 if (r < 0)
288 return 0;
ea430986 289
718db961
LP
290 *found = j;
291 return 1;
292}
ea430986 293
f00c3121 294static int find_unit(Manager *m, sd_bus *bus, const char *path, Unit **unit, sd_bus_error *error) {
718db961
LP
295 Unit *u;
296 int r;
ea430986 297
718db961
LP
298 assert(m);
299 assert(bus);
300 assert(path);
ea430986 301
718db961
LP
302 if (streq_ptr(path, "/org/freedesktop/systemd1/unit/self")) {
303 sd_bus_message *message;
304 pid_t pid;
ea430986 305
718db961
LP
306 message = sd_bus_get_current(bus);
307 if (!message)
f00c3121 308 return 0;
ea430986 309
718db961
LP
310 r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), &pid);
311 if (r < 0)
f00c3121 312 return 0;
ea430986 313
718db961
LP
314 u = manager_get_unit_by_pid(m, pid);
315 } else {
f00c3121 316 r = manager_load_unit_from_dbus_path(m, path, error, &u);
718db961 317 if (r < 0)
f00c3121 318 return 0;
718db961 319 }
ea430986 320
f00c3121
LP
321 if (!u)
322 return 0;
323
324 *unit = u;
325 return 1;
ea430986
LP
326}
327
f00c3121 328static int bus_unit_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
718db961 329 Manager *m = userdata;
ea430986 330
718db961
LP
331 assert(bus);
332 assert(path);
333 assert(interface);
334 assert(found);
ea430986
LP
335 assert(m);
336
f00c3121 337 return find_unit(m, bus, path, (Unit**) found, error);
ea430986
LP
338}
339
f00c3121 340static int bus_unit_interface_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
718db961
LP
341 Manager *m = userdata;
342 Unit *u;
f00c3121 343 int r;
ea430986 344
718db961
LP
345 assert(bus);
346 assert(path);
347 assert(interface);
348 assert(found);
ea430986
LP
349 assert(m);
350
f00c3121
LP
351 r = find_unit(m, bus, path, &u, error);
352 if (r <= 0)
353 return r;
3df5bf61 354
718db961
LP
355 if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface))
356 return 0;
ea430986 357
718db961
LP
358 *found = u;
359 return 1;
ea430986
LP
360}
361
f00c3121 362static int bus_unit_cgroup_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
718db961
LP
363 Manager *m = userdata;
364 Unit *u;
f00c3121 365 int r;
c1e1601e 366
718db961
LP
367 assert(bus);
368 assert(path);
369 assert(interface);
370 assert(found);
c1e1601e
LP
371 assert(m);
372
f00c3121
LP
373 r = find_unit(m, bus, path, &u, error);
374 if (r <= 0)
375 return r;
05e343b7 376
718db961
LP
377 if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface))
378 return 0;
05e343b7 379
718db961
LP
380 if (!unit_get_cgroup_context(u))
381 return 0;
0034c15c 382
718db961
LP
383 *found = u;
384 return 1;
385}
0034c15c 386
f00c3121 387static int bus_cgroup_context_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
718db961
LP
388 Manager *m = userdata;
389 CGroupContext *c;
390 Unit *u;
f00c3121 391 int r;
af25ec12 392
718db961
LP
393 assert(bus);
394 assert(path);
395 assert(interface);
396 assert(found);
397 assert(m);
0034c15c 398
f00c3121
LP
399 r = find_unit(m, bus, path, &u, error);
400 if (r <= 0)
401 return r;
0034c15c 402
718db961
LP
403 if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface))
404 return 0;
0034c15c 405
718db961
LP
406 c = unit_get_cgroup_context(u);
407 if (!c)
408 return 0;
c1e1601e 409
718db961
LP
410 *found = c;
411 return 1;
412}
0034c15c 413
f00c3121 414static int bus_exec_context_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
718db961
LP
415 Manager *m = userdata;
416 ExecContext *c;
417 Unit *u;
f00c3121 418 int r;
0034c15c 419
718db961
LP
420 assert(bus);
421 assert(path);
422 assert(interface);
423 assert(found);
424 assert(m);
0034c15c 425
f00c3121
LP
426 r = find_unit(m, bus, path, &u, error);
427 if (r <= 0)
428 return r;
0034c15c 429
718db961
LP
430 if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface))
431 return 0;
0034c15c 432
718db961
LP
433 c = unit_get_exec_context(u);
434 if (!c)
435 return 0;
0034c15c 436
718db961
LP
437 *found = c;
438 return 1;
c1e1601e
LP
439}
440
f00c3121 441static int bus_kill_context_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
718db961
LP
442 Manager *m = userdata;
443 KillContext *c;
444 Unit *u;
f00c3121 445 int r;
8e274523 446
718db961
LP
447 assert(bus);
448 assert(path);
449 assert(interface);
450 assert(found);
8e274523
LP
451 assert(m);
452
f00c3121
LP
453 r = find_unit(m, bus, path, &u, error);
454 if (r <= 0)
455 return r;
8e274523 456
718db961
LP
457 if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface))
458 return 0;
8e274523 459
718db961
LP
460 c = unit_get_kill_context(u);
461 if (!c)
462 return 0;
53c6a358 463
718db961
LP
464 *found = c;
465 return 1;
466}
8e274523 467
f00c3121 468static int bus_job_enumerate(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
718db961
LP
469 _cleanup_free_ char **l = NULL;
470 Manager *m = userdata;
471 unsigned k = 0;
472 Iterator i;
473 Job *j;
8e274523 474
718db961
LP
475 l = new0(char*, hashmap_size(m->jobs)+1);
476 if (!l)
477 return -ENOMEM;
8e274523 478
718db961
LP
479 HASHMAP_FOREACH(j, m->jobs, i) {
480 l[k] = job_dbus_path(j);
481 if (!l[k])
482 return -ENOMEM;
5e8d1c9a 483
718db961
LP
484 k++;
485 }
5e8d1c9a 486
718db961 487 assert(hashmap_size(m->jobs) == k);
3c661fad 488
718db961
LP
489 *nodes = l;
490 l = NULL;
5e8d1c9a 491
718db961
LP
492 return k;
493}
53c6a358 494
f00c3121 495static int bus_unit_enumerate(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
718db961
LP
496 _cleanup_free_ char **l = NULL;
497 Manager *m = userdata;
498 unsigned k = 0;
499 Iterator i;
500 Unit *u;
3c661fad 501
718db961
LP
502 l = new0(char*, hashmap_size(m->units)+1);
503 if (!l)
504 return -ENOMEM;
53c6a358 505
718db961
LP
506 HASHMAP_FOREACH(u, m->units, i) {
507 l[k] = unit_dbus_path(u);
508 if (!l[k])
509 return -ENOMEM;
53c6a358 510
718db961 511 k++;
3c661fad
LP
512 }
513
718db961
LP
514 *nodes = l;
515 l = NULL;
5e8d1c9a 516
718db961 517 return k;
5e8d1c9a
LP
518}
519
718db961
LP
520static int bus_setup_api_vtables(Manager *m, sd_bus *bus) {
521 UnitType t;
522 int r;
5e8d1c9a 523
ea430986 524 assert(m);
718db961 525 assert(bus);
ea430986 526
969987ea
LP
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
718db961
LP
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;
a16e1123
LP
537 }
538
718db961
LP
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;
fd18e1f4 543 }
c1e1601e 544
718db961
LP
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 }
61902ea3 550
718db961
LP
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 }
61902ea3 556
718db961
LP
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 }
61902ea3 562
718db961
LP
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 }
61902ea3 569
718db961
LP
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 }
61902ea3 576
718db961
LP
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 }
61902ea3
LP
582 }
583
718db961
LP
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 }
61902ea3 591
718db961
LP
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 }
61902ea3
LP
599 }
600
718db961 601 return 0;
61902ea3
LP
602}
603
718db961
LP
604static int bus_setup_disconnected_match(Manager *m, sd_bus *bus) {
605 int r;
61902ea3 606
718db961
LP
607 assert(m);
608 assert(bus);
61902ea3 609
718db961
LP
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);
05e343b7 617
718db961
LP
618 if (r < 0) {
619 log_error("Failed to register match for Disconnected message: %s", strerror(-r));
620 return r;
05e343b7
LP
621 }
622
718db961 623 return 0;
ea430986
LP
624}
625
718db961
LP
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;
6dded4c7 629 Manager *m = userdata;
718db961
LP
630 sd_id128_t id;
631 int r;
6dded4c7 632
718db961 633 assert(s);
6dded4c7
LP
634 assert(m);
635
718db961
LP
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 }
6dded4c7 641
718db961
LP
642 if (set_size(m->private_buses) >= CONNECTIONS_MAX) {
643 log_warning("Too many concurrent connections, refusing");
644 return 0;
645 }
6dded4c7 646
718db961
LP
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 }
6dded4c7 652
718db961
LP
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 }
6dded4c7 658
718db961
LP
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 }
6dded4c7 664
718db961 665 nfd = -1;
6dded4c7 666
718db961
LP
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 }
6dded4c7 672
718db961 673 assert_se(sd_id128_randomize(&id) >= 0);
6dded4c7 674
718db961
LP
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 }
6dded4c7 680
718db961
LP
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;
6dded4c7
LP
685 }
686
718db961
LP
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;
6dded4c7
LP
691 }
692
718db961
LP
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 }
6dded4c7 710
718db961
LP
711 r = bus_setup_disconnected_match(m, bus);
712 if (r < 0)
713 return 0;
6dded4c7 714
718db961
LP
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 }
6dded4c7 720
718db961
LP
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;
6dded4c7
LP
725 }
726
718db961 727 bus = NULL;
6dded4c7 728
718db961 729 log_debug("Accepted new private connection.");
6dded4c7 730
8e274523
LP
731 return 0;
732}
733
718db961
LP
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;
5e8d1c9a
LP
739
740 assert(m);
718db961 741 assert(bus);
5e8d1c9a 742
718db961
LP
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;
5e8d1c9a
LP
754 }
755
718db961
LP
756 r = sd_bus_message_enter_container(reply, 'a', "s");
757 if (r < 0)
758 return bus_log_parse_error(r);
5e8d1c9a 759
718db961
LP
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);
5e8d1c9a 767
718db961
LP
768 r = sd_bus_message_exit_container(reply);
769 if (r < 0)
770 return bus_log_parse_error(r);
5e8d1c9a 771
718db961 772 return 0;
5e8d1c9a
LP
773}
774
718db961
LP
775static int bus_setup_api(Manager *m, sd_bus *bus) {
776 int r;
f278026d 777
718db961
LP
778 assert(m);
779 assert(bus);
c1e1601e 780
718db961
LP
781 r = bus_setup_api_vtables(m, bus);
782 if (r < 0)
783 return r;
cbd37330 784
718db961
LP
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));
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 */
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 }
53c6a358 817
718db961
LP
818 if (r != SD_BUS_NAME_PRIMARY_OWNER) {
819 log_error("Failed to acquire name.");
820 return -EEXIST;
ea430986
LP
821 }
822
718db961 823 bus_list_names(m, bus);
f278026d 824
718db961 825 log_debug("Successfully connected to API bus.");
f278026d
LP
826 return 0;
827}
828
718db961
LP
829static int bus_init_api(Manager *m) {
830 _cleanup_bus_unref_ sd_bus *bus = NULL;
f278026d
LP
831 int r;
832
718db961
LP
833 if (m->api_bus)
834 return 0;
cbd37330 835
718db961
LP
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);
cbd37330 844
718db961
LP
845 if (r < 0) {
846 log_debug("Failed to connect to API bus, retrying later...");
847 return 0;
cbd37330
MS
848 }
849
718db961
LP
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;
cbd37330
MS
854 }
855
718db961
LP
856 r = bus_setup_disconnected_match(m, bus);
857 if (r < 0)
858 return 0;
cbd37330
MS
859 }
860
718db961 861 r = bus_setup_api(m, bus);
cbd37330 862 if (r < 0) {
718db961
LP
863 log_error("Failed to set up API bus: %s", strerror(-r));
864 return 0;
cbd37330 865 }
cbd37330 866
718db961
LP
867 m->api_bus = bus;
868 bus = NULL;
cbd37330
MS
869
870 return 0;
cbd37330
MS
871}
872
718db961
LP
873static int bus_setup_system(Manager *m, sd_bus *bus) {
874 int r;
cbd37330 875
718db961
LP
876 assert(m);
877 assert(bus);
cbd37330 878
718db961
LP
879 if (m->running_as == SYSTEMD_SYSTEM)
880 return 0;
cbd37330 881
718db961
LP
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);
4dd1de72 891
718db961
LP
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;
cbd37330
MS
897}
898
899static int bus_init_system(Manager *m) {
718db961 900 _cleanup_bus_unref_ sd_bus *bus = NULL;
cbd37330
MS
901 int r;
902
903 if (m->system_bus)
904 return 0;
905
718db961
LP
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;
9014a8bd 910 }
8e274523 911
718db961
LP
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 }
cbd37330 917
718db961 918 r = bus_setup_disconnected_match(m, bus);
cbd37330 919 if (r < 0)
cbd37330
MS
920 return 0;
921
718db961
LP
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));
cbd37330
MS
925 return 0;
926 }
927
718db961
LP
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;
cbd37330
MS
932 }
933
718db961
LP
934 m->system_bus = bus;
935 bus = NULL;
cbd37330
MS
936
937 return 0;
5e8d1c9a
LP
938}
939
940static int bus_init_private(Manager *m) {
718db961
LP
941 _cleanup_close_ int fd = -1;
942 union sockaddr_union sa = {
943 .un.sun_family = AF_UNIX
5e8d1c9a 944 };
718db961
LP
945 sd_event_source *s;
946 socklen_t salen;
947 int r;
5e8d1c9a
LP
948
949 assert(m);
950
718db961 951 if (m->private_listen_fd >= 0)
5e8d1c9a
LP
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
LP
960 strcpy(sa.un.sun_path, "/run/systemd/private");
961 salen = offsetof(union sockaddr_union, un.sun_path) + sizeof("/run/systemd/private") - 1;
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
718db961
LP
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 }
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
LP
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);
c1e1601e 1050
718db961
LP
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);
05e343b7 1054
718db961
LP
1055 if (m->queued_message)
1056 m->queued_message = sd_bus_message_unref(m->queued_message);
cbd37330 1057 }
f278026d 1058
718db961
LP
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);
5e8d1c9a 1063
718db961
LP
1064 /* And destroy the object */
1065 sd_bus_close(*bus);
1066 *bus = sd_bus_unref(*bus);
5e8d1c9a
LP
1067}
1068
1069void bus_done(Manager *m) {
718db961 1070 sd_bus *b;
05e343b7
LP
1071
1072 assert(m);
05e343b7 1073
718db961
LP
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);
05e343b7 1080
718db961
LP
1081 set_free(m->private_buses);
1082 set_free(m->subscribed);
05e343b7 1083
718db961
LP
1084 if (m->private_listen_event_source)
1085 m->private_listen_event_source = sd_event_source_unref(m->private_listen_event_source);
05e343b7 1086
718db961
LP
1087 if (m->private_listen_fd >= 0) {
1088 close_nointr_nofail(m->private_listen_fd);
1089 m->private_listen_fd = -1;
05e343b7 1090 }
a567261a 1091}
b23de6af
LP
1092
1093int bus_fdset_add_all(Manager *m, FDSet *fds) {
1094 Iterator i;
718db961
LP
1095 sd_bus *b;
1096 int fd;
b23de6af
LP
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
718db961 1103 * be used there however, except thatt they are closed at the
b23de6af 1104 * very end of deserialization, those making it possible for
44143309 1105 * clients to synchronously wait for systemd to reexec by
b23de6af
LP
1106 * simply waiting for disconnection */
1107
718db961
LP
1108 if (m->api_bus) {
1109 fd = sd_bus_get_fd(m->api_bus);
1110 if (fd >= 0) {
b23de6af 1111 fd = fdset_put_dup(fds, fd);
b23de6af
LP
1112 if (fd < 0)
1113 return fd;
1114 }
1115 }
1116
718db961
LP
1117 SET_FOREACH(b, m->private_buses, i) {
1118 fd = sd_bus_get_fd(b);
1119 if (fd >= 0) {
b23de6af 1120 fd = fdset_put_dup(fds, fd);
b23de6af
LP
1121 if (fd < 0)
1122 return fd;
1123 }
1124 }
1125
718db961
LP
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 */
6fa48533 1129
718db961 1130 return 0;
6fa48533
LP
1131}
1132
1133void bus_serialize(Manager *m, FILE *f) {
6fa48533
LP
1134 assert(m);
1135 assert(f);
1136
718db961 1137 bus_client_track_serialize(m, f, m->subscribed);
6fa48533
LP
1138}
1139
1140int bus_deserialize_item(Manager *m, const char *line) {
6fa48533
LP
1141 assert(m);
1142 assert(line);
1143
718db961 1144 return bus_client_track_deserialize_item(m, &m->subscribed, line);
6fa48533 1145}