Fix fallback behavior when server sends an ERROR early at startup
authorHeikki Linnakangas <[email protected]>
Fri, 26 Jul 2024 11:52:08 +0000 (14:52 +0300)
committerHeikki Linnakangas <[email protected]>
Fri, 26 Jul 2024 12:00:36 +0000 (15:00 +0300)
With sslmode=prefer, the desired behavior is to completely fail the
connection attempt, *not* fall back to a plaintext connection, if the
server responds to the SSLRequest with an error ('E') response instead
of rejecting SSL with an 'N' response. This was broken in commit
05fd30c0e7.

Reported-by: Jacob Champion
Reviewed-by: Michael Paquier
Discussion: https://www.postgresql.org/message-id/CAOYmi%2Bnwvu21mJ4DYKUa98HdfM_KZJi7B1MhyXtnsyOO-PB6Ww%40mail.gmail.com
Backpatch-through: 17

src/interfaces/libpq/fe-connect.c

index e003279fb6c4983bb3b3db732eb275a19e4b4cd7..360d9a454760ffe2a1fed1b3451586ef6bc08e71 100644 (file)
@@ -3521,6 +3521,12 @@ keep_going:                      /* We will come back to here until there is
                         * byte here.
                         */
                        conn->status = CONNECTION_AWAITING_RESPONSE;
+
+                       /*
+                        * Don't fall back to a plaintext connection after
+                        * reading the error.
+                        */
+                       conn->failed_enc_methods |= conn->allowed_enc_methods & (~conn->current_enc_method);
                        goto keep_going;
                    }
                    else
@@ -3612,6 +3618,13 @@ keep_going:                      /* We will come back to here until there is
                         * into AWAITING_RESPONSE state and let the code there
                         * deal with it.  Note we have *not* consumed the "E"
                         * byte here.
+                        *
+                        * Note that unlike on an error response to
+                        * SSLRequest, we allow falling back to SSL or
+                        * plaintext connection here.  GSS support was
+                        * introduced in PostgreSQL version 12, so an error
+                        * response might mean that we are connecting to a
+                        * pre-v12 server.
                         */
                        conn->status = CONNECTION_AWAITING_RESPONSE;
                        goto keep_going;
@@ -3659,6 +3672,10 @@ keep_going:                      /* We will come back to here until there is
                }
                else if (pollres == PGRES_POLLING_FAILED)
                {
+                   /*
+                    * GSS handshake failed.  We will retry with an SSL or
+                    * plaintext connection, if permitted by the options.
+                    */
                    CONNECTION_FAILED();
                }
                /* Else, return POLLING_READING or POLLING_WRITING status */