Commit 26139bb4 authored by Tom Lane's avatar Tom Lane

Improve error messages when a connection is rejected.

parent 1d1cf38c
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.34 1999/03/14 16:06:42 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.35 1999/04/16 04:59:03 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -390,13 +390,53 @@ pg_passwordv0_recvauth(void *arg, PacketLen len, void *pkt) ...@@ -390,13 +390,53 @@ pg_passwordv0_recvauth(void *arg, PacketLen len, void *pkt)
/* /*
* Tell the user the authentication failed, but not why. * Tell the user the authentication failed, but not (much about) why.
*
* There is a tradeoff here between security concerns and making life
* unnecessarily difficult for legitimate users. We would not, for example,
* want to report the password we were expecting to receive...
* But it seems useful to report the username and authorization method
* 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.
*/ */
void void
auth_failed(Port *port) auth_failed(Port *port)
{ {
PacketSendError(&port->pktInfo, "User authentication failed"); char buffer[512];
const char *authmethod = "Unknown auth method:";
switch (port->auth_method)
{
case uaReject:
authmethod = "Rejected host:";
break;
case uaKrb4:
authmethod = "Kerberos4";
break;
case uaKrb5:
authmethod = "Kerberos5";
break;
case uaTrust:
authmethod = "Trusted";
break;
case uaIdent:
authmethod = "IDENT";
break;
case uaPassword:
authmethod = "Password";
break;
case uaCrypt:
authmethod = "Password";
break;
}
sprintf(buffer, "%s authentication failed for user '%s'",
authmethod, port->user);
PacketSendError(&port->pktInfo, buffer);
} }
...@@ -409,12 +449,15 @@ be_recvauth(Port *port) ...@@ -409,12 +449,15 @@ be_recvauth(Port *port)
/* /*
* Get the authentication method to use for this frontend/database * Get the authentication method to use for this frontend/database
* combination. * combination. Note: a failure return indicates a problem with
* the hba config file, not with the request. hba.c should have
* dropped an error message into the postmaster logfile if it failed.
*/ */
if (hba_getauthmethod(&port->raddr, port->user, port->database, if (hba_getauthmethod(&port->raddr, port->user, port->database,
port->auth_arg, &port->auth_method) != STATUS_OK) port->auth_arg, &port->auth_method) != STATUS_OK)
PacketSendError(&port->pktInfo, "Missing or mis-configured pg_hba.conf file"); PacketSendError(&port->pktInfo,
"Missing or erroneous pg_hba.conf file, see postmaster log for details");
else if (PG_PROTOCOL_MAJOR(port->proto) == 0) else if (PG_PROTOCOL_MAJOR(port->proto) == 0)
{ {
...@@ -425,20 +468,39 @@ be_recvauth(Port *port) ...@@ -425,20 +468,39 @@ be_recvauth(Port *port)
} }
else else
{ {
AuthRequest areq;
PacketDoneProc auth_handler;
/* Keep the compiler quiet. */
areq = AUTH_REQ_OK;
/* Handle new style authentication. */ /* Handle new style authentication. */
auth_handler = NULL; AuthRequest areq = AUTH_REQ_OK;
PacketDoneProc auth_handler = NULL;
switch (port->auth_method) switch (port->auth_method)
{ {
case uaReject: case uaReject:
/*
* This could have come from an explicit "reject" entry
* in pg_hba.conf, but more likely it means there was no
* matching entry. Take pity on the poor user and issue
* a helpful error message. NOTE: this is not a security
* breach, because all the info reported here is known
* at the frontend and must be assumed known to bad guys.
* We're merely helping out the less clueful good guys.
* NOTE 2: libpq-be.h defines the maximum error message
* length as 99 characters. It probably wouldn't hurt
* anything to increase it, but there might be some
* client out there that will fail. So, be terse.
*/
{
char buffer[512];
const char *hostinfo = "localhost";
if (port->raddr.sa.sa_family == AF_INET)
hostinfo = inet_ntoa(port->raddr.in.sin_addr);
sprintf(buffer,
"No pg_hba.conf entry for host %s, user %s, database %s",
hostinfo, port->user, port->database);
PacketSendError(&port->pktInfo, buffer);
return;
}
break; break;
case uaKrb4: case uaKrb4:
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* wherein you authenticate a user by seeing what IP address the system * wherein you authenticate a user by seeing what IP address the system
* says he comes from and possibly using ident). * says he comes from and possibly using ident).
* *
* $Id: hba.c,v 1.39 1999/02/13 23:15:43 momjian Exp $ * $Id: hba.c,v 1.40 1999/04/16 04:59:03 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -298,55 +298,42 @@ syntax: ...@@ -298,55 +298,42 @@ syntax:
static void static void
process_open_config_file(FILE *file, SockAddr *raddr, const char *user, process_open_config_file(FILE *file, SockAddr *raddr, const char *user,
const char *database, bool *host_ok_p, const char *database, bool *hba_ok_p,
UserAuth *userauth_p, char *auth_arg) UserAuth *userauth_p, char *auth_arg)
{ {
/*--------------------------------------------------------------------------- /*---------------------------------------------------------------------------
This function does the same thing as find_hba_entry, only with This function does the same thing as find_hba_entry, only with
the config file already open on stream descriptor "file". the config file already open on stream descriptor "file".
----------------------------------------------------------------------------*/ ----------------------------------------------------------------------------*/
bool found_entry; bool found_entry = false; /* found an applicable entry? */
bool error = false; /* found an erroneous entry? */
bool eof = false; /* end of hba file */
/* We've processed a record that applies to our connection */
bool error;
/* Said record has invalid syntax. */
bool eof; /* We've reached the end of the file we're
* reading */
found_entry = false; /* initial value */
error = false; /* initial value */
eof = false; /* initial value */
while (!eof && !found_entry && !error) while (!eof && !found_entry && !error)
{ {
/* Process a line from the config file */ /* Process a line from the config file */
int c = getc(file);
int c; /* a character read from the file */
c = getc(file);
ungetc(c, file);
if (c == EOF) if (c == EOF)
eof = true; eof = true;
else else
{ {
ungetc(c, file);
if (c == '#') if (c == '#')
read_through_eol(file); read_through_eol(file);
else else
{
process_hba_record(file, raddr, user, database, process_hba_record(file, raddr, user, database,
&found_entry, &error, userauth_p, auth_arg); &found_entry, &error, userauth_p, auth_arg);
}
} }
} }
if (!error) if (!error)
{ {
/* If no entry was found then force a rejection. */ /* If no matching entry was found, synthesize 'reject' entry. */
if (!found_entry) if (!found_entry)
*userauth_p = uaReject; *userauth_p = uaReject;
*host_ok_p = true; *hba_ok_p = true;
} }
} }
...@@ -354,25 +341,23 @@ process_open_config_file(FILE *file, SockAddr *raddr, const char *user, ...@@ -354,25 +341,23 @@ process_open_config_file(FILE *file, SockAddr *raddr, const char *user,
static void static void
find_hba_entry(SockAddr *raddr, const char *user, const char *database, find_hba_entry(SockAddr *raddr, const char *user, const char *database,
bool *host_ok_p, UserAuth *userauth_p, char *auth_arg) bool *hba_ok_p, UserAuth *userauth_p, char *auth_arg)
{ {
/* /*
* Read the config file and find an entry that allows connection from * Read the config file and find an entry that allows connection from
* host "*raddr" to database "database". If found, return *host_ok_p == true * host "raddr", user "user", to database "database". If found,
* and *userauth_p and *auth_arg representing the contents of that entry. * return *hba_ok_p = true and *userauth_p and *auth_arg representing
* * the contents of that entry. If there is no matching entry, we
* When a record has invalid syntax, we either ignore it or reject the * set *hba_ok_p = true, *userauth_p = uaReject.
* connection (depending on where it's invalid). No message or anything.
* We need to fix that some day.
* *
* If we don't find or can't access the config file, we issue an error * If the config file is unreadable or contains invalid syntax, we
* message and deny the connection. * issue a diagnostic message to stderr (ie, the postmaster log file)
* and return without changing *hba_ok_p.
* *
* If we find a file by the old name of the config file (pg_hba), we issue * If we find a file by the old name of the config file (pg_hba), we issue
* an error message because it probably needs to be converted. He didn't * an error message because it probably needs to be converted. He didn't
* follow directions and just installed his old hba file in the new database * follow directions and just installed his old hba file in the new database
* system. * system.
*
*/ */
int fd, int fd,
...@@ -431,14 +416,13 @@ find_hba_entry(SockAddr *raddr, const char *user, const char *database, ...@@ -431,14 +416,13 @@ find_hba_entry(SockAddr *raddr, const char *user, const char *database,
} }
else else
{ {
process_open_config_file(file, raddr, user, database, host_ok_p, process_open_config_file(file, raddr, user, database, hba_ok_p,
userauth_p, auth_arg); userauth_p, auth_arg);
FreeFile(file); FreeFile(file);
} }
pfree(conf_file); pfree(conf_file);
} }
pfree(old_conf_file); pfree(old_conf_file);
return;
} }
...@@ -1079,20 +1063,21 @@ GetCharSetByHost(char *TableName, int host, const char *DataDir) ...@@ -1079,20 +1063,21 @@ GetCharSetByHost(char *TableName, int host, const char *DataDir)
#endif #endif
extern int int
hba_getauthmethod(SockAddr *raddr, char *user, char *database, hba_getauthmethod(SockAddr *raddr, char *user, char *database,
char *auth_arg, UserAuth *auth_method) char *auth_arg, UserAuth *auth_method)
{ {
/*--------------------------------------------------------------------------- /*---------------------------------------------------------------------------
Determine what authentication method should be used when accessing database Determine what authentication method should be used when accessing database
"database" from frontend "raddr". Return the method, an optional argument, "database" from frontend "raddr", user "user". Return the method,
and STATUS_OK. an optional argument, and STATUS_OK.
Note that STATUS_ERROR indicates a problem with the hba config file.
If the file is OK but does not contain any entry matching the request,
we return STATUS_OK and method = uaReject.
----------------------------------------------------------------------------*/ ----------------------------------------------------------------------------*/
bool host_ok; bool hba_ok = false;
host_ok = false;
find_hba_entry(raddr, user, database, &host_ok, auth_method, auth_arg); find_hba_entry(raddr, user, database, &hba_ok, auth_method, auth_arg);
return host_ok ? STATUS_OK : STATUS_ERROR; return hba_ok ? STATUS_OK : STATUS_ERROR;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment