dbus.c revision 05a08cb60f02970e8476306074c70ee4e6a57fb3
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen This file is part of systemd.
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen Copyright 2010 Lennart Poettering
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen systemd is free software; you can redistribute it and/or modify it
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen under the terms of the GNU Lesser General Public License as published by
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen the Free Software Foundation; either version 2.1 of the License, or
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen (at your option) any later version.
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen systemd is distributed in the hope that it will be useful, but
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen Lesser General Public License for more details.
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen You should have received a copy of the GNU Lesser General Public License
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
a501033335ed402c8f7e86fe41a15531ba69abd7Tom Gundersenstatic void destroy_bus(Manager *m, sd_bus **bus);
2ad8416dd057e7e3185169609ca3006e7649f576Zbigniew Jędrzejewski-Szmek /* If we cannot get rid of this message we won't dispatch any
2ad8416dd057e7e3185169609ca3006e7649f576Zbigniew Jędrzejewski-Szmek * D-Bus messages, so that we won't end up wanting to queue
2ad8416dd057e7e3185169609ca3006e7649f576Zbigniew Jędrzejewski-Szmek * another message. */
2ad8416dd057e7e3185169609ca3006e7649f576Zbigniew Jędrzejewski-Szmek r = sd_bus_send(m->queued_message_bus, m->queued_message, NULL);
5b9d4dc05560ddda89e48b6b39365824b15e1300Tom Gundersen log_warning_errno(r, "Failed to send queued message: %m");
5b9d4dc05560ddda89e48b6b39365824b15e1300Tom Gundersen m->queued_message = sd_bus_message_unref(m->queued_message);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen m->queued_message_bus = sd_bus_unref(m->queued_message_bus);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersenstatic int signal_agent_released(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
f61942250a43a123580d7bbe5d7873dc5118ed97Tom Gundersen r = sd_bus_message_read(message, "s", &cgroup);
977085794d2996320e345433403de75f662b0622Tom Gundersen /* only forward to system bus if running as system instance */
977085794d2996320e345433403de75f662b0622Tom Gundersen if (m->running_as != SYSTEMD_SYSTEM || !m->system_bus)
847a8a5fed4d265dfa659917515c6f9bd1b8d5c4Tom Gundersen r = sd_bus_send(m->system_bus, message, NULL);
847a8a5fed4d265dfa659917515c6f9bd1b8d5c4Tom Gundersen log_warning_errno(r, "Failed to forward Released message: %m");
866ee3682213789f85b877700457fdca05695a0eTom Gundersenstatic int signal_disconnected(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen log_debug("Got disconnect on private connection.");
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersenstatic int signal_name_owner_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen r = sd_bus_message_read(message, "sss", &name, &old_owner, &new_owner);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersenstatic int signal_activation_request(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
ecb08ec6a5c52f2d940f3b8147e2a480affd46e1Zbigniew Jędrzejewski-Szmek _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
6e37cd2f4af8928d905203108a4331e375d7127cThomas Hindoe Paaboel Andersen _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
ed88bcfb7c15029f9fc95ee2380759a9eb782d46Zbigniew Jędrzejewski-Szmek if (manager_unit_inactive_or_pending(m, SPECIAL_DBUS_SERVICE) ||
ed88bcfb7c15029f9fc95ee2380759a9eb782d46Zbigniew Jędrzejewski-Szmek manager_unit_inactive_or_pending(m, SPECIAL_DBUS_SOCKET)) {
ed88bcfb7c15029f9fc95ee2380759a9eb782d46Zbigniew Jędrzejewski-Szmek r = sd_bus_error_setf(&error, BUS_ERROR_SHUTTING_DOWN, "Refusing activation, D-Bus is shutting down.");
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen r = manager_load_unit(m, name, NULL, &error, &u);
e9f3d2d508bfd9fb5b54e82994bda365a71eb864Zbigniew Jędrzejewski-Szmek r = sd_bus_error_setf(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, %s may be requested by dependency only.", u->id);
36f822c4bd077f9121757e24b6516e5c7ada63b5Zbigniew Jędrzejewski-Szmek r = manager_add_job(m, JOB_START, u, JOB_REPLACE, true, &error, NULL);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen /* Successfully queued, that's it for us */
ecb08ec6a5c52f2d940f3b8147e2a480affd46e1Zbigniew Jędrzejewski-Szmek if (!sd_bus_error_is_set(&error))
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen log_debug("D-Bus activation failed for %s: %s", name, bus_error_message(&error, r));
f61942250a43a123580d7bbe5d7873dc5118ed97Tom Gundersen r = sd_bus_message_new_signal(bus, &reply, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Activator", "ActivationFailure");
74df0fca09b3c31ed19e14ba80f996fdff772417Lennart Poettering r = sd_bus_message_append(reply, "sss", name, error.name, error.message);
f61942250a43a123580d7bbe5d7873dc5118ed97Tom Gundersen r = sd_bus_send_to(bus, reply, "org.freedesktop.DBus", NULL);
a2a5291b3f5ab6ed4c92f51d0fd10a03047380d8Zbigniew Jędrzejewski-Szmek return log_error_errno(r, "Failed to respond with to bus activation request: %m");
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersenstatic int mac_selinux_filter(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
f61942250a43a123580d7bbe5d7873dc5118ed97Tom Gundersen /* Our own method calls are all protected individually with
f61942250a43a123580d7bbe5d7873dc5118ed97Tom Gundersen * selinux checks, but the built-in interfaces need to be
97f2d76d4f4dfab8b0629c09926a05a1e5621125Tom Gundersen * protected too. */
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen if (sd_bus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Set"))
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen else if (sd_bus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", NULL) ||
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen sd_bus_message_is_method_call(message, "org.freedesktop.DBus.Properties", NULL) ||
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen sd_bus_message_is_method_call(message, "org.freedesktop.DBus.ObjectManager", NULL) ||
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen sd_bus_message_is_method_call(message, "org.freedesktop.DBus.Peer", NULL))
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen if (object_path_startswith("/org/freedesktop/systemd1", path)) {
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen r = mac_selinux_access_check(message, verb, error);
464cf22f17e0cf2d8bfa6d72b5e7a662d634f149Tom Gundersen if (streq_ptr(path, "/org/freedesktop/systemd1/unit/self")) {
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
b3e013148603aa670bc2c060ac63d48e54d76fc2Tom Gundersen r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
be32eb9b7fbcb22e4b648086d644135e38279633Tom Gundersen r = manager_get_job_from_dbus_path(m, path, &j);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen manager_load_unit_from_dbus_path(m, path, NULL, &u);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen r = mac_selinux_unit_access_check(u, message, verb, error);
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersenstatic int bus_job_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen r = manager_get_job_from_dbus_path(m, path, &j);
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersenstatic int find_unit(Manager *m, sd_bus *bus, const char *path, Unit **unit, sd_bus_error *error) {
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen if (streq_ptr(path, "/org/freedesktop/systemd1/unit/self")) {
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
464cf22f17e0cf2d8bfa6d72b5e7a662d634f149Tom Gundersen r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen r = manager_load_unit_from_dbus_path(m, path, error, &u);
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersenstatic int bus_unit_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
43b3a5ef61859f06cdbaf26765cab8e1adac4296Tom Gundersen return find_unit(m, bus, path, (Unit**) found, error);
3e137a1b9a0eac2bf43d493d3302c3c959b6ccdbTom Gundersenstatic int bus_unit_interface_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
733f7a2c69c794a81978a08a79916c224ba355a6Tom Gundersen if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface))
3e137a1b9a0eac2bf43d493d3302c3c959b6ccdbTom Gundersenstatic int bus_unit_cgroup_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface))
daeb71a36a98834664e4d95773a3629b746f4db8Tom Gundersenstatic int bus_cgroup_context_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface))
a669ea9860900d5cdebbc4cb9aaea72db7e28a02Tom Gundersenstatic int bus_exec_context_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface))
43b3a5ef61859f06cdbaf26765cab8e1adac4296Tom Gundersenstatic int bus_kill_context_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
847a8a5fed4d265dfa659917515c6f9bd1b8d5c4Tom Gundersen if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface))
be32eb9b7fbcb22e4b648086d644135e38279633Tom Gundersenstatic int bus_job_enumerate(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
be32eb9b7fbcb22e4b648086d644135e38279633Tom Gundersen unsigned k = 0;
*nodes = l;
l = NULL;
static int bus_unit_enumerate(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
Iterator i;
Unit *u;
return -ENOMEM;
l[k] = unit_dbus_path(u);
return -ENOMEM;
*nodes = l;
l = NULL;
UnitType t;
assert(m);
#ifdef HAVE_SELINUX
r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", bus_manager_vtable, m);
r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/job", "org.freedesktop.systemd1.Job", bus_job_vtable, bus_job_find, m);
r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", "org.freedesktop.systemd1.Unit", bus_unit_vtable, bus_unit_find, m);
for (t = 0; t < _UNIT_TYPE_MAX; t++) {
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);
return log_error_errno(r, "Failed to register type specific vtable for %s: %m", unit_vtable[t]->bus_interface);
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);
return log_error_errno(r, "Failed to register control group unit vtable for %s: %m", unit_vtable[t]->bus_interface);
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);
return log_error_errno(r, "Failed to register control group vtable for %s: %m", unit_vtable[t]->bus_interface);
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);
return log_error_errno(r, "Failed to register execute vtable for %s: %m", unit_vtable[t]->bus_interface);
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);
return log_error_errno(r, "Failed to register kill vtable for %s: %m", unit_vtable[t]->bus_interface);
assert(m);
r = sd_bus_add_match(
bus,
NULL,
"path='/org/freedesktop/DBus/Local',"
signal_disconnected, m);
assert(s);
assert(m);
if (nfd < 0) {
log_oom();
r = sd_bus_add_match(
bus,
NULL,
"interface='org.freedesktop.systemd1.Agent',"
"path='/org/freedesktop/systemd1/agent'",
assert(m);
assert(m);
/* Let's make sure we have enough credential bits so that we can make security and selinux decisions */
r = sd_bus_add_match(
bus,
NULL,
"path='/org/freedesktop/DBus',"
r = sd_bus_add_match(
bus,
NULL,
"path='/org/freedesktop/DBus',"
"interface='org.freedesktop.systemd1.Activator',"
r = sd_bus_request_name(bus,"org.freedesktop.systemd1", SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_ALLOW_REPLACEMENT);
if (m->api_bus)
assert(m);
r = sd_bus_add_match(
bus,
NULL,
"interface='org.freedesktop.systemd1.Agent',"
"path='/org/freedesktop/systemd1/agent'",
if (m->system_bus)
sd_event_source *s;
assert(m);
if (m->private_listen_fd >= 0)
if (m->kdbus_fd >= 0)
return -EHOSTDOWN;
if (fd < 0)
m->private_listen_event_source = s;
if (try_bus_connect) {
r = bus_init_system(m);
r = bus_init_api(m);
r = bus_init_private(m);
Iterator i;
Job *j;
assert(m);
if (!*bus)
if (m->queued_message)
sd_bus *b;
assert(m);
if (m->api_bus)
if (m->system_bus)
destroy_bus(m, &b);
if (m->private_listen_event_source)
Iterator i;
sd_bus *b;
int fd;
assert(m);
if (m->api_bus) {
if (fd >= 0) {
if (fd < 0)
return fd;
if (fd >= 0) {
if (fd < 0)
return fd;
int bus_foreach_bus(
Manager *m,
void *userdata) {
Iterator i;
sd_bus *b;
int r, ret = 0;
ret = r;
ret = r;
return ret;
assert(f);
assert(l);
r = strv_extend(l, e);
assert(m);
assert(t);
assert(l);
STRV_FOREACH(i, *l) {
k = sd_bus_track_add_name(*t, *i);
strv_free(*l);
*l = NULL;
return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.manage-units", false, UID_INVALID, &m->polkit_registry, error);
return bus_verify_polkit_async(call, CAP_KILL, "org.freedesktop.systemd1.manage-units", false, UID_INVALID, &m->polkit_registry, error);
return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.manage-unit-files", false, UID_INVALID, &m->polkit_registry, error);
return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.reload-daemon", false, UID_INVALID, &m->polkit_registry, error);
return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.set-environment", false, UID_INVALID, &m->polkit_registry, error);