Authentification et autorisation D-Bus

13

J'essaie de configurer l'accès à distance à D-Bus, et je ne comprends pas comment l'authentification et l'autorisation fonctionnent (pas).

J'ai un serveur D-Bus qui écoute sur une prise abstraite.

$ echo $DBUS_SESSION_BUS_ADDRESS 
unix:abstract=/tmp/dbus-g5sxxvDlmz,guid=49bd93b893fe40d83604952155190c31

Je cours dbus-monitorpour regarder ce qui se passe. Mon cas de test est notify-send hello, qui fonctionne lorsqu'il est exécuté à partir de la machine locale.

Depuis un autre compte sur la même machine, je ne peux pas me connecter à ce 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

Après avoir parcouru la spécification D-Bus , j'ai copié ~/.dbus-keyrings/org_freedesktop_generalsur l'autre compte, mais cela n'aide pas.

J'ai essayé de transmettre le socket D-Bus sur TCP, en m'inspirant de l' accès D-Bus du planificateur à distance à l'aide de socat .

socat TCP-LISTEN:8004,reuseaddr,fork,range=127.0.0.1/32 ABSTRACT-CONNECT:/tmp/dbus-g5sxxvDlmz

Je peux me connecter au socket TCP depuis mon compte.

DBUS_SESSION_BUS_ADDRESS=tcp:host=127.0.0.1,port=8004 notify-send hello

Mais pas de l'autre compte, ni avec dbus-monitorni avec notify-send. Même message d'erreur dbus-monitorque ci-dessus avec le socket abstrait; notify-sendémet maintenant une 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 révèle que cette version de notify-sendn'essaie pas de lire le fichier cookie, donc je comprends pourquoi elle ne pourrait pas se connecter.

J'ai également essayé SSHing sur une autre machine et transféré la connexion TCP.

ssh -R 8004:localhost:8004 remotehost

Étonnamment, dbus-monitorfonctionne sans fichier cookie! Je peux regarder le trafic D-Bus depuis l'hôte distant. Je vois un avis d'écoute dans mon dbus-monitorinstance locale .

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"

Si je cours notify-sendsur la machine locale, dbus-monitorl'hôte distant voit la notification. Il a définitivement atteint un niveau d'accès qui devrait nécessiter une authentification.

notify-sends'est plaint de ne pas avoir trouvé de cookie. Après avoir copié le fichier cookie, notify-sendfonctionne à partir de la machine distante.

La machine locale exécute Debian Wheezy. La machine distante exécute FreeBSD 10.1.

Je ne comprends pas comment fonctionnent l'authentification et l'autorisation D-Bus.

  1. Pourquoi puis-je écouter, pour autant que je sache, sans informations d'identification de la machine distante? Qu'est-ce que j'expose lorsque je transfère D-Bus vers une connexion TCP? Pourquoi les autorisations sont-elles dbus-monitoret notify-senddifférentes?
  2. Pourquoi ne puis-je pas espionner d'un autre compte sur la même machine, que ce soit sur le socket abstrait ou sur la connexion TCP?
  3. J'ai remarqué que le fichier cookie change toutes les quelques minutes (je n'ai pas compris si c'est à intervalles réguliers ou non). Pourquoi?

(Je sais que je peux lancer un démon D-Bus qui écoute sur TCP. Ce n'est pas le but de ma question, je veux comprendre pourquoi ce que j'ai fait et n'a pas fonctionné.)

Gilles 'SO- arrête d'être méchant'
la source

Réponses:

7

D-Bus n'utilise pas le fichier de cookie magique ici; il transmet les informations d'identification via le socket de domaine UNIX ( SCM_CREDENTIALS).

Le fichier de cookie magique n'est qu'un des nombreux mécanismes d'authentification D-Bus. D-Bus implémente une interface compatible SASL (voir RFC4422 ) pour prendre en charge un large éventail de mécanismes d'authentification. L'un de ces mécanismes est appelé authentification "EXTERNE" et cela signifie que le canal de transport lui-même doit être utilisé pour garantir l'authentification. Au moins dans le cas de D-Bus sur des sockets UNIX, cela semble être le premier mécanisme d'authentification essayé.

De la spécification D-Bus:

Titres de compétence spéciaux - octet nul passant

Immédiatement après la connexion au serveur, le client doit envoyer un seul octet nul. Cet octet peut être accompagné d'informations d'identification sur certains systèmes d'exploitation qui utilisent sendmsg () avec SCM_CREDS ou SCM_CREDENTIALS pour transmettre des informations d'identification sur des sockets de domaine UNIX. Cependant, l'octet nul doit être envoyé même sur d'autres types de socket, et même sur des systèmes d'exploitation qui ne nécessitent pas l'envoi d'un octet pour transmettre des informations d'identification. Le protocole de texte décrit dans ce document commence après l'octet nul nul. Si le premier octet reçu du client n'est pas un octet nul, le serveur peut déconnecter ce client.

Un octet nul dans un contexte autre que l'octet initial est une erreur; le protocole est uniquement ASCII.

Les informations d'identification envoyées avec l'octet nul peuvent être utilisées avec le mécanisme SASL EXTERNE.

Si vous stracez une instance de dbus-daemon, vous pouvez voir que lorsque vous vous y connectez, il vérifie les informations d'identification de l'utilisateur qui se connecte:

$ 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

Alors pour répondre à vos questions:

  1. Le démon D-Bus utilise votre ID utilisateur vérifié par le noyau pour vérifier votre identité. En utilisant socatdes connexions proxy, vous permettez à quiconque de se connecter au démon D-Bus à l'aide de votre UID.

  2. Si vous essayez de vous connecter directement au socket à partir d'un autre UID, le démon reconnaît que l'UID de connexion n'est pas un UID censé être autorisé à se connecter. Je crois que la valeur par défaut est que seul le propre UID du démon est autorisé, mais je ne l'ai pas officiellement vérifié. Vous pouvez cependant autoriser d'autres utilisateurs: voir les fichiers de configuration dans /etc/dbus-1/, et aussi man dbus-daemon.

  3. Il s'agit du serveur D-Bus remplaçant les cookies anciens / expirés par de nouveaux. Selon la section DBUS_COOKIE_SHA1 de la spécification D-Bus, un cookie est stocké avec son heure de création, et le serveur est censé supprimer les cookies qu'il juge trop anciens. Apparemment, la durée de vie "peut être assez courte".

Jander
la source
L'implémentation de référence de D-Bus n'utilise pas SCM_CREDENTIALSspécifiquement. Sous Linux, il utilise SO_PEERCREDplutôt l'option socket.
Vasiliy Faronov
@VasiliyFaronov Vous avez raison - comme c'est intéressant! De plus, il semble que l'utilisation SCM_CREDENTIALSaurait empêché un proxy aussi simple, car il exige que l'expéditeur présente activement ses informations d'identification, alors qu'il SO_PEERCREDvérifie simplement qui a établi la connexion. Je me demande pourquoi ils ont fait ce choix.
Jander
Apparemment parce que cela «ne nécessite pas la coopération des pairs», donc «c'est beaucoup moins fragile» (d'après les commentaires en dbus-sysdeps-unix.c).
Vasiliy Faronov