1/*-------------------------------------------------------------------------
4 * Routines to handle authentication via SASL
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/libpq/auth-sasl.c
13 *-------------------------------------------------------------------------
24 * Perform a SASL exchange with a libpq client, using a specific mechanism
27 * shadow_pass is an optional pointer to the stored secret of the role
28 * authenticated, from pg_authid.rolpassword. For mechanisms that use
29 * shadowed passwords, a NULL pointer here means that an entry could not
30 * be found for the role (or the user does not exist), and the mechanism
31 * should fail the authentication exchange.
33 * Mechanisms must take care not to reveal to the client that a user entry
34 * does not exist; ideally, the external failure mode is identical to that
35 * of an incorrect password. Mechanisms may instead use the logdetail
36 * output parameter to internally differentiate between failure cases and
37 * assist debugging by the server admin.
39 * A mechanism is not required to utilize a shadow entry, or even a password
40 * system at all; for these cases, shadow_pass may be ignored and the caller
41 * should just pass NULL.
45 const char **logdetail)
59 * Send the SASL authentication request to user. It includes the list of
60 * authentication mechanisms that are supported.
65 /* Put another '0円' to mark that list is finished. */
72 * Loop through SASL message exchange. This exchange can consist of
73 * multiple messages sent in both directions. First message is always
74 * from the client. All messages from client to server are password
84 /* Only log error if client didn't disconnect. */
88 (
errcode(ERRCODE_PROTOCOL_VIOLATION),
89 errmsg(
"expected SASL response, got message type %d",
96 /* Get the actual SASL message */
100 /* EOF - pq_getmessage already logged error */
105 elog(
DEBUG4,
"processing received SASL response of length %d",
buf.len);
108 * The first SASLInitialResponse message is different from the others.
109 * It indicates which SASL mechanism the client selected, and contains
110 * an optional Initial Client Response payload. The subsequent
111 * SASLResponse messages contain just the SASL payload.
115 const char *selected_mech;
120 * Initialize the status tracker for message exchanges.
122 * If the user doesn't exist, or doesn't have a valid password, or
123 * it's expired, we still go through the motions of SASL
124 * authentication, but tell the authentication method that the
125 * authentication is "doomed". That is, it's going to fail, no
128 * This is because we don't want to reveal to an attacker what
129 * usernames are valid, nor which users have a valid password.
131 opaq = mech->
init(
port, selected_mech, shadow_pass);
149 * The StringInfo guarantees that there's a 0円 byte after the
155 * Hand the incoming message to the mechanism implementation.
161 /* input buffer no longer used */
167 * PG_SASL_EXCHANGE_FAILURE with some output is forbidden by SASL.
168 * Make sure here that the mechanism used got that right.
171 elog(
ERROR,
"output message found after SASL exchange failure");
174 * Negotiation generated data to be sent to the client.
176 elog(
DEBUG4,
"sending SASL challenge of length %d", outputlen);
187 /* Oops, Something bad happened */
int CheckSASLAuth(const pg_be_sasl_mech *mech, Port *port, char *shadow_pass, const char **logdetail)
void sendAuthRequest(Port *port, AuthRequest areq, const void *extradata, int extralen)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
Assert(PointerIsAligned(start, uint64))
void pfree(void *pointer)
int pq_getmessage(StringInfo s, int maxlen)
void pq_startmsgread(void)
#define AUTH_REQ_SASL_CONT
#define PqMsg_SASLResponse
#define AUTH_REQ_SASL_FIN
#define PG_SASL_EXCHANGE_FAILURE
#define PG_SASL_EXCHANGE_CONTINUE
#define PG_SASL_EXCHANGE_SUCCESS
void appendStringInfoChar(StringInfo str, char ch)
void initStringInfo(StringInfo str)
void *(* init)(Port *port, const char *mech, const char *shadow_pass)
int(* exchange)(void *state, const char *input, int inputlen, char **output, int *outputlen, const char **logdetail)
void(* get_mechanisms)(Port *port, StringInfo buf)