diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 4930506..d4aa69c 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -7555,6 +7555,11 @@
+ pg_hba_rules
+ summary of client authentication configuration file contents
+
+
+ pg_groupgroups of database users
@@ -8098,6 +8103,116 @@
+
+ pg_hba_rules
+
+
+ pg_hba_rules
+
+
+
+ The view pg_hba_rules provides a summary of
+ the contents of the client authentication configuration file. A row
+ appears in this view for each entry appearing in the file, with annotations
+ indicating whether the rule could be applied successfully.
+
+
+
+ pg_hba_rules> Columns
+
+
+
+
+ Name
+ Type
+ Description
+
+
+
+
+ line_number
+ integer
+
+ Line number of the client authentication rule in
+ pg_hba.conf file
+
+
+
+ type
+ text
+ Type of connection
+
+
+ database
+ text[]
+ List of database names
+
+
+ user_name
+ text[]
+ List of user names
+
+
+ address
+ text
+
+ Address specifies the set of hosts the record matches.
+ It can be a host name, or it is made up of an IP address
+ or keywords such as (all,
+ samehost and samenet).
+
+
+
+ netmask
+ text
+ Address mask if exist
+
+
+ auth_method
+ text
+ Authentication method
+
+
+ options
+ text[]
+ Configuration options set for authentication method
+
+
+ error
+ text
+
+ If not null, an error message indicating why this
+ rule could not be loaded.
+
+
+
+
+
+
+
+ If the configuration file contains any problems, error field
+ indicating the problem of that rule. Following is the sample output of the view.
+
+
+
+SELECT line_number, type, database, user_name, auth_method FROM pg_hba_rules;
+
+
+
+ line_number | type | database | user_name | auth_method
+-------------+-------+----------+-----------+-------------
+ 84 | local | {all} | {all} | trust
+ 86 | host | {all} | {all} | trust
+ 88 | host | {all} | {all} | trust
+(3 rows)
+
+
+
+ See for more information about the various
+ ways to change client authentication configuration.
+
+
+
pg_group
diff --git a/doc/src/sgml/client-auth.sgml b/doc/src/sgml/client-auth.sgml
index dda5891..f20486c 100644
--- a/doc/src/sgml/client-auth.sgml
+++ b/doc/src/sgml/client-auth.sgml
@@ -54,6 +54,13 @@
database user names and OS user names.
+
+ The system view
+ pg_hba_rules
+ can be helpful for pre-testing changes to the client authentication configuration file, or for
+ diagnosing problems if loading of file did not have the desired effects.
+
+
The pg_hba.conf File
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 07f291b..f7de2a6 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -450,6 +450,12 @@ CREATE VIEW pg_file_settings AS
REVOKE ALL on pg_file_settings FROM PUBLIC;
REVOKE EXECUTE ON FUNCTION pg_show_all_file_settings() FROM PUBLIC;
+CREATE VIEW pg_hba_rules AS
+ SELECT * FROM pg_hba_rules() AS A;
+
+REVOKE ALL on pg_hba_rules FROM PUBLIC;
+REVOKE EXECUTE ON FUNCTION pg_hba_rules() FROM PUBLIC;
+
CREATE VIEW pg_timezone_abbrevs AS
SELECT * FROM pg_timezone_abbrevs();
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 07f046f..ba73b28 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -25,15 +25,22 @@
#include
#include
+#include "access/htup_details.h"
+#include "catalog/objectaddress.h"
#include "catalog/pg_collation.h"
+#include "catalog/pg_type.h"
#include "common/ip.h"
+#include "funcapi.h"
#include "libpq/ifaddr.h"
#include "libpq/libpq.h"
+#include "miscadmin.h"
#include "postmaster/postmaster.h"
#include "regex/regex.h"
#include "replication/walsender.h"
#include "storage/fd.h"
+#include "storage/ipc.h"
#include "utils/acl.h"
+#include "utils/builtins.h"
#include "utils/guc.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
@@ -75,6 +82,15 @@ typedef struct HbaToken
bool quoted;
} HbaToken;
+
+/* Context to use with fill_hba_line function. */
+typedef struct FillHbaLineCxt
+{
+ MemoryContext memcxt;
+ TupleDesc tupdesc;
+ Tuplestorestate *tuple_store;
+} FillHbaLineCxt;
+
/*
* pre-parsed content of HBA config file: list of HbaLine structs.
* parsed_hba_context is the memory context where it lives.
@@ -93,13 +109,19 @@ static MemoryContext parsed_hba_context = NULL;
static List *parsed_ident_lines = NIL;
static MemoryContext parsed_ident_context = NULL;
-
+static void tokenize_file_failure_callback(int code, Datum arg);
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,
- int line_num);
+ int line_num, int level, char **err_msg);
+static Datum getauthmethod(UserAuth auth_method);
+static void fill_hba_auth_opt(Datum *optdata, char *optname, char *optvalue);
+static Datum gethba_options(HbaLine *hba);
+static void fill_hba_line(FillHbaLineCxt *context, int lineno,
+ HbaLine *hba, const char *err_msg);
+static void fill_hba(FillHbaLineCxt *context);
/*
* isblank() exists in the ISO C99 spec, but it's not very portable yet,
@@ -336,8 +358,12 @@ tokenize_inc_file(List *tokens,
return tokens;
}
- /* There is possible recursion here if the file contains @ */
- linecxt = tokenize_file(inc_fullname, inc_file, &inc_lines, &inc_line_nums, NULL);
+ PG_ENSURE_ERROR_CLEANUP(tokenize_file_failure_callback, PointerGetDatum(inc_file));
+ {
+ /* There is possible recursion here if the file contains @ */
+ linecxt = tokenize_file(inc_fullname, inc_file, &inc_lines, &inc_line_nums, NULL);
+ }
+ PG_END_ENSURE_ERROR_CLEANUP(tokenize_file_failure_callback, PointerGetDatum(inc_file));
FreeFile(inc_file);
pfree(inc_fullname);
@@ -365,6 +391,15 @@ tokenize_inc_file(List *tokens,
return tokens;
}
+/* Error cleanup callback for tokenize_file */
+static void
+tokenize_file_failure_callback(int code, Datum arg)
+{
+ FILE *file = (FILE *) DatumGetPointer(arg);
+
+ FreeFile(file);
+}
+
/*
* 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.
@@ -748,11 +783,12 @@ check_same_host_or_net(SockAddr *raddr, IPCompareMethod method)
* reporting error if it's not.
*/
#define INVALID_AUTH_OPTION(optname, validmethods) do {\
- ereport(LOG, \
+ *err_msg = psprintf(_("authentication option \"%s\" is only valid for authentication methods %s"), \
+ optname, _(validmethods)); \
+ ereport(level, \
(errcode(ERRCODE_CONFIG_FILE_ERROR), \
/* translator: the second %s is a list of auth methods */ \
- errmsg("authentication option \"%s\" is only valid for authentication methods %s", \
- optname, _(validmethods)), \
+ errmsg("%s", *err_msg), \
errcontext("line %d of configuration file \"%s\"", \
line_num, HbaFileName))); \
return false; \
@@ -765,10 +801,11 @@ check_same_host_or_net(SockAddr *raddr, IPCompareMethod method)
#define MANDATORY_AUTH_ARG(argvar, argname, authname) do {\
if (argvar == NULL) {\
- ereport(LOG, \
+ *err_msg = psprintf(_("authentication method \"%s\" requires argument \"%s\" to be set"), \
+ authname, argname); \
+ ereport(level, \
(errcode(ERRCODE_CONFIG_FILE_ERROR), \
- errmsg("authentication method \"%s\" requires argument \"%s\" to be set", \
- authname, argname), \
+ errmsg("%s", *err_msg), \
errcontext("line %d of configuration file \"%s\"", \
line_num, HbaFileName))); \
return NULL; \
@@ -818,7 +855,8 @@ check_same_host_or_net(SockAddr *raddr, IPCompareMethod method)
* NULL.
*/
static HbaLine *
-parse_hba_line(List *line, int line_num, char *raw_line)
+parse_hba_line(List *line, int line_num, char *raw_line,
+ int level, char **err_msg)
{
char *str;
struct addrinfo *gai_result;
@@ -841,9 +879,10 @@ parse_hba_line(List *line, int line_num, char *raw_line)
tokens = lfirst(field);
if (tokens->length > 1)
{
- ereport(LOG,
+ *err_msg = pstrdup(_("multiple values specified for connection type"));
+ ereport(level,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("multiple values specified for connection type"),
+ errmsg("%s", *err_msg),
errhint("Specify exactly one connection type per line."),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
@@ -855,9 +894,10 @@ parse_hba_line(List *line, int line_num, char *raw_line)
#ifdef HAVE_UNIX_SOCKETS
parsedline->conntype = ctLocal;
#else
- ereport(LOG,
+ *err_msg = pstrdup(_("local connections are not supported by this build"));
+ ereport(level,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("local connections are not supported by this build"),
+ errmsg("%s", *err_msg),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
@@ -874,16 +914,20 @@ parse_hba_line(List *line, int line_num, char *raw_line)
/* Log a warning if SSL support is not active */
#ifdef USE_SSL
if (!EnableSSL)
- ereport(LOG,
+ {
+ *err_msg = pstrdup(_("hostssl record cannot match because SSL is disabled"));
+ ereport(level,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("hostssl record cannot match because SSL is disabled"),
+ errmsg("%s", *err_msg),
errhint("Set ssl = on in postgresql.conf."),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
+ }
#else
- ereport(LOG,
+ *err_msg = pstrdup(_("hostssl record cannot match because SSL is not supported by this build"));
+ ereport(level,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("hostssl record cannot match because SSL is not supported by this build"),
+ errmsg("%s", *err_msg),
errhint("Compile with --with-openssl to use SSL connections."),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
@@ -901,10 +945,11 @@ parse_hba_line(List *line, int line_num, char *raw_line)
} /* record type */
else
{
- ereport(LOG,
+ *err_msg = psprintf(_("invalid connection type \"%s\""),
+ token->string);
+ ereport(level,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("invalid connection type \"%s\"",
- token->string),
+ errmsg("%s", *err_msg),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
@@ -914,9 +959,10 @@ parse_hba_line(List *line, int line_num, char *raw_line)
field = lnext(field);
if (!field)
{
- ereport(LOG,
+ *err_msg = pstrdup(_("end-of-line before database specification"));
+ ereport(level,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("end-of-line before database specification"),
+ errmsg("%s", *err_msg),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
@@ -933,9 +979,10 @@ parse_hba_line(List *line, int line_num, char *raw_line)
field = lnext(field);
if (!field)
{
- ereport(LOG,
+ *err_msg = pstrdup(_("end-of-line before role specification"));
+ ereport(level,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("end-of-line before role specification"),
+ errmsg("%s", *err_msg),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
@@ -954,9 +1001,10 @@ parse_hba_line(List *line, int line_num, char *raw_line)
field = lnext(field);
if (!field)
{
- ereport(LOG,
+ *err_msg = pstrdup(_("end-of-line before IP address specification"));
+ ereport(level,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("end-of-line before IP address specification"),
+ errmsg("%s", *err_msg),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
@@ -964,9 +1012,10 @@ parse_hba_line(List *line, int line_num, char *raw_line)
tokens = lfirst(field);
if (tokens->length > 1)
{
- ereport(LOG,
+ *err_msg = pstrdup(_("multiple values specified for host address"));
+ ereport(level,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("multiple values specified for host address"),
+ errmsg("%s", *err_msg),
errhint("Specify one address range per line."),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
@@ -1019,10 +1068,11 @@ parse_hba_line(List *line, int line_num, char *raw_line)
parsedline->hostname = str;
else
{
- ereport(LOG,
+ *err_msg = psprintf(_("invalid IP address \"%s\": %s"),
+ str, gai_strerror(ret));
+ ereport(level,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("invalid IP address \"%s\": %s",
- str, gai_strerror(ret)),
+ errmsg("%s", *err_msg),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
if (gai_result)
@@ -1037,10 +1087,11 @@ parse_hba_line(List *line, int line_num, char *raw_line)
{
if (parsedline->hostname)
{
- ereport(LOG,
+ *err_msg = psprintf(_("specifying both host name and CIDR mask is invalid: \"%s\""),
+ token->string);
+ ereport(level,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("specifying both host name and CIDR mask is invalid: \"%s\"",
- token->string),
+ errmsg("%s", *err_msg),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
@@ -1049,10 +1100,11 @@ parse_hba_line(List *line, int line_num, char *raw_line)
if (pg_sockaddr_cidr_mask(&parsedline->mask, cidr_slash + 1,
parsedline->addr.ss_family) < 0)
{
- ereport(LOG,
+ *err_msg = psprintf(_("invalid CIDR mask in address \"%s\""),
+ token->string);
+ ereport(level,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("invalid CIDR mask in address \"%s\"",
- token->string),
+ errmsg("%s", *err_msg),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
@@ -1066,9 +1118,10 @@ parse_hba_line(List *line, int line_num, char *raw_line)
field = lnext(field);
if (!field)
{
- ereport(LOG,
+ *err_msg = pstrdup(_("end-of-line before netmask specification"));
+ ereport(level,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("end-of-line before netmask specification"),
+ errmsg("%s", *err_msg),
errhint("Specify an address range in CIDR notation, or provide a separate netmask."),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
@@ -1077,9 +1130,10 @@ parse_hba_line(List *line, int line_num, char *raw_line)
tokens = lfirst(field);
if (tokens->length > 1)
{
- ereport(LOG,
+ *err_msg = pstrdup(_("multiple values specified for netmask"));
+ ereport(level,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("multiple values specified for netmask"),
+ errmsg("%s", *err_msg),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
@@ -1090,10 +1144,11 @@ parse_hba_line(List *line, int line_num, char *raw_line)
&hints, &gai_result);
if (ret || !gai_result)
{
- ereport(LOG,
+ *err_msg = psprintf(_("invalid IP mask \"%s\": %s"),
+ token->string, gai_strerror(ret));
+ ereport(level,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("invalid IP mask \"%s\": %s",
- token->string, gai_strerror(ret)),
+ errmsg("%s", *err_msg),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
if (gai_result)
@@ -1107,9 +1162,10 @@ parse_hba_line(List *line, int line_num, char *raw_line)
if (parsedline->addr.ss_family != parsedline->mask.ss_family)
{
- ereport(LOG,
+ *err_msg = pstrdup(_("IP address and mask do not match"));
+ ereport(level,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("IP address and mask do not match"),
+ errmsg("%s", *err_msg),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
@@ -1122,9 +1178,10 @@ parse_hba_line(List *line, int line_num, char *raw_line)
field = lnext(field);
if (!field)
{
- ereport(LOG,
+ *err_msg = pstrdup(_("end-of-line before authentication method"));
+ ereport(level,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("end-of-line before authentication method"),
+ errmsg("%s", *err_msg),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
@@ -1132,9 +1189,10 @@ parse_hba_line(List *line, int line_num, char *raw_line)
tokens = lfirst(field);
if (tokens->length > 1)
{
- ereport(LOG,
+ *err_msg = pstrdup(_("multiple values specified for authentication type"));
+ ereport(level,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("multiple values specified for authentication type"),
+ errmsg("%s", *err_msg),
errhint("Specify exactly one authentication type per line."),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
@@ -1169,9 +1227,10 @@ parse_hba_line(List *line, int line_num, char *raw_line)
{
if (Db_user_namespace)
{
- ereport(LOG,
+ *err_msg = pstrdup(_("MD5 authentication is not supported when \"db_user_namespace\" is enabled"));
+ ereport(level,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("MD5 authentication is not supported when \"db_user_namespace\" is enabled"),
+ errmsg("%s", *err_msg),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
@@ -1206,10 +1265,11 @@ parse_hba_line(List *line, int line_num, char *raw_line)
parsedline->auth_method = uaRADIUS;
else
{
- ereport(LOG,
+ *err_msg = psprintf(_("invalid authentication method \"%s\""),
+ token->string);
+ ereport(level,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("invalid authentication method \"%s\"",
- token->string),
+ errmsg("%s", *err_msg),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
@@ -1217,10 +1277,11 @@ parse_hba_line(List *line, int line_num, char *raw_line)
if (unsupauth)
{
- ereport(LOG,
+ *err_msg = psprintf(_("invalid authentication method \"%s\": not supported by this build"),
+ token->string);
+ ereport(level,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("invalid authentication method \"%s\": not supported by this build",
- token->string),
+ errmsg("%s", *err_msg),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
@@ -1238,9 +1299,10 @@ parse_hba_line(List *line, int line_num, char *raw_line)
if (parsedline->conntype == ctLocal &&
parsedline->auth_method == uaGSS)
{
- ereport(LOG,
+ *err_msg = pstrdup(_("gssapi authentication is not supported on local sockets"));
+ ereport(level,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("gssapi authentication is not supported on local sockets"),
+ errmsg("%s", *err_msg),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
@@ -1249,9 +1311,10 @@ parse_hba_line(List *line, int line_num, char *raw_line)
if (parsedline->conntype != ctLocal &&
parsedline->auth_method == uaPeer)
{
- ereport(LOG,
+ *err_msg = pstrdup(_("peer authentication is only supported on local sockets"));
+ ereport(level,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("peer authentication is only supported on local sockets"),
+ errmsg("%s", *err_msg),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
@@ -1266,9 +1329,10 @@ parse_hba_line(List *line, int line_num, char *raw_line)
if (parsedline->conntype != ctHostSSL &&
parsedline->auth_method == uaCert)
{
- ereport(LOG,
+ *err_msg = pstrdup(_("cert authentication is only supported on hostssl connections"));
+ ereport(level,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("cert authentication is only supported on hostssl connections"),
+ errmsg("%s", *err_msg),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
@@ -1315,16 +1379,18 @@ parse_hba_line(List *line, int line_num, char *raw_line)
/*
* Got something that's not a name=value pair.
*/
- ereport(LOG,
+ *err_msg = psprintf(_("authentication option not in name=value format: %s"),
+ token->string);
+ ereport(level,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("authentication option not in name=value format: %s", token->string),
+ errmsg("%s", *err_msg),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
*val++ = '\0'; /* str now holds "name", val holds "value" */
- if (!parse_hba_auth_opt(str, val, parsedline, line_num))
+ if (!parse_hba_auth_opt(str, val, parsedline, line_num, level, err_msg))
/* parse_hba_auth_opt already logged the error message */
return NULL;
pfree(str);
@@ -1352,9 +1418,10 @@ parse_hba_line(List *line, int line_num, char *raw_line)
parsedline->ldapbindpasswd ||
parsedline->ldapsearchattribute)
{
- ereport(LOG,
+ *err_msg = pstrdup(_("cannot use ldapbasedn, ldapbinddn, ldapbindpasswd, ldapsearchattribute, or ldapurl together with ldapprefix"));
+ ereport(level,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("cannot use ldapbasedn, ldapbinddn, ldapbindpasswd, ldapsearchattribute, or ldapurl together with ldapprefix"),
+ errmsg("%s", *err_msg),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
@@ -1362,9 +1429,10 @@ parse_hba_line(List *line, int line_num, char *raw_line)
}
else if (!parsedline->ldapbasedn)
{
- ereport(LOG,
+ *err_msg = pstrdup(_("authentication method \"ldap\" requires argument \"ldapbasedn\", \"ldapprefix\", or \"ldapsuffix\" to be set"));
+ ereport(level,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("authentication method \"ldap\" requires argument \"ldapbasedn\", \"ldapprefix\", or \"ldapsuffix\" to be set"),
+ errmsg("%s", *err_msg),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
@@ -1394,7 +1462,7 @@ parse_hba_line(List *line, int line_num, char *raw_line)
* encounter an error.
*/
static bool
-parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline, int line_num)
+parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline, int line_num, int level, char **err_msg)
{
#ifdef USE_LDAP
hbaline->ldapscope = LDAP_SCOPE_SUBTREE;
@@ -1414,9 +1482,10 @@ parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline, int line_num)
{
if (hbaline->conntype != ctHostSSL)
{
- ereport(LOG,
+ *err_msg = pstrdup(_("clientcert can only be configured for \"hostssl\" rows"));
+ ereport(level,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("clientcert can only be configured for \"hostssl\" rows"),
+ errmsg("%s", *err_msg),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return false;
@@ -1429,9 +1498,10 @@ parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline, int line_num)
{
if (hbaline->auth_method == uaCert)
{
- ereport(LOG,
+ *err_msg = pstrdup(_("clientcert can not be set to 0 when using \"cert\" authentication"));
+ ereport(level,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("clientcert can not be set to 0 when using \"cert\" authentication"),
+ errmsg("%s", *err_msg),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return false;
@@ -1465,18 +1535,23 @@ parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline, int line_num)
rc = ldap_url_parse(val, &urldata);
if (rc != LDAP_SUCCESS)
{
- ereport(LOG,
+ *err_msg = psprintf(_("could not parse LDAP URL \"%s\": %s"),
+ val, ldap_err2string(rc));
+ ereport(level,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("could not parse LDAP URL \"%s\": %s", val, ldap_err2string(rc))));
+ errmsg("%s", *err_msg)));
return false;
}
if (strcmp(urldata->lud_scheme, "ldap") != 0)
{
- ereport(LOG,
+ *err_msg = psprintf(_("unsupported LDAP URL scheme: %s"),
+ urldata->lud_scheme);
+ ereport(level,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("unsupported LDAP URL scheme: %s", urldata->lud_scheme)));
+ errmsg("%s", *err_msg)));
ldap_free_urldesc(urldata);
+
return false;
}
@@ -1489,17 +1564,19 @@ parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline, int line_num)
hbaline->ldapscope = urldata->lud_scope;
if (urldata->lud_filter)
{
- ereport(LOG,
+ *err_msg = pstrdup(_("filters not supported in LDAP URLs"));
+ ereport(level,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("filters not supported in LDAP URLs")));
+ errmsg("%s", *err_msg)));
ldap_free_urldesc(urldata);
return false;
}
ldap_free_urldesc(urldata);
#else /* not OpenLDAP */
- ereport(LOG,
+ *err_msg = pstrdup(_("LDAP URLs not supported on this platform"));
+ ereport(level,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("LDAP URLs not supported on this platform")));
+ errmsg("%s", *err_msg)));
#endif /* not OpenLDAP */
}
else if (strcmp(name, "ldaptls") == 0)
@@ -1521,9 +1598,10 @@ parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline, int line_num)
hbaline->ldapport = atoi(val);
if (hbaline->ldapport == 0)
{
- ereport(LOG,
+ *err_msg = psprintf(_("invalid LDAP port number: \"%s\""), val);
+ ereport(level,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("invalid LDAP port number: \"%s\"", val),
+ errmsg("%s", *err_msg),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return false;
@@ -1609,10 +1687,11 @@ parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline, int line_num)
ret = pg_getaddrinfo_all(val, NULL, &hints, &gai_result);
if (ret || !gai_result)
{
- ereport(LOG,
+ *err_msg = psprintf(_("could not translate RADIUS server name \"%s\" to address: %s"),
+ val, gai_strerror(ret));
+ ereport(level,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("could not translate RADIUS server name \"%s\" to address: %s",
- val, gai_strerror(ret)),
+ errmsg("%s", *err_msg),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
if (gai_result)
@@ -1628,9 +1707,10 @@ parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline, int line_num)
hbaline->radiusport = atoi(val);
if (hbaline->radiusport == 0)
{
- ereport(LOG,
+ *err_msg = psprintf(_("invalid RADIUS port number: \"%s\""), val);
+ ereport(level,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("invalid RADIUS port number: \"%s\"", val),
+ errmsg("%s", *err_msg),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return false;
@@ -1648,10 +1728,11 @@ parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline, int line_num)
}
else
{
- ereport(LOG,
+ *err_msg = psprintf(_("unrecognized authentication option name: \"%s\""),
+ name);
+ ereport(level,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
- errmsg("unrecognized authentication option name: \"%s\"",
- name),
+ errmsg("%s", *err_msg),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return false;
@@ -1790,7 +1871,11 @@ load_hba(void)
return false;
}
- linecxt = tokenize_file(HbaFileName, file, &hba_lines, &hba_line_nums, &hba_raw_lines);
+ PG_ENSURE_ERROR_CLEANUP(tokenize_file_failure_callback, PointerGetDatum(file));
+ {
+ linecxt = tokenize_file(HbaFileName, file, &hba_lines, &hba_line_nums, &hba_raw_lines);
+ }
+ PG_END_ENSURE_ERROR_CLEANUP(tokenize_file_failure_callback, PointerGetDatum(file));
FreeFile(file);
/* Now parse all the lines */
@@ -1802,8 +1887,9 @@ load_hba(void)
forthree(line, hba_lines, line_num, hba_line_nums, raw_line, hba_raw_lines)
{
HbaLine *newline;
+ char *err_msg = NULL;
- if ((newline = parse_hba_line(lfirst(line), lfirst_int(line_num), lfirst(raw_line))) == NULL)
+ if ((newline = parse_hba_line(lfirst(line), lfirst_int(line_num), lfirst(raw_line), LOG, &err_msg)) == NULL)
{
/*
* Parse error in the file, so indicate there's a problem. NB: a
@@ -2166,7 +2252,11 @@ load_ident(void)
return false;
}
- linecxt = tokenize_file(IdentFileName, file, &ident_lines, &ident_line_nums, NULL);
+ PG_ENSURE_ERROR_CLEANUP(tokenize_file_failure_callback, PointerGetDatum(file));
+ {
+ linecxt = tokenize_file(IdentFileName, file, &ident_lines, &ident_line_nums, NULL);
+ }
+ PG_END_ENSURE_ERROR_CLEANUP(tokenize_file_failure_callback, PointerGetDatum(file));
FreeFile(file);
/* Now parse all the lines */
@@ -2255,3 +2345,456 @@ hba_getauthmethod(hbaPort *port)
{
check_hba(port);
}
+
+/*
+ * Returns the Text Datum representation of authentication method
+ */
+static Datum
+getauthmethod(UserAuth auth_method)
+{
+ Datum result;
+
+ switch (auth_method)
+ {
+ case uaReject:
+ result = CStringGetTextDatum("reject");
+ break;
+ case uaImplicitReject:
+
+ /*
+ * This case is not possible, as user cannot provide this option
+ * in pg_hba.conf file. But to find out any new additions to the
+ * enum by the compiler all the enum values are added here.
+ */
+ Assert(0);
+ break;
+ case uaTrust:
+ result = CStringGetTextDatum("trust");
+ break;
+ case uaIdent:
+ result = CStringGetTextDatum("ident");
+ break;
+ case uaPassword:
+ result = CStringGetTextDatum("password");
+ break;
+ case uaMD5:
+ result = CStringGetTextDatum("md5");
+ break;
+ case uaGSS:
+ result = CStringGetTextDatum("gss");
+ break;
+ case uaSSPI:
+ result = CStringGetTextDatum("sspi");
+ break;
+ case uaPAM:
+ result = CStringGetTextDatum("pam");
+ break;
+ case uaBSD:
+ result = CStringGetTextDatum("bsd");
+ break;
+ case uaLDAP:
+ result = CStringGetTextDatum("ldap");
+ break;
+ case uaCert:
+ result = CStringGetTextDatum("cert");
+ break;
+ case uaRADIUS:
+ result = CStringGetTextDatum("radius");
+ break;
+ case uaPeer:
+ result = CStringGetTextDatum("peer");
+ break;
+ }
+
+ return result;
+}
+
+static void
+fill_hba_auth_opt(Datum *optdata, char *optname, char *optvalue)
+{
+ StringInfoData str;
+
+ initStringInfo(&str);
+ appendStringInfoString(&str, optname);
+ appendStringInfoString(&str, optvalue);
+ *optdata = CStringGetTextDatum(str.data);
+}
+
+/* LDAP supports 10 currently, keep this well above the most any method needs */
+#define MAX_OPTIONS 12
+
+static Datum
+gethba_options(HbaLine *hba)
+{
+ int noptions;
+ Datum options[MAX_OPTIONS];
+ char buffer[64];
+
+ 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)
+ fill_hba_auth_opt(&options[noptions++], "krb_realm=", hba->krb_realm);
+ }
+
+ if (hba->usermap)
+ fill_hba_auth_opt(&options[noptions++], "map=", hba->usermap);
+
+ if (hba->clientcert)
+ options[noptions++] = CStringGetTextDatum("clientcert=true");
+
+ if (hba->pamservice)
+ fill_hba_auth_opt(&options[noptions++], "pamservice=", hba->pamservice);
+
+ if (hba->auth_method == uaLDAP)
+ {
+ if (hba->ldapserver)
+ fill_hba_auth_opt(&options[noptions++], "ldapserver=", hba->ldapserver);
+
+ if (hba->ldapport)
+ {
+ snprintf(buffer, sizeof(buffer), "%d", hba->ldapport);
+ fill_hba_auth_opt(&options[noptions++], "ldapport=", buffer);
+ }
+
+ if (hba->ldaptls)
+ options[noptions++] = CStringGetTextDatum("ldaptls=true");
+
+ if (hba->ldapprefix)
+ fill_hba_auth_opt(&options[noptions++], "ldapprefix=", hba->ldapprefix);
+
+ if (hba->ldapsuffix)
+ fill_hba_auth_opt(&options[noptions++], "ldapsuffix=", hba->ldapsuffix);
+
+ if (hba->ldapbasedn)
+ fill_hba_auth_opt(&options[noptions++], "ldapbasedn=", hba->ldapbasedn);
+
+ if (hba->ldapbinddn)
+ fill_hba_auth_opt(&options[noptions++], "ldapbinddn=", hba->ldapbinddn);
+
+ if (hba->ldapbindpasswd)
+ fill_hba_auth_opt(&options[noptions++], "ldapbindpasswd=", hba->ldapbindpasswd);
+
+ if (hba->ldapsearchattribute)
+ fill_hba_auth_opt(&options[noptions++], "ldapsearchattribute=", hba->ldapsearchattribute);
+
+ if (hba->ldapscope)
+ {
+ snprintf(buffer, sizeof(buffer), "%d", hba->ldapscope);
+ fill_hba_auth_opt(&options[noptions++], "ldapscope=", buffer);
+ }
+ }
+
+ if (hba->auth_method == uaRADIUS)
+ {
+ if (hba->radiusserver)
+ fill_hba_auth_opt(&options[noptions++], "radiusserver=", hba->radiusserver);
+
+ if (hba->radiussecret)
+ fill_hba_auth_opt(&options[noptions++], "radiussecret=", hba->radiussecret);
+
+ if (hba->radiusidentifier)
+ fill_hba_auth_opt(&options[noptions++], "radiusidentifier=", hba->radiusidentifier);
+
+ if (hba->radiusport)
+ {
+ snprintf(buffer, sizeof(buffer), "%d", hba->radiusport);
+ fill_hba_auth_opt(&options[noptions++], "radiusport=", buffer);
+ }
+ }
+
+ Assert(noptions <= MAX_OPTIONS);
+ if (noptions)
+ return PointerGetDatum(
+ construct_array(options, noptions, TEXTOID, -1, false, 'i'));
+ return PointerGetDatum(NULL);
+}
+
+#define NUM_PG_HBA_LOOKUP_ATTS 9
+
+static void
+fill_hba_line(FillHbaLineCxt *context, int lineno, HbaLine *hba, const char *err_msg)
+{
+ Datum values[NUM_PG_HBA_LOOKUP_ATTS];
+ bool nulls[NUM_PG_HBA_LOOKUP_ATTS];
+ ListCell *dbcell;
+ char buffer[NI_MAXHOST];
+ HeapTuple tuple;
+ int index;
+ Datum options;
+ MemoryContext old_cxt;
+
+ index = 0;
+ memset(values, 0, sizeof(values));
+ memset(nulls, 0, sizeof(nulls));
+
+ old_cxt = MemoryContextSwitchTo(context->memcxt);
+
+ /* line_number */
+ values[index] = Int32GetDatum(lineno);
+
+ if (err_msg)
+ {
+ /* set all remaining columns as NULL, except error column */
+ memset(&nulls[1], true, (NUM_PG_HBA_LOOKUP_ATTS - 2));
+
+ /* error */
+ values[NUM_PG_HBA_LOOKUP_ATTS - 1] = CStringGetTextDatum(err_msg);
+ }
+ else
+ {
+ /* type */
+ index++;
+ switch (hba->conntype)
+ {
+ case ctLocal:
+ values[index] = CStringGetTextDatum("local");
+ break;
+ case ctHost:
+ values[index] = CStringGetTextDatum("host");
+ break;
+ case ctHostSSL:
+ values[index] = CStringGetTextDatum("hostssl");
+ break;
+ case ctHostNoSSL:
+ values[index] = CStringGetTextDatum("hostnossl");
+ break;
+ }
+
+ /* database */
+ index++;
+ if (list_length(hba->databases) != 0)
+ {
+ List *names = NULL;
+ HbaToken *tok;
+
+ foreach(dbcell, hba->databases)
+ {
+ tok = lfirst(dbcell);
+ names = lappend(names, tok->string);
+ }
+
+ /* database */
+ Assert(names != NULL);
+ values[index] = PointerGetDatum(strlist_to_textarray(names));
+ }
+ else
+ nulls[index] = true;
+
+ /* user */
+ index++;
+ if (list_length(hba->roles) != 0)
+ {
+ List *roles = NULL;
+ HbaToken *tok;
+
+ foreach(dbcell, hba->roles)
+ {
+ tok = lfirst(dbcell);
+ roles = lappend(roles, tok->string);
+ }
+
+ /* user */
+ Assert(roles != NULL);
+ values[index] = PointerGetDatum(strlist_to_textarray(roles));
+ }
+ else
+ nulls[index] = true;
+
+
+ /* address */
+ index++;
+ switch (hba->ip_cmp_method)
+ {
+ case ipCmpMask:
+ if (hba->hostname)
+ {
+ values[index] = CStringGetTextDatum(hba->hostname);
+ nulls[++index] = true;
+ }
+ else
+ {
+ if (pg_getnameinfo_all(&hba->addr, sizeof(struct sockaddr_storage),
+ buffer, sizeof(buffer),
+ NULL, 0,
+ NI_NUMERICHOST) == 0)
+ {
+ clean_ipv6_addr(hba->addr.ss_family, buffer);
+ values[index] = CStringGetTextDatum(buffer);
+ }
+ else
+ nulls[index] = true;
+
+ /* netmask */
+ if (pg_getnameinfo_all(&hba->mask, sizeof(struct sockaddr_storage),
+ buffer, sizeof(buffer),
+ NULL, 0,
+ NI_NUMERICHOST) == 0)
+ {
+ clean_ipv6_addr(hba->mask.ss_family, buffer);
+ values[++index] = CStringGetTextDatum(buffer);
+ }
+ else
+ nulls[++index] = true;
+ }
+ break;
+ case ipCmpAll:
+ values[index] = CStringGetTextDatum("all");
+ nulls[++index] = true;
+ break;
+ case ipCmpSameHost:
+ values[index] = CStringGetTextDatum("samehost");
+ nulls[++index] = true;
+ break;
+ case ipCmpSameNet:
+ values[index] = CStringGetTextDatum("samenet");
+ nulls[++index] = true;
+ break;
+ }
+
+ /* auth_method */
+ index++;
+ values[index] = getauthmethod(hba->auth_method);
+
+ /* options */
+ index++;
+ options = gethba_options(hba);
+ if (options)
+ values[index] = PointerGetDatum(options);
+ else
+ nulls[index] = true;
+
+ /* error */
+ index++;
+ nulls[index] = true;
+ }
+
+ tuple = heap_form_tuple(context->tupdesc, values, nulls);
+ tuplestore_puttuple(context->tuple_store, tuple);
+
+ MemoryContextSwitchTo(old_cxt);
+ return;
+}
+
+/*
+ * Read the config file and fill the HbaLine records for the view.
+ */
+static void
+fill_hba(FillHbaLineCxt *context)
+{
+ FILE *file;
+ List *hba_lines = NIL;
+ List *hba_line_nums = NIL;
+ List *hba_raw_lines = NIL;
+ ListCell *line,
+ *line_num,
+ *raw_line;
+ MemoryContext linecxt;
+ MemoryContext oldcxt;
+ MemoryContext hbacxt;
+
+ file = AllocateFile(HbaFileName, "r");
+ if (file == NULL)
+ {
+ ereport(LOG,
+ (errcode_for_file_access(),
+ errmsg("could not open configuration file \"%s\": %m",
+ HbaFileName)));
+ return;
+ }
+
+ PG_ENSURE_ERROR_CLEANUP(tokenize_file_failure_callback, PointerGetDatum(file));
+ {
+ linecxt = tokenize_file(HbaFileName, file, &hba_lines, &hba_line_nums, &hba_raw_lines);
+ }
+ PG_END_ENSURE_ERROR_CLEANUP(tokenize_file_failure_callback, PointerGetDatum(file));
+ FreeFile(file);
+
+ /* Now parse all the lines */
+ hbacxt = AllocSetContextCreate(CurrentMemoryContext,
+ "hba parser context",
+ ALLOCSET_SMALL_SIZES);
+ oldcxt = MemoryContextSwitchTo(hbacxt);
+ forthree(line, hba_lines, line_num, hba_line_nums, raw_line, hba_raw_lines)
+ {
+ HbaLine *newline;
+ int lineno = lfirst_int(line_num);
+ char *err_msg = NULL;
+
+ MemoryContextReset(hbacxt);
+ newline = parse_hba_line(lfirst(line), lineno, lfirst(raw_line), DEBUG3, &err_msg);
+ fill_hba_line(context, lineno, newline, err_msg);
+ }
+
+ /* Free tokenizer memory */
+ MemoryContextDelete(linecxt);
+ MemoryContextSwitchTo(oldcxt);
+ MemoryContextDelete(hbacxt);
+}
+
+/*
+ * SQL-accessible SRF to return all the settings from the pg_hba.conf
+ * file.
+ */
+Datum
+hba_rules(PG_FUNCTION_ARGS)
+{
+ Tuplestorestate *tuple_store;
+ TupleDesc tupdesc;
+ MemoryContext old_cxt;
+ FillHbaLineCxt *mycxt;
+ ReturnSetInfo *rsi;
+
+ /*
+ * We must use the Materialize mode to be safe against HBA file reloads
+ * while the cursor is open. It's also more efficient than having to look
+ * up our current position in the parsed list every time.
+ */
+ rsi = (ReturnSetInfo *) fcinfo->resultinfo;
+
+ /* Check to see if caller supports us returning a tuplestore */
+ if (rsi == NULL || !IsA(rsi, ReturnSetInfo))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("set-valued function called in context that cannot accept a set")));
+ if (!(rsi->allowedModes & SFRM_Materialize))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("materialize mode required, but it is not " \
+ "allowed in this context")));
+
+ rsi->returnMode = SFRM_Materialize;
+
+ /* Build a tuple descriptor for our result type */
+ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+ elog(ERROR, "return type must be a row type");
+
+ /* Build tuplestore to hold the result rows */
+ old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
+
+ tuple_store =
+ tuplestore_begin_heap(rsi->allowedModes & SFRM_Materialize_Random,
+ false, work_mem);
+ rsi->setDesc = tupdesc;
+ rsi->setResult = tuple_store;
+
+ MemoryContextSwitchTo(old_cxt);
+
+ mycxt = (FillHbaLineCxt *) palloc(sizeof(FillHbaLineCxt));
+ mycxt->memcxt = AllocSetContextCreate(CurrentMemoryContext,
+ "pg_hba_lookup tuple cxt",
+ ALLOCSET_DEFAULT_SIZES);
+ mycxt->tupdesc = tupdesc;
+ mycxt->tuple_store = tuple_store;
+
+ fill_hba(mycxt);
+
+ MemoryContextDelete(mycxt->memcxt);
+ pfree(mycxt);
+
+ PG_RETURN_NULL();
+}
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 03f55a1..9eea9c7 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -3074,6 +3074,8 @@ DATA(insert OID = 2084 ( pg_show_all_settings PGNSP PGUID 12 1 1000 0 0 f f f f
DESCR("SHOW ALL as a function");
DATA(insert OID = 3329 ( pg_show_all_file_settings PGNSP PGUID 12 1 1000 0 0 f f f f t t v s 0 0 2249 "" "{25,23,23,25,25,16,25}" "{o,o,o,o,o,o,o}" "{sourcefile,sourceline,seqno,name,setting,applied,error}" _null_ _null_ show_all_file_settings _null_ _null_ _null_ ));
DESCR("show config file settings");
+DATA(insert OID = 3401 ( pg_hba_rules PGNSP PGUID 12 1 1000 0 0 f f f f t t v s 0 0 2249 "" "{23,25,1009,1009,25,25,25,1009,25}" "{o,o,o,o,o,o,o,o,o}" "{line_number,type,database,user_name,address,netmask,auth_method,options,error}" _null_ _null_ hba_rules _null_ _null_ _null_ ));
+DESCR("show pg_hba config rules");
DATA(insert OID = 1371 ( pg_lock_status PGNSP PGUID 12 1 1000 0 0 f f f f t t v s 0 0 2249 "" "{25,26,26,23,21,25,28,26,26,21,25,23,25,16,16}" "{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{locktype,database,relation,page,tuple,virtualxid,transactionid,classid,objid,objsubid,virtualtransaction,pid,mode,granted,fastpath}" _null_ _null_ pg_lock_status _null_ _null_ _null_ ));
DESCR("view system lock information");
DATA(insert OID = 2561 ( pg_blocking_pids PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 1007 "23" _null_ _null_ _null_ _null_ _null_ pg_blocking_pids _null_ _null_ _null_ ));
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index add6adc..858dd06 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1338,6 +1338,16 @@ pg_group| SELECT pg_authid.rolname AS groname,
WHERE (pg_auth_members.roleid = pg_authid.oid)) AS grolist
FROM pg_authid
WHERE (NOT pg_authid.rolcanlogin);
+pg_hba_rules| SELECT a.line_number,
+ a.type,
+ a.database,
+ a.user_name,
+ a.address,
+ a.netmask,
+ a.auth_method,
+ a.options,
+ a.error
+ FROM pg_hba_rules() a(line_number, type, database, user_name, address, netmask, auth_method, options, error);
pg_indexes| SELECT n.nspname AS schemaname,
c.relname AS tablename,
i.relname AS indexname,
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 993880d..668d46a 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -604,6 +604,7 @@ FileFdwExecutionState
FileFdwPlanState
FileName
FileNameMap
+FillHbaLineCxt
FindSplitData
FixedParallelState
FixedParamState