jackc / pgx

PostgreSQL driver and toolkit for Go
MIT License
10.83k stars 845 forks source link

PasswordMessage passed to postgres instance returns 'insufficient data left in message' #2166

Open joram opened 6 days ago

joram commented 6 days ago

Describe the bug When proxying messages from the psql cli to a postgres instance (using a Backend for the client and a Frontend for the DB, I can successfully pass most messages back and forth until it gets to the PasswordMessage. When I proxy that to the database, it returns the error: FATAL 08P01 insufficient data left in message

To Reproduce Steps to reproduce the behavior:

If possible, please provide runnable example such as:

package main

# the code has a channel of the messages going back and forth, so it can keep the sequence in order.
# I'd be happy to spin up an example codebase with a working copy of the code or something, but it feels too big to drop in a bug report

switch msg := unCast.(type) {

case *pgproto3.SSLRequest:
    _, err := p.clientConn.Write([]byte("N"))
    if err != nil {
        return err
    }

case *pgproto3.StartupMessage:
    p.username = msg.Parameters["user"]
    p.databaseFrontend.Send(msg)
    p.databaseFrontend.Flush()

case *pgproto3.AuthenticationSASL:
    p.clientBackend.Send(msg)
    p.clientBackend.Flush()

case *pgproto3.PasswordMessage:
    p.databaseFrontend.Send(msg)
    p.databaseFrontend.Flush()

case *pgproto3.ErrorResponse:
    p.clientBackend.Send(msg)
    p.clientBackend.Flush()

}

Expected behavior I expect the message from the client to be received without error by the postgres database, and for the initialization handshake to continue.

Actual behavior

 msg c->db (*pgproto3.SSLRequest): &{}
 msg c->db (*pgproto3.StartupMessage): ....
msg db->c (*pgproto3.AuthenticationSASL): &{[SCRAM-SHA-256]}
 msg c->db (*pgproto3.PasswordMessage): &{SCRAM-SHA-256}
 msg db->c (*pgproto3.ErrorResponse): &{FATAL FATAL 08P01 insufficient data left in message   %!!(MISSING)s(int32=0) %!!(MISSING)s(int32=0)        pqformat.c %!!(MISSING)s(int32=531) pq_copymsgbytes map[]}

Version

jackc commented 5 days ago

I've proxied the PG protocol before, but I've never done it with SSL or SASL. I would suggest trying it without SSL and maybe with a simpler password type. I wonder if psql is trying to use channel binding or something else not supported by pgx.

joram commented 5 days ago

Good info, thanks.

I'm currently injecting a N to ssl requests, but I'll give a simpler auth method a try.

Interestingly im able to make it work by proxying net.Conn communication, then when I see a Q message, i wrap those connections with pgproto3 frontend/backend, and operate at a higher level. I was just hoping to keep it with the nice higher level library. :)