]> granicus.if.org Git - postgresql/commitdiff
Clear auth context correctly when re-connecting after failed auth attempt.
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Wed, 7 Jun 2017 11:01:46 +0000 (14:01 +0300)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Wed, 7 Jun 2017 11:04:54 +0000 (14:04 +0300)
If authentication over an SSL connection fails, with sslmode=prefer,
libpq will reconnect without SSL and retry. However, we did not clear
the variables related to GSS, SSPI, and SASL authentication state, when
reconnecting. Because of that, the second authentication attempt would
always fail with a "duplicate GSS/SASL authentication request" error.
pg_SSPI_startup did not check for duplicate authentication requests like
the corresponding GSS and SASL functions, so with SSPI, you would leak
some memory instead.

Another way this could manifest itself, on version 10, is if you list
multiple hostnames in the "host" parameter. If the first server requests
Kerberos or SCRAM authentication, but it fails, the attempts to connect to
the other servers will also fail with "duplicate authentication request"
errors.

To fix, move the clearing of authentication state from closePGconn to
pgDropConnection, so that it is cleared also when re-connecting.

Patch by Michael Paquier, with some kibitzing by me.

Backpatch down to 9.3. 9.2 has the same bug, but the code around closing
the connection is somewhat different, so that this patch doesn't apply.
To fix this in 9.2, I think we would need to back-port commit 210eb9b743
first, and then apply this patch. However, given that we only bumped into
this in our own testing, we haven't heard any reports from users about
this, and that 9.2 will be end-of-lifed in a couple of months anyway, it
doesn't seem worth the risk and trouble.

Discussion: https://www.postgresql.org/message-id/CAB7nPqRuOUm0MyJaUy9L3eXYJU3AKCZ-0-03=-aDTZJGV4GyWw@mail.gmail.com

src/interfaces/libpq/fe-auth.c
src/interfaces/libpq/fe-connect.c

index 493ef82d4a7cefcc29f5437a26f3a63449f1b60c..ab057e945a70cbc95c4fc09d51077fb928694ca2 100644 (file)
@@ -372,7 +372,12 @@ pg_SSPI_startup(PGconn *conn, int use_negotiate)
        SECURITY_STATUS r;
        TimeStamp       expire;
 
-       conn->sspictx = NULL;
+       if (conn->sspictx)
+       {
+               printfPQExpBuffer(&conn->errorMessage,
+                                       libpq_gettext("duplicate SSPI authentication request\n"));
+               return STATUS_ERROR;
+       }
 
        /*
         * Retrieve credentials handle
index 8c7169e171d0dac156ecf29befda7d398ca53150..ec468870d2a5194f1abee36dcccd22e6ff986318 100644 (file)
@@ -401,15 +401,56 @@ pqDropConnection(PGconn *conn, bool flushInput)
 {
        /* Drop any SSL state */
        pqsecure_close(conn);
+
        /* Close the socket itself */
        if (conn->sock != PGINVALID_SOCKET)
                closesocket(conn->sock);
        conn->sock = PGINVALID_SOCKET;
+
        /* Optionally discard any unread data */
        if (flushInput)
                conn->inStart = conn->inCursor = conn->inEnd = 0;
+
        /* Always discard any unsent data */
        conn->outCount = 0;
+
+       /* Free authentication state */
+#ifdef ENABLE_GSS
+       {
+               OM_uint32       min_s;
+
+               if (conn->gctx)
+                       gss_delete_sec_context(&min_s, &conn->gctx, GSS_C_NO_BUFFER);
+               if (conn->gtarg_nam)
+                       gss_release_name(&min_s, &conn->gtarg_nam);
+               if (conn->ginbuf.length)
+                       gss_release_buffer(&min_s, &conn->ginbuf);
+               if (conn->goutbuf.length)
+                       gss_release_buffer(&min_s, &conn->goutbuf);
+       }
+#endif
+#ifdef ENABLE_SSPI
+       if (conn->ginbuf.length)
+               free(conn->ginbuf.value);
+       conn->ginbuf.length = 0;
+       conn->ginbuf.value = NULL;
+       if (conn->sspitarget)
+               free(conn->sspitarget);
+       conn->sspitarget = NULL;
+       if (conn->sspicred)
+       {
+               FreeCredentialsHandle(conn->sspicred);
+               free(conn->sspicred);
+               conn->sspicred = NULL;
+       }
+       if (conn->sspictx)
+       {
+               DeleteSecurityContext(conn->sspictx);
+               free(conn->sspictx);
+               conn->sspictx = NULL;
+       }
+       conn->usesspi = 0;
+#endif
 }
 
 
@@ -3007,41 +3048,6 @@ closePGconn(PGconn *conn)
        if (conn->lobjfuncs)
                free(conn->lobjfuncs);
        conn->lobjfuncs = NULL;
-#ifdef ENABLE_GSS
-       {
-               OM_uint32       min_s;
-
-               if (conn->gctx)
-                       gss_delete_sec_context(&min_s, &conn->gctx, GSS_C_NO_BUFFER);
-               if (conn->gtarg_nam)
-                       gss_release_name(&min_s, &conn->gtarg_nam);
-               if (conn->ginbuf.length)
-                       gss_release_buffer(&min_s, &conn->ginbuf);
-               if (conn->goutbuf.length)
-                       gss_release_buffer(&min_s, &conn->goutbuf);
-       }
-#endif
-#ifdef ENABLE_SSPI
-       if (conn->ginbuf.length)
-               free(conn->ginbuf.value);
-       conn->ginbuf.length = 0;
-       conn->ginbuf.value = NULL;
-       if (conn->sspitarget)
-               free(conn->sspitarget);
-       conn->sspitarget = NULL;
-       if (conn->sspicred)
-       {
-               FreeCredentialsHandle(conn->sspicred);
-               free(conn->sspicred);
-               conn->sspicred = NULL;
-       }
-       if (conn->sspictx)
-       {
-               DeleteSecurityContext(conn->sspictx);
-               free(conn->sspictx);
-               conn->sspictx = NULL;
-       }
-#endif
 }
 
 /*