diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c index 4c18c13861..3a041d9d58 100644 --- a/src/backend/libpq/auth.c +++ b/src/backend/libpq/auth.c @@ -297,9 +297,16 @@ auth_failed(Port *port, int status) break; } - ereport(FATAL, - (errcode(errcode_return), - errmsg(errstr, port->user_name))); + if (port->hba) + ereport(FATAL, + (errcode(errcode_return), + errmsg(errstr, port->user_name), + errdetail_log("Connection matched pg_hba.conf line %d: \"%s\"", port->hba->linenumber, port->hba->rawline))); + else + ereport(FATAL, + (errcode(errcode_return), + errmsg(errstr, port->user_name))); + /* doesn't return */ } diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c index 7df8eb52cc..e138bb9173 100644 --- a/src/backend/libpq/hba.c +++ b/src/backend/libpq/hba.c @@ -50,6 +50,7 @@ #define atoxid(x) ((TransactionId) strtoul((x), NULL, 10)) #define MAX_TOKEN 256 +#define MAX_LINE 8192 /* callback data for check_network_callback */ typedef struct check_network_data @@ -93,7 +94,7 @@ static MemoryContext parsed_ident_context = NULL; static MemoryContext tokenize_file(const char *filename, FILE *file, - List **lines, List **line_nums); + List **lines, List **line_nums, List **raw_lines); static List *tokenize_inc_file(List *tokens, const char *outer_filename, const char *inc_filename); static bool parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline, @@ -111,7 +112,8 @@ pg_isblank(const char c) /* - * Grab one token out of fp. Tokens are strings of non-blank + * Grab one token out of the string pointed to by lineptr. + * Tokens are strings of non-blank * 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 (this allows the inclusion of blanks, but not newlines). @@ -134,7 +136,7 @@ pg_isblank(const char c) * Handle comments. */ static bool -next_token(FILE *fp, char *buf, int bufsz, bool *initial_quote, +next_token(char **lineptr, char *buf, int bufsz, bool *initial_quote, bool *terminating_comma) { int c; @@ -151,10 +153,10 @@ next_token(FILE *fp, char *buf, int bufsz, bool *initial_quote, *terminating_comma = false; /* Move over initial whitespace and commas */ - while ((c = getc(fp)) != EOF && (pg_isblank(c) || c == ',')) + while ((c = (*(*lineptr)++)) != '\0' && (pg_isblank(c) || c == ',')) ; - if (c == EOF || c == '\n') + if (c == '\0' || c == '\n') { *buf = '\0'; return false; @@ -164,17 +166,17 @@ next_token(FILE *fp, char *buf, int bufsz, bool *initial_quote, * Build a token in buf of next characters up to EOF, EOL, unquoted comma, * or unquoted whitespace. */ - while (c != EOF && c != '\n' && + while (c != '\0' && c != '\n' && (!pg_isblank(c) || in_quote)) { /* skip comments to EOL */ if (c == '#' && !in_quote) { - while ((c = getc(fp)) != EOF && c != '\n') + while ((c = (*(*lineptr)++)) != '\0' && c != '\n') ; /* If only comment, consume EOL too; return EOL */ - if (c != EOF && buf == start_buf) - c = getc(fp); + if (c != '\0' && buf == start_buf) + (*lineptr)++; break; } @@ -186,7 +188,7 @@ next_token(FILE *fp, char *buf, int bufsz, bool *initial_quote, errmsg("authentication file token too long, skipping: \"%s\"", start_buf))); /* Discard remainder of line */ - while ((c = getc(fp)) != EOF && c != '\n') + while ((c = (*(*lineptr)++)) != '\0' && c != '\n') ; break; } @@ -215,15 +217,14 @@ next_token(FILE *fp, char *buf, int bufsz, bool *initial_quote, *initial_quote = true; } - c = getc(fp); + c = *(*lineptr)++; } /* * Put back the char right after the token (critical in case it is EOL, * since we need to detect end-of-line at next call). */ - if (c != EOF) - ungetc(c, fp); + (*lineptr)--; *buf = '\0'; @@ -258,13 +259,13 @@ copy_hba_token(HbaToken *in) /* - * Tokenize one HBA field from a file, handling file inclusion and comma lists. + * Tokenize one HBA field from a line, handling file inclusion and comma lists. * * The result is a List of HbaToken structs for each individual token, * or NIL if we reached EOL. */ static List * -next_field_expand(const char *filename, FILE *file) +next_field_expand(const char *filename, char **lineptr) { char buf[MAX_TOKEN]; bool trailing_comma; @@ -273,7 +274,7 @@ next_field_expand(const char *filename, FILE *file) do { - if (!next_token(file, buf, sizeof(buf), &initial_quote, &trailing_comma)) + if (!next_token(lineptr, buf, sizeof(buf), &initial_quote, &trailing_comma)) break; /* Is this referencing a file? */ @@ -335,7 +336,7 @@ tokenize_inc_file(List *tokens, } /* There is possible recursion here if the file contains @ */ - linecxt = tokenize_file(inc_fullname, inc_file, &inc_lines, &inc_line_nums); + linecxt = tokenize_file(inc_fullname, inc_file, &inc_lines, &inc_line_nums, NULL); FreeFile(inc_file); pfree(inc_fullname); @@ -364,8 +365,8 @@ tokenize_inc_file(List *tokens, } /* - * Tokenize the given file, storing the resulting data into two Lists: a - * List of lines, and a List of line numbers. + * Tokenize the given file, storing the resulting data into three Lists: a + * List of lines, a List of line numbers, and a List of raw line contents. * * The list of lines is a triple-nested List structure. Each line is a List of * fields, and each field is a List of HbaTokens. @@ -377,7 +378,7 @@ tokenize_inc_file(List *tokens, */ static MemoryContext tokenize_file(const char *filename, FILE *file, - List **lines, List **line_nums) + List **lines, List **line_nums, List **raw_lines) { List *current_line = NIL; List *current_field = NIL; @@ -396,30 +397,51 @@ tokenize_file(const char *filename, FILE *file, while (!feof(file) && !ferror(file)) { - current_field = next_field_expand(filename, file); + char rawline[MAX_LINE]; + char *lineptr; - /* add tokens to list, unless we are at EOL or comment start */ - if (list_length(current_field) > 0) + if (!fgets(rawline, sizeof(rawline), file)) + break; + if (strlen(rawline) == MAX_LINE-1) + /* Line too long! */ + ereport(ERROR, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("authentication file line too long"), + errcontext("line %d of configuration file \"%s\"", + line_number, filename))); + + /* Strip trailing linebreak from rawline */ + while (rawline[strlen(rawline)-1] == '\n' || + rawline[strlen(rawline)-1] == '\r') + rawline[strlen(rawline)-1] = '\0'; + + lineptr = rawline; + while (strlen(lineptr) > 0) { - if (current_line == NIL) + current_field = next_field_expand(filename, &lineptr); + + /* add tokens to list, unless we are at EOL or comment start */ + if (list_length(current_field) > 0) { - /* make a new line List, record its line number */ - current_line = lappend(current_line, current_field); - *lines = lappend(*lines, current_line); - *line_nums = lappend_int(*line_nums, line_number); - } - else - { - /* append tokens to current line's list */ - current_line = lappend(current_line, current_field); + if (current_line == NIL) + { + /* make a new line List, record its line number */ + current_line = lappend(current_line, current_field); + *lines = lappend(*lines, current_line); + *line_nums = lappend_int(*line_nums, line_number); + if (raw_lines) + *raw_lines = lappend(*raw_lines, pstrdup(rawline)); + } + else + { + /* append tokens to current line's list */ + current_line = lappend(current_line, current_field); + } } } - else - { - /* we are at real or logical EOL, so force a new line List */ - current_line = NIL; - line_number++; - } + /* we are at real or logical EOL, so force a new line List */ + current_line = NIL; + line_number++; } MemoryContextSwitchTo(oldcxt); @@ -815,7 +837,7 @@ check_same_host_or_net(SockAddr *raddr, IPCompareMethod method) * NULL. */ static HbaLine * -parse_hba_line(List *line, int line_num) +parse_hba_line(List *line, int line_num, char *raw_line) { char *str; struct addrinfo *gai_result; @@ -831,6 +853,7 @@ parse_hba_line(List *line, int line_num) parsedline = palloc0(sizeof(HbaLine)); parsedline->linenumber = line_num; + parsedline->rawline = pstrdup(raw_line); /* Check the record type. */ field = list_head(line); @@ -1761,8 +1784,10 @@ load_hba(void) FILE *file; List *hba_lines = NIL; List *hba_line_nums = NIL; + List *hba_raw_lines = NIL; ListCell *line, - *line_num; + *line_num, + *raw_line; List *new_parsed_lines = NIL; bool ok = true; MemoryContext linecxt; @@ -1779,7 +1804,7 @@ load_hba(void) return false; } - linecxt = tokenize_file(HbaFileName, file, &hba_lines, &hba_line_nums); + linecxt = tokenize_file(HbaFileName, file, &hba_lines, &hba_line_nums, &hba_raw_lines); FreeFile(file); /* Now parse all the lines */ @@ -1789,11 +1814,11 @@ load_hba(void) ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_MAXSIZE); oldcxt = MemoryContextSwitchTo(hbacxt); - forboth(line, hba_lines, line_num, hba_line_nums) + forthree(line, hba_lines, line_num, hba_line_nums, raw_line, hba_raw_lines) { HbaLine *newline; - if ((newline = parse_hba_line(lfirst(line), lfirst_int(line_num))) == NULL) + if ((newline = parse_hba_line(lfirst(line), lfirst_int(line_num), lfirst(raw_line))) == NULL) { /* * Parse error in the file, so indicate there's a problem. NB: a @@ -2153,7 +2178,7 @@ load_ident(void) return false; } - linecxt = tokenize_file(IdentFileName, file, &ident_lines, &ident_line_nums); + linecxt = tokenize_file(IdentFileName, file, &ident_lines, &ident_line_nums, NULL); FreeFile(file); /* Now parse all the lines */ diff --git a/src/include/libpq/hba.h b/src/include/libpq/hba.h index 79a5dc608c..5828389fe3 100644 --- a/src/include/libpq/hba.h +++ b/src/include/libpq/hba.h @@ -53,6 +53,7 @@ typedef enum ConnType typedef struct HbaLine { int linenumber; + char *rawline; ConnType conntype; List *databases; List *roles;