Haribabu Kommi <[email protected]> writes:
> [ pg_hba_rules_13.patch ]
I spent awhile hacking on this, and made a lot of things better, but
I'm still very unhappy about the state of the comments. You changed
the APIs of a bunch of functions, often into fairly subtle things,
and you did not touch even one of their API-specification comments.
As an example, next_token() now needs something like
"On error, log a message at ereport level elevel and set *err_msg to
an error string. Note that the return value might be either true or
false after an error; *err_msg must be checked to determine that.
Hence, *err_msg had better be NULL on entry, or you won't be able
to tell."
Having to write such a thing might even convince you that you should
try a little harder to make the behavior less confusing. Just adding
arguments, and not changing the result-value specification, is not
necessarily the best way to do this.
I haven't looked at the docs yet.
I'm still not very happy about the choice of view name ...
regards, tom lane
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 086fafc..3f4724c 100644
*** a/doc/src/sgml/catalogs.sgml
--- b/doc/src/sgml/catalogs.sgml
***************
*** 7804,7809 ****
--- 7804,7814 ----
</row>
<row>
+ <entry><link linkend="view-pg-hba-rules"><structname>pg_hba_rules</structname></link></entry>
+ <entry>summary of client authentication configuration file contents</entry>
+ </row>
+
+ <row>
<entry><link linkend="view-pg-group"><structname>pg_group</structname></link></entry>
<entry>groups of database users</entry>
</row>
***************
*** 8352,8357 ****
--- 8357,8481 ----
</sect1>
+ <sect1 id="view-pg-hba-rules">
+ <title><structname>pg_hba_rules</structname></title>
+
+ <indexterm zone="view-pg-hba-rules">
+ <primary>pg_hba_rules</primary>
+ </indexterm>
+
+ <para>
+ The view <structname>pg_hba_rules</structname> 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.
+ </para>
+
+ <table>
+ <title><structname>pg_hba_rules</> Columns</title>
+
+ <tgroup cols="3">
+ <thead>
+ <row>
+ <entry>Name</entry>
+ <entry>Type</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry><structfield>line_number</structfield></entry>
+ <entry><structfield>integer</structfield></entry>
+ <entry>
+ Line number of the client authentication rule in
+ pg_hba.conf file
+ </entry>
+ </row>
+ <row>
+ <entry><structfield>type</structfield></entry>
+ <entry><structfield>text</structfield></entry>
+ <entry>Type of connection</entry>
+ </row>
+ <row>
+ <entry><structfield>database</structfield></entry>
+ <entry><structfield>text[]</structfield></entry>
+ <entry>List of database names</entry>
+ </row>
+ <row>
+ <entry><structfield>user_name</structfield></entry>
+ <entry><structfield>text[]</structfield></entry>
+ <entry>List of user names</entry>
+ </row>
+ <row>
+ <entry><structfield>address</structfield></entry>
+ <entry><structfield>text</structfield></entry>
+ <entry>
+ 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 (<literal>all</literal>,
+ <literal>samehost</literal> and <literal>samenet</literal>).
+ </entry>
+ </row>
+ <row>
+ <entry><structfield>netmask</structfield></entry>
+ <entry><structfield>text</structfield></entry>
+ <entry>Address mask if exist</entry>
+ </row>
+ <row>
+ <entry><structfield>auth_method</structfield></entry>
+ <entry><type>text</type></entry>
+ <entry>Authentication method</entry>
+ </row>
+ <row>
+ <entry><structfield>options</structfield></entry>
+ <entry><type>text[]</type></entry>
+ <entry>Configuration options set for authentication method</entry>
+ </row>
+ <row>
+ <entry><structfield>error</structfield></entry>
+ <entry><structfield>text</structfield></entry>
+ <entry>
+ If not null, an error message indicates why this
+ rule could not be loaded.
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>
+ <structfield>error</structfield> field, if not NULL, describes problem
+ in the rule on the line <structfield>line_number</structfield>.
+ Following is the sample output of the view.
+ </para>
+
+ <programlisting>
+ SELECT line_number, type, database, user_name, auth_method FROM pg_hba_rules;
+ </programlisting>
+
+ <screen>
+ line_number | type | database | user_name | address | auth_method
+ -------------+-------+------------+------------+--------------+-------------
+ 84 | local | {all} | {all} | | trust
+ 86 | host | {sameuser} | {postgres} | all | trust
+ 88 | host | {postgres} | {postgres} | ::1 | trust
+ 111 | host | {all} | {all} | 127.0.0.1 | trust
+ 121 | host | {all} | {all} | localhost | trust
+ 128 | host | {postgres} | {all} | samenet | ident
+ 134 | host | {postgres} | {all} | samehost | md5
+ 140 | host | {db1,db2} | {all} | .example.com | md5
+ 149 | host | {test} | {test} | 192.168.54.1 | reject
+ 159 | host | {all} | {+support} | 192.168.0.0 | ident
+ 169 | local | {sameuser} | {all} | | md5
+ (11 rows)
+ </screen>
+
+ <para>
+ See <xref linkend="client-authentication"> for more information about the various
+ ways to change client authentication configuration.
+ </para>
+ </sect1>
+
<sect1 id="view-pg-group">
<title><structname>pg_group</structname></title>
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,59 ****
--- 54,66 ----
database user names and OS user names.
</para>
+ <para>
+ The system view
+ <link linkend="view-pg-hba-rules"><structname>pg_hba_rules</structname></link>
+ 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.
+ </para>
+
<sect1 id="auth-pg-hba-conf">
<title>The <filename>pg_hba.conf</filename> File</title>
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 4dfedf8..d920a72 100644
*** a/src/backend/catalog/system_views.sql
--- b/src/backend/catalog/system_views.sql
*************** CREATE VIEW pg_file_settings AS
*** 459,464 ****
--- 459,470 ----
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 bbe0a88..289bd9d 100644
*** a/src/backend/libpq/hba.c
--- b/src/backend/libpq/hba.c
***************
*** 25,39 ****
--- 25,46 ----
#include <arpa/inet.h>
#include <unistd.h>
+ #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"
*************** typedef struct HbaToken
*** 80,91 ****
--- 87,101 ----
* 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;
/*
*************** static MemoryContext parsed_hba_context
*** 106,118 ****
static List *parsed_ident_lines = NIL;
static MemoryContext parsed_ident_context = NULL;
static MemoryContext tokenize_file(const char *filename, FILE *file,
! List **tok_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);
/*
* isblank() exists in the ISO C99 spec, but it's not very portable yet,
--- 116,157 ----
static List *parsed_ident_lines = NIL;
static MemoryContext parsed_ident_context = NULL;
+ /*
+ * The following character array represents the names of the authentication
+ * methods that are supported by PostgreSQL.
+ *
+ * Note: keep this in sync with the UserAuth enum in hba.h.
+ */
+ static const char *const UserAuthName[] =
+ {
+ "reject",
+ "implicit reject", /* Not a user-visible option */
+ "trust",
+ "ident",
+ "password",
+ "md5",
+ "gss",
+ "sspi",
+ "pam",
+ "bsd",
+ "ldap",
+ "cert",
+ "radius",
+ "peer"
+ };
+
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(Tuplestorestate *tuple_store, TupleDesc tupdesc);
!
/*
* isblank() exists in the ISO C99 spec, but it's not very portable yet,
*************** pg_isblank(const char c)
*** 151,157 ****
*/
static bool
next_token(char **lineptr, char *buf, int bufsz, bool *initial_quote,
! bool *terminating_comma)
{
int c;
char *start_buf = buf;
--- 190,196 ----
*/
static bool
next_token(char **lineptr, char *buf, int bufsz, bool *initial_quote,
! bool *terminating_comma, int elevel, char **err_msg)
{
int c;
char *start_buf = buf;
*************** next_token(char **lineptr, char *buf, in
*** 197,206 ****
if (buf >= end_buf)
{
*buf = '\0';
! ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("authentication file token too long, skipping: \"%s\"",
start_buf)));
/* Discard remainder of line */
while ((c = (*(*lineptr)++)) != '\0' && c != '\n')
;
--- 236,246 ----
if (buf >= end_buf)
{
*buf = '\0';
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("authentication file token too long, skipping: \"%s\"",
start_buf)));
+ *err_msg = "authentication file token too long";
/* Discard remainder of line */
while ((c = (*(*lineptr)++)) != '\0' && c != '\n')
;
*************** copy_hba_token(HbaToken *in)
*** 279,285 ****
* or NIL if we reached EOL.
*/
static List *
! next_field_expand(const char *filename, char **lineptr)
{
char buf[MAX_TOKEN];
bool trailing_comma;
--- 319,325 ----
* or NIL if we reached EOL.
*/
static List *
! next_field_expand(const char *filename, char **lineptr, int elevel, char **err_msg)
{
char buf[MAX_TOKEN];
bool trailing_comma;
*************** next_field_expand(const char *filename,
*** 288,302 ****
do
{
! if (!next_token(lineptr, buf, sizeof(buf), &initial_quote, &trailing_comma))
break;
/* Is this referencing a file? */
if (!initial_quote && buf[0] == '@' && buf[1] != '\0')
! tokens = tokenize_inc_file(tokens, filename, buf + 1);
else
tokens = lappend(tokens, make_hba_token(buf, initial_quote));
! } while (trailing_comma);
return tokens;
}
--- 328,342 ----
do
{
! if (!next_token(lineptr, buf, sizeof(buf), &initial_quote, &trailing_comma, elevel, err_msg) || (*err_msg != NULL))
break;
/* Is this referencing a file? */
if (!initial_quote && buf[0] == '@' && buf[1] != '\0')
! tokens = tokenize_inc_file(tokens, filename, buf + 1, elevel, err_msg);
else
tokens = lappend(tokens, make_hba_token(buf, initial_quote));
! } while (trailing_comma && (*err_msg == NULL));
return tokens;
}
*************** next_field_expand(const char *filename,
*** 313,319 ****
static List *
tokenize_inc_file(List *tokens,
const char *outer_filename,
! const char *inc_filename)
{
char *inc_fullname;
FILE *inc_file;
--- 353,361 ----
static List *
tokenize_inc_file(List *tokens,
const char *outer_filename,
! const char *inc_filename,
! int elevel,
! char **err_msg)
{
char *inc_fullname;
FILE *inc_file;
*************** tokenize_inc_file(List *tokens,
*** 340,355 ****
inc_file = AllocateFile(inc_fullname, "r");
if (inc_file == NULL)
{
! ereport(LOG,
(errcode_for_file_access(),
errmsg("could not open secondary authentication file \"@%s\" as \"%s\": %m",
inc_filename, inc_fullname)));
pfree(inc_fullname);
return tokens;
}
/* There is possible recursion here if the file contains @ */
! linecxt = tokenize_file(inc_fullname, inc_file, &inc_lines);
FreeFile(inc_file);
pfree(inc_fullname);
--- 382,401 ----
inc_file = AllocateFile(inc_fullname, "r");
if (inc_file == NULL)
{
! int save_errno = errno;
!
! ereport(elevel,
(errcode_for_file_access(),
errmsg("could not open secondary authentication file \"@%s\" as \"%s\": %m",
inc_filename, inc_fullname)));
+ *err_msg = psprintf("could not open secondary authentication file \"@%s\" as \"%s\": %s",
+ inc_filename, inc_fullname, strerror(save_errno));
pfree(inc_fullname);
return tokens;
}
/* There is possible recursion here if the file contains @ */
! linecxt = tokenize_file(inc_fullname, inc_file, &inc_lines, elevel);
FreeFile(inc_file);
pfree(inc_fullname);
*************** tokenize_inc_file(List *tokens,
*** 389,395 ****
* this function (it's a child of caller's context).
*/
static MemoryContext
! tokenize_file(const char *filename, FILE *file, List **tok_lines)
{
int line_number = 1;
MemoryContext linecxt;
--- 435,441 ----
* this function (it's a child of caller's context).
*/
static MemoryContext
! tokenize_file(const char *filename, FILE *file, List **tok_lines, int elevel)
{
int line_number = 1;
MemoryContext linecxt;
*************** tokenize_file(const char *filename, FILE
*** 407,422 ****
char rawline[MAX_LINE];
char *lineptr;
List *current_line = NIL;
if (!fgets(rawline, sizeof(rawline), file))
break;
if (strlen(rawline) == MAX_LINE - 1)
/* Line too long! */
! ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("authentication file line too long"),
errcontext("line %d of configuration file \"%s\"",
line_number, filename)));
/* Strip trailing linebreak from rawline */
lineptr = rawline + strlen(rawline) - 1;
--- 453,472 ----
char rawline[MAX_LINE];
char *lineptr;
List *current_line = NIL;
+ char *err_msg = NULL;
if (!fgets(rawline, sizeof(rawline), file))
break;
if (strlen(rawline) == MAX_LINE - 1)
+ {
/* Line too long! */
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("authentication file line too long"),
errcontext("line %d of configuration file \"%s\"",
line_number, filename)));
+ err_msg = "authentication file line too long";
+ }
/* Strip trailing linebreak from rawline */
lineptr = rawline + strlen(rawline) - 1;
*************** tokenize_file(const char *filename, FILE
*** 425,442 ****
/* Parse fields */
lineptr = rawline;
! while (*lineptr)
{
List *current_field;
! current_field = next_field_expand(filename, &lineptr);
/* add field to line, unless we are at EOL or comment start */
if (current_field != NIL)
current_line = lappend(current_line, current_field);
}
/* Reached EOL; emit line to TokenizedLine list unless it's boring */
! if (current_line != NIL)
{
TokenizedLine *tok_line;
--- 475,493 ----
/* Parse fields */
lineptr = rawline;
! while (*lineptr && err_msg == NULL)
{
List *current_field;
! current_field = next_field_expand(filename, &lineptr,
! elevel, &err_msg);
/* add field to line, unless we are at EOL or comment start */
if (current_field != NIL)
current_line = lappend(current_line, current_field);
}
/* Reached EOL; emit line to TokenizedLine list unless it's boring */
! if (current_line != NIL || err_msg != NULL)
{
TokenizedLine *tok_line;
*************** tokenize_file(const char *filename, FILE
*** 444,449 ****
--- 495,501 ----
tok_line->fields = current_line;
tok_line->line_num = line_number;
tok_line->raw_line = pstrdup(rawline);
+ tok_line->err_msg = err_msg;
*tok_lines = lappend(*tok_lines, tok_line);
}
*************** check_same_host_or_net(SockAddr *raddr,
*** 746,751 ****
--- 798,807 ----
/*
* Macros used to check and report on invalid configuration options.
+ * On error: log a message at level elevel, set *err_msg, and exit the function.
+ * These macros are not as general-purpose as they look, because they know
+ * what the calling function's error-exit value is.
+ *
* INVALID_AUTH_OPTION = reports when an option is specified for a method where it's
* not supported.
* REQUIRE_AUTH_OPTION = same as INVALID_AUTH_OPTION, except it also checks if the
*************** check_same_host_or_net(SockAddr *raddr,
*** 754,797 ****
* MANDATORY_AUTH_ARG = check if a required option is set for an authentication method,
* reporting error if it's not.
*/
! #define INVALID_AUTH_OPTION(optname, validmethods) do {\
! ereport(LOG, \
(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)), \
errcontext("line %d of configuration file \"%s\"", \
line_num, HbaFileName))); \
return false; \
! } while (0);
! #define REQUIRE_AUTH_OPTION(methodval, optname, validmethods) do {\
if (hbaline->auth_method != methodval) \
INVALID_AUTH_OPTION(optname, validmethods); \
! } while (0);
! #define MANDATORY_AUTH_ARG(argvar, argname, authname) do {\
! if (argvar == NULL) {\
! ereport(LOG, \
(errcode(ERRCODE_CONFIG_FILE_ERROR), \
errmsg("authentication method \"%s\" requires argument \"%s\" to be set", \
authname, argname), \
errcontext("line %d of configuration file \"%s\"", \
line_num, HbaFileName))); \
return NULL; \
} \
! } while (0);
/*
* IDENT_FIELD_ABSENT:
! * Throw an error and exit the function if the given ident field ListCell is
* not populated.
*
* IDENT_MULTI_VALUE:
! * Throw an error and exit the function if the given ident token List has more
* than one element.
*/
! #define IDENT_FIELD_ABSENT(field) do {\
if (!field) { \
ereport(LOG, \
(errcode(ERRCODE_CONFIG_FILE_ERROR), \
--- 810,865 ----
* MANDATORY_AUTH_ARG = check if a required option is set for an authentication method,
* reporting error if it's not.
*/
! #define INVALID_AUTH_OPTION(optname, validmethods) \
! do { \
! ereport(elevel, \
(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)), \
errcontext("line %d of configuration file \"%s\"", \
line_num, HbaFileName))); \
+ *err_msg = psprintf("authentication option \"%s\" is only valid for authentication methods %s", \
+ optname, validmethods); \
return false; \
! } while (0)
! #define REQUIRE_AUTH_OPTION(methodval, optname, validmethods) \
! do { \
if (hbaline->auth_method != methodval) \
INVALID_AUTH_OPTION(optname, validmethods); \
! } while (0)
! #define MANDATORY_AUTH_ARG(argvar, argname, authname) \
! do { \
! if (argvar == NULL) { \
! ereport(elevel, \
(errcode(ERRCODE_CONFIG_FILE_ERROR), \
errmsg("authentication method \"%s\" requires argument \"%s\" to be set", \
authname, argname), \
errcontext("line %d of configuration file \"%s\"", \
line_num, HbaFileName))); \
+ *err_msg = psprintf("authentication method \"%s\" requires argument \"%s\" to be set", \
+ authname, argname); \
return NULL; \
} \
! } 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.
+ *
* IDENT_FIELD_ABSENT:
! * Log a message and exit the function if 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.
*/
! #define IDENT_FIELD_ABSENT(field) \
! do { \
if (!field) { \
ereport(LOG, \
(errcode(ERRCODE_CONFIG_FILE_ERROR), \
*************** check_same_host_or_net(SockAddr *raddr,
*** 799,807 ****
IdentFileName, line_num))); \
return NULL; \
} \
! } while (0);
! #define IDENT_MULTI_VALUE(tokens) do {\
if (tokens->length > 1) { \
ereport(LOG, \
(errcode(ERRCODE_CONFIG_FILE_ERROR), \
--- 867,876 ----
IdentFileName, line_num))); \
return NULL; \
} \
! } while (0)
! #define IDENT_MULTI_VALUE(tokens) \
! do { \
if (tokens->length > 1) { \
ereport(LOG, \
(errcode(ERRCODE_CONFIG_FILE_ERROR), \
*************** check_same_host_or_net(SockAddr *raddr,
*** 810,832 ****
line_num, IdentFileName))); \
return NULL; \
} \
! } while (0);
/*
* Parse one tokenised line from the hba config file and store the result in a
* HbaLine structure.
*
! * Return NULL if parsing fails.
*
* Note: this function leaks memory when an error occurs. Caller is expected
* to have set a memory context that will be reset if this function returns
* NULL.
*/
static HbaLine *
! parse_hba_line(TokenizedLine *tok_line)
{
int line_num = tok_line->line_num;
char *str;
struct addrinfo *gai_result;
struct addrinfo hints;
--- 879,904 ----
line_num, IdentFileName))); \
return NULL; \
} \
! } while (0)
/*
* Parse one tokenised line from the hba config file and store the result in a
* HbaLine structure.
*
! * If parsing fails, log a message at ereport level "elevel", store an error
! * string in tok_line->err_msg, and return NULL. (Some non-error conditions
! * can also result in such messages.)
*
* Note: this function leaks memory when an error occurs. Caller is expected
* 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)
{
int line_num = tok_line->line_num;
+ char **err_msg = &tok_line->err_msg;
char *str;
struct addrinfo *gai_result;
struct addrinfo hints;
*************** parse_hba_line(TokenizedLine *tok_line)
*** 849,860 ****
tokens = lfirst(field);
if (tokens->length > 1)
{
! ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("multiple values specified for connection type"),
errhint("Specify exactly one connection type per line."),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
token = linitial(tokens);
--- 921,933 ----
tokens = lfirst(field);
if (tokens->length > 1)
{
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("multiple values specified for connection type"),
errhint("Specify exactly one connection type per line."),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
+ *err_msg = "multiple values specified for connection type";
return NULL;
}
token = linitial(tokens);
*************** parse_hba_line(TokenizedLine *tok_line)
*** 863,873 ****
#ifdef HAVE_UNIX_SOCKETS
parsedline->conntype = ctLocal;
#else
! ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("local connections are not supported by this build"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
#endif
}
--- 936,947 ----
#ifdef HAVE_UNIX_SOCKETS
parsedline->conntype = ctLocal;
#else
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("local connections are not supported by this build"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
+ *err_msg = "local connections are not supported by this build";
return NULL;
#endif
}
*************** parse_hba_line(TokenizedLine *tok_line)
*** 882,900 ****
/* Log a warning if SSL support is not active */
#ifdef USE_SSL
if (!EnableSSL)
! ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("hostssl record cannot match because SSL is disabled"),
errhint("Set ssl = on in postgresql.conf."),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
#else
! ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("hostssl record cannot match because SSL is not supported by this build"),
errhint("Compile with --with-openssl to use SSL connections."),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
#endif
}
else if (token->string[4] == 'n') /* "hostnossl" */
--- 956,978 ----
/* Log a warning if SSL support is not active */
#ifdef USE_SSL
if (!EnableSSL)
! {
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("hostssl record cannot match because SSL is disabled"),
errhint("Set ssl = on in postgresql.conf."),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
+ *err_msg = "hostssl record cannot match because SSL is disabled";
+ }
#else
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("hostssl record cannot match because SSL is not supported by this build"),
errhint("Compile with --with-openssl to use SSL connections."),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
+ *err_msg = "hostssl record cannot match because SSL is not supported by this build";
#endif
}
else if (token->string[4] == 'n') /* "hostnossl" */
*************** parse_hba_line(TokenizedLine *tok_line)
*** 909,920 ****
} /* record type */
else
{
! ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid connection type \"%s\"",
token->string),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
--- 987,999 ----
} /* record type */
else
{
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid connection type \"%s\"",
token->string),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
+ *err_msg = psprintf("invalid connection type \"%s\"", token->string);
return NULL;
}
*************** parse_hba_line(TokenizedLine *tok_line)
*** 922,932 ****
field = lnext(field);
if (!field)
{
! ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("end-of-line before database specification"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
parsedline->databases = NIL;
--- 1001,1012 ----
field = lnext(field);
if (!field)
{
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("end-of-line before database specification"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
+ *err_msg = "end-of-line before database specification";
return NULL;
}
parsedline->databases = NIL;
*************** parse_hba_line(TokenizedLine *tok_line)
*** 941,951 ****
field = lnext(field);
if (!field)
{
! ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("end-of-line before role specification"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
parsedline->roles = NIL;
--- 1021,1032 ----
field = lnext(field);
if (!field)
{
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("end-of-line before role specification"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
+ *err_msg = "end-of-line before role specification";
return NULL;
}
parsedline->roles = NIL;
*************** parse_hba_line(TokenizedLine *tok_line)
*** 962,983 ****
field = lnext(field);
if (!field)
{
! ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("end-of-line before IP address specification"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
tokens = lfirst(field);
if (tokens->length > 1)
{
! ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("multiple values specified for host address"),
errhint("Specify one address range per line."),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
token = linitial(tokens);
--- 1043,1066 ----
field = lnext(field);
if (!field)
{
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("end-of-line before IP address specification"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
+ *err_msg = "end-of-line before IP address specification";
return NULL;
}
tokens = lfirst(field);
if (tokens->length > 1)
{
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("multiple values specified for host address"),
errhint("Specify one address range per line."),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
+ *err_msg = "multiple values specified for host address";
return NULL;
}
token = linitial(tokens);
*************** parse_hba_line(TokenizedLine *tok_line)
*** 1027,1038 ****
parsedline->hostname = str;
else
{
! ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid IP address \"%s\": %s",
str, gai_strerror(ret)),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
if (gai_result)
pg_freeaddrinfo_all(hints.ai_family, gai_result);
return NULL;
--- 1110,1123 ----
parsedline->hostname = str;
else
{
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid IP address \"%s\": %s",
str, gai_strerror(ret)),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
+ *err_msg = psprintf("invalid IP address \"%s\": %s",
+ str, gai_strerror(ret));
if (gai_result)
pg_freeaddrinfo_all(hints.ai_family, gai_result);
return NULL;
*************** parse_hba_line(TokenizedLine *tok_line)
*** 1045,1068 ****
{
if (parsedline->hostname)
{
! ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("specifying both host name and CIDR mask is invalid: \"%s\"",
token->string),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
if (pg_sockaddr_cidr_mask(&parsedline->mask, cidr_slash + 1,
parsedline->addr.ss_family) < 0)
{
! ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid CIDR mask in address \"%s\"",
token->string),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
pfree(str);
--- 1130,1157 ----
{
if (parsedline->hostname)
{
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("specifying both host name and CIDR mask is invalid: \"%s\"",
token->string),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
+ *err_msg = psprintf("specifying both host name and CIDR mask is invalid: \"%s\"",
+ token->string);
return NULL;
}
if (pg_sockaddr_cidr_mask(&parsedline->mask, cidr_slash + 1,
parsedline->addr.ss_family) < 0)
{
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid CIDR mask in address \"%s\"",
token->string),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
+ *err_msg = psprintf("invalid CIDR mask in address \"%s\"",
+ token->string);
return NULL;
}
pfree(str);
*************** parse_hba_line(TokenizedLine *tok_line)
*** 1074,1095 ****
field = lnext(field);
if (!field)
{
! ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("end-of-line before netmask specification"),
errhint("Specify an address range in CIDR notation, or provide a separate netmask."),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
tokens = lfirst(field);
if (tokens->length > 1)
{
! ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("multiple values specified for netmask"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
token = linitial(tokens);
--- 1163,1186 ----
field = lnext(field);
if (!field)
{
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("end-of-line before netmask specification"),
errhint("Specify an address range in CIDR notation, or provide a separate netmask."),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
+ *err_msg = "end-of-line before netmask specification";
return NULL;
}
tokens = lfirst(field);
if (tokens->length > 1)
{
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("multiple values specified for netmask"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
+ *err_msg = "multiple values specified for netmask";
return NULL;
}
token = linitial(tokens);
*************** parse_hba_line(TokenizedLine *tok_line)
*** 1098,1109 ****
&hints, &gai_result);
if (ret || !gai_result)
{
! ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid IP mask \"%s\": %s",
token->string, gai_strerror(ret)),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
if (gai_result)
pg_freeaddrinfo_all(hints.ai_family, gai_result);
return NULL;
--- 1189,1202 ----
&hints, &gai_result);
if (ret || !gai_result)
{
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid IP mask \"%s\": %s",
token->string, gai_strerror(ret)),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
+ *err_msg = psprintf("invalid IP mask \"%s\": %s",
+ token->string, gai_strerror(ret));
if (gai_result)
pg_freeaddrinfo_all(hints.ai_family, gai_result);
return NULL;
*************** parse_hba_line(TokenizedLine *tok_line)
*** 1115,1125 ****
if (parsedline->addr.ss_family != parsedline->mask.ss_family)
{
! ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("IP address and mask do not match"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
}
--- 1208,1219 ----
if (parsedline->addr.ss_family != parsedline->mask.ss_family)
{
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("IP address and mask do not match"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
+ *err_msg = "IP address and mask do not match";
return NULL;
}
}
*************** parse_hba_line(TokenizedLine *tok_line)
*** 1130,1151 ****
field = lnext(field);
if (!field)
{
! ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("end-of-line before authentication method"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
tokens = lfirst(field);
if (tokens->length > 1)
{
! ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("multiple values specified for authentication type"),
errhint("Specify exactly one authentication type per line."),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
token = linitial(tokens);
--- 1224,1247 ----
field = lnext(field);
if (!field)
{
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("end-of-line before authentication method"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
+ *err_msg = "end-of-line before authentication method";
return NULL;
}
tokens = lfirst(field);
if (tokens->length > 1)
{
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("multiple values specified for authentication type"),
errhint("Specify exactly one authentication type per line."),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
+ *err_msg = "multiple values specified for authentication type";
return NULL;
}
token = linitial(tokens);
*************** parse_hba_line(TokenizedLine *tok_line)
*** 1177,1187 ****
{
if (Db_user_namespace)
{
! ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("MD5 authentication is not supported when \"db_user_namespace\" is enabled"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
parsedline->auth_method = uaMD5;
--- 1273,1284 ----
{
if (Db_user_namespace)
{
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("MD5 authentication is not supported when \"db_user_namespace\" is enabled"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
+ *err_msg = "MD5 authentication is not supported when \"db_user_namespace\" is enabled";
return NULL;
}
parsedline->auth_method = uaMD5;
*************** parse_hba_line(TokenizedLine *tok_line)
*** 1214,1236 ****
parsedline->auth_method = uaRADIUS;
else
{
! ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid authentication method \"%s\"",
token->string),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
if (unsupauth)
{
! ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid authentication method \"%s\": not supported by this build",
token->string),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
--- 1311,1337 ----
parsedline->auth_method = uaRADIUS;
else
{
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid authentication method \"%s\"",
token->string),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
+ *err_msg = psprintf("invalid authentication method \"%s\"",
+ token->string);
return NULL;
}
if (unsupauth)
{
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid authentication method \"%s\": not supported by this build",
token->string),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
+ *err_msg = psprintf("invalid authentication method \"%s\": not supported by this build",
+ token->string);
return NULL;
}
*************** parse_hba_line(TokenizedLine *tok_line)
*** 1246,1267 ****
if (parsedline->conntype == ctLocal &&
parsedline->auth_method == uaGSS)
{
! ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("gssapi authentication is not supported on local sockets"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
if (parsedline->conntype != ctLocal &&
parsedline->auth_method == uaPeer)
{
! ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("peer authentication is only supported on local sockets"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
--- 1347,1370 ----
if (parsedline->conntype == ctLocal &&
parsedline->auth_method == uaGSS)
{
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("gssapi authentication is not supported on local sockets"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
+ *err_msg = "gssapi authentication is not supported on local sockets";
return NULL;
}
if (parsedline->conntype != ctLocal &&
parsedline->auth_method == uaPeer)
{
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("peer authentication is only supported on local sockets"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
+ *err_msg = "peer authentication is only supported on local sockets";
return NULL;
}
*************** parse_hba_line(TokenizedLine *tok_line)
*** 1274,1284 ****
if (parsedline->conntype != ctHostSSL &&
parsedline->auth_method == uaCert)
{
! ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("cert authentication is only supported on hostssl connections"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
--- 1377,1388 ----
if (parsedline->conntype != ctHostSSL &&
parsedline->auth_method == uaCert)
{
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("cert authentication is only supported on hostssl connections"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
+ *err_msg = "cert authentication is only supported on hostssl connections";
return NULL;
}
*************** parse_hba_line(TokenizedLine *tok_line)
*** 1323,1338 ****
/*
* Got something that's not a name=value pair.
*/
! ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("authentication option not in name=value format: %s", token->string),
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))
/* parse_hba_auth_opt already logged the error message */
return NULL;
pfree(str);
--- 1427,1444 ----
/*
* Got something that's not a name=value pair.
*/
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("authentication option not in name=value format: %s", token->string),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
+ *err_msg = psprintf("authentication option not in name=value format: %s",
+ token->string);
return NULL;
}
*val++ = '\0'; /* str now holds "name", val holds "value" */
! if (!parse_hba_auth_opt(str, val, parsedline, elevel, err_msg))
/* parse_hba_auth_opt already logged the error message */
return NULL;
pfree(str);
*************** parse_hba_line(TokenizedLine *tok_line)
*** 1360,1380 ****
parsedline->ldapbindpasswd ||
parsedline->ldapsearchattribute)
{
! ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("cannot use ldapbasedn, ldapbinddn, ldapbindpasswd, ldapsearchattribute, or ldapurl together with ldapprefix"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
}
else if (!parsedline->ldapbasedn)
{
! ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("authentication method \"ldap\" requires argument \"ldapbasedn\", \"ldapprefix\", or \"ldapsuffix\" to be set"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
}
--- 1466,1488 ----
parsedline->ldapbindpasswd ||
parsedline->ldapsearchattribute)
{
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("cannot use ldapbasedn, ldapbinddn, ldapbindpasswd, ldapsearchattribute, or ldapurl together with ldapprefix"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
+ *err_msg = "cannot use ldapbasedn, ldapbinddn, ldapbindpasswd, ldapsearchattribute, or ldapurl together with ldapprefix";
return NULL;
}
}
else if (!parsedline->ldapbasedn)
{
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("authentication method \"ldap\" requires argument \"ldapbasedn\", \"ldapprefix\", or \"ldapsuffix\" to be set"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
+ *err_msg = "authentication method \"ldap\" requires argument \"ldapbasedn\", \"ldapprefix\", or \"ldapsuffix\" to be set";
return NULL;
}
}
*************** parse_hba_line(TokenizedLine *tok_line)
*** 1399,1409 ****
/*
* Parse one name-value pair as an authentication option into the given
* HbaLine. Return true if we successfully parse the option, false if we
! * encounter an error.
*/
static bool
! parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline, int line_num)
{
#ifdef USE_LDAP
hbaline->ldapscope = LDAP_SCOPE_SUBTREE;
#endif
--- 1507,1521 ----
/*
* Parse one name-value pair as an authentication option into the given
* HbaLine. Return true if we successfully parse the option, false if we
! * encounter an error. In the event of an error, also log a message at
! * ereport level "elevel", and store a message string into *err_msg.
*/
static bool
! parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline,
! int elevel, char **err_msg)
{
+ int line_num = hbaline->linenumber;
+
#ifdef USE_LDAP
hbaline->ldapscope = LDAP_SCOPE_SUBTREE;
#endif
*************** parse_hba_auth_opt(char *name, char *val
*** 1422,1432 ****
{
if (hbaline->conntype != ctHostSSL)
{
! ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("clientcert can only be configured for \"hostssl\" rows"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return false;
}
if (strcmp(val, "1") == 0)
--- 1534,1545 ----
{
if (hbaline->conntype != ctHostSSL)
{
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("clientcert can only be configured for \"hostssl\" rows"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
+ *err_msg = "clientcert can only be configured for \"hostssl\" rows";
return false;
}
if (strcmp(val, "1") == 0)
*************** parse_hba_auth_opt(char *name, char *val
*** 1437,1447 ****
{
if (hbaline->auth_method == uaCert)
{
! ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("clientcert can not be set to 0 when using \"cert\" authentication"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return false;
}
hbaline->clientcert = false;
--- 1550,1561 ----
{
if (hbaline->auth_method == uaCert)
{
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("clientcert can not be set to 0 when using \"cert\" authentication"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
+ *err_msg = "clientcert can not be set to 0 when using \"cert\" authentication";
return false;
}
hbaline->clientcert = false;
*************** parse_hba_auth_opt(char *name, char *val
*** 1473,1489 ****
rc = ldap_url_parse(val, &urldata);
if (rc != LDAP_SUCCESS)
{
! ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("could not parse LDAP URL \"%s\": %s", val, ldap_err2string(rc))));
return false;
}
if (strcmp(urldata->lud_scheme, "ldap") != 0)
{
! ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("unsupported LDAP URL scheme: %s", urldata->lud_scheme)));
ldap_free_urldesc(urldata);
return false;
}
--- 1587,1607 ----
rc = ldap_url_parse(val, &urldata);
if (rc != LDAP_SUCCESS)
{
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("could not parse LDAP URL \"%s\": %s", val, ldap_err2string(rc))));
+ *err_msg = psprintf("could not parse LDAP URL \"%s\": %s",
+ val, ldap_err2string(rc));
return false;
}
if (strcmp(urldata->lud_scheme, "ldap") != 0)
{
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("unsupported LDAP URL scheme: %s", urldata->lud_scheme)));
+ *err_msg = psprintf("unsupported LDAP URL scheme: %s",
+ urldata->lud_scheme);
ldap_free_urldesc(urldata);
return false;
}
*************** parse_hba_auth_opt(char *name, char *val
*** 1497,1513 ****
hbaline->ldapscope = urldata->lud_scope;
if (urldata->lud_filter)
{
! ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("filters not supported in LDAP URLs")));
ldap_free_urldesc(urldata);
return false;
}
ldap_free_urldesc(urldata);
#else /* not OpenLDAP */
! ereport(LOG,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("LDAP URLs not supported on this platform")));
#endif /* not OpenLDAP */
}
else if (strcmp(name, "ldaptls") == 0)
--- 1615,1633 ----
hbaline->ldapscope = urldata->lud_scope;
if (urldata->lud_filter)
{
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("filters not supported in LDAP URLs")));
+ *err_msg = "filters not supported in LDAP URLs";
ldap_free_urldesc(urldata);
return false;
}
ldap_free_urldesc(urldata);
#else /* not OpenLDAP */
! ereport(elevel,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("LDAP URLs not supported on this platform")));
+ *err_msg = "LDAP URLs not supported on this platform";
#endif /* not OpenLDAP */
}
else if (strcmp(name, "ldaptls") == 0)
*************** parse_hba_auth_opt(char *name, char *val
*** 1529,1539 ****
hbaline->ldapport = atoi(val);
if (hbaline->ldapport == 0)
{
! ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid LDAP port number: \"%s\"", val),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return false;
}
}
--- 1649,1660 ----
hbaline->ldapport = atoi(val);
if (hbaline->ldapport == 0)
{
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid LDAP port number: \"%s\"", val),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
+ *err_msg = psprintf("invalid LDAP port number: \"%s\"", val);
return false;
}
}
*************** parse_hba_auth_opt(char *name, char *val
*** 1617,1628 ****
ret = pg_getaddrinfo_all(val, NULL, &hints, &gai_result);
if (ret || !gai_result)
{
! ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("could not translate RADIUS server name \"%s\" to address: %s",
val, gai_strerror(ret)),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
if (gai_result)
pg_freeaddrinfo_all(hints.ai_family, gai_result);
return false;
--- 1738,1751 ----
ret = pg_getaddrinfo_all(val, NULL, &hints, &gai_result);
if (ret || !gai_result)
{
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("could not translate RADIUS server name \"%s\" to address: %s",
val, gai_strerror(ret)),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
+ *err_msg = psprintf("could not translate RADIUS server name \"%s\" to address: %s",
+ val, gai_strerror(ret));
if (gai_result)
pg_freeaddrinfo_all(hints.ai_family, gai_result);
return false;
*************** parse_hba_auth_opt(char *name, char *val
*** 1636,1646 ****
hbaline->radiusport = atoi(val);
if (hbaline->radiusport == 0)
{
! ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid RADIUS port number: \"%s\"", val),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return false;
}
}
--- 1759,1770 ----
hbaline->radiusport = atoi(val);
if (hbaline->radiusport == 0)
{
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid RADIUS port number: \"%s\"", val),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
+ *err_msg = psprintf("invalid RADIUS port number: \"%s\"", val);
return false;
}
}
*************** parse_hba_auth_opt(char *name, char *val
*** 1656,1667 ****
}
else
{
! ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("unrecognized authentication option name: \"%s\"",
name),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return false;
}
return true;
--- 1780,1793 ----
}
else
{
! ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("unrecognized authentication option name: \"%s\"",
name),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
+ *err_msg = psprintf("unrecognized authentication option name: \"%s\"",
+ name);
return false;
}
return true;
*************** load_hba(void)
*** 1794,1800 ****
return false;
}
! linecxt = tokenize_file(HbaFileName, file, &hba_lines);
FreeFile(file);
/* Now parse all the lines */
--- 1920,1926 ----
return false;
}
! linecxt = tokenize_file(HbaFileName, file, &hba_lines, LOG);
FreeFile(file);
/* Now parse all the lines */
*************** load_hba(void)
*** 1808,1828 ****
TokenizedLine *tok_line = (TokenizedLine *) lfirst(line);
HbaLine *newline;
! if ((newline = parse_hba_line(tok_line)) == NULL)
{
! /*
! * Parse error in the file, so indicate there's a problem. NB: a
! * problem in a line will free the memory for all previous lines
! * as well!
! */
! MemoryContextReset(hbacxt);
! new_parsed_lines = NIL;
ok = false;
/*
* Keep parsing the rest of the file so we can report errors on
! * more than the first row. Error has already been reported in the
! * parsing function, so no need to log it here.
*/
continue;
}
--- 1934,1955 ----
TokenizedLine *tok_line = (TokenizedLine *) lfirst(line);
HbaLine *newline;
! /* don't parse lines that already have errors */
! if (tok_line->err_msg != NULL)
{
! ok = false;
! continue;
! }
!
! if ((newline = parse_hba_line(tok_line, LOG)) == NULL)
! {
! /* Parse error; remember there's trouble */
ok = false;
/*
* Keep parsing the rest of the file so we can report errors on
! * more than the first line. Error has already been logged, no
! * need for more chatter here.
*/
continue;
}
*************** load_hba(void)
*** 1865,1874 ****
}
/*
* Parse one tokenised line from the ident config file and store the result in
* an IdentLine structure.
*
! * Return NULL if parsing fails.
*
* If ident_user is a regular expression (ie. begins with a slash), it is
* compiled and stored in IdentLine structure.
--- 1992,2393 ----
}
/*
+ * This macro specifies the maximum number of authentication options
+ * that are possible with any given authentication method that is supported.
+ * Currently LDAP supports 10, so the macro value is well above the most any
+ * method needs.
+ */
+ #define MAX_HBA_OPTIONS 12
+
+ /*
+ * 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)
+ options[noptions++] =
+ CStringGetTextDatum("clientcert=true");
+
+ 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->ldapscope)
+ options[noptions++] =
+ CStringGetTextDatum(psprintf("ldapscope=%d", hba->ldapscope));
+ }
+
+ if (hba->auth_method == uaRADIUS)
+ {
+ if (hba->radiusserver)
+ options[noptions++] =
+ CStringGetTextDatum(psprintf("radiusserver=%s", hba->radiusserver));
+
+ if (hba->radiussecret)
+ options[noptions++] =
+ CStringGetTextDatum(psprintf("radiussecret=%s", hba->radiussecret));
+
+ if (hba->radiusidentifier)
+ options[noptions++] =
+ CStringGetTextDatum(psprintf("radiusidentifier=%s", hba->radiusidentifier));
+
+ if (hba->radiusport)
+ options[noptions++] =
+ CStringGetTextDatum(psprintf("radiusport=%d", hba->radiusport));
+ }
+
+ Assert(noptions <= MAX_HBA_OPTIONS);
+
+ if (noptions > 0)
+ return construct_array(options, noptions, TEXTOID, -1, false, 'i');
+ else
+ return NULL;
+ }
+
+ /* Number of columns in pg_hba_rules view */
+ #define NUM_PG_HBA_RULES_ATTS 9
+
+ /*
+ * fill_hba_line: construct one row of pg_hba_rules view, add it to tuplestore
+ *
+ * tuple_store: where to store data
+ * tupdesc: tuple descriptor for the view
+ * lineno: pg_hba 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_RULES_ATTS];
+ bool nulls[NUM_PG_HBA_RULES_ATTS];
+ char buffer[NI_MAXHOST];
+ HeapTuple tuple;
+ int index;
+ ListCell *lc;
+ ArrayType *options;
+
+ memset(values, 0, sizeof(values));
+ memset(nulls, 0, sizeof(nulls));
+ index = 0;
+
+ /* line_number */
+ values[index++] = Int32GetDatum(lineno);
+
+ if (hba != NULL)
+ {
+ /* type */
+ 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;
+ default:
+ elog(ERROR, "unrecognized conntype: %d", (int) hba->conntype);
+ break;
+ }
+
+ /* database */
+ if (hba->databases)
+ {
+ /* flatten HbaToken list to string list */
+ 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 */
+ 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 */
+ 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(hba->addr),
+ 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(hba->mask),
+ 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;
+ default:
+ elog(ERROR, "unrecognized ip_cmp_method: %d",
+ (int) hba->ip_cmp_method);
+ break;
+ }
+
+ /* auth_method */
+ values[index++] = CStringGetTextDatum(UserAuthName[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_RULES_ATTS - 2) * sizeof(bool));
+ }
+
+ /* error */
+ if (err_msg)
+ values[NUM_PG_HBA_RULES_ATTS - 1] = CStringGetTextDatum(err_msg);
+ else
+ nulls[NUM_PG_HBA_RULES_ATTS - 1] = true;
+
+ tuple = heap_form_tuple(tupdesc, values, nulls);
+ tuplestore_puttuple(tuple_store, tuple);
+ }
+
+ /*
+ * Read the config file and fill the tuplestore with view records.
+ */
+ static void
+ fill_hba(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 from the pg_hba.conf file.
+ */
+ Datum
+ pg_hba_rules(PG_FUNCTION_ARGS)
+ {
+ Tuplestorestate *tuple_store;
+ TupleDesc tupdesc;
+ MemoryContext old_cxt;
+ 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");
+ Assert(tupdesc->natts == NUM_PG_HBA_RULES_ATTS);
+
+ /* 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);
+
+ /* Fill the tuplestore */
+ fill_hba(tuple_store, tupdesc);
+
+ PG_RETURN_NULL();
+ }
+
+
+ /*
* 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 ident_user is a regular expression (ie. begins with a slash), it is
* compiled and stored in IdentLine structure.
*************** load_ident(void)
*** 2170,2176 ****
return false;
}
! linecxt = tokenize_file(IdentFileName, file, &ident_lines);
FreeFile(file);
/* Now parse all the lines */
--- 2689,2695 ----
return false;
}
! linecxt = tokenize_file(IdentFileName, file, &ident_lines, LOG);
FreeFile(file);
/* Now parse all the lines */
*************** load_ident(void)
*** 2183,2208 ****
{
TokenizedLine *tok_line = (TokenizedLine *) lfirst(line_cell);
if ((newline = parse_ident_line(tok_line)) == NULL)
{
! /*
! * Parse error in the file, so indicate there's a problem. Free
! * all the memory and regular expressions of lines parsed so far.
! */
! foreach(parsed_line_cell, new_parsed_lines)
! {
! newline = (IdentLine *) lfirst(parsed_line_cell);
! if (newline->ident_user[0] == '/')
! pg_regfree(&newline->re);
! }
! MemoryContextReset(ident_context);
! new_parsed_lines = NIL;
ok = false;
/*
* Keep parsing the rest of the file so we can report errors on
! * more than the first row. Error has already been reported in the
! * parsing function, so no need to log it here.
*/
continue;
}
--- 2702,2723 ----
{
TokenizedLine *tok_line = (TokenizedLine *) lfirst(line_cell);
+ /* don't parse lines that already have errors */
+ if (tok_line->err_msg != NULL)
+ {
+ ok = false;
+ continue;
+ }
+
if ((newline = parse_ident_line(tok_line)) == NULL)
{
! /* Parse error; remember there's trouble */
ok = false;
/*
* Keep parsing the rest of the file so we can report errors on
! * more than the first line. Error has already been logged, no
! * need for more chatter here.
*/
continue;
}
*************** load_ident(void)
*** 2216,2222 ****
if (!ok)
{
! /* File contained one or more errors, so bail out */
foreach(parsed_line_cell, new_parsed_lines)
{
newline = (IdentLine *) lfirst(parsed_line_cell);
--- 2731,2741 ----
if (!ok)
{
! /*
! * File contained one or more errors, so bail out, first being careful
! * to clean up whatever we allocated. Most stuff will go away via
! * MemoryContextDelete, but we have to clean up regexes explicitly.
! */
foreach(parsed_line_cell, new_parsed_lines)
{
newline = (IdentLine *) lfirst(parsed_line_cell);
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 31c828a..dd1568d 100644
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
*************** DATA(insert OID = 2084 ( pg_show_all_se
*** 3076,3081 ****
--- 3076,3083 ----
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_ pg_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/include/libpq/hba.h b/src/include/libpq/hba.h
index dc7d257..893767f 100644
*** a/src/include/libpq/hba.h
--- b/src/include/libpq/hba.h
***************
*** 16,25 ****
#include "regex/regex.h"
typedef enum UserAuth
{
uaReject,
! uaImplicitReject,
uaTrust,
uaIdent,
uaPassword,
--- 16,31 ----
#include "regex/regex.h"
+ /*
+ * The following enum represents the authentication methods that
+ * are supported by PostgreSQL.
+ *
+ * Note: keep this in sync with the UserAuthName array in hba.c.
+ */
typedef enum UserAuth
{
uaReject,
! uaImplicitReject, /* Not a user-visible option */
uaTrust,
uaIdent,
uaPassword,
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 60abcad..de7860a 100644
*** a/src/test/regress/expected/rules.out
--- b/src/test/regress/expected/rules.out
*************** pg_group| SELECT pg_authid.rolname AS gr
*** 1338,1343 ****
--- 1338,1353 ----
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,
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers