diff --git a/doc/src/sgml/errcodes.sgml b/doc/src/sgml/errcodes.sgml index 5819004f48..b5962f98cd 100644 --- a/doc/src/sgml/errcodes.sgml +++ b/doc/src/sgml/errcodes.sgml @@ -1,4 +1,4 @@ - + <productname>PostgreSQL</productname> Error Codes @@ -761,6 +761,12 @@ invalid_authorization_specification + +28P01 +INVALID PASSWORD +invalid_password + + Class 2B — Dependent Privilege Descriptors Still Exist diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c index 70b0f66566..8838113c57 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 6eee981bbd..f7be2611f8 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 1dc52ef148..3e9af73cb0 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 56ee13dbf6..6fe96ab168 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 34ba070d1f..99008be9bf 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 $ * *------------------------------------------------------------------------- */ @@ -367,6 +367,10 @@ "invalid_authorization_specification", ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION }, +{ + "invalid_password", ERRCODE_INVALID_PASSWORD +}, + { "dependent_privilege_descriptors_still_exist", ERRCODE_DEPENDENT_PRIVILEGE_DESCRIPTORS_STILL_EXIST },