PostgreSQL Source Code  git master
auth-sasl.c File Reference
#include "postgres.h"
#include "libpq/auth.h"
#include "libpq/libpq.h"
#include "libpq/pqformat.h"
#include "libpq/sasl.h"
Include dependency graph for auth-sasl.c:

Go to the source code of this file.

Macros

#define PG_MAX_SASL_MESSAGE_LENGTH   1024
 

Functions

int CheckSASLAuth (const pg_be_sasl_mech *mech, Port *port, char *shadow_pass, const char **logdetail)
 

Macro Definition Documentation

◆ PG_MAX_SASL_MESSAGE_LENGTH

#define PG_MAX_SASL_MESSAGE_LENGTH   1024

Definition at line 29 of file auth-sasl.c.

Function Documentation

◆ CheckSASLAuth()

int CheckSASLAuth ( const pg_be_sasl_mech mech,
Port port,
char *  shadow_pass,
const char **  logdetail 
)

Definition at line 52 of file auth-sasl.c.

54 {
55  StringInfoData sasl_mechs;
56  int mtype;
58  void *opaq = NULL;
59  char *output = NULL;
60  int outputlen = 0;
61  const char *input;
62  int inputlen;
63  int result;
64  bool initial;
65 
66  /*
67  * Send the SASL authentication request to user. It includes the list of
68  * authentication mechanisms that are supported.
69  */
70  initStringInfo(&sasl_mechs);
71 
72  mech->get_mechanisms(port, &sasl_mechs);
73  /* Put another '\0' to mark that list is finished. */
74  appendStringInfoChar(&sasl_mechs, '\0');
75 
76  sendAuthRequest(port, AUTH_REQ_SASL, sasl_mechs.data, sasl_mechs.len);
77  pfree(sasl_mechs.data);
78 
79  /*
80  * Loop through SASL message exchange. This exchange can consist of
81  * multiple messages sent in both directions. First message is always
82  * from the client. All messages from client to server are password
83  * packets (type 'p').
84  */
85  initial = true;
86  do
87  {
89  mtype = pq_getbyte();
90  if (mtype != PqMsg_SASLResponse)
91  {
92  /* Only log error if client didn't disconnect. */
93  if (mtype != EOF)
94  {
95  ereport(ERROR,
96  (errcode(ERRCODE_PROTOCOL_VIOLATION),
97  errmsg("expected SASL response, got message type %d",
98  mtype)));
99  }
100  else
101  return STATUS_EOF;
102  }
103 
104  /* Get the actual SASL message */
107  {
108  /* EOF - pq_getmessage already logged error */
109  pfree(buf.data);
110  return STATUS_ERROR;
111  }
112 
113  elog(DEBUG4, "processing received SASL response of length %d", buf.len);
114 
115  /*
116  * The first SASLInitialResponse message is different from the others.
117  * It indicates which SASL mechanism the client selected, and contains
118  * an optional Initial Client Response payload. The subsequent
119  * SASLResponse messages contain just the SASL payload.
120  */
121  if (initial)
122  {
123  const char *selected_mech;
124 
125  selected_mech = pq_getmsgrawstring(&buf);
126 
127  /*
128  * Initialize the status tracker for message exchanges.
129  *
130  * If the user doesn't exist, or doesn't have a valid password, or
131  * it's expired, we still go through the motions of SASL
132  * authentication, but tell the authentication method that the
133  * authentication is "doomed". That is, it's going to fail, no
134  * matter what.
135  *
136  * This is because we don't want to reveal to an attacker what
137  * usernames are valid, nor which users have a valid password.
138  */
139  opaq = mech->init(port, selected_mech, shadow_pass);
140 
141  inputlen = pq_getmsgint(&buf, 4);
142  if (inputlen == -1)
143  input = NULL;
144  else
145  input = pq_getmsgbytes(&buf, inputlen);
146 
147  initial = false;
148  }
149  else
150  {
151  inputlen = buf.len;
152  input = pq_getmsgbytes(&buf, buf.len);
153  }
154  pq_getmsgend(&buf);
155 
156  /*
157  * The StringInfo guarantees that there's a \0 byte after the
158  * response.
159  */
160  Assert(input == NULL || input[inputlen] == '\0');
161 
162  /*
163  * Hand the incoming message to the mechanism implementation.
164  */
165  result = mech->exchange(opaq, input, inputlen,
166  &output, &outputlen,
167  logdetail);
168 
169  /* input buffer no longer used */
170  pfree(buf.data);
171 
172  if (output)
173  {
174  /*
175  * PG_SASL_EXCHANGE_FAILURE with some output is forbidden by SASL.
176  * Make sure here that the mechanism used got that right.
177  */
178  if (result == PG_SASL_EXCHANGE_FAILURE)
179  elog(ERROR, "output message found after SASL exchange failure");
180 
181  /*
182  * Negotiation generated data to be sent to the client.
183  */
184  elog(DEBUG4, "sending SASL challenge of length %d", outputlen);
185 
186  if (result == PG_SASL_EXCHANGE_SUCCESS)
188  else
190 
191  pfree(output);
192  }
193  } while (result == PG_SASL_EXCHANGE_CONTINUE);
194 
195  /* Oops, Something bad happened */
196  if (result != PG_SASL_EXCHANGE_SUCCESS)
197  {
198  return STATUS_ERROR;
199  }
200 
201  return STATUS_OK;
202 }
#define PG_MAX_SASL_MESSAGE_LENGTH
Definition: auth-sasl.c:29
void sendAuthRequest(Port *port, AuthRequest areq, const char *extradata, int extralen)
Definition: auth.c:676
#define STATUS_OK
Definition: c.h:1156
#define STATUS_EOF
Definition: c.h:1158
#define STATUS_ERROR
Definition: c.h:1157
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
#define ereport(elevel,...)
Definition: elog.h:149
#define DEBUG4
Definition: elog.h:27
FILE * input
FILE * output
Assert(fmt[strlen(fmt) - 1] !='\n')
void pfree(void *pointer)
Definition: mcxt.c:1508
static int port
Definition: pg_regress.c:116
static char * buf
Definition: pg_test_fsync.c:73
int pq_getmessage(StringInfo s, int maxlen)
Definition: pqcomm.c:1198
int pq_getbyte(void)
Definition: pqcomm.c:961
void pq_startmsgread(void)
Definition: pqcomm.c:1136
unsigned int pq_getmsgint(StringInfo msg, int b)
Definition: pqformat.c:415
void pq_getmsgend(StringInfo msg)
Definition: pqformat.c:635
const char * pq_getmsgbytes(StringInfo msg, int datalen)
Definition: pqformat.c:508
const char * pq_getmsgrawstring(StringInfo msg)
Definition: pqformat.c:608
#define AUTH_REQ_SASL_CONT
Definition: protocol.h:81
#define PqMsg_SASLResponse
Definition: protocol.h:33
#define AUTH_REQ_SASL
Definition: protocol.h:80
#define AUTH_REQ_SASL_FIN
Definition: protocol.h:82
#define PG_SASL_EXCHANGE_FAILURE
Definition: sasl.h:27
#define PG_SASL_EXCHANGE_CONTINUE
Definition: sasl.h:25
#define PG_SASL_EXCHANGE_SUCCESS
Definition: sasl.h:26
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:194
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
int(* exchange)(void *state, const char *input, int inputlen, char **output, int *outputlen, const char **logdetail)
Definition: sasl.h:126
void(* get_mechanisms)(Port *port, StringInfo buf)
Definition: sasl.h:56
void *(* init)(Port *port, const char *mech, const char *shadow_pass)
Definition: sasl.h:80

References appendStringInfoChar(), Assert(), AUTH_REQ_SASL, AUTH_REQ_SASL_CONT, AUTH_REQ_SASL_FIN, buf, StringInfoData::data, DEBUG4, elog, ereport, errcode(), errmsg(), ERROR, pg_be_sasl_mech::exchange, pg_be_sasl_mech::get_mechanisms, pg_be_sasl_mech::init, initStringInfo(), input, StringInfoData::len, output, pfree(), PG_MAX_SASL_MESSAGE_LENGTH, PG_SASL_EXCHANGE_CONTINUE, PG_SASL_EXCHANGE_FAILURE, PG_SASL_EXCHANGE_SUCCESS, port, pq_getbyte(), pq_getmessage(), pq_getmsgbytes(), pq_getmsgend(), pq_getmsgint(), pq_getmsgrawstring(), pq_startmsgread(), PqMsg_SASLResponse, sendAuthRequest(), STATUS_EOF, STATUS_ERROR, and STATUS_OK.

Referenced by CheckPWChallengeAuth().