dbus.c revision 8f88ecf6232fe6c46eecafad7c421096bb29b617
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/>.
f61942250a43a123580d7bbe5d7873dc5118ed97Tom 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(NULL, m->queued_message, NULL);
9a4b012e43f23516373bf398dd9a458439d19939Tom Gundersen log_warning_errno(r, "Failed to send queued message: %m");
9a4b012e43f23516373bf398dd9a458439d19939Tom Gundersen m->queued_message = sd_bus_message_unref(m->queued_message);
43d60b77a83b3185e37c65c4f2649d24c227c7f0Tom Gundersenstatic int signal_agent_released(sd_bus_message *message, void *userdata, sd_bus_error *error) {
9a4b012e43f23516373bf398dd9a458439d19939Tom Gundersen r = sd_bus_message_read(message, "s", &cgroup);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen /* only forward to system bus if running as system instance */
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen if (m->running_as != SYSTEMD_SYSTEM || !m->system_bus)
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen r = sd_bus_send(m->system_bus, message, NULL);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen log_warning_errno(r, "Failed to forward Released message: %m");
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersenstatic int signal_disconnected(sd_bus_message *message, void *userdata, sd_bus_error *error) {
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen assert_se(bus = sd_bus_message_get_bus(message));
9a4b012e43f23516373bf398dd9a458439d19939Tom Gundersen log_debug("Got disconnect on private connection.");
9a4b012e43f23516373bf398dd9a458439d19939Tom Gundersenstatic int signal_name_owner_changed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
9a4b012e43f23516373bf398dd9a458439d19939Tom Gundersen r = sd_bus_message_read(message, "sss", &name, &old_owner, &new_owner);
187dc6e554f2d5b4b5a3bee72c73ff5df6418aa6Thomas Hindoe Paaboel Andersenstatic int signal_activation_request(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
187dc6e554f2d5b4b5a3bee72c73ff5df6418aa6Thomas Hindoe Paaboel Andersen _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
187dc6e554f2d5b4b5a3bee72c73ff5df6418aa6Thomas Hindoe Paaboel Andersen _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
ed88bcfb7c15029f9fc95ee2380759a9eb782d46Zbigniew Jędrzejewski-Szmek assert_se(bus = sd_bus_message_get_bus(message));
ed88bcfb7c15029f9fc95ee2380759a9eb782d46Zbigniew Jędrzejewski-Szmek r = sd_bus_message_read(message, "s", &name);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen if (manager_unit_inactive_or_pending(m, SPECIAL_DBUS_SERVICE) ||
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen manager_unit_inactive_or_pending(m, SPECIAL_DBUS_SOCKET)) {
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen r = sd_bus_error_setf(&error, BUS_ERROR_SHUTTING_DOWN, "Refusing activation, D-Bus is shutting down.");
e9f3d2d508bfd9fb5b54e82994bda365a71eb864Zbigniew Jędrzejewski-Szmek r = manager_load_unit(m, name, NULL, &error, &u);
36f822c4bd077f9121757e24b6516e5c7ada63b5Zbigniew 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);
dab495dc23bf9a5ba0487a057bb594355555a0e9Tom Gundersen r = manager_add_job(m, JOB_START, u, JOB_REPLACE, true, &error, NULL);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen /* Successfully queued, that's it for us */
f8a0bb5285024b6ce372c3157e761e6543ebdcd2Andreas Henriksson 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);
f61942250a43a123580d7bbe5d7873dc5118ed97Tom Gundersen return log_error_errno(r, "Failed to respond with to bus activation request: %m");
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersenstatic int mac_selinux_filter(sd_bus_message *message, void *userdata, sd_bus_error *error) {
2ad8416dd057e7e3185169609ca3006e7649f576Zbigniew Jędrzejewski-Szmek /* Our own method calls are all protected individually with
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen * selinux checks, but the built-in interfaces need to be
2ad8416dd057e7e3185169609ca3006e7649f576Zbigniew Jędrzejewski-Szmek * protected too. */
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt 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))
2ad8416dd057e7e3185169609ca3006e7649f576Zbigniew Jędrzejewski-Szmek if (object_path_startswith("/org/freedesktop/systemd1", path)) {
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen r = mac_selinux_access_check(message, verb, error);
3b64e4d4f40baac56148c7d333d6a0053358ec7aTom Gundersen if (streq_ptr(path, "/org/freedesktop/systemd1/unit/self")) {
3b64e4d4f40baac56148c7d333d6a0053358ec7aTom Gundersen _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
7eb08da4b388b920c8a894b1500c9cc7dc1f31efTom Gundersen r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
b3e013148603aa670bc2c060ac63d48e54d76fc2Tom Gundersen r = manager_get_job_from_dbus_path(m, path, &j);
32bc8adcd836baff68e4d0f53b9a382f358cccf8Tom Gundersen manager_load_unit_from_dbus_path(m, path, NULL, &u);
ca6038b89645c0c1bd547d6a420bf95eb3d6f4ccTom Gundersen r = mac_selinux_unit_access_check(u, message, verb, error);
32bc8adcd836baff68e4d0f53b9a382f358cccf8Tom Gundersenstatic int bus_job_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen r = manager_get_job_from_dbus_path(m, path, &j);
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersenstatic int find_unit(Manager *m, sd_bus *bus, const char *path, Unit **unit, sd_bus_error *error) {
3c9b886068d99e5d3cbabcac32a4decf37244c54Tom Gundersen if (streq_ptr(path, "/org/freedesktop/systemd1/unit/self")) {
3c9b886068d99e5d3cbabcac32a4decf37244c54Tom Gundersen _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen r = manager_load_unit_from_dbus_path(m, path, error, &u);
3c9b886068d99e5d3cbabcac32a4decf37244c54Tom Gundersenstatic int bus_unit_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
464cf22f17e0cf2d8bfa6d72b5e7a662d634f149Tom Gundersen return find_unit(m, bus, path, (Unit**) found, error);
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersenstatic int bus_unit_interface_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
3c9b886068d99e5d3cbabcac32a4decf37244c54Tom Gundersen if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface))
464cf22f17e0cf2d8bfa6d72b5e7a662d634f149Tom Gundersenstatic int bus_unit_cgroup_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface))
755bde375f4db393ad06e73340bfcf4d0cf91bb2Lennart Poetteringstatic 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))
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersenstatic int bus_exec_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))
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersenstatic int bus_kill_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))
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersenstatic int bus_job_enumerate(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
847a8a5fed4d265dfa659917515c6f9bd1b8d5c4Tom Gundersen unsigned k = 0;
464cf22f17e0cf2d8bfa6d72b5e7a662d634f149Tom Gundersenstatic int bus_unit_enumerate(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
04b67d49254d956d31bcfe80340fb9df7ed332d3Tom Gundersen unsigned k = 0;
*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)
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);