From: Tom Lane <tgl@sss.pgh.pa.us>
To: Chris Gooch <cgooch@bamfunds.com>
Cc: Jacob Champion <jacob.champion@enterprisedb.com>
Cc: pgsql-bugs@lists.postgresql.org <pgsql-bugs@lists.postgresql.org>
Subject: Re: [EXT] Re: GSS Auth issue when user member of lots of AD groups
Date: Sat, 24 May 2025 15:38:48 -0400
Message-ID: <3125964.1748115528@sss.pgh.pa.us> (raw)
In-Reply-To: <3125813.1748115425@sss.pgh.pa.us>
References: <DS0PR22MB5971A9C8A3F44BCC6293C4DABE99A@DS0PR22MB5971.namprd22.prod.outlook.com>
<1529314.1747928806@sss.pgh.pa.us>
<CAOYmi+nZpOu_Yd_dvQQehK78B48MB-TT1Z7Myp1xSQ1uUHHZVQ@mail.gmail.com>
<1536692.1747933034@sss.pgh.pa.us>
<CAOYmi+mPdZwNe16yozk40G8hW3d1Rxnoipu0dw52AiuZRoabaA@mail.gmail.com>
<1647590.1747936713@sss.pgh.pa.us>
<DS0PR22MB597134B3D28AC101C8936007BE9BA@DS0PR22MB5971.namprd22.prod.outlook.com>
<3060113.1748096813@sss.pgh.pa.us>
<3125813.1748115425@sss.pgh.pa.us>
I wrote:
> OK, here's a set of draft patches for that.
Sigh, it'd help if I actually attached the patches ...
regards, tom lane
Attachments:
[text/x-diff] gssapi-fix-HEAD.patch (11.6K, ../3125964.1748115528@sss.pgh.pa.us/2-gssapi-fix-HEAD.patch)
download | inline diff:diff --git a/src/backend/libpq/be-secure-gssapi.c b/src/backend/libpq/be-secure-gssapi.cindex 717ba9824f9..910c7f22711 100644--- a/src/backend/libpq/be-secure-gssapi.c+++ b/src/backend/libpq/be-secure-gssapi.c@@ -46,11 +46,19 @@
* don't want the other side to send arbitrarily huge packets as we
* would have to allocate memory for them to then pass them to GSSAPI.
*
- * Therefore, these two #define's are effectively part of the protocol+ * Therefore, this #define is effectively part of the protocol
* spec and can't ever be changed.
*/
-#define PQ_GSS_SEND_BUFFER_SIZE 16384-#define PQ_GSS_RECV_BUFFER_SIZE 16384+#define PQ_GSS_MAX_PACKET_SIZE 16384++/*+ * However, during the authentication exchange we must cope with whatever+ * message size the GSSAPI library wants to send (because our protocol+ * doesn't support splitting those messages). Depending on configuration+ * those messages might be as much as 64kB. To provide some safety margin+ * we use 128kB buffers during transport negotiation.+ */+#define PQ_GSS_AUTH_BUFFER_SIZE 131072
/*
* Since we manage at most one GSS-encrypted connection per backend,
@@ -210,12 +218,12 @@ be_gssapi_write(Port *port, const void *ptr, size_t len)
errno = ECONNRESET;
return -1;
}
- if (output.length > PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32))+ if (output.length > PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32))
{
ereport(COMMERROR,
(errmsg("server tried to send oversize GSSAPI packet (%zu > %zu)",
(size_t) output.length,
- PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32))));+ PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32))));
errno = ECONNRESET;
return -1;
}
@@ -346,12 +354,12 @@ be_gssapi_read(Port *port, void *ptr, size_t len)
/* Decode the packet length and check for overlength packet */
input.length = pg_ntoh32(*(uint32 *) PqGSSRecvBuffer);
- if (input.length > PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32))+ if (input.length > PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32))
{
ereport(COMMERROR,
(errmsg("oversize GSSAPI packet sent by the client (%zu > %zu)",
(size_t) input.length,
- PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32))));+ PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32))));
errno = ECONNRESET;
return -1;
}
@@ -517,10 +525,13 @@ secure_open_gssapi(Port *port)
* that will never use them, and we ensure that the buffers are
* sufficiently aligned for the length-word accesses that we do in some
* places in this file.
+ *+ * We'll use PQ_GSS_AUTH_BUFFER_SIZE-sized buffers until transport+ * negotiation is complete, then switch to PQ_GSS_MAX_PACKET_SIZE.
*/
- PqGSSSendBuffer = malloc(PQ_GSS_SEND_BUFFER_SIZE);- PqGSSRecvBuffer = malloc(PQ_GSS_RECV_BUFFER_SIZE);- PqGSSResultBuffer = malloc(PQ_GSS_RECV_BUFFER_SIZE);+ PqGSSSendBuffer = malloc(PQ_GSS_AUTH_BUFFER_SIZE);+ PqGSSRecvBuffer = malloc(PQ_GSS_AUTH_BUFFER_SIZE);+ PqGSSResultBuffer = malloc(PQ_GSS_AUTH_BUFFER_SIZE);
if (!PqGSSSendBuffer || !PqGSSRecvBuffer || !PqGSSResultBuffer)
ereport(FATAL,
(errcode(ERRCODE_OUT_OF_MEMORY),
@@ -568,16 +579,16 @@ secure_open_gssapi(Port *port)
/*
* During initialization, packets are always fully consumed and
- * shouldn't ever be over PQ_GSS_RECV_BUFFER_SIZE in length.+ * shouldn't ever be over PQ_GSS_AUTH_BUFFER_SIZE in total length.
*
* Verify on our side that the client doesn't do something funny.
*/
- if (input.length > PQ_GSS_RECV_BUFFER_SIZE)+ if (input.length > PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32))
{
ereport(COMMERROR,
- (errmsg("oversize GSSAPI packet sent by the client (%zu > %d)",+ (errmsg("oversize GSSAPI packet sent by the client (%zu > %zu)",
(size_t) input.length,
- PQ_GSS_RECV_BUFFER_SIZE)));+ PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32))));
return -1;
}
@@ -631,12 +642,12 @@ secure_open_gssapi(Port *port)
{
uint32 netlen = pg_hton32(output.length);
- if (output.length > PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32))+ if (output.length > PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32))
{
ereport(COMMERROR,
(errmsg("server tried to send oversize GSSAPI packet (%zu > %zu)",
(size_t) output.length,
- PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32))));+ PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32))));
gss_release_buffer(&minor, &output);
return -1;
}
@@ -691,12 +702,29 @@ secure_open_gssapi(Port *port)
break;
}
+ /*+ * Release the large authentication buffers and allocate the ones we want+ * for normal operation.+ */+ free(PqGSSSendBuffer);+ free(PqGSSRecvBuffer);+ free(PqGSSResultBuffer);+ PqGSSSendBuffer = malloc(PQ_GSS_MAX_PACKET_SIZE);+ PqGSSRecvBuffer = malloc(PQ_GSS_MAX_PACKET_SIZE);+ PqGSSResultBuffer = malloc(PQ_GSS_MAX_PACKET_SIZE);+ if (!PqGSSSendBuffer || !PqGSSRecvBuffer || !PqGSSResultBuffer)+ ereport(FATAL,+ (errcode(ERRCODE_OUT_OF_MEMORY),+ errmsg("out of memory")));+ PqGSSSendLength = PqGSSSendNext = PqGSSSendConsumed = 0;+ PqGSSRecvLength = PqGSSResultLength = PqGSSResultNext = 0;+
/*
* Determine the max packet size which will fit in our buffer, after
* accounting for the length. be_gssapi_write will need this.
*/
major = gss_wrap_size_limit(&minor, port->gss->ctx, 1, GSS_C_QOP_DEFAULT,
- PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32),+ PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32),
&PqGSSMaxPktSize);
if (GSS_ERROR(major))
diff --git a/src/interfaces/libpq/fe-secure-gssapi.c b/src/interfaces/libpq/fe-secure-gssapi.cindex ce183bc04b4..9bdf0192f1e 100644--- a/src/interfaces/libpq/fe-secure-gssapi.c+++ b/src/interfaces/libpq/fe-secure-gssapi.c@@ -47,11 +47,19 @@
* don't want the other side to send arbitrarily huge packets as we
* would have to allocate memory for them to then pass them to GSSAPI.
*
- * Therefore, these two #define's are effectively part of the protocol+ * Therefore, this #define is effectively part of the protocol
* spec and can't ever be changed.
*/
-#define PQ_GSS_SEND_BUFFER_SIZE 16384-#define PQ_GSS_RECV_BUFFER_SIZE 16384+#define PQ_GSS_MAX_PACKET_SIZE 16384++/*+ * However, during the authentication exchange we must cope with whatever+ * message size the GSSAPI library wants to send (because our protocol+ * doesn't support splitting those messages). Depending on configuration+ * those messages might be as much as 64kB. To provide some safety margin+ * we use 128kB buffers during transport negotiation.+ */+#define PQ_GSS_AUTH_BUFFER_SIZE 131072
/*
* We need these state variables per-connection. To allow the functions
@@ -203,11 +211,11 @@ pg_GSS_write(PGconn *conn, const void *ptr, size_t len)
goto cleanup;
}
- if (output.length > PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32))+ if (output.length > PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32))
{
libpq_append_conn_error(conn, "client tried to send oversize GSSAPI packet (%zu > %zu)",
(size_t) output.length,
- PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32));+ PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32));
errno = EIO; /* for lack of a better idea */
goto cleanup;
}
@@ -342,11 +350,11 @@ pg_GSS_read(PGconn *conn, void *ptr, size_t len)
/* Decode the packet length and check for overlength packet */
input.length = pg_ntoh32(*(uint32 *) PqGSSRecvBuffer);
- if (input.length > PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32))+ if (input.length > PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32))
{
libpq_append_conn_error(conn, "oversize GSSAPI packet sent by the server (%zu > %zu)",
(size_t) input.length,
- PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32));+ PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32));
errno = EIO; /* for lack of a better idea */
return -1;
}
@@ -485,12 +493,15 @@ pqsecure_open_gss(PGconn *conn)
* initialize state variables. By malloc'ing the buffers separately, we
* ensure that they are sufficiently aligned for the length-word accesses
* that we do in some places in this file.
+ *+ * We'll use PQ_GSS_AUTH_BUFFER_SIZE-sized buffers until transport+ * negotiation is complete, then switch to PQ_GSS_MAX_PACKET_SIZE.
*/
if (PqGSSSendBuffer == NULL)
{
- PqGSSSendBuffer = malloc(PQ_GSS_SEND_BUFFER_SIZE);- PqGSSRecvBuffer = malloc(PQ_GSS_RECV_BUFFER_SIZE);- PqGSSResultBuffer = malloc(PQ_GSS_RECV_BUFFER_SIZE);+ PqGSSSendBuffer = malloc(PQ_GSS_AUTH_BUFFER_SIZE);+ PqGSSRecvBuffer = malloc(PQ_GSS_AUTH_BUFFER_SIZE);+ PqGSSResultBuffer = malloc(PQ_GSS_AUTH_BUFFER_SIZE);
if (!PqGSSSendBuffer || !PqGSSRecvBuffer || !PqGSSResultBuffer)
{
libpq_append_conn_error(conn, "out of memory");
@@ -564,13 +575,13 @@ pqsecure_open_gss(PGconn *conn)
* so leave a spot at the end for a NULL byte too) and report that
* back to the caller.
*/
- result = gss_read(conn, PqGSSRecvBuffer + PqGSSRecvLength, PQ_GSS_RECV_BUFFER_SIZE - PqGSSRecvLength - 1, &ret);+ result = gss_read(conn, PqGSSRecvBuffer + PqGSSRecvLength, PQ_GSS_AUTH_BUFFER_SIZE - PqGSSRecvLength - 1, &ret);
if (result != PGRES_POLLING_OK)
return result;
PqGSSRecvLength += ret;
- Assert(PqGSSRecvLength < PQ_GSS_RECV_BUFFER_SIZE);+ Assert(PqGSSRecvLength < PQ_GSS_AUTH_BUFFER_SIZE);
PqGSSRecvBuffer[PqGSSRecvLength] = '\0';
appendPQExpBuffer(&conn->errorMessage, "%s\n", PqGSSRecvBuffer + 1);
@@ -584,11 +595,11 @@ pqsecure_open_gss(PGconn *conn)
/* Get the length and check for over-length packet */
input.length = pg_ntoh32(*(uint32 *) PqGSSRecvBuffer);
- if (input.length > PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32))+ if (input.length > PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32))
{
libpq_append_conn_error(conn, "oversize GSSAPI packet sent by the server (%zu > %zu)",
(size_t) input.length,
- PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32));+ PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32));
return PGRES_POLLING_FAILED;
}
@@ -668,12 +679,33 @@ pqsecure_open_gss(PGconn *conn)
conn->gcred = GSS_C_NO_CREDENTIAL;
gss_release_buffer(&minor, &output);
+ /*+ * Release the large authentication buffers and allocate the ones we+ * want for normal operation. (This maneuver is safe only because+ * pqDropConnection will drop the buffers; otherwise, during a+ * reconnection we'd be at risk of using undersized buffers during+ * negotiation.)+ */+ free(PqGSSSendBuffer);+ free(PqGSSRecvBuffer);+ free(PqGSSResultBuffer);+ PqGSSSendBuffer = malloc(PQ_GSS_MAX_PACKET_SIZE);+ PqGSSRecvBuffer = malloc(PQ_GSS_MAX_PACKET_SIZE);+ PqGSSResultBuffer = malloc(PQ_GSS_MAX_PACKET_SIZE);+ if (!PqGSSSendBuffer || !PqGSSRecvBuffer || !PqGSSResultBuffer)+ {+ libpq_append_conn_error(conn, "out of memory");+ return PGRES_POLLING_FAILED;+ }+ PqGSSSendLength = PqGSSSendNext = PqGSSSendConsumed = 0;+ PqGSSRecvLength = PqGSSResultLength = PqGSSResultNext = 0;+
/*
* Determine the max packet size which will fit in our buffer, after
* accounting for the length. pg_GSS_write will need this.
*/
major = gss_wrap_size_limit(&minor, conn->gctx, 1, GSS_C_QOP_DEFAULT,
- PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32),+ PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32),
&PqGSSMaxPktSize);
if (GSS_ERROR(major))
@@ -687,10 +719,11 @@ pqsecure_open_gss(PGconn *conn)
}
/* Must have output.length > 0 */
- if (output.length > PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32))+ if (output.length > PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32))
{
- pg_GSS_error(libpq_gettext("GSSAPI context establishment error"),- conn, major, minor);+ libpq_append_conn_error(conn, "client tried to send oversize GSSAPI packet (%zu > %zu)",+ (size_t) output.length,+ PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32));
gss_release_buffer(&minor, &output);
return PGRES_POLLING_FAILED;
}
[text/x-diff] gssapi-fix-v15.patch (11.8K, ../3125964.1748115528@sss.pgh.pa.us/3-gssapi-fix-v15.patch)
download | inline diff:diff --git a/src/backend/libpq/be-secure-gssapi.c b/src/backend/libpq/be-secure-gssapi.cindex d3337a3d1c4..4aa828bef08 100644--- a/src/backend/libpq/be-secure-gssapi.c+++ b/src/backend/libpq/be-secure-gssapi.c@@ -45,11 +45,19 @@
* don't want the other side to send arbitrarily huge packets as we
* would have to allocate memory for them to then pass them to GSSAPI.
*
- * Therefore, these two #define's are effectively part of the protocol+ * Therefore, this #define is effectively part of the protocol
* spec and can't ever be changed.
*/
-#define PQ_GSS_SEND_BUFFER_SIZE 16384-#define PQ_GSS_RECV_BUFFER_SIZE 16384+#define PQ_GSS_MAX_PACKET_SIZE 16384++/*+ * However, during the authentication exchange we must cope with whatever+ * message size the GSSAPI library wants to send (because our protocol+ * doesn't support splitting those messages). Depending on configuration+ * those messages might be as much as 64kB. To provide some safety margin+ * we use 128kB buffers during transport negotiation.+ */+#define PQ_GSS_AUTH_BUFFER_SIZE 131072
/*
* Since we manage at most one GSS-encrypted connection per backend,
@@ -209,12 +217,12 @@ be_gssapi_write(Port *port, void *ptr, size_t len)
errno = ECONNRESET;
return -1;
}
- if (output.length > PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32))+ if (output.length > PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32))
{
ereport(COMMERROR,
(errmsg("server tried to send oversize GSSAPI packet (%zu > %zu)",
(size_t) output.length,
- PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32))));+ PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32))));
errno = ECONNRESET;
return -1;
}
@@ -345,12 +353,12 @@ be_gssapi_read(Port *port, void *ptr, size_t len)
/* Decode the packet length and check for overlength packet */
input.length = pg_ntoh32(*(uint32 *) PqGSSRecvBuffer);
- if (input.length > PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32))+ if (input.length > PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32))
{
ereport(COMMERROR,
(errmsg("oversize GSSAPI packet sent by the client (%zu > %zu)",
(size_t) input.length,
- PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32))));+ PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32))));
errno = ECONNRESET;
return -1;
}
@@ -510,10 +518,13 @@ secure_open_gssapi(Port *port)
* that will never use them, and we ensure that the buffers are
* sufficiently aligned for the length-word accesses that we do in some
* places in this file.
+ *+ * We'll use PQ_GSS_AUTH_BUFFER_SIZE-sized buffers until transport+ * negotiation is complete, then switch to PQ_GSS_MAX_PACKET_SIZE.
*/
- PqGSSSendBuffer = malloc(PQ_GSS_SEND_BUFFER_SIZE);- PqGSSRecvBuffer = malloc(PQ_GSS_RECV_BUFFER_SIZE);- PqGSSResultBuffer = malloc(PQ_GSS_RECV_BUFFER_SIZE);+ PqGSSSendBuffer = malloc(PQ_GSS_AUTH_BUFFER_SIZE);+ PqGSSRecvBuffer = malloc(PQ_GSS_AUTH_BUFFER_SIZE);+ PqGSSResultBuffer = malloc(PQ_GSS_AUTH_BUFFER_SIZE);
if (!PqGSSSendBuffer || !PqGSSRecvBuffer || !PqGSSResultBuffer)
ereport(FATAL,
(errcode(ERRCODE_OUT_OF_MEMORY),
@@ -560,16 +571,16 @@ secure_open_gssapi(Port *port)
/*
* During initialization, packets are always fully consumed and
- * shouldn't ever be over PQ_GSS_RECV_BUFFER_SIZE in length.+ * shouldn't ever be over PQ_GSS_AUTH_BUFFER_SIZE in total length.
*
* Verify on our side that the client doesn't do something funny.
*/
- if (input.length > PQ_GSS_RECV_BUFFER_SIZE)+ if (input.length > PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32))
{
ereport(COMMERROR,
- (errmsg("oversize GSSAPI packet sent by the client (%zu > %d)",+ (errmsg("oversize GSSAPI packet sent by the client (%zu > %zu)",
(size_t) input.length,
- PQ_GSS_RECV_BUFFER_SIZE)));+ PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32))));
return -1;
}
@@ -616,12 +627,12 @@ secure_open_gssapi(Port *port)
{
uint32 netlen = pg_hton32(output.length);
- if (output.length > PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32))+ if (output.length > PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32))
{
ereport(COMMERROR,
(errmsg("server tried to send oversize GSSAPI packet (%zu > %zu)",
(size_t) output.length,
- PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32))));+ PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32))));
gss_release_buffer(&minor, &output);
return -1;
}
@@ -676,12 +687,29 @@ secure_open_gssapi(Port *port)
break;
}
+ /*+ * Release the large authentication buffers and allocate the ones we want+ * for normal operation.+ */+ free(PqGSSSendBuffer);+ free(PqGSSRecvBuffer);+ free(PqGSSResultBuffer);+ PqGSSSendBuffer = malloc(PQ_GSS_MAX_PACKET_SIZE);+ PqGSSRecvBuffer = malloc(PQ_GSS_MAX_PACKET_SIZE);+ PqGSSResultBuffer = malloc(PQ_GSS_MAX_PACKET_SIZE);+ if (!PqGSSSendBuffer || !PqGSSRecvBuffer || !PqGSSResultBuffer)+ ereport(FATAL,+ (errcode(ERRCODE_OUT_OF_MEMORY),+ errmsg("out of memory")));+ PqGSSSendLength = PqGSSSendNext = PqGSSSendConsumed = 0;+ PqGSSRecvLength = PqGSSResultLength = PqGSSResultNext = 0;+
/*
* Determine the max packet size which will fit in our buffer, after
* accounting for the length. be_gssapi_write will need this.
*/
major = gss_wrap_size_limit(&minor, port->gss->ctx, 1, GSS_C_QOP_DEFAULT,
- PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32),+ PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32),
&PqGSSMaxPktSize);
if (GSS_ERROR(major))
diff --git a/src/interfaces/libpq/fe-secure-gssapi.c b/src/interfaces/libpq/fe-secure-gssapi.cindex a3768cd70a3..eb23731645f 100644--- a/src/interfaces/libpq/fe-secure-gssapi.c+++ b/src/interfaces/libpq/fe-secure-gssapi.c@@ -47,11 +47,19 @@
* don't want the other side to send arbitrarily huge packets as we
* would have to allocate memory for them to then pass them to GSSAPI.
*
- * Therefore, these two #define's are effectively part of the protocol+ * Therefore, this #define is effectively part of the protocol
* spec and can't ever be changed.
*/
-#define PQ_GSS_SEND_BUFFER_SIZE 16384-#define PQ_GSS_RECV_BUFFER_SIZE 16384+#define PQ_GSS_MAX_PACKET_SIZE 16384++/*+ * However, during the authentication exchange we must cope with whatever+ * message size the GSSAPI library wants to send (because our protocol+ * doesn't support splitting those messages). Depending on configuration+ * those messages might be as much as 64kB. To provide some safety margin+ * we use 128kB buffers during transport negotiation.+ */+#define PQ_GSS_AUTH_BUFFER_SIZE 131072
/*
* We need these state variables per-connection. To allow the functions
@@ -204,12 +212,12 @@ pg_GSS_write(PGconn *conn, const void *ptr, size_t len)
goto cleanup;
}
- if (output.length > PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32))+ if (output.length > PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32))
{
appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("client tried to send oversize GSSAPI packet (%zu > %zu)\n"),
(size_t) output.length,
- PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32));+ PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32));
errno = EIO; /* for lack of a better idea */
goto cleanup;
}
@@ -344,12 +352,12 @@ pg_GSS_read(PGconn *conn, void *ptr, size_t len)
/* Decode the packet length and check for overlength packet */
input.length = pg_ntoh32(*(uint32 *) PqGSSRecvBuffer);
- if (input.length > PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32))+ if (input.length > PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32))
{
appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("oversize GSSAPI packet sent by the server (%zu > %zu)\n"),
(size_t) input.length,
- PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32));+ PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32));
errno = EIO; /* for lack of a better idea */
return -1;
}
@@ -488,12 +496,15 @@ pqsecure_open_gss(PGconn *conn)
* initialize state variables. By malloc'ing the buffers separately, we
* ensure that they are sufficiently aligned for the length-word accesses
* that we do in some places in this file.
+ *+ * We'll use PQ_GSS_AUTH_BUFFER_SIZE-sized buffers until transport+ * negotiation is complete, then switch to PQ_GSS_MAX_PACKET_SIZE.
*/
if (PqGSSSendBuffer == NULL)
{
- PqGSSSendBuffer = malloc(PQ_GSS_SEND_BUFFER_SIZE);- PqGSSRecvBuffer = malloc(PQ_GSS_RECV_BUFFER_SIZE);- PqGSSResultBuffer = malloc(PQ_GSS_RECV_BUFFER_SIZE);+ PqGSSSendBuffer = malloc(PQ_GSS_AUTH_BUFFER_SIZE);+ PqGSSRecvBuffer = malloc(PQ_GSS_AUTH_BUFFER_SIZE);+ PqGSSResultBuffer = malloc(PQ_GSS_AUTH_BUFFER_SIZE);
if (!PqGSSSendBuffer || !PqGSSRecvBuffer || !PqGSSResultBuffer)
{
appendPQExpBufferStr(&conn->errorMessage,
@@ -568,13 +579,13 @@ pqsecure_open_gss(PGconn *conn)
* so leave a spot at the end for a NULL byte too) and report that
* back to the caller.
*/
- result = gss_read(conn, PqGSSRecvBuffer + PqGSSRecvLength, PQ_GSS_RECV_BUFFER_SIZE - PqGSSRecvLength - 1, &ret);+ result = gss_read(conn, PqGSSRecvBuffer + PqGSSRecvLength, PQ_GSS_AUTH_BUFFER_SIZE - PqGSSRecvLength - 1, &ret);
if (result != PGRES_POLLING_OK)
return result;
PqGSSRecvLength += ret;
- Assert(PqGSSRecvLength < PQ_GSS_RECV_BUFFER_SIZE);+ Assert(PqGSSRecvLength < PQ_GSS_AUTH_BUFFER_SIZE);
PqGSSRecvBuffer[PqGSSRecvLength] = '\0';
appendPQExpBuffer(&conn->errorMessage, "%s\n", PqGSSRecvBuffer + 1);
@@ -588,12 +599,12 @@ pqsecure_open_gss(PGconn *conn)
/* Get the length and check for over-length packet */
input.length = pg_ntoh32(*(uint32 *) PqGSSRecvBuffer);
- if (input.length > PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32))+ if (input.length > PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32))
{
appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("oversize GSSAPI packet sent by the server (%zu > %zu)\n"),
(size_t) input.length,
- PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32));+ PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32));
return PGRES_POLLING_FAILED;
}
@@ -655,12 +666,34 @@ pqsecure_open_gss(PGconn *conn)
conn->gcred = GSS_C_NO_CREDENTIAL;
gss_release_buffer(&minor, &output);
+ /*+ * Release the large authentication buffers and allocate the ones we+ * want for normal operation. (This maneuver is safe only because+ * pqDropConnection will drop the buffers; otherwise, during a+ * reconnection we'd be at risk of using undersized buffers during+ * negotiation.)+ */+ free(PqGSSSendBuffer);+ free(PqGSSRecvBuffer);+ free(PqGSSResultBuffer);+ PqGSSSendBuffer = malloc(PQ_GSS_MAX_PACKET_SIZE);+ PqGSSRecvBuffer = malloc(PQ_GSS_MAX_PACKET_SIZE);+ PqGSSResultBuffer = malloc(PQ_GSS_MAX_PACKET_SIZE);+ if (!PqGSSSendBuffer || !PqGSSRecvBuffer || !PqGSSResultBuffer)+ {+ appendPQExpBufferStr(&conn->errorMessage,+ libpq_gettext("out of memory\n"));+ return PGRES_POLLING_FAILED;+ }+ PqGSSSendLength = PqGSSSendNext = PqGSSSendConsumed = 0;+ PqGSSRecvLength = PqGSSResultLength = PqGSSResultNext = 0;+
/*
* Determine the max packet size which will fit in our buffer, after
* accounting for the length. pg_GSS_write will need this.
*/
major = gss_wrap_size_limit(&minor, conn->gctx, 1, GSS_C_QOP_DEFAULT,
- PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32),+ PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32),
&PqGSSMaxPktSize);
if (GSS_ERROR(major))
@@ -674,10 +707,12 @@ pqsecure_open_gss(PGconn *conn)
}
/* Must have output.length > 0 */
- if (output.length > PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32))+ if (output.length > PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32))
{
- pg_GSS_error(libpq_gettext("GSSAPI context establishment error"),- conn, major, minor);+ appendPQExpBuffer(&conn->errorMessage,+ libpq_gettext("client tried to send oversize GSSAPI packet (%zu > %zu)\n"),+ (size_t) output.length,+ PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32));
gss_release_buffer(&minor, &output);
return PGRES_POLLING_FAILED;
}
[text/x-diff] gssapi-fix-v13.patch (11.8K, ../3125964.1748115528@sss.pgh.pa.us/4-gssapi-fix-v13.patch)
download | inline diff:diff --git a/src/backend/libpq/be-secure-gssapi.c b/src/backend/libpq/be-secure-gssapi.cindex 0fc7d565e2a..4992ff5bd20 100644--- a/src/backend/libpq/be-secure-gssapi.c+++ b/src/backend/libpq/be-secure-gssapi.c@@ -45,11 +45,19 @@
* don't want the other side to send arbitrarily huge packets as we
* would have to allocate memory for them to then pass them to GSSAPI.
*
- * Therefore, these two #define's are effectively part of the protocol+ * Therefore, this #define is effectively part of the protocol
* spec and can't ever be changed.
*/
-#define PQ_GSS_SEND_BUFFER_SIZE 16384-#define PQ_GSS_RECV_BUFFER_SIZE 16384+#define PQ_GSS_MAX_PACKET_SIZE 16384++/*+ * However, during the authentication exchange we must cope with whatever+ * message size the GSSAPI library wants to send (because our protocol+ * doesn't support splitting those messages). Depending on configuration+ * those messages might be as much as 64kB. To provide some safety margin+ * we use 128kB buffers during transport negotiation.+ */+#define PQ_GSS_AUTH_BUFFER_SIZE 131072
/*
* Since we manage at most one GSS-encrypted connection per backend,
@@ -209,12 +217,12 @@ be_gssapi_write(Port *port, void *ptr, size_t len)
errno = ECONNRESET;
return -1;
}
- if (output.length > PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32))+ if (output.length > PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32))
{
ereport(COMMERROR,
(errmsg("server tried to send oversize GSSAPI packet (%zu > %zu)",
(size_t) output.length,
- PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32))));+ PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32))));
errno = ECONNRESET;
return -1;
}
@@ -345,12 +353,12 @@ be_gssapi_read(Port *port, void *ptr, size_t len)
/* Decode the packet length and check for overlength packet */
input.length = ntohl(*(uint32 *) PqGSSRecvBuffer);
- if (input.length > PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32))+ if (input.length > PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32))
{
ereport(COMMERROR,
(errmsg("oversize GSSAPI packet sent by the client (%zu > %zu)",
(size_t) input.length,
- PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32))));+ PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32))));
errno = ECONNRESET;
return -1;
}
@@ -510,10 +518,13 @@ secure_open_gssapi(Port *port)
* that will never use them, and we ensure that the buffers are
* sufficiently aligned for the length-word accesses that we do in some
* places in this file.
+ *+ * We'll use PQ_GSS_AUTH_BUFFER_SIZE-sized buffers until transport+ * negotiation is complete, then switch to PQ_GSS_MAX_PACKET_SIZE.
*/
- PqGSSSendBuffer = malloc(PQ_GSS_SEND_BUFFER_SIZE);- PqGSSRecvBuffer = malloc(PQ_GSS_RECV_BUFFER_SIZE);- PqGSSResultBuffer = malloc(PQ_GSS_RECV_BUFFER_SIZE);+ PqGSSSendBuffer = malloc(PQ_GSS_AUTH_BUFFER_SIZE);+ PqGSSRecvBuffer = malloc(PQ_GSS_AUTH_BUFFER_SIZE);+ PqGSSResultBuffer = malloc(PQ_GSS_AUTH_BUFFER_SIZE);
if (!PqGSSSendBuffer || !PqGSSRecvBuffer || !PqGSSResultBuffer)
ereport(FATAL,
(errcode(ERRCODE_OUT_OF_MEMORY),
@@ -560,16 +571,16 @@ secure_open_gssapi(Port *port)
/*
* During initialization, packets are always fully consumed and
- * shouldn't ever be over PQ_GSS_RECV_BUFFER_SIZE in length.+ * shouldn't ever be over PQ_GSS_AUTH_BUFFER_SIZE in total length.
*
* Verify on our side that the client doesn't do something funny.
*/
- if (input.length > PQ_GSS_RECV_BUFFER_SIZE)+ if (input.length > PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32))
{
ereport(COMMERROR,
- (errmsg("oversize GSSAPI packet sent by the client (%zu > %d)",+ (errmsg("oversize GSSAPI packet sent by the client (%zu > %zu)",
(size_t) input.length,
- PQ_GSS_RECV_BUFFER_SIZE)));+ PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32))));
return -1;
}
@@ -616,12 +627,12 @@ secure_open_gssapi(Port *port)
{
uint32 netlen = htonl(output.length);
- if (output.length > PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32))+ if (output.length > PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32))
{
ereport(COMMERROR,
(errmsg("server tried to send oversize GSSAPI packet (%zu > %zu)",
(size_t) output.length,
- PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32))));+ PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32))));
gss_release_buffer(&minor, &output);
return -1;
}
@@ -676,12 +687,29 @@ secure_open_gssapi(Port *port)
break;
}
+ /*+ * Release the large authentication buffers and allocate the ones we want+ * for normal operation.+ */+ free(PqGSSSendBuffer);+ free(PqGSSRecvBuffer);+ free(PqGSSResultBuffer);+ PqGSSSendBuffer = malloc(PQ_GSS_MAX_PACKET_SIZE);+ PqGSSRecvBuffer = malloc(PQ_GSS_MAX_PACKET_SIZE);+ PqGSSResultBuffer = malloc(PQ_GSS_MAX_PACKET_SIZE);+ if (!PqGSSSendBuffer || !PqGSSRecvBuffer || !PqGSSResultBuffer)+ ereport(FATAL,+ (errcode(ERRCODE_OUT_OF_MEMORY),+ errmsg("out of memory")));+ PqGSSSendLength = PqGSSSendNext = PqGSSSendConsumed = 0;+ PqGSSRecvLength = PqGSSResultLength = PqGSSResultNext = 0;+
/*
* Determine the max packet size which will fit in our buffer, after
* accounting for the length. be_gssapi_write will need this.
*/
major = gss_wrap_size_limit(&minor, port->gss->ctx, 1, GSS_C_QOP_DEFAULT,
- PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32),+ PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32),
&PqGSSMaxPktSize);
if (GSS_ERROR(major))
diff --git a/src/interfaces/libpq/fe-secure-gssapi.c b/src/interfaces/libpq/fe-secure-gssapi.cindex ac2a8c8563f..abc07fe5f04 100644--- a/src/interfaces/libpq/fe-secure-gssapi.c+++ b/src/interfaces/libpq/fe-secure-gssapi.c@@ -47,11 +47,19 @@
* don't want the other side to send arbitrarily huge packets as we
* would have to allocate memory for them to then pass them to GSSAPI.
*
- * Therefore, these two #define's are effectively part of the protocol+ * Therefore, this #define is effectively part of the protocol
* spec and can't ever be changed.
*/
-#define PQ_GSS_SEND_BUFFER_SIZE 16384-#define PQ_GSS_RECV_BUFFER_SIZE 16384+#define PQ_GSS_MAX_PACKET_SIZE 16384++/*+ * However, during the authentication exchange we must cope with whatever+ * message size the GSSAPI library wants to send (because our protocol+ * doesn't support splitting those messages). Depending on configuration+ * those messages might be as much as 64kB. To provide some safety margin+ * we use 128kB buffers during transport negotiation.+ */+#define PQ_GSS_AUTH_BUFFER_SIZE 131072
/*
* We need these state variables per-connection. To allow the functions
@@ -204,12 +212,12 @@ pg_GSS_write(PGconn *conn, const void *ptr, size_t len)
goto cleanup;
}
- if (output.length > PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32))+ if (output.length > PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32))
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("client tried to send oversize GSSAPI packet (%zu > %zu)\n"),
(size_t) output.length,
- PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32));+ PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32));
errno = EIO; /* for lack of a better idea */
goto cleanup;
}
@@ -344,12 +352,12 @@ pg_GSS_read(PGconn *conn, void *ptr, size_t len)
/* Decode the packet length and check for overlength packet */
input.length = ntohl(*(uint32 *) PqGSSRecvBuffer);
- if (input.length > PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32))+ if (input.length > PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32))
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("oversize GSSAPI packet sent by the server (%zu > %zu)\n"),
(size_t) input.length,
- PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32));+ PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32));
errno = EIO; /* for lack of a better idea */
return -1;
}
@@ -488,12 +496,15 @@ pqsecure_open_gss(PGconn *conn)
* initialize state variables. By malloc'ing the buffers separately, we
* ensure that they are sufficiently aligned for the length-word accesses
* that we do in some places in this file.
+ *+ * We'll use PQ_GSS_AUTH_BUFFER_SIZE-sized buffers until transport+ * negotiation is complete, then switch to PQ_GSS_MAX_PACKET_SIZE.
*/
if (PqGSSSendBuffer == NULL)
{
- PqGSSSendBuffer = malloc(PQ_GSS_SEND_BUFFER_SIZE);- PqGSSRecvBuffer = malloc(PQ_GSS_RECV_BUFFER_SIZE);- PqGSSResultBuffer = malloc(PQ_GSS_RECV_BUFFER_SIZE);+ PqGSSSendBuffer = malloc(PQ_GSS_AUTH_BUFFER_SIZE);+ PqGSSRecvBuffer = malloc(PQ_GSS_AUTH_BUFFER_SIZE);+ PqGSSResultBuffer = malloc(PQ_GSS_AUTH_BUFFER_SIZE);
if (!PqGSSSendBuffer || !PqGSSRecvBuffer || !PqGSSResultBuffer)
{
printfPQExpBuffer(&conn->errorMessage,
@@ -568,13 +579,13 @@ pqsecure_open_gss(PGconn *conn)
* so leave a spot at the end for a NULL byte too) and report that
* back to the caller.
*/
- result = gss_read(conn, PqGSSRecvBuffer + PqGSSRecvLength, PQ_GSS_RECV_BUFFER_SIZE - PqGSSRecvLength - 1, &ret);+ result = gss_read(conn, PqGSSRecvBuffer + PqGSSRecvLength, PQ_GSS_AUTH_BUFFER_SIZE - PqGSSRecvLength - 1, &ret);
if (result != PGRES_POLLING_OK)
return result;
PqGSSRecvLength += ret;
- Assert(PqGSSRecvLength < PQ_GSS_RECV_BUFFER_SIZE);+ Assert(PqGSSRecvLength < PQ_GSS_AUTH_BUFFER_SIZE);
PqGSSRecvBuffer[PqGSSRecvLength] = '\0';
printfPQExpBuffer(&conn->errorMessage, "%s\n", PqGSSRecvBuffer + 1);
@@ -588,12 +599,12 @@ pqsecure_open_gss(PGconn *conn)
/* Get the length and check for over-length packet */
input.length = ntohl(*(uint32 *) PqGSSRecvBuffer);
- if (input.length > PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32))+ if (input.length > PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32))
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("oversize GSSAPI packet sent by the server (%zu > %zu)\n"),
(size_t) input.length,
- PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32));+ PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32));
return PGRES_POLLING_FAILED;
}
@@ -655,12 +666,34 @@ pqsecure_open_gss(PGconn *conn)
conn->gcred = GSS_C_NO_CREDENTIAL;
gss_release_buffer(&minor, &output);
+ /*+ * Release the large authentication buffers and allocate the ones we+ * want for normal operation. (This maneuver is safe only because+ * pqDropConnection will drop the buffers; otherwise, during a+ * reconnection we'd be at risk of using undersized buffers during+ * negotiation.)+ */+ free(PqGSSSendBuffer);+ free(PqGSSRecvBuffer);+ free(PqGSSResultBuffer);+ PqGSSSendBuffer = malloc(PQ_GSS_MAX_PACKET_SIZE);+ PqGSSRecvBuffer = malloc(PQ_GSS_MAX_PACKET_SIZE);+ PqGSSResultBuffer = malloc(PQ_GSS_MAX_PACKET_SIZE);+ if (!PqGSSSendBuffer || !PqGSSRecvBuffer || !PqGSSResultBuffer)+ {+ printfPQExpBuffer(&conn->errorMessage,+ libpq_gettext("out of memory\n"));+ return PGRES_POLLING_FAILED;+ }+ PqGSSSendLength = PqGSSSendNext = PqGSSSendConsumed = 0;+ PqGSSRecvLength = PqGSSResultLength = PqGSSResultNext = 0;+
/*
* Determine the max packet size which will fit in our buffer, after
* accounting for the length. pg_GSS_write will need this.
*/
major = gss_wrap_size_limit(&minor, conn->gctx, 1, GSS_C_QOP_DEFAULT,
- PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32),+ PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32),
&PqGSSMaxPktSize);
if (GSS_ERROR(major))
@@ -674,10 +707,12 @@ pqsecure_open_gss(PGconn *conn)
}
/* Must have output.length > 0 */
- if (output.length > PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32))+ if (output.length > PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32))
{
- pg_GSS_error(libpq_gettext("GSSAPI context establishment error"),- conn, major, minor);+ printfPQExpBuffer(&conn->errorMessage,+ libpq_gettext("client tried to send oversize GSSAPI packet (%zu > %zu)\n"),+ (size_t) output.length,+ PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32));
gss_release_buffer(&minor, &output);
return PGRES_POLLING_FAILED;
}
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: pgsql-bugs@postgresql.org
Cc: tgl@sss.pgh.pa.us, cgooch@bamfunds.com, jacob.champion@enterprisedb.com, pgsql-bugs@lists.postgresql.org
Subject: Re: [EXT] Re: GSS Auth issue when user member of lots of AD groups
In-Reply-To: <3125964.1748115528@sss.pgh.pa.us>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox