proxy.c revision d90c154eb180783098683ce8e1c03cd29d9b77ce
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering This file is part of systemd.
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering Copyright 2010 Lennart Poettering
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering Copyright 2013 Daniel Mack
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering Copyright 2014 Kay Sievers
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering Copyright 2014 David Herrmann
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering systemd is free software; you can redistribute it and/or modify it
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering under the terms of the GNU Lesser General Public License as published by
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering (at your option) any later version.
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering systemd is distributed in the hope that it will be useful, but
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering Lesser General Public License for more details.
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering You should have received a copy of the GNU Lesser General Public License
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poetteringstatic int proxy_create_destination(Proxy *p, const char *destination, const char *local_sec, bool negotiate_fds) {
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering _cleanup_bus_close_unref_ sd_bus *b = NULL;
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering return log_error_errno(r, "Failed to allocate bus: %m");
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering r = sd_bus_set_description(b, "sd-proxy");
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering return log_error_errno(r, "Failed to set bus name: %m");
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering return log_error_errno(r, "Failed to set address to connect to: %m");
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering r = sd_bus_negotiate_fds(b, negotiate_fds);
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering return log_error_errno(r, "Failed to set FD negotiation: %m");
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering r = sd_bus_negotiate_creds(b, true, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SELINUX_CONTEXT);
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering return log_error_errno(r, "Failed to set credential negotiation: %m");
b->fake_creds_valid = true;
if (local_sec) {
if (!b->fake_label)
return log_oom();
b->manual_peer_interface = true;
r = sd_bus_start(b);
p->destination_bus = b;
b = NULL;
r = sd_bus_new(&b);
r = sd_bus_negotiate_creds(b, true, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SELINUX_CONTEXT);
r = sd_bus_set_anonymous(b, true);
b->manual_peer_interface = true;
r = sd_bus_start(b);
p->local_bus = b;
b = NULL;
const char *unique;
"path='/org/freedesktop/DBus',"
NULL);
if (!match)
return log_oom();
"path='/org/freedesktop/DBus',"
NULL);
if (!match)
return log_oom();
bool is_unix;
return log_oom();
if (!p->owned_names)
return log_oom();
if (is_unix) {
r = proxy_prepare_matches(p);
*out = p;
p = NULL;
return NULL;
free(p);
return NULL;
assert(p);
if (policy) {
if (!configuration) {
const char *scope;
NULL);
NULL);
if (!strv)
return log_oom();
assert(p);
if (!p->policy)
assert(p);
if (fd < 0)
if (events_destination < 0)
if (events_local < 0)
t = timeout_destination;
t = timeout_local;
if (t > nw)
t -= nw;
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_unlocked(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)
r = bus_get_name_creds_kdbus(from, m->sender, SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID, true, &sender_creds);
return handle_policy_error(m, r);
if (policy_check_send(policy, sender_uid, sender_gid, m->header->type, owned_names, NULL, m->path, m->interface, m->member, false, NULL) &&
policy_check_recv(policy, our_ucred->uid, our_ucred->gid, m->header->type, NULL, sender_names, m->path, m->interface, m->member, false))
return synthetic_reply_method_errorf(m, SD_BUS_ERROR_ACCESS_DENIED, "Access prohibited by XML receiver policy.");
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, destination_names, m->path, m->interface, m->member, true, &n)) {
} else if (policy_check_recv(policy, destination_uid, destination_gid, m->header->type, owned_names, NULL, m->path, m->interface, m->member, true)) {
return synthetic_reply_method_errorf(m, SD_BUS_ERROR_ACCESS_DENIED, "Access prohibited by XML sender policy.");
static int process_policy(sd_bus *from, sd_bus *to, sd_bus_message *m, SharedPolicy *sp, const struct ucred *our_ucred, Set *owned_names) {
bool is_hello;
assert(p);
assert(m);
is_hello =
if (!is_hello) {
if (p->got_hello)
return log_error_errno(EIO, "First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member);
if (p->got_hello)
p->got_hello = true;
r = sd_bus_message_new_method_return(m, &n);
n = sd_bus_message_unref(n);
p->local_bus,
"/org/freedesktop/DBus",
sd_bus_creds *c;
assert(a);
assert(m);
if (!a->is_kernel)
c = sd_bus_message_get_creds(m);
assert(p);
if (r == -ECONNRESET || r == -ENOTCONN) /* Treat 'connection reset by peer' as clean exit condition */
return -ECONNRESET;
if (p->policy) {
r = process_policy(p->destination_bus, p->local_bus, m, p->policy, &p->local_creds, p->owned_names);
assert(p);
if (r == -ECONNRESET || r == -ENOTCONN) /* Treat 'connection reset by peer' as clean exit condition */
return -ECONNRESET;
r = process_hello(p, m);
r = bus_proxy_process_driver(p->destination_bus, p->local_bus, m, p->policy, &p->local_creds, p->owned_names);
if (p->policy) {
r = process_policy(p->local_bus, p->destination_bus, m, p->policy, &p->local_creds, p->owned_names);
if (r == -EREMCHG)
assert(p);
bool busy = false;
if (p->got_hello) {
busy = true;
busy = true;
if (!busy) {
r = proxy_wait(p);