aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBruce Momjian <bruce@momjian.us>2010-03-13 14:55:57 +0000
committerBruce Momjian <bruce@momjian.us>2010-03-13 14:55:57 +0000
commita6c1cea2b7ac446558ce0cde14b19e74220eeb7f (patch)
tree9e6e87e2897d671579d045517589df533f475fdc /src
parent8b2ae44dc8dd56511c7004c5b117b720081dc8fb (diff)
downloadpostgresql-a6c1cea2b7ac446558ce0cde14b19e74220eeb7f.tar.gz
postgresql-a6c1cea2b7ac446558ce0cde14b19e74220eeb7f.zip
Add libpq warning message if the .pgpass-retrieved password fails.
Add ERRCODE_INVALID_PASSWORD sqlstate error code.
Diffstat (limited to 'src')
-rw-r--r--src/backend/libpq/auth.c9
-rw-r--r--src/include/utils/errcodes.h3
-rw-r--r--src/interfaces/libpq/fe-connect.c71
-rw-r--r--src/interfaces/libpq/libpq-int.h3
-rw-r--r--src/pl/plpgsql/src/plerrcodes.h6
5 files changed, 73 insertions, 19 deletions
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index 70b0f665665..8838113c575 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/libpq/auth.c,v 1.195 2010/02/26 02:00:42 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/libpq/auth.c,v 1.196 2010/03/13 14:55:57 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -232,7 +232,8 @@ static void
auth_failed(Port *port, int status)
{
const char *errstr;
-
+ int errcode_return = ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION;
+
/*
* If we failed due to EOF from client, just quit; there's no point in
* trying to send a message to the client, and not much point in logging
@@ -269,6 +270,8 @@ auth_failed(Port *port, int status)
case uaMD5:
case uaPassword:
errstr = gettext_noop("password authentication failed for user \"%s\"");
+ /* We use it to indicate if a .pgpass password failed. */
+ errcode_return = ERRCODE_INVALID_PASSWORD;
break;
case uaPAM:
errstr = gettext_noop("PAM authentication failed for user \"%s\"");
@@ -285,7 +288,7 @@ auth_failed(Port *port, int status)
}
ereport(FATAL,
- (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
+ (errcode(errcode_return),
errmsg(errstr, port->user_name)));
/* doesn't return */
}
diff --git a/src/include/utils/errcodes.h b/src/include/utils/errcodes.h
index 6eee981bbdd..f7be2611f86 100644
--- a/src/include/utils/errcodes.h
+++ b/src/include/utils/errcodes.h
@@ -11,7 +11,7 @@
*
* Copyright (c) 2003-2010, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/include/utils/errcodes.h,v 1.31 2010/01/02 16:58:10 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/utils/errcodes.h,v 1.32 2010/03/13 14:55:57 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -194,6 +194,7 @@
/* Class 28 - Invalid Authorization Specification */
#define ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION MAKE_SQLSTATE('2','8', '0','0','0')
+#define ERRCODE_INVALID_PASSWORD MAKE_SQLSTATE('2','8', 'P','0','1')
/* Class 2B - Dependent Privilege Descriptors Still Exist */
#define ERRCODE_DEPENDENT_PRIVILEGE_DESCRIPTORS_STILL_EXIST MAKE_SQLSTATE('2','B', '0','0','0')
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 1dc52ef1485..3e9af73cb0a 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.389 2010/03/03 20:31:09 tgl Exp $
+ * $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.390 2010/03/13 14:55:57 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -91,6 +91,9 @@ static int ldapServiceLookup(const char *purl, PQconninfoOption *options,
*/
#define ERRCODE_APPNAME_UNKNOWN "42704"
+/* This is part of the protocol so just define it */
+#define ERRCODE_INVALID_PASSWORD "28P01"
+
/*
* fall back options if they are not specified by arguments or defined
* by environment variables
@@ -284,6 +287,8 @@ static int parseServiceFile(const char *serviceFile,
static char *pwdfMatchesString(char *buf, char *token);
static char *PasswordFromFile(char *hostname, char *port, char *dbname,
char *username);
+static bool getPgPassFilename(char *pgpassfile);
+static void dot_pg_pass_warning(PGconn *conn);
static void default_threadlock(int acquire);
@@ -652,6 +657,8 @@ connectOptions2(PGconn *conn)
conn->dbName, conn->pguser);
if (conn->pgpass == NULL)
conn->pgpass = strdup(DefaultPassword);
+ else
+ conn->dot_pgpass_used = true;
}
/*
@@ -2133,6 +2140,8 @@ keep_going: /* We will come back to here until there is
error_return:
+ dot_pg_pass_warning(conn);
+
/*
* We used to close the socket at this point, but that makes it awkward
* for those above us if they wish to remove this socket from their own
@@ -2191,6 +2200,7 @@ makeEmptyPGconn(void)
conn->verbosity = PQERRORS_DEFAULT;
conn->sock = -1;
conn->password_needed = false;
+ conn->dot_pgpass_used = false;
#ifdef USE_SSL
conn->allow_ssl_try = true;
conn->wait_ssl_try = false;
@@ -4323,7 +4333,6 @@ PasswordFromFile(char *hostname, char *port, char *dbname, char *username)
FILE *fp;
char pgpassfile[MAXPGPATH];
struct stat stat_buf;
- char *passfile_env;
#define LINELEN NAMEDATALEN*5
char buf[LINELEN];
@@ -4349,17 +4358,8 @@ PasswordFromFile(char *hostname, char *port, char *dbname, char *username)
if (port == NULL)
port = DEF_PGPORT_STR;
- if ((passfile_env = getenv("PGPASSFILE")) != NULL)
- /* use the literal path from the environment, if set */
- strlcpy(pgpassfile, passfile_env, sizeof(pgpassfile));
- else
- {
- char homedir[MAXPGPATH];
-
- if (!pqGetHomeDirectory(homedir, sizeof(homedir)))
- return NULL;
- snprintf(pgpassfile, MAXPGPATH, "%s/%s", homedir, PGPASSFILE);
- }
+ if (!getPgPassFilename(pgpassfile))
+ return NULL;
/* If password file cannot be opened, ignore it. */
if (stat(pgpassfile, &stat_buf) != 0)
@@ -4426,6 +4426,51 @@ PasswordFromFile(char *hostname, char *port, char *dbname, char *username)
#undef LINELEN
}
+
+static bool getPgPassFilename(char *pgpassfile)
+{
+ char *passfile_env;
+
+ if ((passfile_env = getenv("PGPASSFILE")) != NULL)
+ /* use the literal path from the environment, if set */
+ strlcpy(pgpassfile, passfile_env, MAXPGPATH);
+ else
+ {
+ char homedir[MAXPGPATH];
+
+ if (!pqGetHomeDirectory(homedir, sizeof(homedir)))
+ return false;
+ snprintf(pgpassfile, MAXPGPATH, "%s/%s", homedir, PGPASSFILE);
+ }
+ return true;
+}
+
+/*
+ * If the connection failed, we should mention if
+ * we got the password from .pgpass in case that
+ * password is wrong.
+ */
+static void
+dot_pg_pass_warning(PGconn *conn)
+{
+ /* If it was 'invalid authorization', add .pgpass mention */
+ if (conn->dot_pgpass_used && conn->password_needed && conn->result &&
+ /* only works with >= 9.0 servers */
+ strcmp(PQresultErrorField(conn->result, PG_DIAG_SQLSTATE),
+ ERRCODE_INVALID_PASSWORD) == 0)
+ {
+ char pgpassfile[MAXPGPATH];
+
+ if (!getPgPassFilename(pgpassfile))
+ return;
+ appendPQExpBufferStr(&conn->errorMessage,
+ libpq_gettext("password retrieved from "));
+ appendPQExpBufferStr(&conn->errorMessage, pgpassfile);
+ appendPQExpBufferChar(&conn->errorMessage, '\n');
+ }
+}
+
+
/*
* Obtain user's home directory, return in given buffer
*
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 56ee13dbf6d..6fe96ab1684 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -12,7 +12,7 @@
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.149 2010/02/26 02:01:33 momjian Exp $
+ * $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.150 2010/03/13 14:55:57 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -343,6 +343,7 @@ struct pg_conn
ProtocolVersion pversion; /* FE/BE protocol version in use */
int sversion; /* server version, e.g. 70401 for 7.4.1 */
bool password_needed; /* true if server demanded a password */
+ bool dot_pgpass_used; /* true if used .pgpass */
bool sigpipe_so; /* have we masked SIGPIPE via SO_NOSIGPIPE? */
bool sigpipe_flag; /* can we mask SIGPIPE via MSG_NOSIGNAL? */
diff --git a/src/pl/plpgsql/src/plerrcodes.h b/src/pl/plpgsql/src/plerrcodes.h
index 34ba070d1f4..99008be9bf2 100644
--- a/src/pl/plpgsql/src/plerrcodes.h
+++ b/src/pl/plpgsql/src/plerrcodes.h
@@ -9,7 +9,7 @@
*
* Copyright (c) 2003-2010, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/plerrcodes.h,v 1.20 2010/01/02 16:58:13 momjian Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/plerrcodes.h,v 1.21 2010/03/13 14:55:57 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -368,6 +368,10 @@
},
{
+ "invalid_password", ERRCODE_INVALID_PASSWORD
+},
+
+{
"dependent_privilege_descriptors_still_exist", ERRCODE_DEPENDENT_PRIVILEGE_DESCRIPTORS_STILL_EXIST
},