aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2010-03-06 00:46:07 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2010-03-06 00:46:07 +0000
commitb00c0a60011fa76540435b8272b4d746edb11116 (patch)
tree7d45b7b66f0632b588c5e6d754dcb79cb2fa8d21
parent48fcbb803bb7fefd04a750130adf4dabf1a274e0 (diff)
downloadpostgresql-b00c0a60011fa76540435b8272b4d746edb11116.tar.gz
postgresql-b00c0a60011fa76540435b8272b4d746edb11116.zip
When reading pg_hba.conf and similar files, do not treat @file as an inclusion
unless (1) the @ isn't quoted and (2) the filename isn't empty. This guards against unexpectedly treating usernames or other strings in "flat files" as inclusion requests, as seen in a recent trouble report from Ed L. The empty-filename case would be guaranteed to misbehave anyway, because our subsequent path-munging behavior results in trying to read the directory containing the current input file. I think this might finally explain the report at http://archives.postgresql.org/pgsql-bugs/2004-05/msg00132.php of a crash after printing "authentication file token too long, skipping", since I was able to duplicate that message (though not a crash) on a platform where stdio doesn't refuse to read directories. We never got far in investigating that problem, but now I'm suspicious that the trigger condition was an @ in the flat password file. Back-patch to all active branches since the problem can be demonstrated in all branches except HEAD. The test case, creating a user named "@", doesn't cause a problem in HEAD since we got rid of the flat password file. Nonetheless it seems like a good idea to not consider quoted @ as a file inclusion spec, so I changed HEAD too.
-rw-r--r--src/backend/libpq/hba.c29
1 files changed, 20 insertions, 9 deletions
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 20470454c66..7f1cdd84c34 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.157.2.1 2010/03/03 20:31:29 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.157.2.2 2010/03/06 00:46:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -101,6 +101,10 @@ pg_isblank(const char c)
* double quotes (and usually are, in current usage).
*
* The token, if any, is returned at *buf (a buffer of size bufsz).
+ * Also, we set *initial_quote to indicate whether there was quoting before
+ * the first character. (We use that to prevent "@x" from being treated
+ * as a file inclusion request. Note that @"x" should be so treated;
+ * we want to allow that to support embedded spaces in file paths.)
*
* If successful: store null-terminated token at *buf and return TRUE.
* If no more tokens on line: set *buf = '\0' and return FALSE.
@@ -113,7 +117,7 @@ pg_isblank(const char c)
* database names specially, by appending a newline to them.
*/
static bool
-next_token(FILE *fp, char *buf, int bufsz)
+next_token(FILE *fp, char *buf, int bufsz, bool *initial_quote)
{
int c;
char *start_buf = buf;
@@ -122,8 +126,11 @@ next_token(FILE *fp, char *buf, int bufsz)
bool was_quote = false;
bool saw_quote = false;
+ /* end_buf reserves two bytes to ensure we can append \n and \0 */
Assert(end_buf > start_buf);
+ *initial_quote = false;
+
/* Move over initial whitespace and commas */
while ((c = getc(fp)) != EOF && (pg_isblank(c) || c == ','))
;
@@ -182,6 +189,8 @@ next_token(FILE *fp, char *buf, int bufsz)
{
in_quote = !in_quote;
saw_quote = true;
+ if (buf == start_buf)
+ *initial_quote = true;
}
c = getc(fp);
@@ -224,12 +233,13 @@ next_token_expand(const char *filename, FILE *file)
char *comma_str = pstrdup("");
bool got_something = false;
bool trailing_comma;
+ bool initial_quote;
char *incbuf;
int needed;
do
{
- if (!next_token(file, buf, sizeof(buf)))
+ if (!next_token(file, buf, sizeof(buf), &initial_quote))
break;
got_something = true;
@@ -243,7 +253,7 @@ next_token_expand(const char *filename, FILE *file)
trailing_comma = false;
/* Is this referencing a file? */
- if (buf[0] == '@')
+ if (!initial_quote && buf[0] == '@' && buf[1] != '\0')
incbuf = tokenize_inc_file(filename, buf + 1);
else
incbuf = pstrdup(buf);
@@ -1014,28 +1024,29 @@ read_pg_database_line(FILE *fp, char *dbname, Oid *dboid,
Oid *dbtablespace, TransactionId *dbfrozenxid)
{
char buf[MAX_TOKEN];
+ bool initial_quote;
if (feof(fp))
return false;
- if (!next_token(fp, buf, sizeof(buf)))
+ if (!next_token(fp, buf, sizeof(buf), &initial_quote))
return false;
if (strlen(buf) >= NAMEDATALEN)
elog(FATAL, "bad data in flat pg_database file");
strcpy(dbname, buf);
- next_token(fp, buf, sizeof(buf));
+ next_token(fp, buf, sizeof(buf), &initial_quote);
if (!isdigit((unsigned char) buf[0]))
elog(FATAL, "bad data in flat pg_database file");
*dboid = atooid(buf);
- next_token(fp, buf, sizeof(buf));
+ next_token(fp, buf, sizeof(buf), &initial_quote);
if (!isdigit((unsigned char) buf[0]))
elog(FATAL, "bad data in flat pg_database file");
*dbtablespace = atooid(buf);
- next_token(fp, buf, sizeof(buf));
+ next_token(fp, buf, sizeof(buf), &initial_quote);
if (!isdigit((unsigned char) buf[0]))
elog(FATAL, "bad data in flat pg_database file");
*dbfrozenxid = atoxid(buf);
/* expect EOL next */
- if (next_token(fp, buf, sizeof(buf)))
+ if (next_token(fp, buf, sizeof(buf), &initial_quote))
elog(FATAL, "bad data in flat pg_database file");
return true;
}