1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
7 Copyright 2013 Daniel Mack
8 Copyright 2014 Kay Sievers
9 Copyright 2014 David Herrmann
11 systemd is free software; you can redistribute it and/or modify it
12 under the terms of the GNU Lesser General Public License as published by
13 the Free Software Foundation; either version 2.1 of the License, or
14 (at your option) any later version.
16 systemd is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 Lesser General Public License for more details.
21 You should have received a copy of the GNU Lesser General Public License
22 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #include <sys/socket.h>
26 #include <sys/types.h>
33 #include "sd-daemon.h"
35 #include "bus-internal.h"
36 #include "bus-message.h"
39 #include "bus-control.h"
41 #include "bus-xml-policy.h"
44 #include "synthesize.h"
46 static int proxy_create_destination(Proxy *p, const char *destination, const char *local_sec, bool negotiate_fds) {
47 _cleanup_bus_close_unref_ sd_bus *b = NULL;
52 return log_error_errno(r, "Failed to allocate bus: %m");
54 r = sd_bus_set_description(b, "sd-proxy");
56 return log_error_errno(r, "Failed to set bus name: %m");
58 r = sd_bus_set_address(b, destination);
60 return log_error_errno(r, "Failed to set address to connect to: %m");
62 r = sd_bus_negotiate_fds(b, negotiate_fds);
64 return log_error_errno(r, "Failed to set FD negotiation: %m");
66 r = sd_bus_negotiate_creds(b, true, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SELINUX_CONTEXT);
68 return log_error_errno(r, "Failed to set credential negotiation: %m");
70 if (p->local_creds.pid > 0) {
71 b->fake_pids.pid = p->local_creds.pid;
72 b->fake_pids_valid = true;
74 b->fake_creds.uid = UID_INVALID;
75 b->fake_creds.euid = p->local_creds.uid;
76 b->fake_creds.suid = UID_INVALID;
77 b->fake_creds.fsuid = UID_INVALID;
78 b->fake_creds.gid = GID_INVALID;
79 b->fake_creds.egid = p->local_creds.gid;
80 b->fake_creds.sgid = GID_INVALID;
81 b->fake_creds.fsgid = GID_INVALID;
82 b->fake_creds_valid = true;
86 b->fake_label = strdup(local_sec);
91 b->manual_peer_interface = true;
95 return log_error_errno(r, "Failed to start bus client: %m");
97 p->destination_bus = b;
102 static int proxy_create_local(Proxy *p, int in_fd, int out_fd, bool negotiate_fds) {
103 _cleanup_bus_close_unref_ sd_bus *b = NULL;
104 sd_id128_t server_id;
109 return log_error_errno(r, "Failed to allocate bus: %m");
111 r = sd_bus_set_fd(b, in_fd, out_fd);
113 return log_error_errno(r, "Failed to set fds: %m");
115 r = sd_bus_get_bus_id(p->destination_bus, &server_id);
117 return log_error_errno(r, "Failed to get server ID: %m");
119 r = sd_bus_set_server(b, 1, server_id);
121 return log_error_errno(r, "Failed to set server mode: %m");
123 r = sd_bus_negotiate_fds(b, negotiate_fds);
125 return log_error_errno(r, "Failed to set FD negotiation: %m");
127 r = sd_bus_negotiate_creds(b, true, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SELINUX_CONTEXT);
129 return log_error_errno(r, "Failed to set credential negotiation: %m");
131 r = sd_bus_set_anonymous(b, true);
133 return log_error_errno(r, "Failed to set anonymous authentication: %m");
135 b->manual_peer_interface = true;
139 return log_error_errno(r, "Failed to start bus client: %m");
146 static int proxy_prepare_matches(Proxy *p) {
147 _cleanup_free_ char *match = NULL;
151 if (!p->destination_bus->is_kernel)
154 r = sd_bus_get_unique_name(p->destination_bus, &unique);
156 return log_error_errno(r, "Failed to get unique name: %m");
158 match = strjoin("type='signal',"
159 "sender='org.freedesktop.DBus',"
160 "path='/org/freedesktop/DBus',"
161 "interface='org.freedesktop.DBus',"
162 "member='NameOwnerChanged',"
170 r = sd_bus_add_match(p->destination_bus, NULL, match, NULL, NULL);
172 return log_error_errno(r, "Failed to add match for NameLost: %m");
175 match = strjoin("type='signal',"
176 "sender='org.freedesktop.DBus',"
177 "path='/org/freedesktop/DBus',"
178 "interface='org.freedesktop.DBus',"
179 "member='NameOwnerChanged',"
187 r = sd_bus_add_match(p->destination_bus, NULL, match, NULL, NULL);
189 return log_error_errno(r, "Failed to add match for NameAcquired: %m");
194 int proxy_new(Proxy **out, int in_fd, int out_fd, const char *destination) {
195 _cleanup_(proxy_freep) Proxy *p = NULL;
196 _cleanup_free_ char *local_sec = NULL;
205 p->local_out = out_fd;
207 p->owned_names = set_new(&string_hash_ops);
211 is_unix = sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
212 sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
215 (void) getpeercred(in_fd, &p->local_creds);
216 (void) getpeersec(in_fd, &local_sec);
219 r = proxy_create_destination(p, destination, local_sec, is_unix);
223 r = proxy_create_local(p, in_fd, out_fd, is_unix);
227 r = proxy_prepare_matches(p);
236 Proxy *proxy_free(Proxy *p) {
240 sd_bus_close_unrefp(&p->local_bus);
241 sd_bus_close_unrefp(&p->destination_bus);
242 set_free_free(p->owned_names);
248 int proxy_set_policy(Proxy *p, SharedPolicy *sp, char **configuration) {
249 _cleanup_strv_free_ char **strv = NULL;
256 /* no need to load legacy policy if destination is not kdbus */
257 if (!p->destination_bus->is_kernel)
262 policy = shared_policy_acquire(sp);
264 /* policy already pre-loaded */
265 shared_policy_release(sp, policy);
269 if (!configuration) {
272 r = sd_bus_get_scope(p->destination_bus, &scope);
274 return log_error_errno(r, "Couldn't determine bus scope: %m");
276 if (streq(scope, "system"))
277 strv = strv_new("/etc/dbus-1/system.conf",
278 "/etc/dbus-1/system.d/",
279 "/etc/dbus-1/system-local.conf",
281 else if (streq(scope, "user"))
282 strv = strv_new("/etc/dbus-1/session.conf",
283 "/etc/dbus-1/session.d/",
284 "/etc/dbus-1/session-local.conf",
287 return log_error("Unknown scope %s, don't know which policy to load. Refusing.", scope);
292 configuration = strv;
295 return shared_policy_preload(sp, configuration);
298 int proxy_hello_policy(Proxy *p, uid_t original_uid) {
307 policy = shared_policy_acquire(p->policy);
309 if (p->local_creds.uid == original_uid)
310 log_debug("Permitting access, since bus owner matches bus client.");
311 else if (policy_check_hello(policy, p->local_creds.uid, p->local_creds.gid))
312 log_debug("Permitting access due to XML policy.");
314 r = log_error_errno(EPERM, "Policy denied connection.");
316 shared_policy_release(p->policy, policy);
321 static int proxy_wait(Proxy *p) {
322 uint64_t timeout_destination, timeout_local, t;
323 int events_destination, events_local, fd;
324 struct timespec _ts, *ts;
325 struct pollfd *pollfd;
330 fd = sd_bus_get_fd(p->destination_bus);
332 return log_error_errno(fd, "Failed to get fd: %m");
334 events_destination = sd_bus_get_events(p->destination_bus);
335 if (events_destination < 0)
336 return log_error_errno(events_destination, "Failed to get events mask: %m");
338 r = sd_bus_get_timeout(p->destination_bus, &timeout_destination);
340 return log_error_errno(r, "Failed to get timeout: %m");
342 events_local = sd_bus_get_events(p->local_bus);
343 if (events_local < 0)
344 return log_error_errno(events_local, "Failed to get events mask: %m");
346 r = sd_bus_get_timeout(p->local_bus, &timeout_local);
348 return log_error_errno(r, "Failed to get timeout: %m");
350 t = timeout_destination;
351 if (t == (uint64_t) -1 || (timeout_local != (uint64_t) -1 && timeout_local < timeout_destination))
354 if (t == (uint64_t) -1)
359 nw = now(CLOCK_MONOTONIC);
365 ts = timespec_store(&_ts, t);
368 pollfd = (struct pollfd[3]) {
369 { .fd = fd, .events = events_destination, },
370 { .fd = p->local_in, .events = events_local & POLLIN, },
371 { .fd = p->local_out, .events = events_local & POLLOUT, },
374 r = ppoll(pollfd, 3, ts, NULL);
376 return log_error_errno(errno, "ppoll() failed: %m");
381 static int handle_policy_error(sd_bus_message *m, int r) {
382 if (r == -ESRCH || r == -ENXIO)
383 return synthetic_reply_method_errorf(m, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", m->destination);
388 static int process_policy_unlocked(sd_bus *from, sd_bus *to, sd_bus_message *m, Policy *policy, const struct ucred *our_ucred, Set *owned_names) {
399 * dbus-1 distinguishes expected and non-expected replies by tracking
400 * method-calls and timeouts. By default, DENY rules are *NEVER* applied
401 * on expected replies, unless explicitly specified. But we dont track
402 * method-calls, thus, we cannot know whether a reply is expected.
403 * Fortunately, the kdbus forbids non-expected replies, so we can safely
404 * ignore any policy on those and let the kernel deal with it.
406 * TODO: To be correct, we should only ignore policy-tags that are
407 * applied on non-expected replies. However, so far we don't parse those
408 * tags so we let everything pass. I haven't seen a DENY policy tag on
409 * expected-replies, ever, so don't bother..
411 if (m->reply_cookie > 0)
414 if (from->is_kernel) {
415 uid_t sender_uid = UID_INVALID;
416 gid_t sender_gid = GID_INVALID;
417 char **sender_names = NULL;
419 /* Driver messages are always OK */
420 if (streq_ptr(m->sender, "org.freedesktop.DBus"))
423 /* The message came from the kernel, and is sent to our legacy client. */
424 (void) sd_bus_creds_get_well_known_names(&m->creds, &sender_names);
426 (void) sd_bus_creds_get_euid(&m->creds, &sender_uid);
427 (void) sd_bus_creds_get_egid(&m->creds, &sender_gid);
429 if (sender_uid == UID_INVALID || sender_gid == GID_INVALID) {
430 _cleanup_bus_creds_unref_ sd_bus_creds *sender_creds = NULL;
432 /* If the message came from another legacy
433 * client, then the message creds will be
434 * missing, simply because on legacy clients
435 * per-message creds were unknown. In this
436 * case, query the creds of the peer
439 r = bus_get_name_creds_kdbus(from, m->sender, SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID, true, &sender_creds);
441 return handle_policy_error(m, r);
443 (void) sd_bus_creds_get_euid(sender_creds, &sender_uid);
444 (void) sd_bus_creds_get_egid(sender_creds, &sender_gid);
447 /* First check whether the sender can send the message to our name */
448 if (policy_check_send(policy, sender_uid, sender_gid, m->header->type, owned_names, NULL, m->path, m->interface, m->member, false, NULL) &&
449 policy_check_recv(policy, our_ucred->uid, our_ucred->gid, m->header->type, NULL, sender_names, m->path, m->interface, m->member, false))
452 /* Return an error back to the caller */
453 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
454 return synthetic_reply_method_errorf(m, SD_BUS_ERROR_ACCESS_DENIED, "Access prohibited by XML receiver policy.");
456 /* Return 1, indicating that the message shall not be processed any further */
461 _cleanup_bus_creds_unref_ sd_bus_creds *destination_creds = NULL;
462 uid_t destination_uid = UID_INVALID;
463 gid_t destination_gid = GID_INVALID;
464 const char *destination_unique = NULL;
465 char **destination_names = NULL;
468 /* Driver messages are always OK */
469 if (streq_ptr(m->destination, "org.freedesktop.DBus"))
472 /* The message came from the legacy client, and is sent to kdbus. */
473 if (m->destination) {
474 r = bus_get_name_creds_kdbus(to, m->destination,
475 SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME|
476 SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_PID,
477 true, &destination_creds);
479 return handle_policy_error(m, r);
481 r = sd_bus_creds_get_unique_name(destination_creds, &destination_unique);
483 return handle_policy_error(m, r);
485 (void) sd_bus_creds_get_well_known_names(destination_creds, &destination_names);
487 (void) sd_bus_creds_get_euid(destination_creds, &destination_uid);
488 (void) sd_bus_creds_get_egid(destination_creds, &destination_gid);
491 /* First check if we (the sender) can send to this name */
492 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)) {
494 /* If we made a receiver decision, then remember which
495 * name's policy we used, and to which unique ID it
496 * mapped when we made the decision. Then, let's pass
497 * this to the kernel when sending the message, so that
498 * it refuses the operation should the name and unique
499 * ID not map to each other anymore. */
501 r = free_and_strdup(&m->destination_ptr, n);
505 r = bus_kernel_parse_unique_name(destination_unique, &m->verify_destination_id);
510 if (sd_bus_message_is_signal(m, NULL, NULL)) {
511 /* If we forward a signal from dbus-1 to kdbus,
512 * we have no idea who the recipient is.
513 * Therefore, we cannot apply any dbus-1
514 * receiver policies that match on receiver
515 * credentials. We know sd-bus always sets
516 * KDBUS_MSG_SIGNAL, so the kernel applies
517 * receiver policies to the message. Therefore,
518 * skip policy checks in this case. */
520 } else if (policy_check_recv(policy, destination_uid, destination_gid, m->header->type, owned_names, NULL, m->path, m->interface, m->member, true)) {
525 /* Return an error back to the caller */
526 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
527 return synthetic_reply_method_errorf(m, SD_BUS_ERROR_ACCESS_DENIED, "Access prohibited by XML sender policy.");
529 /* Return 1, indicating that the message shall not be processed any further */
536 static int process_policy(sd_bus *from, sd_bus *to, sd_bus_message *m, SharedPolicy *sp, const struct ucred *our_ucred, Set *owned_names) {
542 policy = shared_policy_acquire(sp);
543 r = process_policy_unlocked(from, to, m, policy, our_ucred, owned_names);
544 shared_policy_release(sp, policy);
549 static int process_hello(Proxy *p, sd_bus_message *m) {
550 _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
557 /* As reaction to hello we need to respond with two messages:
558 * the callback reply and the NameAcquired for the unique
559 * name, since hello is otherwise obsolete on kdbus. */
562 sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") &&
563 streq_ptr(m->destination, "org.freedesktop.DBus");
569 return log_error_errno(EIO, "First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member);
573 return log_error_errno(EIO, "Got duplicate hello, aborting.");
577 if (!p->destination_bus->is_kernel)
580 r = sd_bus_message_new_method_return(m, &n);
582 return log_error_errno(r, "Failed to generate HELLO reply: %m");
584 r = sd_bus_message_append(n, "s", p->destination_bus->unique_name);
586 return log_error_errno(r, "Failed to append unique name to HELLO reply: %m");
588 r = bus_message_append_sender(n, "org.freedesktop.DBus");
590 return log_error_errno(r, "Failed to append sender to HELLO reply: %m");
592 r = bus_seal_synthetic_message(p->local_bus, n);
594 return log_error_errno(r, "Failed to seal HELLO reply: %m");
596 r = sd_bus_send(p->local_bus, n, NULL);
598 return log_error_errno(r, "Failed to send HELLO reply: %m");
600 n = sd_bus_message_unref(n);
601 r = sd_bus_message_new_signal(
604 "/org/freedesktop/DBus",
605 "org.freedesktop.DBus",
608 return log_error_errno(r, "Failed to allocate initial NameAcquired message: %m");
610 r = sd_bus_message_append(n, "s", p->destination_bus->unique_name);
612 return log_error_errno(r, "Failed to append unique name to NameAcquired message: %m");
614 r = bus_message_append_sender(n, "org.freedesktop.DBus");
616 return log_error_errno(r, "Failed to append sender to NameAcquired message: %m");
618 r = bus_seal_synthetic_message(p->local_bus, n);
620 return log_error_errno(r, "Failed to seal NameAcquired message: %m");
622 r = sd_bus_send(p->local_bus, n, NULL);
624 return log_error_errno(r, "Failed to send NameAcquired message: %m");
629 static int patch_sender(sd_bus *a, sd_bus_message *m) {
630 char **well_known = NULL;
640 /* We will change the sender of messages from the bus driver
641 * so that they originate from the bus driver. This is a
642 * speciality originating from dbus1, where the bus driver did
643 * not have a unique id, but only the well-known name. */
645 c = sd_bus_message_get_creds(m);
649 r = sd_bus_creds_get_well_known_names(c, &well_known);
653 if (strv_contains(well_known, "org.freedesktop.DBus"))
654 m->sender = "org.freedesktop.DBus";
659 static int proxy_process_destination_to_local(Proxy *p) {
660 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
665 r = sd_bus_process(p->destination_bus, &m);
666 if (r == -ECONNRESET || r == -ENOTCONN) /* Treat 'connection reset by peer' as clean exit condition */
669 log_error_errno(r, "Failed to process destination bus: %m");
677 /* We officially got EOF, let's quit */
678 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected"))
681 r = synthesize_name_acquired(p->destination_bus, p->local_bus, m);
682 if (r == -ECONNRESET || r == -ENOTCONN)
685 return log_error_errno(r, "Failed to synthesize message: %m");
687 patch_sender(p->destination_bus, m);
690 r = process_policy(p->destination_bus, p->local_bus, m, p->policy, &p->local_creds, p->owned_names);
691 if (r == -ECONNRESET || r == -ENOTCONN)
694 return log_error_errno(r, "Failed to process policy: %m");
699 r = sd_bus_send(p->local_bus, m, NULL);
701 if (r == -ECONNRESET || r == -ENOTCONN)
704 /* If the peer tries to send a reply and it is
705 * rejected with EPERM by the kernel, we ignore the
706 * error. This catches cases where the original
707 * method-call didn't had EXPECT_REPLY set, but the
708 * proxy-peer still sends a reply. This is allowed in
709 * dbus1, but not in kdbus. We don't want to track
710 * reply-windows in the proxy, so we simply ignore
711 * EPERM for all replies. The only downside is, that
712 * callers are no longer notified if their replies are
713 * dropped. However, this is equivalent to the
714 * caller's timeout to expire, so this should be
715 * acceptable. Nobody sane sends replies without a
716 * matching method-call, so nobody should care. */
717 if (r == -EPERM && m->reply_cookie > 0)
720 /* Return the error to the client, if we can */
721 synthetic_reply_method_errnof(m, r, "Failed to forward message we got from destination: %m");
723 "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",
724 p->local_creds.uid, p->local_creds.gid, bus_message_type_to_string(m->header->type),
725 strna(m->destination), strna(m->path), strna(m->interface), strna(m->member));
732 static int proxy_process_local_to_destination(Proxy *p) {
733 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
738 r = sd_bus_process(p->local_bus, &m);
739 if (r == -ECONNRESET || r == -ENOTCONN) /* Treat 'connection reset by peer' as clean exit condition */
742 log_error_errno(r, "Failed to process local bus: %m");
750 /* We officially got EOF, let's quit */
751 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected"))
754 r = process_hello(p, m);
755 if (r == -ECONNRESET || r == -ENOTCONN)
758 return log_error_errno(r, "Failed to process HELLO: %m");
762 r = bus_proxy_process_driver(p->destination_bus, p->local_bus, m, p->policy, &p->local_creds, p->owned_names);
763 if (r == -ECONNRESET || r == -ENOTCONN)
766 return log_error_errno(r, "Failed to process driver calls: %m");
772 r = process_policy(p->local_bus, p->destination_bus, m, p->policy, &p->local_creds, p->owned_names);
773 if (r == -ECONNRESET || r == -ENOTCONN)
776 return log_error_errno(r, "Failed to process policy: %m");
781 r = sd_bus_send(p->destination_bus, m, NULL);
783 if (r == -ECONNRESET || r == -ENOTCONN)
786 /* The name database changed since the policy check, hence let's check again */
790 /* see above why EPERM is ignored for replies */
791 if (r == -EPERM && m->reply_cookie > 0)
794 synthetic_reply_method_errnof(m, r, "Failed to forward message we got from local: %m");
796 "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",
797 p->local_creds.uid, p->local_creds.gid, bus_message_type_to_string(m->header->type),
798 strna(m->destination), strna(m->path), strna(m->interface), strna(m->member));
808 int proxy_run(Proxy *p) {
817 /* Read messages from bus, to pass them on to our client */
818 r = proxy_process_destination_to_local(p);
819 if (r == -ECONNRESET || r == -ENOTCONN)
827 /* Read messages from our client, to pass them on to the bus */
828 r = proxy_process_local_to_destination(p);
829 if (r == -ECONNRESET || r == -ENOTCONN)
838 if (r == -ECONNRESET || r == -ENOTCONN)