summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Paquier <michael@paquier.xyz>2025-11-04 20:12:48 +0900
committerMichael Paquier <michael@paquier.xyz>2025-11-04 20:12:48 +0900
commit861af9261035cec7408040d646cba92959ba6f13 (patch)
treeb1766f2a5c6fdc006ee37745225b97b3d68e70c8
parentad1581d7feaeb1d78a0858703dac1bcb52f600d8 (diff)
libpq: Improve error handling in passwordFromFile()
Previously, passwordFromFile() returned NULL for valid cases (like no matching password found) and actual errors (two out-of-memory paths). This made it impossible for its sole caller, pqConnectOptions2(), to distinguish between these scenarios and fail the connection appropriately should an out-of-memory error occur. This patch extends passwordFromFile() to be able to detect both valid and failure cases, with an error string given back to the caller of the function. Out-of-memory failures unlikely happen in the field, so no backpatch is done. Author: Joshua Shanks <jjshanks@gmail.com> Discussion: https://postgr.es/m/CAOxqWDfihFRmhNVdfu8epYTXQRxkCHSOrg+=-ij2c_X3gW=o3g@mail.gmail.com
-rw-r--r--src/interfaces/libpq/fe-connect.c35
1 files changed, 28 insertions, 7 deletions
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index a3d12931fff..19bbc006669 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -501,8 +501,9 @@ static int parseServiceFile(const char *serviceFile,
PQExpBuffer errorMessage,
bool *group_found);
static char *pwdfMatchesString(char *buf, const char *token);
-static char *passwordFromFile(const char *hostname, const char *port, const char *dbname,
- const char *username, const char *pgpassfile);
+static char *passwordFromFile(const char *hostname, const char *port,
+ const char *dbname, const char *username,
+ const char *pgpassfile, const char **errmsg);
static void pgpassfileWarning(PGconn *conn);
static void default_threadlock(int acquire);
static bool sslVerifyProtocolVersion(const char *version);
@@ -1454,6 +1455,7 @@ pqConnectOptions2(PGconn *conn)
* least one of them is guaranteed nonempty by now).
*/
const char *pwhost = conn->connhost[i].host;
+ const char *password_errmsg = NULL;
if (pwhost == NULL || pwhost[0] == '\0')
pwhost = conn->connhost[i].hostaddr;
@@ -1463,7 +1465,15 @@ pqConnectOptions2(PGconn *conn)
conn->connhost[i].port,
conn->dbName,
conn->pguser,
- conn->pgpassfile);
+ conn->pgpassfile,
+ &password_errmsg);
+
+ if (password_errmsg != NULL)
+ {
+ conn->status = CONNECTION_BAD;
+ libpq_append_conn_error(conn, "%s", password_errmsg);
+ return false;
+ }
}
}
}
@@ -7942,10 +7952,16 @@ pwdfMatchesString(char *buf, const char *token)
return NULL;
}
-/* Get a password from the password file. Return value is malloc'd. */
+/*
+ * Get a password from the password file. Return value is malloc'd.
+ *
+ * On failure, *errmsg is set to an error to be returned. It is
+ * left NULL on success, or if no password could be found.
+ */
static char *
-passwordFromFile(const char *hostname, const char *port, const char *dbname,
- const char *username, const char *pgpassfile)
+passwordFromFile(const char *hostname, const char *port,
+ const char *dbname, const char *username,
+ const char *pgpassfile, const char **errmsg)
{
FILE *fp;
#ifndef WIN32
@@ -7953,6 +7969,8 @@ passwordFromFile(const char *hostname, const char *port, const char *dbname,
#endif
PQExpBufferData buf;
+ *errmsg = NULL;
+
if (dbname == NULL || dbname[0] == '\0')
return NULL;
@@ -8019,7 +8037,10 @@ passwordFromFile(const char *hostname, const char *port, const char *dbname,
{
/* Make sure there's a reasonable amount of room in the buffer */
if (!enlargePQExpBuffer(&buf, 128))
+ {
+ *errmsg = libpq_gettext("out of memory");
break;
+ }
/* Read some data, appending it to what we already have */
if (fgets(buf.data + buf.len, buf.maxlen - buf.len, fp) == NULL)
@@ -8058,7 +8079,7 @@ passwordFromFile(const char *hostname, const char *port, const char *dbname,
if (!ret)
{
- /* Out of memory. XXX: an error message would be nice. */
+ *errmsg = libpq_gettext("out of memory");
return NULL;
}