guelfey / go.dbus

Native Go bindings for D-Bus
BSD 2-Clause "Simplified" License
124 stars 42 forks source link

"dbus: authentication failed" with any example #68

Closed ringerc closed 3 years ago

ringerc commented 3 years ago

On Fedora 33, building and running any of the examples e.g. list-names.go will fail with

$ ./listnames
Failed to connect to session bus: dbus: authentication failed

There's a usable session bus address

$ echo $DBUS_SESSION_BUS_ADDRESS
unix:path=/run/user/1000/bus

and command-line d-bus operations work

$ dbus-send --session --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.ListNames
method return time=1629168407.533841 sender=org.freedesktop.DBus -> destination=:1.10056 serial=4294967295 reply_serial=2
   array [
      string "org.freedesktop.DBus"
      .....

so the bus is usable.

SELinux is in permissive mode (unfortunately, due to unrelated issues) so it's not SELinux related.

I don't see any relevant output in dbus-monitor --session when I attempt to auth while it's running.

It's unclear why this is happening. I'll look into it, but wanted to file this now so others with a similar issue can find it.

ringerc commented 3 years ago

I did some quick and dirty instrumentation of auth.go and produced the following trace of comms where -> is client-to-server and <- is server-to-client:

trace:

$ go build && ./listnames 
2021/08/17 11:49:55 auth: begin, methods: []
2021/08/17 11:49:55 auth: using default methods EXTERNAL and COOKIESHA1
2021/08/17 11:49:55 connecting to transport
2021/08/17 11:49:55 send empty byte
2021/08/17 11:49:55 AUTH
2021/08/17 11:49:55 authWriteLine():
2021/08/17 11:49:55     AUTH
2021/08/17 11:49:55 getting response
2021/08/17 11:49:55 authReadLine():
2021/08/17 11:49:55     REJECTED
2021/08/17 11:49:55     EXTERNAL
2021/08/17 11:49:55 response: [[82 69 74 69 67 84 69 68] [69 88 84 69 82 78 65 76]]
2021/08/17 11:49:55   REJECTED
2021/08/17 11:49:55   EXTERNAL
2021/08/17 11:49:55 trying EXTERNAL
2021/08/17 11:49:55 trying method dbus.authExternal({craig})
2021/08/17 11:49:55 Initial status AuthOk, sending FirstData
2021/08/17 11:49:55 authWriteLine():
2021/08/17 11:49:55     AUTH
2021/08/17 11:49:55     EXTERNAL
2021/08/17 11:49:55     6372616967
2021/08/17 11:49:55 dbus.authExternal({craig}) tryAuth(state=waitingForOk) reading line
2021/08/17 11:49:55 authReadLine():
2021/08/17 11:49:55     REJECTED
2021/08/17 11:49:55     EXTERNAL
2021/08/17 11:49:55 dbus.authExternal({craig}) tryAuth(state=waitingForOk) state=waitingForOk gotmsg=REJECTED
2021/08/17 11:49:55 dbus.authExternal({craig}) tryAuth(state=waitingForOk) got REJECTED (waitingOK)
2021/08/17 11:49:55 dbus.authExternal({craig}) ok: false
ringerc commented 3 years ago

relevant D-Bus spec section

It seems the server doesn't like AUTH EXTERNAL 6372616967 though it advertises EXTERNAL, so it sends REJECTED and lists EXTERNAL as the supported mechanism.

The protocol documents AUTH as AUTH [mechanism] [initial-response] and says

If the [initial-response] argument is provided, it is intended for use with mechanisms that have no initial challenge (or an empty initial challenge), as if it were the argument to an initial DATA command. If the selected mechanism has an initial challenge and [initial-response] was provided, the server should reject authentication by sending REJECTED.

(bold mine)

so it looks like the server wants to send an initial challenge.

ringerc commented 3 years ago

If I change the FirstResponse result to send simply AUTH EXTERNAL then the server replies with a DATA payload, so that seems to be the issue.

Seems like the SASL mech expects to exchange a pair of empty-payload DATA messages. This requires some reworking of the mechanism API to use variable length argument and response arrays, but works.

ringerc commented 3 years ago

I've prepped a patch to handle the working handshake.

What I'm not so sure about is under which circumstances the original

AUTH EXTERNAL [hex-encoded-username]

handshake works and is required. Thus I can't be sure I'm not breaking something that's required to work correctly on some other platform, version or SASL based D-Bus configuration.

It might make sense to try the empty handshake, and if it gets REJECTED retry the EXTERNAL handshake with the initial-data field. Thoughts?

ringerc commented 3 years ago

It looks like https://github.com/keybase/go.dbus might've picked up as a continuation of this repo, so will file there instead.