*** a/src/backend/libpq/auth.c --- b/src/backend/libpq/auth.c *************** *** 297,305 **** auth_failed(Port *port, int status) break; } ! ereport(FATAL, ! (errcode(errcode_return), ! errmsg(errstr, port->user_name))); /* doesn't return */ } --- 297,312 ---- break; } ! 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 */ } *** a/src/backend/libpq/hba.c --- b/src/backend/libpq/hba.c *************** *** 50,55 **** --- 50,56 ---- #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,99 **** static MemoryContext parsed_ident_context = NULL; static MemoryContext tokenize_file(const char *filename, FILE *file, ! List **lines, List **line_nums); 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, --- 94,100 ---- static MemoryContext tokenize_file(const char *filename, FILE *file, ! 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,117 **** pg_isblank(const char c) /* ! * Grab one token out of fp. 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). --- 112,119 ---- /* ! * 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,140 **** pg_isblank(const char c) * Handle comments. */ static bool ! next_token(FILE *fp, char *buf, int bufsz, bool *initial_quote, bool *terminating_comma) { int c; --- 136,142 ---- * Handle comments. */ static bool ! next_token(char **lineptr, char *buf, int bufsz, bool *initial_quote, bool *terminating_comma) { int c; *************** *** 151,160 **** 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 == ',')) ; ! if (c == EOF || c == '\n') { *buf = '\0'; return false; --- 153,162 ---- *terminating_comma = false; /* Move over initial whitespace and commas */ ! while ((c = (*(*lineptr)++)) != '\0' && (pg_isblank(c) || c == ',')) ; ! if (c == '\0' || c == '\n') { *buf = '\0'; return false; *************** *** 164,180 **** 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' && (!pg_isblank(c) || in_quote)) { /* skip comments to EOL */ if (c == '#' && !in_quote) { ! while ((c = getc(fp)) != EOF && c != '\n') ; /* If only comment, consume EOL too; return EOL */ ! if (c != EOF && buf == start_buf) ! c = getc(fp); break; } --- 166,182 ---- * Build a token in buf of next characters up to EOF, EOL, unquoted comma, * or unquoted whitespace. */ ! while (c != '\0' && c != '\n' && (!pg_isblank(c) || in_quote)) { /* skip comments to EOL */ if (c == '#' && !in_quote) { ! while ((c = (*(*lineptr)++)) != '\0' && c != '\n') ; /* If only comment, consume EOL too; return EOL */ ! if (c != '\0' && buf == start_buf) ! (*lineptr)++; break; } *************** *** 186,193 **** 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') ! ; break; } --- 188,195 ---- errmsg("authentication file token too long, skipping: \"%s\"", start_buf))); /* Discard remainder of line */ ! while ((c = (*(*lineptr)++)) != '\0' && c != '\n') ! (*lineptr)++; break; } *************** *** 215,229 **** next_token(FILE *fp, char *buf, int bufsz, bool *initial_quote, *initial_quote = true; } ! c = getc(fp); } /* * 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); *buf = '\0'; --- 217,231 ---- *initial_quote = true; } ! c = (**lineptr); ! (*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). */ ! (*lineptr)--; *buf = '\0'; *************** *** 258,270 **** copy_hba_token(HbaToken *in) /* ! * Tokenize one HBA field from a file, 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) { char buf[MAX_TOKEN]; bool trailing_comma; --- 260,272 ---- /* ! * 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, char **lineptr) { char buf[MAX_TOKEN]; bool trailing_comma; *************** *** 273,279 **** next_field_expand(const char *filename, FILE *file) do { ! if (!next_token(file, buf, sizeof(buf), &initial_quote, &trailing_comma)) break; /* Is this referencing a file? */ --- 275,281 ---- do { ! if (!next_token(lineptr, buf, sizeof(buf), &initial_quote, &trailing_comma)) break; /* Is this referencing a file? */ *************** *** 335,341 **** 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); FreeFile(inc_file); pfree(inc_fullname); --- 337,343 ---- } /* There is possible recursion here if the file contains @ */ ! linecxt = tokenize_file(inc_fullname, inc_file, &inc_lines, &inc_line_nums, NULL); FreeFile(inc_file); pfree(inc_fullname); *************** *** 377,383 **** tokenize_inc_file(List *tokens, */ static MemoryContext tokenize_file(const char *filename, FILE *file, ! List **lines, List **line_nums) { List *current_line = NIL; List *current_field = NIL; --- 379,385 ---- */ static MemoryContext tokenize_file(const char *filename, FILE *file, ! List **lines, List **line_nums, List **raw_lines) { List *current_line = NIL; List *current_field = NIL; *************** *** 396,425 **** tokenize_file(const char *filename, FILE *file, while (!feof(file) && !ferror(file)) { ! current_field = next_field_expand(filename, file); ! /* add tokens to list, unless we are at EOL or comment start */ ! if (list_length(current_field) > 0) { ! 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); ! } ! 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++; ! } } MemoryContextSwitchTo(oldcxt); --- 398,448 ---- while (!feof(file) && !ferror(file)) { ! char rawline[MAX_LINE]; ! char *lineptr; ! ! 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) { ! 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) { ! 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); ! } } } ! /* we are at real or logical EOL, so force a new line List */ ! current_line = NIL; ! line_number++; } MemoryContextSwitchTo(oldcxt); *************** *** 815,821 **** check_same_host_or_net(SockAddr *raddr, IPCompareMethod method) * NULL. */ static HbaLine * ! parse_hba_line(List *line, int line_num) { char *str; struct addrinfo *gai_result; --- 838,844 ---- * NULL. */ static HbaLine * ! parse_hba_line(List *line, int line_num, char *raw_line) { char *str; struct addrinfo *gai_result; *************** *** 831,836 **** parse_hba_line(List *line, int line_num) --- 854,860 ---- parsedline = palloc0(sizeof(HbaLine)); parsedline->linenumber = line_num; + parsedline->rawline = pstrdup(raw_line); /* Check the record type. */ field = list_head(line); *************** *** 1761,1768 **** load_hba(void) FILE *file; List *hba_lines = NIL; List *hba_line_nums = NIL; ListCell *line, ! *line_num; List *new_parsed_lines = NIL; bool ok = true; MemoryContext linecxt; --- 1785,1794 ---- FILE *file; List *hba_lines = NIL; List *hba_line_nums = NIL; + List *hba_raw_lines = NIL; ListCell *line, ! *line_num, ! *raw_line; List *new_parsed_lines = NIL; bool ok = true; MemoryContext linecxt; *************** *** 1779,1785 **** load_hba(void) return false; } ! linecxt = tokenize_file(HbaFileName, file, &hba_lines, &hba_line_nums); FreeFile(file); /* Now parse all the lines */ --- 1805,1811 ---- return false; } ! linecxt = tokenize_file(HbaFileName, file, &hba_lines, &hba_line_nums, &hba_raw_lines); FreeFile(file); /* Now parse all the lines */ *************** *** 1789,1799 **** load_hba(void) ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_MAXSIZE); oldcxt = MemoryContextSwitchTo(hbacxt); ! forboth(line, hba_lines, line_num, hba_line_nums) { HbaLine *newline; ! if ((newline = parse_hba_line(lfirst(line), lfirst_int(line_num))) == NULL) { /* * Parse error in the file, so indicate there's a problem. NB: a --- 1815,1825 ---- ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_MAXSIZE); oldcxt = MemoryContextSwitchTo(hbacxt); ! 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), lfirst(raw_line))) == NULL) { /* * Parse error in the file, so indicate there's a problem. NB: a *************** *** 2153,2159 **** load_ident(void) return false; } ! linecxt = tokenize_file(IdentFileName, file, &ident_lines, &ident_line_nums); FreeFile(file); /* Now parse all the lines */ --- 2179,2185 ---- return false; } ! linecxt = tokenize_file(IdentFileName, file, &ident_lines, &ident_line_nums, NULL); FreeFile(file); /* Now parse all the lines */ *** a/src/include/libpq/hba.h --- b/src/include/libpq/hba.h *************** *** 53,58 **** typedef enum ConnType --- 53,59 ---- typedef struct HbaLine { int linenumber; + char *rawline; ConnType conntype; List *databases; List *roles;