bus-proxyd.c revision b49c7806a395fd655edd19785f56874b28f5a24c
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen This file is part of systemd.
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen Copyright 2010 Lennart Poettering
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen Copyright 2013 Daniel Mack
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen Copyright 2014 Kay Sievers
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen systemd is free software; you can redistribute it and/or modify it
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen under the terms of the GNU Lesser General Public License as published by
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen the Free Software Foundation; either version 2.1 of the License, or
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen (at your option) any later version.
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen systemd is distributed in the hope that it will be useful, but
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen WITHOUT ANY WARRANTY; without even the implied warranty of
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen Lesser General Public License for more details.
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen You should have received a copy of the GNU Lesser General Public License
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen along with systemd; If not, see <http://www.gnu.org/licenses/>.
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensenstatic char *arg_command_line_buffer = NULL;
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensenstatic bool arg_drop_privileges = false;
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensenstatic char **arg_configuration = NULL;
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensenstatic int help(void) {
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen "Connect STDIO or a socket to a given bus address.\n\n"
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen " -h --help Show this help\n"
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen " --version Show package version\n"
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen " --drop-privileges Drop privileges\n"
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen " --configuration=PATH Configuration file or directory\n"
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen " --machine=MACHINE Connect to specified machine\n"
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen " --address=ADDRESS Connect to the bus specified by ADDRESS\n"
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen " (default: " DEFAULT_SYSTEM_BUS_ADDRESS ")\n",
help();
case ARG_VERSION:
case ARG_ADDRESS: {
return log_oom();
arg_address = a;
case ARG_DROP_PRIVILEGES:
arg_drop_privileges = true;
case ARG_CONFIGURATION:
return log_oom();
case ARG_MACHINE: {
return log_oom();
#ifdef ENABLE_KDBUS
return log_oom();
arg_address = a;
return -EINVAL;
return -EINVAL;
if (!arg_address) {
if (!arg_address)
return log_oom();
const char *comm;
char **cmdline;
assert(a);
assert(b);
r = sd_bus_get_owner_creds(b, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_COMM|SD_BUS_CREDS_AUGMENT, &creds);
if (!name)
return -ENOMEM;
return -ENOMEM;
sd_notifyf(false,
pid, p,
if (arg_command_line_buffer) {
size_t m, w;
pid, p,
a->unique_name);
assert(a);
assert(b);
assert(m);
* synthesize NameLost/NameAcquired, since socket clients need
if (!a->is_kernel)
r = sd_bus_message_rewind(m, true);
"/org/freedesktop/DBus",
"/org/freedesktop/DBus",
r = bus_seal_synthetic_message(b, n);
assert(b);
assert(m);
r = bus_seal_synthetic_message(b, m);
static int synthetic_reply_method_errorf(sd_bus_message *call, const char *name, const char *format, ...) {
if (sd_bus_error_is_set(p))
r = sd_bus_message_append_strv(m, l);
static int get_creds_by_name(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
return sd_bus_error_setf(error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", name);
return -ENOTSUP;
*_creds = c;
c = NULL;
static int get_creds_by_message(sd_bus *bus, sd_bus_message *m, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
const char *name;
assert(m);
static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m, Policy *policy, const struct ucred *ucred, Set *owned_names) {
assert(a);
assert(b);
assert(m);
if (!a->is_kernel)
return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
const char *match;
return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
const char *match;
return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_MATCH_RULE_NOT_FOUND, "Match rule not found"));
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionSELinuxSecurityContext")) {
return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixProcessID")) {
return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
const char *name;
return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
char *arg0;
int err = 0;
return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
sd_bus_error_setf(&error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Could not get owners of name '%s': no such name.", arg0);
err = r;
if (err < 0)
const char *name;
return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
const char *name;
return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
if (r == -ESRCH)
if (r == -EADDRINUSE)
return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
r = sd_bus_error_setf(&error, SD_BUS_ERROR_NOT_SUPPORTED, "%s() is not supported", sd_bus_message_get_member(m));
const char *name;
bool in_queue;
return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
param = 0;
if (r == -EALREADY)
if (r == -EEXIST)
in_queue = (r == 0);
if (in_queue)
const char *name;
return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
if (flags != 0)
if (r != -ESRCH)
&msg,
name,
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "UpdateActivationEnvironment")) {
return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
const char *key;
const char *value;
r = sd_bus_message_exit_container(m);
r = sd_bus_message_exit_container(m);
if (!args)
&msg,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
return synthetic_reply_method_errorf(m, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", m->destination);
static int process_policy(sd_bus *from, sd_bus *to, sd_bus_message *m, Policy *policy, const struct ucred *our_ucred, Set *owned_names) {
assert(m);
if (!policy)
if (m->reply_cookie > 0)
bool granted = false;
r = bus_get_name_creds_kdbus(from, m->sender, SD_BUS_CREDS_UID|SD_BUS_CREDS_GID, true, &sender_creds);
return handle_policy_error(m, r);
if (policy_check_send(policy, sender_uid, sender_gid, m->header->type, NULL, m->path, m->interface, m->member, false))
granted = true;
Iterator i;
if (policy_check_send(policy, sender_uid, sender_gid, m->header->type, n, m->path, m->interface, m->member, false)) {
granted = true;
if (granted) {
if (policy_check_recv(policy, our_ucred->uid, our_ucred->gid, m->header->type, NULL, m->path, m->interface, m->member, false))
if (policy_check_recv(policy, our_ucred->uid, our_ucred->gid, m->header->type, *n, m->path, m->interface, m->member, false))
return synthetic_reply_method_errorf(m, SD_BUS_ERROR_ACCESS_DENIED, "Access prohibited by XML receiver policy.");
bool granted = false;
if (m->destination) {
true, &destination_creds);
return handle_policy_error(m, r);
return handle_policy_error(m, r);
if (policy_check_send(policy, our_ucred->uid, our_ucred->gid, m->header->type, NULL, m->path, m->interface, m->member, true))
granted = true;
if (policy_check_send(policy, our_ucred->uid, our_ucred->gid, m->header->type, *n, m->path, m->interface, m->member, true)) {
granted = true;
if (granted) {
if (policy_check_recv(policy, destination_uid, destination_gid, m->header->type, NULL, m->path, m->interface, m->member, true))
Iterator i;
if (policy_check_recv(policy, destination_uid, destination_gid, m->header->type, n, m->path, m->interface, m->member, true))
return synthetic_reply_method_errorf(m, SD_BUS_ERROR_ACCESS_DENIED, "Access prohibited by XML sender policy.");
bool is_hello;
assert(a);
assert(b);
assert(m);
is_hello =
if (!is_hello) {
if (*got_hello)
return -EIO;
if (*got_hello) {
return -EIO;
*got_hello = true;
if (!a->is_kernel)
r = sd_bus_message_new_method_return(m, &n);
r = bus_seal_synthetic_message(b, n);
n = sd_bus_message_unref(n);
"/org/freedesktop/DBus",
r = bus_seal_synthetic_message(b, n);
sd_bus_creds *c;
assert(a);
assert(m);
if (!a->is_kernel)
c = sd_bus_message_get_creds(m);
#ifdef HAVE_SMACK
if (!mac_smack_use())
bool got_hello = false;
bool is_unix;
log_open();
goto finish;
r = sd_listen_fds(0);
goto finish;
is_unix =
if (is_unix) {
if (arg_drop_privileges) {
goto finish;
goto finish;
if (!owned_names) {
log_oom();
goto finish;
r = sd_bus_new(&a);
goto finish;
goto finish;
goto finish;
goto finish;
r = sd_bus_negotiate_creds(a, true, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_GID|SD_BUS_CREDS_SELINUX_CONTEXT);
goto finish;
a->fake_pids_valid = true;
a->fake_creds_valid = true;
if (peersec) {
a->manual_peer_interface = true;
r = sd_bus_start(a);
goto finish;
goto finish;
if (a->is_kernel) {
if (!arg_configuration) {
const char *scope;
goto finish;
"/etc/dbus-1/system.conf",
NULL);
"/etc/dbus-1/session.conf",
NULL);
goto finish;
if (!arg_configuration) {
r = log_oom();
goto finish;
goto finish;
goto finish;
r = sd_bus_new(&b);
goto finish;
goto finish;
goto finish;
goto finish;
r = sd_bus_negotiate_creds(b, true, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_GID|SD_BUS_CREDS_SELINUX_CONTEXT);
goto finish;
r = sd_bus_set_anonymous(b, true);
goto finish;
b->manual_peer_interface = true;
r = sd_bus_start(b);
goto finish;
r = rename_service(a, b);
if (a->is_kernel) {
const char *unique;
goto finish;
"path='/org/freedesktop/DBus',"
NULL);
if (!match) {
log_oom();
goto finish;
goto finish;
"path='/org/freedesktop/DBus',"
NULL);
if (!match) {
log_oom();
goto finish;
goto finish;
if (got_hello) {
r = sd_bus_process(a, &m);
if (r == -ECONNRESET)
goto finish;
bool processed = false;
goto finish;
k = synthesize_name_acquired(a, b, m);
goto finish;
patch_sender(a, m);
if (policy) {
goto finish;
processed = true;
if (!processed) {
if (k == -ECONNRESET) {
goto finish;
goto finish;
r = sd_bus_process(b, &m);
if (r == -ECONNRESET)
goto finish;
bool processed = false;
goto finish;
goto finish;
processed = true;
if (!processed) {
goto finish;
processed = true;
if (!processed) {
if (policy) {
goto finish;
processed = true;
if (k == -EREMCHG) {
} else if (k == -ECONNRESET) {
goto finish;
goto finish;
if (fd < 0) {
goto finish;
if (events_a < 0) {
goto finish;
goto finish;
if (events_b < 0) {
goto finish;
goto finish;
t = timeout_a;
t = timeout_b;
if (t > nw)
t -= nw;
goto finish;
sd_notify(false,