proxy.c revision de865432f887e68ac7add166cf618c88431d6538
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering/***
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering This file is part of systemd.
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering Copyright 2010 Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering Copyright 2013 Daniel Mack
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering Copyright 2014 Kay Sievers
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering Copyright 2014 David Herrmann
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering systemd is free software; you can redistribute it and/or modify it
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering under the terms of the GNU Lesser General Public License as published by
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering (at your option) any later version.
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering systemd is distributed in the hope that it will be useful, but
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering Lesser General Public License for more details.
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering You should have received a copy of the GNU Lesser General Public License
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering***/
4871690d9e32608bbd9b18505b5326c2079c9690Allin Cottrell
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering#include <sys/socket.h>
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering#include <sys/types.h>
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering#include <string.h>
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering#include <errno.h>
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering#include <poll.h>
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering#include "log.h"
d025f1e4dca8fc1436aff76f9e6185fe3e728daaZbigniew Jędrzejewski-Szmek#include "util.h"
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering#include "sd-daemon.h"
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering#include "sd-bus.h"
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering#include "bus-internal.h"
3b7124a8db56ed57525b9ecfd19cfdc8c9facba0Lennart Poettering#include "bus-message.h"
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering#include "bus-util.h"
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering#include "strv.h"
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering#include "bus-control.h"
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering#include "set.h"
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering#include "bus-xml-policy.h"
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering#include "driver.h"
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering#include "proxy.h"
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering#include "synthesize.h"
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering#include "formats-util.h"
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poetteringstatic int proxy_create_destination(Proxy *p, const char *destination, const char *local_sec, bool negotiate_fds) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering _cleanup_bus_flush_close_unref_ sd_bus *b = NULL;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering int r;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering r = sd_bus_new(&b);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (r < 0)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return log_error_errno(r, "Failed to allocate bus: %m");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering r = sd_bus_set_description(b, "sd-proxy");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (r < 0)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return log_error_errno(r, "Failed to set bus name: %m");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering r = sd_bus_set_address(b, destination);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (r < 0)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return log_error_errno(r, "Failed to set address to connect to: %m");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering r = sd_bus_negotiate_fds(b, negotiate_fds);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (r < 0)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return log_error_errno(r, "Failed to set FD negotiation: %m");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart 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);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (r < 0)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return log_error_errno(r, "Failed to set credential negotiation: %m");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (p->local_creds.pid > 0) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering b->fake_pids.pid = p->local_creds.pid;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering b->fake_pids_valid = true;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering b->fake_creds.uid = UID_INVALID;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering b->fake_creds.euid = p->local_creds.uid;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering b->fake_creds.suid = UID_INVALID;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering b->fake_creds.fsuid = UID_INVALID;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering b->fake_creds.gid = GID_INVALID;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering b->fake_creds.egid = p->local_creds.gid;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering b->fake_creds.sgid = GID_INVALID;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering b->fake_creds.fsgid = GID_INVALID;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering b->fake_creds_valid = true;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering }
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (local_sec) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering b->fake_label = strdup(local_sec);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (!b->fake_label)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return log_oom();
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering }
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering b->manual_peer_interface = true;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering r = sd_bus_start(b);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (r < 0)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return log_error_errno(r, "Failed to start bus client: %m");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering p->destination_bus = b;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering b = NULL;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return 0;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering}
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poetteringstatic int proxy_create_local(Proxy *p, int in_fd, int out_fd, bool negotiate_fds) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering _cleanup_bus_flush_close_unref_ sd_bus *b = NULL;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering sd_id128_t server_id;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering int r;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering r = sd_bus_new(&b);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (r < 0)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return log_error_errno(r, "Failed to allocate bus: %m");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering r = sd_bus_set_fd(b, in_fd, out_fd);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (r < 0)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return log_error_errno(r, "Failed to set fds: %m");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering r = sd_bus_get_bus_id(p->destination_bus, &server_id);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (r < 0)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return log_error_errno(r, "Failed to get server ID: %m");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering r = sd_bus_set_server(b, 1, server_id);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (r < 0)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return log_error_errno(r, "Failed to set server mode: %m");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering r = sd_bus_negotiate_fds(b, negotiate_fds);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (r < 0)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return log_error_errno(r, "Failed to set FD negotiation: %m");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart 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);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (r < 0)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return log_error_errno(r, "Failed to set credential negotiation: %m");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering r = sd_bus_set_anonymous(b, true);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (r < 0)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return log_error_errno(r, "Failed to set anonymous authentication: %m");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering b->manual_peer_interface = true;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering r = sd_bus_start(b);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (r < 0)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return log_error_errno(r, "Failed to start bus client: %m");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering p->local_bus = b;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering b = NULL;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return 0;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering}
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poetteringstatic int proxy_prepare_matches(Proxy *p) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering _cleanup_free_ char *match = NULL;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering const char *unique;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering int r;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (!p->destination_bus->is_kernel)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return 0;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering r = sd_bus_get_unique_name(p->destination_bus, &unique);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (r < 0)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return log_error_errno(r, "Failed to get unique name: %m");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering match = strjoin("type='signal',"
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering "sender='org.freedesktop.DBus',"
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering "path='/org/freedesktop/DBus',"
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering "interface='org.freedesktop.DBus',"
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering "member='NameOwnerChanged',"
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering "arg1='",
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering unique,
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering "'",
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering NULL);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (!match)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return log_oom();
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering r = sd_bus_add_match(p->destination_bus, NULL, match, NULL, NULL);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (r < 0)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return log_error_errno(r, "Failed to add match for NameLost: %m");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering free(match);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering match = strjoin("type='signal',"
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering "sender='org.freedesktop.DBus',"
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering "path='/org/freedesktop/DBus',"
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering "interface='org.freedesktop.DBus',"
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering "member='NameOwnerChanged',"
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering "arg2='",
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering unique,
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering "'",
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering NULL);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (!match)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return log_oom();
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering r = sd_bus_add_match(p->destination_bus, NULL, match, NULL, NULL);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (r < 0)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return log_error_errno(r, "Failed to add match for NameAcquired: %m");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering free(match);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering match = strjoin("type='signal',"
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering "destination='",
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering unique,
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering "'",
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering NULL);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (!match)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return log_oom();
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering r = sd_bus_add_match(p->destination_bus, NULL, match, NULL, NULL);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (r < 0)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering log_error_errno(r, "Failed to add match for NameAcquired: %m");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return 0;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering}
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poetteringint proxy_new(Proxy **out, int in_fd, int out_fd, const char *destination) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering _cleanup_(proxy_freep) Proxy *p = NULL;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering _cleanup_free_ char *local_sec = NULL;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering bool is_unix;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering int r;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering p = new0(Proxy, 1);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (!p)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return log_oom();
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering p->local_in = in_fd;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering p->local_out = out_fd;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering p->owned_names = set_new(&string_hash_ops);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (!p->owned_names)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return log_oom();
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering is_unix = sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (is_unix) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering (void) getpeercred(in_fd, &p->local_creds);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering (void) getpeersec(in_fd, &local_sec);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering }
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering r = proxy_create_destination(p, destination, local_sec, is_unix);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (r < 0)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return r;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering r = proxy_create_local(p, in_fd, out_fd, is_unix);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (r < 0)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return r;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering r = proxy_prepare_matches(p);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (r < 0)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return r;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering *out = p;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering p = NULL;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return 0;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering}
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart PoetteringProxy *proxy_free(Proxy *p) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (!p)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return NULL;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering sd_bus_flush_close_unref(p->local_bus);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering sd_bus_flush_close_unref(p->destination_bus);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering set_free_free(p->owned_names);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering free(p);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return NULL;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering}
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poetteringint proxy_set_policy(Proxy *p, SharedPolicy *sp, char **configuration) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering _cleanup_strv_free_ char **strv = NULL;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering Policy *policy;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering int r;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering assert(p);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering assert(sp);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering /* no need to load legacy policy if destination is not kdbus */
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (!p->destination_bus->is_kernel)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return 0;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering p->policy = sp;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering policy = shared_policy_acquire(sp);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (policy) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering /* policy already pre-loaded */
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering shared_policy_release(sp, policy);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return 0;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering }
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (!configuration) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering const char *scope;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering r = sd_bus_get_scope(p->destination_bus, &scope);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (r < 0)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return log_error_errno(r, "Couldn't determine bus scope: %m");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (streq(scope, "system"))
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering strv = strv_new("/usr/share/dbus-1/system.conf",
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering "/etc/dbus-1/system.conf",
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering "/usr/share/dbus-1/system.d/",
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering "/etc/dbus-1/system.d/",
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering "/etc/dbus-1/system-local.conf",
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering NULL);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering else if (streq(scope, "user"))
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering strv = strv_new("/usr/share/dbus-1/session.conf",
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering "/etc/dbus-1/session.conf",
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering "/usr/share/dbus-1/session.d/",
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering "/etc/dbus-1/session.d/",
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering "/etc/dbus-1/session-local.conf",
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering NULL);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering else
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return log_error("Unknown scope %s, don't know which policy to load. Refusing.", scope);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (!strv)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return log_oom();
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering configuration = strv;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering }
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return shared_policy_preload(sp, configuration);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering}
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poetteringint proxy_hello_policy(Proxy *p, uid_t original_uid) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering Policy *policy;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering int r = 0;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering assert(p);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (!p->policy)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return 0;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering policy = shared_policy_acquire(p->policy);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (p->local_creds.uid == original_uid)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering log_debug("Permitting access, since bus owner matches bus client.");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering else if (policy_check_hello(policy, p->local_creds.uid, p->local_creds.gid))
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering log_debug("Permitting access due to XML policy.");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering else
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering r = log_error_errno(EPERM, "Policy denied connection.");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering shared_policy_release(p->policy, policy);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return r;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering}
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poetteringstatic int proxy_wait(Proxy *p) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering uint64_t timeout_destination, timeout_local, t;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering int events_destination, events_local, fd;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering struct timespec _ts, *ts;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering struct pollfd *pollfd;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering int r;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering assert(p);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering fd = sd_bus_get_fd(p->destination_bus);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (fd < 0)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return log_error_errno(fd, "Failed to get fd: %m");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering events_destination = sd_bus_get_events(p->destination_bus);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (events_destination < 0)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return log_error_errno(events_destination, "Failed to get events mask: %m");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering r = sd_bus_get_timeout(p->destination_bus, &timeout_destination);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (r < 0)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return log_error_errno(r, "Failed to get timeout: %m");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering events_local = sd_bus_get_events(p->local_bus);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (events_local < 0)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return log_error_errno(events_local, "Failed to get events mask: %m");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering r = sd_bus_get_timeout(p->local_bus, &timeout_local);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (r < 0)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return log_error_errno(r, "Failed to get timeout: %m");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering t = timeout_destination;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (t == (uint64_t) -1 || (timeout_local != (uint64_t) -1 && timeout_local < timeout_destination))
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering t = timeout_local;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (t == (uint64_t) -1)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering ts = NULL;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering else {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering usec_t nw;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering nw = now(CLOCK_MONOTONIC);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (t > nw)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering t -= nw;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering else
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering t = 0;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering ts = timespec_store(&_ts, t);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering }
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering pollfd = (struct pollfd[3]) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering { .fd = fd, .events = events_destination, },
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering { .fd = p->local_in, .events = events_local & POLLIN, },
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering { .fd = p->local_out, .events = events_local & POLLOUT, },
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering };
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering r = ppoll(pollfd, 3, ts, NULL);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (r < 0)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return log_error_errno(errno, "ppoll() failed: %m");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return 0;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering}
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poetteringstatic int handle_policy_error(sd_bus_message *m, int r) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (r == -ESRCH || r == -ENXIO)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return synthetic_reply_method_errorf(m, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", m->destination);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return r;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering}
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poetteringstatic int process_policy_unlocked(sd_bus *from, sd_bus *to, sd_bus_message *m, Policy *policy, const struct ucred *our_ucred, Set *owned_names) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering int r;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering assert(from);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering assert(to);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering assert(m);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (!policy)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return 0;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering /*
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering * dbus-1 distinguishes expected and non-expected replies by tracking
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering * method-calls and timeouts. By default, DENY rules are *NEVER* applied
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering * on expected replies, unless explicitly specified. But we dont track
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering * method-calls, thus, we cannot know whether a reply is expected.
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering * Fortunately, the kdbus forbids non-expected replies, so we can safely
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering * ignore any policy on those and let the kernel deal with it.
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering *
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering * TODO: To be correct, we should only ignore policy-tags that are
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering * applied on non-expected replies. However, so far we don't parse those
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering * tags so we let everything pass. I haven't seen a DENY policy tag on
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering * expected-replies, ever, so don't bother..
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering */
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (m->reply_cookie > 0)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return 0;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (from->is_kernel) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering uid_t sender_uid = UID_INVALID;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering gid_t sender_gid = GID_INVALID;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering char **sender_names = NULL;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering /* Driver messages are always OK */
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (streq_ptr(m->sender, "org.freedesktop.DBus"))
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return 0;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering /* The message came from the kernel, and is sent to our legacy client. */
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering (void) sd_bus_creds_get_well_known_names(&m->creds, &sender_names);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering (void) sd_bus_creds_get_euid(&m->creds, &sender_uid);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering (void) sd_bus_creds_get_egid(&m->creds, &sender_gid);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (sender_uid == UID_INVALID || sender_gid == GID_INVALID) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering _cleanup_bus_creds_unref_ sd_bus_creds *sender_creds = NULL;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering /* If the message came from another legacy
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering * client, then the message creds will be
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering * missing, simply because on legacy clients
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering * per-message creds were unknown. In this
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering * case, query the creds of the peer
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering * instead. */
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering r = bus_get_name_creds_kdbus(from, m->sender, SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID, true, &sender_creds);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (r < 0)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return handle_policy_error(m, r);
(void) sd_bus_creds_get_euid(sender_creds, &sender_uid);
(void) sd_bus_creds_get_egid(sender_creds, &sender_gid);
}
/* First check whether the sender can send the message to our name */
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 0;
/* Return an error back to the caller */
if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
return synthetic_reply_method_errorf(m, SD_BUS_ERROR_ACCESS_DENIED, "Access prohibited by XML receiver policy.");
/* Return 1, indicating that the message shall not be processed any further */
return 1;
}
if (to->is_kernel) {
_cleanup_bus_creds_unref_ sd_bus_creds *destination_creds = NULL;
uid_t destination_uid = UID_INVALID;
gid_t destination_gid = GID_INVALID;
const char *destination_unique = NULL;
char **destination_names = NULL;
char *n;
/* Driver messages are always OK */
if (streq_ptr(m->destination, "org.freedesktop.DBus"))
return 0;
/* The message came from the legacy client, and is sent to kdbus. */
if (m->destination) {
r = bus_get_name_creds_kdbus(to, m->destination,
SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME|
SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_PID,
true, &destination_creds);
if (r < 0)
return handle_policy_error(m, r);
r = sd_bus_creds_get_unique_name(destination_creds, &destination_unique);
if (r < 0)
return handle_policy_error(m, r);
(void) sd_bus_creds_get_well_known_names(destination_creds, &destination_names);
(void) sd_bus_creds_get_euid(destination_creds, &destination_uid);
(void) sd_bus_creds_get_egid(destination_creds, &destination_gid);
}
/* First check if we (the sender) can send to this name */
if (sd_bus_message_is_signal(m, NULL, NULL)) {
/* If we forward a signal from dbus-1 to kdbus, we have
* no idea who the recipient is. Therefore, we cannot
* apply any dbus-1 policies that match on receiver
* credentials. We know sd-bus always sets
* KDBUS_MSG_SIGNAL, so the kernel applies policies to
* the message. Therefore, skip policy checks in this
* case. */
return 0;
} else 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)) {
if (n) {
/* If we made a receiver decision, then remember which
* name's policy we used, and to which unique ID it
* mapped when we made the decision. Then, let's pass
* this to the kernel when sending the message, so that
* it refuses the operation should the name and unique
* ID not map to each other anymore. */
r = free_and_strdup(&m->destination_ptr, n);
if (r < 0)
return r;
r = bus_kernel_parse_unique_name(destination_unique, &m->verify_destination_id);
if (r < 0)
return r;
}
if (policy_check_recv(policy, destination_uid, destination_gid, m->header->type, owned_names, NULL, m->path, m->interface, m->member, true))
return 0;
}
/* Return an error back to the caller */
if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
return synthetic_reply_method_errorf(m, SD_BUS_ERROR_ACCESS_DENIED, "Access prohibited by XML sender policy.");
/* Return 1, indicating that the message shall not be processed any further */
return 1;
}
return 0;
}
static int process_policy(sd_bus *from, sd_bus *to, sd_bus_message *m, SharedPolicy *sp, const struct ucred *our_ucred, Set *owned_names) {
Policy *policy;
int r;
assert(sp);
policy = shared_policy_acquire(sp);
r = process_policy_unlocked(from, to, m, policy, our_ucred, owned_names);
shared_policy_release(sp, policy);
return r;
}
static int process_hello(Proxy *p, sd_bus_message *m) {
_cleanup_bus_message_unref_ sd_bus_message *n = NULL;
bool is_hello;
int r;
assert(p);
assert(m);
/* As reaction to hello we need to respond with two messages:
* the callback reply and the NameAcquired for the unique
* name, since hello is otherwise obsolete on kdbus. */
is_hello =
sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") &&
streq_ptr(m->destination, "org.freedesktop.DBus");
if (!is_hello) {
if (p->got_hello)
return 0;
return log_error_errno(EIO, "First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member);
}
if (p->got_hello)
return log_error_errno(EIO, "Got duplicate hello, aborting.");
p->got_hello = true;
if (!p->destination_bus->is_kernel)
return 0;
r = sd_bus_message_new_method_return(m, &n);
if (r < 0)
return log_error_errno(r, "Failed to generate HELLO reply: %m");
r = sd_bus_message_append(n, "s", p->destination_bus->unique_name);
if (r < 0)
return log_error_errno(r, "Failed to append unique name to HELLO reply: %m");
r = bus_message_append_sender(n, "org.freedesktop.DBus");
if (r < 0)
return log_error_errno(r, "Failed to append sender to HELLO reply: %m");
r = bus_seal_synthetic_message(p->local_bus, n);
if (r < 0)
return log_error_errno(r, "Failed to seal HELLO reply: %m");
r = sd_bus_send(p->local_bus, n, NULL);
if (r < 0)
return log_error_errno(r, "Failed to send HELLO reply: %m");
n = sd_bus_message_unref(n);
r = sd_bus_message_new_signal(
p->local_bus,
&n,
"/org/freedesktop/DBus",
"org.freedesktop.DBus",
"NameAcquired");
if (r < 0)
return log_error_errno(r, "Failed to allocate initial NameAcquired message: %m");
r = sd_bus_message_append(n, "s", p->destination_bus->unique_name);
if (r < 0)
return log_error_errno(r, "Failed to append unique name to NameAcquired message: %m");
r = bus_message_append_sender(n, "org.freedesktop.DBus");
if (r < 0)
return log_error_errno(r, "Failed to append sender to NameAcquired message: %m");
r = bus_seal_synthetic_message(p->local_bus, n);
if (r < 0)
return log_error_errno(r, "Failed to seal NameAcquired message: %m");
r = sd_bus_send(p->local_bus, n, NULL);
if (r < 0)
return log_error_errno(r, "Failed to send NameAcquired message: %m");
return 1;
}
static int patch_sender(sd_bus *a, sd_bus_message *m) {
char **well_known = NULL;
sd_bus_creds *c;
int r;
assert(a);
assert(m);
if (!a->is_kernel)
return 0;
/* We will change the sender of messages from the bus driver
* so that they originate from the bus driver. This is a
* speciality originating from dbus1, where the bus driver did
* not have a unique id, but only the well-known name. */
c = sd_bus_message_get_creds(m);
if (!c)
return 0;
r = sd_bus_creds_get_well_known_names(c, &well_known);
if (r < 0)
return r;
if (strv_contains(well_known, "org.freedesktop.DBus"))
m->sender = "org.freedesktop.DBus";
return 0;
}
static int proxy_process_destination_to_local(Proxy *p) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
int r;
assert(p);
r = sd_bus_process(p->destination_bus, &m);
if (r == -ECONNRESET || r == -ENOTCONN) /* Treat 'connection reset by peer' as clean exit condition */
return r;
if (r < 0) {
log_error_errno(r, "Failed to process destination bus: %m");
return r;
}
if (r == 0)
return 0;
if (!m)
return 1;
/* We officially got EOF, let's quit */
if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected"))
return -ECONNRESET;
r = synthesize_name_acquired(p->destination_bus, p->local_bus, m);
if (r == -ECONNRESET || r == -ENOTCONN)
return r;
if (r < 0)
return log_error_errno(r, "Failed to synthesize message: %m");
patch_sender(p->destination_bus, m);
if (p->policy) {
r = process_policy(p->destination_bus, p->local_bus, m, p->policy, &p->local_creds, p->owned_names);
if (r == -ECONNRESET || r == -ENOTCONN)
return r;
if (r < 0)
return log_error_errno(r, "Failed to process policy: %m");
if (r > 0)
return 1;
}
r = sd_bus_send(p->local_bus, m, NULL);
if (r < 0) {
if (r == -ECONNRESET || r == -ENOTCONN)
return r;
/* If the peer tries to send a reply and it is
* rejected with EPERM by the kernel, we ignore the
* error. This catches cases where the original
* method-call didn't had EXPECT_REPLY set, but the
* proxy-peer still sends a reply. This is allowed in
* dbus1, but not in kdbus. We don't want to track
* reply-windows in the proxy, so we simply ignore
* EPERM for all replies. The only downside is, that
* callers are no longer notified if their replies are
* dropped. However, this is equivalent to the
* caller's timeout to expire, so this should be
* acceptable. Nobody sane sends replies without a
* matching method-call, so nobody should care. */
if (r == -EPERM && m->reply_cookie > 0)
return 1;
/* Return the error to the client, if we can */
synthetic_reply_method_errnof(m, r, "Failed to forward message we got from destination: %m");
if (r == -ENOBUFS) {
/* if local dbus1 peer does not dispatch its queue, warn only once */
if (!p->queue_overflow)
log_error("Dropped messages due to queue overflow of local peer (pid: "PID_FMT" uid: "UID_FMT")", p->local_creds.pid, p->local_creds.uid);
p->queue_overflow = true;
} else
log_error_errno(r,
"Failed to forward message we got from destination: uid=" UID_FMT " gid=" GID_FMT" message=%s destination=%s path=%s interface=%s member=%s: %m",
p->local_creds.uid, p->local_creds.gid, bus_message_type_to_string(m->header->type),
strna(m->destination), strna(m->path), strna(m->interface), strna(m->member));
return 1;
}
p->queue_overflow = false;
return 1;
}
static int proxy_process_local_to_destination(Proxy *p) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
int r;
assert(p);
r = sd_bus_process(p->local_bus, &m);
if (r == -ECONNRESET || r == -ENOTCONN) /* Treat 'connection reset by peer' as clean exit condition */
return r;
if (r < 0) {
log_error_errno(r, "Failed to process local bus: %m");
return r;
}
if (r == 0)
return 0;
if (!m)
return 1;
/* We officially got EOF, let's quit */
if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected"))
return -ECONNRESET;
r = process_hello(p, m);
if (r == -ECONNRESET || r == -ENOTCONN)
return r;
if (r < 0)
return log_error_errno(r, "Failed to process HELLO: %m");
if (r > 0)
return 1;
r = bus_proxy_process_driver(p->destination_bus, p->local_bus, m, p->policy, &p->local_creds, p->owned_names);
if (r == -ECONNRESET || r == -ENOTCONN)
return r;
if (r < 0)
return log_error_errno(r, "Failed to process driver calls: %m");
if (r > 0)
return 1;
for (;;) {
if (p->policy) {
r = process_policy(p->local_bus, p->destination_bus, m, p->policy, &p->local_creds, p->owned_names);
if (r == -ECONNRESET || r == -ENOTCONN)
return r;
if (r < 0)
return log_error_errno(r, "Failed to process policy: %m");
if (r > 0)
return 1;
}
r = sd_bus_send(p->destination_bus, m, NULL);
if (r < 0) {
if (r == -ECONNRESET || r == -ENOTCONN)
return r;
/* The name database changed since the policy check, hence let's check again */
if (r == -EREMCHG)
continue;
/* see above why EPERM is ignored for replies */
if (r == -EPERM && m->reply_cookie > 0)
return 1;
synthetic_reply_method_errnof(m, r, "Failed to forward message we got from local: %m");
log_error_errno(r,
"Failed to forward message we got from local: uid=" UID_FMT " gid=" GID_FMT" message=%s destination=%s path=%s interface=%s member=%s: %m",
p->local_creds.uid, p->local_creds.gid, bus_message_type_to_string(m->header->type),
strna(m->destination), strna(m->path), strna(m->interface), strna(m->member));
return 1;
}
break;
}
return 1;
}
int proxy_run(Proxy *p) {
int r;
assert(p);
for (;;) {
bool busy = false;
if (p->got_hello) {
/* Read messages from bus, to pass them on to our client */
r = proxy_process_destination_to_local(p);
if (r == -ECONNRESET || r == -ENOTCONN)
return 0;
if (r < 0)
return r;
if (r > 0)
busy = true;
}
/* Read messages from our client, to pass them on to the bus */
r = proxy_process_local_to_destination(p);
if (r == -ECONNRESET || r == -ENOTCONN)
return 0;
if (r < 0)
return r;
if (r > 0)
busy = true;
if (!busy) {
r = proxy_wait(p);
if (r == -ECONNRESET || r == -ENOTCONN)
return 0;
if (r < 0)
return r;
}
}
return 0;
}