34#ifdef HAVE_SYS_UCRED_H
66 gss_flags = GSS_C_MUTUAL_FLAG;
67 gss_buffer_desc ginbuf;
68 gss_buffer_desc goutbuf;
74 if (
conn->gctx != GSS_C_NO_CONTEXT)
76 ginbuf.length = payloadlen;
77 ginbuf.value =
malloc(payloadlen);
106 conn->gcred = GSS_C_NO_CREDENTIAL;
109 gss_flags |= GSS_C_DELEG_FLAG;
111 maj_stat = gss_init_sec_context(&min_stat,
118 GSS_C_NO_CHANNEL_BINDINGS,
119 (ginbuf.value == NULL) ? GSS_C_NO_BUFFER : &ginbuf,
127 if (goutbuf.length != 0)
136 goutbuf.value, goutbuf.length) !=
STATUS_OK)
138 gss_release_buffer(&lmin_s, &goutbuf);
142 gss_release_buffer(&lmin_s, &goutbuf);
144 if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
149 gss_release_name(&lmin_s, &
conn->gtarg_nam);
151 gss_delete_sec_context(&lmin_s, &
conn->gctx, GSS_C_NO_BUFFER);
155 if (maj_stat == GSS_S_COMPLETE)
158 gss_release_name(&lmin_s, &
conn->gtarg_nam);
174 if (!(host && host[0] !=
'\0'))
194 conn->gctx = GSS_C_NO_CONTEXT;
196 return pg_GSS_continue(
conn, payloadlen);
207pg_SSPI_error(
PGconn *
conn,
const char *mprefix, SECURITY_STATUS r)
211 if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS |
212 FORMAT_MESSAGE_FROM_SYSTEM,
214 sysmsg,
sizeof(sysmsg), NULL) == 0)
216 mprefix, (
unsigned int) r);
219 mprefix, sysmsg, (
unsigned int) r);
229 CtxtHandle newContext;
232 SecBufferDesc outbuf;
233 SecBuffer OutBuffers[1];
234 SecBuffer InBuffers[1];
235 char *inputbuf = NULL;
237 if (
conn->sspictx != NULL)
243 inputbuf =
malloc(payloadlen);
260 inbuf.ulVersion = SECBUFFER_VERSION;
262 inbuf.pBuffers = InBuffers;
263 InBuffers[0].pvBuffer = inputbuf;
264 InBuffers[0].cbBuffer = payloadlen;
265 InBuffers[0].BufferType = SECBUFFER_TOKEN;
272 OutBuffers[0].pvBuffer = NULL;
273 OutBuffers[0].BufferType = SECBUFFER_TOKEN;
274 OutBuffers[0].cbBuffer = 0;
276 outbuf.pBuffers = OutBuffers;
277 outbuf.ulVersion = SECBUFFER_VERSION;
279 r = InitializeSecurityContext(
conn->sspicred,
282 ISC_REQ_ALLOCATE_MEMORY,
284 SECURITY_NETWORK_DREP,
285 (
conn->sspictx == NULL) ? NULL : &inbuf,
295 if (r != SEC_E_OK && r != SEC_I_CONTINUE_NEEDED)
302 if (
conn->sspictx == NULL)
306 if (
conn->sspictx == NULL)
311 memcpy(
conn->sspictx, &newContext,
sizeof(CtxtHandle));
318 if (outbuf.cBuffers > 0)
320 if (outbuf.cBuffers != 1)
328 "SSPI returned invalid number of output buffers\n");
337 if (outbuf.pBuffers[0].cbBuffer > 0)
341 outbuf.pBuffers[0].pvBuffer, outbuf.pBuffers[0].cbBuffer))
343 FreeContextBuffer(outbuf.pBuffers[0].pvBuffer);
347 FreeContextBuffer(outbuf.pBuffers[0].pvBuffer);
364pg_SSPI_startup(
PGconn *
conn,
int use_negotiate,
int payloadlen)
380 if (
conn->sspicred == NULL)
386 r = AcquireCredentialsHandle(NULL,
387 use_negotiate ?
"negotiate" :
"kerberos",
388 SECPKG_CRED_OUTBOUND,
399 conn->sspicred = NULL;
408 if (!(host && host[0] !=
'\0'))
414 if (!
conn->sspitarget)
427 return pg_SSPI_continue(
conn, payloadlen);
437 char *initialresponse = NULL;
438 int initialresponselen;
439 const char *selected_mechanism;
464 selected_mechanism = NULL;
470 "fe_sendauth: invalid authentication request from server: invalid list of authentication mechanisms\n");
477 if (mechanism_buf.
data[0] ==
'\0')
549 if (!selected_mechanism)
558 bool allowed =
false;
580 libpq_append_conn_error(
conn,
"channel binding is required, but server did not offer an authentication method that supports channel binding");
639 &initialresponse, &initialresponselen);
682 free(initialresponse);
688 free(initialresponse);
693 free(initialresponse);
713 challenge =
malloc(payloadlen + 1);
732 challenge[payloadlen] =
'\0';
735 challenge, payloadlen,
799 char *crypt_pwd = NULL;
800 const char *pwd_to_send;
821 const char *errstr = NULL;
841 4, crypt_pwd, &errstr))
848 pwd_to_send = crypt_pwd;
859 pwd_to_send, strlen(pwd_to_send) + 1);
873 return libpq_gettext(
"server requested a cleartext password");
878 return libpq_gettext(
"server requested GSSAPI authentication");
880 return libpq_gettext(
"server requested SSPI authentication");
884 return libpq_gettext(
"server requested SASL authentication");
887 return libpq_gettext(
"server requested an unknown authentication type");
894#define auth_method_allowed(conn, type) \
895 (((conn)->allowed_auth_methods & (1 << (type))) != 0)
906 const char *reason = NULL;
909 "AUTH_REQ_MAX overflows the allowed_auth_methods bitmask");
979 reason =
libpq_gettext(
"server did not complete authentication");
1088#if defined(ENABLE_GSS) || defined(ENABLE_SSPI)
1090#if !defined(ENABLE_SSPI)
1107#if defined(ENABLE_GSS) && defined(ENABLE_SSPI)
1109 r = pg_GSS_startup(
conn, payloadlen);
1111 r = pg_SSPI_startup(
conn, 0, payloadlen);
1112#elif defined(ENABLE_GSS) && !defined(ENABLE_SSPI)
1113 r = pg_GSS_startup(
conn, payloadlen);
1114#elif !defined(ENABLE_GSS) && defined(ENABLE_SSPI)
1115 r = pg_SSPI_startup(
conn, 0, payloadlen);
1132#if defined(ENABLE_GSS) && defined(ENABLE_SSPI)
1134 r = pg_SSPI_continue(
conn, payloadlen);
1136 r = pg_GSS_continue(
conn, payloadlen);
1137#elif defined(ENABLE_GSS) && !defined(ENABLE_SSPI)
1138 r = pg_GSS_continue(
conn, payloadlen);
1139#elif !defined(ENABLE_GSS) && defined(ENABLE_SSPI)
1140 r = pg_SSPI_continue(
conn, payloadlen);
1184#if !defined(ENABLE_GSS)
1214 "fe_sendauth: error sending password authentication\n");
1244 "fe_sendauth: invalid authentication request from server: AUTH_REQ_SASL_CONT without AUTH_REQ_SASL\n");
1260 "fe_sendauth: error in SASL authentication\n");
1288 char *result = NULL;
1289 const char *
name = NULL;
1296 struct passwd pwbuf;
1297 struct passwd *pw = NULL;
1303 if (GetUserName(
username, &namesize))
1305 else if (errorMessage)
1307 "user name lookup failure: error code %lu",
1310 rc = getpwuid_r(user_id, &pwbuf,
buf,
sizeof buf, &pw);
1315 libpq_append_error(errorMessage,
"could not look up local user ID %ld: %m", (
long) user_id);
1320 libpq_append_error(errorMessage,
"local user with ID %ld does not exist", (
long) user_id);
1328 result = strdup(
name);
1329 if (result == NULL && errorMessage)
1366 const char *errstr = NULL;
1407 const char *algorithm)
1409#define MAX_ALGORITHM_NAME_LEN 50
1411 char *crypt_pwd = NULL;
1419 if (algorithm == NULL)
1424 res =
PQexec(
conn,
"show password_encryption");
1450 strcpy(algobuf,
val);
1453 algorithm = algobuf;
1461 if (strcmp(algorithm,
"on") == 0 ||
1462 strcmp(algorithm,
"off") == 0)
1468 if (strcmp(algorithm,
"scram-sha-256") == 0)
1470 const char *errstr = NULL;
1478 else if (strcmp(algorithm,
"md5") == 0)
1483 const char *errstr = NULL;
1536 if (!encrypted_password)
1544 strlen(encrypted_password));
void pg_GSS_error(const char *errmsg, OM_uint32 maj_stat, OM_uint32 min_stat)
#define StaticAssertDecl(condition, errmessage)
const pg_fe_sasl_mech pg_oauth_mech
const pg_fe_sasl_mech pg_scram_mech
char * pg_fe_scram_build_secret(const char *password, int iterations, const char **errstr)
char * PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user, const char *algorithm)
#define MAX_ALGORITHM_NAME_LEN
static bool check_expected_areq(AuthRequest areq, PGconn *conn)
void PQsetAuthDataHook(PQauthDataHook_type hook)
PGresult * PQchangePassword(PGconn *conn, const char *user, const char *passwd)
PQauthDataHook_type PQauthDataHook
static int pg_SASL_continue(PGconn *conn, int payloadlen, bool final, bool *async)
static int pg_password_sendauth(PGconn *conn, const char *password, AuthRequest areq)
PQauthDataHook_type PQgetAuthDataHook(void)
int PQdefaultAuthDataHook(PGauthData type, PGconn *conn, void *data)
static int pg_SASL_init(PGconn *conn, int payloadlen, bool *async)
int pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn, bool *async)
char * pg_fe_getauthname(PQExpBuffer errorMessage)
char * PQencryptPassword(const char *passwd, const char *user)
static const char * auth_method_description(AuthRequest areq)
char * pg_fe_getusername(uid_t user_id, PQExpBuffer errorMessage)
#define auth_method_allowed(conn, type)
int pqPacketSend(PGconn *conn, char pack_type, const void *buf, size_t buf_len)
void PQfreemem(void *ptr)
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
ExecStatusType PQresultStatus(const PGresult *res)
void PQclear(PGresult *res)
int PQntuples(const PGresult *res)
char * PQescapeLiteral(PGconn *conn, const char *str, size_t len)
PGresult * PQexec(PGconn *conn, const char *query)
char * PQescapeIdentifier(PGconn *conn, const char *str, size_t len)
int PQnfields(const PGresult *res)
int pg_GSS_load_servicename(PGconn *conn)
bool pg_GSS_have_cred_cache(gss_cred_id_t *cred_out)
int pqPutInt(int value, size_t bytes, PGconn *conn)
int pqFlush(PGconn *conn)
int pqPutMsgStart(char msg_type, PGconn *conn)
int pqGetnchar(char *s, size_t len, PGconn *conn)
int pqGets(PQExpBuffer buf, PGconn *conn)
int pqPutnchar(const char *s, size_t len, PGconn *conn)
int pqPuts(const char *s, PGconn *conn)
void libpq_append_error(PQExpBuffer errorMessage, const char *fmt,...)
void libpq_append_conn_error(PGconn *conn, const char *fmt,...)
int pqPutMsgEnd(PGconn *conn)
void pqTraceOutputMessage(PGconn *conn, const char *message, bool toServer)
Assert(PointerIsAligned(start, uint64))
int(* PQauthDataHook_type)(PGauthData type, PGconn *conn, void *data)
#define PQnoPasswordSupplied
#define AUTH_RESPONSE_PASSWORD
#define AUTH_RESPONSE_SASL
#define AUTH_RESPONSE_SASL_INITIAL
#define pqClearConnErrorState(conn)
#define AUTH_RESPONSE_GSS
#define pgunlock_thread()
bool pg_md5_encrypt(const char *passwd, const char *salt, size_t salt_len, char *buf, const char **errstr)
int pg_strcasecmp(const char *s1, const char *s2)
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
void initPQExpBuffer(PQExpBuffer str)
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
void termPQExpBuffer(PQExpBuffer str)
#define PQExpBufferDataBroken(buf)
#define AUTH_REQ_SASL_CONT
#define PqMsg_GSSResponse
#define PqMsg_SASLResponse
#define PqMsg_SASLInitialResponse
#define AUTH_REQ_PASSWORD
#define AUTH_REQ_GSS_CONT
#define PqMsg_PasswordMessage
#define AUTH_REQ_SASL_FIN
#define SCRAM_SHA_256_PLUS_NAME
#define SCRAM_SHA_256_NAME
char current_auth_response
const pg_fe_sasl_mech * sasl
void(* cleanup_async_auth)(PGconn *conn)
bool client_finished_auth
uint32 allowed_auth_methods
PQExpBufferData errorMessage
void * scram_client_key_binary
PostgresPollingStatusType(* async_auth)(PGconn *conn)
int scram_sha_256_iterations
const pg_fe_sasl_mech * allowed_sasl_mechs[2]
bool(* channel_bound)(void *state)
SASLStatus(* exchange)(void *state, bool final, char *input, int inputlen, char **output, int *outputlen)
void *(* init)(PGconn *conn, const char *password, const char *mech)