@ -21,6 +21,7 @@
# include "libpq/pqformat.h"
# include "libpq/pqformat.h"
# include "miscadmin.h"
# include "miscadmin.h"
# include "pgstat.h"
# include "pgstat.h"
# include "utils/memutils.h"
/*
/*
@ -81,10 +82,14 @@ static uint32 PqGSSMaxPktSize; /* Maximum size we can encrypt and fit the
* transport negotiation is complete ) .
* transport negotiation is complete ) .
*
*
* On success , returns the number of data bytes consumed ( possibly less than
* On success , returns the number of data bytes consumed ( possibly less than
* len ) . On failure , returns - 1 with errno set appropriately . ( For fatal
* len ) . On failure , returns - 1 with errno set appropriately . For retryable
* errors , we may just elog and exit , if errno wouldn ' t be sufficient to
* errors , caller should call again ( passing the same data ) once the socket
* describe the error . ) For retryable errors , caller should call again
* is ready .
* ( passing the same data ) once the socket is ready .
*
* Dealing with fatal errors here is a bit tricky : we can ' t invoke elog ( FATAL )
* since it would try to write to the client , probably resulting in infinite
* recursion . Instead , use elog ( COMMERROR ) to log extra info about the
* failure if necessary , and then return an errno indicating connection loss .
*/
*/
ssize_t
ssize_t
be_gssapi_write ( Port * port , void * ptr , size_t len )
be_gssapi_write ( Port * port , void * ptr , size_t len )
@ -108,8 +113,11 @@ be_gssapi_write(Port *port, void *ptr, size_t len)
* again , so if it offers a len less than that , something is wrong .
* again , so if it offers a len less than that , something is wrong .
*/
*/
if ( len < PqGSSSendConsumed )
if ( len < PqGSSSendConsumed )
elog ( FATAL , " GSSAPI caller failed to retransmit all data needing to be retried " ) ;
{
elog ( COMMERROR , " GSSAPI caller failed to retransmit all data needing to be retried " ) ;
errno = ECONNRESET ;
return - 1 ;
}
/* Discount whatever source data we already encrypted. */
/* Discount whatever source data we already encrypted. */
bytes_to_encrypt = len - PqGSSSendConsumed ;
bytes_to_encrypt = len - PqGSSSendConsumed ;
bytes_encrypted = PqGSSSendConsumed ;
bytes_encrypted = PqGSSSendConsumed ;
@ -192,17 +200,27 @@ be_gssapi_write(Port *port, void *ptr, size_t len)
major = gss_wrap ( & minor , gctx , 1 , GSS_C_QOP_DEFAULT ,
major = gss_wrap ( & minor , gctx , 1 , GSS_C_QOP_DEFAULT ,
& input , & conf_state , & output ) ;
& input , & conf_state , & output ) ;
if ( major ! = GSS_S_COMPLETE )
if ( major ! = GSS_S_COMPLETE )
pg_GSS_error ( FATAL , gettext_noop ( " GSSAPI wrap error " ) , major , minor ) ;
{
pg_GSS_error ( _ ( " GSSAPI wrap error " ) , major , minor ) ;
errno = ECONNRESET ;
return - 1 ;
}
if ( conf_state = = 0 )
if ( conf_state = = 0 )
ereport ( FATAL ,
{
ereport ( COMMERROR ,
( errmsg ( " outgoing GSSAPI message would not use confidentiality " ) ) ) ;
( errmsg ( " outgoing GSSAPI message would not use confidentiality " ) ) ) ;
errno = ECONNRESET ;
return - 1 ;
}
if ( output . length > PQ_GSS_SEND_BUFFER_SIZE - sizeof ( uint32 ) )
if ( output . length > PQ_GSS_SEND_BUFFER_SIZE - sizeof ( uint32 ) )
ereport ( FATAL ,
{
ereport ( COMMERROR ,
( errmsg ( " server tried to send oversize GSSAPI packet (%zu > %zu) " ,
( errmsg ( " server 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_SEND_BUFFER_SIZE - sizeof ( uint32 ) ) ) ) ;
errno = ECONNRESET ;
return - 1 ;
}
bytes_encrypted + = input . length ;
bytes_encrypted + = input . length ;
bytes_to_encrypt - = input . length ;
bytes_to_encrypt - = input . length ;
@ -234,9 +252,11 @@ be_gssapi_write(Port *port, void *ptr, size_t len)
* transport negotiation is complete ) .
* transport negotiation is complete ) .
*
*
* Returns the number of data bytes read , or on failure , returns - 1
* Returns the number of data bytes read , or on failure , returns - 1
* with errno set appropriately . ( For fatal errors , we may just elog and
* with errno set appropriately . For retryable errors , caller should call
* exit , if errno wouldn ' t be sufficient to describe the error . ) For
* again once the socket is ready .
* retryable errors , caller should call again once the socket is ready .
*
* We treat fatal errors the same as in be_gssapi_write ( ) , even though the
* argument about infinite recursion doesn ' t apply here .
*/
*/
ssize_t
ssize_t
be_gssapi_read ( Port * port , void * ptr , size_t len )
be_gssapi_read ( Port * port , void * ptr , size_t len )
@ -326,10 +346,14 @@ be_gssapi_read(Port *port, void *ptr, size_t len)
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_RECV_BUFFER_SIZE - sizeof ( uint32 ) )
ereport ( FATAL ,
{
ereport ( COMMERROR ,
( errmsg ( " oversize GSSAPI packet sent by the client (%zu > %zu) " ,
( errmsg ( " oversize GSSAPI packet sent by the client (%zu > %zu) " ,
( size_t ) input . length ,
( size_t ) input . length ,
PQ_GSS_RECV_BUFFER_SIZE - sizeof ( uint32 ) ) ) ) ;
PQ_GSS_RECV_BUFFER_SIZE - sizeof ( uint32 ) ) ) ) ;
errno = ECONNRESET ;
return - 1 ;
}
/*
/*
* Read as much of the packet as we are able to on this call into
* Read as much of the packet as we are able to on this call into
@ -361,12 +385,18 @@ be_gssapi_read(Port *port, void *ptr, size_t len)
major = gss_unwrap ( & minor , gctx , & input , & output , & conf_state , NULL ) ;
major = gss_unwrap ( & minor , gctx , & input , & output , & conf_state , NULL ) ;
if ( major ! = GSS_S_COMPLETE )
if ( major ! = GSS_S_COMPLETE )
pg_GSS_error ( FATAL , gettext_noop ( " GSSAPI unwrap error " ) ,
{
major , minor ) ;
pg_GSS_error ( _ ( " GSSAPI unwrap error " ) , major , minor ) ;
errno = ECONNRESET ;
return - 1 ;
}
if ( conf_state = = 0 )
if ( conf_state = = 0 )
ereport ( FATAL ,
{
ereport ( COMMERROR ,
( errmsg ( " incoming GSSAPI message did not use confidentiality " ) ) ) ;
( errmsg ( " incoming GSSAPI message did not use confidentiality " ) ) ) ;
errno = ECONNRESET ;
return - 1 ;
}
memcpy ( PqGSSResultBuffer , output . value , output . length ) ;
memcpy ( PqGSSResultBuffer , output . value , output . length ) ;
PqGSSResultLength = output . length ;
PqGSSResultLength = output . length ;
@ -468,6 +498,12 @@ secure_open_gssapi(Port *port)
OM_uint32 major ,
OM_uint32 major ,
minor ;
minor ;
/*
* Allocate subsidiary Port data for GSSAPI operations .
*/
port - > gss = ( pg_gssinfo * )
MemoryContextAllocZero ( TopMemoryContext , sizeof ( pg_gssinfo ) ) ;
/*
/*
* Allocate buffers and initialize state variables . By malloc ' ing the
* Allocate buffers and initialize state variables . By malloc ' ing the
* buffers at this point , we avoid wasting static data space in processes
* buffers at this point , we avoid wasting static data space in processes
@ -521,10 +557,13 @@ secure_open_gssapi(Port *port)
* Verify on our side that the client doesn ' t do something funny .
* 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_RECV_BUFFER_SIZE )
ereport ( FATAL ,
{
ereport ( COMMERROR ,
( errmsg ( " oversize GSSAPI packet sent by the client (%zu > %d) " ,
( errmsg ( " oversize GSSAPI packet sent by the client (%zu > %d) " ,
( size_t ) input . length ,
( size_t ) input . length ,
PQ_GSS_RECV_BUFFER_SIZE ) ) ) ;
PQ_GSS_RECV_BUFFER_SIZE ) ) ) ;
return - 1 ;
}
/*
/*
* Get the rest of the packet so we can pass it to GSSAPI to accept
* Get the rest of the packet so we can pass it to GSSAPI to accept
@ -544,7 +583,7 @@ secure_open_gssapi(Port *port)
NULL , NULL ) ;
NULL , NULL ) ;
if ( GSS_ERROR ( major ) )
if ( GSS_ERROR ( major ) )
{
{
pg_GSS_error ( ERROR , gettext _noop ( " could not accept GSSAPI security context " ) ,
pg_GSS_error ( _ ( " could not accept GSSAPI security context " ) ,
major , minor ) ;
major , minor ) ;
gss_release_buffer ( & minor , & output ) ;
gss_release_buffer ( & minor , & output ) ;
return - 1 ;
return - 1 ;
@ -570,10 +609,14 @@ secure_open_gssapi(Port *port)
uint32 netlen = pg_hton32 ( output . length ) ;
uint32 netlen = pg_hton32 ( output . length ) ;
if ( output . length > PQ_GSS_SEND_BUFFER_SIZE - sizeof ( uint32 ) )
if ( output . length > PQ_GSS_SEND_BUFFER_SIZE - sizeof ( uint32 ) )
ereport ( FATAL ,
{
ereport ( COMMERROR ,
( errmsg ( " server tried to send oversize GSSAPI packet (%zu > %zu) " ,
( errmsg ( " server 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_SEND_BUFFER_SIZE - sizeof ( uint32 ) ) ) ) ;
gss_release_buffer ( & minor , & output ) ;
return - 1 ;
}
memcpy ( PqGSSSendBuffer , ( char * ) & netlen , sizeof ( uint32 ) ) ;
memcpy ( PqGSSSendBuffer , ( char * ) & netlen , sizeof ( uint32 ) ) ;
PqGSSSendLength + = sizeof ( uint32 ) ;
PqGSSSendLength + = sizeof ( uint32 ) ;
@ -634,8 +677,10 @@ secure_open_gssapi(Port *port)
& PqGSSMaxPktSize ) ;
& PqGSSMaxPktSize ) ;
if ( GSS_ERROR ( major ) )
if ( GSS_ERROR ( major ) )
pg_GSS_error ( FATAL , gettext_noop ( " GSSAPI size check error " ) ,
{
major , minor ) ;
pg_GSS_error ( _ ( " GSSAPI size check error " ) , major , minor ) ;
return - 1 ;
}
port - > gss - > enc = true ;
port - > gss - > enc = true ;
@ -667,12 +712,13 @@ be_gssapi_get_enc(Port *port)
}
}
/*
/*
* Return the GSSAPI principal used for authentication on this connection .
* Return the GSSAPI principal used for authentication on this connection
* ( NULL if we did not perform GSSAPI authentication ) .
*/
*/
const char *
const char *
be_gssapi_get_princ ( Port * port )
be_gssapi_get_princ ( Port * port )
{
{
if ( ! port | | ! port - > gss - > auth )
if ( ! port | | ! port - > gss )
return NULL ;
return NULL ;
return port - > gss - > princ ;
return port - > gss - > princ ;