Skip to content

Commit b3a5bf7

Browse files
committed
Fix bugs in libpq's GSSAPI encryption support.
The critical issue fixed here is that if a GSSAPI-encrypted connection is successfully made, pqsecure_open_gss() cleared conn->allow_ssl_try, as an admittedly-hacky way of preventing us from then trying to tunnel SSL encryption over the already-encrypted connection. The problem with that is that if we abandon the GSSAPI connection because of a failure during authentication, we would not attempt SSL encryption in the next try with the same server. This can lead to unexpected connection failure, or silently getting a non-encrypted connection where an encrypted one is expected. Fortunately, we'd only manage to make a GSSAPI-encrypted connection if both client and server hold valid tickets in the same Kerberos infrastructure, which is a relatively uncommon environment. Nonetheless this is a very nasty bug with potential security consequences. To fix, don't reset the flag, instead adding a check for conn->gssenc being already true when deciding whether to try to initiate SSL. While here, fix some lesser issues in libpq's GSSAPI code: * Use the need_new_connection stanza when dropping an attempted GSSAPI connection, instead of partially duplicating that code. The consequences of this are pretty minor: AFAICS it could only lead to auth_req_received or password_needed remaining set when they shouldn't, which is not too harmful. * Fix pg_GSS_error() to not repeat the "mprefix" it's given multiple times, and to notice any failure return from gss_display_status(). * Avoid gratuitous dependency on NI_MAXHOST in pg_GSS_load_servicename(). Per report from Mikael Gustavsson. Back-patch to v12 where this code was introduced. Discussion: https://postgr.es/m/e5b0b6ed05764324a2f3fe7acfc766d5@smhi.se
1 parent d379659 commit b3a5bf7

File tree

3 files changed

+29
-28
lines changed

3 files changed

+29
-28
lines changed

src/interfaces/libpq/fe-connect.c

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2814,11 +2814,16 @@ PQconnectPoll(PGconn *conn)
28142814
#ifdef USE_SSL
28152815

28162816
/*
2817-
* If SSL is enabled and we haven't already got it running,
2818-
* request it instead of sending the startup message.
2817+
* If SSL is enabled and we haven't already got encryption of
2818+
* some sort running, request SSL instead of sending the
2819+
* startup message.
28192820
*/
28202821
if (conn->allow_ssl_try && !conn->wait_ssl_try &&
2821-
!conn->ssl_in_use)
2822+
!conn->ssl_in_use
2823+
#ifdef ENABLE_GSS
2824+
&& !conn->gssenc
2825+
#endif
2826+
)
28222827
{
28232828
ProtocolVersion pv;
28242829

@@ -2947,6 +2952,7 @@ PQconnectPoll(PGconn *conn)
29472952
}
29482953
/* Otherwise, proceed with normal startup */
29492954
conn->allow_ssl_try = false;
2955+
/* We can proceed using this connection */
29502956
conn->status = CONNECTION_MADE;
29512957
return PGRES_POLLING_WRITING;
29522958
}
@@ -3044,8 +3050,7 @@ PQconnectPoll(PGconn *conn)
30443050
* don't hang up the socket, though.
30453051
*/
30463052
conn->try_gss = false;
3047-
pqDropConnection(conn, true);
3048-
conn->status = CONNECTION_NEEDED;
3053+
need_new_connection = true;
30493054
goto keep_going;
30503055
}
30513056

@@ -3063,6 +3068,7 @@ PQconnectPoll(PGconn *conn)
30633068
}
30643069

30653070
conn->try_gss = false;
3071+
/* We can proceed using this connection */
30663072
conn->status = CONNECTION_MADE;
30673073
return PGRES_POLLING_WRITING;
30683074
}
@@ -3091,8 +3097,7 @@ PQconnectPoll(PGconn *conn)
30913097
* the current connection to do so, though.
30923098
*/
30933099
conn->try_gss = false;
3094-
pqDropConnection(conn, true);
3095-
conn->status = CONNECTION_NEEDED;
3100+
need_new_connection = true;
30963101
goto keep_going;
30973102
}
30983103
return pollres;
@@ -3263,10 +3268,9 @@ PQconnectPoll(PGconn *conn)
32633268
*/
32643269
if (conn->gssenc && conn->gssencmode[0] == 'p')
32653270
{
3266-
/* postmaster expects us to drop the connection */
3271+
/* only retry once */
32673272
conn->try_gss = false;
3268-
pqDropConnection(conn, true);
3269-
conn->status = CONNECTION_NEEDED;
3273+
need_new_connection = true;
32703274
goto keep_going;
32713275
}
32723276
#endif

src/interfaces/libpq/fe-gssapi-common.c

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,21 @@
2020

2121
/*
2222
* Fetch all errors of a specific type and append to "str".
23+
* Each error string is preceded by a space.
2324
*/
2425
static void
25-
pg_GSS_error_int(PQExpBuffer str, const char *mprefix,
26-
OM_uint32 stat, int type)
26+
pg_GSS_error_int(PQExpBuffer str, OM_uint32 stat, int type)
2727
{
2828
OM_uint32 lmin_s;
2929
gss_buffer_desc lmsg;
3030
OM_uint32 msg_ctx = 0;
3131

3232
do
3333
{
34-
gss_display_status(&lmin_s, stat, type,
35-
GSS_C_NO_OID, &msg_ctx, &lmsg);
36-
appendPQExpBuffer(str, "%s: %s\n", mprefix, (char *) lmsg.value);
34+
if (gss_display_status(&lmin_s, stat, type, GSS_C_NO_OID,
35+
&msg_ctx, &lmsg) != GSS_S_COMPLETE)
36+
break;
37+
appendPQExpBuffer(str, " %s", (char *) lmsg.value);
3738
gss_release_buffer(&lmin_s, &lmsg);
3839
} while (msg_ctx);
3940
}
@@ -46,12 +47,11 @@ pg_GSS_error(const char *mprefix, PGconn *conn,
4647
OM_uint32 maj_stat, OM_uint32 min_stat)
4748
{
4849
resetPQExpBuffer(&conn->errorMessage);
49-
50-
/* Fetch major error codes */
51-
pg_GSS_error_int(&conn->errorMessage, mprefix, maj_stat, GSS_C_GSS_CODE);
52-
53-
/* Add the minor codes as well */
54-
pg_GSS_error_int(&conn->errorMessage, mprefix, min_stat, GSS_C_MECH_CODE);
50+
appendPQExpBuffer(&conn->errorMessage, "%s:", mprefix);
51+
pg_GSS_error_int(&conn->errorMessage, maj_stat, GSS_C_GSS_CODE);
52+
appendPQExpBufferChar(&conn->errorMessage, ':');
53+
pg_GSS_error_int(&conn->errorMessage, min_stat, GSS_C_MECH_CODE);
54+
appendPQExpBufferChar(&conn->errorMessage, '\n');
5555
}
5656

5757
/*
@@ -103,7 +103,7 @@ pg_GSS_load_servicename(PGconn *conn)
103103
* Import service principal name so the proper ticket can be acquired by
104104
* the GSSAPI system.
105105
*/
106-
maxlen = NI_MAXHOST + strlen(conn->krbsrvname) + 2;
106+
maxlen = strlen(conn->krbsrvname) + strlen(host) + 2;
107107
temp_gbuf.value = (char *) malloc(maxlen);
108108
if (!temp_gbuf.value)
109109
{

src/interfaces/libpq/fe-secure-gssapi.c

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -647,17 +647,14 @@ pqsecure_open_gss(PGconn *conn)
647647
if (output.length == 0)
648648
{
649649
/*
650-
* We're done - hooray! Kind of gross, but we need to disable SSL
651-
* here so that we don't accidentally tunnel one over the other.
650+
* We're done - hooray! Set flag to tell the low-level I/O routines
651+
* to do GSS wrapping/unwrapping.
652652
*/
653-
#ifdef USE_SSL
654-
conn->allow_ssl_try = false;
655-
#endif
653+
conn->gssenc = true;
656654

657655
/* Clean up */
658656
gss_release_cred(&minor, &conn->gcred);
659657
conn->gcred = GSS_C_NO_CREDENTIAL;
660-
conn->gssenc = true;
661658
gss_release_buffer(&minor, &output);
662659

663660
/*

0 commit comments

Comments
 (0)