mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-09 08:10:09 +08:00
Add system view pg_ident_file_mappings
This view is similar to pg_hba_file_rules view, except that it is associated with the parsing of pg_ident.conf. Similarly to its cousin, this view is useful to check via SQL if changes planned in pg_ident.conf would work upon reload or restart, or to diagnose a previous failure. Bumps catalog version. Author: Julien Rouhaud Reviewed-by: Aleksander Alekseev, Michael Paquier Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
This commit is contained in:
parent
091a971bb5
commit
a2c84990be
@ -9591,6 +9591,11 @@ SCRAM-SHA-256$<replaceable><iteration count></replaceable>:<replaceable>&l
|
||||
<entry>summary of client authentication configuration file contents</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><link linkend="view-pg-ident-file-mappings"><structname>pg_ident_file_mappings</structname></link></entry>
|
||||
<entry>summary of client user name mapping configuration file contents</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><link linkend="view-pg-indexes"><structname>pg_indexes</structname></link></entry>
|
||||
<entry>indexes</entry>
|
||||
@ -10589,6 +10594,108 @@ SCRAM-SHA-256$<replaceable><iteration count></replaceable>:<replaceable>&l
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="view-pg-ident-file-mappings">
|
||||
<title><structname>pg_ident_file_mappings</structname></title>
|
||||
|
||||
<indexterm zone="view-pg-ident-file-mappings">
|
||||
<primary>pg_ident_file_mappings</primary>
|
||||
</indexterm>
|
||||
|
||||
<para>
|
||||
The view <structname>pg_ident_file_mappings</structname> provides a summary
|
||||
of the contents of the client user name mapping configuration file,
|
||||
<link linkend="auth-username-maps"><filename>pg_ident.conf</filename></link>.
|
||||
A row appears in this view for each non-empty, non-comment line in the file,
|
||||
with annotations indicating whether the rule could be applied successfully.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This view can be helpful for checking whether planned changes in the
|
||||
authentication configuration file will work, or for diagnosing a previous
|
||||
failure. Note that this view reports on the <emphasis>current</emphasis>
|
||||
contents of the file, not on what was last loaded by the server.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
By default, the <structname>pg_ident_file_mappings</structname> view can be
|
||||
read only by superusers.
|
||||
</para>
|
||||
|
||||
<table>
|
||||
<title><structname>pg_ident_file_mappings</structname> Columns</title> <tgroup
|
||||
cols="1">
|
||||
<thead>
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
Column Type
|
||||
</para>
|
||||
<para>
|
||||
Description
|
||||
</para></entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>line_number</structfield> <type>int4</type>
|
||||
</para>
|
||||
<para>
|
||||
Line number of this rule in <filename>pg_ident.conf</filename>
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>map_name</structfield> <type>text</type>
|
||||
</para>
|
||||
<para>
|
||||
Name of the map
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>sys_name</structfield> <type>text</type>
|
||||
</para>
|
||||
<para>
|
||||
Detected user name of the client
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>pg_username</structfield> <type>text</type>
|
||||
</para>
|
||||
<para>
|
||||
Requested PostgreSQL user name
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="catalog_table_entry"><para role="column_definition">
|
||||
<structfield>error</structfield> <type>text</type>
|
||||
</para>
|
||||
<para>
|
||||
If not <literal>NULL</literal>, an error message indicating why this
|
||||
line could not be processed
|
||||
</para></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
<para>
|
||||
Usually, a row reflecting an incorrect entry will have values for only
|
||||
the <structfield>line_number</structfield> and <structfield>error</structfield> fields.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
See <xref linkend="client-authentication"/> for more information about
|
||||
client authentication configuration.
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="view-pg-indexes">
|
||||
<title><structname>pg_indexes</structname></title>
|
||||
|
||||
|
@ -896,6 +896,16 @@ mymap /^(.*)@otherdomain\.com$ guest
|
||||
-HUP</literal>) to make it re-read the file.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The system view
|
||||
<link linkend="view-pg-ident-file-mappings"><structname>pg_ident_file_mappings</structname></link>
|
||||
can be helpful for pre-testing changes to the
|
||||
<filename>pg_ident.conf</filename> file, or for diagnosing problems if
|
||||
loading of the file did not have the desired effects. Rows in the view with
|
||||
non-null <structfield>error</structfield> fields indicate problems in the
|
||||
corresponding lines of the file.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
A <filename>pg_ident.conf</filename> file that could be used in
|
||||
conjunction with the <filename>pg_hba.conf</filename> file in <xref
|
||||
|
@ -25475,8 +25475,9 @@ SELECT collation for ('foo' COLLATE "de_DE");
|
||||
sending a <systemitem>SIGHUP</systemitem> signal to the postmaster
|
||||
process, which in turn sends <systemitem>SIGHUP</systemitem> to each
|
||||
of its children.) You can use the
|
||||
<link linkend="view-pg-file-settings"><structname>pg_file_settings</structname></link> and
|
||||
<link linkend="view-pg-hba-file-rules"><structname>pg_hba_file_rules</structname></link> views
|
||||
<link linkend="view-pg-file-settings"><structname>pg_file_settings</structname></link>,
|
||||
<link linkend="view-pg-hba-file-rules"><structname>pg_hba_file_rules</structname></link> and
|
||||
<link linkend="view-pg-hba-file-rules"><structname>pg_ident_file_mappings</structname></link> views
|
||||
to check the configuration files for possible errors, before reloading.
|
||||
</para></entry>
|
||||
</row>
|
||||
|
@ -617,6 +617,12 @@ CREATE VIEW pg_hba_file_rules AS
|
||||
REVOKE ALL ON pg_hba_file_rules FROM PUBLIC;
|
||||
REVOKE EXECUTE ON FUNCTION pg_hba_file_rules() FROM PUBLIC;
|
||||
|
||||
CREATE VIEW pg_ident_file_mappings AS
|
||||
SELECT * FROM pg_ident_file_mappings() AS A;
|
||||
|
||||
REVOKE ALL ON pg_ident_file_mappings FROM PUBLIC;
|
||||
REVOKE EXECUTE ON FUNCTION pg_ident_file_mappings() FROM PUBLIC;
|
||||
|
||||
CREATE VIEW pg_timezone_abbrevs AS
|
||||
SELECT * FROM pg_timezone_abbrevs();
|
||||
|
||||
|
@ -887,25 +887,22 @@ do { \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Macros for handling pg_ident problems.
|
||||
* Much as above, but currently the message level is hardwired as LOG
|
||||
* and there is no provision for an err_msg string.
|
||||
* Macros for handling pg_ident problems, similar as above.
|
||||
*
|
||||
* IDENT_FIELD_ABSENT:
|
||||
* Log a message and exit the function if the given ident field ListCell is
|
||||
* not populated.
|
||||
* Reports when the given ident field ListCell is not populated.
|
||||
*
|
||||
* IDENT_MULTI_VALUE:
|
||||
* Log a message and exit the function if the given ident token List has more
|
||||
* than one element.
|
||||
* Reports when the given ident token List has more than one element.
|
||||
*/
|
||||
#define IDENT_FIELD_ABSENT(field) \
|
||||
do { \
|
||||
if (!field) { \
|
||||
ereport(LOG, \
|
||||
ereport(elevel, \
|
||||
(errcode(ERRCODE_CONFIG_FILE_ERROR), \
|
||||
errmsg("missing entry in file \"%s\" at end of line %d", \
|
||||
IdentFileName, line_num))); \
|
||||
*err_msg = psprintf("missing entry at end of line"); \
|
||||
return NULL; \
|
||||
} \
|
||||
} while (0)
|
||||
@ -913,11 +910,12 @@ do { \
|
||||
#define IDENT_MULTI_VALUE(tokens) \
|
||||
do { \
|
||||
if (tokens->length > 1) { \
|
||||
ereport(LOG, \
|
||||
ereport(elevel, \
|
||||
(errcode(ERRCODE_CONFIG_FILE_ERROR), \
|
||||
errmsg("multiple values in ident field"), \
|
||||
errcontext("line %d of configuration file \"%s\"", \
|
||||
line_num, IdentFileName))); \
|
||||
*err_msg = psprintf("multiple values in ident field"); \
|
||||
return NULL; \
|
||||
} \
|
||||
} while (0)
|
||||
@ -2306,7 +2304,8 @@ load_hba(void)
|
||||
* Parse one tokenised line from the ident config file and store the result in
|
||||
* an IdentLine structure.
|
||||
*
|
||||
* If parsing fails, log a message and return NULL.
|
||||
* If parsing fails, log a message at ereport level elevel, store an error
|
||||
* string in tok_line->err_msg and return NULL.
|
||||
*
|
||||
* If ident_user is a regular expression (ie. begins with a slash), it is
|
||||
* compiled and stored in IdentLine structure.
|
||||
@ -2315,10 +2314,11 @@ load_hba(void)
|
||||
* to have set a memory context that will be reset if this function returns
|
||||
* NULL.
|
||||
*/
|
||||
static IdentLine *
|
||||
parse_ident_line(TokenizedAuthLine *tok_line)
|
||||
IdentLine *
|
||||
parse_ident_line(TokenizedAuthLine *tok_line, int elevel)
|
||||
{
|
||||
int line_num = tok_line->line_num;
|
||||
char **err_msg = &tok_line->err_msg;
|
||||
ListCell *field;
|
||||
List *tokens;
|
||||
AuthToken *token;
|
||||
@ -2372,11 +2372,14 @@ parse_ident_line(TokenizedAuthLine *tok_line)
|
||||
char errstr[100];
|
||||
|
||||
pg_regerror(r, &parsedline->re, errstr, sizeof(errstr));
|
||||
ereport(LOG,
|
||||
ereport(elevel,
|
||||
(errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
|
||||
errmsg("invalid regular expression \"%s\": %s",
|
||||
parsedline->ident_user + 1, errstr)));
|
||||
|
||||
*err_msg = psprintf("invalid regular expression \"%s\": %s",
|
||||
parsedline->ident_user + 1, errstr);
|
||||
|
||||
pfree(wstr);
|
||||
return NULL;
|
||||
}
|
||||
@ -2627,7 +2630,7 @@ load_ident(void)
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((newline = parse_ident_line(tok_line)) == NULL)
|
||||
if ((newline = parse_ident_line(tok_line, LOG)) == NULL)
|
||||
{
|
||||
/* Parse error; remember there's trouble */
|
||||
ok = false;
|
||||
|
@ -28,6 +28,9 @@ 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);
|
||||
static void fill_ident_line(Tuplestorestate *tuple_store, TupleDesc tupdesc,
|
||||
int lineno, IdentLine *ident, const char *err_msg);
|
||||
static void fill_ident_view(Tuplestorestate *tuple_store, TupleDesc tupdesc);
|
||||
|
||||
|
||||
/*
|
||||
@ -426,3 +429,136 @@ pg_hba_file_rules(PG_FUNCTION_ARGS)
|
||||
|
||||
PG_RETURN_NULL();
|
||||
}
|
||||
|
||||
/* Number of columns in pg_ident_file_mappings view */
|
||||
#define NUM_PG_IDENT_FILE_MAPPINGS_ATTS 5
|
||||
|
||||
/*
|
||||
* fill_ident_line: build one row of pg_ident_file_mappings view, add it to
|
||||
* tuplestore
|
||||
*
|
||||
* tuple_store: where to store data
|
||||
* tupdesc: tuple descriptor for the view
|
||||
* lineno: pg_ident.conf line number (must always be valid)
|
||||
* ident: 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_ident_line(Tuplestorestate *tuple_store, TupleDesc tupdesc,
|
||||
int lineno, IdentLine *ident, const char *err_msg)
|
||||
{
|
||||
Datum values[NUM_PG_IDENT_FILE_MAPPINGS_ATTS];
|
||||
bool nulls[NUM_PG_IDENT_FILE_MAPPINGS_ATTS];
|
||||
HeapTuple tuple;
|
||||
int index;
|
||||
|
||||
Assert(tupdesc->natts == NUM_PG_IDENT_FILE_MAPPINGS_ATTS);
|
||||
|
||||
memset(values, 0, sizeof(values));
|
||||
memset(nulls, 0, sizeof(nulls));
|
||||
index = 0;
|
||||
|
||||
/* line_number */
|
||||
values[index++] = Int32GetDatum(lineno);
|
||||
|
||||
if (ident != NULL)
|
||||
{
|
||||
values[index++] = CStringGetTextDatum(ident->usermap);
|
||||
values[index++] = CStringGetTextDatum(ident->ident_user);
|
||||
values[index++] = CStringGetTextDatum(ident->pg_role);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no parsing result, so set relevant fields to nulls */
|
||||
memset(&nulls[1], true, (NUM_PG_IDENT_FILE_MAPPINGS_ATTS - 2) * sizeof(bool));
|
||||
}
|
||||
|
||||
/* error */
|
||||
if (err_msg)
|
||||
values[NUM_PG_IDENT_FILE_MAPPINGS_ATTS - 1] = CStringGetTextDatum(err_msg);
|
||||
else
|
||||
nulls[NUM_PG_IDENT_FILE_MAPPINGS_ATTS - 1] = true;
|
||||
|
||||
tuple = heap_form_tuple(tupdesc, values, nulls);
|
||||
tuplestore_puttuple(tuple_store, tuple);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the pg_ident.conf file and fill the tuplestore with view records.
|
||||
*/
|
||||
static void
|
||||
fill_ident_view(Tuplestorestate *tuple_store, TupleDesc tupdesc)
|
||||
{
|
||||
FILE *file;
|
||||
List *ident_lines = NIL;
|
||||
ListCell *line;
|
||||
MemoryContext linecxt;
|
||||
MemoryContext identcxt;
|
||||
MemoryContext oldcxt;
|
||||
|
||||
/*
|
||||
* In the unlikely event that we can't open pg_ident.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(IdentFileName, "r");
|
||||
if (file == NULL)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not open usermap file \"%s\": %m",
|
||||
IdentFileName)));
|
||||
|
||||
linecxt = tokenize_auth_file(HbaFileName, file, &ident_lines, DEBUG3);
|
||||
FreeFile(file);
|
||||
|
||||
/* Now parse all the lines */
|
||||
identcxt = AllocSetContextCreate(CurrentMemoryContext,
|
||||
"ident parser context",
|
||||
ALLOCSET_SMALL_SIZES);
|
||||
oldcxt = MemoryContextSwitchTo(identcxt);
|
||||
foreach(line, ident_lines)
|
||||
{
|
||||
TokenizedAuthLine *tok_line = (TokenizedAuthLine *) lfirst(line);
|
||||
IdentLine *identline = NULL;
|
||||
|
||||
/* don't parse lines that already have errors */
|
||||
if (tok_line->err_msg == NULL)
|
||||
identline = parse_ident_line(tok_line, DEBUG3);
|
||||
|
||||
fill_ident_line(tuple_store, tupdesc, tok_line->line_num, identline,
|
||||
tok_line->err_msg);
|
||||
}
|
||||
|
||||
/* Free tokenizer memory */
|
||||
MemoryContextDelete(linecxt);
|
||||
/* Free parse_ident_line memory */
|
||||
MemoryContextSwitchTo(oldcxt);
|
||||
MemoryContextDelete(identcxt);
|
||||
}
|
||||
|
||||
/*
|
||||
* SQL-accessible SRF to return all the entries in the pg_ident.conf file.
|
||||
*/
|
||||
Datum
|
||||
pg_ident_file_mappings(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_ident_view(rsi->setResult, rsi->setDesc);
|
||||
|
||||
PG_RETURN_NULL();
|
||||
}
|
||||
|
@ -53,6 +53,6 @@
|
||||
*/
|
||||
|
||||
/* yyyymmddN */
|
||||
#define CATALOG_VERSION_NO 202203272
|
||||
#define CATALOG_VERSION_NO 202203291
|
||||
|
||||
#endif
|
||||
|
@ -6115,6 +6115,12 @@
|
||||
proargmodes => '{o,o,o,o,o,o,o,o,o}',
|
||||
proargnames => '{line_number,type,database,user_name,address,netmask,auth_method,options,error}',
|
||||
prosrc => 'pg_hba_file_rules' },
|
||||
{ oid => '9556', descr => 'show pg_ident.conf mappings',
|
||||
proname => 'pg_ident_file_mappings', prorows => '1000', proretset => 't',
|
||||
provolatile => 'v', prorettype => 'record', proargtypes => '',
|
||||
proallargtypes => '{int4,text,text,text,text}', proargmodes => '{o,o,o,o,o}',
|
||||
proargnames => '{line_number,map_name,sys_name,pg_username,error}',
|
||||
prosrc => 'pg_ident_file_mappings' },
|
||||
{ oid => '1371', descr => 'view system lock information',
|
||||
proname => 'pg_lock_status', prorows => '1000', proretset => 't',
|
||||
provolatile => 'v', prorettype => 'record', proargtypes => '',
|
||||
|
@ -171,6 +171,7 @@ 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 IdentLine *parse_ident_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);
|
||||
|
@ -1347,6 +1347,12 @@ pg_hba_file_rules| SELECT a.line_number,
|
||||
a.options,
|
||||
a.error
|
||||
FROM pg_hba_file_rules() a(line_number, type, database, user_name, address, netmask, auth_method, options, error);
|
||||
pg_ident_file_mappings| SELECT a.line_number,
|
||||
a.map_name,
|
||||
a.sys_name,
|
||||
a.pg_username,
|
||||
a.error
|
||||
FROM pg_ident_file_mappings() a(line_number, map_name, sys_name, pg_username, error);
|
||||
pg_indexes| SELECT n.nspname AS schemaname,
|
||||
c.relname AS tablename,
|
||||
i.relname AS indexname,
|
||||
|
@ -56,6 +56,14 @@ select count(*) > 0 as ok, count(*) FILTER (WHERE error IS NOT NULL) = 0 AS no_e
|
||||
t | t
|
||||
(1 row)
|
||||
|
||||
-- There may be no rules, and there should be no errors.
|
||||
select count(*) >= 0 as ok, count(*) FILTER (WHERE error IS NOT NULL) = 0 AS no_err
|
||||
from pg_ident_file_mappings;
|
||||
ok | no_err
|
||||
----+--------
|
||||
t | t
|
||||
(1 row)
|
||||
|
||||
-- There will surely be at least one active lock
|
||||
select count(*) > 0 as ok from pg_locks;
|
||||
ok
|
||||
|
@ -29,6 +29,10 @@ select count(*) >= 0 as ok from pg_file_settings;
|
||||
select count(*) > 0 as ok, count(*) FILTER (WHERE error IS NOT NULL) = 0 AS no_err
|
||||
from pg_hba_file_rules;
|
||||
|
||||
-- There may be no rules, and there should be no errors.
|
||||
select count(*) >= 0 as ok, count(*) FILTER (WHERE error IS NOT NULL) = 0 AS no_err
|
||||
from pg_ident_file_mappings;
|
||||
|
||||
-- There will surely be at least one active lock
|
||||
select count(*) > 0 as ok from pg_locks;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user