*----------------------------------------------------------------
*/
static void sendAuthRequest(Port *port, AuthRequest areq);
-static void auth_failed(Port *port, int status);
+static void auth_failed(Port *port, int status, char *logdetail);
static char *recv_password_packet(Port *port);
-static int recv_and_check_password_packet(Port *port);
+static int recv_and_check_password_packet(Port *port, char **logdetail);
/*----------------------------------------------------------------
* in use, and these are items that must be presumed known to an attacker
* anyway.
* Note that many sorts of failure report additional information in the
- * postmaster log, which we hope is only readable by good guys.
+ * postmaster log, which we hope is only readable by good guys. In
+ * particular, if logdetail isn't NULL, we send that string to the log.
*/
static void
-auth_failed(Port *port, int status)
+auth_failed(Port *port, int status, char *logdetail)
{
const char *errstr;
int errcode_return = ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION;
}
if (port->hba)
- ereport(FATAL,
- (errcode(errcode_return),
- errmsg(errstr, port->user_name),
- errdetail_log("Connection matched pg_hba.conf line %d: \"%s\"", port->hba->linenumber, port->hba->rawline)));
- else
- ereport(FATAL,
- (errcode(errcode_return),
- errmsg(errstr, port->user_name)));
+ {
+ char *cdetail;
+
+ cdetail = psprintf(_("Connection matched pg_hba.conf line %d: \"%s\""),
+ port->hba->linenumber, port->hba->rawline);
+ if (logdetail)
+ logdetail = psprintf("%s\n%s", logdetail, cdetail);
+ else
+ logdetail = cdetail;
+ }
+
+ ereport(FATAL,
+ (errcode(errcode_return),
+ errmsg(errstr, port->user_name),
+ logdetail ? errdetail_log("%s", logdetail) : 0));
/* doesn't return */
}
ClientAuthentication(Port *port)
{
int status = STATUS_ERROR;
+ char *logdetail = NULL;
/*
* Get the authentication method to use for this frontend/database
(errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
errmsg("MD5 authentication is not supported when \"db_user_namespace\" is enabled")));
sendAuthRequest(port, AUTH_REQ_MD5);
- status = recv_and_check_password_packet(port);
+ status = recv_and_check_password_packet(port, &logdetail);
break;
case uaPassword:
sendAuthRequest(port, AUTH_REQ_PASSWORD);
- status = recv_and_check_password_packet(port);
+ status = recv_and_check_password_packet(port, &logdetail);
break;
case uaPAM:
if (status == STATUS_OK)
sendAuthRequest(port, AUTH_REQ_OK);
else
- auth_failed(port, status);
+ auth_failed(port, status, logdetail);
/* Done with authentication, so we should turn off immediate interrupts */
ImmediateInterruptOK = false;
/*
* Called when we have sent an authorization request for a password.
* Get the response and check it.
+ * On error, optionally store a detail string at *logdetail.
*/
static int
-recv_and_check_password_packet(Port *port)
+recv_and_check_password_packet(Port *port, char **logdetail)
{
char *passwd;
int result;
if (passwd == NULL)
return STATUS_EOF; /* client wouldn't send password */
- result = md5_crypt_verify(port, port->user_name, passwd);
+ result = md5_crypt_verify(port, port->user_name, passwd, logdetail);
pfree(passwd);
#include "utils/timestamp.h"
+/*
+ * Check given password for given user, and return STATUS_OK or STATUS_ERROR.
+ * In the error case, optionally store a palloc'd string at *logdetail
+ * that will be sent to the postmaster log (but not the client).
+ */
int
-md5_crypt_verify(const Port *port, const char *role, char *client_pass)
+md5_crypt_verify(const Port *port, const char *role, char *client_pass,
+ char **logdetail)
{
int retval = STATUS_ERROR;
char *shadow_pass,
if (isnull)
{
ReleaseSysCache(roleTup);
+ *logdetail = psprintf(_("User \"%s\" has no password assigned."),
+ role);
return STATUS_ERROR; /* user has no password */
}
shadow_pass = TextDatumGetCString(datum);
if (isnull)
retval = STATUS_OK;
else if (vuntil < GetCurrentTimestamp())
+ {
+ *logdetail = psprintf(_("User \"%s\" has an expired password."),
+ role);
retval = STATUS_ERROR;
+ }
else
retval = STATUS_OK;
}