diff options
Diffstat (limited to 'src/backend/libpq/auth.c')
-rw-r--r-- | src/backend/libpq/auth.c | 167 |
1 files changed, 6 insertions, 161 deletions
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c index 967b5ef73cc..8cc23ef7fb4 100644 --- a/src/backend/libpq/auth.c +++ b/src/backend/libpq/auth.c @@ -26,11 +26,11 @@ #include "commands/user.h" #include "common/ip.h" #include "common/md5.h" -#include "common/scram-common.h" #include "libpq/auth.h" #include "libpq/crypt.h" #include "libpq/libpq.h" #include "libpq/pqformat.h" +#include "libpq/sasl.h" #include "libpq/scram.h" #include "miscadmin.h" #include "port/pg_bswap.h" @@ -45,8 +45,6 @@ * Global authentication functions *---------------------------------------------------------------- */ -static void sendAuthRequest(Port *port, AuthRequest areq, const char *extradata, - int extralen); static void auth_failed(Port *port, int status, char *logdetail); static char *recv_password_packet(Port *port); static void set_authn_id(Port *port, const char *id); @@ -60,7 +58,6 @@ static int CheckPasswordAuth(Port *port, char **logdetail); static int CheckPWChallengeAuth(Port *port, char **logdetail); static int CheckMD5Auth(Port *port, char *shadow_pass, char **logdetail); -static int CheckSCRAMAuth(Port *port, char *shadow_pass, char **logdetail); /*---------------------------------------------------------------- @@ -224,14 +221,6 @@ static int PerformRadiusTransaction(const char *server, const char *secret, cons */ #define PG_MAX_AUTH_TOKEN_LENGTH 65535 -/* - * Maximum accepted size of SASL messages. - * - * The messages that the server or libpq generate are much smaller than this, - * but have some headroom. - */ -#define PG_MAX_SASL_MESSAGE_LENGTH 1024 - /*---------------------------------------------------------------- * Global authentication functions *---------------------------------------------------------------- @@ -668,7 +657,7 @@ ClientAuthentication(Port *port) /* * Send an authentication request packet to the frontend. */ -static void +void sendAuthRequest(Port *port, AuthRequest areq, const char *extradata, int extralen) { StringInfoData buf; @@ -848,12 +837,14 @@ CheckPWChallengeAuth(Port *port, char **logdetail) * SCRAM secret, we must do SCRAM authentication. * * If MD5 authentication is not allowed, always use SCRAM. If the user - * had an MD5 password, CheckSCRAMAuth() will fail. + * had an MD5 password, CheckSASLAuth() with the SCRAM mechanism 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); + auth_result = CheckSASLAuth(&pg_be_scram_mech, port, shadow_pass, + logdetail); if (shadow_pass) pfree(shadow_pass); @@ -911,152 +902,6 @@ CheckMD5Auth(Port *port, char *shadow_pass, char **logdetail) return result; } -static int -CheckSCRAMAuth(Port *port, char *shadow_pass, char **logdetail) -{ - StringInfoData sasl_mechs; - int mtype; - StringInfoData buf; - void *scram_opaq = NULL; - char *output = NULL; - int outputlen = 0; - const char *input; - int inputlen; - int result; - bool initial; - - /* - * Send the SASL authentication request to user. It includes the list of - * authentication mechanisms that are supported. - */ - initStringInfo(&sasl_mechs); - - pg_be_scram_get_mechanisms(port, &sasl_mechs); - /* Put another '\0' to mark that list is finished. */ - appendStringInfoChar(&sasl_mechs, '\0'); - - sendAuthRequest(port, AUTH_REQ_SASL, sasl_mechs.data, sasl_mechs.len); - pfree(sasl_mechs.data); - - /* - * Loop through SASL message exchange. This exchange can consist of - * multiple messages sent in both directions. First message is always - * from the client. All messages from client to server are password - * packets (type 'p'). - */ - initial = true; - do - { - pq_startmsgread(); - mtype = pq_getbyte(); - if (mtype != 'p') - { - /* Only log error if client didn't disconnect. */ - if (mtype != EOF) - { - ereport(ERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("expected SASL response, got message type %d", - mtype))); - } - else - return STATUS_EOF; - } - - /* Get the actual SASL message */ - initStringInfo(&buf); - if (pq_getmessage(&buf, PG_MAX_SASL_MESSAGE_LENGTH)) - { - /* EOF - pq_getmessage already logged error */ - pfree(buf.data); - return STATUS_ERROR; - } - - elog(DEBUG4, "processing received SASL response of length %d", buf.len); - - /* - * The first SASLInitialResponse message is different from the others. - * It indicates which SASL mechanism the client selected, and contains - * an optional Initial Client Response payload. The subsequent - * SASLResponse messages contain just the SASL payload. - */ - if (initial) - { - const char *selected_mech; - - selected_mech = pq_getmsgrawstring(&buf); - - /* - * Initialize the status tracker for message exchanges. - * - * If the user doesn't exist, or doesn't have a valid password, or - * it's expired, we still go through the motions of SASL - * authentication, but tell the authentication method that the - * authentication is "doomed". That is, it's going to fail, no - * matter what. - * - * This is because we don't want to reveal to an attacker what - * usernames are valid, nor which users have a valid password. - */ - scram_opaq = pg_be_scram_init(port, selected_mech, shadow_pass); - - inputlen = pq_getmsgint(&buf, 4); - if (inputlen == -1) - input = NULL; - else - input = pq_getmsgbytes(&buf, inputlen); - - initial = false; - } - else - { - inputlen = buf.len; - input = pq_getmsgbytes(&buf, buf.len); - } - pq_getmsgend(&buf); - - /* - * The StringInfo guarantees that there's a \0 byte after the - * response. - */ - Assert(input == NULL || input[inputlen] == '\0'); - - /* - * we pass 'logdetail' as NULL when doing a mock authentication, - * because we should already have a better error message in that case - */ - result = pg_be_scram_exchange(scram_opaq, input, inputlen, - &output, &outputlen, - logdetail); - - /* input buffer no longer used */ - pfree(buf.data); - - if (output) - { - /* - * Negotiation generated data to be sent to the client. - */ - elog(DEBUG4, "sending SASL challenge of length %u", outputlen); - - if (result == SASL_EXCHANGE_SUCCESS) - sendAuthRequest(port, AUTH_REQ_SASL_FIN, output, outputlen); - else - sendAuthRequest(port, AUTH_REQ_SASL_CONT, output, outputlen); - - pfree(output); - } - } while (result == SASL_EXCHANGE_CONTINUE); - - /* Oops, Something bad happened */ - if (result != SASL_EXCHANGE_SUCCESS) - { - return STATUS_ERROR; - } - - return STATUS_OK; -} - /*---------------------------------------------------------------- * GSSAPI authentication system |