Skip to content

Commit bbf9c28

Browse files
committed
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
1 parent dce92e5 commit bbf9c28

File tree

3 files changed

+73
-5
lines changed

3 files changed

+73
-5
lines changed

src/interfaces/libpq/fe-connect.c

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3194,10 +3194,11 @@ PQconnectPoll(PGconn *conn)
31943194

31953195
/*
31963196
* Validate message type: we expect only an authentication
3197-
* request or an error here. Anything else probably means
3198-
* it's not Postgres on the other end at all.
3197+
* request, NegotiateProtocolVersion, or an error here.
3198+
* Anything else probably means it's not Postgres on the other
3199+
* end at all.
31993200
*/
3200-
if (!(beresp == 'R' || beresp == 'E'))
3201+
if (!(beresp == 'R' || beresp == 'v' || beresp == 'E'))
32013202
{
32023203
libpq_append_conn_error(conn, "expected authentication request from server, but received %c",
32033204
beresp);
@@ -3214,14 +3215,15 @@ PQconnectPoll(PGconn *conn)
32143215
/*
32153216
* Try to validate message length before using it.
32163217
* Authentication requests can't be very large, although GSS
3217-
* auth requests may not be that small. Errors can be a
3218+
* auth requests may not be that small. Same for
3219+
* NegotiateProtocolVersion. Errors can be a
32183220
* little larger, but not huge. If we see a large apparent
32193221
* length in an error, it means we're really talking to a
32203222
* pre-3.0-protocol server; cope. (Before version 14, the
32213223
* server also used the old protocol for errors that happened
32223224
* before processing the startup packet.)
32233225
*/
3224-
if (beresp == 'R' && (msgLength < 8 || msgLength > 2000))
3226+
if ((beresp == 'R' || beresp == 'v') && (msgLength < 8 || msgLength > 2000))
32253227
{
32263228
libpq_append_conn_error(conn, "expected authentication request from server, but received %c",
32273229
beresp);
@@ -3351,6 +3353,16 @@ PQconnectPoll(PGconn *conn)
33513353

33523354
goto error_return;
33533355
}
3356+
else if (beresp == 'v')
3357+
{
3358+
if (pqGetNegotiateProtocolVersion3(conn))
3359+
{
3360+
goto error_return;
3361+
}
3362+
/* OK, we read the message; mark data consumed */
3363+
conn->inStart = conn->inCursor;
3364+
goto error_return;
3365+
}
33543366

33553367
/* It is an authentication request. */
33563368
conn->auth_req_received = true;

src/interfaces/libpq/fe-protocol3.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1385,6 +1385,61 @@ reportErrorPosition(PQExpBuffer msg, const char *query, int loc, int encoding)
13851385
}
13861386

13871387

1388+
/*
1389+
* Attempt to read a NegotiateProtocolVersion message.
1390+
* Entry: 'v' message type and length have already been consumed.
1391+
* Exit: returns 0 if successfully consumed message.
1392+
* returns EOF if not enough data.
1393+
*/
1394+
int
1395+
pqGetNegotiateProtocolVersion3(PGconn *conn)
1396+
{
1397+
int tmp;
1398+
ProtocolVersion their_version;
1399+
int num;
1400+
PQExpBufferData buf;
1401+
1402+
if (pqGetInt(&tmp, 4, conn) != 0)
1403+
return EOF;
1404+
their_version = tmp;
1405+
1406+
if (pqGetInt(&num, 4, conn) != 0)
1407+
return EOF;
1408+
1409+
initPQExpBuffer(&buf);
1410+
for (int i = 0; i < num; i++)
1411+
{
1412+
if (pqGets(&conn->workBuffer, conn))
1413+
{
1414+
termPQExpBuffer(&buf);
1415+
return EOF;
1416+
}
1417+
if (buf.len > 0)
1418+
appendPQExpBufferChar(&buf, ' ');
1419+
appendPQExpBufferStr(&buf, conn->workBuffer.data);
1420+
}
1421+
1422+
if (their_version < conn->pversion)
1423+
appendPQExpBuffer(&conn->errorMessage,
1424+
libpq_gettext("protocol version not supported by server: client uses %u.%u, server supports up to %u.%u\n"),
1425+
PG_PROTOCOL_MAJOR(conn->pversion), PG_PROTOCOL_MINOR(conn->pversion),
1426+
PG_PROTOCOL_MAJOR(their_version), PG_PROTOCOL_MINOR(their_version));
1427+
if (num > 0)
1428+
appendPQExpBuffer(&conn->errorMessage,
1429+
libpq_ngettext("protocol extension not supported by server: %s\n",
1430+
"protocol extensions not supported by server: %s\n", num),
1431+
buf.data);
1432+
1433+
/* neither -- server shouldn't have sent it */
1434+
if (!(their_version < conn->pversion) && !(num > 0))
1435+
appendPQExpBuffer(&conn->errorMessage,
1436+
libpq_gettext("invalid %s message"), "NegotiateProtocolVersion");
1437+
1438+
termPQExpBuffer(&buf);
1439+
return 0;
1440+
}
1441+
1442+
13881443
/*
13891444
* Attempt to read a ParameterStatus message.
13901445
* This is possible in several places, so we break it out as a subroutine.

src/interfaces/libpq/libpq-int.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,7 @@ extern void pqParseInput3(PGconn *conn);
685685
extern int pqGetErrorNotice3(PGconn *conn, bool isError);
686686
extern void pqBuildErrorMessage3(PQExpBuffer msg, const PGresult *res,
687687
PGVerbosity verbosity, PGContextVisibility show_context);
688+
extern int pqGetNegotiateProtocolVersion3(PGconn *conn);
688689
extern int pqGetCopyData3(PGconn *conn, char **buffer, int async);
689690
extern int pqGetline3(PGconn *conn, char *s, int maxlen);
690691
extern int pqGetlineAsync3(PGconn *conn, char *buffer, int bufsize);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy