With gssencmode='require', check credential cache before connecting
authorHeikki Linnakangas <[email protected]>
Sun, 7 Apr 2024 23:49:35 +0000 (02:49 +0300)
committerHeikki Linnakangas <[email protected]>
Sun, 7 Apr 2024 23:49:35 +0000 (02:49 +0300)
Previously, libpq would establish the TCP connection, and then
immediately disconnect if the credentials were not available.  The
same thing happened if you tried to use a Unix domain socket with
gssencmode=require. Check those conditions before establishing the TCP
connection.

This is a very minor issue, but my motivation to do this now is that
I'm about to add more detail to the tests for encryption negotiation.
This makes the case of gssencmode=require but no credentials
configured fail at the same stage as with gssencmode=require and
GSSAPI support not compiled at all. That avoids having to deal with
variations in expected output depending on build options.

Discussion: https://www.postgresql.org/message-id/CAEze2Wja8VUoZygCepwUeiCrWa4jP316k0mvJrOW4PFmWP0Tcw@mail.gmail.com

src/interfaces/libpq/fe-connect.c

index 01e49c6975e2fd6d20d6d797c90a84677e4510ab..4f477f97527efc84952ef0ed8bed6c344873a616 100644 (file)
@@ -2855,6 +2855,33 @@ keep_going:                      /* We will come back to here until there is
                    /* Remember current address for possible use later */
                    memcpy(&conn->raddr, &addr_cur->addr, sizeof(SockAddr));
 
+#ifdef ENABLE_GSS
+
+                   /*
+                    * Before establishing the connection, check if it's
+                    * doomed to fail because gssencmode='require' but GSSAPI
+                    * is not available.
+                    */
+                   if (conn->gssencmode[0] == 'r')
+                   {
+                       if (conn->raddr.addr.ss_family == AF_UNIX)
+                       {
+                           libpq_append_conn_error(conn,
+                                                   "GSSAPI encryption required but it is not supported over a local socket)");
+                           goto error_return;
+                       }
+                       if (conn->gcred == GSS_C_NO_CREDENTIAL)
+                       {
+                           if (!pg_GSS_have_cred_cache(&conn->gcred))
+                           {
+                               libpq_append_conn_error(conn,
+                                                       "GSSAPI encryption required but no credential cache");
+                               goto error_return;
+                           }
+                       }
+                   }
+#endif
+
                    /*
                     * Set connip, too.  Note we purposely ignore strdup
                     * failure; not a big problem if it fails.
@@ -3218,7 +3245,7 @@ keep_going:                       /* We will come back to here until there is
                 * for GSSAPI Encryption (and skip past SSL negotiation and
                 * regular startup below).
                 */
-               if (conn->try_gss && !conn->gctx)
+               if (conn->try_gss && !conn->gctx && conn->gcred == GSS_C_NO_CREDENTIAL)
                    conn->try_gss = pg_GSS_have_cred_cache(&conn->gcred);
                if (conn->try_gss && !conn->gctx)
                {
@@ -3237,8 +3264,9 @@ keep_going:                       /* We will come back to here until there is
                }
                else if (!conn->gctx && conn->gssencmode[0] == 'r')
                {
+                   /* XXX: shouldn't happen */
                    libpq_append_conn_error(conn,
-                                           "GSSAPI encryption required but was impossible (possibly no credential cache, no server support, or using a local socket)");
+                                           "GSSAPI encryption required but was impossible");
                    goto error_return;
                }
 #endif