Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit ba23174

Browse filesBrowse files
committed
Teach libpq to handle arbitrary-length lines in .pgpass files.
Historically there's been a hard-wired assumption here that no line of a .pgpass file could be as long as NAMEDATALEN*5 bytes. That's a bit shaky to start off with, because (a) there's no reason to suppose that host names fit in NAMEDATALEN, and (b) this figure fails to allow for backslash escape characters. However, it fails completely if someone wants to use a very long password, and we're now hearing reports of people wanting to use "security tokens" that can run up to several hundred bytes. Another angle is that the file is specified to allow comment lines, but there's no reason to assume that long comment lines aren't possible. Rather than guessing at what might be a more suitable limit, let's replace the fixed-size buffer with an expansible PQExpBuffer. That adds one malloc/free cycle to the typical use-case, but that's surely pretty cheap relative to the I/O this code has to do. Also, add TAP test cases to exercise this code, because there was no test coverage before. This reverts most of commit 2eb3bc5, as there's no longer a need for a warning message about overlength .pgpass lines. (I kept the explicit check for comment lines, though.) In HEAD and v13, this also fixes an oversight in 74a308c: there's not much point in explicit_bzero'ing the line buffer if we only do so in two of the three exit paths. Back-patch to all supported branches, except that the test case only goes back to v10 where src/test/authentication/ was added. Discussion: https://postgr.es/m/4187382.1598909041@sss.pgh.pa.us
1 parent 5394b87 commit ba23174
Copy full SHA for ba23174

File tree

Expand file treeCollapse file tree

1 file changed

+58
-42
lines changed
Filter options
Expand file treeCollapse file tree

1 file changed

+58
-42
lines changed

‎src/interfaces/libpq/fe-connect.c

Copy file name to clipboardExpand all lines: src/interfaces/libpq/fe-connect.c
+58-42Lines changed: 58 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -5841,9 +5841,7 @@ PasswordFromFile(char *hostname, char *port, char *dbname, char *username)
58415841
FILE *fp;
58425842
char pgpassfile[MAXPGPATH];
58435843
struct stat stat_buf;
5844-
5845-
#define LINELEN NAMEDATALEN*5
5846-
char buf[LINELEN];
5844+
PQExpBufferData buf;
58475845

58485846
if (dbname == NULL || strlen(dbname) == 0)
58495847
return NULL;
@@ -5902,63 +5900,81 @@ PasswordFromFile(char *hostname, char *port, char *dbname, char *username)
59025900
if (fp == NULL)
59035901
return NULL;
59045902

5903+
/* Use an expansible buffer to accommodate any reasonable line length */
5904+
initPQExpBuffer(&buf);
5905+
59055906
while (!feof(fp) && !ferror(fp))
59065907
{
5907-
char *t = buf,
5908-
*ret,
5909-
*p1,
5910-
*p2;
5911-
int len;
5908+
/* Make sure there's a reasonable amount of room in the buffer */
5909+
if (!enlargePQExpBuffer(&buf, 128))
5910+
break;
59125911

5913-
if (fgets(buf, sizeof(buf), fp) == NULL)
5912+
/* Read some data, appending it to what we already have */
5913+
if (fgets(buf.data + buf.len, buf.maxlen - buf.len, fp) == NULL)
59145914
break;
5915+
buf.len += strlen(buf.data + buf.len);
59155916

5916-
len = strlen(buf);
5917+
/* If we don't yet have a whole line, loop around to read more */
5918+
if (!(buf.len > 0 && buf.data[buf.len - 1] == '\n') && !feof(fp))
5919+
continue;
59175920

5918-
/* Remove trailing newline */
5919-
if (len > 0 && buf[len - 1] == '\n')
5921+
/* ignore comments */
5922+
if (buf.data[0] != '#')
59205923
{
5921-
buf[--len] = '\0';
5922-
/* Handle DOS-style line endings, too, even when not on Windows */
5923-
if (len > 0 && buf[len - 1] == '\r')
5924-
buf[--len] = '\0';
5925-
}
5924+
char *t = buf.data;
5925+
int len = buf.len;
59265926

5927-
if (len == 0)
5928-
continue;
5927+
/* Remove trailing newline */
5928+
if (len > 0 && t[len - 1] == '\n')
5929+
{
5930+
t[--len] = '\0';
5931+
/* Handle DOS-style line endings, too */
5932+
if (len > 0 && t[len - 1] == '\r')
5933+
t[--len] = '\0';
5934+
}
59295935

5930-
if ((t = pwdfMatchesString(t, hostname)) == NULL ||
5931-
(t = pwdfMatchesString(t, port)) == NULL ||
5932-
(t = pwdfMatchesString(t, dbname)) == NULL ||
5933-
(t = pwdfMatchesString(t, username)) == NULL)
5934-
continue;
5936+
if (len > 0 &&
5937+
(t = pwdfMatchesString(t, hostname)) != NULL &&
5938+
(t = pwdfMatchesString(t, port)) != NULL &&
5939+
(t = pwdfMatchesString(t, dbname)) != NULL &&
5940+
(t = pwdfMatchesString(t, username)) != NULL)
5941+
{
5942+
/* Found a match. */
5943+
char *ret,
5944+
*p1,
5945+
*p2;
59355946

5936-
/* Found a match. */
5937-
ret = strdup(t);
5938-
fclose(fp);
5947+
ret = strdup(t);
59395948

5940-
if (!ret)
5941-
{
5942-
/* Out of memory. XXX: an error message would be nice. */
5943-
return NULL;
5944-
}
5949+
fclose(fp);
5950+
termPQExpBuffer(&buf);
59455951

5946-
/* De-escape password. */
5947-
for (p1 = p2 = ret; *p1 != ':' && *p1 != '\0'; ++p1, ++p2)
5948-
{
5949-
if (*p1 == '\\' && p1[1] != '\0')
5950-
++p1;
5951-
*p2 = *p1;
5952+
if (!ret)
5953+
{
5954+
/* Out of memory. XXX: an error message would be nice. */
5955+
return NULL;
5956+
}
5957+
5958+
/* De-escape password. */
5959+
for (p1 = p2 = ret; *p1 != ':' && *p1 != '\0'; ++p1, ++p2)
5960+
{
5961+
if (*p1 == '\\' && p1[1] != '\0')
5962+
++p1;
5963+
*p2 = *p1;
5964+
}
5965+
*p2 = '\0';
5966+
5967+
return ret;
5968+
}
59525969
}
5953-
*p2 = '\0';
59545970

5955-
return ret;
5971+
/* No match, reset buffer to prepare for next line. */
5972+
buf.len = 0;
59565973
}
59575974

59585975
fclose(fp);
5976+
termPQExpBuffer(&buf);
59595977
return NULL;
5960-
5961-
#undef LINELEN
59625978
}
59635979

59645980

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.