Re: Change authentication error message (patch)
От | Tom Lane |
---|---|
Тема | Re: Change authentication error message (patch) |
Дата | |
Msg-id | 28363.1390585775@sss.pgh.pa.us обсуждение исходный текст |
Ответ на | Re: Change authentication error message (patch) (Tom Lane <tgl@sss.pgh.pa.us>) |
Список | pgsql-hackers |
I wrote: > I agree with doing *something*, but this particular thing seems to violate > our very long-standing policy on how to deal with authentication failures, > as well as being too vague to be really useful. > What would be well within that policy is to log additional information > into the postmaster log. I see that md5_crypt_verify knows perfectly > well whether the problem is no password set, wrong password, or expired > password. I don't see anything wrong with having it emit a log entry > --- maybe not in the second case for fear of log-spam complaints, but > certainly the third case and maybe the first one. Or possibly cleaner, > have it return additional status so that auth_failed() can include the > info in the main ereport using errdetail_log(). Attached is a proposed patch that does exactly that. This just addresses the cases mentioned above; once the infrastructure is in place, there might be more things that would be worth logging using this mechanism. regards, tom lane diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c index 882dc8f..1974b57 100644 *** a/src/backend/libpq/auth.c --- b/src/backend/libpq/auth.c *************** *** 38,46 **** *---------------------------------------------------------------- */ static void sendAuthRequest(Port *port, AuthRequest areq); ! static void auth_failed(Port *port, int status); static char *recv_password_packet(Port *port); ! static int recv_and_check_password_packet(Port *port); /*---------------------------------------------------------------- --- 38,46 ---- *---------------------------------------------------------------- */ static void sendAuthRequest(Port *port, AuthRequest areq); ! 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, char **logdetail); /*---------------------------------------------------------------- *************** ClientAuthentication_hook_type ClientAut *** 207,216 **** * 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. */ static void ! auth_failed(Port *port, int status) { const char *errstr; int errcode_return = ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION; --- 207,217 ---- * 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. In ! * particular, if logdetail isn't NULL, we send that string to the log. */ static void ! auth_failed(Port *port, int status, char *logdetail) { const char *errstr; int errcode_return = ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION; *************** auth_failed(Port *port, int status) *** 273,286 **** } 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))); /* doesn't return */ } --- 274,294 ---- } if (port->hba) ! { ! 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 */ } *************** void *** 294,299 **** --- 302,308 ---- ClientAuthentication(Port *port) { int status = STATUS_ERROR; + char *logdetail = NULL; /* * Get the authentication method to use for this frontend/database *************** ClientAuthentication(Port *port) *** 507,518 **** (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); break; case uaPassword: sendAuthRequest(port, AUTH_REQ_PASSWORD); ! status = recv_and_check_password_packet(port); break; case uaPAM: --- 516,527 ---- (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, &logdetail); break; case uaPassword: sendAuthRequest(port, AUTH_REQ_PASSWORD); ! status = recv_and_check_password_packet(port, &logdetail); break; case uaPAM: *************** ClientAuthentication(Port *port) *** 552,558 **** if (status == STATUS_OK) sendAuthRequest(port, AUTH_REQ_OK); else ! auth_failed(port, status); /* Done with authentication, so we should turn off immediate interrupts */ ImmediateInterruptOK = false; --- 561,567 ---- if (status == STATUS_OK) sendAuthRequest(port, AUTH_REQ_OK); else ! auth_failed(port, status, logdetail); /* Done with authentication, so we should turn off immediate interrupts */ ImmediateInterruptOK = false; *************** recv_password_packet(Port *port) *** 680,688 **** /* * Called when we have sent an authorization request for a password. * Get the response and check it. */ static int ! recv_and_check_password_packet(Port *port) { char *passwd; int result; --- 689,698 ---- /* * 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, char **logdetail) { char *passwd; int result; *************** recv_and_check_password_packet(Port *por *** 692,698 **** if (passwd == NULL) return STATUS_EOF; /* client wouldn't send password */ ! result = md5_crypt_verify(port, port->user_name, passwd); pfree(passwd); --- 702,708 ---- if (passwd == NULL) return STATUS_EOF; /* client wouldn't send password */ ! result = md5_crypt_verify(port, port->user_name, passwd, logdetail); pfree(passwd); diff --git a/src/backend/libpq/crypt.c b/src/backend/libpq/crypt.c index 56b3ea8..5451db6 100644 *** a/src/backend/libpq/crypt.c --- b/src/backend/libpq/crypt.c *************** *** 29,36 **** #include "utils/timestamp.h" int ! md5_crypt_verify(const Port *port, const char *role, char *client_pass) { int retval = STATUS_ERROR; char *shadow_pass, --- 29,42 ---- #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, ! char **logdetail) { int retval = STATUS_ERROR; char *shadow_pass, *************** md5_crypt_verify(const Port *port, const *** 58,63 **** --- 64,71 ---- if (isnull) { ReleaseSysCache(roleTup); + *logdetail = psprintf(_("User \"%s\" has no password assigned."), + role); return STATUS_ERROR; /* user has no password */ } shadow_pass = TextDatumGetCString(datum); *************** md5_crypt_verify(const Port *port, const *** 148,154 **** --- 156,166 ---- 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; } diff --git a/src/include/libpq/crypt.h b/src/include/libpq/crypt.h index 818e57e..b91024f 100644 *** a/src/include/libpq/crypt.h --- b/src/include/libpq/crypt.h *************** *** 15,21 **** #include "libpq/libpq-be.h" ! extern int md5_crypt_verify(const Port *port, const char *user, ! char *client_pass); #endif --- 15,21 ---- #include "libpq/libpq-be.h" ! extern int md5_crypt_verify(const Port *port, const char *role, ! char *client_pass, char **logdetail); #endif
В списке pgsql-hackers по дате отправления: