Skip to content

Commit f2fa0c6

Browse files
committed
Clear auth context correctly when re-connecting after failed auth attempt.
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 210eb9b 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
1 parent 9d09842 commit f2fa0c6

File tree

2 files changed

+47
-36
lines changed

2 files changed

+47
-36
lines changed

src/interfaces/libpq/fe-auth.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -618,7 +618,12 @@ pg_SSPI_startup(PGconn *conn, int use_negotiate)
618618
SECURITY_STATUS r;
619619
TimeStamp expire;
620620

621-
conn->sspictx = NULL;
621+
if (conn->sspictx)
622+
{
623+
printfPQExpBuffer(&conn->errorMessage,
624+
libpq_gettext("duplicate SSPI authentication request\n"));
625+
return STATUS_ERROR;
626+
}
622627

623628
/*
624629
* Retreive credentials handle

src/interfaces/libpq/fe-connect.c

Lines changed: 41 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -401,15 +401,56 @@ pqDropConnection(PGconn *conn, bool flushInput)
401401
{
402402
/* Drop any SSL state */
403403
pqsecure_close(conn);
404+
404405
/* Close the socket itself */
405406
if (conn->sock >= 0)
406407
closesocket(conn->sock);
407408
conn->sock = -1;
409+
408410
/* Optionally discard any unread data */
409411
if (flushInput)
410412
conn->inStart = conn->inCursor = conn->inEnd = 0;
413+
411414
/* Always discard any unsent data */
412415
conn->outCount = 0;
416+
417+
/* Free authentication state */
418+
#ifdef ENABLE_GSS
419+
{
420+
OM_uint32 min_s;
421+
422+
if (conn->gctx)
423+
gss_delete_sec_context(&min_s, &conn->gctx, GSS_C_NO_BUFFER);
424+
if (conn->gtarg_nam)
425+
gss_release_name(&min_s, &conn->gtarg_nam);
426+
if (conn->ginbuf.length)
427+
gss_release_buffer(&min_s, &conn->ginbuf);
428+
if (conn->goutbuf.length)
429+
gss_release_buffer(&min_s, &conn->goutbuf);
430+
}
431+
#endif
432+
#ifdef ENABLE_SSPI
433+
if (conn->ginbuf.length)
434+
free(conn->ginbuf.value);
435+
conn->ginbuf.length = 0;
436+
conn->ginbuf.value = NULL;
437+
if (conn->sspitarget)
438+
free(conn->sspitarget);
439+
conn->sspitarget = NULL;
440+
if (conn->sspicred)
441+
{
442+
FreeCredentialsHandle(conn->sspicred);
443+
free(conn->sspicred);
444+
conn->sspicred = NULL;
445+
}
446+
if (conn->sspictx)
447+
{
448+
DeleteSecurityContext(conn->sspictx);
449+
free(conn->sspictx);
450+
conn->sspictx = NULL;
451+
}
452+
conn->usesspi = 0;
453+
#endif
413454
}
414455

415456

@@ -2998,41 +3039,6 @@ closePGconn(PGconn *conn)
29983039
if (conn->lobjfuncs)
29993040
free(conn->lobjfuncs);
30003041
conn->lobjfuncs = NULL;
3001-
#ifdef ENABLE_GSS
3002-
{
3003-
OM_uint32 min_s;
3004-
3005-
if (conn->gctx)
3006-
gss_delete_sec_context(&min_s, &conn->gctx, GSS_C_NO_BUFFER);
3007-
if (conn->gtarg_nam)
3008-
gss_release_name(&min_s, &conn->gtarg_nam);
3009-
if (conn->ginbuf.length)
3010-
gss_release_buffer(&min_s, &conn->ginbuf);
3011-
if (conn->goutbuf.length)
3012-
gss_release_buffer(&min_s, &conn->goutbuf);
3013-
}
3014-
#endif
3015-
#ifdef ENABLE_SSPI
3016-
if (conn->ginbuf.length)
3017-
free(conn->ginbuf.value);
3018-
conn->ginbuf.length = 0;
3019-
conn->ginbuf.value = NULL;
3020-
if (conn->sspitarget)
3021-
free(conn->sspitarget);
3022-
conn->sspitarget = NULL;
3023-
if (conn->sspicred)
3024-
{
3025-
FreeCredentialsHandle(conn->sspicred);
3026-
free(conn->sspicred);
3027-
conn->sspicred = NULL;
3028-
}
3029-
if (conn->sspictx)
3030-
{
3031-
DeleteSecurityContext(conn->sspictx);
3032-
free(conn->sspictx);
3033-
conn->sspictx = NULL;
3034-
}
3035-
#endif
30363042
}
30373043

30383044
/*

0 commit comments

Comments
 (0)