diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c index 70b0b93..5e4932b 100644 --- a/src/backend/libpq/auth.c +++ b/src/backend/libpq/auth.c @@ -40,7 +40,7 @@ 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); - +static char *sanitizeLine(char *rawLine, char *secret); /*---------------------------------------------------------------- * Ident authentication @@ -196,6 +196,11 @@ static int CheckRADIUSAuth(Port *port); ClientAuthentication_hook_type ClientAuthentication_hook = NULL; /* + * String used to replace a secret within a log message. + */ +#define SANITIZED_PASSWD "[sanitized]" + +/* * Tell the user the authentication failed, but not (much about) why. * * There is a tradeoff here between security concerns and making life @@ -206,13 +211,15 @@ ClientAuthentication_hook_type ClientAuthentication_hook = NULL; * 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. + * particular, if logdetail isn't NULL, we send that string to the log after + * sanitizing it for passwords from the hba file. */ static void auth_failed(Port *port, int status, char *logdetail) { const char *errstr; char *cdetail; + char *sdetail = NULL; int errcode_return = ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION; /* @@ -260,20 +267,29 @@ auth_failed(Port *port, int status, char *logdetail) break; case uaLDAP: errstr = gettext_noop("LDAP authentication failed for user \"%s\""); + /* sanitize the ldapbind password from rawline for cdetail*/ + sdetail = sanitizeLine(port->hba->rawline, port->hba->ldapbindpasswd); break; case uaCert: errstr = gettext_noop("certificate authentication failed for user \"%s\""); break; case uaRADIUS: errstr = gettext_noop("RADIUS authentication failed for user \"%s\""); + /* sanitize the radius shared secret from the rawline for cdetail*/ + sdetail = sanitizeLine(port->hba->rawline, port->hba->radiussecret); break; default: errstr = gettext_noop("authentication failed for user \"%s\": invalid authentication method"); break; } + if (!sdetail) { + /* auth_method does not require hba line sanitization, include whole line */ + sdetail = port->hba->rawline; + } + cdetail = psprintf(_("Connection matched pg_hba.conf line %d: \"%s\""), - port->hba->linenumber, port->hba->rawline); + port->hba->linenumber, sdetail); if (logdetail) logdetail = psprintf("%s\n%s", logdetail, cdetail); else @@ -287,6 +303,29 @@ auth_failed(Port *port, int status, char *logdetail) /* doesn't return */ } +/* + * Simple search/replace function specifically written to stanitize + * hba lines for logging. To keep things simple this method uses an + * internal buffer which, while of adequate size for an hba line, is + * subject to buffer overflows if used inappropriatly; which is why this + * method isn't named as a generic string replacement method. + */ +static char +*sanitizeLine(char *rawLine, char *secret) +{ + static char buffer[4096]; + char *p; + + if(!(p = strstr(rawLine, secret))) + return rawLine; + + strncpy(buffer, rawLine, p-rawLine); + buffer[p-rawLine] = '\0'; + + sprintf(buffer+(p-rawLine), "%s%s", SANITIZED_PASSWD, p+strlen(secret)); + + return buffer; +} /* * Client authentication starts here. If there is an error, this