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