Skip to content

Commit 79e594c

Browse files
committed
Fix GSS client to non-GSS server connection
If the client is compiled with GSSAPI support and tries to start up GSS with the server, but the server is not compiled with GSSAPI support, we would mistakenly end up falling through to call ProcessStartupPacket with secure_done = true, but the client might then try to perform SSL, which the backend wouldn't understand and we'd end up failing the connection with: FATAL: unsupported frontend protocol 1234.5679: server supports 2.0 to 3.0 Fix by arranging to track ssl_done independently from gss_done, instead of trying to use the same boolean for both. Author: Andrew Gierth Discussion: https://postgr.es/m/87h82kzwqn.fsf@news-spur.riddles.org.uk Backpatch: 12-, where GSSAPI encryption was added.
1 parent c08da32 commit 79e594c

File tree

1 file changed

+24
-13
lines changed

1 file changed

+24
-13
lines changed

src/backend/postmaster/postmaster.c

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ static void BackendRun(Port *port) pg_attribute_noreturn();
404404
static void ExitPostmaster(int status) pg_attribute_noreturn();
405405
static int ServerLoop(void);
406406
static int BackendStartup(Port *port);
407-
static int ProcessStartupPacket(Port *port, bool secure_done);
407+
static int ProcessStartupPacket(Port *port, bool ssl_done, bool gss_done);
408408
static void SendNegotiateProtocolVersion(List *unrecognized_protocol_options);
409409
static void processCancelRequest(Port *port, void *pkt);
410410
static int initMasks(fd_set *rmask);
@@ -1891,11 +1891,15 @@ initMasks(fd_set *rmask)
18911891
* send anything to the client, which would typically be appropriate
18921892
* if we detect a communications failure.)
18931893
*
1894-
* Set secure_done when negotiation of an encrypted layer (currently, TLS or
1895-
* GSSAPI) is already completed.
1894+
* Set ssl_done and/or gss_done when negotiation of an encrypted layer
1895+
* (currently, TLS or GSSAPI) is completed. A successful negotiation of either
1896+
* encryption layer sets both flags, but a rejected negotiation sets only the
1897+
* flag for that layer, since the client may wish to try the other one. We
1898+
* should make no assumption here about the order in which the client may make
1899+
* requests.
18961900
*/
18971901
static int
1898-
ProcessStartupPacket(Port *port, bool secure_done)
1902+
ProcessStartupPacket(Port *port, bool ssl_done, bool gss_done)
18991903
{
19001904
int32 len;
19011905
void *buf;
@@ -1928,7 +1932,7 @@ ProcessStartupPacket(Port *port, bool secure_done)
19281932
if (pq_getbytes(((char *) &len) + 1, 3) == EOF)
19291933
{
19301934
/* Got a partial length word, so bleat about that */
1931-
if (!secure_done)
1935+
if (!ssl_done && !gss_done)
19321936
ereport(COMMERROR,
19331937
(errcode(ERRCODE_PROTOCOL_VIOLATION),
19341938
errmsg("incomplete startup packet")));
@@ -1980,7 +1984,7 @@ ProcessStartupPacket(Port *port, bool secure_done)
19801984
return STATUS_ERROR;
19811985
}
19821986

1983-
if (proto == NEGOTIATE_SSL_CODE && !secure_done)
1987+
if (proto == NEGOTIATE_SSL_CODE && !ssl_done)
19841988
{
19851989
char SSLok;
19861990

@@ -2009,11 +2013,14 @@ ProcessStartupPacket(Port *port, bool secure_done)
20092013
if (SSLok == 'S' && secure_open_server(port) == -1)
20102014
return STATUS_ERROR;
20112015
#endif
2012-
/* regular startup packet, cancel, etc packet should follow... */
2013-
/* but not another SSL negotiation request */
2014-
return ProcessStartupPacket(port, true);
2016+
/*
2017+
* regular startup packet, cancel, etc packet should follow, but not
2018+
* another SSL negotiation request, and a GSS request should only
2019+
* follow if SSL was rejected (client may negotiate in either order)
2020+
*/
2021+
return ProcessStartupPacket(port, true, SSLok == 'S');
20152022
}
2016-
else if (proto == NEGOTIATE_GSS_CODE && !secure_done)
2023+
else if (proto == NEGOTIATE_GSS_CODE && !gss_done)
20172024
{
20182025
char GSSok = 'N';
20192026
#ifdef ENABLE_GSS
@@ -2036,8 +2043,12 @@ ProcessStartupPacket(Port *port, bool secure_done)
20362043
if (GSSok == 'G' && secure_open_gssapi(port) == -1)
20372044
return STATUS_ERROR;
20382045
#endif
2039-
/* Won't ever see more than one negotiation request */
2040-
return ProcessStartupPacket(port, true);
2046+
/*
2047+
* regular startup packet, cancel, etc packet should follow, but not
2048+
* another GSS negotiation request, and an SSL request should only
2049+
* follow if GSS was rejected (client may negotiate in either order)
2050+
*/
2051+
return ProcessStartupPacket(port, GSSok == 'G', true);
20412052
}
20422053

20432054
/* Could add additional special packet types here */
@@ -4339,7 +4350,7 @@ BackendInitialize(Port *port)
43394350
* Receive the startup packet (which might turn out to be a cancel request
43404351
* packet).
43414352
*/
4342-
status = ProcessStartupPacket(port, false);
4353+
status = ProcessStartupPacket(port, false, false);
43434354

43444355
/*
43454356
* Stop here if it was bad or a cancel packet. ProcessStartupPacket

0 commit comments

Comments
 (0)