diff options
author | Tom Lane | 2010-03-06 00:46:13 +0000 |
---|---|---|
committer | Tom Lane | 2010-03-06 00:46:13 +0000 |
commit | 0a32a06bc91894ea86c52dc971703e257d8988ec (patch) | |
tree | 84ab29b1aa54dd886bdcaf716db70bbb01cf976c /src/backend | |
parent | 14669da788122b2d948ca7700bdb99877e4d2dc0 (diff) |
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.
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/libpq/hba.c | 31 |
1 files changed, 21 insertions, 10 deletions
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c index a8f1bd36067..300faece07d 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.149.2.1 2010/03/03 20:31:34 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.149.2.2 2010/03/06 00:46:13 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -102,6 +102,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. @@ -114,7 +118,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; @@ -123,8 +127,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 == ',')) ; @@ -183,6 +190,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); @@ -225,12 +234,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; @@ -244,7 +254,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); @@ -1013,32 +1023,33 @@ read_pg_database_line(FILE *fp, char *dbname, Oid *dboid, TransactionId *dbvacuumxid) { 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); - 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"); *dbvacuumxid = 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; } |