mirror of
https://github.com/postgres/postgres.git
synced 2025-05-02 11:44:50 +03:00
libpq: Handle NegotiateProtocolVersion message
Before, receiving a NegotiateProtocolVersion message would result in a confusing error message like expected authentication request from server, but received v This adds proper handling of this protocol message and produces an on-topic error message from it. Reviewed-by: Jacob Champion <jchampion@timescale.com> Reviewed-by: Nathan Bossart <nathandbossart@gmail.com> Discussion: https://www.postgresql.org/message-id/flat/f9c7862f-b864-8ef7-a861-c4638c83e209%40enterprisedb.com
This commit is contained in:
parent
dce92e59b1
commit
bbf9c282ce
@ -3194,10 +3194,11 @@ keep_going: /* We will come back to here until there is
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Validate message type: we expect only an authentication
|
* Validate message type: we expect only an authentication
|
||||||
* request or an error here. Anything else probably means
|
* request, NegotiateProtocolVersion, or an error here.
|
||||||
* it's not Postgres on the other end at all.
|
* Anything else probably means it's not Postgres on the other
|
||||||
|
* end at all.
|
||||||
*/
|
*/
|
||||||
if (!(beresp == 'R' || beresp == 'E'))
|
if (!(beresp == 'R' || beresp == 'v' || beresp == 'E'))
|
||||||
{
|
{
|
||||||
libpq_append_conn_error(conn, "expected authentication request from server, but received %c",
|
libpq_append_conn_error(conn, "expected authentication request from server, but received %c",
|
||||||
beresp);
|
beresp);
|
||||||
@ -3214,14 +3215,15 @@ keep_going: /* We will come back to here until there is
|
|||||||
/*
|
/*
|
||||||
* Try to validate message length before using it.
|
* Try to validate message length before using it.
|
||||||
* Authentication requests can't be very large, although GSS
|
* Authentication requests can't be very large, although GSS
|
||||||
* auth requests may not be that small. Errors can be a
|
* auth requests may not be that small. Same for
|
||||||
|
* NegotiateProtocolVersion. Errors can be a
|
||||||
* little larger, but not huge. If we see a large apparent
|
* little larger, but not huge. If we see a large apparent
|
||||||
* length in an error, it means we're really talking to a
|
* length in an error, it means we're really talking to a
|
||||||
* pre-3.0-protocol server; cope. (Before version 14, the
|
* pre-3.0-protocol server; cope. (Before version 14, the
|
||||||
* server also used the old protocol for errors that happened
|
* server also used the old protocol for errors that happened
|
||||||
* before processing the startup packet.)
|
* before processing the startup packet.)
|
||||||
*/
|
*/
|
||||||
if (beresp == 'R' && (msgLength < 8 || msgLength > 2000))
|
if ((beresp == 'R' || beresp == 'v') && (msgLength < 8 || msgLength > 2000))
|
||||||
{
|
{
|
||||||
libpq_append_conn_error(conn, "expected authentication request from server, but received %c",
|
libpq_append_conn_error(conn, "expected authentication request from server, but received %c",
|
||||||
beresp);
|
beresp);
|
||||||
@ -3351,6 +3353,16 @@ keep_going: /* We will come back to here until there is
|
|||||||
|
|
||||||
goto error_return;
|
goto error_return;
|
||||||
}
|
}
|
||||||
|
else if (beresp == 'v')
|
||||||
|
{
|
||||||
|
if (pqGetNegotiateProtocolVersion3(conn))
|
||||||
|
{
|
||||||
|
goto error_return;
|
||||||
|
}
|
||||||
|
/* OK, we read the message; mark data consumed */
|
||||||
|
conn->inStart = conn->inCursor;
|
||||||
|
goto error_return;
|
||||||
|
}
|
||||||
|
|
||||||
/* It is an authentication request. */
|
/* It is an authentication request. */
|
||||||
conn->auth_req_received = true;
|
conn->auth_req_received = true;
|
||||||
|
@ -1385,6 +1385,61 @@ reportErrorPosition(PQExpBuffer msg, const char *query, int loc, int encoding)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Attempt to read a NegotiateProtocolVersion message.
|
||||||
|
* Entry: 'v' message type and length have already been consumed.
|
||||||
|
* Exit: returns 0 if successfully consumed message.
|
||||||
|
* returns EOF if not enough data.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
pqGetNegotiateProtocolVersion3(PGconn *conn)
|
||||||
|
{
|
||||||
|
int tmp;
|
||||||
|
ProtocolVersion their_version;
|
||||||
|
int num;
|
||||||
|
PQExpBufferData buf;
|
||||||
|
|
||||||
|
if (pqGetInt(&tmp, 4, conn) != 0)
|
||||||
|
return EOF;
|
||||||
|
their_version = tmp;
|
||||||
|
|
||||||
|
if (pqGetInt(&num, 4, conn) != 0)
|
||||||
|
return EOF;
|
||||||
|
|
||||||
|
initPQExpBuffer(&buf);
|
||||||
|
for (int i = 0; i < num; i++)
|
||||||
|
{
|
||||||
|
if (pqGets(&conn->workBuffer, conn))
|
||||||
|
{
|
||||||
|
termPQExpBuffer(&buf);
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
if (buf.len > 0)
|
||||||
|
appendPQExpBufferChar(&buf, ' ');
|
||||||
|
appendPQExpBufferStr(&buf, conn->workBuffer.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (their_version < conn->pversion)
|
||||||
|
appendPQExpBuffer(&conn->errorMessage,
|
||||||
|
libpq_gettext("protocol version not supported by server: client uses %u.%u, server supports up to %u.%u\n"),
|
||||||
|
PG_PROTOCOL_MAJOR(conn->pversion), PG_PROTOCOL_MINOR(conn->pversion),
|
||||||
|
PG_PROTOCOL_MAJOR(their_version), PG_PROTOCOL_MINOR(their_version));
|
||||||
|
if (num > 0)
|
||||||
|
appendPQExpBuffer(&conn->errorMessage,
|
||||||
|
libpq_ngettext("protocol extension not supported by server: %s\n",
|
||||||
|
"protocol extensions not supported by server: %s\n", num),
|
||||||
|
buf.data);
|
||||||
|
|
||||||
|
/* neither -- server shouldn't have sent it */
|
||||||
|
if (!(their_version < conn->pversion) && !(num > 0))
|
||||||
|
appendPQExpBuffer(&conn->errorMessage,
|
||||||
|
libpq_gettext("invalid %s message"), "NegotiateProtocolVersion");
|
||||||
|
|
||||||
|
termPQExpBuffer(&buf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Attempt to read a ParameterStatus message.
|
* Attempt to read a ParameterStatus message.
|
||||||
* This is possible in several places, so we break it out as a subroutine.
|
* This is possible in several places, so we break it out as a subroutine.
|
||||||
|
@ -685,6 +685,7 @@ extern void pqParseInput3(PGconn *conn);
|
|||||||
extern int pqGetErrorNotice3(PGconn *conn, bool isError);
|
extern int pqGetErrorNotice3(PGconn *conn, bool isError);
|
||||||
extern void pqBuildErrorMessage3(PQExpBuffer msg, const PGresult *res,
|
extern void pqBuildErrorMessage3(PQExpBuffer msg, const PGresult *res,
|
||||||
PGVerbosity verbosity, PGContextVisibility show_context);
|
PGVerbosity verbosity, PGContextVisibility show_context);
|
||||||
|
extern int pqGetNegotiateProtocolVersion3(PGconn *conn);
|
||||||
extern int pqGetCopyData3(PGconn *conn, char **buffer, int async);
|
extern int pqGetCopyData3(PGconn *conn, char **buffer, int async);
|
||||||
extern int pqGetline3(PGconn *conn, char *s, int maxlen);
|
extern int pqGetline3(PGconn *conn, char *s, int maxlen);
|
||||||
extern int pqGetlineAsync3(PGconn *conn, char *buffer, int bufsize);
|
extern int pqGetlineAsync3(PGconn *conn, char *buffer, int bufsize);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user