Allow records to span multiple lines in pg_hba.conf and pg_ident.conf.
A backslash at the end of a line now causes the next line to be appended to the current one (effectively, the backslash and newline are discarded). This allows long HBA entries to be created without legibility problems. While we're here, get rid of the former hard-wired length limit on pg_hba.conf lines, by using an expansible StringInfo buffer instead of a fixed-size local variable. Since the same code is used to read the ident map file, these changes apply there as well. Fabien Coelho, reviewed by Justin Pryzby and David Zhang Discussion: https://postgr.es/m/alpine.DEB.2.21.2003251906140.15243@pseudo
This commit is contained in:
parent
d2511d7132
commit
8f8154a503
|
@ -77,13 +77,15 @@
|
|||
The general format of the <filename>pg_hba.conf</filename> file is
|
||||
a set of records, one per line. Blank lines are ignored, as is any
|
||||
text after the <literal>#</literal> comment character.
|
||||
Records cannot be continued across lines.
|
||||
A record can be continued onto the next line by ending the line with
|
||||
a backslash. (Backslashes are not special except at the end of a line.)
|
||||
A record is made
|
||||
up of a number of fields which are separated by spaces and/or tabs.
|
||||
Fields can contain white space if the field value is double-quoted.
|
||||
Quoting one of the keywords in a database, user, or address field (e.g.,
|
||||
<literal>all</literal> or <literal>replication</literal>) makes the word lose its special
|
||||
meaning, and just match a database, user, or host with that name.
|
||||
Backslash line continuation applies even within quoted text or comments.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
|
@ -821,7 +823,7 @@ local db1,db2,@demodbs all md5
|
|||
<synopsis>
|
||||
<replaceable>map-name</replaceable> <replaceable>system-username</replaceable> <replaceable>database-username</replaceable>
|
||||
</synopsis>
|
||||
Comments and whitespace are handled in the same way as in
|
||||
Comments, whitespace and line continuations are handled in the same way as in
|
||||
<filename>pg_hba.conf</filename>. The
|
||||
<replaceable>map-name</replaceable> is an arbitrary name that will be used to
|
||||
refer to this mapping in <filename>pg_hba.conf</filename>. The other
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "catalog/pg_collation.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "common/ip.h"
|
||||
#include "common/string.h"
|
||||
#include "funcapi.h"
|
||||
#include "libpq/ifaddr.h"
|
||||
#include "libpq/libpq.h"
|
||||
|
@ -54,7 +55,6 @@
|
|||
|
||||
|
||||
#define MAX_TOKEN 256
|
||||
#define MAX_LINE 8192
|
||||
|
||||
/* callback data for check_network_callback */
|
||||
typedef struct check_network_data
|
||||
|
@ -166,11 +166,19 @@ pg_isblank(const char c)
|
|||
/*
|
||||
* 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).
|
||||
* Comments (started by an unquoted '#') are skipped.
|
||||
* 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 or '#', but not newlines). As in SQL, write two double-quotes
|
||||
* to represent a double quote.
|
||||
*
|
||||
* Comments (started by an unquoted '#') are skipped, i.e. the remainder
|
||||
* of the line is ignored.
|
||||
*
|
||||
* (Note that line continuation processing happens before tokenization.
|
||||
* Thus, if a continuation occurs within quoted text or a comment, the
|
||||
* quoted text or comment is considered to continue to the next line.)
|
||||
*
|
||||
* The token, if any, is returned at *buf (a buffer of size bufsz), and
|
||||
* *lineptr is advanced past the token.
|
||||
|
@ -470,6 +478,7 @@ static MemoryContext
|
|||
tokenize_file(const char *filename, FILE *file, List **tok_lines, int elevel)
|
||||
{
|
||||
int line_number = 1;
|
||||
StringInfoData buf;
|
||||
MemoryContext linecxt;
|
||||
MemoryContext oldcxt;
|
||||
|
||||
|
@ -478,47 +487,72 @@ tokenize_file(const char *filename, FILE *file, List **tok_lines, int elevel)
|
|||
ALLOCSET_SMALL_SIZES);
|
||||
oldcxt = MemoryContextSwitchTo(linecxt);
|
||||
|
||||
initStringInfo(&buf);
|
||||
|
||||
*tok_lines = NIL;
|
||||
|
||||
while (!feof(file) && !ferror(file))
|
||||
{
|
||||
char rawline[MAX_LINE];
|
||||
char *lineptr;
|
||||
List *current_line = NIL;
|
||||
char *err_msg = NULL;
|
||||
int last_backslash_buflen = 0;
|
||||
int continuations = 0;
|
||||
|
||||
if (!fgets(rawline, sizeof(rawline), file))
|
||||
/* Collect the next input line, handling backslash continuations */
|
||||
resetStringInfo(&buf);
|
||||
|
||||
while (!feof(file) && !ferror(file))
|
||||
{
|
||||
int save_errno = errno;
|
||||
/* Make sure there's a reasonable amount of room in the buffer */
|
||||
enlargeStringInfo(&buf, 128);
|
||||
|
||||
if (!ferror(file))
|
||||
break; /* normal EOF */
|
||||
/* I/O error! */
|
||||
ereport(elevel,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not read file \"%s\": %m", filename)));
|
||||
err_msg = psprintf("could not read file \"%s\": %s",
|
||||
filename, strerror(save_errno));
|
||||
rawline[0] = '\0';
|
||||
}
|
||||
if (strlen(rawline) == MAX_LINE - 1)
|
||||
{
|
||||
/* Line too long! */
|
||||
ereport(elevel,
|
||||
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
||||
errmsg("authentication file line too long"),
|
||||
errcontext("line %d of configuration file \"%s\"",
|
||||
line_number, filename)));
|
||||
err_msg = "authentication file line too long";
|
||||
}
|
||||
/* Read some data, appending it to what we already have */
|
||||
if (fgets(buf.data + buf.len, buf.maxlen - buf.len, file) == NULL)
|
||||
{
|
||||
int save_errno = errno;
|
||||
|
||||
/* Strip trailing linebreak from rawline */
|
||||
lineptr = rawline + strlen(rawline) - 1;
|
||||
while (lineptr >= rawline && (*lineptr == '\n' || *lineptr == '\r'))
|
||||
*lineptr-- = '\0';
|
||||
if (!ferror(file))
|
||||
break; /* normal EOF */
|
||||
/* I/O error! */
|
||||
ereport(elevel,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not read file \"%s\": %m", filename)));
|
||||
err_msg = psprintf("could not read file \"%s\": %s",
|
||||
filename, strerror(save_errno));
|
||||
resetStringInfo(&buf);
|
||||
break;
|
||||
}
|
||||
buf.len += strlen(buf.data + buf.len);
|
||||
|
||||
/* If we haven't got a whole line, loop to read more */
|
||||
if (!(buf.len > 0 && buf.data[buf.len - 1] == '\n'))
|
||||
continue;
|
||||
|
||||
/* Strip trailing newline, including \r in case we're on Windows */
|
||||
buf.len = pg_strip_crlf(buf.data);
|
||||
|
||||
/*
|
||||
* Check for backslash continuation. The backslash must be after
|
||||
* the last place we found a continuation, else two backslashes
|
||||
* followed by two \n's would behave surprisingly.
|
||||
*/
|
||||
if (buf.len > last_backslash_buflen &&
|
||||
buf.data[buf.len - 1] == '\\')
|
||||
{
|
||||
/* Continuation, so strip it and keep reading */
|
||||
buf.data[--buf.len] = '\0';
|
||||
last_backslash_buflen = buf.len;
|
||||
continuations++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Nope, so we have the whole line */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Parse fields */
|
||||
lineptr = rawline;
|
||||
lineptr = buf.data;
|
||||
while (*lineptr && err_msg == NULL)
|
||||
{
|
||||
List *current_field;
|
||||
|
@ -538,12 +572,12 @@ tokenize_file(const char *filename, FILE *file, List **tok_lines, int elevel)
|
|||
tok_line = (TokenizedLine *) palloc(sizeof(TokenizedLine));
|
||||
tok_line->fields = current_line;
|
||||
tok_line->line_num = line_number;
|
||||
tok_line->raw_line = pstrdup(rawline);
|
||||
tok_line->raw_line = pstrdup(buf.data);
|
||||
tok_line->err_msg = err_msg;
|
||||
*tok_lines = lappend(*tok_lines, tok_line);
|
||||
}
|
||||
|
||||
line_number++;
|
||||
line_number += continuations + 1;
|
||||
}
|
||||
|
||||
MemoryContextSwitchTo(oldcxt);
|
||||
|
|
|
@ -29,7 +29,8 @@ sub reset_pg_hba
|
|||
my $hba_method = shift;
|
||||
|
||||
unlink($node->data_dir . '/pg_hba.conf');
|
||||
$node->append_conf('pg_hba.conf', "local all all $hba_method");
|
||||
# just for testing purposes, use a continuation line
|
||||
$node->append_conf('pg_hba.conf', "local all all\\\n $hba_method");
|
||||
$node->reload;
|
||||
return;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue