aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/libpq/hba.c517
-rw-r--r--src/backend/utils/adt/Makefile1
-rw-r--r--src/backend/utils/adt/hbafuncs.c428
-rw-r--r--src/include/libpq/hba.h31
-rw-r--r--src/tools/pgindent/typedefs.list4
5 files changed, 511 insertions, 470 deletions
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 90953c38f3d..673135144d4 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -69,32 +69,6 @@ typedef struct check_network_data
#define token_matches(t, k) (strcmp(t->string, k) == 0)
/*
- * A single string token lexed from a config file, together with whether
- * the token had been quoted.
- */
-typedef struct HbaToken
-{
- char *string;
- bool quoted;
-} HbaToken;
-
-/*
- * TokenizedLine represents one line lexed from a config file.
- * Each item in the "fields" list is a sub-list of HbaTokens.
- * We don't emit a TokenizedLine for empty or all-comment lines,
- * so "fields" is never NIL (nor are any of its sub-lists).
- * Exception: if an error occurs during tokenization, we might
- * have fields == NIL, in which case err_msg != NULL.
- */
-typedef struct TokenizedLine
-{
- List *fields; /* List of lists of HbaTokens */
- int line_num; /* Line number */
- char *raw_line; /* Raw line text */
- char *err_msg; /* Error message if any */
-} TokenizedLine;
-
-/*
* pre-parsed content of HBA config file: list of HbaLine structs.
* parsed_hba_context is the memory context where it lives.
*/
@@ -138,16 +112,10 @@ static const char *const UserAuthName[] =
};
-static MemoryContext tokenize_file(const char *filename, FILE *file,
- List **tok_lines, int elevel);
static List *tokenize_inc_file(List *tokens, const char *outer_filename,
const char *inc_filename, int elevel, char **err_msg);
static bool parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline,
int elevel, char **err_msg);
-static ArrayType *gethba_options(HbaLine *hba);
-static void fill_hba_line(Tuplestorestate *tuple_store, TupleDesc tupdesc,
- int lineno, HbaLine *hba, const char *err_msg);
-static void fill_hba_view(Tuplestorestate *tuple_store, TupleDesc tupdesc);
/*
@@ -288,31 +256,31 @@ next_token(char **lineptr, char *buf, int bufsz,
}
/*
- * Construct a palloc'd HbaToken struct, copying the given string.
+ * Construct a palloc'd AuthToken struct, copying the given string.
*/
-static HbaToken *
-make_hba_token(const char *token, bool quoted)
+static AuthToken *
+make_auth_token(const char *token, bool quoted)
{
- HbaToken *hbatoken;
+ AuthToken *authtoken;
int toklen;
toklen = strlen(token);
/* we copy string into same palloc block as the struct */
- hbatoken = (HbaToken *) palloc(sizeof(HbaToken) + toklen + 1);
- hbatoken->string = (char *) hbatoken + sizeof(HbaToken);
- hbatoken->quoted = quoted;
- memcpy(hbatoken->string, token, toklen + 1);
+ authtoken = (AuthToken *) palloc(sizeof(AuthToken) + toklen + 1);
+ authtoken->string = (char *) authtoken + sizeof(AuthToken);
+ authtoken->quoted = quoted;
+ memcpy(authtoken->string, token, toklen + 1);
- return hbatoken;
+ return authtoken;
}
/*
- * Copy a HbaToken struct into freshly palloc'd memory.
+ * Copy a AuthToken struct into freshly palloc'd memory.
*/
-static HbaToken *
-copy_hba_token(HbaToken *in)
+static AuthToken *
+copy_auth_token(AuthToken *in)
{
- HbaToken *out = make_hba_token(in->string, in->quoted);
+ AuthToken *out = make_auth_token(in->string, in->quoted);
return out;
}
@@ -329,7 +297,7 @@ copy_hba_token(HbaToken *in)
* may be non-NIL anyway, so *err_msg must be tested to determine whether
* there was an error.
*
- * The result is a List of HbaToken structs, one for each token in the field,
+ * The result is a List of AuthToken structs, one for each token in the field,
* or NIL if we reached EOL.
*/
static List *
@@ -353,7 +321,7 @@ next_field_expand(const char *filename, char **lineptr,
tokens = tokenize_inc_file(tokens, filename, buf + 1,
elevel, err_msg);
else
- tokens = lappend(tokens, make_hba_token(buf, initial_quote));
+ tokens = lappend(tokens, make_auth_token(buf, initial_quote));
} while (trailing_comma && (*err_msg == NULL));
return tokens;
@@ -364,7 +332,7 @@ next_field_expand(const char *filename, char **lineptr,
* Expand a file included from another file into an hba "field"
*
* Opens and tokenises a file included from another HBA config file with @,
- * and returns all values found therein as a flat list of HbaTokens. If a
+ * and returns all values found therein as a flat list of AuthTokens. If a
* @-token is found, recursively expand it. The newly read tokens are
* appended to "tokens" (so that foo,bar,@baz does what you expect).
* All new tokens are allocated in caller's memory context.
@@ -419,7 +387,7 @@ tokenize_inc_file(List *tokens,
}
/* There is possible recursion here if the file contains @ */
- linecxt = tokenize_file(inc_fullname, inc_file, &inc_lines, elevel);
+ linecxt = tokenize_auth_file(inc_fullname, inc_file, &inc_lines, elevel);
FreeFile(inc_file);
pfree(inc_fullname);
@@ -427,7 +395,7 @@ tokenize_inc_file(List *tokens,
/* Copy all tokens found in the file and append to the tokens list */
foreach(inc_line, inc_lines)
{
- TokenizedLine *tok_line = (TokenizedLine *) lfirst(inc_line);
+ TokenizedAuthLine *tok_line = (TokenizedAuthLine *) lfirst(inc_line);
ListCell *inc_field;
/* If any line has an error, propagate that up to caller */
@@ -444,9 +412,9 @@ tokenize_inc_file(List *tokens,
foreach(inc_token, inc_tokens)
{
- HbaToken *token = lfirst(inc_token);
+ AuthToken *token = lfirst(inc_token);
- tokens = lappend(tokens, copy_hba_token(token));
+ tokens = lappend(tokens, copy_auth_token(token));
}
}
}
@@ -456,9 +424,11 @@ tokenize_inc_file(List *tokens,
}
/*
- * Tokenize the given file.
+ * tokenize_auth_file
+ * Tokenize the given file.
*
- * The output is a list of TokenizedLine structs; see struct definition above.
+ * The output is a list of TokenizedAuthLine structs; see the struct definition
+ * in libpq/hba.h.
*
* filename: the absolute path to the target file
* file: the already-opened target file
@@ -466,14 +436,15 @@ tokenize_inc_file(List *tokens,
* elevel: message logging level
*
* Errors are reported by logging messages at ereport level elevel and by
- * adding TokenizedLine structs containing non-null err_msg fields to the
+ * adding TokenizedAuthLine structs containing non-null err_msg fields to the
* output list.
*
* Return value is a memory context which contains all memory allocated by
* this function (it's a child of caller's context).
*/
-static MemoryContext
-tokenize_file(const char *filename, FILE *file, List **tok_lines, int elevel)
+MemoryContext
+tokenize_auth_file(const char *filename, FILE *file, List **tok_lines,
+ int elevel)
{
int line_number = 1;
StringInfoData buf;
@@ -481,7 +452,7 @@ tokenize_file(const char *filename, FILE *file, List **tok_lines, int elevel)
MemoryContext oldcxt;
linecxt = AllocSetContextCreate(CurrentMemoryContext,
- "tokenize_file",
+ "tokenize_auth_file",
ALLOCSET_SMALL_SIZES);
oldcxt = MemoryContextSwitchTo(linecxt);
@@ -550,12 +521,14 @@ tokenize_file(const char *filename, FILE *file, List **tok_lines, int elevel)
current_line = lappend(current_line, current_field);
}
- /* Reached EOL; emit line to TokenizedLine list unless it's boring */
+ /*
+ * Reached EOL; emit line to TokenizedAuthLine list unless it's boring
+ */
if (current_line != NIL || err_msg != NULL)
{
- TokenizedLine *tok_line;
+ TokenizedAuthLine *tok_line;
- tok_line = (TokenizedLine *) palloc(sizeof(TokenizedLine));
+ tok_line = (TokenizedAuthLine *) palloc(sizeof(TokenizedAuthLine));
tok_line->fields = current_line;
tok_line->line_num = line_number;
tok_line->raw_line = pstrdup(buf.data);
@@ -600,13 +573,13 @@ is_member(Oid userid, const char *role)
}
/*
- * Check HbaToken list for a match to role, allowing group names.
+ * Check AuthToken list for a match to role, allowing group names.
*/
static bool
check_role(const char *role, Oid roleid, List *tokens)
{
ListCell *cell;
- HbaToken *tok;
+ AuthToken *tok;
foreach(cell, tokens)
{
@@ -624,13 +597,13 @@ check_role(const char *role, Oid roleid, List *tokens)
}
/*
- * Check to see if db/role combination matches HbaToken list.
+ * Check to see if db/role combination matches AuthToken list.
*/
static bool
check_db(const char *dbname, const char *role, Oid roleid, List *tokens)
{
ListCell *cell;
- HbaToken *tok;
+ AuthToken *tok;
foreach(cell, tokens)
{
@@ -962,8 +935,8 @@ do { \
* to have set a memory context that will be reset if this function returns
* NULL.
*/
-static HbaLine *
-parse_hba_line(TokenizedLine *tok_line, int elevel)
+HbaLine *
+parse_hba_line(TokenizedAuthLine *tok_line, int elevel)
{
int line_num = tok_line->line_num;
char **err_msg = &tok_line->err_msg;
@@ -976,7 +949,7 @@ parse_hba_line(TokenizedLine *tok_line, int elevel)
ListCell *field;
List *tokens;
ListCell *tokencell;
- HbaToken *token;
+ AuthToken *token;
HbaLine *parsedline;
parsedline = palloc0(sizeof(HbaLine));
@@ -1097,7 +1070,7 @@ parse_hba_line(TokenizedLine *tok_line, int elevel)
foreach(tokencell, tokens)
{
parsedline->databases = lappend(parsedline->databases,
- copy_hba_token(lfirst(tokencell)));
+ copy_auth_token(lfirst(tokencell)));
}
/* Get the roles. */
@@ -1117,7 +1090,7 @@ parse_hba_line(TokenizedLine *tok_line, int elevel)
foreach(tokencell, tokens)
{
parsedline->roles = lappend(parsedline->roles,
- copy_hba_token(lfirst(tokencell)));
+ copy_auth_token(lfirst(tokencell)));
}
if (parsedline->conntype != ctLocal)
@@ -2257,7 +2230,7 @@ load_hba(void)
return false;
}
- linecxt = tokenize_file(HbaFileName, file, &hba_lines, LOG);
+ linecxt = tokenize_auth_file(HbaFileName, file, &hba_lines, LOG);
FreeFile(file);
/* Now parse all the lines */
@@ -2268,7 +2241,7 @@ load_hba(void)
oldcxt = MemoryContextSwitchTo(hbacxt);
foreach(line, hba_lines)
{
- TokenizedLine *tok_line = (TokenizedLine *) lfirst(line);
+ TokenizedAuthLine *tok_line = (TokenizedAuthLine *) lfirst(line);
HbaLine *newline;
/* don't parse lines that already have errors */
@@ -2328,398 +2301,6 @@ load_hba(void)
return true;
}
-/*
- * This macro specifies the maximum number of authentication options
- * that are possible with any given authentication method that is supported.
- * Currently LDAP supports 11, and there are 3 that are not dependent on
- * the auth method here. It may not actually be possible to set all of them
- * at the same time, but we'll set the macro value high enough to be
- * conservative and avoid warnings from static analysis tools.
- */
-#define MAX_HBA_OPTIONS 14
-
-/*
- * Create a text array listing the options specified in the HBA line.
- * Return NULL if no options are specified.
- */
-static ArrayType *
-gethba_options(HbaLine *hba)
-{
- int noptions;
- Datum options[MAX_HBA_OPTIONS];
-
- noptions = 0;
-
- if (hba->auth_method == uaGSS || hba->auth_method == uaSSPI)
- {
- if (hba->include_realm)
- options[noptions++] =
- CStringGetTextDatum("include_realm=true");
-
- if (hba->krb_realm)
- options[noptions++] =
- CStringGetTextDatum(psprintf("krb_realm=%s", hba->krb_realm));
- }
-
- if (hba->usermap)
- options[noptions++] =
- CStringGetTextDatum(psprintf("map=%s", hba->usermap));
-
- if (hba->clientcert != clientCertOff)
- options[noptions++] =
- CStringGetTextDatum(psprintf("clientcert=%s", (hba->clientcert == clientCertCA) ? "verify-ca" : "verify-full"));
-
- if (hba->pamservice)
- options[noptions++] =
- CStringGetTextDatum(psprintf("pamservice=%s", hba->pamservice));
-
- if (hba->auth_method == uaLDAP)
- {
- if (hba->ldapserver)
- options[noptions++] =
- CStringGetTextDatum(psprintf("ldapserver=%s", hba->ldapserver));
-
- if (hba->ldapport)
- options[noptions++] =
- CStringGetTextDatum(psprintf("ldapport=%d", hba->ldapport));
-
- if (hba->ldaptls)
- options[noptions++] =
- CStringGetTextDatum("ldaptls=true");
-
- if (hba->ldapprefix)
- options[noptions++] =
- CStringGetTextDatum(psprintf("ldapprefix=%s", hba->ldapprefix));
-
- if (hba->ldapsuffix)
- options[noptions++] =
- CStringGetTextDatum(psprintf("ldapsuffix=%s", hba->ldapsuffix));
-
- if (hba->ldapbasedn)
- options[noptions++] =
- CStringGetTextDatum(psprintf("ldapbasedn=%s", hba->ldapbasedn));
-
- if (hba->ldapbinddn)
- options[noptions++] =
- CStringGetTextDatum(psprintf("ldapbinddn=%s", hba->ldapbinddn));
-
- if (hba->ldapbindpasswd)
- options[noptions++] =
- CStringGetTextDatum(psprintf("ldapbindpasswd=%s",
- hba->ldapbindpasswd));
-
- if (hba->ldapsearchattribute)
- options[noptions++] =
- CStringGetTextDatum(psprintf("ldapsearchattribute=%s",
- hba->ldapsearchattribute));
-
- if (hba->ldapsearchfilter)
- options[noptions++] =
- CStringGetTextDatum(psprintf("ldapsearchfilter=%s",
- hba->ldapsearchfilter));
-
- if (hba->ldapscope)
- options[noptions++] =
- CStringGetTextDatum(psprintf("ldapscope=%d", hba->ldapscope));
- }
-
- if (hba->auth_method == uaRADIUS)
- {
- if (hba->radiusservers_s)
- options[noptions++] =
- CStringGetTextDatum(psprintf("radiusservers=%s", hba->radiusservers_s));
-
- if (hba->radiussecrets_s)
- options[noptions++] =
- CStringGetTextDatum(psprintf("radiussecrets=%s", hba->radiussecrets_s));
-
- if (hba->radiusidentifiers_s)
- options[noptions++] =
- CStringGetTextDatum(psprintf("radiusidentifiers=%s", hba->radiusidentifiers_s));
-
- if (hba->radiusports_s)
- options[noptions++] =
- CStringGetTextDatum(psprintf("radiusports=%s", hba->radiusports_s));
- }
-
- /* If you add more options, consider increasing MAX_HBA_OPTIONS. */
- Assert(noptions <= MAX_HBA_OPTIONS);
-
- if (noptions > 0)
- return construct_array(options, noptions, TEXTOID, -1, false, TYPALIGN_INT);
- else
- return NULL;
-}
-
-/* Number of columns in pg_hba_file_rules view */
-#define NUM_PG_HBA_FILE_RULES_ATTS 9
-
-/*
- * fill_hba_line: build one row of pg_hba_file_rules view, add it to tuplestore
- *
- * tuple_store: where to store data
- * tupdesc: tuple descriptor for the view
- * lineno: pg_hba.conf line number (must always be valid)
- * hba: parsed line data (can be NULL, in which case err_msg should be set)
- * err_msg: error message (NULL if none)
- *
- * Note: leaks memory, but we don't care since this is run in a short-lived
- * memory context.
- */
-static void
-fill_hba_line(Tuplestorestate *tuple_store, TupleDesc tupdesc,
- int lineno, HbaLine *hba, const char *err_msg)
-{
- Datum values[NUM_PG_HBA_FILE_RULES_ATTS];
- bool nulls[NUM_PG_HBA_FILE_RULES_ATTS];
- char buffer[NI_MAXHOST];
- HeapTuple tuple;
- int index;
- ListCell *lc;
- const char *typestr;
- const char *addrstr;
- const char *maskstr;
- ArrayType *options;
-
- Assert(tupdesc->natts == NUM_PG_HBA_FILE_RULES_ATTS);
-
- memset(values, 0, sizeof(values));
- memset(nulls, 0, sizeof(nulls));
- index = 0;
-
- /* line_number */
- values[index++] = Int32GetDatum(lineno);
-
- if (hba != NULL)
- {
- /* type */
- /* Avoid a default: case so compiler will warn about missing cases */
- typestr = NULL;
- switch (hba->conntype)
- {
- case ctLocal:
- typestr = "local";
- break;
- case ctHost:
- typestr = "host";
- break;
- case ctHostSSL:
- typestr = "hostssl";
- break;
- case ctHostNoSSL:
- typestr = "hostnossl";
- break;
- case ctHostGSS:
- typestr = "hostgssenc";
- break;
- case ctHostNoGSS:
- typestr = "hostnogssenc";
- break;
- }
- if (typestr)
- values[index++] = CStringGetTextDatum(typestr);
- else
- nulls[index++] = true;
-
- /* database */
- if (hba->databases)
- {
- /*
- * Flatten HbaToken list to string list. It might seem that we
- * should re-quote any quoted tokens, but that has been rejected
- * on the grounds that it makes it harder to compare the array
- * elements to other system catalogs. That makes entries like
- * "all" or "samerole" formally ambiguous ... but users who name
- * databases/roles that way are inflicting their own pain.
- */
- List *names = NIL;
-
- foreach(lc, hba->databases)
- {
- HbaToken *tok = lfirst(lc);
-
- names = lappend(names, tok->string);
- }
- values[index++] = PointerGetDatum(strlist_to_textarray(names));
- }
- else
- nulls[index++] = true;
-
- /* user */
- if (hba->roles)
- {
- /* Flatten HbaToken list to string list; see comment above */
- List *roles = NIL;
-
- foreach(lc, hba->roles)
- {
- HbaToken *tok = lfirst(lc);
-
- roles = lappend(roles, tok->string);
- }
- values[index++] = PointerGetDatum(strlist_to_textarray(roles));
- }
- else
- nulls[index++] = true;
-
- /* address and netmask */
- /* Avoid a default: case so compiler will warn about missing cases */
- addrstr = maskstr = NULL;
- switch (hba->ip_cmp_method)
- {
- case ipCmpMask:
- if (hba->hostname)
- {
- addrstr = hba->hostname;
- }
- else
- {
- /*
- * Note: if pg_getnameinfo_all fails, it'll set buffer to
- * "???", which we want to return.
- */
- if (hba->addrlen > 0)
- {
- if (pg_getnameinfo_all(&hba->addr, hba->addrlen,
- buffer, sizeof(buffer),
- NULL, 0,
- NI_NUMERICHOST) == 0)
- clean_ipv6_addr(hba->addr.ss_family, buffer);
- addrstr = pstrdup(buffer);
- }
- if (hba->masklen > 0)
- {
- if (pg_getnameinfo_all(&hba->mask, hba->masklen,
- buffer, sizeof(buffer),
- NULL, 0,
- NI_NUMERICHOST) == 0)
- clean_ipv6_addr(hba->mask.ss_family, buffer);
- maskstr = pstrdup(buffer);
- }
- }
- break;
- case ipCmpAll:
- addrstr = "all";
- break;
- case ipCmpSameHost:
- addrstr = "samehost";
- break;
- case ipCmpSameNet:
- addrstr = "samenet";
- break;
- }
- if (addrstr)
- values[index++] = CStringGetTextDatum(addrstr);
- else
- nulls[index++] = true;
- if (maskstr)
- values[index++] = CStringGetTextDatum(maskstr);
- else
- nulls[index++] = true;
-
- /* auth_method */
- values[index++] = CStringGetTextDatum(hba_authname(hba->auth_method));
-
- /* options */
- options = gethba_options(hba);
- if (options)
- values[index++] = PointerGetDatum(options);
- else
- nulls[index++] = true;
- }
- else
- {
- /* no parsing result, so set relevant fields to nulls */
- memset(&nulls[1], true, (NUM_PG_HBA_FILE_RULES_ATTS - 2) * sizeof(bool));
- }
-
- /* error */
- if (err_msg)
- values[NUM_PG_HBA_FILE_RULES_ATTS - 1] = CStringGetTextDatum(err_msg);
- else
- nulls[NUM_PG_HBA_FILE_RULES_ATTS - 1] = true;
-
- tuple = heap_form_tuple(tupdesc, values, nulls);
- tuplestore_puttuple(tuple_store, tuple);
-}
-
-/*
- * Read the pg_hba.conf file and fill the tuplestore with view records.
- */
-static void
-fill_hba_view(Tuplestorestate *tuple_store, TupleDesc tupdesc)
-{
- FILE *file;
- List *hba_lines = NIL;
- ListCell *line;
- MemoryContext linecxt;
- MemoryContext hbacxt;
- MemoryContext oldcxt;
-
- /*
- * In the unlikely event that we can't open pg_hba.conf, we throw an
- * error, rather than trying to report it via some sort of view entry.
- * (Most other error conditions should result in a message in a view
- * entry.)
- */
- file = AllocateFile(HbaFileName, "r");
- if (file == NULL)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not open configuration file \"%s\": %m",
- HbaFileName)));
-
- linecxt = tokenize_file(HbaFileName, file, &hba_lines, DEBUG3);
- FreeFile(file);
-
- /* Now parse all the lines */
- hbacxt = AllocSetContextCreate(CurrentMemoryContext,
- "hba parser context",
- ALLOCSET_SMALL_SIZES);
- oldcxt = MemoryContextSwitchTo(hbacxt);
- foreach(line, hba_lines)
- {
- TokenizedLine *tok_line = (TokenizedLine *) lfirst(line);
- HbaLine *hbaline = NULL;
-
- /* don't parse lines that already have errors */
- if (tok_line->err_msg == NULL)
- hbaline = parse_hba_line(tok_line, DEBUG3);
-
- fill_hba_line(tuple_store, tupdesc, tok_line->line_num,
- hbaline, tok_line->err_msg);
- }
-
- /* Free tokenizer memory */
- MemoryContextDelete(linecxt);
- /* Free parse_hba_line memory */
- MemoryContextSwitchTo(oldcxt);
- MemoryContextDelete(hbacxt);
-}
-
-/*
- * SQL-accessible SRF to return all the entries in the pg_hba.conf file.
- */
-Datum
-pg_hba_file_rules(PG_FUNCTION_ARGS)
-{
- ReturnSetInfo *rsi;
-
- /*
- * Build tuplestore to hold the result rows. We must use the Materialize
- * mode to be safe against HBA file changes while the cursor is open.
- * It's also more efficient than having to look up our current position in
- * the parsed list every time.
- */
- SetSingleFuncCall(fcinfo, 0);
-
- /* Fill the tuplestore */
- rsi = (ReturnSetInfo *) fcinfo->resultinfo;
- fill_hba_view(rsi->setResult, rsi->setDesc);
-
- PG_RETURN_NULL();
-}
-
/*
* Parse one tokenised line from the ident config file and store the result in
@@ -2735,12 +2316,12 @@ pg_hba_file_rules(PG_FUNCTION_ARGS)
* NULL.
*/
static IdentLine *
-parse_ident_line(TokenizedLine *tok_line)
+parse_ident_line(TokenizedAuthLine *tok_line)
{
int line_num = tok_line->line_num;
ListCell *field;
List *tokens;
- HbaToken *token;
+ AuthToken *token;
IdentLine *parsedline;
Assert(tok_line->fields != NIL);
@@ -3026,7 +2607,7 @@ load_ident(void)
return false;
}
- linecxt = tokenize_file(IdentFileName, file, &ident_lines, LOG);
+ linecxt = tokenize_auth_file(IdentFileName, file, &ident_lines, LOG);
FreeFile(file);
/* Now parse all the lines */
@@ -3037,7 +2618,7 @@ load_ident(void)
oldcxt = MemoryContextSwitchTo(ident_context);
foreach(line_cell, ident_lines)
{
- TokenizedLine *tok_line = (TokenizedLine *) lfirst(line_cell);
+ TokenizedAuthLine *tok_line = (TokenizedAuthLine *) lfirst(line_cell);
/* don't parse lines that already have errors */
if (tok_line->err_msg != NULL)
diff --git a/src/backend/utils/adt/Makefile b/src/backend/utils/adt/Makefile
index 41b486bceff..7c722ea2ce5 100644
--- a/src/backend/utils/adt/Makefile
+++ b/src/backend/utils/adt/Makefile
@@ -42,6 +42,7 @@ OBJS = \
geo_ops.o \
geo_selfuncs.o \
geo_spgist.o \
+ hbafuncs.o \
inet_cidr_ntop.o \
inet_net_pton.o \
int.o \
diff --git a/src/backend/utils/adt/hbafuncs.c b/src/backend/utils/adt/hbafuncs.c
new file mode 100644
index 00000000000..f46cd935a1c
--- /dev/null
+++ b/src/backend/utils/adt/hbafuncs.c
@@ -0,0 +1,428 @@
+/*-------------------------------------------------------------------------
+ *
+ * hbafuncs.c
+ * Support functions for SQL views of authentication files.
+ *
+ * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * src/backend/utils/adt/hbafuncs.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "catalog/objectaddress.h"
+#include "common/ip.h"
+#include "funcapi.h"
+#include "libpq/hba.h"
+#include "miscadmin.h"
+#include "utils/array.h"
+#include "utils/builtins.h"
+#include "utils/guc.h"
+
+
+static ArrayType *get_hba_options(HbaLine *hba);
+static void fill_hba_line(Tuplestorestate *tuple_store, TupleDesc tupdesc,
+ int lineno, HbaLine *hba, const char *err_msg);
+static void fill_hba_view(Tuplestorestate *tuple_store, TupleDesc tupdesc);
+
+
+/*
+ * This macro specifies the maximum number of authentication options
+ * that are possible with any given authentication method that is supported.
+ * Currently LDAP supports 11, and there are 3 that are not dependent on
+ * the auth method here. It may not actually be possible to set all of them
+ * at the same time, but we'll set the macro value high enough to be
+ * conservative and avoid warnings from static analysis tools.
+ */
+#define MAX_HBA_OPTIONS 14
+
+/*
+ * Create a text array listing the options specified in the HBA line.
+ * Return NULL if no options are specified.
+ */
+static ArrayType *
+get_hba_options(HbaLine *hba)
+{
+ int noptions;
+ Datum options[MAX_HBA_OPTIONS];
+
+ noptions = 0;
+
+ if (hba->auth_method == uaGSS || hba->auth_method == uaSSPI)
+ {
+ if (hba->include_realm)
+ options[noptions++] =
+ CStringGetTextDatum("include_realm=true");
+
+ if (hba->krb_realm)
+ options[noptions++] =
+ CStringGetTextDatum(psprintf("krb_realm=%s", hba->krb_realm));
+ }
+
+ if (hba->usermap)
+ options[noptions++] =
+ CStringGetTextDatum(psprintf("map=%s", hba->usermap));
+
+ if (hba->clientcert != clientCertOff)
+ options[noptions++] =
+ CStringGetTextDatum(psprintf("clientcert=%s", (hba->clientcert == clientCertCA) ? "verify-ca" : "verify-full"));
+
+ if (hba->pamservice)
+ options[noptions++] =
+ CStringGetTextDatum(psprintf("pamservice=%s", hba->pamservice));
+
+ if (hba->auth_method == uaLDAP)
+ {
+ if (hba->ldapserver)
+ options[noptions++] =
+ CStringGetTextDatum(psprintf("ldapserver=%s", hba->ldapserver));
+
+ if (hba->ldapport)
+ options[noptions++] =
+ CStringGetTextDatum(psprintf("ldapport=%d", hba->ldapport));
+
+ if (hba->ldaptls)
+ options[noptions++] =
+ CStringGetTextDatum("ldaptls=true");
+
+ if (hba->ldapprefix)
+ options[noptions++] =
+ CStringGetTextDatum(psprintf("ldapprefix=%s", hba->ldapprefix));
+
+ if (hba->ldapsuffix)
+ options[noptions++] =
+ CStringGetTextDatum(psprintf("ldapsuffix=%s", hba->ldapsuffix));
+
+ if (hba->ldapbasedn)
+ options[noptions++] =
+ CStringGetTextDatum(psprintf("ldapbasedn=%s", hba->ldapbasedn));
+
+ if (hba->ldapbinddn)
+ options[noptions++] =
+ CStringGetTextDatum(psprintf("ldapbinddn=%s", hba->ldapbinddn));
+
+ if (hba->ldapbindpasswd)
+ options[noptions++] =
+ CStringGetTextDatum(psprintf("ldapbindpasswd=%s",
+ hba->ldapbindpasswd));
+
+ if (hba->ldapsearchattribute)
+ options[noptions++] =
+ CStringGetTextDatum(psprintf("ldapsearchattribute=%s",
+ hba->ldapsearchattribute));
+
+ if (hba->ldapsearchfilter)
+ options[noptions++] =
+ CStringGetTextDatum(psprintf("ldapsearchfilter=%s",
+ hba->ldapsearchfilter));
+
+ if (hba->ldapscope)
+ options[noptions++] =
+ CStringGetTextDatum(psprintf("ldapscope=%d", hba->ldapscope));
+ }
+
+ if (hba->auth_method == uaRADIUS)
+ {
+ if (hba->radiusservers_s)
+ options[noptions++] =
+ CStringGetTextDatum(psprintf("radiusservers=%s", hba->radiusservers_s));
+
+ if (hba->radiussecrets_s)
+ options[noptions++] =
+ CStringGetTextDatum(psprintf("radiussecrets=%s", hba->radiussecrets_s));
+
+ if (hba->radiusidentifiers_s)
+ options[noptions++] =
+ CStringGetTextDatum(psprintf("radiusidentifiers=%s", hba->radiusidentifiers_s));
+
+ if (hba->radiusports_s)
+ options[noptions++] =
+ CStringGetTextDatum(psprintf("radiusports=%s", hba->radiusports_s));
+ }
+
+ /* If you add more options, consider increasing MAX_HBA_OPTIONS. */
+ Assert(noptions <= MAX_HBA_OPTIONS);
+
+ if (noptions > 0)
+ return construct_array(options, noptions, TEXTOID, -1, false, TYPALIGN_INT);
+ else
+ return NULL;
+}
+
+/* Number of columns in pg_hba_file_rules view */
+#define NUM_PG_HBA_FILE_RULES_ATTS 9
+
+/*
+ * fill_hba_line
+ * Build one row of pg_hba_file_rules view, add it to tuplestore.
+ *
+ * tuple_store: where to store data
+ * tupdesc: tuple descriptor for the view
+ * lineno: pg_hba.conf line number (must always be valid)
+ * hba: parsed line data (can be NULL, in which case err_msg should be set)
+ * err_msg: error message (NULL if none)
+ *
+ * Note: leaks memory, but we don't care since this is run in a short-lived
+ * memory context.
+ */
+static void
+fill_hba_line(Tuplestorestate *tuple_store, TupleDesc tupdesc,
+ int lineno, HbaLine *hba, const char *err_msg)
+{
+ Datum values[NUM_PG_HBA_FILE_RULES_ATTS];
+ bool nulls[NUM_PG_HBA_FILE_RULES_ATTS];
+ char buffer[NI_MAXHOST];
+ HeapTuple tuple;
+ int index;
+ ListCell *lc;
+ const char *typestr;
+ const char *addrstr;
+ const char *maskstr;
+ ArrayType *options;
+
+ Assert(tupdesc->natts == NUM_PG_HBA_FILE_RULES_ATTS);
+
+ memset(values, 0, sizeof(values));
+ memset(nulls, 0, sizeof(nulls));
+ index = 0;
+
+ /* line_number */
+ values[index++] = Int32GetDatum(lineno);
+
+ if (hba != NULL)
+ {
+ /* type */
+ /* Avoid a default: case so compiler will warn about missing cases */
+ typestr = NULL;
+ switch (hba->conntype)
+ {
+ case ctLocal:
+ typestr = "local";
+ break;
+ case ctHost:
+ typestr = "host";
+ break;
+ case ctHostSSL:
+ typestr = "hostssl";
+ break;
+ case ctHostNoSSL:
+ typestr = "hostnossl";
+ break;
+ case ctHostGSS:
+ typestr = "hostgssenc";
+ break;
+ case ctHostNoGSS:
+ typestr = "hostnogssenc";
+ break;
+ }
+ if (typestr)
+ values[index++] = CStringGetTextDatum(typestr);
+ else
+ nulls[index++] = true;
+
+ /* database */
+ if (hba->databases)
+ {
+ /*
+ * Flatten AuthToken list to string list. It might seem that we
+ * should re-quote any quoted tokens, but that has been rejected
+ * on the grounds that it makes it harder to compare the array
+ * elements to other system catalogs. That makes entries like
+ * "all" or "samerole" formally ambiguous ... but users who name
+ * databases/roles that way are inflicting their own pain.
+ */
+ List *names = NIL;
+
+ foreach(lc, hba->databases)
+ {
+ AuthToken *tok = lfirst(lc);
+
+ names = lappend(names, tok->string);
+ }
+ values[index++] = PointerGetDatum(strlist_to_textarray(names));
+ }
+ else
+ nulls[index++] = true;
+
+ /* user */
+ if (hba->roles)
+ {
+ /* Flatten AuthToken list to string list; see comment above */
+ List *roles = NIL;
+
+ foreach(lc, hba->roles)
+ {
+ AuthToken *tok = lfirst(lc);
+
+ roles = lappend(roles, tok->string);
+ }
+ values[index++] = PointerGetDatum(strlist_to_textarray(roles));
+ }
+ else
+ nulls[index++] = true;
+
+ /* address and netmask */
+ /* Avoid a default: case so compiler will warn about missing cases */
+ addrstr = maskstr = NULL;
+ switch (hba->ip_cmp_method)
+ {
+ case ipCmpMask:
+ if (hba->hostname)
+ {
+ addrstr = hba->hostname;
+ }
+ else
+ {
+ /*
+ * Note: if pg_getnameinfo_all fails, it'll set buffer to
+ * "???", which we want to return.
+ */
+ if (hba->addrlen > 0)
+ {
+ if (pg_getnameinfo_all(&hba->addr, hba->addrlen,
+ buffer, sizeof(buffer),
+ NULL, 0,
+ NI_NUMERICHOST) == 0)
+ clean_ipv6_addr(hba->addr.ss_family, buffer);
+ addrstr = pstrdup(buffer);
+ }
+ if (hba->masklen > 0)
+ {
+ if (pg_getnameinfo_all(&hba->mask, hba->masklen,
+ buffer, sizeof(buffer),
+ NULL, 0,
+ NI_NUMERICHOST) == 0)
+ clean_ipv6_addr(hba->mask.ss_family, buffer);
+ maskstr = pstrdup(buffer);
+ }
+ }
+ break;
+ case ipCmpAll:
+ addrstr = "all";
+ break;
+ case ipCmpSameHost:
+ addrstr = "samehost";
+ break;
+ case ipCmpSameNet:
+ addrstr = "samenet";
+ break;
+ }
+ if (addrstr)
+ values[index++] = CStringGetTextDatum(addrstr);
+ else
+ nulls[index++] = true;
+ if (maskstr)
+ values[index++] = CStringGetTextDatum(maskstr);
+ else
+ nulls[index++] = true;
+
+ /* auth_method */
+ values[index++] = CStringGetTextDatum(hba_authname(hba->auth_method));
+
+ /* options */
+ options = get_hba_options(hba);
+ if (options)
+ values[index++] = PointerGetDatum(options);
+ else
+ nulls[index++] = true;
+ }
+ else
+ {
+ /* no parsing result, so set relevant fields to nulls */
+ memset(&nulls[1], true, (NUM_PG_HBA_FILE_RULES_ATTS - 2) * sizeof(bool));
+ }
+
+ /* error */
+ if (err_msg)
+ values[NUM_PG_HBA_FILE_RULES_ATTS - 1] = CStringGetTextDatum(err_msg);
+ else
+ nulls[NUM_PG_HBA_FILE_RULES_ATTS - 1] = true;
+
+ tuple = heap_form_tuple(tupdesc, values, nulls);
+ tuplestore_puttuple(tuple_store, tuple);
+}
+
+/*
+ * fill_hba_view
+ * Read the pg_hba.conf file and fill the tuplestore with view records.
+ */
+static void
+fill_hba_view(Tuplestorestate *tuple_store, TupleDesc tupdesc)
+{
+ FILE *file;
+ List *hba_lines = NIL;
+ ListCell *line;
+ MemoryContext linecxt;
+ MemoryContext hbacxt;
+ MemoryContext oldcxt;
+
+ /*
+ * In the unlikely event that we can't open pg_hba.conf, we throw an
+ * error, rather than trying to report it via some sort of view entry.
+ * (Most other error conditions should result in a message in a view
+ * entry.)
+ */
+ file = AllocateFile(HbaFileName, "r");
+ if (file == NULL)
+ ereport(ERROR,
+ (errcode_for_file_access(),
+ errmsg("could not open configuration file \"%s\": %m",
+ HbaFileName)));
+
+ linecxt = tokenize_auth_file(HbaFileName, file, &hba_lines, DEBUG3);
+ FreeFile(file);
+
+ /* Now parse all the lines */
+ hbacxt = AllocSetContextCreate(CurrentMemoryContext,
+ "hba parser context",
+ ALLOCSET_SMALL_SIZES);
+ oldcxt = MemoryContextSwitchTo(hbacxt);
+ foreach(line, hba_lines)
+ {
+ TokenizedAuthLine *tok_line = (TokenizedAuthLine *) lfirst(line);
+ HbaLine *hbaline = NULL;
+
+ /* don't parse lines that already have errors */
+ if (tok_line->err_msg == NULL)
+ hbaline = parse_hba_line(tok_line, DEBUG3);
+
+ fill_hba_line(tuple_store, tupdesc, tok_line->line_num,
+ hbaline, tok_line->err_msg);
+ }
+
+ /* Free tokenizer memory */
+ MemoryContextDelete(linecxt);
+ /* Free parse_hba_line memory */
+ MemoryContextSwitchTo(oldcxt);
+ MemoryContextDelete(hbacxt);
+}
+
+/*
+ * pg_hba_file_rules
+ *
+ * SQL-accessible set-returning function to return all the entries in the
+ * pg_hba.conf file.
+ */
+Datum
+pg_hba_file_rules(PG_FUNCTION_ARGS)
+{
+ ReturnSetInfo *rsi;
+
+ /*
+ * Build tuplestore to hold the result rows. We must use the Materialize
+ * mode to be safe against HBA file changes while the cursor is open. It's
+ * also more efficient than having to look up our current position in the
+ * parsed list every time.
+ */
+ SetSingleFuncCall(fcinfo, 0);
+
+ /* Fill the tuplestore */
+ rsi = (ReturnSetInfo *) fcinfo->resultinfo;
+ fill_hba_view(rsi->setResult, rsi->setDesc);
+
+ PG_RETURN_NULL();
+}
diff --git a/src/include/libpq/hba.h b/src/include/libpq/hba.h
index 8d9f3821b12..13ecb329f80 100644
--- a/src/include/libpq/hba.h
+++ b/src/include/libpq/hba.h
@@ -132,6 +132,34 @@ typedef struct IdentLine
regex_t re;
} IdentLine;
+/*
+ * A single string token lexed from an authentication configuration file
+ * (pg_ident.conf or pg_hba.conf), together with whether the token has
+ * been quoted.
+ */
+typedef struct AuthToken
+{
+ char *string;
+ bool quoted;
+} AuthToken;
+
+/*
+ * TokenizedAuthLine represents one line lexed from an authentication
+ * configuration file. Each item in the "fields" list is a sub-list of
+ * AuthTokens. We don't emit a TokenizedAuthLine for empty or all-comment
+ * lines, so "fields" is never NIL (nor are any of its sub-lists).
+ *
+ * Exception: if an error occurs during tokenization, we might have
+ * fields == NIL, in which case err_msg != NULL.
+ */
+typedef struct TokenizedAuthLine
+{
+ List *fields; /* List of lists of AuthTokens */
+ int line_num; /* Line number */
+ char *raw_line; /* Raw line text */
+ char *err_msg; /* Error message if any */
+} TokenizedAuthLine;
+
/* kluge to avoid including libpq/libpq-be.h here */
typedef struct Port hbaPort;
@@ -142,6 +170,9 @@ extern void hba_getauthmethod(hbaPort *port);
extern int check_usermap(const char *usermap_name,
const char *pg_role, const char *auth_user,
bool case_sensitive);
+extern HbaLine *parse_hba_line(TokenizedAuthLine *tok_line, int elevel);
extern bool pg_isblank(const char c);
+extern MemoryContext tokenize_auth_file(const char *filename, FILE *file,
+ List **tok_lines, int elevel);
#endif /* HBA_H */
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 93d51905086..49688036a7e 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -153,6 +153,7 @@ AttrMissing
AttrNumber
AttributeOpts
AuthRequest
+AuthToken
AutoPrewarmSharedState
AutoVacOpts
AutoVacuumShmemStruct
@@ -1063,7 +1064,6 @@ HashState
HashTapeInfo
HashValueFunc
HbaLine
-HbaToken
HeadlineJsonState
HeadlineParsedText
HeadlineWordEntry
@@ -2699,7 +2699,7 @@ ToastTupleContext
ToastedAttribute
TocEntry
TokenAuxData
-TokenizedLine
+TokenizedAuthLine
TrackItem
TransInvalidationInfo
TransState