diff options
Diffstat (limited to 'src/backend/libpq/hba.c')
-rw-r--r-- | src/backend/libpq/hba.c | 111 |
1 files changed, 71 insertions, 40 deletions
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c index 52608eb4537..03a845eae99 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.143 2005/06/28 05:08:56 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.144 2005/06/28 22:16:45 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -96,17 +96,23 @@ pg_isblank(const char c) /* * Grab one token out of fp. Tokens are strings of non-blank - * characters bounded by blank characters, beginning of line, and - * end of line. Blank means space or tab. Return the token as - * *buf. Leave file positioned at the character immediately after the - * token or EOF, whichever comes first. If no more tokens on line, - * return empty string as *buf and position the file to the beginning - * of the next line or EOF, whichever comes first. Allow spaces in - * quoted strings. Terminate on unquoted commas. Handle - * comments. Treat unquoted keywords that might be role names or + * characters bounded by blank characters, commas, beginning of line, and + * end of line. Blank means space or tab. Tokens can be delimited by + * double quotes (and usually are, in current usage). + * + * The token, if any, is returned at *buf (a buffer of size bufsz). + * + * If successful: store null-terminated token at *buf and return TRUE. + * If no more tokens on line: set *buf = '\0' and return FALSE. + * + * Leave file positioned at the character immediately after the token or EOF, + * whichever comes first. If no more tokens on line, position the file to the + * beginning of the next line or EOF, whichever comes first. + * + * Handle comments. Treat unquoted keywords that might be role names or * database names specially, by appending a newline to them. */ -static void +static bool next_token(FILE *fp, char *buf, int bufsz) { int c; @@ -125,7 +131,7 @@ next_token(FILE *fp, char *buf, int bufsz) if (c == EOF || c == '\n') { *buf = '\0'; - return; + return false; } /* @@ -200,6 +206,8 @@ next_token(FILE *fp, char *buf, int bufsz) *buf++ = '\n'; *buf = '\0'; } + + return (saw_quote || buf > start_buf); } /* @@ -207,25 +215,26 @@ next_token(FILE *fp, char *buf, int bufsz) * to break apart the commas to expand any file names then * reconstruct with commas. * - * The result is always a palloc'd string. If it's zero-length then - * we have reached EOL. + * The result is a palloc'd string, or NULL if we have reached EOL. */ static char * next_token_expand(const char *filename, FILE *file) { char buf[MAX_TOKEN]; char *comma_str = pstrdup(""); + bool got_something = false; bool trailing_comma; char *incbuf; int needed; do { - next_token(file, buf, sizeof(buf)); - if (!buf[0]) + if (!next_token(file, buf, sizeof(buf))) break; - if (buf[strlen(buf) - 1] == ',') + got_something = true; + + if (strlen(buf) > 0 && buf[strlen(buf) - 1] == ',') { trailing_comma = true; buf[strlen(buf) - 1] = '\0'; @@ -249,6 +258,12 @@ next_token_expand(const char *filename, FILE *file) pfree(incbuf); } while (trailing_comma); + if (!got_something) + { + pfree(comma_str); + return NULL; + } + return comma_str; } @@ -402,7 +417,7 @@ tokenize_file(const char *filename, FILE *file, buf = next_token_expand(filename, file); /* add token to list, unless we are at EOL or comment start */ - if (buf[0]) + if (buf) { if (current_line == NIL) { @@ -423,8 +438,6 @@ tokenize_file(const char *filename, FILE *file, current_line = NIL; /* Advance line number whenever we reach EOL */ line_number++; - /* Don't forget to pfree the next_token_expand result */ - pfree(buf); } } } @@ -462,25 +475,33 @@ get_role_line(const char *role) /* - * Does member belong to role? + * Does user belong to role? + * + * user is always the name given as the attempted login identifier. + * We check to see if it is a member of the specified role name. */ static bool -check_member(const char *role, const char *member) +is_member(const char *user, const char *role) { List **line; - List **line2; ListCell *line_item; - if ((line = get_role_line(member)) == NULL) - return false; /* if member not exist, say "no" */ + if ((line = get_role_line(user)) == NULL) + return false; /* if user not exist, say "no" */ - if ((line2 = get_role_line(role)) == NULL) - return false; /* if role not exist, say "no" */ + /* A user always belongs to its own role */ + if (strcmp(user, role) == 0) + return true; - /* skip over the role name, password, valuntil, examine all the members */ - for_each_cell(line_item, lfourth(*line2)) + /* + * skip over the role name, password, valuntil, examine all the + * membership entries + */ + if (list_length(*line) < 4) + return false; + for_each_cell(line_item, lnext(lnext(lnext(list_head(*line))))) { - if (strcmp((char *) lfirst(line_item), member) == 0) + if (strcmp((char *) lfirst(line_item), role) == 0) return true; } @@ -488,18 +509,24 @@ check_member(const char *role, const char *member) } /* - * Check comma member list for a specific role, handle role names. + * Check comma-separated list for a match to role, allowing group names. + * + * NB: param_str is destructively modified! In current usage, this is + * okay only because this code is run after forking off from the postmaster, + * and so it doesn't matter that we clobber the stored hba info. */ static bool -check_role(char *role, char *param_str) +check_role(const char *role, char *param_str) { char *tok; - for (tok = strtok(param_str, MULTI_VALUE_SEP); tok != NULL; tok = strtok(NULL, MULTI_VALUE_SEP)) + for (tok = strtok(param_str, MULTI_VALUE_SEP); + tok != NULL; + tok = strtok(NULL, MULTI_VALUE_SEP)) { if (tok[0] == '+') { - if (check_member(tok + 1, role)) + if (is_member(role, tok + 1)) return true; } else if (strcmp(tok, role) == 0 || @@ -512,13 +539,19 @@ check_role(char *role, char *param_str) /* * Check to see if db/role combination matches param string. + * + * NB: param_str is destructively modified! In current usage, this is + * okay only because this code is run after forking off from the postmaster, + * and so it doesn't matter that we clobber the stored hba info. */ static bool -check_db(char *dbname, char *role, char *param_str) +check_db(const char *dbname, const char *role, char *param_str) { char *tok; - for (tok = strtok(param_str, MULTI_VALUE_SEP); tok != NULL; tok = strtok(NULL, MULTI_VALUE_SEP)) + for (tok = strtok(param_str, MULTI_VALUE_SEP); + tok != NULL; + tok = strtok(NULL, MULTI_VALUE_SEP)) { if (strcmp(tok, "all\n") == 0) return true; @@ -530,7 +563,7 @@ check_db(char *dbname, char *role, char *param_str) else if (strcmp(tok, "samegroup\n") == 0 || strcmp(tok, "samerole\n") == 0) { - if (check_member(dbname, role)) + if (is_member(role, dbname)) return true; } else if (strcmp(tok, dbname) == 0) @@ -981,8 +1014,7 @@ read_pg_database_line(FILE *fp, char *dbname, if (feof(fp)) return false; - next_token(fp, buf, sizeof(buf)); - if (!buf[0]) + if (!next_token(fp, buf, sizeof(buf))) return false; if (strlen(buf) >= NAMEDATALEN) elog(FATAL, "bad data in flat pg_database file"); @@ -1000,8 +1032,7 @@ read_pg_database_line(FILE *fp, char *dbname, if (!isdigit((unsigned char) buf[0])) elog(FATAL, "bad data in flat pg_database file"); /* expect EOL next */ - next_token(fp, buf, sizeof(buf)); - if (buf[0]) + if (next_token(fp, buf, sizeof(buf))) elog(FATAL, "bad data in flat pg_database file"); return true; } |