Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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

+17-5
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

+55
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

+1
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)