@ -47,11 +47,18 @@
* don ' t want the other side to send arbitrarily huge packets as we
* 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 .
* 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 .
* spec and can ' t ever be changed .
*/
*/
# define PQ_GSS_SEND_BUFFER_SIZE 16384
# define PQ_GSS_MAX_PACKET_SIZE 16384 /* includes uint32 header word */
# define PQ_GSS_RECV_BUFFER_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 64 kB .
*/
# define PQ_GSS_AUTH_BUFFER_SIZE 65536 /* includes uint32 header word */
/*
/*
* We need these state variables per - connection . To allow the functions
* We need these state variables per - connection . To allow the functions
@ -203,11 +210,11 @@ pg_GSS_write(PGconn *conn, const void *ptr, size_t len)
goto cleanup ;
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) " ,
libpq_append_conn_error ( conn , " client tried to send oversize GSSAPI packet (%zu > %zu) " ,
( size_t ) output . length ,
( 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 */
errno = EIO ; /* for lack of a better idea */
goto cleanup ;
goto cleanup ;
}
}
@ -342,11 +349,11 @@ pg_GSS_read(PGconn *conn, void *ptr, size_t len)
/* Decode the packet length and check for overlength packet */
/* Decode the packet length and check for overlength packet */
input . length = pg_ntoh32 ( * ( uint32 * ) PqGSSRecvBuffer ) ;
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) " ,
libpq_append_conn_error ( conn , " oversize GSSAPI packet sent by the server (%zu > %zu) " ,
( size_t ) input . length ,
( 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 */
errno = EIO ; /* for lack of a better idea */
return - 1 ;
return - 1 ;
}
}
@ -485,12 +492,15 @@ pqsecure_open_gss(PGconn *conn)
* initialize state variables . By malloc ' ing the buffers separately , we
* initialize state variables . By malloc ' ing the buffers separately , we
* ensure that they are sufficiently aligned for the length - word accesses
* ensure that they are sufficiently aligned for the length - word accesses
* that we do in some places in this file .
* 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 )
if ( PqGSSSendBuffer = = NULL )
{
{
PqGSSSendBuffer = malloc ( PQ_GSS_SEND _BUFFER_SIZE ) ;
PqGSSSendBuffer = malloc ( PQ_GSS_AUTH _BUFFER_SIZE ) ;
PqGSSRecvBuffer = malloc ( PQ_GSS_RECV _BUFFER_SIZE ) ;
PqGSSRecvBuffer = malloc ( PQ_GSS_AUTH _BUFFER_SIZE ) ;
PqGSSResultBuffer = malloc ( PQ_GSS_RECV _BUFFER_SIZE ) ;
PqGSSResultBuffer = malloc ( PQ_GSS_AUTH _BUFFER_SIZE ) ;
if ( ! PqGSSSendBuffer | | ! PqGSSRecvBuffer | | ! PqGSSResultBuffer )
if ( ! PqGSSSendBuffer | | ! PqGSSRecvBuffer | | ! PqGSSResultBuffer )
{
{
libpq_append_conn_error ( conn , " out of memory " ) ;
libpq_append_conn_error ( conn , " out of memory " ) ;
@ -564,13 +574,13 @@ pqsecure_open_gss(PGconn *conn)
* so leave a spot at the end for a NULL byte too ) and report that
* so leave a spot at the end for a NULL byte too ) and report that
* back to the caller .
* 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 )
if ( result ! = PGRES_POLLING_OK )
return result ;
return result ;
PqGSSRecvLength + = ret ;
PqGSSRecvLength + = ret ;
Assert ( PqGSSRecvLength < PQ_GSS_RECV _BUFFER_SIZE ) ;
Assert ( PqGSSRecvLength < PQ_GSS_AUTH _BUFFER_SIZE ) ;
PqGSSRecvBuffer [ PqGSSRecvLength ] = ' \0 ' ;
PqGSSRecvBuffer [ PqGSSRecvLength ] = ' \0 ' ;
appendPQExpBuffer ( & conn - > errorMessage , " %s \n " , PqGSSRecvBuffer + 1 ) ;
appendPQExpBuffer ( & conn - > errorMessage , " %s \n " , PqGSSRecvBuffer + 1 ) ;
@ -584,11 +594,11 @@ pqsecure_open_gss(PGconn *conn)
/* Get the length and check for over-length packet */
/* Get the length and check for over-length packet */
input . length = pg_ntoh32 ( * ( uint32 * ) PqGSSRecvBuffer ) ;
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) " ,
libpq_append_conn_error ( conn , " oversize GSSAPI packet sent by the server (%zu > %zu) " ,
( size_t ) input . length ,
( size_t ) input . length ,
PQ_GSS_RECV _BUFFER_SIZE - sizeof ( uint32 ) ) ;
PQ_GSS_AUTH _BUFFER_SIZE - sizeof ( uint32 ) ) ;
return PGRES_POLLING_FAILED ;
return PGRES_POLLING_FAILED ;
}
}
@ -668,12 +678,33 @@ pqsecure_open_gss(PGconn *conn)
conn - > gcred = GSS_C_NO_CREDENTIAL ;
conn - > gcred = GSS_C_NO_CREDENTIAL ;
gss_release_buffer ( & minor , & output ) ;
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
* Determine the max packet size which will fit in our buffer , after
* accounting for the length . pg_GSS_write will need this .
* accounting for the length . pg_GSS_write will need this .
*/
*/
major = gss_wrap_size_limit ( & minor , conn - > gctx , 1 , GSS_C_QOP_DEFAULT ,
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 ) ;
& PqGSSMaxPktSize ) ;
if ( GSS_ERROR ( major ) )
if ( GSS_ERROR ( major ) )
@ -687,10 +718,11 @@ pqsecure_open_gss(PGconn *conn)
}
}
/* Must have output.length > 0 */
/* 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 " ) ,
libpq_append_conn_error ( conn , " client tried to send oversize GSSAPI packet (%zu > %zu) " ,
conn , major , minor ) ;
( size_t ) output . length ,
PQ_GSS_AUTH_BUFFER_SIZE - sizeof ( uint32 ) ) ;
gss_release_buffer ( & minor , & output ) ;
gss_release_buffer ( & minor , & output ) ;
return PGRES_POLLING_FAILED ;
return PGRES_POLLING_FAILED ;
}
}