OSDN Git Service

Add libpq warning message if the .pgpass-retrieved password fails.
authorBruce Momjian <bruce@momjian.us>
Sat, 13 Mar 2010 14:55:57 +0000 (14:55 +0000)
committerBruce Momjian <bruce@momjian.us>
Sat, 13 Mar 2010 14:55:57 +0000 (14:55 +0000)
Add ERRCODE_INVALID_PASSWORD sqlstate error code.

doc/src/sgml/errcodes.sgml
src/backend/libpq/auth.c
src/include/utils/errcodes.h
src/interfaces/libpq/fe-connect.c
src/interfaces/libpq/libpq-int.h
src/pl/plpgsql/src/plerrcodes.h

index 5819004..b5962f9 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/errcodes.sgml,v 1.28 2009/12/07 05:22:21 tgl Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/errcodes.sgml,v 1.29 2010/03/13 14:55:57 momjian Exp $ -->
 
 <appendix id="errcodes-appendix">
  <title><productname>PostgreSQL</productname> Error Codes</title>
 <entry>invalid_authorization_specification</entry>
 </row>
 
+<row>
+<entry><literal>28P01</literal></entry>
+<entry>INVALID PASSWORD</entry>
+<entry>invalid_password</entry>
+</row>
+
 
 <row>
 <entry spanname="span13"><emphasis role="bold">Class 2B &mdash; Dependent Privilege Descriptors Still Exist</></entry>
index 70b0f66..8838113 100644 (file)
@@ -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 */
 }
index 6eee981..f7be261 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
 
 /* 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')
index 1dc52ef..3e9af73 100644 (file)
@@ -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
  *
index 56ee13d..6fe96ab 100644 (file)
@@ -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? */
 
index 34ba070..99008be 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
 },
 
 {
+       "invalid_password", ERRCODE_INVALID_PASSWORD
+},
+
+{
        "dependent_privilege_descriptors_still_exist", ERRCODE_DEPENDENT_PRIVILEGE_DESCRIPTORS_STILL_EXIST
 },