proxy.c revision 2c960818c8887386fce216a1bbbadbe8d35d59c3
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering This file is part of systemd.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Copyright 2010 Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Copyright 2013 Daniel Mack
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Copyright 2014 Kay Sievers
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Copyright 2014 David Herrmann
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is free software; you can redistribute it and/or modify it
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering under the terms of the GNU Lesser General Public License as published by
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering (at your option) any later version.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is distributed in the hope that it will be useful, but
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Lesser General Public License for more details.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering You should have received a copy of the GNU Lesser General Public License
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int proxy_create_destination(Proxy *p, const char *destination, const char *local_sec, bool negotiate_fds) {
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering _cleanup_bus_flush_close_unref_ sd_bus *b = NULL;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return log_error_errno(r, "Failed to allocate bus: %m");
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering r = sd_bus_set_description(b, "sd-proxy");
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return log_error_errno(r, "Failed to set bus name: %m");
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return log_error_errno(r, "Failed to set address to connect to: %m");
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering r = sd_bus_negotiate_fds(b, negotiate_fds);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return log_error_errno(r, "Failed to set FD negotiation: %m");
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart 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);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return log_error_errno(r, "Failed to set credential negotiation: %m");
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return log_error_errno(r, "Failed to start bus client: %m");
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poetteringstatic int proxy_create_local(Proxy *p, int in_fd, int out_fd, bool negotiate_fds) {
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering _cleanup_bus_flush_close_unref_ sd_bus *b = NULL;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return log_error_errno(r, "Failed to allocate bus: %m");
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return log_error_errno(r, "Failed to set fds: %m");
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering r = sd_bus_get_bus_id(p->destination_bus, &server_id);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return log_error_errno(r, "Failed to get server ID: %m");
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return log_error_errno(r, "Failed to set server mode: %m");
cb81cd8073392936882643af0129934bf67e96c4Lennart Poettering r = sd_bus_negotiate_fds(b, negotiate_fds);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return log_error_errno(r, "Failed to set FD negotiation: %m");
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart 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);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return log_error_errno(r, "Failed to set credential negotiation: %m");
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return log_error_errno(r, "Failed to set anonymous authentication: %m");
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return log_error_errno(r, "Failed to start bus client: %m");
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poetteringstatic int proxy_match_synthetic(sd_bus_message *m, void *userdata, sd_bus_error *error) {
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering return 0; /* make sure to continue processing it in further handlers */
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering * We always need NameOwnerChanged so we can synthesize NameLost and
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering * NameAcquired. Furthermore, dbus-1 always passes unicast-signals through, so
df2d202e6ed4001a21c6512c244acad5d4706c87Lennart Poettering * subscribe unconditionally.
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poetteringstatic int proxy_prepare_matches(Proxy *p) {
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering r = sd_bus_get_unique_name(p->destination_bus, &unique);
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering return log_error_errno(r, "Failed to get unique name: %m");
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering "sender='org.freedesktop.DBus',"
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering "interface='org.freedesktop.DBus',"
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering "member='NameOwnerChanged',"
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering r = sd_bus_add_match(p->destination_bus, NULL, match, proxy_match_synthetic, p);
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering return log_error_errno(r, "Failed to add match for NameLost: %m");
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering "sender='org.freedesktop.DBus',"
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering "interface='org.freedesktop.DBus',"
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering "member='NameOwnerChanged',"
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering r = sd_bus_add_match(p->destination_bus, NULL, match, proxy_match_synthetic, p);
4e724d9c5ab76c3f8327945317463ef706011082Lennart Poettering return log_error_errno(r, "Failed to add match for NameAcquired: %m");
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering "destination='",
4e724d9c5ab76c3f8327945317463ef706011082Lennart Poettering r = sd_bus_add_match(p->destination_bus, NULL, match, proxy_match_synthetic, p);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering log_error_errno(r, "Failed to add match for directed signals: %m");
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering /* FIXME: temporarily ignore error to support older kdbus versions */
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poetteringint proxy_new(Proxy **out, int in_fd, int out_fd, const char *destination) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering p->owned_names = set_new(&string_hash_ops);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering is_unix = sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering (void) getpeercred(in_fd, &p->local_creds);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering r = proxy_create_destination(p, destination, local_sec, is_unix);
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering r = proxy_create_local(p, in_fd, out_fd, is_unix);
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering LIST_REMOVE(activations_by_proxy, p->activations, activation);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering sd_bus_message_unref(activation->request);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering sd_bus_flush_close_unref(p->destination_bus);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poetteringint proxy_set_policy(Proxy *p, SharedPolicy *sp, char **configuration) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* no need to load legacy policy if destination is not kdbus */
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /* policy already pre-loaded */
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering r = sd_bus_get_scope(p->destination_bus, &scope);
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering return log_error_errno(r, "Couldn't determine bus scope: %m");
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering strv = strv_new("/usr/share/dbus-1/system.conf",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering strv = strv_new("/usr/share/dbus-1/session.conf",
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering return log_error("Unknown scope %s, don't know which policy to load. Refusing.", scope);
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering return shared_policy_preload(sp, configuration);
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poetteringint proxy_hello_policy(Proxy *p, uid_t original_uid) {
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering policy = shared_policy_acquire(p->policy);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_debug("Permitting access, since bus owner matches bus client.");
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering else if (policy_check_hello(policy, p->local_creds.uid, p->local_creds.gid))
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_debug("Permitting access due to XML policy.");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = log_error_errno(EPERM, "Policy denied connection.");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering shared_policy_release(p->policy, policy);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering uint64_t timeout_destination, timeout_local, t;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int events_destination, events_local, fd;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return log_error_errno(fd, "Failed to get fd: %m");
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering events_destination = sd_bus_get_events(p->destination_bus);
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering return log_error_errno(events_destination, "Failed to get events mask: %m");
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering r = sd_bus_get_timeout(p->destination_bus, &timeout_destination);
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering return log_error_errno(r, "Failed to get timeout: %m");
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering events_local = sd_bus_get_events(p->local_bus);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering return log_error_errno(events_local, "Failed to get events mask: %m");
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering r = sd_bus_get_timeout(p->local_bus, &timeout_local);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering return log_error_errno(r, "Failed to get timeout: %m");
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering if (t == (uint64_t) -1 || (timeout_local != (uint64_t) -1 && timeout_local < timeout_destination))
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering { .fd = fd, .events = events_destination, },
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering { .fd = p->local_in, .events = events_local & POLLIN, },
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering { .fd = p->local_out, .events = events_local & POLLOUT, },
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return log_error_errno(errno, "ppoll() failed: %m");
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poetteringstatic int handle_policy_error(sd_bus_message *m, int r) {
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering return synthetic_reply_method_errorf(m, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", m->destination);
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart 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) {
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering * dbus-1 distinguishes expected and non-expected replies by tracking
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering * method-calls and timeouts. By default, DENY rules are *NEVER* applied
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering * on expected replies, unless explicitly specified. But we dont track
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering * method-calls, thus, we cannot know whether a reply is expected.
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering * Fortunately, the kdbus forbids non-expected replies, so we can safely
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering * ignore any policy on those and let the kernel deal with it.
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering * TODO: To be correct, we should only ignore policy-tags that are
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering * applied on non-expected replies. However, so far we don't parse those
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering * tags so we let everything pass. I haven't seen a DENY policy tag on
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering * expected-replies, ever, so don't bother..
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering /* Driver messages are always OK */
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering if (streq_ptr(m->sender, "org.freedesktop.DBus"))
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* The message came from the kernel, and is sent to our legacy client. */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering (void) sd_bus_creds_get_well_known_names(&m->creds, &sender_names);
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering (void) sd_bus_creds_get_euid(&m->creds, &sender_uid);
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering (void) sd_bus_creds_get_egid(&m->creds, &sender_gid);
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering if (sender_uid == UID_INVALID || sender_gid == GID_INVALID) {
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering _cleanup_bus_creds_unref_ sd_bus_creds *sender_creds = NULL;
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering /* If the message came from another legacy
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering * client, then the message creds will be
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * missing, simply because on legacy clients
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering * per-message creds were unknown. In this
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering * case, query the creds of the peer
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = bus_get_name_creds_kdbus(from, m->sender, SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID, true, &sender_creds);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering (void) sd_bus_creds_get_euid(sender_creds, &sender_uid);
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering (void) sd_bus_creds_get_egid(sender_creds, &sender_gid);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /* First check whether the sender can send the message to our name */
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering if (policy_check_send(policy, sender_uid, sender_gid, m->header->type, owned_names, NULL, m->path, m->interface, m->member, false, NULL) &&
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering policy_check_recv(policy, our_ucred->uid, our_ucred->gid, m->header->type, NULL, sender_names, m->path, m->interface, m->member, false))
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Return an error back to the caller */
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return synthetic_reply_method_errorf(m, SD_BUS_ERROR_ACCESS_DENIED, "Access prohibited by XML receiver policy.");
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /* Return 1, indicating that the message shall not be processed any further */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering _cleanup_bus_creds_unref_ sd_bus_creds *destination_creds = NULL;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering /* Driver messages are always OK */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (streq_ptr(m->destination, "org.freedesktop.DBus"))
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering /* The message came from the legacy client, and is sent to kdbus. */
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering r = bus_get_name_creds_kdbus(to, m->destination,
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME|
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_PID,
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering r = sd_bus_creds_get_unique_name(destination_creds, &destination_unique);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering (void) sd_bus_creds_get_well_known_names(destination_creds, &destination_names);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering (void) sd_bus_creds_get_euid(destination_creds, &destination_uid);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering (void) sd_bus_creds_get_egid(destination_creds, &destination_gid);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /* First check if we (the sender) can send to this name */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (sd_bus_message_is_signal(m, NULL, NULL)) {
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering /* If we forward a signal from dbus-1 to kdbus, we have
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering * no idea who the recipient is. Therefore, we cannot
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering * apply any dbus-1 policies that match on receiver
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering * credentials. We know sd-bus always sets
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering * KDBUS_MSG_SIGNAL, so the kernel applies policies to
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering * the message. Therefore, skip policy checks in this
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering } 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)) {
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering /* If we made a receiver decision, then remember which
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering * name's policy we used, and to which unique ID it
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering * mapped when we made the decision. Then, let's pass
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering * this to the kernel when sending the message, so that
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering * it refuses the operation should the name and unique
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering * ID not map to each other anymore. */
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering r = free_and_strdup(&m->destination_ptr, n);
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering r = bus_kernel_parse_unique_name(destination_unique, &m->verify_destination_id);
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering if (policy_check_recv(policy, destination_uid, destination_gid, m->header->type, owned_names, NULL, m->path, m->interface, m->member, true))
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering /* Return an error back to the caller */
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering return synthetic_reply_method_errorf(m, SD_BUS_ERROR_ACCESS_DENIED, "Access prohibited by XML sender policy.");
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering /* Return 1, indicating that the message shall not be processed any further */
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poetteringstatic int process_policy(sd_bus *from, sd_bus *to, sd_bus_message *m, SharedPolicy *sp, const struct ucred *our_ucred, Set *owned_names) {
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering r = process_policy_unlocked(from, to, m, policy, our_ucred, owned_names);
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poetteringstatic int process_hello(Proxy *p, sd_bus_message *m) {
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering /* As reaction to hello we need to respond with two messages:
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering * the callback reply and the NameAcquired for the unique
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering * name, since hello is otherwise obsolete on kdbus. */
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") &&
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering streq_ptr(m->destination, "org.freedesktop.DBus");
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering return log_error_errno(EIO, "First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member);
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering return log_error_errno(EIO, "Got duplicate hello, aborting.");
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering r = sd_bus_message_new_method_return(m, &n);
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering return log_error_errno(r, "Failed to generate HELLO reply: %m");
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering r = sd_bus_message_append(n, "s", p->destination_bus->unique_name);
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering return log_error_errno(r, "Failed to append unique name to HELLO reply: %m");
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering r = bus_message_append_sender(n, "org.freedesktop.DBus");
5f8cc96a0301c1177b11dd2e89370ef0b2ef577bLennart Poettering return log_error_errno(r, "Failed to append sender to HELLO reply: %m");
5f8cc96a0301c1177b11dd2e89370ef0b2ef577bLennart Poettering r = bus_seal_synthetic_message(p->local_bus, n);
5f8cc96a0301c1177b11dd2e89370ef0b2ef577bLennart Poettering return log_error_errno(r, "Failed to seal HELLO reply: %m");
5f8cc96a0301c1177b11dd2e89370ef0b2ef577bLennart Poettering return log_error_errno(r, "Failed to send HELLO reply: %m");
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering "org.freedesktop.DBus",
5f8cc96a0301c1177b11dd2e89370ef0b2ef577bLennart Poettering "NameAcquired");
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering return log_error_errno(r, "Failed to allocate initial NameAcquired message: %m");
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering r = sd_bus_message_append(n, "s", p->destination_bus->unique_name);
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering return log_error_errno(r, "Failed to append unique name to NameAcquired message: %m");
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering r = bus_message_append_sender(n, "org.freedesktop.DBus");
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering return log_error_errno(r, "Failed to append sender to NameAcquired message: %m");
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering r = sd_bus_message_set_destination(n, p->destination_bus->unique_name);
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering return log_error_errno(r, "Failed to set destination for NameAcquired message: %m");
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering r = bus_seal_synthetic_message(p->local_bus, n);
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering return log_error_errno(r, "Failed to seal NameAcquired message: %m");
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering return log_error_errno(r, "Failed to send NameAcquired message: %m");
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poetteringstatic int patch_sender(sd_bus *a, sd_bus_message *m) {
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering /* We will change the sender of messages from the bus driver
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering * so that they originate from the bus driver. This is a
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering * speciality originating from dbus1, where the bus driver did
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering * not have a unique id, but only the well-known name. */
0370612e0522191f929e3feb7d4937fff3d421e2Lennart Poettering r = sd_bus_creds_get_well_known_names(c, &well_known);
0370612e0522191f929e3feb7d4937fff3d421e2Lennart Poettering if (strv_contains(well_known, "org.freedesktop.DBus"))
0370612e0522191f929e3feb7d4937fff3d421e2Lennart Poetteringstatic int proxy_process_destination_to_local(Proxy *p) {
0370612e0522191f929e3feb7d4937fff3d421e2Lennart Poettering _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
086821244b5113f00a0ef993b78dc56aae2a8f6cLennart Poettering * Usually, we would just take any message that the bus passes to us
086821244b5113f00a0ef993b78dc56aae2a8f6cLennart Poettering * and forward it to the local connection. However, there are actually
086821244b5113f00a0ef993b78dc56aae2a8f6cLennart Poettering * applications that fail if they receive broadcasts that they didn't
086821244b5113f00a0ef993b78dc56aae2a8f6cLennart Poettering * subscribe to. Therefore, we actually emulate a real broadcast
086821244b5113f00a0ef993b78dc56aae2a8f6cLennart Poettering * matching here, and discard any broadcasts that weren't matched. Our
086821244b5113f00a0ef993b78dc56aae2a8f6cLennart Poettering * match-handlers remembers whether a message was matched by any rule,
086821244b5113f00a0ef993b78dc56aae2a8f6cLennart Poettering * by marking it in @p->message_matched.
086821244b5113f00a0ef993b78dc56aae2a8f6cLennart Poettering r = sd_bus_process(p->destination_bus, &m);
086821244b5113f00a0ef993b78dc56aae2a8f6cLennart Poettering matched_synthetic = p->synthetic_matched;
086821244b5113f00a0ef993b78dc56aae2a8f6cLennart Poettering if (r == -ECONNRESET || r == -ENOTCONN) /* Treat 'connection reset by peer' as clean exit condition */
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering log_error_errno(r, "Failed to process destination bus: %m");
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering /* We officially got EOF, let's quit */
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected"))
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering r = synthesize_name_acquired(p, p->destination_bus, p->local_bus, m);
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering return log_error_errno(r, "Failed to synthesize message: %m");
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering /* discard broadcasts that were not matched by any MATCH rule */
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering if (!matched && !sd_bus_message_get_destination(m)) {
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering log_debug("Dropped unmatched broadcast: uid=" UID_FMT " gid=" GID_FMT " pid=" PID_FMT " message=%s path=%s interface=%s member=%s sender=%s destination=%s",
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering p->local_creds.uid, p->local_creds.gid, p->local_creds.pid, bus_message_type_to_string(m->header->type),
70244d1d25eb80b57e160ea004d0e6bf793d4cafLennart Poettering strna(m->path), strna(m->interface), strna(m->member), strna(m->sender), strna(m->destination));
1ddb263d21099ae42195c2bc382bdf72a7f24f82Lennart Poettering r = process_policy(p->destination_bus, p->local_bus, m, p->policy, &p->local_creds, p->owned_names);
1ddb263d21099ae42195c2bc382bdf72a7f24f82Lennart Poettering return log_error_errno(r, "Failed to process policy: %m");
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering /* If the peer tries to send a reply and it is
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering * rejected with EBADSLT by the kernel, we ignore the
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering * error. This catches cases where the original
70244d1d25eb80b57e160ea004d0e6bf793d4cafLennart Poettering * method-call didn't had EXPECT_REPLY set, but the
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering * proxy-peer still sends a reply. This is allowed in
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering * dbus1, but not in kdbus. We don't want to track
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering * reply-windows in the proxy, so we simply ignore
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering * EBADSLT for all replies. The only downside is, that
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering * callers are no longer notified if their replies are
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering * dropped. However, this is equivalent to the
1ddb263d21099ae42195c2bc382bdf72a7f24f82Lennart Poettering * caller's timeout to expire, so this should be
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering * acceptable. Nobody sane sends replies without a
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering * matching method-call, so nobody should care. */
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering if ((r == -EPERM || r == -EBADSLT) && m->reply_cookie > 0)
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering /* Return the error to the client, if we can */
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering synthetic_reply_method_errnof(m, r, "Failed to forward message we got from destination: %m");
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering /* if local dbus1 peer does not dispatch its queue, warn only once */
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering 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);
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering "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",
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering p->local_creds.uid, p->local_creds.gid, bus_message_type_to_string(m->header->type),
70244d1d25eb80b57e160ea004d0e6bf793d4cafLennart Poettering strna(m->destination), strna(m->path), strna(m->interface), strna(m->member));
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poetteringstatic int proxy_process_local_to_destination(Proxy *p) {
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering if (r == -ECONNRESET || r == -ENOTCONN) /* Treat 'connection reset by peer' as clean exit condition */
403ed0e5c914f2a0a683403d8ba7eaf96e3ffcdfMichael Chapman log_error_errno(r, "Failed to process local bus: %m");
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering /* We officially got EOF, let's quit */
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected"))
26166c88e0b47b83972f32b5057ecbffe06bf904Lennart Poettering return log_error_errno(r, "Failed to process HELLO: %m");
efe0286285a7432f738fafae840fa4eda51c2986Lennart Poettering r = bus_proxy_process_driver(p, p->destination_bus, p->local_bus, m, p->policy, &p->local_creds, p->owned_names);
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering return log_error_errno(r, "Failed to process driver calls: %m");
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering r = process_policy(p->local_bus, p->destination_bus, m, p->policy, &p->local_creds, p->owned_names);
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering return log_error_errno(r, "Failed to process policy: %m");
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering r = sd_bus_send(p->destination_bus, m, NULL);
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering /* The name database changed since the policy check, hence let's check again */
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering /* see above why EBADSLT is ignored for replies */
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering if ((r == -EPERM || r == -EBADSLT) && m->reply_cookie > 0)
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering synthetic_reply_method_errnof(m, r, "Failed to forward message we got from local: %m");
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering "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",
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering p->local_creds.uid, p->local_creds.gid, bus_message_type_to_string(m->header->type),
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering strna(m->destination), strna(m->path), strna(m->interface), strna(m->member));
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poetteringint proxy_match(sd_bus_message *m, void *userdata, sd_bus_error *error) {
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering return 0; /* make sure to continue processing it in further handlers */
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering /* Read messages from bus, to pass them on to our client */
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering r = proxy_process_destination_to_local(p);
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering /* Read messages from our client, to pass them on to the bus */