@ -24,6 +24,7 @@
# include <sys/select.h>
# endif
# include "commands/user.h"
# include "common/ip.h"
# include "common/md5.h"
# include "libpq/auth.h"
@ -49,17 +50,15 @@ static char *recv_password_packet(Port *port);
/*----------------------------------------------------------------
* MD5 authentication
* Password - based authentication methods ( password , md5 , and scram )
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
static int CheckMD5Auth ( Port * port , char * * logdetail ) ;
static int CheckPasswordAuth ( Port * port , char * * logdetail ) ;
static int CheckPWChallengeAuth ( Port * port , char * * logdetail ) ;
/*----------------------------------------------------------------
* Plaintext password authentication
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
static int CheckMD5Auth ( Port * port , char * shadow_pass , char * * logdetail ) ;
static int CheckSCRAMAuth ( Port * port , char * shadow_pass , char * * logdetail ) ;
static int CheckPasswordAuth ( Port * port , char * * logdetail ) ;
/*----------------------------------------------------------------
* Ident authentication
@ -200,12 +199,6 @@ static int CheckRADIUSAuth(Port *port);
static int PerformRadiusTransaction ( char * server , char * secret , char * portstr , char * identifier , char * user_name , char * passwd ) ;
/*----------------------------------------------------------------
* SASL authentication
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
static int CheckSASLAuth ( Port * port , char * * logdetail ) ;
/*
* Maximum accepted size of GSS and SSPI authentication tokens .
*
@ -291,7 +284,7 @@ auth_failed(Port *port, int status, char *logdetail)
break ;
case uaPassword :
case uaMD5 :
case uaSASL :
case uaSCRAM :
errstr = gettext_noop ( " password authentication failed for user \" %s \" " ) ;
/* We use it to indicate if a .pgpass password failed. */
errcode_return = ERRCODE_INVALID_PASSWORD ;
@ -552,17 +545,14 @@ ClientAuthentication(Port *port)
break ;
case uaMD5 :
status = CheckMD5Auth ( port , & logdetail ) ;
case uaSCRAM :
status = CheckPWChallengeAuth ( port , & logdetail ) ;
break ;
case uaPassword :
status = CheckPasswordAuth ( port , & logdetail ) ;
break ;
case uaSASL :
status = CheckSASLAuth ( port , & logdetail ) ;
break ;
case uaPAM :
# ifdef USE_PAM
status = CheckPAMAuth ( port , port - > user_name , " " ) ;
@ -710,41 +700,34 @@ recv_password_packet(Port *port)
/*----------------------------------------------------------------
* MD5 authentication
* Password - based authentication mechanisms
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
/*
* Plaintext password authentication .
*/
static int
CheckMD5Auth ( Port * port , char * * logdetail )
CheckPassword Auth ( Port * port , char * * logdetail )
{
char md5Salt [ 4 ] ; /* Password salt */
char * passwd ;
char * shadow_pass ;
int result ;
char * shadow_pass ;
if ( Db_user_namespace )
ereport ( FATAL ,
( errcode ( ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION ) ,
errmsg ( " MD5 authentication is not supported when \" db_user_namespace \" is enabled " ) ) ) ;
/* include the salt to use for computing the response */
if ( ! pg_backend_random ( md5Salt , 4 ) )
{
ereport ( LOG ,
( errmsg ( " could not generate random MD5 salt " ) ) ) ;
return STATUS_ERROR ;
}
sendAuthRequest ( port , AUTH_REQ_MD5 , md5Salt , 4 ) ;
sendAuthRequest ( port , AUTH_REQ_PASSWORD , NULL , 0 ) ;
passwd = recv_password_packet ( port ) ;
if ( passwd = = NULL )
return STATUS_EOF ; /* client wouldn't send password */
result = get_role_password ( port - > user_name , & shadow_pass , logdetail ) ;
if ( result = = STATUS_OK )
result = md5_crypt_verify ( port - > user_name , shadow_pass , passwd ,
md5Salt , 4 , logdetail ) ;
shadow_pass = get_role_password ( port - > user_name , logdetail ) ;
if ( shadow_pass )
{
result = plain_crypt_verify ( port - > user_name , shadow_pass , passwd ,
logdetail ) ;
}
else
result = STATUS_ERROR ;
if ( shadow_pass )
pfree ( shadow_pass ) ;
@ -753,42 +736,114 @@ CheckMD5Auth(Port *port, char **logdetail)
return result ;
}
/*----------------------------------------------------------------
* Plaintext password authentication
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/*
* MD5 and SCRAM authentication .
*/
static int
CheckPWChallengeAuth ( Port * port , char * * logdetail )
{
int auth_result ;
char * shadow_pass ;
PasswordType pwtype ;
Assert ( port - > hba - > auth_method = = uaSCRAM | |
port - > hba - > auth_method = = uaMD5 ) ;
/* First look up the user's password. */
shadow_pass = get_role_password ( port - > user_name , logdetail ) ;
/*
* If the user does not exist , or has no password , we still go through the
* motions of authentication , to avoid revealing to the client that the
* user didn ' t exist . If ' md5 ' is allowed , we choose whether to use ' md5 '
* or ' scram ' authentication based on current password_encryption setting .
* The idea is that most genuine users probably have a password of that
* type , if we pretend that this user had a password of that type , too , it
* " blends in " best .
*
* If the user had a password , but it was expired , we ' ll use the details
* of the expired password for the authentication , but report it as
* failure to the client even if correct password was given .
*/
if ( ! shadow_pass )
pwtype = Password_encryption ;
else
pwtype = get_password_type ( shadow_pass ) ;
/*
* If ' md5 ' authentication is allowed , decide whether to perform ' md5 ' or
* ' scram ' authentication based on the type of password the user has . If
* it ' s an MD5 hash , we must do MD5 authentication , and if it ' s a SCRAM
* verifier , we must do SCRAM authentication . If it ' s stored in
* plaintext , we could do either one , so we opt for the more secure
* mechanism , SCRAM .
*
* If MD5 authentication is not allowed , always use SCRAM . If the user
* had an MD5 password , CheckSCRAMAuth ( ) will fail .
*/
if ( port - > hba - > auth_method = = uaMD5 & & pwtype = = PASSWORD_TYPE_MD5 )
{
auth_result = CheckMD5Auth ( port , shadow_pass , logdetail ) ;
}
else
{
auth_result = CheckSCRAMAuth ( port , shadow_pass , logdetail ) ;
}
if ( shadow_pass )
pfree ( shadow_pass ) ;
/*
* If get_role_password ( ) returned error , return error , even if the
* authentication succeeded .
*/
if ( ! shadow_pass )
{
Assert ( auth_result ! = STATUS_OK ) ;
return STATUS_ERROR ;
}
return auth_result ;
}
static int
CheckPasswordAuth ( Port * port , char * * logdetail )
CheckMD5 Auth ( Port * port , char * shadow_pass , char * * logdetail )
{
char md5Salt [ 4 ] ; /* Password salt */
char * passwd ;
int result ;
char * shadow_pass ;
sendAuthRequest ( port , AUTH_REQ_PASSWORD , NULL , 0 ) ;
if ( Db_user_namespace )
ereport ( FATAL ,
( errcode ( ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION ) ,
errmsg ( " MD5 authentication is not supported when \" db_user_namespace \" is enabled " ) ) ) ;
/* include the salt to use for computing the response */
if ( ! pg_backend_random ( md5Salt , 4 ) )
{
ereport ( LOG ,
( errmsg ( " could not generate random MD5 salt " ) ) ) ;
return STATUS_ERROR ;
}
sendAuthRequest ( port , AUTH_REQ_MD5 , md5Salt , 4 ) ;
passwd = recv_password_packet ( port ) ;
if ( passwd = = NULL )
return STATUS_EOF ; /* client wouldn't send password */
result = get_role_password ( port - > user_name , & shadow_pass , logdetail ) ;
if ( result = = STATUS_OK )
result = plain_crypt_verify ( port - > user_name , shadow_pass , passwd ,
logdetail ) ;
if ( shadow_pass )
pfree ( shadow_pass ) ;
result = md5_crypt_verify ( port - > user_name , shadow_pass , passwd ,
md5Salt , 4 , logdetail ) ;
else
result = STATUS_ERROR ;
pfree ( passwd ) ;
return result ;
}
/*----------------------------------------------------------------
* SASL authentication system
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
static int
CheckSASLAuth ( Port * port , char * * logdetail )
CheckSCRAMAuth ( Port * port , char * shadow_pass , char * * logdetail )
{
int mtype ;
StringInfoData buf ;
@ -796,8 +851,6 @@ CheckSASLAuth(Port *port, char **logdetail)
char * output = NULL ;
int outputlen = 0 ;
int result ;
char * shadow_pass ;
bool doomed = false ;
/*
* SASL auth is not supported for protocol versions before 3 , because it
@ -827,11 +880,9 @@ CheckSASLAuth(Port *port, char **logdetail)
* This is because we don ' t want to reveal to an attacker what usernames
* are valid , nor which users have a valid password .
*/
if ( get_role_password ( port - > user_name , & shadow_pass , logdetail ) ! = STATUS_OK )
doomed = true ;
/* Initialize the status tracker for message exchanges */
scram_opaq = pg_be_scram_init ( port - > user_name , shadow_pass , doomed ) ;
scram_opaq = pg_be_scram_init ( port - > user_name , shadow_pass ) ;
/*
* Loop through SASL message exchange . This exchange can consist of
@ -875,7 +926,7 @@ CheckSASLAuth(Port *port, char **logdetail)
*/
result = pg_be_scram_exchange ( scram_opaq , buf . data , buf . len ,
& output , & outputlen ,
doomed ? NULL : logdetail ) ;
logdetail ) ;
/* input buffer no longer used */
pfree ( buf . data ) ;