@@ -404,7 +404,7 @@ static void BackendRun(Port *port) pg_attribute_noreturn();
404404static void ExitPostmaster (int status ) pg_attribute_noreturn ();
405405static int ServerLoop (void );
406406static 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 );
408408static void SendNegotiateProtocolVersion (List * unrecognized_protocol_options );
409409static void processCancelRequest (Port * port , void * pkt );
410410static int initMasks (fd_set * rmask );
@@ -1914,11 +1914,15 @@ initMasks(fd_set *rmask)
19141914 * send anything to the client, which would typically be appropriate
19151915 * if we detect a communications failure.)
19161916 *
1917- * Set secure_done when negotiation of an encrypted layer (currently, TLS or
1918- * GSSAPI) is already completed.
1917+ * Set ssl_done and/or gss_done when negotiation of an encrypted layer
1918+ * (currently, TLS or GSSAPI) is completed. A successful negotiation of either
1919+ * encryption layer sets both flags, but a rejected negotiation sets only the
1920+ * flag for that layer, since the client may wish to try the other one. We
1921+ * should make no assumption here about the order in which the client may make
1922+ * requests.
19191923 */
19201924static int
1921- ProcessStartupPacket (Port * port , bool secure_done )
1925+ ProcessStartupPacket (Port * port , bool ssl_done , bool gss_done )
19221926{
19231927 int32 len ;
19241928 void * buf ;
@@ -1951,7 +1955,7 @@ ProcessStartupPacket(Port *port, bool secure_done)
19511955 if (pq_getbytes (((char * ) & len ) + 1 , 3 ) == EOF )
19521956 {
19531957 /* Got a partial length word, so bleat about that */
1954- if (!secure_done )
1958+ if (!ssl_done && ! gss_done )
19551959 ereport (COMMERROR ,
19561960 (errcode (ERRCODE_PROTOCOL_VIOLATION ),
19571961 errmsg ("incomplete startup packet" )));
@@ -2003,7 +2007,7 @@ ProcessStartupPacket(Port *port, bool secure_done)
20032007 return STATUS_ERROR ;
20042008 }
20052009
2006- if (proto == NEGOTIATE_SSL_CODE && !secure_done )
2010+ if (proto == NEGOTIATE_SSL_CODE && !ssl_done )
20072011 {
20082012 char SSLok ;
20092013
@@ -2032,11 +2036,14 @@ ProcessStartupPacket(Port *port, bool secure_done)
20322036 if (SSLok == 'S' && secure_open_server (port ) == -1 )
20332037 return STATUS_ERROR ;
20342038#endif
2035- /* regular startup packet, cancel, etc packet should follow... */
2036- /* but not another SSL negotiation request */
2037- return ProcessStartupPacket (port , true);
2039+ /*
2040+ * regular startup packet, cancel, etc packet should follow, but not
2041+ * another SSL negotiation request, and a GSS request should only
2042+ * follow if SSL was rejected (client may negotiate in either order)
2043+ */
2044+ return ProcessStartupPacket (port , true, SSLok == 'S' );
20382045 }
2039- else if (proto == NEGOTIATE_GSS_CODE && !secure_done )
2046+ else if (proto == NEGOTIATE_GSS_CODE && !gss_done )
20402047 {
20412048 char GSSok = 'N' ;
20422049#ifdef ENABLE_GSS
@@ -2059,8 +2066,12 @@ ProcessStartupPacket(Port *port, bool secure_done)
20592066 if (GSSok == 'G' && secure_open_gssapi (port ) == -1 )
20602067 return STATUS_ERROR ;
20612068#endif
2062- /* Won't ever see more than one negotiation request */
2063- return ProcessStartupPacket (port , true);
2069+ /*
2070+ * regular startup packet, cancel, etc packet should follow, but not
2071+ * another GSS negotiation request, and an SSL request should only
2072+ * follow if GSS was rejected (client may negotiate in either order)
2073+ */
2074+ return ProcessStartupPacket (port , GSSok == 'G' , true);
20642075 }
20652076
20662077 /* Could add additional special packet types here */
@@ -4412,7 +4423,7 @@ BackendInitialize(Port *port)
44124423 * Receive the startup packet (which might turn out to be a cancel request
44134424 * packet).
44144425 */
4415- status = ProcessStartupPacket (port , false);
4426+ status = ProcessStartupPacket (port , false, false );
44164427
44174428 /*
44184429 * Stop here if it was bad or a cancel packet. ProcessStartupPacket
0 commit comments