I'm trying to set up remote access to D-Bus, and I don't understand how authentication and authorization are (not) working.
I have a D-Bus server listening on an abstract socket.
$ echo $DBUS_SESSION_BUS_ADDRESS
unix:abstract=/tmp/dbus-g5sxxvDlmz,guid=49bd93b893fe40d83604952155190c31
I run dbus-monitor
to watch what's going on. My test case is notify-send hello
, which works when executed from the local machine.
From another account on the same machine, I can't connect to that bus.
otheraccount$ DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-g5sxxvDlmz,guid=49bd93b893fe40d83604952155190c31 dbus-monitor
Failed to open connection to session bus: Did not receive a reply. Possible causes include: the remote application did not send a reply, the message bus security policy blocked the reply, the reply timeout expired, or the network connection was broken.
otheraccount$ DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-g5sxxvDlmz,guid=49bd93b893fe40d83604952155190c31 notify-send hello
After browsing the D-Bus specification, I copied ~/.dbus-keyrings/org_freedesktop_general
to the other account, but it doesn't help.
I tried forwarding the D-Bus socket over TCP, inspired by schedar's Access D-Bus remotely using socat.
socat TCP-LISTEN:8004,reuseaddr,fork,range=127.0.0.1/32 ABSTRACT-CONNECT:/tmp/dbus-g5sxxvDlmz
I can connect to the TCP socket from my account.
DBUS_SESSION_BUS_ADDRESS=tcp:host=127.0.0.1,port=8004 notify-send hello
But not from the other account, neither with dbus-monitor
nor with notify-send
. Same error message for dbus-monitor
as above with the abstract socket; notify-send
now emits a trace:
otheraccount$ DBUS_SESSION_BUS_ADDRESS=tcp:host=127.0.0.1,port=8004 notify-send hello
** (notify-send:2952): WARNING **: The connection is closed
Stracing reveals that this version of notify-send
doesn't try to read the cookie file, so I understand why it wouldn't be able to connect.
I also tried SSHing into another machine and forwarding the TCP connection.
ssh -R 8004:localhost:8004 remotehost
Surprisingly, dbus-monitor
works without a cookie file! I can watch the D-Bus traffic from the remote host. I see a notice about eavesdropping in my local dbus-monitor
instance.
remotehost$ DBUS_SESSION_BUS_ADDRESS=tcp:host=127.0.0.1,port=8004 dbus-monitor
signal sender=org.freedesktop.DBus -> dest=:1.58 serial=2 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=NameAcquired
string ":1.58"
method call sender=:1.58 -> dest=org.freedesktop.DBus serial=2 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=AddMatch
string "eavesdrop=true"
If I run notify-send
on the local machine, dbus-monitor
on the remote host sees the notification. It's definitely reached a level of access that should require authentication.
notify-send
complained about not finding a cookie. After copying the cookie file, notify-send
works from the remote machine.
The local machine runs Debian wheezy. The remote machine runs FreeBSD 10.1.
I don't understand how D-Bus authentication and authorization work.
- Why can I eavesdrop, as far as I can tell, with no credentials from the remote machine? What am I exposing when I forward D-Bus to a TCP connection? Why are authorizations for
dbus-monitor
andnotify-send
different? - Why can I not eavesdrop from another account on the same machine, whether over the abstract socket or over the TCP connection?
- I noticed that the cookie file changes every few minutes (I haven't figured out if it's at regular intervals or not). Why?
(I know I can launch a D-Bus daemon that listens on TCP. That's not the purpose of my question, I want to understand why what I did did and did not work.)
Best Answer
D-Bus isn't using the magic cookie file here; it's passing credentials over the UNIX domain socket (
SCM_CREDENTIALS
).The magic cookie file is only one of several D-Bus authentication mechanisms. D-Bus implements a SASL-compliant interface (see RFC4422) to support a wide range of authentication mechanisms. One of these mechanisms is called "EXTERNAL" auth, and it means that the transport channel itself should be used to guarantee authentication. At least in the case of D-Bus over UNIX sockets, this appears to be the first authentication mechanism that is tried.
From the D-Bus spec:
If you strace an instance of
dbus-daemon
, you can see that when you connect to it, it checks the credentials of the connecting user:So to answer your questions:
The D-Bus daemon is using your kernel-verified user ID to verify your identity. By using
socat
to proxy connections, you are letting anybody connect to the D-Bus daemon using your UID.If you try to connect directly to the socket from another UID, the daemon recognizes that the connecting UID is not a UID that is supposed to be allowed to connect. I believe the default is that only the daemon's own UID is allowed, but haven't formally verified that. You can allow other users, though: see the configuration files in
/etc/dbus-1/
, and alsoman dbus-daemon
.This is the D-Bus server replacing old/expired cookies with new ones. According to the DBUS_COOKIE_SHA1 section of the D-Bus spec, a cookie is stored along with its creation time, and the server is supposed to delete cookies that it decides are too old. Apparently the lifetime "can be fairly short".