我正在尝试设置对 D-Bus 的远程访问,但我不明白身份验证和授权是如何(不)工作的。
我有一个 D-Bus 服务器正在监听一个抽象套接字。
$ echo $DBUS_SESSION_BUS_ADDRESS
unix:abstract=/tmp/dbus-g5sxxvDlmz,guid=49bd93b893fe40d83604952155190c31
我跑过去dbus-monitor
看看发生了什么事。我的测试用例是notify-send hello
,它在从本地计算机执行时有效。
从同一台计算机上的另一个帐户,我无法连接到该总线。
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
浏览完后D总线规格,我复制~/.dbus-keyrings/org_freedesktop_general
到另一个帐户,但没有帮助。
我尝试通过 TCP 转发 D-Bus 套接字,灵感来自调度程序的使用 socat 远程访问 D-Bus。
socat TCP-LISTEN:8004,reuseaddr,fork,range=127.0.0.1/32 ABSTRACT-CONNECT:/tmp/dbus-g5sxxvDlmz
我可以从我的帐户连接到 TCP 套接字。
DBUS_SESSION_BUS_ADDRESS=tcp:host=127.0.0.1,port=8004 notify-send hello
但不是来自其他帐户,既不是 withdbus-monitor
也不是 with notify-send
。dbus-monitor
与上面的抽象套接字相同的错误消息;notify-send
现在发出一条痕迹:
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 显示这个版本notify-send
不会尝试读取 cookie 文件,所以我明白为什么它无法连接。
我还尝试通过 SSH 连接到另一台机器并转发 TCP 连接。
ssh -R 8004:localhost:8004 remotehost
令人惊讶的是,dbus-monitor
无需 cookie 文件即可工作!我可以从远程主机观看 D-Bus 流量。我在本地实例中看到有关窃听的通知dbus-monitor
。
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"
如果我notify-send
在本地计算机上运行,则dbus-monitor
远程主机上会看到通知。它肯定已经达到了需要身份验证的访问级别。
notify-send
抱怨找不到cookie。复制 cookie 文件后,notify-send
即可在远程计算机上工作。
本地机器运行 Debian wheezy。远程计算机运行 FreeBSD 10.1。
我不明白 D-Bus 身份验证和授权是如何工作的。
- 据我所知,为什么我可以在没有远程计算机凭据的情况下进行窃听?当我将 D-Bus 转发到 TCP 连接时,我会暴露什么?为什么
dbus-monitor
和 的授权notify-send
不同? - 为什么我无法从同一台计算机上的另一个帐户进行窃听,无论是通过抽象套接字还是通过 TCP 连接?
- 我注意到cookie文件每隔几分钟就会改变一次(我还没有弄清楚它是否是定期的)。为什么?
(我知道我可以启动一个侦听 TCP 的 D-Bus 守护进程。这不是我问题的目的,我想了解为什么我所做的事情起作用了,但不起作用。)
答案1
D-Bus 在这里没有使用 magic cookie 文件;它通过 UNIX 域套接字 ( ) 传递凭据SCM_CREDENTIALS
。
magic cookie 文件只是多种 D-Bus 身份验证机制之一。 D-Bus 实现了SASL- 兼容接口(参见RFC4422)以支持广泛的身份验证机制。其中一种机制称为“外部”身份验证,这意味着传输通道本身应该用于保证身份验证。至少在 UNIX 套接字上的 D-Bus 的情况下,这似乎是第一个尝试的身份验证机制。
来自 D-Bus 规范:
连接到服务器后,客户端必须立即发送一个 nul 字节。在某些操作系统上,该字节可能伴随有凭证信息,这些操作系统使用带有 SCM_CREDS 或 SCM_CREDENTIALS 的 sendmsg() 通过 UNIX 域套接字传递凭证。但是,即使在其他类型的套接字上,甚至在不需要发送字节来传输凭据的操作系统上,也必须发送 nul 字节。本文档中描述的文本协议在单个 nul 字节之后开始。如果从客户端接收到的第一个字节不是空字节,则服务器可能会断开该客户端的连接。
除初始字节之外的任何上下文中的 null 字节都是错误;该协议仅支持 ASCII。
与 nul 字节一起发送的凭证可以与 SASL 机制 EXTERNAL 一起使用。
如果您 strace 的实例dbus-daemon
,您可以看到当您连接到它时,它会检查连接用户的凭据:
$ strace dbus-daemon --session --nofork
...
accept4(4, {sa_family=AF_LOCAL, NULL}, [2], SOCK_CLOEXEC) = 8
...
recvmsg(8, {msg_name(0)=NULL, msg_iov(1)=[{"\0", 1}], msg_controllen=0, msg_flags=0}, 0) = 1
getsockopt(8, SOL_SOCKET, SO_PEERCRED, {pid=6694, uid=1000, gid=1000}, [12]) = 0
所以回答你的问题:
D-Bus 守护程序正在使用经过内核验证的用户 ID 来验证您的身份。通过使用
socat
代理连接,您可以让任何人使用您的 UID 连接到 D-Bus 守护程序。如果您尝试从另一个 UID 直接连接到套接字,则守护程序会识别出连接的 UID 不是应该允许连接的 UID。我相信默认情况下只允许守护进程自己的 UID,但尚未正式验证这一点。不过,您可以允许其他用户:请参阅
/etc/dbus-1/
和中的配置文件man dbus-daemon
。这是 D-Bus 服务器用新的 cookie 替换旧的/过期的 cookie。根据DBUS_COOKIE_SHA1根据 D-Bus 规范的部分,cookie 与其创建时间一起存储,并且服务器应该删除它认为太旧的 cookie。显然,寿命“可能相当短”。