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-Bus仕様 を参照した後、~/.dbus-keyrings/org_freedesktop_general
を他のアカウントにコピーしましたが、役に立ちません。
schedar の socatを使用してリモートでD-Busにアクセスする からヒントを得て、TCP経由で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
ただし、他のアカウントからではなく、dbus-monitor
も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
紐付けにより、このバージョンの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の認証と承認の仕組みがわかりません。
dbus-monitor
とnotify-send
の認証が異なるのはなぜですか?(私はTCPをリッスンするD-Busデーモンを起動できることを知っています。それは私の質問の目的ではありません。なぜ私が何をし、何が機能しなかったのかを理解したいのです。)
D-Busは、ここではマジッククッキーファイルを使用していません。 UNIXドメインソケット(SCM_CREDENTIALS
)を介して資格情報を渡しています。
Magic cookieファイルは、いくつかのD-Bus認証メカニズムの1つにすぎません。 D-Busは [〜#〜] sasl [〜#〜] 準拠のインターフェース( RFC4422 を参照)を実装して、幅広い認証メカニズムをサポートします。これらのメカニズムの1つは「外部」認証と呼ばれ、トランスポートチャネル自体を使用して認証を保証する必要があることを意味します。少なくともUNIXソケット経由のD-Busの場合、これは最初に試行される認証メカニズムのようです。
D-Bus仕様から:
サーバーに接続した直後に、クライアントは単一のnulバイトを送信する必要があります。このバイトには、SCM_CREDSまたはSCM_CREDENTIALSでsendmsg()を使用してUNIXドメインソケットを介して資格情報を渡す一部のオペレーティングシステムの資格情報が伴う場合があります。ただし、nulバイトは、他の種類のソケットや、資格情報を送信するためにバイトを送信する必要がないオペレーティングシステムでも送信する必要があります。このドキュメントで説明するテキストプロトコルは、1つのnulバイトの後に始まります。クライアントから受信した最初のバイトがNULバイトでない場合、サーバーはそのクライアントを切断することがあります。
最初のバイト以外のコンテキストでのNULバイトはエラーです。プロトコルはASCIIのみです。
Nulバイトと共に送信される資格情報は、SASLメカニズムEXTERNALで使用できます。
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を使用してIDを検証しています。 socat
をプロキシ接続に使用することで、UIDを使用して誰でもD-Busデーモンに接続できるようになります。
別のUIDからソケットに直接接続しようとすると、デーモンは、接続しているUIDが接続を許可されているはずのUIDではないことを認識します。デフォルトでは、デーモン自体のUIDのみが許可されていると思いますが、正式には確認されていません。ただし、他のユーザーを許可することもできます。/etc/dbus-1/
およびman dbus-daemon
の構成ファイルを参照してください。
これは、古い/期限切れのCookieを新しいものに置き換えるD-Busサーバーです。 D-Bus仕様の DBUS_COOKIE_SHA1 セクションによると、Cookieはその作成時間とともに保存され、サーバーは古すぎると判断したCookieを削除することになっています。どうやら寿命は「かなり短くなる可能性がある」。