1996-10-12 09:47:12 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* hba.c
|
1996-10-12 09:47:12 +02:00
|
|
|
* Routines to handle host based authentication (that's the scheme
|
|
|
|
* wherein you authenticate a user by seeing what IP address the system
|
2008-08-01 11:09:49 +02:00
|
|
|
* says he comes from and choosing authentication method based on it).
|
1996-10-12 09:47:12 +02:00
|
|
|
*
|
2023-01-02 21:00:37 +01:00
|
|
|
* Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
|
2001-08-02 01:52:50 +02:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/backend/libpq/hba.c
|
1996-10-12 09:47:12 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
2001-08-01 00:55:45 +02:00
|
|
|
#include "postgres.h"
|
|
|
|
|
2005-02-26 19:43:34 +01:00
|
|
|
#include <ctype.h>
|
1996-10-12 09:47:12 +02:00
|
|
|
#include <pwd.h>
|
1997-08-27 05:48:50 +02:00
|
|
|
#include <fcntl.h>
|
2001-08-21 17:21:25 +02:00
|
|
|
#include <sys/param.h>
|
2001-09-07 21:52:54 +02:00
|
|
|
#include <sys/socket.h>
|
2022-08-13 23:53:28 +02:00
|
|
|
#include <netdb.h>
|
1996-10-12 09:47:12 +02:00
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <arpa/inet.h>
|
1996-11-03 08:00:57 +01:00
|
|
|
#include <unistd.h>
|
1996-10-12 09:47:12 +02:00
|
|
|
|
2017-01-31 00:00:26 +01:00
|
|
|
#include "access/htup_details.h"
|
2011-04-11 00:02:17 +02:00
|
|
|
#include "catalog/pg_collation.h"
|
2017-01-31 00:00:26 +01:00
|
|
|
#include "catalog/pg_type.h"
|
2016-09-02 12:49:59 +02:00
|
|
|
#include "common/ip.h"
|
2020-09-03 18:16:48 +02:00
|
|
|
#include "common/string.h"
|
2017-01-31 00:00:26 +01:00
|
|
|
#include "funcapi.h"
|
2016-09-02 12:49:59 +02:00
|
|
|
#include "libpq/ifaddr.h"
|
1999-07-16 01:04:24 +02:00
|
|
|
#include "libpq/libpq.h"
|
2017-01-31 00:00:26 +01:00
|
|
|
#include "miscadmin.h"
|
2011-04-26 21:40:11 +02:00
|
|
|
#include "postmaster/postmaster.h"
|
2008-11-28 15:26:58 +01:00
|
|
|
#include "regex/regex.h"
|
2010-01-15 10:19:10 +01:00
|
|
|
#include "replication/walsender.h"
|
2000-07-08 05:04:41 +02:00
|
|
|
#include "storage/fd.h"
|
2009-08-29 21:26:52 +02:00
|
|
|
#include "utils/acl.h"
|
2017-01-31 00:00:26 +01:00
|
|
|
#include "utils/builtins.h"
|
2022-11-09 00:47:02 +01:00
|
|
|
#include "utils/conffiles.h"
|
2004-07-11 02:18:45 +02:00
|
|
|
#include "utils/guc.h"
|
2009-08-29 21:26:52 +02:00
|
|
|
#include "utils/lsyscache.h"
|
2011-06-20 23:20:14 +02:00
|
|
|
#include "utils/memutils.h"
|
2019-11-12 04:00:16 +01:00
|
|
|
#include "utils/varlena.h"
|
1999-10-23 05:13:33 +02:00
|
|
|
|
2012-12-04 05:29:56 +01:00
|
|
|
#ifdef USE_LDAP
|
2012-12-04 23:25:51 +01:00
|
|
|
#ifdef WIN32
|
|
|
|
#include <winldap.h>
|
|
|
|
#else
|
2012-12-04 05:29:56 +01:00
|
|
|
#include <ldap.h>
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
2006-07-13 18:49:20 +02:00
|
|
|
|
2004-02-02 17:58:30 +01:00
|
|
|
#define MAX_TOKEN 256
|
|
|
|
|
2009-10-01 03:58:58 +02:00
|
|
|
/* callback data for check_network_callback */
|
|
|
|
typedef struct check_network_data
|
|
|
|
{
|
|
|
|
IPCompareMethod method; /* test method */
|
|
|
|
SockAddr *raddr; /* client's actual address */
|
|
|
|
bool result; /* set to true if match */
|
|
|
|
} check_network_data;
|
|
|
|
|
2022-11-14 03:58:10 +01:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
const char *filename;
|
|
|
|
int linenum;
|
|
|
|
} tokenize_error_callback_arg;
|
2011-06-20 23:20:14 +02:00
|
|
|
|
Refactor regular expression handling in hba.c
AuthToken gains a regular expression, and IdentLine is changed so as it
uses an AuthToken rather than tracking separately the ident user string
used for the regex compilation and its generated regex_t. In the case
of pg_ident.conf, a set of AuthTokens is built in the pre-parsing phase
of the file, and an extra regular expression is compiled when building
the list of IdentLines, after checking the sanity of the fields in a
pre-parsed entry.
The logic in charge of computing and executing regular expressions is
now done in a new set of routines called respectively
regcomp_auth_token() and regexec_auth_token() that are wrappers around
pg_regcomp() and pg_regexec(), working on AuthTokens. While on it, this
patch adds a routine able to free an AuthToken, free_auth_token(), to
simplify a bit the logic around the requirement of using a specific free
routine for computed regular expressions. Note that there are no
functional or behavior changes introduced by this commit.
The goal of this patch is to ease the use of regular expressions with
more items of pg_hba.conf (user list, database list, potentially
hostnames) where AuthTokens are used extensively. This will be tackled
later in a separate patch.
Author: Bertrand Drouvot, Michael Paquier
Discussion: https://postgr.es/m/fff0d7c1-8ad4-76a1-9db3-0ab6ec338bf7@amazon.com
2022-10-19 03:08:49 +02:00
|
|
|
#define token_has_regexp(t) (t->regex != NULL)
|
Support the same patterns for pg-user in pg_ident.conf as in pg_hba.conf
While pg_hba.conf has support for non-literal username matches, and
this commit extends the capabilities that are supported for the
PostgreSQL user listed in an ident entry part of pg_ident.conf, with
support for:
1. The "all" keyword, where all the requested users are allowed.
2. Membership checks using the + prefix.
3. Using a regex to match against multiple roles.
1. is a feature that has been requested by Jelte Fennema, 2. something
that has been mentioned independently by Andrew Dunstan, and 3. is
something I came up with while discussing how to extend the first one,
whose implementation is facilitated by 8fea868.
This allows matching certain system users against many different
postgres users with a single line in pg_ident.conf. Without this, one
would need one line for each of the postgres users that a system user
can log in as, which can be cumbersome to maintain.
Tests are added to the TAP test of peer authentication to provide
coverage for all that.
Note that this introduces a set of backward-incompatible changes to be
able to detect the new patterns, for the following cases:
- A role named "all".
- A role prefixed with '+' characters, which is something that would not
have worked in HBA entries anyway.
- A role prefixed by a slash character, similarly to 8fea868.
Any of these can be still be handled by using quotes in the Postgres
role defined in an ident entry.
A huge advantage of this change is that the code applies the same checks
for the Postgres roles in HBA and ident entries, via the common routine
check_role().
**This compatibility change should be mentioned in the release notes.**
Author: Jelte Fennema
Discussion: https://postgr.es/m/DBBPR83MB0507FEC2E8965012990A80D0F7FC9@DBBPR83MB0507.EURPRD83.prod.outlook.com
2023-01-20 03:21:55 +01:00
|
|
|
#define token_is_member_check(t) (!t->quoted && t->string[0] == '+')
|
2011-06-20 23:20:14 +02:00
|
|
|
#define token_is_keyword(t, k) (!t->quoted && strcmp(t->string, k) == 0)
|
|
|
|
#define token_matches(t, k) (strcmp(t->string, k) == 0)
|
Support the same patterns for pg-user in pg_ident.conf as in pg_hba.conf
While pg_hba.conf has support for non-literal username matches, and
this commit extends the capabilities that are supported for the
PostgreSQL user listed in an ident entry part of pg_ident.conf, with
support for:
1. The "all" keyword, where all the requested users are allowed.
2. Membership checks using the + prefix.
3. Using a regex to match against multiple roles.
1. is a feature that has been requested by Jelte Fennema, 2. something
that has been mentioned independently by Andrew Dunstan, and 3. is
something I came up with while discussing how to extend the first one,
whose implementation is facilitated by 8fea868.
This allows matching certain system users against many different
postgres users with a single line in pg_ident.conf. Without this, one
would need one line for each of the postgres users that a system user
can log in as, which can be cumbersome to maintain.
Tests are added to the TAP test of peer authentication to provide
coverage for all that.
Note that this introduces a set of backward-incompatible changes to be
able to detect the new patterns, for the following cases:
- A role named "all".
- A role prefixed with '+' characters, which is something that would not
have worked in HBA entries anyway.
- A role prefixed by a slash character, similarly to 8fea868.
Any of these can be still be handled by using quotes in the Postgres
role defined in an ident entry.
A huge advantage of this change is that the code applies the same checks
for the Postgres roles in HBA and ident entries, via the common routine
check_role().
**This compatibility change should be mentioned in the release notes.**
Author: Jelte Fennema
Discussion: https://postgr.es/m/DBBPR83MB0507FEC2E8965012990A80D0F7FC9@DBBPR83MB0507.EURPRD83.prod.outlook.com
2023-01-20 03:21:55 +01:00
|
|
|
#define token_matches_insensitive(t,k) (pg_strcasecmp(t->string, k) == 0)
|
2011-06-20 23:20:14 +02:00
|
|
|
|
2022-11-24 00:21:55 +01:00
|
|
|
/*
|
|
|
|
* Memory context holding the list of TokenizedAuthLines when parsing
|
|
|
|
* HBA or ident configuration files. This is created when opening the first
|
2022-11-24 23:40:12 +01:00
|
|
|
* file (depth of CONF_FILE_START_DEPTH).
|
2022-11-24 00:21:55 +01:00
|
|
|
*/
|
|
|
|
static MemoryContext tokenize_context = NULL;
|
|
|
|
|
2011-06-20 23:20:14 +02:00
|
|
|
/*
|
|
|
|
* pre-parsed content of HBA config file: list of HbaLine structs.
|
|
|
|
* parsed_hba_context is the memory context where it lives.
|
|
|
|
*/
|
2008-09-15 14:32:57 +02:00
|
|
|
static List *parsed_hba_lines = NIL;
|
2011-06-20 23:20:14 +02:00
|
|
|
static MemoryContext parsed_hba_context = NULL;
|
2008-09-15 14:32:57 +02:00
|
|
|
|
2001-08-01 00:55:45 +02:00
|
|
|
/*
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
* pre-parsed content of ident mapping file: list of IdentLine structs.
|
|
|
|
* parsed_ident_context is the memory context where it lives.
|
2001-08-01 00:55:45 +02:00
|
|
|
*/
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
static List *parsed_ident_lines = NIL;
|
|
|
|
static MemoryContext parsed_ident_context = NULL;
|
2004-08-29 07:07:03 +02:00
|
|
|
|
2017-01-31 00:00:26 +01:00
|
|
|
/*
|
|
|
|
* 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",
|
2018-01-30 22:50:30 +01:00
|
|
|
"scram-sha-256",
|
2017-01-31 00:00:26 +01:00
|
|
|
"gss",
|
|
|
|
"sspi",
|
|
|
|
"pam",
|
|
|
|
"bsd",
|
|
|
|
"ldap",
|
|
|
|
"cert",
|
|
|
|
"radius",
|
|
|
|
"peer"
|
|
|
|
};
|
|
|
|
|
2022-12-08 14:30:01 +01:00
|
|
|
/*
|
|
|
|
* Make sure UserAuthName[] tracks additions to the UserAuth enum
|
|
|
|
*/
|
|
|
|
StaticAssertDecl(lengthof(UserAuthName) == USER_AUTH_LAST + 1,
|
|
|
|
"UserAuthName[] must match the UserAuth enum");
|
|
|
|
|
2001-07-30 16:50:24 +02:00
|
|
|
|
2022-11-24 00:21:55 +01:00
|
|
|
static List *tokenize_expand_file(List *tokens, const char *outer_filename,
|
|
|
|
const char *inc_filename, int elevel,
|
|
|
|
int depth, char **err_msg);
|
2011-06-20 23:20:14 +02:00
|
|
|
static bool parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline,
|
2017-01-31 00:00:26 +01:00
|
|
|
int elevel, char **err_msg);
|
2022-10-21 02:55:56 +02:00
|
|
|
static int regcomp_auth_token(AuthToken *token, char *filename, int line_num,
|
|
|
|
char **err_msg, int elevel);
|
Refactor regular expression handling in hba.c
AuthToken gains a regular expression, and IdentLine is changed so as it
uses an AuthToken rather than tracking separately the ident user string
used for the regex compilation and its generated regex_t. In the case
of pg_ident.conf, a set of AuthTokens is built in the pre-parsing phase
of the file, and an extra regular expression is compiled when building
the list of IdentLines, after checking the sanity of the fields in a
pre-parsed entry.
The logic in charge of computing and executing regular expressions is
now done in a new set of routines called respectively
regcomp_auth_token() and regexec_auth_token() that are wrappers around
pg_regcomp() and pg_regexec(), working on AuthTokens. While on it, this
patch adds a routine able to free an AuthToken, free_auth_token(), to
simplify a bit the logic around the requirement of using a specific free
routine for computed regular expressions. Note that there are no
functional or behavior changes introduced by this commit.
The goal of this patch is to ease the use of regular expressions with
more items of pg_hba.conf (user list, database list, potentially
hostnames) where AuthTokens are used extensively. This will be tackled
later in a separate patch.
Author: Bertrand Drouvot, Michael Paquier
Discussion: https://postgr.es/m/fff0d7c1-8ad4-76a1-9db3-0ab6ec338bf7@amazon.com
2022-10-19 03:08:49 +02:00
|
|
|
static int regexec_auth_token(const char *match, AuthToken *token,
|
|
|
|
size_t nmatch, regmatch_t pmatch[]);
|
2022-11-14 03:58:10 +01:00
|
|
|
static void tokenize_error_callback(void *arg);
|
2017-01-31 00:00:26 +01:00
|
|
|
|
1999-10-23 05:13:33 +02:00
|
|
|
|
2001-08-01 00:55:45 +02:00
|
|
|
/*
|
2003-04-13 06:07:17 +02:00
|
|
|
* isblank() exists in the ISO C99 spec, but it's not very portable yet,
|
|
|
|
* so provide our own version.
|
2001-08-01 00:55:45 +02:00
|
|
|
*/
|
2008-08-01 11:09:49 +02:00
|
|
|
bool
|
2003-04-13 06:07:17 +02:00
|
|
|
pg_isblank(const char c)
|
1996-10-28 10:03:50 +01:00
|
|
|
{
|
2002-06-26 16:52:08 +02:00
|
|
|
return c == ' ' || c == '\t' || c == '\r';
|
1996-10-28 10:03:50 +01:00
|
|
|
}
|
|
|
|
|
1996-10-12 09:47:12 +02:00
|
|
|
|
2001-07-30 16:50:24 +02:00
|
|
|
/*
|
2017-01-31 00:00:26 +01:00
|
|
|
* Grab one token out of the string pointed to by *lineptr.
|
|
|
|
*
|
2020-09-03 18:16:48 +02:00
|
|
|
* Tokens are strings of non-blank characters bounded by blank characters,
|
|
|
|
* commas, beginning of line, and end of line. Blank means space or tab.
|
|
|
|
*
|
|
|
|
* Tokens can be delimited by double quotes (this allows the inclusion of
|
|
|
|
* blanks or '#', but not newlines). As in SQL, write two double-quotes
|
|
|
|
* to represent a double quote.
|
|
|
|
*
|
|
|
|
* Comments (started by an unquoted '#') are skipped, i.e. the remainder
|
|
|
|
* of the line is ignored.
|
|
|
|
*
|
|
|
|
* (Note that line continuation processing happens before tokenization.
|
|
|
|
* Thus, if a continuation occurs within quoted text or a comment, the
|
|
|
|
* quoted text or comment is considered to continue to the next line.)
|
2017-01-31 00:00:26 +01:00
|
|
|
*
|
|
|
|
* The token, if any, is returned at *buf (a buffer of size bufsz), and
|
|
|
|
* *lineptr is advanced past the token.
|
2005-06-29 00:16:45 +02:00
|
|
|
*
|
2010-03-06 01:45:49 +01:00
|
|
|
* Also, we set *initial_quote to indicate whether there was quoting before
|
|
|
|
* the first character. (We use that to prevent "@x" from being treated
|
|
|
|
* as a file inclusion request. Note that @"x" should be so treated;
|
|
|
|
* we want to allow that to support embedded spaces in file paths.)
|
2017-01-31 00:00:26 +01:00
|
|
|
*
|
2011-06-20 23:20:14 +02:00
|
|
|
* We set *terminating_comma to indicate whether the token is terminated by a
|
2017-01-31 00:00:26 +01:00
|
|
|
* comma (which is not returned).
|
|
|
|
*
|
|
|
|
* In event of an error, log a message at ereport level elevel, and also
|
|
|
|
* set *err_msg to a string describing the error. Currently the only
|
|
|
|
* possible error is token too long for buf.
|
2005-06-29 00:16:45 +02:00
|
|
|
*
|
2017-08-16 06:22:32 +02:00
|
|
|
* If successful: store null-terminated token at *buf and return true.
|
|
|
|
* If no more tokens on line: set *buf = '\0' and return false.
|
|
|
|
* If error: fill buf with truncated or misformatted token and return false.
|
2001-07-30 16:50:24 +02:00
|
|
|
*/
|
2005-06-29 00:16:45 +02:00
|
|
|
static bool
|
2017-01-31 00:00:26 +01:00
|
|
|
next_token(char **lineptr, char *buf, int bufsz,
|
|
|
|
bool *initial_quote, bool *terminating_comma,
|
|
|
|
int elevel, char **err_msg)
|
1996-10-12 09:47:12 +02:00
|
|
|
{
|
|
|
|
int c;
|
2002-12-11 23:17:11 +01:00
|
|
|
char *start_buf = buf;
|
2017-01-31 00:42:41 +01:00
|
|
|
char *end_buf = buf + (bufsz - 1);
|
2002-04-04 06:25:54 +02:00
|
|
|
bool in_quote = false;
|
|
|
|
bool was_quote = false;
|
2003-12-25 04:44:05 +01:00
|
|
|
bool saw_quote = false;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2004-02-02 17:58:30 +01:00
|
|
|
Assert(end_buf > start_buf);
|
|
|
|
|
2010-03-06 01:45:49 +01:00
|
|
|
*initial_quote = false;
|
2011-06-20 23:20:14 +02:00
|
|
|
*terminating_comma = false;
|
2010-03-06 01:45:49 +01:00
|
|
|
|
2017-01-31 00:42:41 +01:00
|
|
|
/* Move over any whitespace and commas preceding the next token */
|
2013-03-10 15:54:37 +01:00
|
|
|
while ((c = (*(*lineptr)++)) != '\0' && (pg_isblank(c) || c == ','))
|
2001-07-30 16:50:24 +02:00
|
|
|
;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2004-02-02 17:58:30 +01:00
|
|
|
/*
|
2017-01-31 00:42:41 +01:00
|
|
|
* Build a token in buf of next characters up to EOL, unquoted comma, or
|
|
|
|
* unquoted whitespace.
|
2004-02-02 17:58:30 +01:00
|
|
|
*/
|
2017-01-31 00:42:41 +01:00
|
|
|
while (c != '\0' &&
|
2008-07-24 19:43:45 +02:00
|
|
|
(!pg_isblank(c) || in_quote))
|
1996-10-12 09:47:12 +02:00
|
|
|
{
|
2004-02-02 17:58:30 +01:00
|
|
|
/* skip comments to EOL */
|
|
|
|
if (c == '#' && !in_quote)
|
|
|
|
{
|
2017-01-31 00:42:41 +01:00
|
|
|
while ((c = (*(*lineptr)++)) != '\0')
|
2004-02-02 17:58:30 +01:00
|
|
|
;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (buf >= end_buf)
|
|
|
|
{
|
2004-05-25 21:11:14 +02:00
|
|
|
*buf = '\0';
|
2017-01-31 00:00:26 +01:00
|
|
|
ereport(elevel,
|
2004-02-02 17:58:30 +01:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
|
|
|
errmsg("authentication file token too long, skipping: \"%s\"",
|
2004-05-25 21:11:14 +02:00
|
|
|
start_buf)));
|
2017-01-31 00:00:26 +01:00
|
|
|
*err_msg = "authentication file token too long";
|
2004-02-02 17:58:30 +01:00
|
|
|
/* Discard remainder of line */
|
2017-01-31 00:42:41 +01:00
|
|
|
while ((c = (*(*lineptr)++)) != '\0')
|
2004-02-02 17:58:30 +01:00
|
|
|
;
|
2017-01-31 00:42:41 +01:00
|
|
|
/* Un-eat the '\0', in case we're called again */
|
|
|
|
(*lineptr)--;
|
2017-01-31 00:00:26 +01:00
|
|
|
return false;
|
2004-02-02 17:58:30 +01:00
|
|
|
}
|
|
|
|
|
2017-01-31 00:42:41 +01:00
|
|
|
/* we do not pass back a terminating comma in the token */
|
2008-07-24 19:43:45 +02:00
|
|
|
if (c == ',' && !in_quote)
|
2011-06-20 23:20:14 +02:00
|
|
|
{
|
|
|
|
*terminating_comma = true;
|
2004-02-02 17:58:30 +01:00
|
|
|
break;
|
2011-06-20 23:20:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (c != '"' || was_quote)
|
|
|
|
*buf++ = c;
|
2004-02-02 17:58:30 +01:00
|
|
|
|
|
|
|
/* Literal double-quote is two double-quotes */
|
|
|
|
if (in_quote && c == '"')
|
|
|
|
was_quote = !was_quote;
|
|
|
|
else
|
|
|
|
was_quote = false;
|
|
|
|
|
|
|
|
if (c == '"')
|
1996-10-12 09:47:12 +02:00
|
|
|
{
|
2004-02-02 17:58:30 +01:00
|
|
|
in_quote = !in_quote;
|
|
|
|
saw_quote = true;
|
2010-03-06 01:45:49 +01:00
|
|
|
if (buf == start_buf)
|
|
|
|
*initial_quote = true;
|
1996-10-12 09:47:12 +02:00
|
|
|
}
|
2001-10-25 07:50:21 +02:00
|
|
|
|
2013-03-10 15:54:37 +01:00
|
|
|
c = *(*lineptr)++;
|
1996-10-12 09:47:12 +02:00
|
|
|
}
|
2003-12-25 04:44:05 +01:00
|
|
|
|
2004-02-02 17:58:30 +01:00
|
|
|
/*
|
2017-01-31 00:42:41 +01:00
|
|
|
* Un-eat the char right after the token (critical in case it is '\0',
|
|
|
|
* else next call will read past end of string).
|
2004-02-02 17:58:30 +01:00
|
|
|
*/
|
2013-03-10 15:54:37 +01:00
|
|
|
(*lineptr)--;
|
2004-02-02 17:58:30 +01:00
|
|
|
|
|
|
|
*buf = '\0';
|
2003-12-25 04:44:05 +01:00
|
|
|
|
2005-06-29 00:16:45 +02:00
|
|
|
return (saw_quote || buf > start_buf);
|
1996-10-12 09:47:12 +02:00
|
|
|
}
|
|
|
|
|
2017-01-31 00:00:26 +01:00
|
|
|
/*
|
Refactor code related to pg_hba_file_rules() into new file
hba.c is growing big, and more contents are planned for it. In order to
prepare for this future work, this commit moves all the code related to
the system function processing the contents of pg_hba.conf,
pg_hba_file_rules() to a new file called hbafuncs.c, which will be used
as the location for the SQL portion of the authentication file parsing.
While on it, HbaToken, the structure holding a string token lexed from a
configuration file related to authentication, is renamed to a more
generic AuthToken, as it gets used not only for pg_hba.conf, but also
for pg_ident.conf. TokenizedLine is now named TokenizedAuthLine.
The size of hba.c is reduced by ~12%.
Author: Julien Rouhaud
Reviewed-by: Aleksander Alekseev, Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-03-24 04:42:30 +01:00
|
|
|
* Construct a palloc'd AuthToken struct, copying the given string.
|
2017-01-31 00:00:26 +01:00
|
|
|
*/
|
Refactor code related to pg_hba_file_rules() into new file
hba.c is growing big, and more contents are planned for it. In order to
prepare for this future work, this commit moves all the code related to
the system function processing the contents of pg_hba.conf,
pg_hba_file_rules() to a new file called hbafuncs.c, which will be used
as the location for the SQL portion of the authentication file parsing.
While on it, HbaToken, the structure holding a string token lexed from a
configuration file related to authentication, is renamed to a more
generic AuthToken, as it gets used not only for pg_hba.conf, but also
for pg_ident.conf. TokenizedLine is now named TokenizedAuthLine.
The size of hba.c is reduced by ~12%.
Author: Julien Rouhaud
Reviewed-by: Aleksander Alekseev, Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-03-24 04:42:30 +01:00
|
|
|
static AuthToken *
|
|
|
|
make_auth_token(const char *token, bool quoted)
|
2011-06-20 23:20:14 +02:00
|
|
|
{
|
Refactor code related to pg_hba_file_rules() into new file
hba.c is growing big, and more contents are planned for it. In order to
prepare for this future work, this commit moves all the code related to
the system function processing the contents of pg_hba.conf,
pg_hba_file_rules() to a new file called hbafuncs.c, which will be used
as the location for the SQL portion of the authentication file parsing.
While on it, HbaToken, the structure holding a string token lexed from a
configuration file related to authentication, is renamed to a more
generic AuthToken, as it gets used not only for pg_hba.conf, but also
for pg_ident.conf. TokenizedLine is now named TokenizedAuthLine.
The size of hba.c is reduced by ~12%.
Author: Julien Rouhaud
Reviewed-by: Aleksander Alekseev, Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-03-24 04:42:30 +01:00
|
|
|
AuthToken *authtoken;
|
2011-06-20 23:20:14 +02:00
|
|
|
int toklen;
|
|
|
|
|
|
|
|
toklen = strlen(token);
|
2017-01-31 00:00:26 +01:00
|
|
|
/* we copy string into same palloc block as the struct */
|
Refactor regular expression handling in hba.c
AuthToken gains a regular expression, and IdentLine is changed so as it
uses an AuthToken rather than tracking separately the ident user string
used for the regex compilation and its generated regex_t. In the case
of pg_ident.conf, a set of AuthTokens is built in the pre-parsing phase
of the file, and an extra regular expression is compiled when building
the list of IdentLines, after checking the sanity of the fields in a
pre-parsed entry.
The logic in charge of computing and executing regular expressions is
now done in a new set of routines called respectively
regcomp_auth_token() and regexec_auth_token() that are wrappers around
pg_regcomp() and pg_regexec(), working on AuthTokens. While on it, this
patch adds a routine able to free an AuthToken, free_auth_token(), to
simplify a bit the logic around the requirement of using a specific free
routine for computed regular expressions. Note that there are no
functional or behavior changes introduced by this commit.
The goal of this patch is to ease the use of regular expressions with
more items of pg_hba.conf (user list, database list, potentially
hostnames) where AuthTokens are used extensively. This will be tackled
later in a separate patch.
Author: Bertrand Drouvot, Michael Paquier
Discussion: https://postgr.es/m/fff0d7c1-8ad4-76a1-9db3-0ab6ec338bf7@amazon.com
2022-10-19 03:08:49 +02:00
|
|
|
authtoken = (AuthToken *) palloc0(sizeof(AuthToken) + toklen + 1);
|
Refactor code related to pg_hba_file_rules() into new file
hba.c is growing big, and more contents are planned for it. In order to
prepare for this future work, this commit moves all the code related to
the system function processing the contents of pg_hba.conf,
pg_hba_file_rules() to a new file called hbafuncs.c, which will be used
as the location for the SQL portion of the authentication file parsing.
While on it, HbaToken, the structure holding a string token lexed from a
configuration file related to authentication, is renamed to a more
generic AuthToken, as it gets used not only for pg_hba.conf, but also
for pg_ident.conf. TokenizedLine is now named TokenizedAuthLine.
The size of hba.c is reduced by ~12%.
Author: Julien Rouhaud
Reviewed-by: Aleksander Alekseev, Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-03-24 04:42:30 +01:00
|
|
|
authtoken->string = (char *) authtoken + sizeof(AuthToken);
|
|
|
|
authtoken->quoted = quoted;
|
Refactor regular expression handling in hba.c
AuthToken gains a regular expression, and IdentLine is changed so as it
uses an AuthToken rather than tracking separately the ident user string
used for the regex compilation and its generated regex_t. In the case
of pg_ident.conf, a set of AuthTokens is built in the pre-parsing phase
of the file, and an extra regular expression is compiled when building
the list of IdentLines, after checking the sanity of the fields in a
pre-parsed entry.
The logic in charge of computing and executing regular expressions is
now done in a new set of routines called respectively
regcomp_auth_token() and regexec_auth_token() that are wrappers around
pg_regcomp() and pg_regexec(), working on AuthTokens. While on it, this
patch adds a routine able to free an AuthToken, free_auth_token(), to
simplify a bit the logic around the requirement of using a specific free
routine for computed regular expressions. Note that there are no
functional or behavior changes introduced by this commit.
The goal of this patch is to ease the use of regular expressions with
more items of pg_hba.conf (user list, database list, potentially
hostnames) where AuthTokens are used extensively. This will be tackled
later in a separate patch.
Author: Bertrand Drouvot, Michael Paquier
Discussion: https://postgr.es/m/fff0d7c1-8ad4-76a1-9db3-0ab6ec338bf7@amazon.com
2022-10-19 03:08:49 +02:00
|
|
|
authtoken->regex = NULL;
|
Refactor code related to pg_hba_file_rules() into new file
hba.c is growing big, and more contents are planned for it. In order to
prepare for this future work, this commit moves all the code related to
the system function processing the contents of pg_hba.conf,
pg_hba_file_rules() to a new file called hbafuncs.c, which will be used
as the location for the SQL portion of the authentication file parsing.
While on it, HbaToken, the structure holding a string token lexed from a
configuration file related to authentication, is renamed to a more
generic AuthToken, as it gets used not only for pg_hba.conf, but also
for pg_ident.conf. TokenizedLine is now named TokenizedAuthLine.
The size of hba.c is reduced by ~12%.
Author: Julien Rouhaud
Reviewed-by: Aleksander Alekseev, Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-03-24 04:42:30 +01:00
|
|
|
memcpy(authtoken->string, token, toklen + 1);
|
2011-06-20 23:20:14 +02:00
|
|
|
|
Refactor code related to pg_hba_file_rules() into new file
hba.c is growing big, and more contents are planned for it. In order to
prepare for this future work, this commit moves all the code related to
the system function processing the contents of pg_hba.conf,
pg_hba_file_rules() to a new file called hbafuncs.c, which will be used
as the location for the SQL portion of the authentication file parsing.
While on it, HbaToken, the structure holding a string token lexed from a
configuration file related to authentication, is renamed to a more
generic AuthToken, as it gets used not only for pg_hba.conf, but also
for pg_ident.conf. TokenizedLine is now named TokenizedAuthLine.
The size of hba.c is reduced by ~12%.
Author: Julien Rouhaud
Reviewed-by: Aleksander Alekseev, Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-03-24 04:42:30 +01:00
|
|
|
return authtoken;
|
2011-06-20 23:20:14 +02:00
|
|
|
}
|
|
|
|
|
Refactor regular expression handling in hba.c
AuthToken gains a regular expression, and IdentLine is changed so as it
uses an AuthToken rather than tracking separately the ident user string
used for the regex compilation and its generated regex_t. In the case
of pg_ident.conf, a set of AuthTokens is built in the pre-parsing phase
of the file, and an extra regular expression is compiled when building
the list of IdentLines, after checking the sanity of the fields in a
pre-parsed entry.
The logic in charge of computing and executing regular expressions is
now done in a new set of routines called respectively
regcomp_auth_token() and regexec_auth_token() that are wrappers around
pg_regcomp() and pg_regexec(), working on AuthTokens. While on it, this
patch adds a routine able to free an AuthToken, free_auth_token(), to
simplify a bit the logic around the requirement of using a specific free
routine for computed regular expressions. Note that there are no
functional or behavior changes introduced by this commit.
The goal of this patch is to ease the use of regular expressions with
more items of pg_hba.conf (user list, database list, potentially
hostnames) where AuthTokens are used extensively. This will be tackled
later in a separate patch.
Author: Bertrand Drouvot, Michael Paquier
Discussion: https://postgr.es/m/fff0d7c1-8ad4-76a1-9db3-0ab6ec338bf7@amazon.com
2022-10-19 03:08:49 +02:00
|
|
|
/*
|
|
|
|
* Free an AuthToken, that may include a regular expression that needs
|
|
|
|
* to be cleaned up explicitly.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
free_auth_token(AuthToken *token)
|
|
|
|
{
|
|
|
|
if (token_has_regexp(token))
|
|
|
|
pg_regfree(token->regex);
|
|
|
|
}
|
|
|
|
|
2002-04-04 06:25:54 +02:00
|
|
|
/*
|
Refactor code related to pg_hba_file_rules() into new file
hba.c is growing big, and more contents are planned for it. In order to
prepare for this future work, this commit moves all the code related to
the system function processing the contents of pg_hba.conf,
pg_hba_file_rules() to a new file called hbafuncs.c, which will be used
as the location for the SQL portion of the authentication file parsing.
While on it, HbaToken, the structure holding a string token lexed from a
configuration file related to authentication, is renamed to a more
generic AuthToken, as it gets used not only for pg_hba.conf, but also
for pg_ident.conf. TokenizedLine is now named TokenizedAuthLine.
The size of hba.c is reduced by ~12%.
Author: Julien Rouhaud
Reviewed-by: Aleksander Alekseev, Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-03-24 04:42:30 +01:00
|
|
|
* Copy a AuthToken struct into freshly palloc'd memory.
|
2011-06-20 23:20:14 +02:00
|
|
|
*/
|
Refactor code related to pg_hba_file_rules() into new file
hba.c is growing big, and more contents are planned for it. In order to
prepare for this future work, this commit moves all the code related to
the system function processing the contents of pg_hba.conf,
pg_hba_file_rules() to a new file called hbafuncs.c, which will be used
as the location for the SQL portion of the authentication file parsing.
While on it, HbaToken, the structure holding a string token lexed from a
configuration file related to authentication, is renamed to a more
generic AuthToken, as it gets used not only for pg_hba.conf, but also
for pg_ident.conf. TokenizedLine is now named TokenizedAuthLine.
The size of hba.c is reduced by ~12%.
Author: Julien Rouhaud
Reviewed-by: Aleksander Alekseev, Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-03-24 04:42:30 +01:00
|
|
|
static AuthToken *
|
|
|
|
copy_auth_token(AuthToken *in)
|
2011-06-20 23:20:14 +02:00
|
|
|
{
|
Refactor code related to pg_hba_file_rules() into new file
hba.c is growing big, and more contents are planned for it. In order to
prepare for this future work, this commit moves all the code related to
the system function processing the contents of pg_hba.conf,
pg_hba_file_rules() to a new file called hbafuncs.c, which will be used
as the location for the SQL portion of the authentication file parsing.
While on it, HbaToken, the structure holding a string token lexed from a
configuration file related to authentication, is renamed to a more
generic AuthToken, as it gets used not only for pg_hba.conf, but also
for pg_ident.conf. TokenizedLine is now named TokenizedAuthLine.
The size of hba.c is reduced by ~12%.
Author: Julien Rouhaud
Reviewed-by: Aleksander Alekseev, Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-03-24 04:42:30 +01:00
|
|
|
AuthToken *out = make_auth_token(in->string, in->quoted);
|
2011-06-20 23:20:14 +02:00
|
|
|
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
Refactor regular expression handling in hba.c
AuthToken gains a regular expression, and IdentLine is changed so as it
uses an AuthToken rather than tracking separately the ident user string
used for the regex compilation and its generated regex_t. In the case
of pg_ident.conf, a set of AuthTokens is built in the pre-parsing phase
of the file, and an extra regular expression is compiled when building
the list of IdentLines, after checking the sanity of the fields in a
pre-parsed entry.
The logic in charge of computing and executing regular expressions is
now done in a new set of routines called respectively
regcomp_auth_token() and regexec_auth_token() that are wrappers around
pg_regcomp() and pg_regexec(), working on AuthTokens. While on it, this
patch adds a routine able to free an AuthToken, free_auth_token(), to
simplify a bit the logic around the requirement of using a specific free
routine for computed regular expressions. Note that there are no
functional or behavior changes introduced by this commit.
The goal of this patch is to ease the use of regular expressions with
more items of pg_hba.conf (user list, database list, potentially
hostnames) where AuthTokens are used extensively. This will be tackled
later in a separate patch.
Author: Bertrand Drouvot, Michael Paquier
Discussion: https://postgr.es/m/fff0d7c1-8ad4-76a1-9db3-0ab6ec338bf7@amazon.com
2022-10-19 03:08:49 +02:00
|
|
|
/*
|
|
|
|
* Compile the regular expression and store it in the AuthToken given in
|
2022-10-21 02:55:56 +02:00
|
|
|
* input. Returns the result of pg_regcomp(). On error, the details are
|
|
|
|
* stored in "err_msg".
|
Refactor regular expression handling in hba.c
AuthToken gains a regular expression, and IdentLine is changed so as it
uses an AuthToken rather than tracking separately the ident user string
used for the regex compilation and its generated regex_t. In the case
of pg_ident.conf, a set of AuthTokens is built in the pre-parsing phase
of the file, and an extra regular expression is compiled when building
the list of IdentLines, after checking the sanity of the fields in a
pre-parsed entry.
The logic in charge of computing and executing regular expressions is
now done in a new set of routines called respectively
regcomp_auth_token() and regexec_auth_token() that are wrappers around
pg_regcomp() and pg_regexec(), working on AuthTokens. While on it, this
patch adds a routine able to free an AuthToken, free_auth_token(), to
simplify a bit the logic around the requirement of using a specific free
routine for computed regular expressions. Note that there are no
functional or behavior changes introduced by this commit.
The goal of this patch is to ease the use of regular expressions with
more items of pg_hba.conf (user list, database list, potentially
hostnames) where AuthTokens are used extensively. This will be tackled
later in a separate patch.
Author: Bertrand Drouvot, Michael Paquier
Discussion: https://postgr.es/m/fff0d7c1-8ad4-76a1-9db3-0ab6ec338bf7@amazon.com
2022-10-19 03:08:49 +02:00
|
|
|
*/
|
|
|
|
static int
|
2022-10-21 02:55:56 +02:00
|
|
|
regcomp_auth_token(AuthToken *token, char *filename, int line_num,
|
|
|
|
char **err_msg, int elevel)
|
Refactor regular expression handling in hba.c
AuthToken gains a regular expression, and IdentLine is changed so as it
uses an AuthToken rather than tracking separately the ident user string
used for the regex compilation and its generated regex_t. In the case
of pg_ident.conf, a set of AuthTokens is built in the pre-parsing phase
of the file, and an extra regular expression is compiled when building
the list of IdentLines, after checking the sanity of the fields in a
pre-parsed entry.
The logic in charge of computing and executing regular expressions is
now done in a new set of routines called respectively
regcomp_auth_token() and regexec_auth_token() that are wrappers around
pg_regcomp() and pg_regexec(), working on AuthTokens. While on it, this
patch adds a routine able to free an AuthToken, free_auth_token(), to
simplify a bit the logic around the requirement of using a specific free
routine for computed regular expressions. Note that there are no
functional or behavior changes introduced by this commit.
The goal of this patch is to ease the use of regular expressions with
more items of pg_hba.conf (user list, database list, potentially
hostnames) where AuthTokens are used extensively. This will be tackled
later in a separate patch.
Author: Bertrand Drouvot, Michael Paquier
Discussion: https://postgr.es/m/fff0d7c1-8ad4-76a1-9db3-0ab6ec338bf7@amazon.com
2022-10-19 03:08:49 +02:00
|
|
|
{
|
|
|
|
pg_wchar *wstr;
|
|
|
|
int wlen;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
Assert(token->regex == NULL);
|
|
|
|
|
|
|
|
if (token->string[0] != '/')
|
|
|
|
return 0; /* nothing to compile */
|
|
|
|
|
|
|
|
token->regex = (regex_t *) palloc0(sizeof(regex_t));
|
|
|
|
wstr = palloc((strlen(token->string + 1) + 1) * sizeof(pg_wchar));
|
|
|
|
wlen = pg_mb2wchar_with_len(token->string + 1,
|
|
|
|
wstr, strlen(token->string + 1));
|
|
|
|
|
|
|
|
rc = pg_regcomp(token->regex, wstr, wlen, REG_ADVANCED, C_COLLATION_OID);
|
|
|
|
|
2022-10-21 02:55:56 +02:00
|
|
|
if (rc)
|
|
|
|
{
|
|
|
|
char errstr[100];
|
|
|
|
|
|
|
|
pg_regerror(rc, token->regex, errstr, sizeof(errstr));
|
|
|
|
ereport(elevel,
|
|
|
|
(errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
|
|
|
|
errmsg("invalid regular expression \"%s\": %s",
|
|
|
|
token->string + 1, errstr),
|
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
|
|
|
line_num, filename)));
|
|
|
|
|
|
|
|
*err_msg = psprintf("invalid regular expression \"%s\": %s",
|
|
|
|
token->string + 1, errstr);
|
|
|
|
}
|
|
|
|
|
Refactor regular expression handling in hba.c
AuthToken gains a regular expression, and IdentLine is changed so as it
uses an AuthToken rather than tracking separately the ident user string
used for the regex compilation and its generated regex_t. In the case
of pg_ident.conf, a set of AuthTokens is built in the pre-parsing phase
of the file, and an extra regular expression is compiled when building
the list of IdentLines, after checking the sanity of the fields in a
pre-parsed entry.
The logic in charge of computing and executing regular expressions is
now done in a new set of routines called respectively
regcomp_auth_token() and regexec_auth_token() that are wrappers around
pg_regcomp() and pg_regexec(), working on AuthTokens. While on it, this
patch adds a routine able to free an AuthToken, free_auth_token(), to
simplify a bit the logic around the requirement of using a specific free
routine for computed regular expressions. Note that there are no
functional or behavior changes introduced by this commit.
The goal of this patch is to ease the use of regular expressions with
more items of pg_hba.conf (user list, database list, potentially
hostnames) where AuthTokens are used extensively. This will be tackled
later in a separate patch.
Author: Bertrand Drouvot, Michael Paquier
Discussion: https://postgr.es/m/fff0d7c1-8ad4-76a1-9db3-0ab6ec338bf7@amazon.com
2022-10-19 03:08:49 +02:00
|
|
|
pfree(wstr);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Execute a regular expression computed in an AuthToken, checking for a match
|
|
|
|
* with the string specified in "match". The caller may optionally give an
|
|
|
|
* array to store the matches. Returns the result of pg_regexec().
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
regexec_auth_token(const char *match, AuthToken *token, size_t nmatch,
|
|
|
|
regmatch_t pmatch[])
|
|
|
|
{
|
|
|
|
pg_wchar *wmatchstr;
|
|
|
|
int wmatchlen;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
Assert(token->string[0] == '/' && token->regex);
|
|
|
|
|
|
|
|
wmatchstr = palloc((strlen(match) + 1) * sizeof(pg_wchar));
|
|
|
|
wmatchlen = pg_mb2wchar_with_len(match, wmatchstr, strlen(match));
|
|
|
|
|
|
|
|
r = pg_regexec(token->regex, wmatchstr, wmatchlen, 0, NULL, nmatch, pmatch, 0);
|
|
|
|
|
|
|
|
pfree(wmatchstr);
|
|
|
|
return r;
|
|
|
|
}
|
2011-06-20 23:20:14 +02:00
|
|
|
|
|
|
|
/*
|
2013-03-10 15:54:37 +01:00
|
|
|
* Tokenize one HBA field from a line, handling file inclusion and comma lists.
|
2004-09-18 03:22:58 +02:00
|
|
|
*
|
2017-01-31 00:00:26 +01:00
|
|
|
* filename: current file's pathname (needed to resolve relative pathnames)
|
|
|
|
* *lineptr: current line pointer, which will be advanced past field
|
|
|
|
*
|
|
|
|
* In event of an error, log a message at ereport level elevel, and also
|
|
|
|
* set *err_msg to a string describing the error. Note that the result
|
|
|
|
* may be non-NIL anyway, so *err_msg must be tested to determine whether
|
|
|
|
* there was an error.
|
|
|
|
*
|
Refactor code related to pg_hba_file_rules() into new file
hba.c is growing big, and more contents are planned for it. In order to
prepare for this future work, this commit moves all the code related to
the system function processing the contents of pg_hba.conf,
pg_hba_file_rules() to a new file called hbafuncs.c, which will be used
as the location for the SQL portion of the authentication file parsing.
While on it, HbaToken, the structure holding a string token lexed from a
configuration file related to authentication, is renamed to a more
generic AuthToken, as it gets used not only for pg_hba.conf, but also
for pg_ident.conf. TokenizedLine is now named TokenizedAuthLine.
The size of hba.c is reduced by ~12%.
Author: Julien Rouhaud
Reviewed-by: Aleksander Alekseev, Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-03-24 04:42:30 +01:00
|
|
|
* The result is a List of AuthToken structs, one for each token in the field,
|
2011-06-20 23:20:14 +02:00
|
|
|
* or NIL if we reached EOL.
|
2002-04-04 06:25:54 +02:00
|
|
|
*/
|
2011-06-20 23:20:14 +02:00
|
|
|
static List *
|
2017-01-31 00:00:26 +01:00
|
|
|
next_field_expand(const char *filename, char **lineptr,
|
Invent open_auth_file() in hba.c to refactor authentication file opening
This adds a check on the recursion depth when including authentication
configuration files, something that has never been done when processing
'@' files for database and user name lists in pg_hba.conf. On HEAD,
this was leading to a rather confusing error, as of:
FATAL: exceeded maxAllocatedDescs (NN) while trying to open file "/path/blah.conf"
This refactors the code so as the error reported is now the following,
which is the same as for GUCs:
FATAL: could not open file "/path/blah.conf": maximum nesting depth exceeded
This reduces a bit the verbosity of the error message used for files
included in user and database lists, reporting only the file name of
what's failing to load, without mentioning the relative or absolute path
specified after '@' in a HBA file. The absolute path is built upon what
'@' defines anyway, so there is no actual loss of information. This
makes the future inclusion logic much simpler. A follow-up patch will
add an error context to be able to track on which line of which file the
inclusion is failing, to close the loop, providing all the information
needed to know the full chain of events.
This logic has been extracted from a larger patch written by Julien,
rewritten by me to have a unique code path calling AllocateFile() on
authentication files, and is useful on its own. This new interface
will be used later for authentication files included with
@include[_dir,_if_exists], in a follow-up patch.
Author: Michael Paquier, Julien Rouhaud
Discussion: https://www.postgresql.org/message-id/Y2xUBJ+S+Z0zbxRW@paquier.xyz
2022-11-14 02:21:42 +01:00
|
|
|
int elevel, int depth, char **err_msg)
|
2002-04-04 06:25:54 +02:00
|
|
|
{
|
|
|
|
char buf[MAX_TOKEN];
|
|
|
|
bool trailing_comma;
|
2010-03-06 01:45:49 +01:00
|
|
|
bool initial_quote;
|
2011-06-20 23:20:14 +02:00
|
|
|
List *tokens = NIL;
|
2002-04-04 06:25:54 +02:00
|
|
|
|
|
|
|
do
|
|
|
|
{
|
2017-01-31 00:00:26 +01:00
|
|
|
if (!next_token(lineptr, buf, sizeof(buf),
|
|
|
|
&initial_quote, &trailing_comma,
|
|
|
|
elevel, err_msg))
|
2002-04-04 06:25:54 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
/* Is this referencing a file? */
|
2010-03-06 01:45:49 +01:00
|
|
|
if (!initial_quote && buf[0] == '@' && buf[1] != '\0')
|
2022-11-24 00:21:55 +01:00
|
|
|
tokens = tokenize_expand_file(tokens, filename, buf + 1,
|
|
|
|
elevel, depth + 1, err_msg);
|
2002-04-04 06:25:54 +02:00
|
|
|
else
|
2022-11-24 00:21:55 +01:00
|
|
|
{
|
|
|
|
MemoryContext oldcxt;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* lappend() may do its own allocations, so move to the context
|
|
|
|
* for the list of tokens.
|
|
|
|
*/
|
|
|
|
oldcxt = MemoryContextSwitchTo(tokenize_context);
|
Refactor code related to pg_hba_file_rules() into new file
hba.c is growing big, and more contents are planned for it. In order to
prepare for this future work, this commit moves all the code related to
the system function processing the contents of pg_hba.conf,
pg_hba_file_rules() to a new file called hbafuncs.c, which will be used
as the location for the SQL portion of the authentication file parsing.
While on it, HbaToken, the structure holding a string token lexed from a
configuration file related to authentication, is renamed to a more
generic AuthToken, as it gets used not only for pg_hba.conf, but also
for pg_ident.conf. TokenizedLine is now named TokenizedAuthLine.
The size of hba.c is reduced by ~12%.
Author: Julien Rouhaud
Reviewed-by: Aleksander Alekseev, Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-03-24 04:42:30 +01:00
|
|
|
tokens = lappend(tokens, make_auth_token(buf, initial_quote));
|
2022-11-24 00:21:55 +01:00
|
|
|
MemoryContextSwitchTo(oldcxt);
|
|
|
|
}
|
2017-01-31 00:00:26 +01:00
|
|
|
} while (trailing_comma && (*err_msg == NULL));
|
2002-04-04 06:25:54 +02:00
|
|
|
|
2011-06-20 23:20:14 +02:00
|
|
|
return tokens;
|
2002-04-04 06:25:54 +02:00
|
|
|
}
|
|
|
|
|
Add support for file inclusions in HBA and ident configuration files
pg_hba.conf and pg_ident.conf gain support for three record keywords:
- "include", to include a file.
- "include_if_exists", to include a file, ignoring it if missing.
- "include_dir", to include a directory of files. These are classified
by name (C locale, mostly) and need to be prefixed by ".conf", hence
following the same rules as GUCs.
This commit relies on the refactoring pieces done in efc9816, ad6c528,
783e8c6 and 1b73d0b, adding a small wrapper to build a list of
TokenizedAuthLines (tokenize_include_file), and the code is shaped to
offer some symmetry with what is done for GUCs with the same options.
pg_hba_file_rules and pg_ident_file_mappings gain a new field called
file_name, to track from which file a record is located, taking
advantage of the addition of rule_number in c591300 to offer an
organized view of the HBA or ident records loaded.
Bump catalog version.
Author: Julien Rouhaud
Reviewed-by: Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-11-24 05:51:34 +01:00
|
|
|
/*
|
|
|
|
* tokenize_include_file
|
|
|
|
* Include a file from another file into an hba "field".
|
|
|
|
*
|
|
|
|
* Opens and tokenises a file included from another authentication file
|
|
|
|
* with one of the include records ("include", "include_if_exists" or
|
|
|
|
* "include_dir"), and assign all values found to an existing list of
|
|
|
|
* list of AuthTokens.
|
|
|
|
*
|
|
|
|
* All new tokens are allocated in the memory context dedicated to the
|
|
|
|
* tokenization, aka tokenize_context.
|
|
|
|
*
|
|
|
|
* If missing_ok is true, ignore a missing file.
|
|
|
|
*
|
|
|
|
* In event of an error, log a message at ereport level elevel, and also
|
|
|
|
* set *err_msg to a string describing the error. Note that the result
|
|
|
|
* may be non-NIL anyway, so *err_msg must be tested to determine whether
|
|
|
|
* there was an error.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
tokenize_include_file(const char *outer_filename,
|
|
|
|
const char *inc_filename,
|
|
|
|
List **tok_lines,
|
|
|
|
int elevel,
|
|
|
|
int depth,
|
|
|
|
bool missing_ok,
|
|
|
|
char **err_msg)
|
|
|
|
{
|
|
|
|
char *inc_fullname;
|
|
|
|
FILE *inc_file;
|
|
|
|
|
|
|
|
inc_fullname = AbsoluteConfigLocation(inc_filename, outer_filename);
|
|
|
|
inc_file = open_auth_file(inc_fullname, elevel, depth, err_msg);
|
|
|
|
|
|
|
|
if (!inc_file)
|
|
|
|
{
|
|
|
|
if (errno == ENOENT && missing_ok)
|
|
|
|
{
|
|
|
|
ereport(elevel,
|
|
|
|
(errmsg("skipping missing authentication file \"%s\"",
|
|
|
|
inc_fullname)));
|
|
|
|
*err_msg = NULL;
|
|
|
|
pfree(inc_fullname);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* error in err_msg, so leave and report */
|
|
|
|
pfree(inc_fullname);
|
|
|
|
Assert(err_msg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
tokenize_auth_file(inc_fullname, inc_file, tok_lines, elevel,
|
|
|
|
depth);
|
|
|
|
free_auth_file(inc_file, depth);
|
|
|
|
pfree(inc_fullname);
|
|
|
|
}
|
|
|
|
|
2002-04-04 06:25:54 +02:00
|
|
|
/*
|
2022-11-24 00:21:55 +01:00
|
|
|
* tokenize_expand_file
|
2011-06-20 23:20:14 +02:00
|
|
|
* Expand a file included from another file into an hba "field"
|
|
|
|
*
|
|
|
|
* Opens and tokenises a file included from another HBA config file with @,
|
Refactor code related to pg_hba_file_rules() into new file
hba.c is growing big, and more contents are planned for it. In order to
prepare for this future work, this commit moves all the code related to
the system function processing the contents of pg_hba.conf,
pg_hba_file_rules() to a new file called hbafuncs.c, which will be used
as the location for the SQL portion of the authentication file parsing.
While on it, HbaToken, the structure holding a string token lexed from a
configuration file related to authentication, is renamed to a more
generic AuthToken, as it gets used not only for pg_hba.conf, but also
for pg_ident.conf. TokenizedLine is now named TokenizedAuthLine.
The size of hba.c is reduced by ~12%.
Author: Julien Rouhaud
Reviewed-by: Aleksander Alekseev, Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-03-24 04:42:30 +01:00
|
|
|
* and returns all values found therein as a flat list of AuthTokens. If a
|
Add support for file inclusions in HBA and ident configuration files
pg_hba.conf and pg_ident.conf gain support for three record keywords:
- "include", to include a file.
- "include_if_exists", to include a file, ignoring it if missing.
- "include_dir", to include a directory of files. These are classified
by name (C locale, mostly) and need to be prefixed by ".conf", hence
following the same rules as GUCs.
This commit relies on the refactoring pieces done in efc9816, ad6c528,
783e8c6 and 1b73d0b, adding a small wrapper to build a list of
TokenizedAuthLines (tokenize_include_file), and the code is shaped to
offer some symmetry with what is done for GUCs with the same options.
pg_hba_file_rules and pg_ident_file_mappings gain a new field called
file_name, to track from which file a record is located, taking
advantage of the addition of rule_number in c591300 to offer an
organized view of the HBA or ident records loaded.
Bump catalog version.
Author: Julien Rouhaud
Reviewed-by: Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-11-24 05:51:34 +01:00
|
|
|
* @-token or include record is found, recursively expand it. The newly
|
|
|
|
* read tokens are appended to "tokens" (so that foo,bar,@baz does what you
|
|
|
|
* expect). All new tokens are allocated in the memory context dedicated
|
|
|
|
* to the list of TokenizedAuthLines, aka tokenize_context.
|
2017-01-31 00:00:26 +01:00
|
|
|
*
|
|
|
|
* In event of an error, log a message at ereport level elevel, and also
|
|
|
|
* set *err_msg to a string describing the error. Note that the result
|
|
|
|
* may be non-NIL anyway, so *err_msg must be tested to determine whether
|
|
|
|
* there was an error.
|
2002-04-04 06:25:54 +02:00
|
|
|
*/
|
2011-06-20 23:20:14 +02:00
|
|
|
static List *
|
2022-11-24 00:21:55 +01:00
|
|
|
tokenize_expand_file(List *tokens,
|
|
|
|
const char *outer_filename,
|
|
|
|
const char *inc_filename,
|
|
|
|
int elevel,
|
|
|
|
int depth,
|
|
|
|
char **err_msg)
|
2002-04-04 06:25:54 +02:00
|
|
|
{
|
|
|
|
char *inc_fullname;
|
|
|
|
FILE *inc_file;
|
2022-11-24 02:03:11 +01:00
|
|
|
List *inc_lines = NIL;
|
2011-06-20 23:20:14 +02:00
|
|
|
ListCell *inc_line;
|
2002-04-04 06:25:54 +02:00
|
|
|
|
2022-11-09 00:47:02 +01:00
|
|
|
inc_fullname = AbsoluteConfigLocation(inc_filename, outer_filename);
|
Invent open_auth_file() in hba.c to refactor authentication file opening
This adds a check on the recursion depth when including authentication
configuration files, something that has never been done when processing
'@' files for database and user name lists in pg_hba.conf. On HEAD,
this was leading to a rather confusing error, as of:
FATAL: exceeded maxAllocatedDescs (NN) while trying to open file "/path/blah.conf"
This refactors the code so as the error reported is now the following,
which is the same as for GUCs:
FATAL: could not open file "/path/blah.conf": maximum nesting depth exceeded
This reduces a bit the verbosity of the error message used for files
included in user and database lists, reporting only the file name of
what's failing to load, without mentioning the relative or absolute path
specified after '@' in a HBA file. The absolute path is built upon what
'@' defines anyway, so there is no actual loss of information. This
makes the future inclusion logic much simpler. A follow-up patch will
add an error context to be able to track on which line of which file the
inclusion is failing, to close the loop, providing all the information
needed to know the full chain of events.
This logic has been extracted from a larger patch written by Julien,
rewritten by me to have a unique code path calling AllocateFile() on
authentication files, and is useful on its own. This new interface
will be used later for authentication files included with
@include[_dir,_if_exists], in a follow-up patch.
Author: Michael Paquier, Julien Rouhaud
Discussion: https://www.postgresql.org/message-id/Y2xUBJ+S+Z0zbxRW@paquier.xyz
2022-11-14 02:21:42 +01:00
|
|
|
inc_file = open_auth_file(inc_fullname, elevel, depth, err_msg);
|
2002-04-04 06:25:54 +02:00
|
|
|
|
2004-12-27 20:19:24 +01:00
|
|
|
if (inc_file == NULL)
|
2002-04-04 06:25:54 +02:00
|
|
|
{
|
Invent open_auth_file() in hba.c to refactor authentication file opening
This adds a check on the recursion depth when including authentication
configuration files, something that has never been done when processing
'@' files for database and user name lists in pg_hba.conf. On HEAD,
this was leading to a rather confusing error, as of:
FATAL: exceeded maxAllocatedDescs (NN) while trying to open file "/path/blah.conf"
This refactors the code so as the error reported is now the following,
which is the same as for GUCs:
FATAL: could not open file "/path/blah.conf": maximum nesting depth exceeded
This reduces a bit the verbosity of the error message used for files
included in user and database lists, reporting only the file name of
what's failing to load, without mentioning the relative or absolute path
specified after '@' in a HBA file. The absolute path is built upon what
'@' defines anyway, so there is no actual loss of information. This
makes the future inclusion logic much simpler. A follow-up patch will
add an error context to be able to track on which line of which file the
inclusion is failing, to close the loop, providing all the information
needed to know the full chain of events.
This logic has been extracted from a larger patch written by Julien,
rewritten by me to have a unique code path calling AllocateFile() on
authentication files, and is useful on its own. This new interface
will be used later for authentication files included with
@include[_dir,_if_exists], in a follow-up patch.
Author: Michael Paquier, Julien Rouhaud
Discussion: https://www.postgresql.org/message-id/Y2xUBJ+S+Z0zbxRW@paquier.xyz
2022-11-14 02:21:42 +01:00
|
|
|
/* error already logged */
|
2002-04-04 06:25:54 +02:00
|
|
|
pfree(inc_fullname);
|
2011-06-20 23:20:14 +02:00
|
|
|
return tokens;
|
2002-04-04 06:25:54 +02:00
|
|
|
}
|
|
|
|
|
Add support for file inclusions in HBA and ident configuration files
pg_hba.conf and pg_ident.conf gain support for three record keywords:
- "include", to include a file.
- "include_if_exists", to include a file, ignoring it if missing.
- "include_dir", to include a directory of files. These are classified
by name (C locale, mostly) and need to be prefixed by ".conf", hence
following the same rules as GUCs.
This commit relies on the refactoring pieces done in efc9816, ad6c528,
783e8c6 and 1b73d0b, adding a small wrapper to build a list of
TokenizedAuthLines (tokenize_include_file), and the code is shaped to
offer some symmetry with what is done for GUCs with the same options.
pg_hba_file_rules and pg_ident_file_mappings gain a new field called
file_name, to track from which file a record is located, taking
advantage of the addition of rule_number in c591300 to offer an
organized view of the HBA or ident records loaded.
Bump catalog version.
Author: Julien Rouhaud
Reviewed-by: Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-11-24 05:51:34 +01:00
|
|
|
/*
|
|
|
|
* There is possible recursion here if the file contains @ or an include
|
2022-11-26 02:14:18 +01:00
|
|
|
* record.
|
Add support for file inclusions in HBA and ident configuration files
pg_hba.conf and pg_ident.conf gain support for three record keywords:
- "include", to include a file.
- "include_if_exists", to include a file, ignoring it if missing.
- "include_dir", to include a directory of files. These are classified
by name (C locale, mostly) and need to be prefixed by ".conf", hence
following the same rules as GUCs.
This commit relies on the refactoring pieces done in efc9816, ad6c528,
783e8c6 and 1b73d0b, adding a small wrapper to build a list of
TokenizedAuthLines (tokenize_include_file), and the code is shaped to
offer some symmetry with what is done for GUCs with the same options.
pg_hba_file_rules and pg_ident_file_mappings gain a new field called
file_name, to track from which file a record is located, taking
advantage of the addition of rule_number in c591300 to offer an
organized view of the HBA or ident records loaded.
Bump catalog version.
Author: Julien Rouhaud
Reviewed-by: Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-11-24 05:51:34 +01:00
|
|
|
*/
|
2022-11-24 00:21:55 +01:00
|
|
|
tokenize_auth_file(inc_fullname, inc_file, &inc_lines, elevel,
|
|
|
|
depth);
|
2004-12-27 20:19:24 +01:00
|
|
|
|
|
|
|
pfree(inc_fullname);
|
2002-04-04 06:25:54 +02:00
|
|
|
|
2022-11-24 00:21:55 +01:00
|
|
|
/*
|
|
|
|
* Move all the tokens found in the file to the tokens list. These are
|
|
|
|
* already saved in tokenize_context.
|
|
|
|
*/
|
2011-06-20 23:20:14 +02:00
|
|
|
foreach(inc_line, inc_lines)
|
2002-04-04 06:25:54 +02:00
|
|
|
{
|
Refactor code related to pg_hba_file_rules() into new file
hba.c is growing big, and more contents are planned for it. In order to
prepare for this future work, this commit moves all the code related to
the system function processing the contents of pg_hba.conf,
pg_hba_file_rules() to a new file called hbafuncs.c, which will be used
as the location for the SQL portion of the authentication file parsing.
While on it, HbaToken, the structure holding a string token lexed from a
configuration file related to authentication, is renamed to a more
generic AuthToken, as it gets used not only for pg_hba.conf, but also
for pg_ident.conf. TokenizedLine is now named TokenizedAuthLine.
The size of hba.c is reduced by ~12%.
Author: Julien Rouhaud
Reviewed-by: Aleksander Alekseev, Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-03-24 04:42:30 +01:00
|
|
|
TokenizedAuthLine *tok_line = (TokenizedAuthLine *) lfirst(inc_line);
|
2011-06-20 23:20:14 +02:00
|
|
|
ListCell *inc_field;
|
2002-04-04 06:25:54 +02:00
|
|
|
|
2017-01-31 00:00:26 +01:00
|
|
|
/* If any line has an error, propagate that up to caller */
|
|
|
|
if (tok_line->err_msg)
|
|
|
|
{
|
|
|
|
*err_msg = pstrdup(tok_line->err_msg);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-01-27 19:43:00 +01:00
|
|
|
foreach(inc_field, tok_line->fields)
|
2002-04-04 06:25:54 +02:00
|
|
|
{
|
2011-06-20 23:20:14 +02:00
|
|
|
List *inc_tokens = lfirst(inc_field);
|
|
|
|
ListCell *inc_token;
|
2002-04-04 06:25:54 +02:00
|
|
|
|
2011-06-20 23:20:14 +02:00
|
|
|
foreach(inc_token, inc_tokens)
|
|
|
|
{
|
Refactor code related to pg_hba_file_rules() into new file
hba.c is growing big, and more contents are planned for it. In order to
prepare for this future work, this commit moves all the code related to
the system function processing the contents of pg_hba.conf,
pg_hba_file_rules() to a new file called hbafuncs.c, which will be used
as the location for the SQL portion of the authentication file parsing.
While on it, HbaToken, the structure holding a string token lexed from a
configuration file related to authentication, is renamed to a more
generic AuthToken, as it gets used not only for pg_hba.conf, but also
for pg_ident.conf. TokenizedLine is now named TokenizedAuthLine.
The size of hba.c is reduced by ~12%.
Author: Julien Rouhaud
Reviewed-by: Aleksander Alekseev, Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-03-24 04:42:30 +01:00
|
|
|
AuthToken *token = lfirst(inc_token);
|
2022-11-24 00:21:55 +01:00
|
|
|
MemoryContext oldcxt;
|
2002-04-04 06:25:54 +02:00
|
|
|
|
2022-11-24 00:21:55 +01:00
|
|
|
/*
|
|
|
|
* lappend() may do its own allocations, so move to the
|
|
|
|
* context for the list of tokens.
|
|
|
|
*/
|
|
|
|
oldcxt = MemoryContextSwitchTo(tokenize_context);
|
|
|
|
tokens = lappend(tokens, token);
|
|
|
|
MemoryContextSwitchTo(oldcxt);
|
2011-06-20 23:20:14 +02:00
|
|
|
}
|
|
|
|
}
|
2004-12-27 20:19:24 +01:00
|
|
|
}
|
|
|
|
|
2022-11-24 00:21:55 +01:00
|
|
|
free_auth_file(inc_file, depth);
|
2011-06-20 23:20:14 +02:00
|
|
|
return tokens;
|
1996-10-12 09:47:12 +02:00
|
|
|
}
|
|
|
|
|
2022-11-24 00:21:55 +01:00
|
|
|
/*
|
|
|
|
* free_auth_file
|
|
|
|
* Free a file opened by open_auth_file().
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
free_auth_file(FILE *file, int depth)
|
|
|
|
{
|
|
|
|
FreeFile(file);
|
|
|
|
|
|
|
|
/* If this is the last cleanup, remove the tokenization context */
|
2022-11-24 23:40:12 +01:00
|
|
|
if (depth == CONF_FILE_START_DEPTH)
|
2022-11-24 00:21:55 +01:00
|
|
|
{
|
|
|
|
MemoryContextDelete(tokenize_context);
|
|
|
|
tokenize_context = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Invent open_auth_file() in hba.c to refactor authentication file opening
This adds a check on the recursion depth when including authentication
configuration files, something that has never been done when processing
'@' files for database and user name lists in pg_hba.conf. On HEAD,
this was leading to a rather confusing error, as of:
FATAL: exceeded maxAllocatedDescs (NN) while trying to open file "/path/blah.conf"
This refactors the code so as the error reported is now the following,
which is the same as for GUCs:
FATAL: could not open file "/path/blah.conf": maximum nesting depth exceeded
This reduces a bit the verbosity of the error message used for files
included in user and database lists, reporting only the file name of
what's failing to load, without mentioning the relative or absolute path
specified after '@' in a HBA file. The absolute path is built upon what
'@' defines anyway, so there is no actual loss of information. This
makes the future inclusion logic much simpler. A follow-up patch will
add an error context to be able to track on which line of which file the
inclusion is failing, to close the loop, providing all the information
needed to know the full chain of events.
This logic has been extracted from a larger patch written by Julien,
rewritten by me to have a unique code path calling AllocateFile() on
authentication files, and is useful on its own. This new interface
will be used later for authentication files included with
@include[_dir,_if_exists], in a follow-up patch.
Author: Michael Paquier, Julien Rouhaud
Discussion: https://www.postgresql.org/message-id/Y2xUBJ+S+Z0zbxRW@paquier.xyz
2022-11-14 02:21:42 +01:00
|
|
|
/*
|
|
|
|
* open_auth_file
|
|
|
|
* Open the given file.
|
|
|
|
*
|
|
|
|
* filename: the absolute path to the target file
|
|
|
|
* elevel: message logging level
|
|
|
|
* depth: recursion level when opening the file
|
|
|
|
* err_msg: details about the error
|
|
|
|
*
|
|
|
|
* Return value is the opened file. On error, returns NULL with details
|
|
|
|
* about the error stored in "err_msg".
|
|
|
|
*/
|
|
|
|
FILE *
|
|
|
|
open_auth_file(const char *filename, int elevel, int depth,
|
|
|
|
char **err_msg)
|
|
|
|
{
|
|
|
|
FILE *file;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Reject too-deep include nesting depth. This is just a safety check to
|
|
|
|
* avoid dumping core due to stack overflow if an include file loops back
|
|
|
|
* to itself. The maximum nesting depth is pretty arbitrary.
|
|
|
|
*/
|
2022-11-24 23:40:12 +01:00
|
|
|
if (depth > CONF_FILE_MAX_DEPTH)
|
Invent open_auth_file() in hba.c to refactor authentication file opening
This adds a check on the recursion depth when including authentication
configuration files, something that has never been done when processing
'@' files for database and user name lists in pg_hba.conf. On HEAD,
this was leading to a rather confusing error, as of:
FATAL: exceeded maxAllocatedDescs (NN) while trying to open file "/path/blah.conf"
This refactors the code so as the error reported is now the following,
which is the same as for GUCs:
FATAL: could not open file "/path/blah.conf": maximum nesting depth exceeded
This reduces a bit the verbosity of the error message used for files
included in user and database lists, reporting only the file name of
what's failing to load, without mentioning the relative or absolute path
specified after '@' in a HBA file. The absolute path is built upon what
'@' defines anyway, so there is no actual loss of information. This
makes the future inclusion logic much simpler. A follow-up patch will
add an error context to be able to track on which line of which file the
inclusion is failing, to close the loop, providing all the information
needed to know the full chain of events.
This logic has been extracted from a larger patch written by Julien,
rewritten by me to have a unique code path calling AllocateFile() on
authentication files, and is useful on its own. This new interface
will be used later for authentication files included with
@include[_dir,_if_exists], in a follow-up patch.
Author: Michael Paquier, Julien Rouhaud
Discussion: https://www.postgresql.org/message-id/Y2xUBJ+S+Z0zbxRW@paquier.xyz
2022-11-14 02:21:42 +01:00
|
|
|
{
|
|
|
|
ereport(elevel,
|
|
|
|
(errcode_for_file_access(),
|
|
|
|
errmsg("could not open file \"%s\": maximum nesting depth exceeded",
|
|
|
|
filename)));
|
|
|
|
if (err_msg)
|
|
|
|
*err_msg = psprintf("could not open file \"%s\": maximum nesting depth exceeded",
|
|
|
|
filename);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
file = AllocateFile(filename, "r");
|
|
|
|
if (file == NULL)
|
|
|
|
{
|
|
|
|
int save_errno = errno;
|
|
|
|
|
|
|
|
ereport(elevel,
|
|
|
|
(errcode_for_file_access(),
|
|
|
|
errmsg("could not open file \"%s\": %m",
|
|
|
|
filename)));
|
|
|
|
if (err_msg)
|
|
|
|
*err_msg = psprintf("could not open file \"%s\": %s",
|
|
|
|
filename, strerror(save_errno));
|
2022-11-24 00:21:55 +01:00
|
|
|
/* the caller may care about some specific errno */
|
|
|
|
errno = save_errno;
|
Invent open_auth_file() in hba.c to refactor authentication file opening
This adds a check on the recursion depth when including authentication
configuration files, something that has never been done when processing
'@' files for database and user name lists in pg_hba.conf. On HEAD,
this was leading to a rather confusing error, as of:
FATAL: exceeded maxAllocatedDescs (NN) while trying to open file "/path/blah.conf"
This refactors the code so as the error reported is now the following,
which is the same as for GUCs:
FATAL: could not open file "/path/blah.conf": maximum nesting depth exceeded
This reduces a bit the verbosity of the error message used for files
included in user and database lists, reporting only the file name of
what's failing to load, without mentioning the relative or absolute path
specified after '@' in a HBA file. The absolute path is built upon what
'@' defines anyway, so there is no actual loss of information. This
makes the future inclusion logic much simpler. A follow-up patch will
add an error context to be able to track on which line of which file the
inclusion is failing, to close the loop, providing all the information
needed to know the full chain of events.
This logic has been extracted from a larger patch written by Julien,
rewritten by me to have a unique code path calling AllocateFile() on
authentication files, and is useful on its own. This new interface
will be used later for authentication files included with
@include[_dir,_if_exists], in a follow-up patch.
Author: Michael Paquier, Julien Rouhaud
Discussion: https://www.postgresql.org/message-id/Y2xUBJ+S+Z0zbxRW@paquier.xyz
2022-11-14 02:21:42 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2022-11-24 02:27:38 +01:00
|
|
|
/*
|
|
|
|
* When opening the top-level file, create the memory context used for the
|
|
|
|
* tokenization. This will be closed with this file when coming back to
|
|
|
|
* this level of cleanup.
|
|
|
|
*/
|
2022-11-24 23:40:12 +01:00
|
|
|
if (depth == CONF_FILE_START_DEPTH)
|
2022-11-24 02:27:38 +01:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* A context may be present, but assume that it has been eliminated
|
|
|
|
* already.
|
|
|
|
*/
|
|
|
|
tokenize_context = AllocSetContextCreate(CurrentMemoryContext,
|
|
|
|
"tokenize_context",
|
|
|
|
ALLOCSET_START_SMALL_SIZES);
|
|
|
|
}
|
|
|
|
|
Invent open_auth_file() in hba.c to refactor authentication file opening
This adds a check on the recursion depth when including authentication
configuration files, something that has never been done when processing
'@' files for database and user name lists in pg_hba.conf. On HEAD,
this was leading to a rather confusing error, as of:
FATAL: exceeded maxAllocatedDescs (NN) while trying to open file "/path/blah.conf"
This refactors the code so as the error reported is now the following,
which is the same as for GUCs:
FATAL: could not open file "/path/blah.conf": maximum nesting depth exceeded
This reduces a bit the verbosity of the error message used for files
included in user and database lists, reporting only the file name of
what's failing to load, without mentioning the relative or absolute path
specified after '@' in a HBA file. The absolute path is built upon what
'@' defines anyway, so there is no actual loss of information. This
makes the future inclusion logic much simpler. A follow-up patch will
add an error context to be able to track on which line of which file the
inclusion is failing, to close the loop, providing all the information
needed to know the full chain of events.
This logic has been extracted from a larger patch written by Julien,
rewritten by me to have a unique code path calling AllocateFile() on
authentication files, and is useful on its own. This new interface
will be used later for authentication files included with
@include[_dir,_if_exists], in a follow-up patch.
Author: Michael Paquier, Julien Rouhaud
Discussion: https://www.postgresql.org/message-id/Y2xUBJ+S+Z0zbxRW@paquier.xyz
2022-11-14 02:21:42 +01:00
|
|
|
return file;
|
|
|
|
}
|
|
|
|
|
2022-11-14 03:58:10 +01:00
|
|
|
/*
|
|
|
|
* error context callback for tokenize_auth_file()
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
tokenize_error_callback(void *arg)
|
|
|
|
{
|
|
|
|
tokenize_error_callback_arg *callback_arg = (tokenize_error_callback_arg *) arg;
|
|
|
|
|
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
|
|
|
callback_arg->linenum, callback_arg->filename);
|
|
|
|
}
|
|
|
|
|
2001-07-30 16:50:24 +02:00
|
|
|
/*
|
Refactor code related to pg_hba_file_rules() into new file
hba.c is growing big, and more contents are planned for it. In order to
prepare for this future work, this commit moves all the code related to
the system function processing the contents of pg_hba.conf,
pg_hba_file_rules() to a new file called hbafuncs.c, which will be used
as the location for the SQL portion of the authentication file parsing.
While on it, HbaToken, the structure holding a string token lexed from a
configuration file related to authentication, is renamed to a more
generic AuthToken, as it gets used not only for pg_hba.conf, but also
for pg_ident.conf. TokenizedLine is now named TokenizedAuthLine.
The size of hba.c is reduced by ~12%.
Author: Julien Rouhaud
Reviewed-by: Aleksander Alekseev, Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-03-24 04:42:30 +01:00
|
|
|
* tokenize_auth_file
|
|
|
|
* Tokenize the given file.
|
2011-06-20 23:20:14 +02:00
|
|
|
*
|
Refactor code related to pg_hba_file_rules() into new file
hba.c is growing big, and more contents are planned for it. In order to
prepare for this future work, this commit moves all the code related to
the system function processing the contents of pg_hba.conf,
pg_hba_file_rules() to a new file called hbafuncs.c, which will be used
as the location for the SQL portion of the authentication file parsing.
While on it, HbaToken, the structure holding a string token lexed from a
configuration file related to authentication, is renamed to a more
generic AuthToken, as it gets used not only for pg_hba.conf, but also
for pg_ident.conf. TokenizedLine is now named TokenizedAuthLine.
The size of hba.c is reduced by ~12%.
Author: Julien Rouhaud
Reviewed-by: Aleksander Alekseev, Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-03-24 04:42:30 +01:00
|
|
|
* The output is a list of TokenizedAuthLine structs; see the struct definition
|
2022-11-24 00:21:55 +01:00
|
|
|
* in libpq/hba.h. This is the central piece in charge of parsing the
|
|
|
|
* authentication files. All the operations of this function happen in its own
|
|
|
|
* local memory context, easing the cleanup of anything allocated here. This
|
|
|
|
* matters a lot when reloading authentication files in the postmaster.
|
2004-12-27 20:19:24 +01:00
|
|
|
*
|
2017-01-31 00:00:26 +01:00
|
|
|
* filename: the absolute path to the target file
|
|
|
|
* file: the already-opened target file
|
2022-11-24 00:21:55 +01:00
|
|
|
* tok_lines: receives output list, saved into tokenize_context
|
2017-01-31 00:00:26 +01:00
|
|
|
* elevel: message logging level
|
Invent open_auth_file() in hba.c to refactor authentication file opening
This adds a check on the recursion depth when including authentication
configuration files, something that has never been done when processing
'@' files for database and user name lists in pg_hba.conf. On HEAD,
this was leading to a rather confusing error, as of:
FATAL: exceeded maxAllocatedDescs (NN) while trying to open file "/path/blah.conf"
This refactors the code so as the error reported is now the following,
which is the same as for GUCs:
FATAL: could not open file "/path/blah.conf": maximum nesting depth exceeded
This reduces a bit the verbosity of the error message used for files
included in user and database lists, reporting only the file name of
what's failing to load, without mentioning the relative or absolute path
specified after '@' in a HBA file. The absolute path is built upon what
'@' defines anyway, so there is no actual loss of information. This
makes the future inclusion logic much simpler. A follow-up patch will
add an error context to be able to track on which line of which file the
inclusion is failing, to close the loop, providing all the information
needed to know the full chain of events.
This logic has been extracted from a larger patch written by Julien,
rewritten by me to have a unique code path calling AllocateFile() on
authentication files, and is useful on its own. This new interface
will be used later for authentication files included with
@include[_dir,_if_exists], in a follow-up patch.
Author: Michael Paquier, Julien Rouhaud
Discussion: https://www.postgresql.org/message-id/Y2xUBJ+S+Z0zbxRW@paquier.xyz
2022-11-14 02:21:42 +01:00
|
|
|
* depth: level of recursion when tokenizing the target file
|
2017-01-31 00:00:26 +01:00
|
|
|
*
|
|
|
|
* Errors are reported by logging messages at ereport level elevel and by
|
Refactor code related to pg_hba_file_rules() into new file
hba.c is growing big, and more contents are planned for it. In order to
prepare for this future work, this commit moves all the code related to
the system function processing the contents of pg_hba.conf,
pg_hba_file_rules() to a new file called hbafuncs.c, which will be used
as the location for the SQL portion of the authentication file parsing.
While on it, HbaToken, the structure holding a string token lexed from a
configuration file related to authentication, is renamed to a more
generic AuthToken, as it gets used not only for pg_hba.conf, but also
for pg_ident.conf. TokenizedLine is now named TokenizedAuthLine.
The size of hba.c is reduced by ~12%.
Author: Julien Rouhaud
Reviewed-by: Aleksander Alekseev, Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-03-24 04:42:30 +01:00
|
|
|
* adding TokenizedAuthLine structs containing non-null err_msg fields to the
|
2017-01-31 00:00:26 +01:00
|
|
|
* output list.
|
2001-07-30 16:50:24 +02:00
|
|
|
*/
|
2022-11-24 00:21:55 +01:00
|
|
|
void
|
Refactor code related to pg_hba_file_rules() into new file
hba.c is growing big, and more contents are planned for it. In order to
prepare for this future work, this commit moves all the code related to
the system function processing the contents of pg_hba.conf,
pg_hba_file_rules() to a new file called hbafuncs.c, which will be used
as the location for the SQL portion of the authentication file parsing.
While on it, HbaToken, the structure holding a string token lexed from a
configuration file related to authentication, is renamed to a more
generic AuthToken, as it gets used not only for pg_hba.conf, but also
for pg_ident.conf. TokenizedLine is now named TokenizedAuthLine.
The size of hba.c is reduced by ~12%.
Author: Julien Rouhaud
Reviewed-by: Aleksander Alekseev, Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-03-24 04:42:30 +01:00
|
|
|
tokenize_auth_file(const char *filename, FILE *file, List **tok_lines,
|
Invent open_auth_file() in hba.c to refactor authentication file opening
This adds a check on the recursion depth when including authentication
configuration files, something that has never been done when processing
'@' files for database and user name lists in pg_hba.conf. On HEAD,
this was leading to a rather confusing error, as of:
FATAL: exceeded maxAllocatedDescs (NN) while trying to open file "/path/blah.conf"
This refactors the code so as the error reported is now the following,
which is the same as for GUCs:
FATAL: could not open file "/path/blah.conf": maximum nesting depth exceeded
This reduces a bit the verbosity of the error message used for files
included in user and database lists, reporting only the file name of
what's failing to load, without mentioning the relative or absolute path
specified after '@' in a HBA file. The absolute path is built upon what
'@' defines anyway, so there is no actual loss of information. This
makes the future inclusion logic much simpler. A follow-up patch will
add an error context to be able to track on which line of which file the
inclusion is failing, to close the loop, providing all the information
needed to know the full chain of events.
This logic has been extracted from a larger patch written by Julien,
rewritten by me to have a unique code path calling AllocateFile() on
authentication files, and is useful on its own. This new interface
will be used later for authentication files included with
@include[_dir,_if_exists], in a follow-up patch.
Author: Michael Paquier, Julien Rouhaud
Discussion: https://www.postgresql.org/message-id/Y2xUBJ+S+Z0zbxRW@paquier.xyz
2022-11-14 02:21:42 +01:00
|
|
|
int elevel, int depth)
|
1997-03-12 22:23:16 +01:00
|
|
|
{
|
2001-08-01 00:55:45 +02:00
|
|
|
int line_number = 1;
|
2020-09-03 18:16:48 +02:00
|
|
|
StringInfoData buf;
|
2011-06-20 23:20:14 +02:00
|
|
|
MemoryContext linecxt;
|
2022-11-24 00:21:55 +01:00
|
|
|
MemoryContext funccxt; /* context of this function's caller */
|
2022-11-14 03:58:10 +01:00
|
|
|
ErrorContextCallback tokenerrcontext;
|
|
|
|
tokenize_error_callback_arg callback_arg;
|
|
|
|
|
2022-11-24 00:21:55 +01:00
|
|
|
Assert(tokenize_context);
|
|
|
|
|
2022-11-14 03:58:10 +01:00
|
|
|
callback_arg.filename = filename;
|
|
|
|
callback_arg.linenum = line_number;
|
|
|
|
|
|
|
|
tokenerrcontext.callback = tokenize_error_callback;
|
|
|
|
tokenerrcontext.arg = (void *) &callback_arg;
|
|
|
|
tokenerrcontext.previous = error_context_stack;
|
|
|
|
error_context_stack = &tokenerrcontext;
|
2011-06-20 23:20:14 +02:00
|
|
|
|
2022-11-24 00:21:55 +01:00
|
|
|
/*
|
|
|
|
* Do all the local tokenization in its own context, to ease the cleanup
|
|
|
|
* of any memory allocated while tokenizing.
|
|
|
|
*/
|
2015-07-02 00:55:39 +02:00
|
|
|
linecxt = AllocSetContextCreate(CurrentMemoryContext,
|
Refactor code related to pg_hba_file_rules() into new file
hba.c is growing big, and more contents are planned for it. In order to
prepare for this future work, this commit moves all the code related to
the system function processing the contents of pg_hba.conf,
pg_hba_file_rules() to a new file called hbafuncs.c, which will be used
as the location for the SQL portion of the authentication file parsing.
While on it, HbaToken, the structure holding a string token lexed from a
configuration file related to authentication, is renamed to a more
generic AuthToken, as it gets used not only for pg_hba.conf, but also
for pg_ident.conf. TokenizedLine is now named TokenizedAuthLine.
The size of hba.c is reduced by ~12%.
Author: Julien Rouhaud
Reviewed-by: Aleksander Alekseev, Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-03-24 04:42:30 +01:00
|
|
|
"tokenize_auth_file",
|
Add macros to make AllocSetContextCreate() calls simpler and safer.
I found that half a dozen (nearly 5%) of our AllocSetContextCreate calls
had typos in the context-sizing parameters. While none of these led to
especially significant problems, they did create minor inefficiencies,
and it's now clear that expecting people to copy-and-paste those calls
accurately is not a great idea. Let's reduce the risk of future errors
by introducing single macros that encapsulate the common use-cases.
Three such macros are enough to cover all but two special-purpose contexts;
those two calls can be left as-is, I think.
While this patch doesn't in itself improve matters for third-party
extensions, it doesn't break anything for them either, and they can
gradually adopt the simplified notation over time.
In passing, change TopMemoryContext to use the default allocation
parameters. Formerly it could only be extended 8K at a time. That was
probably reasonable when this code was written; but nowadays we create
many more contexts than we did then, so that it's not unusual to have a
couple hundred K in TopMemoryContext, even without considering various
dubious code that sticks other things there. There seems no good reason
not to let it use growing blocks like most other contexts.
Back-patch to 9.6, mostly because that's still close enough to HEAD that
it's easy to do so, and keeping the branches in sync can be expected to
avoid some future back-patching pain. The bugs fixed by these changes
don't seem to be significant enough to justify fixing them further back.
Discussion: <21072.1472321324@sss.pgh.pa.us>
2016-08-27 23:50:38 +02:00
|
|
|
ALLOCSET_SMALL_SIZES);
|
2022-11-24 00:21:55 +01:00
|
|
|
funccxt = MemoryContextSwitchTo(linecxt);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2020-09-03 18:16:48 +02:00
|
|
|
initStringInfo(&buf);
|
|
|
|
|
2022-11-24 23:40:12 +01:00
|
|
|
if (depth == CONF_FILE_START_DEPTH)
|
2022-11-24 00:21:55 +01:00
|
|
|
*tok_lines = NIL;
|
2004-05-26 06:41:50 +02:00
|
|
|
|
2010-03-03 21:31:09 +01:00
|
|
|
while (!feof(file) && !ferror(file))
|
1996-10-12 09:47:12 +02:00
|
|
|
{
|
Add support for file inclusions in HBA and ident configuration files
pg_hba.conf and pg_ident.conf gain support for three record keywords:
- "include", to include a file.
- "include_if_exists", to include a file, ignoring it if missing.
- "include_dir", to include a directory of files. These are classified
by name (C locale, mostly) and need to be prefixed by ".conf", hence
following the same rules as GUCs.
This commit relies on the refactoring pieces done in efc9816, ad6c528,
783e8c6 and 1b73d0b, adding a small wrapper to build a list of
TokenizedAuthLines (tokenize_include_file), and the code is shaped to
offer some symmetry with what is done for GUCs with the same options.
pg_hba_file_rules and pg_ident_file_mappings gain a new field called
file_name, to track from which file a record is located, taking
advantage of the addition of rule_number in c591300 to offer an
organized view of the HBA or ident records loaded.
Bump catalog version.
Author: Julien Rouhaud
Reviewed-by: Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-11-24 05:51:34 +01:00
|
|
|
TokenizedAuthLine *tok_line;
|
|
|
|
MemoryContext oldcxt;
|
2013-03-10 15:54:37 +01:00
|
|
|
char *lineptr;
|
2017-01-27 19:43:00 +01:00
|
|
|
List *current_line = NIL;
|
2017-01-31 00:00:26 +01:00
|
|
|
char *err_msg = NULL;
|
2020-09-03 18:16:48 +02:00
|
|
|
int last_backslash_buflen = 0;
|
|
|
|
int continuations = 0;
|
2001-07-30 16:50:24 +02:00
|
|
|
|
2020-09-03 18:16:48 +02:00
|
|
|
/* Collect the next input line, handling backslash continuations */
|
|
|
|
resetStringInfo(&buf);
|
2017-01-31 00:00:26 +01:00
|
|
|
|
2021-11-18 01:09:54 +01:00
|
|
|
while (pg_get_line_append(file, &buf, NULL))
|
2017-01-31 00:00:26 +01:00
|
|
|
{
|
2020-09-03 18:16:48 +02:00
|
|
|
/* Strip trailing newline, including \r in case we're on Windows */
|
|
|
|
buf.len = pg_strip_crlf(buf.data);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check for backslash continuation. The backslash must be after
|
|
|
|
* the last place we found a continuation, else two backslashes
|
|
|
|
* followed by two \n's would behave surprisingly.
|
|
|
|
*/
|
|
|
|
if (buf.len > last_backslash_buflen &&
|
|
|
|
buf.data[buf.len - 1] == '\\')
|
|
|
|
{
|
|
|
|
/* Continuation, so strip it and keep reading */
|
|
|
|
buf.data[--buf.len] = '\0';
|
|
|
|
last_backslash_buflen = buf.len;
|
|
|
|
continuations++;
|
|
|
|
continue;
|
|
|
|
}
|
2013-03-10 15:54:37 +01:00
|
|
|
|
2020-09-03 18:16:48 +02:00
|
|
|
/* Nope, so we have the whole line */
|
|
|
|
break;
|
|
|
|
}
|
2013-03-10 15:54:37 +01:00
|
|
|
|
2020-09-06 19:57:10 +02:00
|
|
|
if (ferror(file))
|
|
|
|
{
|
|
|
|
/* I/O error! */
|
|
|
|
int save_errno = errno;
|
|
|
|
|
|
|
|
ereport(elevel,
|
|
|
|
(errcode_for_file_access(),
|
|
|
|
errmsg("could not read file \"%s\": %m", filename)));
|
|
|
|
err_msg = psprintf("could not read file \"%s\": %s",
|
|
|
|
filename, strerror(save_errno));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-01-27 19:43:00 +01:00
|
|
|
/* Parse fields */
|
2020-09-03 18:16:48 +02:00
|
|
|
lineptr = buf.data;
|
2017-01-31 00:00:26 +01:00
|
|
|
while (*lineptr && err_msg == NULL)
|
2001-07-30 16:50:24 +02:00
|
|
|
{
|
2017-01-27 19:43:00 +01:00
|
|
|
List *current_field;
|
|
|
|
|
2017-01-31 00:00:26 +01:00
|
|
|
current_field = next_field_expand(filename, &lineptr,
|
Invent open_auth_file() in hba.c to refactor authentication file opening
This adds a check on the recursion depth when including authentication
configuration files, something that has never been done when processing
'@' files for database and user name lists in pg_hba.conf. On HEAD,
this was leading to a rather confusing error, as of:
FATAL: exceeded maxAllocatedDescs (NN) while trying to open file "/path/blah.conf"
This refactors the code so as the error reported is now the following,
which is the same as for GUCs:
FATAL: could not open file "/path/blah.conf": maximum nesting depth exceeded
This reduces a bit the verbosity of the error message used for files
included in user and database lists, reporting only the file name of
what's failing to load, without mentioning the relative or absolute path
specified after '@' in a HBA file. The absolute path is built upon what
'@' defines anyway, so there is no actual loss of information. This
makes the future inclusion logic much simpler. A follow-up patch will
add an error context to be able to track on which line of which file the
inclusion is failing, to close the loop, providing all the information
needed to know the full chain of events.
This logic has been extracted from a larger patch written by Julien,
rewritten by me to have a unique code path calling AllocateFile() on
authentication files, and is useful on its own. This new interface
will be used later for authentication files included with
@include[_dir,_if_exists], in a follow-up patch.
Author: Michael Paquier, Julien Rouhaud
Discussion: https://www.postgresql.org/message-id/Y2xUBJ+S+Z0zbxRW@paquier.xyz
2022-11-14 02:21:42 +01:00
|
|
|
elevel, depth, &err_msg);
|
2017-01-27 19:43:00 +01:00
|
|
|
/* add field to line, unless we are at EOL or comment start */
|
|
|
|
if (current_field != NIL)
|
2022-11-24 00:21:55 +01:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* lappend() may do its own allocations, so move to the
|
|
|
|
* context for the list of tokens.
|
|
|
|
*/
|
|
|
|
oldcxt = MemoryContextSwitchTo(tokenize_context);
|
2017-01-27 19:43:00 +01:00
|
|
|
current_line = lappend(current_line, current_field);
|
2022-11-24 00:21:55 +01:00
|
|
|
MemoryContextSwitchTo(oldcxt);
|
|
|
|
}
|
2017-01-27 19:43:00 +01:00
|
|
|
}
|
2013-03-10 15:54:37 +01:00
|
|
|
|
Refactor code related to pg_hba_file_rules() into new file
hba.c is growing big, and more contents are planned for it. In order to
prepare for this future work, this commit moves all the code related to
the system function processing the contents of pg_hba.conf,
pg_hba_file_rules() to a new file called hbafuncs.c, which will be used
as the location for the SQL portion of the authentication file parsing.
While on it, HbaToken, the structure holding a string token lexed from a
configuration file related to authentication, is renamed to a more
generic AuthToken, as it gets used not only for pg_hba.conf, but also
for pg_ident.conf. TokenizedLine is now named TokenizedAuthLine.
The size of hba.c is reduced by ~12%.
Author: Julien Rouhaud
Reviewed-by: Aleksander Alekseev, Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-03-24 04:42:30 +01:00
|
|
|
/*
|
Add support for file inclusions in HBA and ident configuration files
pg_hba.conf and pg_ident.conf gain support for three record keywords:
- "include", to include a file.
- "include_if_exists", to include a file, ignoring it if missing.
- "include_dir", to include a directory of files. These are classified
by name (C locale, mostly) and need to be prefixed by ".conf", hence
following the same rules as GUCs.
This commit relies on the refactoring pieces done in efc9816, ad6c528,
783e8c6 and 1b73d0b, adding a small wrapper to build a list of
TokenizedAuthLines (tokenize_include_file), and the code is shaped to
offer some symmetry with what is done for GUCs with the same options.
pg_hba_file_rules and pg_ident_file_mappings gain a new field called
file_name, to track from which file a record is located, taking
advantage of the addition of rule_number in c591300 to offer an
organized view of the HBA or ident records loaded.
Bump catalog version.
Author: Julien Rouhaud
Reviewed-by: Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-11-24 05:51:34 +01:00
|
|
|
* Reached EOL; no need to emit line to TokenizedAuthLine list if it's
|
|
|
|
* boring.
|
Refactor code related to pg_hba_file_rules() into new file
hba.c is growing big, and more contents are planned for it. In order to
prepare for this future work, this commit moves all the code related to
the system function processing the contents of pg_hba.conf,
pg_hba_file_rules() to a new file called hbafuncs.c, which will be used
as the location for the SQL portion of the authentication file parsing.
While on it, HbaToken, the structure holding a string token lexed from a
configuration file related to authentication, is renamed to a more
generic AuthToken, as it gets used not only for pg_hba.conf, but also
for pg_ident.conf. TokenizedLine is now named TokenizedAuthLine.
The size of hba.c is reduced by ~12%.
Author: Julien Rouhaud
Reviewed-by: Aleksander Alekseev, Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-03-24 04:42:30 +01:00
|
|
|
*/
|
Add support for file inclusions in HBA and ident configuration files
pg_hba.conf and pg_ident.conf gain support for three record keywords:
- "include", to include a file.
- "include_if_exists", to include a file, ignoring it if missing.
- "include_dir", to include a directory of files. These are classified
by name (C locale, mostly) and need to be prefixed by ".conf", hence
following the same rules as GUCs.
This commit relies on the refactoring pieces done in efc9816, ad6c528,
783e8c6 and 1b73d0b, adding a small wrapper to build a list of
TokenizedAuthLines (tokenize_include_file), and the code is shaped to
offer some symmetry with what is done for GUCs with the same options.
pg_hba_file_rules and pg_ident_file_mappings gain a new field called
file_name, to track from which file a record is located, taking
advantage of the addition of rule_number in c591300 to offer an
organized view of the HBA or ident records loaded.
Bump catalog version.
Author: Julien Rouhaud
Reviewed-by: Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-11-24 05:51:34 +01:00
|
|
|
if (current_line == NIL && err_msg == NULL)
|
|
|
|
goto next_line;
|
|
|
|
|
|
|
|
/* If the line is valid, check if that's an include directive */
|
|
|
|
if (err_msg == NULL && list_length(current_line) == 2)
|
2017-01-27 19:43:00 +01:00
|
|
|
{
|
Add support for file inclusions in HBA and ident configuration files
pg_hba.conf and pg_ident.conf gain support for three record keywords:
- "include", to include a file.
- "include_if_exists", to include a file, ignoring it if missing.
- "include_dir", to include a directory of files. These are classified
by name (C locale, mostly) and need to be prefixed by ".conf", hence
following the same rules as GUCs.
This commit relies on the refactoring pieces done in efc9816, ad6c528,
783e8c6 and 1b73d0b, adding a small wrapper to build a list of
TokenizedAuthLines (tokenize_include_file), and the code is shaped to
offer some symmetry with what is done for GUCs with the same options.
pg_hba_file_rules and pg_ident_file_mappings gain a new field called
file_name, to track from which file a record is located, taking
advantage of the addition of rule_number in c591300 to offer an
organized view of the HBA or ident records loaded.
Bump catalog version.
Author: Julien Rouhaud
Reviewed-by: Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-11-24 05:51:34 +01:00
|
|
|
AuthToken *first,
|
|
|
|
*second;
|
2017-01-27 19:43:00 +01:00
|
|
|
|
Add support for file inclusions in HBA and ident configuration files
pg_hba.conf and pg_ident.conf gain support for three record keywords:
- "include", to include a file.
- "include_if_exists", to include a file, ignoring it if missing.
- "include_dir", to include a directory of files. These are classified
by name (C locale, mostly) and need to be prefixed by ".conf", hence
following the same rules as GUCs.
This commit relies on the refactoring pieces done in efc9816, ad6c528,
783e8c6 and 1b73d0b, adding a small wrapper to build a list of
TokenizedAuthLines (tokenize_include_file), and the code is shaped to
offer some symmetry with what is done for GUCs with the same options.
pg_hba_file_rules and pg_ident_file_mappings gain a new field called
file_name, to track from which file a record is located, taking
advantage of the addition of rule_number in c591300 to offer an
organized view of the HBA or ident records loaded.
Bump catalog version.
Author: Julien Rouhaud
Reviewed-by: Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-11-24 05:51:34 +01:00
|
|
|
first = linitial(linitial_node(List, current_line));
|
|
|
|
second = linitial(lsecond_node(List, current_line));
|
|
|
|
|
|
|
|
if (strcmp(first->string, "include") == 0)
|
|
|
|
{
|
|
|
|
tokenize_include_file(filename, second->string, tok_lines,
|
|
|
|
elevel, depth + 1, false, &err_msg);
|
|
|
|
|
|
|
|
if (err_msg)
|
|
|
|
goto process_line;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* tokenize_auth_file() has taken care of creating the
|
|
|
|
* TokenizedAuthLines.
|
|
|
|
*/
|
|
|
|
goto next_line;
|
|
|
|
}
|
|
|
|
else if (strcmp(first->string, "include_dir") == 0)
|
|
|
|
{
|
|
|
|
char **filenames;
|
|
|
|
char *dir_name = second->string;
|
|
|
|
int num_filenames;
|
|
|
|
StringInfoData err_buf;
|
|
|
|
|
|
|
|
filenames = GetConfFilesInDir(dir_name, filename, elevel,
|
|
|
|
&num_filenames, &err_msg);
|
|
|
|
|
|
|
|
if (!filenames)
|
|
|
|
{
|
|
|
|
/* the error is in err_msg, so create an entry */
|
|
|
|
goto process_line;
|
|
|
|
}
|
|
|
|
|
|
|
|
initStringInfo(&err_buf);
|
|
|
|
for (int i = 0; i < num_filenames; i++)
|
|
|
|
{
|
|
|
|
tokenize_include_file(filename, filenames[i], tok_lines,
|
|
|
|
elevel, depth + 1, false, &err_msg);
|
|
|
|
/* cumulate errors if any */
|
|
|
|
if (err_msg)
|
|
|
|
{
|
|
|
|
if (err_buf.len > 0)
|
|
|
|
appendStringInfoChar(&err_buf, '\n');
|
|
|
|
appendStringInfoString(&err_buf, err_msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* clean up things */
|
|
|
|
for (int i = 0; i < num_filenames; i++)
|
|
|
|
pfree(filenames[i]);
|
|
|
|
pfree(filenames);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If there were no errors, the line is fully processed,
|
|
|
|
* bypass the general TokenizedAuthLine processing.
|
|
|
|
*/
|
|
|
|
if (err_buf.len == 0)
|
|
|
|
goto next_line;
|
|
|
|
|
|
|
|
/* Otherwise, process the cumulated errors, if any. */
|
|
|
|
err_msg = err_buf.data;
|
|
|
|
goto process_line;
|
|
|
|
}
|
|
|
|
else if (strcmp(first->string, "include_if_exists") == 0)
|
|
|
|
{
|
|
|
|
|
|
|
|
tokenize_include_file(filename, second->string, tok_lines,
|
|
|
|
elevel, depth + 1, true, &err_msg);
|
|
|
|
if (err_msg)
|
|
|
|
goto process_line;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* tokenize_auth_file() has taken care of creating the
|
|
|
|
* TokenizedAuthLines.
|
|
|
|
*/
|
|
|
|
goto next_line;
|
|
|
|
}
|
2001-07-30 16:50:24 +02:00
|
|
|
}
|
2017-01-27 19:43:00 +01:00
|
|
|
|
Add support for file inclusions in HBA and ident configuration files
pg_hba.conf and pg_ident.conf gain support for three record keywords:
- "include", to include a file.
- "include_if_exists", to include a file, ignoring it if missing.
- "include_dir", to include a directory of files. These are classified
by name (C locale, mostly) and need to be prefixed by ".conf", hence
following the same rules as GUCs.
This commit relies on the refactoring pieces done in efc9816, ad6c528,
783e8c6 and 1b73d0b, adding a small wrapper to build a list of
TokenizedAuthLines (tokenize_include_file), and the code is shaped to
offer some symmetry with what is done for GUCs with the same options.
pg_hba_file_rules and pg_ident_file_mappings gain a new field called
file_name, to track from which file a record is located, taking
advantage of the addition of rule_number in c591300 to offer an
organized view of the HBA or ident records loaded.
Bump catalog version.
Author: Julien Rouhaud
Reviewed-by: Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-11-24 05:51:34 +01:00
|
|
|
process_line:
|
|
|
|
|
|
|
|
/*
|
|
|
|
* General processing: report the error if any and emit line to the
|
|
|
|
* TokenizedAuthLine. This is saved in the memory context dedicated
|
|
|
|
* to this list.
|
|
|
|
*/
|
|
|
|
oldcxt = MemoryContextSwitchTo(tokenize_context);
|
|
|
|
tok_line = (TokenizedAuthLine *) palloc0(sizeof(TokenizedAuthLine));
|
|
|
|
tok_line->fields = current_line;
|
|
|
|
tok_line->file_name = pstrdup(filename);
|
|
|
|
tok_line->line_num = line_number;
|
|
|
|
tok_line->raw_line = pstrdup(buf.data);
|
|
|
|
tok_line->err_msg = err_msg ? pstrdup(err_msg) : NULL;
|
|
|
|
*tok_lines = lappend(*tok_lines, tok_line);
|
|
|
|
MemoryContextSwitchTo(oldcxt);
|
|
|
|
|
|
|
|
next_line:
|
2020-09-03 18:16:48 +02:00
|
|
|
line_number += continuations + 1;
|
2022-11-14 03:58:10 +01:00
|
|
|
callback_arg.linenum = line_number;
|
2001-07-30 16:50:24 +02:00
|
|
|
}
|
2011-06-20 23:20:14 +02:00
|
|
|
|
2022-11-24 00:21:55 +01:00
|
|
|
MemoryContextSwitchTo(funccxt);
|
|
|
|
MemoryContextDelete(linecxt);
|
2011-06-20 23:20:14 +02:00
|
|
|
|
2022-11-14 03:58:10 +01:00
|
|
|
error_context_stack = tokenerrcontext.previous;
|
2001-07-30 16:50:24 +02:00
|
|
|
}
|
|
|
|
|
2002-04-04 06:25:54 +02:00
|
|
|
|
|
|
|
/*
|
2005-06-29 00:16:45 +02:00
|
|
|
* Does user belong to role?
|
|
|
|
*
|
2009-08-29 21:26:52 +02:00
|
|
|
* userid is the OID of the role given as the attempted login identifier.
|
2005-06-29 00:16:45 +02:00
|
|
|
* We check to see if it is a member of the specified role name.
|
2002-04-04 06:25:54 +02:00
|
|
|
*/
|
2003-04-03 23:25:02 +02:00
|
|
|
static bool
|
2009-08-29 21:26:52 +02:00
|
|
|
is_member(Oid userid, const char *role)
|
2002-04-04 06:25:54 +02:00
|
|
|
{
|
2009-08-29 21:26:52 +02:00
|
|
|
Oid roleid;
|
2002-04-04 06:25:54 +02:00
|
|
|
|
2009-08-29 21:26:52 +02:00
|
|
|
if (!OidIsValid(userid))
|
2005-06-29 00:16:45 +02:00
|
|
|
return false; /* if user not exist, say "no" */
|
2004-05-26 06:41:50 +02:00
|
|
|
|
2010-08-05 16:45:09 +02:00
|
|
|
roleid = get_role_oid(role, true);
|
2005-02-20 05:45:59 +01:00
|
|
|
|
2009-08-29 21:26:52 +02:00
|
|
|
if (!OidIsValid(roleid))
|
|
|
|
return false; /* if target role not exist, say "no" */
|
2001-07-30 16:50:24 +02:00
|
|
|
|
2011-11-03 17:45:02 +01:00
|
|
|
/*
|
|
|
|
* See if user is directly or indirectly a member of role. For this
|
|
|
|
* purpose, a superuser is not considered to be automatically a member of
|
|
|
|
* the role, so group auth only applies to explicit membership.
|
|
|
|
*/
|
|
|
|
return is_member_of_role_nosuper(userid, roleid);
|
2002-04-04 06:25:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
Refactor code related to pg_hba_file_rules() into new file
hba.c is growing big, and more contents are planned for it. In order to
prepare for this future work, this commit moves all the code related to
the system function processing the contents of pg_hba.conf,
pg_hba_file_rules() to a new file called hbafuncs.c, which will be used
as the location for the SQL portion of the authentication file parsing.
While on it, HbaToken, the structure holding a string token lexed from a
configuration file related to authentication, is renamed to a more
generic AuthToken, as it gets used not only for pg_hba.conf, but also
for pg_ident.conf. TokenizedLine is now named TokenizedAuthLine.
The size of hba.c is reduced by ~12%.
Author: Julien Rouhaud
Reviewed-by: Aleksander Alekseev, Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-03-24 04:42:30 +01:00
|
|
|
* Check AuthToken list for a match to role, allowing group names.
|
Add support for regexps on database and user entries in pg_hba.conf
As of this commit, any database or user entry beginning with a slash (/)
is considered as a regular expression. This is particularly useful for
users, as now there is no clean way to match pattern on multiple HBA
lines. For example, a user name mapping with a regular expression needs
first to match with a HBA line, and we would skip the follow-up HBA
entries if the ident regexp does *not* match with what has matched in
the HBA line.
pg_hba.conf is able to handle multiple databases and roles with a
comma-separated list of these, hence individual regular expressions that
include commas need to be double-quoted.
At authentication time, user and database names are now checked in the
following order:
- Arbitrary keywords (like "all", the ones beginning by '+' for
membership check), that we know will never have a regexp. A fancy case
is for physical WAL senders, we *have* to only match "replication" for
the database.
- Regular expression matching.
- Exact match.
The previous logic did the same, but without the regexp step.
We have discussed as well the possibility to support regexp pattern
matching for host names, but these happen to lead to tricky issues based
on what I understand, particularly with host entries that have CIDRs.
This commit relies heavily on the refactoring done in a903971 and
fc579e1, so as the amount of code required to compile and execute
regular expressions is now minimal. When parsing pg_hba.conf, all the
computed regexps needs to explicitely free()'d, same as pg_ident.conf.
Documentation and TAP tests are added to cover this feature, including
cases where the regexps use commas (for clarity in the docs, coverage
for the parsing logic in the tests).
Note that this introduces a breakage with older versions, where a
database or user name beginning with a slash are treated as something to
check for an equal match. Per discussion, we have discarded this as
being much of an issue in practice as it would require a cluster to
have database and/or role names that begin with a slash, as well as HBA
entries using these. Hence, the consistency gained with regexps in
pg_ident.conf is more appealing in the long term.
**This compatibility change should be mentioned in the release notes.**
Author: Bertrand Drouvot
Reviewed-by: Jacob Champion, Tom Lane, Michael Paquier
Discussion: https://postgr.es/m/fff0d7c1-8ad4-76a1-9db3-0ab6ec338bf7@amazon.com
2022-10-24 04:45:31 +02:00
|
|
|
*
|
|
|
|
* Each AuthToken listed is checked one-by-one. Keywords are processed
|
|
|
|
* first (these cannot have regular expressions), followed by regular
|
Support the same patterns for pg-user in pg_ident.conf as in pg_hba.conf
While pg_hba.conf has support for non-literal username matches, and
this commit extends the capabilities that are supported for the
PostgreSQL user listed in an ident entry part of pg_ident.conf, with
support for:
1. The "all" keyword, where all the requested users are allowed.
2. Membership checks using the + prefix.
3. Using a regex to match against multiple roles.
1. is a feature that has been requested by Jelte Fennema, 2. something
that has been mentioned independently by Andrew Dunstan, and 3. is
something I came up with while discussing how to extend the first one,
whose implementation is facilitated by 8fea868.
This allows matching certain system users against many different
postgres users with a single line in pg_ident.conf. Without this, one
would need one line for each of the postgres users that a system user
can log in as, which can be cumbersome to maintain.
Tests are added to the TAP test of peer authentication to provide
coverage for all that.
Note that this introduces a set of backward-incompatible changes to be
able to detect the new patterns, for the following cases:
- A role named "all".
- A role prefixed with '+' characters, which is something that would not
have worked in HBA entries anyway.
- A role prefixed by a slash character, similarly to 8fea868.
Any of these can be still be handled by using quotes in the Postgres
role defined in an ident entry.
A huge advantage of this change is that the code applies the same checks
for the Postgres roles in HBA and ident entries, via the common routine
check_role().
**This compatibility change should be mentioned in the release notes.**
Author: Jelte Fennema
Discussion: https://postgr.es/m/DBBPR83MB0507FEC2E8965012990A80D0F7FC9@DBBPR83MB0507.EURPRD83.prod.outlook.com
2023-01-20 03:21:55 +01:00
|
|
|
* expressions (if any), the case-insensitive match (if requested) and
|
|
|
|
* the exact match.
|
2002-04-04 06:25:54 +02:00
|
|
|
*/
|
2003-04-03 23:25:02 +02:00
|
|
|
static bool
|
Support the same patterns for pg-user in pg_ident.conf as in pg_hba.conf
While pg_hba.conf has support for non-literal username matches, and
this commit extends the capabilities that are supported for the
PostgreSQL user listed in an ident entry part of pg_ident.conf, with
support for:
1. The "all" keyword, where all the requested users are allowed.
2. Membership checks using the + prefix.
3. Using a regex to match against multiple roles.
1. is a feature that has been requested by Jelte Fennema, 2. something
that has been mentioned independently by Andrew Dunstan, and 3. is
something I came up with while discussing how to extend the first one,
whose implementation is facilitated by 8fea868.
This allows matching certain system users against many different
postgres users with a single line in pg_ident.conf. Without this, one
would need one line for each of the postgres users that a system user
can log in as, which can be cumbersome to maintain.
Tests are added to the TAP test of peer authentication to provide
coverage for all that.
Note that this introduces a set of backward-incompatible changes to be
able to detect the new patterns, for the following cases:
- A role named "all".
- A role prefixed with '+' characters, which is something that would not
have worked in HBA entries anyway.
- A role prefixed by a slash character, similarly to 8fea868.
Any of these can be still be handled by using quotes in the Postgres
role defined in an ident entry.
A huge advantage of this change is that the code applies the same checks
for the Postgres roles in HBA and ident entries, via the common routine
check_role().
**This compatibility change should be mentioned in the release notes.**
Author: Jelte Fennema
Discussion: https://postgr.es/m/DBBPR83MB0507FEC2E8965012990A80D0F7FC9@DBBPR83MB0507.EURPRD83.prod.outlook.com
2023-01-20 03:21:55 +01:00
|
|
|
check_role(const char *role, Oid roleid, List *tokens, bool case_insensitive)
|
2002-04-04 06:25:54 +02:00
|
|
|
{
|
2011-06-20 23:20:14 +02:00
|
|
|
ListCell *cell;
|
Refactor code related to pg_hba_file_rules() into new file
hba.c is growing big, and more contents are planned for it. In order to
prepare for this future work, this commit moves all the code related to
the system function processing the contents of pg_hba.conf,
pg_hba_file_rules() to a new file called hbafuncs.c, which will be used
as the location for the SQL portion of the authentication file parsing.
While on it, HbaToken, the structure holding a string token lexed from a
configuration file related to authentication, is renamed to a more
generic AuthToken, as it gets used not only for pg_hba.conf, but also
for pg_ident.conf. TokenizedLine is now named TokenizedAuthLine.
The size of hba.c is reduced by ~12%.
Author: Julien Rouhaud
Reviewed-by: Aleksander Alekseev, Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-03-24 04:42:30 +01:00
|
|
|
AuthToken *tok;
|
2002-04-04 06:25:54 +02:00
|
|
|
|
2011-06-20 23:20:14 +02:00
|
|
|
foreach(cell, tokens)
|
2002-04-04 06:25:54 +02:00
|
|
|
{
|
2011-06-20 23:20:14 +02:00
|
|
|
tok = lfirst(cell);
|
Support the same patterns for pg-user in pg_ident.conf as in pg_hba.conf
While pg_hba.conf has support for non-literal username matches, and
this commit extends the capabilities that are supported for the
PostgreSQL user listed in an ident entry part of pg_ident.conf, with
support for:
1. The "all" keyword, where all the requested users are allowed.
2. Membership checks using the + prefix.
3. Using a regex to match against multiple roles.
1. is a feature that has been requested by Jelte Fennema, 2. something
that has been mentioned independently by Andrew Dunstan, and 3. is
something I came up with while discussing how to extend the first one,
whose implementation is facilitated by 8fea868.
This allows matching certain system users against many different
postgres users with a single line in pg_ident.conf. Without this, one
would need one line for each of the postgres users that a system user
can log in as, which can be cumbersome to maintain.
Tests are added to the TAP test of peer authentication to provide
coverage for all that.
Note that this introduces a set of backward-incompatible changes to be
able to detect the new patterns, for the following cases:
- A role named "all".
- A role prefixed with '+' characters, which is something that would not
have worked in HBA entries anyway.
- A role prefixed by a slash character, similarly to 8fea868.
Any of these can be still be handled by using quotes in the Postgres
role defined in an ident entry.
A huge advantage of this change is that the code applies the same checks
for the Postgres roles in HBA and ident entries, via the common routine
check_role().
**This compatibility change should be mentioned in the release notes.**
Author: Jelte Fennema
Discussion: https://postgr.es/m/DBBPR83MB0507FEC2E8965012990A80D0F7FC9@DBBPR83MB0507.EURPRD83.prod.outlook.com
2023-01-20 03:21:55 +01:00
|
|
|
if (token_is_member_check(tok))
|
2001-07-30 16:50:24 +02:00
|
|
|
{
|
2011-06-20 23:20:14 +02:00
|
|
|
if (is_member(roleid, tok->string + 1))
|
2003-04-03 23:25:02 +02:00
|
|
|
return true;
|
2002-04-04 06:25:54 +02:00
|
|
|
}
|
Add support for regexps on database and user entries in pg_hba.conf
As of this commit, any database or user entry beginning with a slash (/)
is considered as a regular expression. This is particularly useful for
users, as now there is no clean way to match pattern on multiple HBA
lines. For example, a user name mapping with a regular expression needs
first to match with a HBA line, and we would skip the follow-up HBA
entries if the ident regexp does *not* match with what has matched in
the HBA line.
pg_hba.conf is able to handle multiple databases and roles with a
comma-separated list of these, hence individual regular expressions that
include commas need to be double-quoted.
At authentication time, user and database names are now checked in the
following order:
- Arbitrary keywords (like "all", the ones beginning by '+' for
membership check), that we know will never have a regexp. A fancy case
is for physical WAL senders, we *have* to only match "replication" for
the database.
- Regular expression matching.
- Exact match.
The previous logic did the same, but without the regexp step.
We have discussed as well the possibility to support regexp pattern
matching for host names, but these happen to lead to tricky issues based
on what I understand, particularly with host entries that have CIDRs.
This commit relies heavily on the refactoring done in a903971 and
fc579e1, so as the amount of code required to compile and execute
regular expressions is now minimal. When parsing pg_hba.conf, all the
computed regexps needs to explicitely free()'d, same as pg_ident.conf.
Documentation and TAP tests are added to cover this feature, including
cases where the regexps use commas (for clarity in the docs, coverage
for the parsing logic in the tests).
Note that this introduces a breakage with older versions, where a
database or user name beginning with a slash are treated as something to
check for an equal match. Per discussion, we have discarded this as
being much of an issue in practice as it would require a cluster to
have database and/or role names that begin with a slash, as well as HBA
entries using these. Hence, the consistency gained with regexps in
pg_ident.conf is more appealing in the long term.
**This compatibility change should be mentioned in the release notes.**
Author: Bertrand Drouvot
Reviewed-by: Jacob Champion, Tom Lane, Michael Paquier
Discussion: https://postgr.es/m/fff0d7c1-8ad4-76a1-9db3-0ab6ec338bf7@amazon.com
2022-10-24 04:45:31 +02:00
|
|
|
else if (token_is_keyword(tok, "all"))
|
|
|
|
return true;
|
|
|
|
else if (token_has_regexp(tok))
|
|
|
|
{
|
|
|
|
if (regexec_auth_token(role, tok, 0, NULL) == REG_OKAY)
|
|
|
|
return true;
|
|
|
|
}
|
Support the same patterns for pg-user in pg_ident.conf as in pg_hba.conf
While pg_hba.conf has support for non-literal username matches, and
this commit extends the capabilities that are supported for the
PostgreSQL user listed in an ident entry part of pg_ident.conf, with
support for:
1. The "all" keyword, where all the requested users are allowed.
2. Membership checks using the + prefix.
3. Using a regex to match against multiple roles.
1. is a feature that has been requested by Jelte Fennema, 2. something
that has been mentioned independently by Andrew Dunstan, and 3. is
something I came up with while discussing how to extend the first one,
whose implementation is facilitated by 8fea868.
This allows matching certain system users against many different
postgres users with a single line in pg_ident.conf. Without this, one
would need one line for each of the postgres users that a system user
can log in as, which can be cumbersome to maintain.
Tests are added to the TAP test of peer authentication to provide
coverage for all that.
Note that this introduces a set of backward-incompatible changes to be
able to detect the new patterns, for the following cases:
- A role named "all".
- A role prefixed with '+' characters, which is something that would not
have worked in HBA entries anyway.
- A role prefixed by a slash character, similarly to 8fea868.
Any of these can be still be handled by using quotes in the Postgres
role defined in an ident entry.
A huge advantage of this change is that the code applies the same checks
for the Postgres roles in HBA and ident entries, via the common routine
check_role().
**This compatibility change should be mentioned in the release notes.**
Author: Jelte Fennema
Discussion: https://postgr.es/m/DBBPR83MB0507FEC2E8965012990A80D0F7FC9@DBBPR83MB0507.EURPRD83.prod.outlook.com
2023-01-20 03:21:55 +01:00
|
|
|
else if (case_insensitive)
|
|
|
|
{
|
|
|
|
if (token_matches_insensitive(tok, role))
|
|
|
|
return true;
|
|
|
|
}
|
Add support for regexps on database and user entries in pg_hba.conf
As of this commit, any database or user entry beginning with a slash (/)
is considered as a regular expression. This is particularly useful for
users, as now there is no clean way to match pattern on multiple HBA
lines. For example, a user name mapping with a regular expression needs
first to match with a HBA line, and we would skip the follow-up HBA
entries if the ident regexp does *not* match with what has matched in
the HBA line.
pg_hba.conf is able to handle multiple databases and roles with a
comma-separated list of these, hence individual regular expressions that
include commas need to be double-quoted.
At authentication time, user and database names are now checked in the
following order:
- Arbitrary keywords (like "all", the ones beginning by '+' for
membership check), that we know will never have a regexp. A fancy case
is for physical WAL senders, we *have* to only match "replication" for
the database.
- Regular expression matching.
- Exact match.
The previous logic did the same, but without the regexp step.
We have discussed as well the possibility to support regexp pattern
matching for host names, but these happen to lead to tricky issues based
on what I understand, particularly with host entries that have CIDRs.
This commit relies heavily on the refactoring done in a903971 and
fc579e1, so as the amount of code required to compile and execute
regular expressions is now minimal. When parsing pg_hba.conf, all the
computed regexps needs to explicitely free()'d, same as pg_ident.conf.
Documentation and TAP tests are added to cover this feature, including
cases where the regexps use commas (for clarity in the docs, coverage
for the parsing logic in the tests).
Note that this introduces a breakage with older versions, where a
database or user name beginning with a slash are treated as something to
check for an equal match. Per discussion, we have discarded this as
being much of an issue in practice as it would require a cluster to
have database and/or role names that begin with a slash, as well as HBA
entries using these. Hence, the consistency gained with regexps in
pg_ident.conf is more appealing in the long term.
**This compatibility change should be mentioned in the release notes.**
Author: Bertrand Drouvot
Reviewed-by: Jacob Champion, Tom Lane, Michael Paquier
Discussion: https://postgr.es/m/fff0d7c1-8ad4-76a1-9db3-0ab6ec338bf7@amazon.com
2022-10-24 04:45:31 +02:00
|
|
|
else if (token_matches(tok, role))
|
2003-04-03 23:25:02 +02:00
|
|
|
return true;
|
2002-04-04 06:25:54 +02:00
|
|
|
}
|
2003-04-03 23:25:02 +02:00
|
|
|
return false;
|
2002-04-04 06:25:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
Refactor code related to pg_hba_file_rules() into new file
hba.c is growing big, and more contents are planned for it. In order to
prepare for this future work, this commit moves all the code related to
the system function processing the contents of pg_hba.conf,
pg_hba_file_rules() to a new file called hbafuncs.c, which will be used
as the location for the SQL portion of the authentication file parsing.
While on it, HbaToken, the structure holding a string token lexed from a
configuration file related to authentication, is renamed to a more
generic AuthToken, as it gets used not only for pg_hba.conf, but also
for pg_ident.conf. TokenizedLine is now named TokenizedAuthLine.
The size of hba.c is reduced by ~12%.
Author: Julien Rouhaud
Reviewed-by: Aleksander Alekseev, Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-03-24 04:42:30 +01:00
|
|
|
* Check to see if db/role combination matches AuthToken list.
|
Add support for regexps on database and user entries in pg_hba.conf
As of this commit, any database or user entry beginning with a slash (/)
is considered as a regular expression. This is particularly useful for
users, as now there is no clean way to match pattern on multiple HBA
lines. For example, a user name mapping with a regular expression needs
first to match with a HBA line, and we would skip the follow-up HBA
entries if the ident regexp does *not* match with what has matched in
the HBA line.
pg_hba.conf is able to handle multiple databases and roles with a
comma-separated list of these, hence individual regular expressions that
include commas need to be double-quoted.
At authentication time, user and database names are now checked in the
following order:
- Arbitrary keywords (like "all", the ones beginning by '+' for
membership check), that we know will never have a regexp. A fancy case
is for physical WAL senders, we *have* to only match "replication" for
the database.
- Regular expression matching.
- Exact match.
The previous logic did the same, but without the regexp step.
We have discussed as well the possibility to support regexp pattern
matching for host names, but these happen to lead to tricky issues based
on what I understand, particularly with host entries that have CIDRs.
This commit relies heavily on the refactoring done in a903971 and
fc579e1, so as the amount of code required to compile and execute
regular expressions is now minimal. When parsing pg_hba.conf, all the
computed regexps needs to explicitely free()'d, same as pg_ident.conf.
Documentation and TAP tests are added to cover this feature, including
cases where the regexps use commas (for clarity in the docs, coverage
for the parsing logic in the tests).
Note that this introduces a breakage with older versions, where a
database or user name beginning with a slash are treated as something to
check for an equal match. Per discussion, we have discarded this as
being much of an issue in practice as it would require a cluster to
have database and/or role names that begin with a slash, as well as HBA
entries using these. Hence, the consistency gained with regexps in
pg_ident.conf is more appealing in the long term.
**This compatibility change should be mentioned in the release notes.**
Author: Bertrand Drouvot
Reviewed-by: Jacob Champion, Tom Lane, Michael Paquier
Discussion: https://postgr.es/m/fff0d7c1-8ad4-76a1-9db3-0ab6ec338bf7@amazon.com
2022-10-24 04:45:31 +02:00
|
|
|
*
|
|
|
|
* Each AuthToken listed is checked one-by-one. Keywords are checked
|
|
|
|
* first (these cannot have regular expressions), followed by regular
|
|
|
|
* expressions (if any) and the exact match.
|
2002-04-04 06:25:54 +02:00
|
|
|
*/
|
2003-04-03 23:25:02 +02:00
|
|
|
static bool
|
2011-06-20 23:20:14 +02:00
|
|
|
check_db(const char *dbname, const char *role, Oid roleid, List *tokens)
|
2002-04-04 06:25:54 +02:00
|
|
|
{
|
2011-06-20 23:20:14 +02:00
|
|
|
ListCell *cell;
|
Refactor code related to pg_hba_file_rules() into new file
hba.c is growing big, and more contents are planned for it. In order to
prepare for this future work, this commit moves all the code related to
the system function processing the contents of pg_hba.conf,
pg_hba_file_rules() to a new file called hbafuncs.c, which will be used
as the location for the SQL portion of the authentication file parsing.
While on it, HbaToken, the structure holding a string token lexed from a
configuration file related to authentication, is renamed to a more
generic AuthToken, as it gets used not only for pg_hba.conf, but also
for pg_ident.conf. TokenizedLine is now named TokenizedAuthLine.
The size of hba.c is reduced by ~12%.
Author: Julien Rouhaud
Reviewed-by: Aleksander Alekseev, Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-03-24 04:42:30 +01:00
|
|
|
AuthToken *tok;
|
2002-04-04 06:25:54 +02:00
|
|
|
|
2011-06-20 23:20:14 +02:00
|
|
|
foreach(cell, tokens)
|
2002-04-04 06:25:54 +02:00
|
|
|
{
|
2011-06-20 23:20:14 +02:00
|
|
|
tok = lfirst(cell);
|
2017-02-13 22:50:29 +01:00
|
|
|
if (am_walsender && !am_db_walsender)
|
2010-04-21 05:32:53 +02:00
|
|
|
{
|
2017-02-13 22:50:29 +01:00
|
|
|
/*
|
|
|
|
* physical replication walsender connections can only match
|
|
|
|
* replication keyword
|
|
|
|
*/
|
2011-06-20 23:20:14 +02:00
|
|
|
if (token_is_keyword(tok, "replication"))
|
2010-04-21 05:32:53 +02:00
|
|
|
return true;
|
|
|
|
}
|
2011-06-20 23:20:14 +02:00
|
|
|
else if (token_is_keyword(tok, "all"))
|
2003-04-03 23:25:02 +02:00
|
|
|
return true;
|
2011-06-20 23:20:14 +02:00
|
|
|
else if (token_is_keyword(tok, "sameuser"))
|
2002-04-04 06:25:54 +02:00
|
|
|
{
|
2005-06-28 07:09:14 +02:00
|
|
|
if (strcmp(dbname, role) == 0)
|
2003-04-03 23:25:02 +02:00
|
|
|
return true;
|
2001-07-30 16:50:24 +02:00
|
|
|
}
|
2011-06-20 23:20:14 +02:00
|
|
|
else if (token_is_keyword(tok, "samegroup") ||
|
|
|
|
token_is_keyword(tok, "samerole"))
|
2002-04-04 06:25:54 +02:00
|
|
|
{
|
2009-08-29 21:26:52 +02:00
|
|
|
if (is_member(roleid, dbname))
|
2003-04-03 23:25:02 +02:00
|
|
|
return true;
|
2002-04-04 06:25:54 +02:00
|
|
|
}
|
2011-06-20 23:20:14 +02:00
|
|
|
else if (token_is_keyword(tok, "replication"))
|
2010-04-21 05:32:53 +02:00
|
|
|
continue; /* never match this if not walsender */
|
Add support for regexps on database and user entries in pg_hba.conf
As of this commit, any database or user entry beginning with a slash (/)
is considered as a regular expression. This is particularly useful for
users, as now there is no clean way to match pattern on multiple HBA
lines. For example, a user name mapping with a regular expression needs
first to match with a HBA line, and we would skip the follow-up HBA
entries if the ident regexp does *not* match with what has matched in
the HBA line.
pg_hba.conf is able to handle multiple databases and roles with a
comma-separated list of these, hence individual regular expressions that
include commas need to be double-quoted.
At authentication time, user and database names are now checked in the
following order:
- Arbitrary keywords (like "all", the ones beginning by '+' for
membership check), that we know will never have a regexp. A fancy case
is for physical WAL senders, we *have* to only match "replication" for
the database.
- Regular expression matching.
- Exact match.
The previous logic did the same, but without the regexp step.
We have discussed as well the possibility to support regexp pattern
matching for host names, but these happen to lead to tricky issues based
on what I understand, particularly with host entries that have CIDRs.
This commit relies heavily on the refactoring done in a903971 and
fc579e1, so as the amount of code required to compile and execute
regular expressions is now minimal. When parsing pg_hba.conf, all the
computed regexps needs to explicitely free()'d, same as pg_ident.conf.
Documentation and TAP tests are added to cover this feature, including
cases where the regexps use commas (for clarity in the docs, coverage
for the parsing logic in the tests).
Note that this introduces a breakage with older versions, where a
database or user name beginning with a slash are treated as something to
check for an equal match. Per discussion, we have discarded this as
being much of an issue in practice as it would require a cluster to
have database and/or role names that begin with a slash, as well as HBA
entries using these. Hence, the consistency gained with regexps in
pg_ident.conf is more appealing in the long term.
**This compatibility change should be mentioned in the release notes.**
Author: Bertrand Drouvot
Reviewed-by: Jacob Champion, Tom Lane, Michael Paquier
Discussion: https://postgr.es/m/fff0d7c1-8ad4-76a1-9db3-0ab6ec338bf7@amazon.com
2022-10-24 04:45:31 +02:00
|
|
|
else if (token_has_regexp(tok))
|
|
|
|
{
|
|
|
|
if (regexec_auth_token(dbname, tok, 0, NULL) == REG_OKAY)
|
|
|
|
return true;
|
|
|
|
}
|
2011-06-20 23:20:14 +02:00
|
|
|
else if (token_matches(tok, dbname))
|
2003-04-03 23:25:02 +02:00
|
|
|
return true;
|
2001-07-30 16:50:24 +02:00
|
|
|
}
|
2003-04-03 23:25:02 +02:00
|
|
|
return false;
|
2001-07-30 16:50:24 +02:00
|
|
|
}
|
|
|
|
|
2010-10-15 21:53:39 +02:00
|
|
|
static bool
|
|
|
|
ipv4eq(struct sockaddr_in *a, struct sockaddr_in *b)
|
|
|
|
{
|
|
|
|
return (a->sin_addr.s_addr == b->sin_addr.s_addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
ipv6eq(struct sockaddr_in6 *a, struct sockaddr_in6 *b)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < 16; i++)
|
|
|
|
if (a->sin6_addr.s6_addr[i] != b->sin6_addr.s6_addr[i])
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2010-10-16 16:12:16 +02:00
|
|
|
|
2010-10-24 14:54:00 +02:00
|
|
|
/*
|
|
|
|
* Check whether host name matches pattern.
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
hostname_match(const char *pattern, const char *actual_hostname)
|
|
|
|
{
|
|
|
|
if (pattern[0] == '.') /* suffix match */
|
|
|
|
{
|
|
|
|
size_t plen = strlen(pattern);
|
|
|
|
size_t hlen = strlen(actual_hostname);
|
|
|
|
|
|
|
|
if (hlen < plen)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return (pg_strcasecmp(pattern, actual_hostname + (hlen - plen)) == 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return (pg_strcasecmp(pattern, actual_hostname) == 0);
|
|
|
|
}
|
|
|
|
|
2010-10-15 21:53:39 +02:00
|
|
|
/*
|
|
|
|
* Check to see if a connecting IP matches a given host name.
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
check_hostname(hbaPort *port, const char *hostname)
|
|
|
|
{
|
|
|
|
struct addrinfo *gai_result,
|
|
|
|
*gai;
|
|
|
|
int ret;
|
|
|
|
bool found;
|
|
|
|
|
Fix assorted issues in client host name lookup.
The code for matching clients to pg_hba.conf lines that specify host names
(instead of IP address ranges) failed to complain if reverse DNS lookup
failed; instead it silently didn't match, so that you might end up getting
a surprising "no pg_hba.conf entry for ..." error, as seen in bug #9518
from Mike Blackwell. Since we don't want to make this a fatal error in
situations where pg_hba.conf contains a mixture of host names and IP
addresses (clients matching one of the numeric entries should not have to
have rDNS data), remember the lookup failure and mention it as DETAIL if
we get to "no pg_hba.conf entry". Apply the same approach to forward-DNS
lookup failures, too, rather than treating them as immediate hard errors.
Along the way, fix a couple of bugs that prevented us from detecting an
rDNS lookup error reliably, and make sure that we make only one rDNS lookup
attempt; formerly, if the lookup attempt failed, the code would try again
for each host name entry in pg_hba.conf. Since more or less the whole
point of this design is to ensure there's only one lookup attempt not one
per entry, the latter point represents a performance bug that seems
sufficient justification for back-patching.
Also, adjust src/port/getaddrinfo.c so that it plays as well as it can
with this code. Which is not all that well, since it does not have actual
support for rDNS lookup, but at least it should return the expected (and
required by spec) error codes so that the main code correctly perceives the
lack of functionality as a lookup failure. It's unlikely that PG is still
being used in production on any machines that require our getaddrinfo.c,
so I'm not excited about working harder than this.
To keep the code in the various branches similar, this includes
back-patching commits c424d0d1052cb4053c8712ac44123f9b9a9aa3f2 and
1997f34db4687e671690ed054c8f30bb501b1168 into 9.2 and earlier.
Back-patch to 9.1 where the facility for hostnames in pg_hba.conf was
introduced.
2014-04-02 23:11:24 +02:00
|
|
|
/* Quick out if remote host name already known bad */
|
|
|
|
if (port->remote_hostname_resolv < 0)
|
|
|
|
return false;
|
|
|
|
|
2010-10-15 21:53:39 +02:00
|
|
|
/* Lookup remote host name if not already done */
|
|
|
|
if (!port->remote_hostname)
|
|
|
|
{
|
|
|
|
char remote_hostname[NI_MAXHOST];
|
|
|
|
|
Fix assorted issues in client host name lookup.
The code for matching clients to pg_hba.conf lines that specify host names
(instead of IP address ranges) failed to complain if reverse DNS lookup
failed; instead it silently didn't match, so that you might end up getting
a surprising "no pg_hba.conf entry for ..." error, as seen in bug #9518
from Mike Blackwell. Since we don't want to make this a fatal error in
situations where pg_hba.conf contains a mixture of host names and IP
addresses (clients matching one of the numeric entries should not have to
have rDNS data), remember the lookup failure and mention it as DETAIL if
we get to "no pg_hba.conf entry". Apply the same approach to forward-DNS
lookup failures, too, rather than treating them as immediate hard errors.
Along the way, fix a couple of bugs that prevented us from detecting an
rDNS lookup error reliably, and make sure that we make only one rDNS lookup
attempt; formerly, if the lookup attempt failed, the code would try again
for each host name entry in pg_hba.conf. Since more or less the whole
point of this design is to ensure there's only one lookup attempt not one
per entry, the latter point represents a performance bug that seems
sufficient justification for back-patching.
Also, adjust src/port/getaddrinfo.c so that it plays as well as it can
with this code. Which is not all that well, since it does not have actual
support for rDNS lookup, but at least it should return the expected (and
required by spec) error codes so that the main code correctly perceives the
lack of functionality as a lookup failure. It's unlikely that PG is still
being used in production on any machines that require our getaddrinfo.c,
so I'm not excited about working harder than this.
To keep the code in the various branches similar, this includes
back-patching commits c424d0d1052cb4053c8712ac44123f9b9a9aa3f2 and
1997f34db4687e671690ed054c8f30bb501b1168 into 9.2 and earlier.
Back-patch to 9.1 where the facility for hostnames in pg_hba.conf was
introduced.
2014-04-02 23:11:24 +02:00
|
|
|
ret = pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
|
|
|
|
remote_hostname, sizeof(remote_hostname),
|
|
|
|
NULL, 0,
|
|
|
|
NI_NAMEREQD);
|
|
|
|
if (ret != 0)
|
|
|
|
{
|
|
|
|
/* remember failure; don't complain in the postmaster log yet */
|
|
|
|
port->remote_hostname_resolv = -2;
|
|
|
|
port->remote_hostname_errcode = ret;
|
2010-10-15 21:53:39 +02:00
|
|
|
return false;
|
Fix assorted issues in client host name lookup.
The code for matching clients to pg_hba.conf lines that specify host names
(instead of IP address ranges) failed to complain if reverse DNS lookup
failed; instead it silently didn't match, so that you might end up getting
a surprising "no pg_hba.conf entry for ..." error, as seen in bug #9518
from Mike Blackwell. Since we don't want to make this a fatal error in
situations where pg_hba.conf contains a mixture of host names and IP
addresses (clients matching one of the numeric entries should not have to
have rDNS data), remember the lookup failure and mention it as DETAIL if
we get to "no pg_hba.conf entry". Apply the same approach to forward-DNS
lookup failures, too, rather than treating them as immediate hard errors.
Along the way, fix a couple of bugs that prevented us from detecting an
rDNS lookup error reliably, and make sure that we make only one rDNS lookup
attempt; formerly, if the lookup attempt failed, the code would try again
for each host name entry in pg_hba.conf. Since more or less the whole
point of this design is to ensure there's only one lookup attempt not one
per entry, the latter point represents a performance bug that seems
sufficient justification for back-patching.
Also, adjust src/port/getaddrinfo.c so that it plays as well as it can
with this code. Which is not all that well, since it does not have actual
support for rDNS lookup, but at least it should return the expected (and
required by spec) error codes so that the main code correctly perceives the
lack of functionality as a lookup failure. It's unlikely that PG is still
being used in production on any machines that require our getaddrinfo.c,
so I'm not excited about working harder than this.
To keep the code in the various branches similar, this includes
back-patching commits c424d0d1052cb4053c8712ac44123f9b9a9aa3f2 and
1997f34db4687e671690ed054c8f30bb501b1168 into 9.2 and earlier.
Back-patch to 9.1 where the facility for hostnames in pg_hba.conf was
introduced.
2014-04-02 23:11:24 +02:00
|
|
|
}
|
2010-10-15 21:53:39 +02:00
|
|
|
|
|
|
|
port->remote_hostname = pstrdup(remote_hostname);
|
|
|
|
}
|
|
|
|
|
Fix assorted issues in client host name lookup.
The code for matching clients to pg_hba.conf lines that specify host names
(instead of IP address ranges) failed to complain if reverse DNS lookup
failed; instead it silently didn't match, so that you might end up getting
a surprising "no pg_hba.conf entry for ..." error, as seen in bug #9518
from Mike Blackwell. Since we don't want to make this a fatal error in
situations where pg_hba.conf contains a mixture of host names and IP
addresses (clients matching one of the numeric entries should not have to
have rDNS data), remember the lookup failure and mention it as DETAIL if
we get to "no pg_hba.conf entry". Apply the same approach to forward-DNS
lookup failures, too, rather than treating them as immediate hard errors.
Along the way, fix a couple of bugs that prevented us from detecting an
rDNS lookup error reliably, and make sure that we make only one rDNS lookup
attempt; formerly, if the lookup attempt failed, the code would try again
for each host name entry in pg_hba.conf. Since more or less the whole
point of this design is to ensure there's only one lookup attempt not one
per entry, the latter point represents a performance bug that seems
sufficient justification for back-patching.
Also, adjust src/port/getaddrinfo.c so that it plays as well as it can
with this code. Which is not all that well, since it does not have actual
support for rDNS lookup, but at least it should return the expected (and
required by spec) error codes so that the main code correctly perceives the
lack of functionality as a lookup failure. It's unlikely that PG is still
being used in production on any machines that require our getaddrinfo.c,
so I'm not excited about working harder than this.
To keep the code in the various branches similar, this includes
back-patching commits c424d0d1052cb4053c8712ac44123f9b9a9aa3f2 and
1997f34db4687e671690ed054c8f30bb501b1168 into 9.2 and earlier.
Back-patch to 9.1 where the facility for hostnames in pg_hba.conf was
introduced.
2014-04-02 23:11:24 +02:00
|
|
|
/* Now see if remote host name matches this pg_hba line */
|
2010-10-24 14:54:00 +02:00
|
|
|
if (!hostname_match(hostname, port->remote_hostname))
|
2010-10-15 21:53:39 +02:00
|
|
|
return false;
|
|
|
|
|
Fix assorted issues in client host name lookup.
The code for matching clients to pg_hba.conf lines that specify host names
(instead of IP address ranges) failed to complain if reverse DNS lookup
failed; instead it silently didn't match, so that you might end up getting
a surprising "no pg_hba.conf entry for ..." error, as seen in bug #9518
from Mike Blackwell. Since we don't want to make this a fatal error in
situations where pg_hba.conf contains a mixture of host names and IP
addresses (clients matching one of the numeric entries should not have to
have rDNS data), remember the lookup failure and mention it as DETAIL if
we get to "no pg_hba.conf entry". Apply the same approach to forward-DNS
lookup failures, too, rather than treating them as immediate hard errors.
Along the way, fix a couple of bugs that prevented us from detecting an
rDNS lookup error reliably, and make sure that we make only one rDNS lookup
attempt; formerly, if the lookup attempt failed, the code would try again
for each host name entry in pg_hba.conf. Since more or less the whole
point of this design is to ensure there's only one lookup attempt not one
per entry, the latter point represents a performance bug that seems
sufficient justification for back-patching.
Also, adjust src/port/getaddrinfo.c so that it plays as well as it can
with this code. Which is not all that well, since it does not have actual
support for rDNS lookup, but at least it should return the expected (and
required by spec) error codes so that the main code correctly perceives the
lack of functionality as a lookup failure. It's unlikely that PG is still
being used in production on any machines that require our getaddrinfo.c,
so I'm not excited about working harder than this.
To keep the code in the various branches similar, this includes
back-patching commits c424d0d1052cb4053c8712ac44123f9b9a9aa3f2 and
1997f34db4687e671690ed054c8f30bb501b1168 into 9.2 and earlier.
Back-patch to 9.1 where the facility for hostnames in pg_hba.conf was
introduced.
2014-04-02 23:11:24 +02:00
|
|
|
/* If we already verified the forward lookup, we're done */
|
2010-10-15 21:53:39 +02:00
|
|
|
if (port->remote_hostname_resolv == +1)
|
|
|
|
return true;
|
|
|
|
|
Fix assorted issues in client host name lookup.
The code for matching clients to pg_hba.conf lines that specify host names
(instead of IP address ranges) failed to complain if reverse DNS lookup
failed; instead it silently didn't match, so that you might end up getting
a surprising "no pg_hba.conf entry for ..." error, as seen in bug #9518
from Mike Blackwell. Since we don't want to make this a fatal error in
situations where pg_hba.conf contains a mixture of host names and IP
addresses (clients matching one of the numeric entries should not have to
have rDNS data), remember the lookup failure and mention it as DETAIL if
we get to "no pg_hba.conf entry". Apply the same approach to forward-DNS
lookup failures, too, rather than treating them as immediate hard errors.
Along the way, fix a couple of bugs that prevented us from detecting an
rDNS lookup error reliably, and make sure that we make only one rDNS lookup
attempt; formerly, if the lookup attempt failed, the code would try again
for each host name entry in pg_hba.conf. Since more or less the whole
point of this design is to ensure there's only one lookup attempt not one
per entry, the latter point represents a performance bug that seems
sufficient justification for back-patching.
Also, adjust src/port/getaddrinfo.c so that it plays as well as it can
with this code. Which is not all that well, since it does not have actual
support for rDNS lookup, but at least it should return the expected (and
required by spec) error codes so that the main code correctly perceives the
lack of functionality as a lookup failure. It's unlikely that PG is still
being used in production on any machines that require our getaddrinfo.c,
so I'm not excited about working harder than this.
To keep the code in the various branches similar, this includes
back-patching commits c424d0d1052cb4053c8712ac44123f9b9a9aa3f2 and
1997f34db4687e671690ed054c8f30bb501b1168 into 9.2 and earlier.
Back-patch to 9.1 where the facility for hostnames in pg_hba.conf was
introduced.
2014-04-02 23:11:24 +02:00
|
|
|
/* Lookup IP from host name and check against original IP */
|
2010-10-15 21:53:39 +02:00
|
|
|
ret = getaddrinfo(port->remote_hostname, NULL, NULL, &gai_result);
|
|
|
|
if (ret != 0)
|
Fix assorted issues in client host name lookup.
The code for matching clients to pg_hba.conf lines that specify host names
(instead of IP address ranges) failed to complain if reverse DNS lookup
failed; instead it silently didn't match, so that you might end up getting
a surprising "no pg_hba.conf entry for ..." error, as seen in bug #9518
from Mike Blackwell. Since we don't want to make this a fatal error in
situations where pg_hba.conf contains a mixture of host names and IP
addresses (clients matching one of the numeric entries should not have to
have rDNS data), remember the lookup failure and mention it as DETAIL if
we get to "no pg_hba.conf entry". Apply the same approach to forward-DNS
lookup failures, too, rather than treating them as immediate hard errors.
Along the way, fix a couple of bugs that prevented us from detecting an
rDNS lookup error reliably, and make sure that we make only one rDNS lookup
attempt; formerly, if the lookup attempt failed, the code would try again
for each host name entry in pg_hba.conf. Since more or less the whole
point of this design is to ensure there's only one lookup attempt not one
per entry, the latter point represents a performance bug that seems
sufficient justification for back-patching.
Also, adjust src/port/getaddrinfo.c so that it plays as well as it can
with this code. Which is not all that well, since it does not have actual
support for rDNS lookup, but at least it should return the expected (and
required by spec) error codes so that the main code correctly perceives the
lack of functionality as a lookup failure. It's unlikely that PG is still
being used in production on any machines that require our getaddrinfo.c,
so I'm not excited about working harder than this.
To keep the code in the various branches similar, this includes
back-patching commits c424d0d1052cb4053c8712ac44123f9b9a9aa3f2 and
1997f34db4687e671690ed054c8f30bb501b1168 into 9.2 and earlier.
Back-patch to 9.1 where the facility for hostnames in pg_hba.conf was
introduced.
2014-04-02 23:11:24 +02:00
|
|
|
{
|
|
|
|
/* remember failure; don't complain in the postmaster log yet */
|
|
|
|
port->remote_hostname_resolv = -2;
|
|
|
|
port->remote_hostname_errcode = ret;
|
|
|
|
return false;
|
|
|
|
}
|
2010-10-15 21:53:39 +02:00
|
|
|
|
|
|
|
found = false;
|
|
|
|
for (gai = gai_result; gai; gai = gai->ai_next)
|
|
|
|
{
|
|
|
|
if (gai->ai_addr->sa_family == port->raddr.addr.ss_family)
|
|
|
|
{
|
|
|
|
if (gai->ai_addr->sa_family == AF_INET)
|
|
|
|
{
|
|
|
|
if (ipv4eq((struct sockaddr_in *) gai->ai_addr,
|
|
|
|
(struct sockaddr_in *) &port->raddr.addr))
|
|
|
|
{
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (gai->ai_addr->sa_family == AF_INET6)
|
|
|
|
{
|
|
|
|
if (ipv6eq((struct sockaddr_in6 *) gai->ai_addr,
|
|
|
|
(struct sockaddr_in6 *) &port->raddr.addr))
|
|
|
|
{
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gai_result)
|
|
|
|
freeaddrinfo(gai_result);
|
|
|
|
|
|
|
|
if (!found)
|
|
|
|
elog(DEBUG2, "pg_hba.conf host name \"%s\" rejected because address resolution did not return a match with IP address of client",
|
|
|
|
hostname);
|
|
|
|
|
|
|
|
port->remote_hostname_resolv = found ? +1 : -1;
|
|
|
|
|
|
|
|
return found;
|
|
|
|
}
|
|
|
|
|
2009-10-01 03:58:58 +02:00
|
|
|
/*
|
|
|
|
* Check to see if a connecting IP matches the given address and netmask.
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
check_ip(SockAddr *raddr, struct sockaddr *addr, struct sockaddr *mask)
|
|
|
|
{
|
2015-02-17 18:49:18 +01:00
|
|
|
if (raddr->addr.ss_family == addr->sa_family &&
|
|
|
|
pg_range_sockaddr(&raddr->addr,
|
|
|
|
(struct sockaddr_storage *) addr,
|
|
|
|
(struct sockaddr_storage *) mask))
|
|
|
|
return true;
|
|
|
|
return false;
|
2009-10-01 03:58:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* pg_foreach_ifaddr callback: does client addr match this machine interface?
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
check_network_callback(struct sockaddr *addr, struct sockaddr *netmask,
|
|
|
|
void *cb_data)
|
|
|
|
{
|
|
|
|
check_network_data *cn = (check_network_data *) cb_data;
|
|
|
|
struct sockaddr_storage mask;
|
|
|
|
|
|
|
|
/* Already found a match? */
|
|
|
|
if (cn->result)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (cn->method == ipCmpSameHost)
|
|
|
|
{
|
|
|
|
/* Make an all-ones netmask of appropriate length for family */
|
|
|
|
pg_sockaddr_cidr_mask(&mask, NULL, addr->sa_family);
|
|
|
|
cn->result = check_ip(cn->raddr, addr, (struct sockaddr *) &mask);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Use the netmask of the interface itself */
|
|
|
|
cn->result = check_ip(cn->raddr, addr, netmask);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Use pg_foreach_ifaddr to check a samehost or samenet match
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
check_same_host_or_net(SockAddr *raddr, IPCompareMethod method)
|
|
|
|
{
|
|
|
|
check_network_data cn;
|
|
|
|
|
|
|
|
cn.method = method;
|
|
|
|
cn.raddr = raddr;
|
|
|
|
cn.result = false;
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
if (pg_foreach_ifaddr(check_network_callback, &cn) < 0)
|
|
|
|
{
|
2020-12-04 14:25:23 +01:00
|
|
|
ereport(LOG,
|
|
|
|
(errmsg("error enumerating network interfaces: %m")));
|
2009-10-01 03:58:58 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return cn.result;
|
|
|
|
}
|
|
|
|
|
2001-07-30 16:50:24 +02:00
|
|
|
|
2008-10-23 15:31:10 +02:00
|
|
|
/*
|
|
|
|
* Macros used to check and report on invalid configuration options.
|
2017-01-31 00:00:26 +01:00
|
|
|
* 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.
|
|
|
|
*
|
2008-10-23 15:31:10 +02:00
|
|
|
* 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
|
|
|
|
* method is actually the one specified. Used as a shortcut when
|
|
|
|
* the option is only valid for one authentication method.
|
|
|
|
* MANDATORY_AUTH_ARG = check if a required option is set for an authentication method,
|
|
|
|
* reporting error if it's not.
|
|
|
|
*/
|
2017-01-31 00:00:26 +01:00
|
|
|
#define INVALID_AUTH_OPTION(optname, validmethods) \
|
|
|
|
do { \
|
|
|
|
ereport(elevel, \
|
2008-10-23 15:31:10 +02:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR), \
|
2009-04-15 23:42:50 +02:00
|
|
|
/* translator: the second %s is a list of auth methods */ \
|
|
|
|
errmsg("authentication option \"%s\" is only valid for authentication methods %s", \
|
|
|
|
optname, _(validmethods)), \
|
2008-10-23 15:31:10 +02:00
|
|
|
errcontext("line %d of configuration file \"%s\"", \
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name))); \
|
2017-01-31 00:00:26 +01:00
|
|
|
*err_msg = psprintf("authentication option \"%s\" is only valid for authentication methods %s", \
|
|
|
|
optname, validmethods); \
|
2008-10-24 14:48:31 +02:00
|
|
|
return false; \
|
2017-01-31 00:00:26 +01:00
|
|
|
} while (0)
|
2008-10-23 15:31:10 +02:00
|
|
|
|
2017-01-31 00:00:26 +01:00
|
|
|
#define REQUIRE_AUTH_OPTION(methodval, optname, validmethods) \
|
|
|
|
do { \
|
2011-06-20 23:20:14 +02:00
|
|
|
if (hbaline->auth_method != methodval) \
|
2009-01-02 12:34:03 +01:00
|
|
|
INVALID_AUTH_OPTION(optname, validmethods); \
|
2017-01-31 00:00:26 +01:00
|
|
|
} while (0)
|
2008-10-23 15:31:10 +02:00
|
|
|
|
2017-01-31 00:00:26 +01:00
|
|
|
#define MANDATORY_AUTH_ARG(argvar, argname, authname) \
|
|
|
|
do { \
|
|
|
|
if (argvar == NULL) { \
|
|
|
|
ereport(elevel, \
|
2008-10-23 15:31:10 +02:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR), \
|
2009-03-25 15:12:02 +01:00
|
|
|
errmsg("authentication method \"%s\" requires argument \"%s\" to be set", \
|
2008-10-23 15:31:10 +02:00
|
|
|
authname, argname), \
|
|
|
|
errcontext("line %d of configuration file \"%s\"", \
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name))); \
|
2017-01-31 00:00:26 +01:00
|
|
|
*err_msg = psprintf("authentication method \"%s\" requires argument \"%s\" to be set", \
|
|
|
|
authname, argname); \
|
2013-04-16 04:33:24 +02:00
|
|
|
return NULL; \
|
2008-10-23 15:31:10 +02:00
|
|
|
} \
|
2017-01-31 00:00:26 +01:00
|
|
|
} while (0)
|
2008-10-23 15:31:10 +02:00
|
|
|
|
2011-06-20 23:20:14 +02:00
|
|
|
/*
|
2022-03-29 03:15:48 +02:00
|
|
|
* Macros for handling pg_ident problems, similar as above.
|
2017-01-31 00:00:26 +01:00
|
|
|
*
|
2011-06-20 23:20:14 +02:00
|
|
|
* IDENT_FIELD_ABSENT:
|
2022-03-29 03:15:48 +02:00
|
|
|
* Reports when the given ident field ListCell is not populated.
|
2011-06-20 23:20:14 +02:00
|
|
|
*
|
|
|
|
* IDENT_MULTI_VALUE:
|
2022-03-29 03:15:48 +02:00
|
|
|
* Reports when the given ident token List has more than one element.
|
2011-06-20 23:20:14 +02:00
|
|
|
*/
|
2017-01-31 00:00:26 +01:00
|
|
|
#define IDENT_FIELD_ABSENT(field) \
|
|
|
|
do { \
|
2011-06-20 23:20:14 +02:00
|
|
|
if (!field) { \
|
2022-03-29 03:15:48 +02:00
|
|
|
ereport(elevel, \
|
2011-06-20 23:20:14 +02:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR), \
|
2022-08-05 02:50:27 +02:00
|
|
|
errmsg("missing entry at end of line"), \
|
|
|
|
errcontext("line %d of configuration file \"%s\"", \
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name))); \
|
2022-09-06 03:19:44 +02:00
|
|
|
*err_msg = pstrdup("missing entry at end of line"); \
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
return NULL; \
|
2011-06-20 23:20:14 +02:00
|
|
|
} \
|
2017-01-31 00:00:26 +01:00
|
|
|
} while (0)
|
2011-06-20 23:20:14 +02:00
|
|
|
|
2017-01-31 00:00:26 +01:00
|
|
|
#define IDENT_MULTI_VALUE(tokens) \
|
|
|
|
do { \
|
2011-06-20 23:20:14 +02:00
|
|
|
if (tokens->length > 1) { \
|
2022-03-29 03:15:48 +02:00
|
|
|
ereport(elevel, \
|
2011-06-20 23:20:14 +02:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR), \
|
|
|
|
errmsg("multiple values in ident field"), \
|
|
|
|
errcontext("line %d of configuration file \"%s\"", \
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name))); \
|
2022-09-06 03:19:44 +02:00
|
|
|
*err_msg = pstrdup("multiple values in ident field"); \
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
return NULL; \
|
2011-06-20 23:20:14 +02:00
|
|
|
} \
|
2017-01-31 00:00:26 +01:00
|
|
|
} while (0)
|
2011-06-20 23:20:14 +02:00
|
|
|
|
2008-10-23 15:31:10 +02:00
|
|
|
|
2001-07-30 16:50:24 +02:00
|
|
|
/*
|
2011-06-20 23:20:14 +02:00
|
|
|
* Parse one tokenised line from the hba config file and store the result in a
|
2017-01-27 19:43:00 +01:00
|
|
|
* HbaLine structure.
|
2011-06-20 23:20:14 +02:00
|
|
|
*
|
2017-01-31 00:00:26 +01:00
|
|
|
* 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.)
|
2011-06-20 23:20:14 +02:00
|
|
|
*
|
|
|
|
* 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.
|
2001-07-30 16:50:24 +02:00
|
|
|
*/
|
Refactor code related to pg_hba_file_rules() into new file
hba.c is growing big, and more contents are planned for it. In order to
prepare for this future work, this commit moves all the code related to
the system function processing the contents of pg_hba.conf,
pg_hba_file_rules() to a new file called hbafuncs.c, which will be used
as the location for the SQL portion of the authentication file parsing.
While on it, HbaToken, the structure holding a string token lexed from a
configuration file related to authentication, is renamed to a more
generic AuthToken, as it gets used not only for pg_hba.conf, but also
for pg_ident.conf. TokenizedLine is now named TokenizedAuthLine.
The size of hba.c is reduced by ~12%.
Author: Julien Rouhaud
Reviewed-by: Aleksander Alekseev, Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-03-24 04:42:30 +01:00
|
|
|
HbaLine *
|
|
|
|
parse_hba_line(TokenizedAuthLine *tok_line, int elevel)
|
1997-03-12 22:23:16 +01:00
|
|
|
{
|
2017-01-27 19:43:00 +01:00
|
|
|
int line_num = tok_line->line_num;
|
2022-10-26 04:36:21 +02:00
|
|
|
char *file_name = tok_line->file_name;
|
2017-01-31 00:00:26 +01:00
|
|
|
char **err_msg = &tok_line->err_msg;
|
2011-06-20 23:20:14 +02:00
|
|
|
char *str;
|
2003-09-06 01:07:21 +02:00
|
|
|
struct addrinfo *gai_result;
|
2003-06-12 09:36:51 +02:00
|
|
|
struct addrinfo hints;
|
|
|
|
int ret;
|
2003-09-06 01:07:21 +02:00
|
|
|
char *cidr_slash;
|
2008-09-15 14:32:57 +02:00
|
|
|
char *unsupauth;
|
2011-06-20 23:20:14 +02:00
|
|
|
ListCell *field;
|
|
|
|
List *tokens;
|
|
|
|
ListCell *tokencell;
|
Refactor code related to pg_hba_file_rules() into new file
hba.c is growing big, and more contents are planned for it. In order to
prepare for this future work, this commit moves all the code related to
the system function processing the contents of pg_hba.conf,
pg_hba_file_rules() to a new file called hbafuncs.c, which will be used
as the location for the SQL portion of the authentication file parsing.
While on it, HbaToken, the structure holding a string token lexed from a
configuration file related to authentication, is renamed to a more
generic AuthToken, as it gets used not only for pg_hba.conf, but also
for pg_ident.conf. TokenizedLine is now named TokenizedAuthLine.
The size of hba.c is reduced by ~12%.
Author: Julien Rouhaud
Reviewed-by: Aleksander Alekseev, Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-03-24 04:42:30 +01:00
|
|
|
AuthToken *token;
|
2011-06-20 23:20:14 +02:00
|
|
|
HbaLine *parsedline;
|
2008-09-15 14:32:57 +02:00
|
|
|
|
2011-06-20 23:20:14 +02:00
|
|
|
parsedline = palloc0(sizeof(HbaLine));
|
2022-10-26 05:57:40 +02:00
|
|
|
parsedline->sourcefile = pstrdup(file_name);
|
2008-09-15 14:32:57 +02:00
|
|
|
parsedline->linenumber = line_num;
|
2017-01-27 19:43:00 +01:00
|
|
|
parsedline->rawline = pstrdup(tok_line->raw_line);
|
2008-09-15 14:32:57 +02:00
|
|
|
|
1998-01-26 02:42:53 +01:00
|
|
|
/* Check the record type. */
|
2017-01-27 19:43:00 +01:00
|
|
|
Assert(tok_line->fields != NIL);
|
|
|
|
field = list_head(tok_line->fields);
|
2011-06-20 23:20:14 +02:00
|
|
|
tokens = lfirst(field);
|
|
|
|
if (tokens->length > 1)
|
|
|
|
{
|
2017-01-31 00:00:26 +01:00
|
|
|
ereport(elevel,
|
2011-06-20 23:20:14 +02:00
|
|
|
(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\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2017-01-31 00:00:26 +01:00
|
|
|
*err_msg = "multiple values specified for connection type";
|
2011-06-20 23:20:14 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
token = linitial(tokens);
|
|
|
|
if (strcmp(token->string, "local") == 0)
|
1998-01-26 02:42:53 +01:00
|
|
|
{
|
2008-09-15 14:32:57 +02:00
|
|
|
parsedline->conntype = ctLocal;
|
1998-01-26 02:42:53 +01:00
|
|
|
}
|
2011-06-20 23:20:14 +02:00
|
|
|
else if (strcmp(token->string, "host") == 0 ||
|
|
|
|
strcmp(token->string, "hostssl") == 0 ||
|
GSSAPI encryption support
On both the frontend and backend, prepare for GSSAPI encryption
support by moving common code for error handling into a separate file.
Fix a TODO for handling multiple status messages in the process.
Eliminate the OIDs, which have not been needed for some time.
Add frontend and backend encryption support functions. Keep the
context initiation for authentication-only separate on both the
frontend and backend in order to avoid concerns about changing the
requested flags to include encryption support.
In postmaster, pull GSSAPI authorization checking into a shared
function. Also share the initiator name between the encryption and
non-encryption codepaths.
For HBA, add "hostgssenc" and "hostnogssenc" entries that behave
similarly to their SSL counterparts. "hostgssenc" requires either
"gss", "trust", or "reject" for its authentication.
Similarly, add a "gssencmode" parameter to libpq. Supported values are
"disable", "require", and "prefer". Notably, negotiation will only be
attempted if credentials can be acquired. Move credential acquisition
into its own function to support this behavior.
Add a simple pg_stat_gssapi view similar to pg_stat_ssl, for monitoring
if GSSAPI authentication was used, what principal was used, and if
encryption is being used on the connection.
Finally, add documentation for everything new, and update existing
documentation on connection security.
Thanks to Michael Paquier for the Windows fixes.
Author: Robbie Harwood, with changes to the read/write functions by me.
Reviewed in various forms and at different times by: Michael Paquier,
Andres Freund, David Steele.
Discussion: https://www.postgresql.org/message-id/flat/jlg1tgq1ktm.fsf@thriss.redhat.com
2019-04-03 21:02:33 +02:00
|
|
|
strcmp(token->string, "hostnossl") == 0 ||
|
|
|
|
strcmp(token->string, "hostgssenc") == 0 ||
|
|
|
|
strcmp(token->string, "hostnogssenc") == 0)
|
1996-10-12 09:47:12 +02:00
|
|
|
{
|
2002-12-06 05:37:05 +01:00
|
|
|
|
2011-06-20 23:20:14 +02:00
|
|
|
if (token->string[4] == 's') /* "hostssl" */
|
1999-09-27 05:13:16 +02:00
|
|
|
{
|
2017-01-03 03:37:12 +01:00
|
|
|
parsedline->conntype = ctHostSSL;
|
|
|
|
/* Log a warning if SSL support is not active */
|
2001-08-02 16:27:40 +02:00
|
|
|
#ifdef USE_SSL
|
2017-01-03 03:37:12 +01:00
|
|
|
if (!EnableSSL)
|
2017-01-31 00:00:26 +01:00
|
|
|
{
|
|
|
|
ereport(elevel,
|
2011-04-26 21:40:11 +02:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
2017-01-03 03:37:12 +01:00
|
|
|
errmsg("hostssl record cannot match because SSL is disabled"),
|
2011-04-26 21:40:11 +02:00
|
|
|
errhint("Set ssl = on in postgresql.conf."),
|
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2017-01-31 00:00:26 +01:00
|
|
|
*err_msg = "hostssl record cannot match because SSL is disabled";
|
|
|
|
}
|
1999-09-27 05:13:16 +02:00
|
|
|
#else
|
2017-01-31 00:00:26 +01:00
|
|
|
ereport(elevel,
|
2008-10-27 21:04:45 +01:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
2017-01-03 03:37:12 +01:00
|
|
|
errmsg("hostssl record cannot match because SSL is not supported by this build"),
|
2008-10-27 21:04:45 +01:00
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2017-01-31 00:00:26 +01:00
|
|
|
*err_msg = "hostssl record cannot match because SSL is not supported by this build";
|
1999-09-27 05:13:16 +02:00
|
|
|
#endif
|
2001-08-02 16:27:40 +02:00
|
|
|
}
|
GSSAPI encryption support
On both the frontend and backend, prepare for GSSAPI encryption
support by moving common code for error handling into a separate file.
Fix a TODO for handling multiple status messages in the process.
Eliminate the OIDs, which have not been needed for some time.
Add frontend and backend encryption support functions. Keep the
context initiation for authentication-only separate on both the
frontend and backend in order to avoid concerns about changing the
requested flags to include encryption support.
In postmaster, pull GSSAPI authorization checking into a shared
function. Also share the initiator name between the encryption and
non-encryption codepaths.
For HBA, add "hostgssenc" and "hostnogssenc" entries that behave
similarly to their SSL counterparts. "hostgssenc" requires either
"gss", "trust", or "reject" for its authentication.
Similarly, add a "gssencmode" parameter to libpq. Supported values are
"disable", "require", and "prefer". Notably, negotiation will only be
attempted if credentials can be acquired. Move credential acquisition
into its own function to support this behavior.
Add a simple pg_stat_gssapi view similar to pg_stat_ssl, for monitoring
if GSSAPI authentication was used, what principal was used, and if
encryption is being used on the connection.
Finally, add documentation for everything new, and update existing
documentation on connection security.
Thanks to Michael Paquier for the Windows fixes.
Author: Robbie Harwood, with changes to the read/write functions by me.
Reviewed in various forms and at different times by: Michael Paquier,
Andres Freund, David Steele.
Discussion: https://www.postgresql.org/message-id/flat/jlg1tgq1ktm.fsf@thriss.redhat.com
2019-04-03 21:02:33 +02:00
|
|
|
else if (token->string[4] == 'g') /* "hostgssenc" */
|
At long last I put together a patch to support 4 client SSL negotiation
modes (and replace the requiressl boolean). The four options were first
spelled out by Magnus Hagander <mha@sollentuna.net> on 2000-08-23 in email
to pgsql-hackers, archived here:
http://archives.postgresql.org/pgsql-hackers/2000-08/msg00639.php
My original less-flexible patch and the ensuing thread are archived at:
http://dbforums.com/t623845.html
Attached is a new patch, including documentation.
To sum up, there's a new client parameter "sslmode" and environment
variable "PGSSLMODE", with these options:
sslmode description
------- -----------
disable Unencrypted non-SSL only
allow Negotiate, prefer non-SSL
prefer Negotiate, prefer SSL (default)
require Require SSL
The only change to the server is a new pg_hba.conf line type,
"hostnossl", for specifying connections that are not allowed to use SSL
(for example, to prevent servers on a local network from accidentally
using SSL and wasting cycles). Thus the 3 pg_hba.conf line types are:
pg_hba.conf line types
----------------------
host applies to either SSL or regular connections
hostssl applies only to SSL connections
hostnossl applies only to regular connections
These client and server options, the postgresql.conf ssl = false option,
and finally the possibility of compiling with no SSL support at all,
make quite a range of combinations to test. I threw together a test
script to try many of them out. It's in a separate tarball with its
config files, a patch to psql so it'll announce SSL connections even in
absence of a tty, and the test output. The test is especially informative
when run on the same tty the postmaster was started on, so the FATAL:
errors during negotiation are interleaved with the psql client output.
I saw Tom write that new submissions for 7.4 have to be in before midnight
local time, and since I'm on the east coast in the US, this just makes it
in before the bell. :)
Jon Jensen
2003-07-26 15:50:02 +02:00
|
|
|
{
|
GSSAPI encryption support
On both the frontend and backend, prepare for GSSAPI encryption
support by moving common code for error handling into a separate file.
Fix a TODO for handling multiple status messages in the process.
Eliminate the OIDs, which have not been needed for some time.
Add frontend and backend encryption support functions. Keep the
context initiation for authentication-only separate on both the
frontend and backend in order to avoid concerns about changing the
requested flags to include encryption support.
In postmaster, pull GSSAPI authorization checking into a shared
function. Also share the initiator name between the encryption and
non-encryption codepaths.
For HBA, add "hostgssenc" and "hostnogssenc" entries that behave
similarly to their SSL counterparts. "hostgssenc" requires either
"gss", "trust", or "reject" for its authentication.
Similarly, add a "gssencmode" parameter to libpq. Supported values are
"disable", "require", and "prefer". Notably, negotiation will only be
attempted if credentials can be acquired. Move credential acquisition
into its own function to support this behavior.
Add a simple pg_stat_gssapi view similar to pg_stat_ssl, for monitoring
if GSSAPI authentication was used, what principal was used, and if
encryption is being used on the connection.
Finally, add documentation for everything new, and update existing
documentation on connection security.
Thanks to Michael Paquier for the Windows fixes.
Author: Robbie Harwood, with changes to the read/write functions by me.
Reviewed in various forms and at different times by: Michael Paquier,
Andres Freund, David Steele.
Discussion: https://www.postgresql.org/message-id/flat/jlg1tgq1ktm.fsf@thriss.redhat.com
2019-04-03 21:02:33 +02:00
|
|
|
parsedline->conntype = ctHostGSS;
|
|
|
|
#ifndef ENABLE_GSS
|
|
|
|
ereport(elevel,
|
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
|
|
|
errmsg("hostgssenc record cannot match because GSSAPI is not supported by this build"),
|
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
GSSAPI encryption support
On both the frontend and backend, prepare for GSSAPI encryption
support by moving common code for error handling into a separate file.
Fix a TODO for handling multiple status messages in the process.
Eliminate the OIDs, which have not been needed for some time.
Add frontend and backend encryption support functions. Keep the
context initiation for authentication-only separate on both the
frontend and backend in order to avoid concerns about changing the
requested flags to include encryption support.
In postmaster, pull GSSAPI authorization checking into a shared
function. Also share the initiator name between the encryption and
non-encryption codepaths.
For HBA, add "hostgssenc" and "hostnogssenc" entries that behave
similarly to their SSL counterparts. "hostgssenc" requires either
"gss", "trust", or "reject" for its authentication.
Similarly, add a "gssencmode" parameter to libpq. Supported values are
"disable", "require", and "prefer". Notably, negotiation will only be
attempted if credentials can be acquired. Move credential acquisition
into its own function to support this behavior.
Add a simple pg_stat_gssapi view similar to pg_stat_ssl, for monitoring
if GSSAPI authentication was used, what principal was used, and if
encryption is being used on the connection.
Finally, add documentation for everything new, and update existing
documentation on connection security.
Thanks to Michael Paquier for the Windows fixes.
Author: Robbie Harwood, with changes to the read/write functions by me.
Reviewed in various forms and at different times by: Michael Paquier,
Andres Freund, David Steele.
Discussion: https://www.postgresql.org/message-id/flat/jlg1tgq1ktm.fsf@thriss.redhat.com
2019-04-03 21:02:33 +02:00
|
|
|
*err_msg = "hostgssenc record cannot match because GSSAPI is not supported by this build";
|
|
|
|
#endif
|
At long last I put together a patch to support 4 client SSL negotiation
modes (and replace the requiressl boolean). The four options were first
spelled out by Magnus Hagander <mha@sollentuna.net> on 2000-08-23 in email
to pgsql-hackers, archived here:
http://archives.postgresql.org/pgsql-hackers/2000-08/msg00639.php
My original less-flexible patch and the ensuing thread are archived at:
http://dbforums.com/t623845.html
Attached is a new patch, including documentation.
To sum up, there's a new client parameter "sslmode" and environment
variable "PGSSLMODE", with these options:
sslmode description
------- -----------
disable Unencrypted non-SSL only
allow Negotiate, prefer non-SSL
prefer Negotiate, prefer SSL (default)
require Require SSL
The only change to the server is a new pg_hba.conf line type,
"hostnossl", for specifying connections that are not allowed to use SSL
(for example, to prevent servers on a local network from accidentally
using SSL and wasting cycles). Thus the 3 pg_hba.conf line types are:
pg_hba.conf line types
----------------------
host applies to either SSL or regular connections
hostssl applies only to SSL connections
hostnossl applies only to regular connections
These client and server options, the postgresql.conf ssl = false option,
and finally the possibility of compiling with no SSL support at all,
make quite a range of combinations to test. I threw together a test
script to try many of them out. It's in a separate tarball with its
config files, a patch to psql so it'll announce SSL connections even in
absence of a tty, and the test output. The test is especially informative
when run on the same tty the postmaster was started on, so the FATAL:
errors during negotiation are interleaved with the psql client output.
I saw Tom write that new submissions for 7.4 have to be in before midnight
local time, and since I'm on the east coast in the US, this just makes it
in before the bell. :)
Jon Jensen
2003-07-26 15:50:02 +02:00
|
|
|
}
|
GSSAPI encryption support
On both the frontend and backend, prepare for GSSAPI encryption
support by moving common code for error handling into a separate file.
Fix a TODO for handling multiple status messages in the process.
Eliminate the OIDs, which have not been needed for some time.
Add frontend and backend encryption support functions. Keep the
context initiation for authentication-only separate on both the
frontend and backend in order to avoid concerns about changing the
requested flags to include encryption support.
In postmaster, pull GSSAPI authorization checking into a shared
function. Also share the initiator name between the encryption and
non-encryption codepaths.
For HBA, add "hostgssenc" and "hostnogssenc" entries that behave
similarly to their SSL counterparts. "hostgssenc" requires either
"gss", "trust", or "reject" for its authentication.
Similarly, add a "gssencmode" parameter to libpq. Supported values are
"disable", "require", and "prefer". Notably, negotiation will only be
attempted if credentials can be acquired. Move credential acquisition
into its own function to support this behavior.
Add a simple pg_stat_gssapi view similar to pg_stat_ssl, for monitoring
if GSSAPI authentication was used, what principal was used, and if
encryption is being used on the connection.
Finally, add documentation for everything new, and update existing
documentation on connection security.
Thanks to Michael Paquier for the Windows fixes.
Author: Robbie Harwood, with changes to the read/write functions by me.
Reviewed in various forms and at different times by: Michael Paquier,
Andres Freund, David Steele.
Discussion: https://www.postgresql.org/message-id/flat/jlg1tgq1ktm.fsf@thriss.redhat.com
2019-04-03 21:02:33 +02:00
|
|
|
else if (token->string[4] == 'n' && token->string[6] == 's')
|
|
|
|
parsedline->conntype = ctHostNoSSL;
|
|
|
|
else if (token->string[4] == 'n' && token->string[6] == 'g')
|
|
|
|
parsedline->conntype = ctHostNoGSS;
|
2008-09-15 14:32:57 +02:00
|
|
|
else
|
|
|
|
{
|
2014-11-25 08:39:31 +01:00
|
|
|
/* "host" */
|
2008-09-15 14:32:57 +02:00
|
|
|
parsedline->conntype = ctHost;
|
|
|
|
}
|
|
|
|
} /* record type */
|
|
|
|
else
|
2008-10-27 21:04:45 +01:00
|
|
|
{
|
2017-01-31 00:00:26 +01:00
|
|
|
ereport(elevel,
|
2008-10-27 21:04:45 +01:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
|
|
|
errmsg("invalid connection type \"%s\"",
|
2011-06-20 23:20:14 +02:00
|
|
|
token->string),
|
2008-10-27 21:04:45 +01:00
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2017-01-31 00:00:26 +01:00
|
|
|
*err_msg = psprintf("invalid connection type \"%s\"", token->string);
|
2011-06-20 23:20:14 +02:00
|
|
|
return NULL;
|
2008-10-27 21:04:45 +01:00
|
|
|
}
|
1998-01-26 02:42:53 +01:00
|
|
|
|
2011-06-20 23:20:14 +02:00
|
|
|
/* Get the databases. */
|
Represent Lists as expansible arrays, not chains of cons-cells.
Originally, Postgres Lists were a more or less exact reimplementation of
Lisp lists, which consist of chains of separately-allocated cons cells,
each having a value and a next-cell link. We'd hacked that once before
(commit d0b4399d8) to add a separate List header, but the data was still
in cons cells. That makes some operations -- notably list_nth() -- O(N),
and it's bulky because of the next-cell pointers and per-cell palloc
overhead, and it's very cache-unfriendly if the cons cells end up
scattered around rather than being adjacent.
In this rewrite, we still have List headers, but the data is in a
resizable array of values, with no next-cell links. Now we need at
most two palloc's per List, and often only one, since we can allocate
some values in the same palloc call as the List header. (Of course,
extending an existing List may require repalloc's to enlarge the array.
But this involves just O(log N) allocations not O(N).)
Of course this is not without downsides. The key difficulty is that
addition or deletion of a list entry may now cause other entries to
move, which it did not before.
For example, that breaks foreach() and sister macros, which historically
used a pointer to the current cons-cell as loop state. We can repair
those macros transparently by making their actual loop state be an
integer list index; the exposed "ListCell *" pointer is no longer state
carried across loop iterations, but is just a derived value. (In
practice, modern compilers can optimize things back to having just one
loop state value, at least for simple cases with inline loop bodies.)
In principle, this is a semantics change for cases where the loop body
inserts or deletes list entries ahead of the current loop index; but
I found no such cases in the Postgres code.
The change is not at all transparent for code that doesn't use foreach()
but chases lists "by hand" using lnext(). The largest share of such
code in the backend is in loops that were maintaining "prev" and "next"
variables in addition to the current-cell pointer, in order to delete
list cells efficiently using list_delete_cell(). However, we no longer
need a previous-cell pointer to delete a list cell efficiently. Keeping
a next-cell pointer doesn't work, as explained above, but we can improve
matters by changing such code to use a regular foreach() loop and then
using the new macro foreach_delete_current() to delete the current cell.
(This macro knows how to update the associated foreach loop's state so
that no cells will be missed in the traversal.)
There remains a nontrivial risk of code assuming that a ListCell *
pointer will remain good over an operation that could now move the list
contents. To help catch such errors, list.c can be compiled with a new
define symbol DEBUG_LIST_MEMORY_USAGE that forcibly moves list contents
whenever that could possibly happen. This makes list operations
significantly more expensive so it's not normally turned on (though it
is on by default if USE_VALGRIND is on).
There are two notable API differences from the previous code:
* lnext() now requires the List's header pointer in addition to the
current cell's address.
* list_delete_cell() no longer requires a previous-cell argument.
These changes are somewhat unfortunate, but on the other hand code using
either function needs inspection to see if it is assuming anything
it shouldn't, so it's not all bad.
Programmers should be aware of these significant performance changes:
* list_nth() and related functions are now O(1); so there's no
major access-speed difference between a list and an array.
* Inserting or deleting a list element now takes time proportional to
the distance to the end of the list, due to moving the array elements.
(However, it typically *doesn't* require palloc or pfree, so except in
long lists it's probably still faster than before.) Notably, lcons()
used to be about the same cost as lappend(), but that's no longer true
if the list is long. Code that uses lcons() and list_delete_first()
to maintain a stack might usefully be rewritten to push and pop at the
end of the list rather than the beginning.
* There are now list_insert_nth...() and list_delete_nth...() functions
that add or remove a list cell identified by index. These have the
data-movement penalty explained above, but there's no search penalty.
* list_concat() and variants now copy the second list's data into
storage belonging to the first list, so there is no longer any
sharing of cells between the input lists. The second argument is
now declared "const List *" to reflect that it isn't changed.
This patch just does the minimum needed to get the new implementation
in place and fix bugs exposed by the regression tests. As suggested
by the foregoing, there's a fair amount of followup work remaining to
do.
Also, the ENABLE_LIST_COMPAT macros are finally removed in this
commit. Code using those should have been gone a dozen years ago.
Patch by me; thanks to David Rowley, Jesper Pedersen, and others
for review.
Discussion: https://postgr.es/m/11587.1550975080@sss.pgh.pa.us
2019-07-15 19:41:58 +02:00
|
|
|
field = lnext(tok_line->fields, field);
|
2011-06-20 23:20:14 +02:00
|
|
|
if (!field)
|
2008-10-27 21:04:45 +01:00
|
|
|
{
|
2017-01-31 00:00:26 +01:00
|
|
|
ereport(elevel,
|
2008-10-27 21:04:45 +01:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
|
|
|
errmsg("end-of-line before database specification"),
|
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2017-01-31 00:00:26 +01:00
|
|
|
*err_msg = "end-of-line before database specification";
|
2011-06-20 23:20:14 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
parsedline->databases = NIL;
|
|
|
|
tokens = lfirst(field);
|
|
|
|
foreach(tokencell, tokens)
|
|
|
|
{
|
Add support for regexps on database and user entries in pg_hba.conf
As of this commit, any database or user entry beginning with a slash (/)
is considered as a regular expression. This is particularly useful for
users, as now there is no clean way to match pattern on multiple HBA
lines. For example, a user name mapping with a regular expression needs
first to match with a HBA line, and we would skip the follow-up HBA
entries if the ident regexp does *not* match with what has matched in
the HBA line.
pg_hba.conf is able to handle multiple databases and roles with a
comma-separated list of these, hence individual regular expressions that
include commas need to be double-quoted.
At authentication time, user and database names are now checked in the
following order:
- Arbitrary keywords (like "all", the ones beginning by '+' for
membership check), that we know will never have a regexp. A fancy case
is for physical WAL senders, we *have* to only match "replication" for
the database.
- Regular expression matching.
- Exact match.
The previous logic did the same, but without the regexp step.
We have discussed as well the possibility to support regexp pattern
matching for host names, but these happen to lead to tricky issues based
on what I understand, particularly with host entries that have CIDRs.
This commit relies heavily on the refactoring done in a903971 and
fc579e1, so as the amount of code required to compile and execute
regular expressions is now minimal. When parsing pg_hba.conf, all the
computed regexps needs to explicitely free()'d, same as pg_ident.conf.
Documentation and TAP tests are added to cover this feature, including
cases where the regexps use commas (for clarity in the docs, coverage
for the parsing logic in the tests).
Note that this introduces a breakage with older versions, where a
database or user name beginning with a slash are treated as something to
check for an equal match. Per discussion, we have discarded this as
being much of an issue in practice as it would require a cluster to
have database and/or role names that begin with a slash, as well as HBA
entries using these. Hence, the consistency gained with regexps in
pg_ident.conf is more appealing in the long term.
**This compatibility change should be mentioned in the release notes.**
Author: Bertrand Drouvot
Reviewed-by: Jacob Champion, Tom Lane, Michael Paquier
Discussion: https://postgr.es/m/fff0d7c1-8ad4-76a1-9db3-0ab6ec338bf7@amazon.com
2022-10-24 04:45:31 +02:00
|
|
|
AuthToken *tok = copy_auth_token(lfirst(tokencell));
|
|
|
|
|
|
|
|
/* Compile a regexp for the database token, if necessary */
|
2022-10-26 04:36:21 +02:00
|
|
|
if (regcomp_auth_token(tok, file_name, line_num, err_msg, elevel))
|
Add support for regexps on database and user entries in pg_hba.conf
As of this commit, any database or user entry beginning with a slash (/)
is considered as a regular expression. This is particularly useful for
users, as now there is no clean way to match pattern on multiple HBA
lines. For example, a user name mapping with a regular expression needs
first to match with a HBA line, and we would skip the follow-up HBA
entries if the ident regexp does *not* match with what has matched in
the HBA line.
pg_hba.conf is able to handle multiple databases and roles with a
comma-separated list of these, hence individual regular expressions that
include commas need to be double-quoted.
At authentication time, user and database names are now checked in the
following order:
- Arbitrary keywords (like "all", the ones beginning by '+' for
membership check), that we know will never have a regexp. A fancy case
is for physical WAL senders, we *have* to only match "replication" for
the database.
- Regular expression matching.
- Exact match.
The previous logic did the same, but without the regexp step.
We have discussed as well the possibility to support regexp pattern
matching for host names, but these happen to lead to tricky issues based
on what I understand, particularly with host entries that have CIDRs.
This commit relies heavily on the refactoring done in a903971 and
fc579e1, so as the amount of code required to compile and execute
regular expressions is now minimal. When parsing pg_hba.conf, all the
computed regexps needs to explicitely free()'d, same as pg_ident.conf.
Documentation and TAP tests are added to cover this feature, including
cases where the regexps use commas (for clarity in the docs, coverage
for the parsing logic in the tests).
Note that this introduces a breakage with older versions, where a
database or user name beginning with a slash are treated as something to
check for an equal match. Per discussion, we have discarded this as
being much of an issue in practice as it would require a cluster to
have database and/or role names that begin with a slash, as well as HBA
entries using these. Hence, the consistency gained with regexps in
pg_ident.conf is more appealing in the long term.
**This compatibility change should be mentioned in the release notes.**
Author: Bertrand Drouvot
Reviewed-by: Jacob Champion, Tom Lane, Michael Paquier
Discussion: https://postgr.es/m/fff0d7c1-8ad4-76a1-9db3-0ab6ec338bf7@amazon.com
2022-10-24 04:45:31 +02:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
parsedline->databases = lappend(parsedline->databases, tok);
|
2008-10-27 21:04:45 +01:00
|
|
|
}
|
1998-01-26 02:42:53 +01:00
|
|
|
|
2011-06-20 23:20:14 +02:00
|
|
|
/* Get the roles. */
|
Represent Lists as expansible arrays, not chains of cons-cells.
Originally, Postgres Lists were a more or less exact reimplementation of
Lisp lists, which consist of chains of separately-allocated cons cells,
each having a value and a next-cell link. We'd hacked that once before
(commit d0b4399d8) to add a separate List header, but the data was still
in cons cells. That makes some operations -- notably list_nth() -- O(N),
and it's bulky because of the next-cell pointers and per-cell palloc
overhead, and it's very cache-unfriendly if the cons cells end up
scattered around rather than being adjacent.
In this rewrite, we still have List headers, but the data is in a
resizable array of values, with no next-cell links. Now we need at
most two palloc's per List, and often only one, since we can allocate
some values in the same palloc call as the List header. (Of course,
extending an existing List may require repalloc's to enlarge the array.
But this involves just O(log N) allocations not O(N).)
Of course this is not without downsides. The key difficulty is that
addition or deletion of a list entry may now cause other entries to
move, which it did not before.
For example, that breaks foreach() and sister macros, which historically
used a pointer to the current cons-cell as loop state. We can repair
those macros transparently by making their actual loop state be an
integer list index; the exposed "ListCell *" pointer is no longer state
carried across loop iterations, but is just a derived value. (In
practice, modern compilers can optimize things back to having just one
loop state value, at least for simple cases with inline loop bodies.)
In principle, this is a semantics change for cases where the loop body
inserts or deletes list entries ahead of the current loop index; but
I found no such cases in the Postgres code.
The change is not at all transparent for code that doesn't use foreach()
but chases lists "by hand" using lnext(). The largest share of such
code in the backend is in loops that were maintaining "prev" and "next"
variables in addition to the current-cell pointer, in order to delete
list cells efficiently using list_delete_cell(). However, we no longer
need a previous-cell pointer to delete a list cell efficiently. Keeping
a next-cell pointer doesn't work, as explained above, but we can improve
matters by changing such code to use a regular foreach() loop and then
using the new macro foreach_delete_current() to delete the current cell.
(This macro knows how to update the associated foreach loop's state so
that no cells will be missed in the traversal.)
There remains a nontrivial risk of code assuming that a ListCell *
pointer will remain good over an operation that could now move the list
contents. To help catch such errors, list.c can be compiled with a new
define symbol DEBUG_LIST_MEMORY_USAGE that forcibly moves list contents
whenever that could possibly happen. This makes list operations
significantly more expensive so it's not normally turned on (though it
is on by default if USE_VALGRIND is on).
There are two notable API differences from the previous code:
* lnext() now requires the List's header pointer in addition to the
current cell's address.
* list_delete_cell() no longer requires a previous-cell argument.
These changes are somewhat unfortunate, but on the other hand code using
either function needs inspection to see if it is assuming anything
it shouldn't, so it's not all bad.
Programmers should be aware of these significant performance changes:
* list_nth() and related functions are now O(1); so there's no
major access-speed difference between a list and an array.
* Inserting or deleting a list element now takes time proportional to
the distance to the end of the list, due to moving the array elements.
(However, it typically *doesn't* require palloc or pfree, so except in
long lists it's probably still faster than before.) Notably, lcons()
used to be about the same cost as lappend(), but that's no longer true
if the list is long. Code that uses lcons() and list_delete_first()
to maintain a stack might usefully be rewritten to push and pop at the
end of the list rather than the beginning.
* There are now list_insert_nth...() and list_delete_nth...() functions
that add or remove a list cell identified by index. These have the
data-movement penalty explained above, but there's no search penalty.
* list_concat() and variants now copy the second list's data into
storage belonging to the first list, so there is no longer any
sharing of cells between the input lists. The second argument is
now declared "const List *" to reflect that it isn't changed.
This patch just does the minimum needed to get the new implementation
in place and fix bugs exposed by the regression tests. As suggested
by the foregoing, there's a fair amount of followup work remaining to
do.
Also, the ENABLE_LIST_COMPAT macros are finally removed in this
commit. Code using those should have been gone a dozen years ago.
Patch by me; thanks to David Rowley, Jesper Pedersen, and others
for review.
Discussion: https://postgr.es/m/11587.1550975080@sss.pgh.pa.us
2019-07-15 19:41:58 +02:00
|
|
|
field = lnext(tok_line->fields, field);
|
2011-06-20 23:20:14 +02:00
|
|
|
if (!field)
|
2008-10-27 21:04:45 +01:00
|
|
|
{
|
2017-01-31 00:00:26 +01:00
|
|
|
ereport(elevel,
|
2008-10-27 21:04:45 +01:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
|
|
|
errmsg("end-of-line before role specification"),
|
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2017-01-31 00:00:26 +01:00
|
|
|
*err_msg = "end-of-line before role specification";
|
2011-06-20 23:20:14 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
parsedline->roles = NIL;
|
|
|
|
tokens = lfirst(field);
|
|
|
|
foreach(tokencell, tokens)
|
|
|
|
{
|
Add support for regexps on database and user entries in pg_hba.conf
As of this commit, any database or user entry beginning with a slash (/)
is considered as a regular expression. This is particularly useful for
users, as now there is no clean way to match pattern on multiple HBA
lines. For example, a user name mapping with a regular expression needs
first to match with a HBA line, and we would skip the follow-up HBA
entries if the ident regexp does *not* match with what has matched in
the HBA line.
pg_hba.conf is able to handle multiple databases and roles with a
comma-separated list of these, hence individual regular expressions that
include commas need to be double-quoted.
At authentication time, user and database names are now checked in the
following order:
- Arbitrary keywords (like "all", the ones beginning by '+' for
membership check), that we know will never have a regexp. A fancy case
is for physical WAL senders, we *have* to only match "replication" for
the database.
- Regular expression matching.
- Exact match.
The previous logic did the same, but without the regexp step.
We have discussed as well the possibility to support regexp pattern
matching for host names, but these happen to lead to tricky issues based
on what I understand, particularly with host entries that have CIDRs.
This commit relies heavily on the refactoring done in a903971 and
fc579e1, so as the amount of code required to compile and execute
regular expressions is now minimal. When parsing pg_hba.conf, all the
computed regexps needs to explicitely free()'d, same as pg_ident.conf.
Documentation and TAP tests are added to cover this feature, including
cases where the regexps use commas (for clarity in the docs, coverage
for the parsing logic in the tests).
Note that this introduces a breakage with older versions, where a
database or user name beginning with a slash are treated as something to
check for an equal match. Per discussion, we have discarded this as
being much of an issue in practice as it would require a cluster to
have database and/or role names that begin with a slash, as well as HBA
entries using these. Hence, the consistency gained with regexps in
pg_ident.conf is more appealing in the long term.
**This compatibility change should be mentioned in the release notes.**
Author: Bertrand Drouvot
Reviewed-by: Jacob Champion, Tom Lane, Michael Paquier
Discussion: https://postgr.es/m/fff0d7c1-8ad4-76a1-9db3-0ab6ec338bf7@amazon.com
2022-10-24 04:45:31 +02:00
|
|
|
AuthToken *tok = copy_auth_token(lfirst(tokencell));
|
|
|
|
|
|
|
|
/* Compile a regexp from the role token, if necessary */
|
2022-10-26 04:36:21 +02:00
|
|
|
if (regcomp_auth_token(tok, file_name, line_num, err_msg, elevel))
|
Add support for regexps on database and user entries in pg_hba.conf
As of this commit, any database or user entry beginning with a slash (/)
is considered as a regular expression. This is particularly useful for
users, as now there is no clean way to match pattern on multiple HBA
lines. For example, a user name mapping with a regular expression needs
first to match with a HBA line, and we would skip the follow-up HBA
entries if the ident regexp does *not* match with what has matched in
the HBA line.
pg_hba.conf is able to handle multiple databases and roles with a
comma-separated list of these, hence individual regular expressions that
include commas need to be double-quoted.
At authentication time, user and database names are now checked in the
following order:
- Arbitrary keywords (like "all", the ones beginning by '+' for
membership check), that we know will never have a regexp. A fancy case
is for physical WAL senders, we *have* to only match "replication" for
the database.
- Regular expression matching.
- Exact match.
The previous logic did the same, but without the regexp step.
We have discussed as well the possibility to support regexp pattern
matching for host names, but these happen to lead to tricky issues based
on what I understand, particularly with host entries that have CIDRs.
This commit relies heavily on the refactoring done in a903971 and
fc579e1, so as the amount of code required to compile and execute
regular expressions is now minimal. When parsing pg_hba.conf, all the
computed regexps needs to explicitely free()'d, same as pg_ident.conf.
Documentation and TAP tests are added to cover this feature, including
cases where the regexps use commas (for clarity in the docs, coverage
for the parsing logic in the tests).
Note that this introduces a breakage with older versions, where a
database or user name beginning with a slash are treated as something to
check for an equal match. Per discussion, we have discarded this as
being much of an issue in practice as it would require a cluster to
have database and/or role names that begin with a slash, as well as HBA
entries using these. Hence, the consistency gained with regexps in
pg_ident.conf is more appealing in the long term.
**This compatibility change should be mentioned in the release notes.**
Author: Bertrand Drouvot
Reviewed-by: Jacob Champion, Tom Lane, Michael Paquier
Discussion: https://postgr.es/m/fff0d7c1-8ad4-76a1-9db3-0ab6ec338bf7@amazon.com
2022-10-24 04:45:31 +02:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
parsedline->roles = lappend(parsedline->roles, tok);
|
2008-10-27 21:04:45 +01:00
|
|
|
}
|
2002-04-04 06:25:54 +02:00
|
|
|
|
2008-09-15 14:32:57 +02:00
|
|
|
if (parsedline->conntype != ctLocal)
|
|
|
|
{
|
2003-06-12 09:36:51 +02:00
|
|
|
/* Read the IP address field. (with or without CIDR netmask) */
|
Represent Lists as expansible arrays, not chains of cons-cells.
Originally, Postgres Lists were a more or less exact reimplementation of
Lisp lists, which consist of chains of separately-allocated cons cells,
each having a value and a next-cell link. We'd hacked that once before
(commit d0b4399d8) to add a separate List header, but the data was still
in cons cells. That makes some operations -- notably list_nth() -- O(N),
and it's bulky because of the next-cell pointers and per-cell palloc
overhead, and it's very cache-unfriendly if the cons cells end up
scattered around rather than being adjacent.
In this rewrite, we still have List headers, but the data is in a
resizable array of values, with no next-cell links. Now we need at
most two palloc's per List, and often only one, since we can allocate
some values in the same palloc call as the List header. (Of course,
extending an existing List may require repalloc's to enlarge the array.
But this involves just O(log N) allocations not O(N).)
Of course this is not without downsides. The key difficulty is that
addition or deletion of a list entry may now cause other entries to
move, which it did not before.
For example, that breaks foreach() and sister macros, which historically
used a pointer to the current cons-cell as loop state. We can repair
those macros transparently by making their actual loop state be an
integer list index; the exposed "ListCell *" pointer is no longer state
carried across loop iterations, but is just a derived value. (In
practice, modern compilers can optimize things back to having just one
loop state value, at least for simple cases with inline loop bodies.)
In principle, this is a semantics change for cases where the loop body
inserts or deletes list entries ahead of the current loop index; but
I found no such cases in the Postgres code.
The change is not at all transparent for code that doesn't use foreach()
but chases lists "by hand" using lnext(). The largest share of such
code in the backend is in loops that were maintaining "prev" and "next"
variables in addition to the current-cell pointer, in order to delete
list cells efficiently using list_delete_cell(). However, we no longer
need a previous-cell pointer to delete a list cell efficiently. Keeping
a next-cell pointer doesn't work, as explained above, but we can improve
matters by changing such code to use a regular foreach() loop and then
using the new macro foreach_delete_current() to delete the current cell.
(This macro knows how to update the associated foreach loop's state so
that no cells will be missed in the traversal.)
There remains a nontrivial risk of code assuming that a ListCell *
pointer will remain good over an operation that could now move the list
contents. To help catch such errors, list.c can be compiled with a new
define symbol DEBUG_LIST_MEMORY_USAGE that forcibly moves list contents
whenever that could possibly happen. This makes list operations
significantly more expensive so it's not normally turned on (though it
is on by default if USE_VALGRIND is on).
There are two notable API differences from the previous code:
* lnext() now requires the List's header pointer in addition to the
current cell's address.
* list_delete_cell() no longer requires a previous-cell argument.
These changes are somewhat unfortunate, but on the other hand code using
either function needs inspection to see if it is assuming anything
it shouldn't, so it's not all bad.
Programmers should be aware of these significant performance changes:
* list_nth() and related functions are now O(1); so there's no
major access-speed difference between a list and an array.
* Inserting or deleting a list element now takes time proportional to
the distance to the end of the list, due to moving the array elements.
(However, it typically *doesn't* require palloc or pfree, so except in
long lists it's probably still faster than before.) Notably, lcons()
used to be about the same cost as lappend(), but that's no longer true
if the list is long. Code that uses lcons() and list_delete_first()
to maintain a stack might usefully be rewritten to push and pop at the
end of the list rather than the beginning.
* There are now list_insert_nth...() and list_delete_nth...() functions
that add or remove a list cell identified by index. These have the
data-movement penalty explained above, but there's no search penalty.
* list_concat() and variants now copy the second list's data into
storage belonging to the first list, so there is no longer any
sharing of cells between the input lists. The second argument is
now declared "const List *" to reflect that it isn't changed.
This patch just does the minimum needed to get the new implementation
in place and fix bugs exposed by the regression tests. As suggested
by the foregoing, there's a fair amount of followup work remaining to
do.
Also, the ENABLE_LIST_COMPAT macros are finally removed in this
commit. Code using those should have been gone a dozen years ago.
Patch by me; thanks to David Rowley, Jesper Pedersen, and others
for review.
Discussion: https://postgr.es/m/11587.1550975080@sss.pgh.pa.us
2019-07-15 19:41:58 +02:00
|
|
|
field = lnext(tok_line->fields, field);
|
2011-06-20 23:20:14 +02:00
|
|
|
if (!field)
|
2008-10-27 21:04:45 +01:00
|
|
|
{
|
2017-01-31 00:00:26 +01:00
|
|
|
ereport(elevel,
|
2008-10-27 21:04:45 +01:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
2009-06-21 22:15:32 +02:00
|
|
|
errmsg("end-of-line before IP address specification"),
|
2008-10-27 21:04:45 +01:00
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2017-01-31 00:00:26 +01:00
|
|
|
*err_msg = "end-of-line before IP address specification";
|
2011-06-20 23:20:14 +02:00
|
|
|
return NULL;
|
2008-10-27 21:04:45 +01:00
|
|
|
}
|
2011-06-20 23:20:14 +02:00
|
|
|
tokens = lfirst(field);
|
|
|
|
if (tokens->length > 1)
|
|
|
|
{
|
2017-01-31 00:00:26 +01:00
|
|
|
ereport(elevel,
|
2011-06-20 23:20:14 +02:00
|
|
|
(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\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2017-01-31 00:00:26 +01:00
|
|
|
*err_msg = "multiple values specified for host address";
|
2011-06-20 23:20:14 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
token = linitial(tokens);
|
2009-10-01 03:58:58 +02:00
|
|
|
|
2011-06-20 23:20:14 +02:00
|
|
|
if (token_is_keyword(token, "all"))
|
2010-10-18 21:14:47 +02:00
|
|
|
{
|
|
|
|
parsedline->ip_cmp_method = ipCmpAll;
|
|
|
|
}
|
2011-06-20 23:20:14 +02:00
|
|
|
else if (token_is_keyword(token, "samehost"))
|
2003-06-12 09:36:51 +02:00
|
|
|
{
|
2009-10-01 03:58:58 +02:00
|
|
|
/* Any IP on this host is allowed to connect */
|
|
|
|
parsedline->ip_cmp_method = ipCmpSameHost;
|
2003-06-12 09:36:51 +02:00
|
|
|
}
|
2011-06-20 23:20:14 +02:00
|
|
|
else if (token_is_keyword(token, "samenet"))
|
2003-06-12 09:36:51 +02:00
|
|
|
{
|
2009-10-01 03:58:58 +02:00
|
|
|
/* Any IP on the host's subnets is allowed to connect */
|
|
|
|
parsedline->ip_cmp_method = ipCmpSameNet;
|
2003-06-12 09:36:51 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-10-01 03:58:58 +02:00
|
|
|
/* IP and netmask are specified */
|
|
|
|
parsedline->ip_cmp_method = ipCmpMask;
|
|
|
|
|
|
|
|
/* need a modifiable copy of token */
|
2011-06-20 23:20:14 +02:00
|
|
|
str = pstrdup(token->string);
|
2009-10-01 03:58:58 +02:00
|
|
|
|
|
|
|
/* Check if it has a CIDR suffix and if so isolate it */
|
2011-06-20 23:20:14 +02:00
|
|
|
cidr_slash = strchr(str, '/');
|
2009-10-01 03:58:58 +02:00
|
|
|
if (cidr_slash)
|
|
|
|
*cidr_slash = '\0';
|
|
|
|
|
|
|
|
/* Get the IP address either way */
|
|
|
|
hints.ai_flags = AI_NUMERICHOST;
|
2014-04-16 19:20:54 +02:00
|
|
|
hints.ai_family = AF_UNSPEC;
|
2009-10-01 03:58:58 +02:00
|
|
|
hints.ai_socktype = 0;
|
|
|
|
hints.ai_protocol = 0;
|
|
|
|
hints.ai_addrlen = 0;
|
|
|
|
hints.ai_canonname = NULL;
|
|
|
|
hints.ai_addr = NULL;
|
|
|
|
hints.ai_next = NULL;
|
2003-06-12 09:36:51 +02:00
|
|
|
|
2011-06-20 23:20:14 +02:00
|
|
|
ret = pg_getaddrinfo_all(str, NULL, &hints, &gai_result);
|
2010-10-15 21:53:39 +02:00
|
|
|
if (ret == 0 && gai_result)
|
2020-11-03 03:11:50 +01:00
|
|
|
{
|
2010-10-15 21:53:39 +02:00
|
|
|
memcpy(&parsedline->addr, gai_result->ai_addr,
|
|
|
|
gai_result->ai_addrlen);
|
2020-11-03 03:11:50 +01:00
|
|
|
parsedline->addrlen = gai_result->ai_addrlen;
|
|
|
|
}
|
2010-10-15 21:53:39 +02:00
|
|
|
else if (ret == EAI_NONAME)
|
2011-06-20 23:20:14 +02:00
|
|
|
parsedline->hostname = str;
|
2010-10-15 21:53:39 +02:00
|
|
|
else
|
2003-09-06 01:07:21 +02:00
|
|
|
{
|
2017-01-31 00:00:26 +01:00
|
|
|
ereport(elevel,
|
2004-05-20 00:06:16 +02:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
2009-10-01 03:58:58 +02:00
|
|
|
errmsg("invalid IP address \"%s\": %s",
|
2011-06-20 23:20:14 +02:00
|
|
|
str, gai_strerror(ret)),
|
2008-09-15 22:55:04 +02:00
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2017-01-31 00:00:26 +01:00
|
|
|
*err_msg = psprintf("invalid IP address \"%s\": %s",
|
|
|
|
str, gai_strerror(ret));
|
2003-09-06 01:07:21 +02:00
|
|
|
if (gai_result)
|
2005-10-17 18:24:20 +02:00
|
|
|
pg_freeaddrinfo_all(hints.ai_family, gai_result);
|
2011-06-20 23:20:14 +02:00
|
|
|
return NULL;
|
2003-09-06 01:07:21 +02:00
|
|
|
}
|
2003-07-22 21:00:12 +02:00
|
|
|
|
2005-10-17 18:24:20 +02:00
|
|
|
pg_freeaddrinfo_all(hints.ai_family, gai_result);
|
2003-06-12 09:36:51 +02:00
|
|
|
|
2009-10-01 03:58:58 +02:00
|
|
|
/* Get the netmask */
|
|
|
|
if (cidr_slash)
|
2004-05-20 00:06:16 +02:00
|
|
|
{
|
2010-10-15 21:53:39 +02:00
|
|
|
if (parsedline->hostname)
|
|
|
|
{
|
2017-01-31 00:00:26 +01:00
|
|
|
ereport(elevel,
|
2010-10-15 21:53:39 +02:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
|
|
|
errmsg("specifying both host name and CIDR mask is invalid: \"%s\"",
|
2011-06-20 23:20:14 +02:00
|
|
|
token->string),
|
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2017-01-31 00:00:26 +01:00
|
|
|
*err_msg = psprintf("specifying both host name and CIDR mask is invalid: \"%s\"",
|
|
|
|
token->string);
|
2011-06-20 23:20:14 +02:00
|
|
|
return NULL;
|
2010-10-15 21:53:39 +02:00
|
|
|
}
|
|
|
|
|
2009-10-01 03:58:58 +02:00
|
|
|
if (pg_sockaddr_cidr_mask(&parsedline->mask, cidr_slash + 1,
|
|
|
|
parsedline->addr.ss_family) < 0)
|
|
|
|
{
|
2017-01-31 00:00:26 +01:00
|
|
|
ereport(elevel,
|
2009-10-01 03:58:58 +02:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
|
|
|
errmsg("invalid CIDR mask in address \"%s\"",
|
2011-06-20 23:20:14 +02:00
|
|
|
token->string),
|
2009-10-01 03:58:58 +02:00
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2017-01-31 00:00:26 +01:00
|
|
|
*err_msg = psprintf("invalid CIDR mask in address \"%s\"",
|
|
|
|
token->string);
|
2011-06-20 23:20:14 +02:00
|
|
|
return NULL;
|
2009-10-01 03:58:58 +02:00
|
|
|
}
|
2020-11-03 03:11:50 +01:00
|
|
|
parsedline->masklen = parsedline->addrlen;
|
2011-06-20 23:20:14 +02:00
|
|
|
pfree(str);
|
2009-10-01 03:58:58 +02:00
|
|
|
}
|
2010-10-15 21:53:39 +02:00
|
|
|
else if (!parsedline->hostname)
|
2009-10-01 03:58:58 +02:00
|
|
|
{
|
|
|
|
/* Read the mask field. */
|
2011-06-20 23:20:14 +02:00
|
|
|
pfree(str);
|
Represent Lists as expansible arrays, not chains of cons-cells.
Originally, Postgres Lists were a more or less exact reimplementation of
Lisp lists, which consist of chains of separately-allocated cons cells,
each having a value and a next-cell link. We'd hacked that once before
(commit d0b4399d8) to add a separate List header, but the data was still
in cons cells. That makes some operations -- notably list_nth() -- O(N),
and it's bulky because of the next-cell pointers and per-cell palloc
overhead, and it's very cache-unfriendly if the cons cells end up
scattered around rather than being adjacent.
In this rewrite, we still have List headers, but the data is in a
resizable array of values, with no next-cell links. Now we need at
most two palloc's per List, and often only one, since we can allocate
some values in the same palloc call as the List header. (Of course,
extending an existing List may require repalloc's to enlarge the array.
But this involves just O(log N) allocations not O(N).)
Of course this is not without downsides. The key difficulty is that
addition or deletion of a list entry may now cause other entries to
move, which it did not before.
For example, that breaks foreach() and sister macros, which historically
used a pointer to the current cons-cell as loop state. We can repair
those macros transparently by making their actual loop state be an
integer list index; the exposed "ListCell *" pointer is no longer state
carried across loop iterations, but is just a derived value. (In
practice, modern compilers can optimize things back to having just one
loop state value, at least for simple cases with inline loop bodies.)
In principle, this is a semantics change for cases where the loop body
inserts or deletes list entries ahead of the current loop index; but
I found no such cases in the Postgres code.
The change is not at all transparent for code that doesn't use foreach()
but chases lists "by hand" using lnext(). The largest share of such
code in the backend is in loops that were maintaining "prev" and "next"
variables in addition to the current-cell pointer, in order to delete
list cells efficiently using list_delete_cell(). However, we no longer
need a previous-cell pointer to delete a list cell efficiently. Keeping
a next-cell pointer doesn't work, as explained above, but we can improve
matters by changing such code to use a regular foreach() loop and then
using the new macro foreach_delete_current() to delete the current cell.
(This macro knows how to update the associated foreach loop's state so
that no cells will be missed in the traversal.)
There remains a nontrivial risk of code assuming that a ListCell *
pointer will remain good over an operation that could now move the list
contents. To help catch such errors, list.c can be compiled with a new
define symbol DEBUG_LIST_MEMORY_USAGE that forcibly moves list contents
whenever that could possibly happen. This makes list operations
significantly more expensive so it's not normally turned on (though it
is on by default if USE_VALGRIND is on).
There are two notable API differences from the previous code:
* lnext() now requires the List's header pointer in addition to the
current cell's address.
* list_delete_cell() no longer requires a previous-cell argument.
These changes are somewhat unfortunate, but on the other hand code using
either function needs inspection to see if it is assuming anything
it shouldn't, so it's not all bad.
Programmers should be aware of these significant performance changes:
* list_nth() and related functions are now O(1); so there's no
major access-speed difference between a list and an array.
* Inserting or deleting a list element now takes time proportional to
the distance to the end of the list, due to moving the array elements.
(However, it typically *doesn't* require palloc or pfree, so except in
long lists it's probably still faster than before.) Notably, lcons()
used to be about the same cost as lappend(), but that's no longer true
if the list is long. Code that uses lcons() and list_delete_first()
to maintain a stack might usefully be rewritten to push and pop at the
end of the list rather than the beginning.
* There are now list_insert_nth...() and list_delete_nth...() functions
that add or remove a list cell identified by index. These have the
data-movement penalty explained above, but there's no search penalty.
* list_concat() and variants now copy the second list's data into
storage belonging to the first list, so there is no longer any
sharing of cells between the input lists. The second argument is
now declared "const List *" to reflect that it isn't changed.
This patch just does the minimum needed to get the new implementation
in place and fix bugs exposed by the regression tests. As suggested
by the foregoing, there's a fair amount of followup work remaining to
do.
Also, the ENABLE_LIST_COMPAT macros are finally removed in this
commit. Code using those should have been gone a dozen years ago.
Patch by me; thanks to David Rowley, Jesper Pedersen, and others
for review.
Discussion: https://postgr.es/m/11587.1550975080@sss.pgh.pa.us
2019-07-15 19:41:58 +02:00
|
|
|
field = lnext(tok_line->fields, field);
|
2011-06-20 23:20:14 +02:00
|
|
|
if (!field)
|
2009-10-01 03:58:58 +02:00
|
|
|
{
|
2017-01-31 00:00:26 +01:00
|
|
|
ereport(elevel,
|
2009-10-01 03:58:58 +02:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
|
|
|
errmsg("end-of-line before netmask specification"),
|
2011-06-20 23:20:14 +02:00
|
|
|
errhint("Specify an address range in CIDR notation, or provide a separate netmask."),
|
2009-10-01 03:58:58 +02:00
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2017-01-31 00:00:26 +01:00
|
|
|
*err_msg = "end-of-line before netmask specification";
|
2011-06-20 23:20:14 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
tokens = lfirst(field);
|
|
|
|
if (tokens->length > 1)
|
|
|
|
{
|
2017-01-31 00:00:26 +01:00
|
|
|
ereport(elevel,
|
2011-06-20 23:20:14 +02:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
|
|
|
errmsg("multiple values specified for netmask"),
|
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2017-01-31 00:00:26 +01:00
|
|
|
*err_msg = "multiple values specified for netmask";
|
2011-06-20 23:20:14 +02:00
|
|
|
return NULL;
|
2009-10-01 03:58:58 +02:00
|
|
|
}
|
2011-06-20 23:20:14 +02:00
|
|
|
token = linitial(tokens);
|
2009-10-01 03:58:58 +02:00
|
|
|
|
2011-06-20 23:20:14 +02:00
|
|
|
ret = pg_getaddrinfo_all(token->string, NULL,
|
|
|
|
&hints, &gai_result);
|
2009-10-01 03:58:58 +02:00
|
|
|
if (ret || !gai_result)
|
|
|
|
{
|
2017-01-31 00:00:26 +01:00
|
|
|
ereport(elevel,
|
2009-10-01 03:58:58 +02:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
|
|
|
errmsg("invalid IP mask \"%s\": %s",
|
2011-06-20 23:20:14 +02:00
|
|
|
token->string, gai_strerror(ret)),
|
2009-10-01 03:58:58 +02:00
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2017-01-31 00:00:26 +01:00
|
|
|
*err_msg = psprintf("invalid IP mask \"%s\": %s",
|
|
|
|
token->string, gai_strerror(ret));
|
2009-10-01 03:58:58 +02:00
|
|
|
if (gai_result)
|
|
|
|
pg_freeaddrinfo_all(hints.ai_family, gai_result);
|
2011-06-20 23:20:14 +02:00
|
|
|
return NULL;
|
2009-10-01 03:58:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(&parsedline->mask, gai_result->ai_addr,
|
|
|
|
gai_result->ai_addrlen);
|
2020-11-03 03:11:50 +01:00
|
|
|
parsedline->masklen = gai_result->ai_addrlen;
|
2009-10-01 03:58:58 +02:00
|
|
|
pg_freeaddrinfo_all(hints.ai_family, gai_result);
|
|
|
|
|
|
|
|
if (parsedline->addr.ss_family != parsedline->mask.ss_family)
|
|
|
|
{
|
2017-01-31 00:00:26 +01:00
|
|
|
ereport(elevel,
|
2009-10-01 03:58:58 +02:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
2010-05-26 18:43:13 +02:00
|
|
|
errmsg("IP address and mask do not match"),
|
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2017-01-31 00:00:26 +01:00
|
|
|
*err_msg = "IP address and mask do not match";
|
2011-06-20 23:20:14 +02:00
|
|
|
return NULL;
|
2009-10-01 03:58:58 +02:00
|
|
|
}
|
2004-05-20 00:06:16 +02:00
|
|
|
}
|
2003-06-12 09:36:51 +02:00
|
|
|
}
|
2008-09-15 14:32:57 +02:00
|
|
|
} /* != ctLocal */
|
|
|
|
|
|
|
|
/* Get the authentication method */
|
Represent Lists as expansible arrays, not chains of cons-cells.
Originally, Postgres Lists were a more or less exact reimplementation of
Lisp lists, which consist of chains of separately-allocated cons cells,
each having a value and a next-cell link. We'd hacked that once before
(commit d0b4399d8) to add a separate List header, but the data was still
in cons cells. That makes some operations -- notably list_nth() -- O(N),
and it's bulky because of the next-cell pointers and per-cell palloc
overhead, and it's very cache-unfriendly if the cons cells end up
scattered around rather than being adjacent.
In this rewrite, we still have List headers, but the data is in a
resizable array of values, with no next-cell links. Now we need at
most two palloc's per List, and often only one, since we can allocate
some values in the same palloc call as the List header. (Of course,
extending an existing List may require repalloc's to enlarge the array.
But this involves just O(log N) allocations not O(N).)
Of course this is not without downsides. The key difficulty is that
addition or deletion of a list entry may now cause other entries to
move, which it did not before.
For example, that breaks foreach() and sister macros, which historically
used a pointer to the current cons-cell as loop state. We can repair
those macros transparently by making their actual loop state be an
integer list index; the exposed "ListCell *" pointer is no longer state
carried across loop iterations, but is just a derived value. (In
practice, modern compilers can optimize things back to having just one
loop state value, at least for simple cases with inline loop bodies.)
In principle, this is a semantics change for cases where the loop body
inserts or deletes list entries ahead of the current loop index; but
I found no such cases in the Postgres code.
The change is not at all transparent for code that doesn't use foreach()
but chases lists "by hand" using lnext(). The largest share of such
code in the backend is in loops that were maintaining "prev" and "next"
variables in addition to the current-cell pointer, in order to delete
list cells efficiently using list_delete_cell(). However, we no longer
need a previous-cell pointer to delete a list cell efficiently. Keeping
a next-cell pointer doesn't work, as explained above, but we can improve
matters by changing such code to use a regular foreach() loop and then
using the new macro foreach_delete_current() to delete the current cell.
(This macro knows how to update the associated foreach loop's state so
that no cells will be missed in the traversal.)
There remains a nontrivial risk of code assuming that a ListCell *
pointer will remain good over an operation that could now move the list
contents. To help catch such errors, list.c can be compiled with a new
define symbol DEBUG_LIST_MEMORY_USAGE that forcibly moves list contents
whenever that could possibly happen. This makes list operations
significantly more expensive so it's not normally turned on (though it
is on by default if USE_VALGRIND is on).
There are two notable API differences from the previous code:
* lnext() now requires the List's header pointer in addition to the
current cell's address.
* list_delete_cell() no longer requires a previous-cell argument.
These changes are somewhat unfortunate, but on the other hand code using
either function needs inspection to see if it is assuming anything
it shouldn't, so it's not all bad.
Programmers should be aware of these significant performance changes:
* list_nth() and related functions are now O(1); so there's no
major access-speed difference between a list and an array.
* Inserting or deleting a list element now takes time proportional to
the distance to the end of the list, due to moving the array elements.
(However, it typically *doesn't* require palloc or pfree, so except in
long lists it's probably still faster than before.) Notably, lcons()
used to be about the same cost as lappend(), but that's no longer true
if the list is long. Code that uses lcons() and list_delete_first()
to maintain a stack might usefully be rewritten to push and pop at the
end of the list rather than the beginning.
* There are now list_insert_nth...() and list_delete_nth...() functions
that add or remove a list cell identified by index. These have the
data-movement penalty explained above, but there's no search penalty.
* list_concat() and variants now copy the second list's data into
storage belonging to the first list, so there is no longer any
sharing of cells between the input lists. The second argument is
now declared "const List *" to reflect that it isn't changed.
This patch just does the minimum needed to get the new implementation
in place and fix bugs exposed by the regression tests. As suggested
by the foregoing, there's a fair amount of followup work remaining to
do.
Also, the ENABLE_LIST_COMPAT macros are finally removed in this
commit. Code using those should have been gone a dozen years ago.
Patch by me; thanks to David Rowley, Jesper Pedersen, and others
for review.
Discussion: https://postgr.es/m/11587.1550975080@sss.pgh.pa.us
2019-07-15 19:41:58 +02:00
|
|
|
field = lnext(tok_line->fields, field);
|
2011-06-20 23:20:14 +02:00
|
|
|
if (!field)
|
2008-10-27 21:04:45 +01:00
|
|
|
{
|
2017-01-31 00:00:26 +01:00
|
|
|
ereport(elevel,
|
2008-10-27 21:04:45 +01:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
|
|
|
errmsg("end-of-line before authentication method"),
|
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2017-01-31 00:00:26 +01:00
|
|
|
*err_msg = "end-of-line before authentication method";
|
2011-06-20 23:20:14 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
tokens = lfirst(field);
|
|
|
|
if (tokens->length > 1)
|
|
|
|
{
|
2017-01-31 00:00:26 +01:00
|
|
|
ereport(elevel,
|
2011-06-20 23:20:14 +02:00
|
|
|
(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\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2017-01-31 00:00:26 +01:00
|
|
|
*err_msg = "multiple values specified for authentication type";
|
2011-06-20 23:20:14 +02:00
|
|
|
return NULL;
|
2008-10-27 21:04:45 +01:00
|
|
|
}
|
2011-06-20 23:20:14 +02:00
|
|
|
token = linitial(tokens);
|
1998-01-26 02:42:53 +01:00
|
|
|
|
2008-09-15 14:32:57 +02:00
|
|
|
unsupauth = NULL;
|
2011-06-20 23:20:14 +02:00
|
|
|
if (strcmp(token->string, "trust") == 0)
|
2008-09-15 14:32:57 +02:00
|
|
|
parsedline->auth_method = uaTrust;
|
2011-06-20 23:20:14 +02:00
|
|
|
else if (strcmp(token->string, "ident") == 0)
|
2008-09-15 14:32:57 +02:00
|
|
|
parsedline->auth_method = uaIdent;
|
2011-06-20 23:20:14 +02:00
|
|
|
else if (strcmp(token->string, "peer") == 0)
|
2011-03-19 18:44:35 +01:00
|
|
|
parsedline->auth_method = uaPeer;
|
2011-06-20 23:20:14 +02:00
|
|
|
else if (strcmp(token->string, "password") == 0)
|
2008-09-15 14:32:57 +02:00
|
|
|
parsedline->auth_method = uaPassword;
|
2011-06-20 23:20:14 +02:00
|
|
|
else if (strcmp(token->string, "gss") == 0)
|
2008-09-15 14:32:57 +02:00
|
|
|
#ifdef ENABLE_GSS
|
|
|
|
parsedline->auth_method = uaGSS;
|
|
|
|
#else
|
|
|
|
unsupauth = "gss";
|
|
|
|
#endif
|
2011-06-20 23:20:14 +02:00
|
|
|
else if (strcmp(token->string, "sspi") == 0)
|
2008-09-15 14:32:57 +02:00
|
|
|
#ifdef ENABLE_SSPI
|
|
|
|
parsedline->auth_method = uaSSPI;
|
|
|
|
#else
|
|
|
|
unsupauth = "sspi";
|
|
|
|
#endif
|
2011-06-20 23:20:14 +02:00
|
|
|
else if (strcmp(token->string, "reject") == 0)
|
2008-09-15 14:32:57 +02:00
|
|
|
parsedline->auth_method = uaReject;
|
2011-06-20 23:20:14 +02:00
|
|
|
else if (strcmp(token->string, "md5") == 0)
|
2008-11-20 21:45:30 +01:00
|
|
|
{
|
|
|
|
if (Db_user_namespace)
|
|
|
|
{
|
2017-01-31 00:00:26 +01:00
|
|
|
ereport(elevel,
|
2008-11-20 21:45:30 +01:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
2010-05-26 18:43:13 +02:00
|
|
|
errmsg("MD5 authentication is not supported when \"db_user_namespace\" is enabled"),
|
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2017-01-31 00:00:26 +01:00
|
|
|
*err_msg = "MD5 authentication is not supported when \"db_user_namespace\" is enabled";
|
2011-06-20 23:20:14 +02:00
|
|
|
return NULL;
|
2008-11-20 21:45:30 +01:00
|
|
|
}
|
2008-09-15 14:32:57 +02:00
|
|
|
parsedline->auth_method = uaMD5;
|
2008-11-20 21:45:30 +01:00
|
|
|
}
|
2017-04-18 13:50:50 +02:00
|
|
|
else if (strcmp(token->string, "scram-sha-256") == 0)
|
Allow SCRAM authentication, when pg_hba.conf says 'md5'.
If a user has a SCRAM verifier in pg_authid.rolpassword, there's no reason
we cannot attempt to perform SCRAM authentication instead of MD5. The worst
that can happen is that the client doesn't support SCRAM, and the
authentication will fail. But previously, it would fail for sure, because
we would not even try. SCRAM is strictly more secure than MD5, so there's
no harm in trying it. This allows for a more graceful transition from MD5
passwords to SCRAM, as user passwords can be changed to SCRAM verifiers
incrementally, without changing pg_hba.conf.
Refactor the code in auth.c to support that better. Notably, we now have to
look up the user's pg_authid entry before sending the password challenge,
also when performing MD5 authentication. Also simplify the concept of a
"doomed" authentication. Previously, if a user had a password, but it had
expired, we still performed SCRAM authentication (but always returned error
at the end) using the salt and iteration count from the expired password.
Now we construct a fake salt, like we do when the user doesn't have a
password or doesn't exist at all. That simplifies get_role_password(), and
we can don't need to distinguish the "user has expired password", and
"user does not exist" cases in auth.c.
On second thoughts, also rename uaSASL to uaSCRAM. It refers to the
mechanism specified in pg_hba.conf, and while we use SASL for SCRAM
authentication at the protocol level, the mechanism should be called SCRAM,
not SASL. As a comparison, we have uaLDAP, even though it looks like the
plain 'password' authentication at the protocol level.
Discussion: https://www.postgresql.org/message-id/6425.1489506016@sss.pgh.pa.us
Reviewed-by: Michael Paquier
2017-03-24 12:32:21 +01:00
|
|
|
parsedline->auth_method = uaSCRAM;
|
2011-06-20 23:20:14 +02:00
|
|
|
else if (strcmp(token->string, "pam") == 0)
|
2008-09-15 14:32:57 +02:00
|
|
|
#ifdef USE_PAM
|
|
|
|
parsedline->auth_method = uaPAM;
|
|
|
|
#else
|
|
|
|
unsupauth = "pam";
|
2016-04-08 19:51:54 +02:00
|
|
|
#endif
|
|
|
|
else if (strcmp(token->string, "bsd") == 0)
|
|
|
|
#ifdef USE_BSD_AUTH
|
|
|
|
parsedline->auth_method = uaBSD;
|
|
|
|
#else
|
|
|
|
unsupauth = "bsd";
|
2008-09-15 14:32:57 +02:00
|
|
|
#endif
|
2011-06-20 23:20:14 +02:00
|
|
|
else if (strcmp(token->string, "ldap") == 0)
|
2008-09-15 14:32:57 +02:00
|
|
|
#ifdef USE_LDAP
|
|
|
|
parsedline->auth_method = uaLDAP;
|
|
|
|
#else
|
|
|
|
unsupauth = "ldap";
|
2008-11-20 12:48:26 +01:00
|
|
|
#endif
|
2011-06-20 23:20:14 +02:00
|
|
|
else if (strcmp(token->string, "cert") == 0)
|
2008-11-20 12:48:26 +01:00
|
|
|
#ifdef USE_SSL
|
|
|
|
parsedline->auth_method = uaCert;
|
|
|
|
#else
|
|
|
|
unsupauth = "cert";
|
2008-09-15 14:32:57 +02:00
|
|
|
#endif
|
2011-06-20 23:20:14 +02:00
|
|
|
else if (strcmp(token->string, "radius") == 0)
|
2010-01-27 13:12:00 +01:00
|
|
|
parsedline->auth_method = uaRADIUS;
|
2008-09-15 14:32:57 +02:00
|
|
|
else
|
|
|
|
{
|
2017-01-31 00:00:26 +01:00
|
|
|
ereport(elevel,
|
2008-09-15 14:32:57 +02:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
|
|
|
errmsg("invalid authentication method \"%s\"",
|
2011-06-20 23:20:14 +02:00
|
|
|
token->string),
|
2008-09-15 22:55:04 +02:00
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2017-01-31 00:00:26 +01:00
|
|
|
*err_msg = psprintf("invalid authentication method \"%s\"",
|
|
|
|
token->string);
|
2011-06-20 23:20:14 +02:00
|
|
|
return NULL;
|
2008-09-15 14:32:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (unsupauth)
|
|
|
|
{
|
2017-01-31 00:00:26 +01:00
|
|
|
ereport(elevel,
|
2008-09-15 14:32:57 +02:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
2011-04-26 21:56:28 +02:00
|
|
|
errmsg("invalid authentication method \"%s\": not supported by this build",
|
2011-06-20 23:20:14 +02:00
|
|
|
token->string),
|
2008-09-15 22:55:04 +02:00
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2017-01-31 00:00:26 +01:00
|
|
|
*err_msg = psprintf("invalid authentication method \"%s\": not supported by this build",
|
|
|
|
token->string);
|
2011-06-20 23:20:14 +02:00
|
|
|
return NULL;
|
2008-09-15 14:32:57 +02:00
|
|
|
}
|
|
|
|
|
2011-03-19 18:44:35 +01:00
|
|
|
/*
|
|
|
|
* XXX: When using ident on local connections, change it to peer, for
|
|
|
|
* backwards compatibility.
|
|
|
|
*/
|
|
|
|
if (parsedline->conntype == ctLocal &&
|
|
|
|
parsedline->auth_method == uaIdent)
|
|
|
|
parsedline->auth_method = uaPeer;
|
|
|
|
|
2008-09-15 14:32:57 +02:00
|
|
|
/* Invalid authentication combinations */
|
2010-03-08 10:57:26 +01:00
|
|
|
if (parsedline->conntype == ctLocal &&
|
|
|
|
parsedline->auth_method == uaGSS)
|
|
|
|
{
|
2017-01-31 00:00:26 +01:00
|
|
|
ereport(elevel,
|
2010-03-08 10:57:26 +01:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
|
|
|
errmsg("gssapi authentication is not supported on local sockets"),
|
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2017-01-31 00:00:26 +01:00
|
|
|
*err_msg = "gssapi authentication is not supported on local sockets";
|
2011-06-20 23:20:14 +02:00
|
|
|
return NULL;
|
2010-03-08 10:57:26 +01:00
|
|
|
}
|
2010-07-06 21:19:02 +02:00
|
|
|
|
2011-03-19 18:44:35 +01:00
|
|
|
if (parsedline->conntype != ctLocal &&
|
|
|
|
parsedline->auth_method == uaPeer)
|
|
|
|
{
|
2017-01-31 00:00:26 +01:00
|
|
|
ereport(elevel,
|
2011-03-19 18:44:35 +01:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
|
|
|
errmsg("peer authentication is only supported on local sockets"),
|
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2017-01-31 00:00:26 +01:00
|
|
|
*err_msg = "peer authentication is only supported on local sockets";
|
2011-06-20 23:20:14 +02:00
|
|
|
return NULL;
|
2011-03-19 18:44:35 +01:00
|
|
|
}
|
|
|
|
|
2010-03-08 10:57:26 +01:00
|
|
|
/*
|
|
|
|
* SSPI authentication can never be enabled on ctLocal connections,
|
|
|
|
* because it's only supported on Windows, where ctLocal isn't supported.
|
|
|
|
*/
|
2012-01-27 20:39:38 +01:00
|
|
|
|
|
|
|
|
2008-11-20 12:48:26 +01:00
|
|
|
if (parsedline->conntype != ctHostSSL &&
|
|
|
|
parsedline->auth_method == uaCert)
|
|
|
|
{
|
2017-01-31 00:00:26 +01:00
|
|
|
ereport(elevel,
|
2008-11-20 12:48:26 +01:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
|
|
|
errmsg("cert authentication is only supported on hostssl connections"),
|
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2017-01-31 00:00:26 +01:00
|
|
|
*err_msg = "cert authentication is only supported on hostssl connections";
|
2011-06-20 23:20:14 +02:00
|
|
|
return NULL;
|
2008-11-20 12:48:26 +01:00
|
|
|
}
|
|
|
|
|
2015-11-06 17:18:27 +01:00
|
|
|
/*
|
|
|
|
* For GSS and SSPI, set the default value of include_realm to true.
|
|
|
|
* Having include_realm set to false is dangerous in multi-realm
|
|
|
|
* situations and is generally considered bad practice. We keep the
|
|
|
|
* capability around for backwards compatibility, but we might want to
|
|
|
|
* remove it at some point in the future. Users who still need to strip
|
|
|
|
* the realm off would be better served by using an appropriate regex in a
|
|
|
|
* pg_ident.conf mapping.
|
|
|
|
*/
|
|
|
|
if (parsedline->auth_method == uaGSS ||
|
|
|
|
parsedline->auth_method == uaSSPI)
|
|
|
|
parsedline->include_realm = true;
|
|
|
|
|
2016-04-08 20:23:52 +02:00
|
|
|
/*
|
|
|
|
* For SSPI, include_realm defaults to the SAM-compatible domain (aka
|
|
|
|
* NetBIOS name) and user names instead of the Kerberos principal name for
|
|
|
|
* compatibility.
|
|
|
|
*/
|
|
|
|
if (parsedline->auth_method == uaSSPI)
|
|
|
|
{
|
|
|
|
parsedline->compat_realm = true;
|
|
|
|
parsedline->upn_username = false;
|
|
|
|
}
|
|
|
|
|
2008-10-23 15:31:10 +02:00
|
|
|
/* Parse remaining arguments */
|
Represent Lists as expansible arrays, not chains of cons-cells.
Originally, Postgres Lists were a more or less exact reimplementation of
Lisp lists, which consist of chains of separately-allocated cons cells,
each having a value and a next-cell link. We'd hacked that once before
(commit d0b4399d8) to add a separate List header, but the data was still
in cons cells. That makes some operations -- notably list_nth() -- O(N),
and it's bulky because of the next-cell pointers and per-cell palloc
overhead, and it's very cache-unfriendly if the cons cells end up
scattered around rather than being adjacent.
In this rewrite, we still have List headers, but the data is in a
resizable array of values, with no next-cell links. Now we need at
most two palloc's per List, and often only one, since we can allocate
some values in the same palloc call as the List header. (Of course,
extending an existing List may require repalloc's to enlarge the array.
But this involves just O(log N) allocations not O(N).)
Of course this is not without downsides. The key difficulty is that
addition or deletion of a list entry may now cause other entries to
move, which it did not before.
For example, that breaks foreach() and sister macros, which historically
used a pointer to the current cons-cell as loop state. We can repair
those macros transparently by making their actual loop state be an
integer list index; the exposed "ListCell *" pointer is no longer state
carried across loop iterations, but is just a derived value. (In
practice, modern compilers can optimize things back to having just one
loop state value, at least for simple cases with inline loop bodies.)
In principle, this is a semantics change for cases where the loop body
inserts or deletes list entries ahead of the current loop index; but
I found no such cases in the Postgres code.
The change is not at all transparent for code that doesn't use foreach()
but chases lists "by hand" using lnext(). The largest share of such
code in the backend is in loops that were maintaining "prev" and "next"
variables in addition to the current-cell pointer, in order to delete
list cells efficiently using list_delete_cell(). However, we no longer
need a previous-cell pointer to delete a list cell efficiently. Keeping
a next-cell pointer doesn't work, as explained above, but we can improve
matters by changing such code to use a regular foreach() loop and then
using the new macro foreach_delete_current() to delete the current cell.
(This macro knows how to update the associated foreach loop's state so
that no cells will be missed in the traversal.)
There remains a nontrivial risk of code assuming that a ListCell *
pointer will remain good over an operation that could now move the list
contents. To help catch such errors, list.c can be compiled with a new
define symbol DEBUG_LIST_MEMORY_USAGE that forcibly moves list contents
whenever that could possibly happen. This makes list operations
significantly more expensive so it's not normally turned on (though it
is on by default if USE_VALGRIND is on).
There are two notable API differences from the previous code:
* lnext() now requires the List's header pointer in addition to the
current cell's address.
* list_delete_cell() no longer requires a previous-cell argument.
These changes are somewhat unfortunate, but on the other hand code using
either function needs inspection to see if it is assuming anything
it shouldn't, so it's not all bad.
Programmers should be aware of these significant performance changes:
* list_nth() and related functions are now O(1); so there's no
major access-speed difference between a list and an array.
* Inserting or deleting a list element now takes time proportional to
the distance to the end of the list, due to moving the array elements.
(However, it typically *doesn't* require palloc or pfree, so except in
long lists it's probably still faster than before.) Notably, lcons()
used to be about the same cost as lappend(), but that's no longer true
if the list is long. Code that uses lcons() and list_delete_first()
to maintain a stack might usefully be rewritten to push and pop at the
end of the list rather than the beginning.
* There are now list_insert_nth...() and list_delete_nth...() functions
that add or remove a list cell identified by index. These have the
data-movement penalty explained above, but there's no search penalty.
* list_concat() and variants now copy the second list's data into
storage belonging to the first list, so there is no longer any
sharing of cells between the input lists. The second argument is
now declared "const List *" to reflect that it isn't changed.
This patch just does the minimum needed to get the new implementation
in place and fix bugs exposed by the regression tests. As suggested
by the foregoing, there's a fair amount of followup work remaining to
do.
Also, the ENABLE_LIST_COMPAT macros are finally removed in this
commit. Code using those should have been gone a dozen years ago.
Patch by me; thanks to David Rowley, Jesper Pedersen, and others
for review.
Discussion: https://postgr.es/m/11587.1550975080@sss.pgh.pa.us
2019-07-15 19:41:58 +02:00
|
|
|
while ((field = lnext(tok_line->fields, field)) != NULL)
|
2008-09-15 14:32:57 +02:00
|
|
|
{
|
2011-06-20 23:20:14 +02:00
|
|
|
tokens = lfirst(field);
|
|
|
|
foreach(tokencell, tokens)
|
2003-09-05 22:31:36 +02:00
|
|
|
{
|
2011-06-20 23:20:14 +02:00
|
|
|
char *val;
|
2012-06-10 21:20:04 +02:00
|
|
|
|
2011-06-20 23:20:14 +02:00
|
|
|
token = lfirst(tokencell);
|
|
|
|
|
|
|
|
str = pstrdup(token->string);
|
|
|
|
val = strchr(str, '=');
|
|
|
|
if (val == NULL)
|
2008-11-20 10:29:36 +01:00
|
|
|
{
|
|
|
|
/*
|
2011-06-20 23:20:14 +02:00
|
|
|
* Got something that's not a name=value pair.
|
2008-11-20 10:29:36 +01:00
|
|
|
*/
|
2017-01-31 00:00:26 +01:00
|
|
|
ereport(elevel,
|
2008-10-23 15:31:10 +02:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
2011-06-20 23:20:14 +02:00
|
|
|
errmsg("authentication option not in name=value format: %s", token->string),
|
2008-10-23 15:31:10 +02:00
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2017-01-31 00:00:26 +01:00
|
|
|
*err_msg = psprintf("authentication option not in name=value format: %s",
|
|
|
|
token->string);
|
2011-06-20 23:20:14 +02:00
|
|
|
return NULL;
|
2003-09-05 22:31:36 +02:00
|
|
|
}
|
2011-06-20 23:20:14 +02:00
|
|
|
|
|
|
|
*val++ = '\0'; /* str now holds "name", val holds "value" */
|
2017-01-31 00:00:26 +01:00
|
|
|
if (!parse_hba_auth_opt(str, val, parsedline, elevel, err_msg))
|
2011-06-20 23:20:14 +02:00
|
|
|
/* parse_hba_auth_opt already logged the error message */
|
|
|
|
return NULL;
|
|
|
|
pfree(str);
|
2003-09-05 22:31:36 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
2008-10-23 15:31:10 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if the selected authentication method has any mandatory arguments
|
|
|
|
* that are not set.
|
|
|
|
*/
|
|
|
|
if (parsedline->auth_method == uaLDAP)
|
|
|
|
{
|
2019-03-21 03:19:03 +01:00
|
|
|
#ifndef HAVE_LDAP_INITIALIZE
|
|
|
|
/* Not mandatory for OpenLDAP, because it can use DNS SRV records */
|
2008-10-23 15:31:10 +02:00
|
|
|
MANDATORY_AUTH_ARG(parsedline->ldapserver, "ldapserver", "ldap");
|
2019-03-21 03:19:03 +01:00
|
|
|
#endif
|
2009-12-12 22:35:21 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* LDAP can operate in two modes: either with a direct bind, using
|
|
|
|
* ldapprefix and ldapsuffix, or using a search+bind, using
|
2017-09-12 15:46:14 +02:00
|
|
|
* ldapbasedn, ldapbinddn, ldapbindpasswd and one of
|
|
|
|
* ldapsearchattribute or ldapsearchfilter. Disallow mixing these
|
|
|
|
* parameters.
|
2009-12-12 22:35:21 +01:00
|
|
|
*/
|
|
|
|
if (parsedline->ldapprefix || parsedline->ldapsuffix)
|
|
|
|
{
|
|
|
|
if (parsedline->ldapbasedn ||
|
|
|
|
parsedline->ldapbinddn ||
|
|
|
|
parsedline->ldapbindpasswd ||
|
2017-09-12 15:46:14 +02:00
|
|
|
parsedline->ldapsearchattribute ||
|
|
|
|
parsedline->ldapsearchfilter)
|
2009-12-12 22:35:21 +01:00
|
|
|
{
|
2017-01-31 00:00:26 +01:00
|
|
|
ereport(elevel,
|
2009-12-12 22:35:21 +01:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
2018-06-08 05:37:09 +02:00
|
|
|
errmsg("cannot use ldapbasedn, ldapbinddn, ldapbindpasswd, ldapsearchattribute, ldapsearchfilter, or ldapurl together with ldapprefix"),
|
2009-12-12 22:35:21 +01:00
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2018-06-08 05:37:09 +02:00
|
|
|
*err_msg = "cannot use ldapbasedn, ldapbinddn, ldapbindpasswd, ldapsearchattribute, ldapsearchfilter, or ldapurl together with ldapprefix";
|
2011-06-20 23:20:14 +02:00
|
|
|
return NULL;
|
2009-12-12 22:35:21 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (!parsedline->ldapbasedn)
|
|
|
|
{
|
2017-01-31 00:00:26 +01:00
|
|
|
ereport(elevel,
|
2009-12-12 22:35:21 +01:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
2010-03-21 01:17:59 +01:00
|
|
|
errmsg("authentication method \"ldap\" requires argument \"ldapbasedn\", \"ldapprefix\", or \"ldapsuffix\" to be set"),
|
2009-12-12 22:35:21 +01:00
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2017-01-31 00:00:26 +01:00
|
|
|
*err_msg = "authentication method \"ldap\" requires argument \"ldapbasedn\", \"ldapprefix\", or \"ldapsuffix\" to be set";
|
2011-06-20 23:20:14 +02:00
|
|
|
return NULL;
|
2009-12-12 22:35:21 +01:00
|
|
|
}
|
2017-09-12 15:46:14 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* When using search+bind, you can either use a simple attribute
|
|
|
|
* (defaulting to "uid") or a fully custom search filter. You can't
|
|
|
|
* do both.
|
|
|
|
*/
|
|
|
|
if (parsedline->ldapsearchattribute && parsedline->ldapsearchfilter)
|
|
|
|
{
|
|
|
|
ereport(elevel,
|
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
|
|
|
errmsg("cannot use ldapsearchattribute together with ldapsearchfilter"),
|
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2017-09-12 15:46:14 +02:00
|
|
|
*err_msg = "cannot use ldapsearchattribute together with ldapsearchfilter";
|
|
|
|
return NULL;
|
|
|
|
}
|
2008-10-23 15:31:10 +02:00
|
|
|
}
|
2008-11-20 12:48:26 +01:00
|
|
|
|
2010-01-27 13:12:00 +01:00
|
|
|
if (parsedline->auth_method == uaRADIUS)
|
|
|
|
{
|
2017-03-22 17:55:16 +01:00
|
|
|
MANDATORY_AUTH_ARG(parsedline->radiusservers, "radiusservers", "radius");
|
|
|
|
MANDATORY_AUTH_ARG(parsedline->radiussecrets, "radiussecrets", "radius");
|
|
|
|
|
2022-08-17 17:12:35 +02:00
|
|
|
if (parsedline->radiusservers == NIL)
|
2017-03-22 17:55:16 +01:00
|
|
|
{
|
2021-05-31 18:32:41 +02:00
|
|
|
ereport(elevel,
|
2017-03-22 17:55:16 +01:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
|
|
|
errmsg("list of RADIUS servers cannot be empty"),
|
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2021-05-31 18:32:41 +02:00
|
|
|
*err_msg = "list of RADIUS servers cannot be empty";
|
2017-03-22 17:55:16 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2022-08-17 17:12:35 +02:00
|
|
|
if (parsedline->radiussecrets == NIL)
|
2017-03-22 17:55:16 +01:00
|
|
|
{
|
2021-05-31 18:32:41 +02:00
|
|
|
ereport(elevel,
|
2017-03-22 17:55:16 +01:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
|
|
|
errmsg("list of RADIUS secrets cannot be empty"),
|
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2021-05-31 18:32:41 +02:00
|
|
|
*err_msg = "list of RADIUS secrets cannot be empty";
|
2017-03-22 17:55:16 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Verify length of option lists - each can be 0 (except for secrets,
|
|
|
|
* but that's already checked above), 1 (use the same value
|
|
|
|
* everywhere) or the same as the number of servers.
|
|
|
|
*/
|
2021-05-31 18:32:41 +02:00
|
|
|
if (!(list_length(parsedline->radiussecrets) == 1 ||
|
|
|
|
list_length(parsedline->radiussecrets) == list_length(parsedline->radiusservers)))
|
|
|
|
{
|
|
|
|
ereport(elevel,
|
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
|
|
|
errmsg("the number of RADIUS secrets (%d) must be 1 or the same as the number of RADIUS servers (%d)",
|
|
|
|
list_length(parsedline->radiussecrets),
|
|
|
|
list_length(parsedline->radiusservers)),
|
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2021-05-31 18:32:41 +02:00
|
|
|
*err_msg = psprintf("the number of RADIUS secrets (%d) must be 1 or the same as the number of RADIUS servers (%d)",
|
|
|
|
list_length(parsedline->radiussecrets),
|
|
|
|
list_length(parsedline->radiusservers));
|
2017-03-22 17:55:16 +01:00
|
|
|
return NULL;
|
2021-05-31 18:32:41 +02:00
|
|
|
}
|
|
|
|
if (!(list_length(parsedline->radiusports) == 0 ||
|
|
|
|
list_length(parsedline->radiusports) == 1 ||
|
|
|
|
list_length(parsedline->radiusports) == list_length(parsedline->radiusservers)))
|
|
|
|
{
|
|
|
|
ereport(elevel,
|
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
|
|
|
errmsg("the number of RADIUS ports (%d) must be 1 or the same as the number of RADIUS servers (%d)",
|
|
|
|
list_length(parsedline->radiusports),
|
|
|
|
list_length(parsedline->radiusservers)),
|
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2021-05-31 18:32:41 +02:00
|
|
|
*err_msg = psprintf("the number of RADIUS ports (%d) must be 1 or the same as the number of RADIUS servers (%d)",
|
|
|
|
list_length(parsedline->radiusports),
|
|
|
|
list_length(parsedline->radiusservers));
|
2017-03-22 17:55:16 +01:00
|
|
|
return NULL;
|
2021-05-31 18:32:41 +02:00
|
|
|
}
|
|
|
|
if (!(list_length(parsedline->radiusidentifiers) == 0 ||
|
|
|
|
list_length(parsedline->radiusidentifiers) == 1 ||
|
|
|
|
list_length(parsedline->radiusidentifiers) == list_length(parsedline->radiusservers)))
|
|
|
|
{
|
|
|
|
ereport(elevel,
|
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
|
|
|
errmsg("the number of RADIUS identifiers (%d) must be 1 or the same as the number of RADIUS servers (%d)",
|
|
|
|
list_length(parsedline->radiusidentifiers),
|
|
|
|
list_length(parsedline->radiusservers)),
|
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2021-05-31 18:32:41 +02:00
|
|
|
*err_msg = psprintf("the number of RADIUS identifiers (%d) must be 1 or the same as the number of RADIUS servers (%d)",
|
|
|
|
list_length(parsedline->radiusidentifiers),
|
|
|
|
list_length(parsedline->radiusservers));
|
2017-03-22 17:55:16 +01:00
|
|
|
return NULL;
|
2021-05-31 18:32:41 +02:00
|
|
|
}
|
2010-01-27 13:12:00 +01:00
|
|
|
}
|
|
|
|
|
2008-11-20 12:48:26 +01:00
|
|
|
/*
|
|
|
|
* Enforce any parameters implied by other settings.
|
|
|
|
*/
|
|
|
|
if (parsedline->auth_method == uaCert)
|
|
|
|
{
|
2022-01-26 09:52:41 +01:00
|
|
|
/*
|
Create routine able to set single-call SRFs for Materialize mode
Set-returning functions that use the Materialize mode, creating a
tuplestore to include all the tuples returned in a set rather than doing
so in multiple calls, use roughly the same set of steps to prepare
ReturnSetInfo for this job:
- Check if ReturnSetInfo supports returning a tuplestore and if the
materialize mode is enabled.
- Create a tuplestore for all the tuples part of the returned set in the
per-query memory context, stored in ReturnSetInfo->setResult.
- Build a tuple descriptor mostly from get_call_result_type(), then
stored in ReturnSetInfo->setDesc. Note that there are some cases where
the SRF's tuple descriptor has to be the one specified by the function
caller.
This refactoring is done so as there are (well, should be) no behavior
changes in any of the in-core functions refactored, and the centralized
function that checks and sets up the function's ReturnSetInfo can be
controlled with a set of bits32 options. Two of them prove to be
necessary now:
- SRF_SINGLE_USE_EXPECTED to use expectedDesc as tuple descriptor, as
expected by the function's caller.
- SRF_SINGLE_BLESS to validate the tuple descriptor for the SRF.
The same initialization pattern is simplified in 28 places per my
count as of src/backend/, shaving up to ~900 lines of code. These
mostly come from the removal of the per-query initializations and the
sanity checks now grouped in a single location. There are more
locations that could be simplified in contrib/, that are left for a
follow-up cleanup.
fcc2817, 07daca5 and d61a361 have prepared the areas of the code related
to this change, to ease this refactoring.
Author: Melanie Plageman, Michael Paquier
Reviewed-by: Álvaro Herrera, Justin Pryzby
Discussion: https://postgr.es/m/CAAKRu_azyd1Z3W_r7Ou4sorTjRCs+PxeHw1CWJeXKofkE6TuZg@mail.gmail.com
2022-03-07 02:26:29 +01:00
|
|
|
* For auth method cert, client certificate validation is mandatory,
|
|
|
|
* and it implies the level of verify-full.
|
2022-01-26 09:52:41 +01:00
|
|
|
*/
|
|
|
|
parsedline->clientcert = clientCertFull;
|
2008-11-20 12:48:26 +01:00
|
|
|
}
|
2009-06-11 16:49:15 +02:00
|
|
|
|
2011-06-20 23:20:14 +02:00
|
|
|
return parsedline;
|
1996-10-12 09:47:12 +02:00
|
|
|
}
|
|
|
|
|
2017-03-22 17:55:16 +01:00
|
|
|
|
2001-07-30 16:50:24 +02:00
|
|
|
/*
|
2011-06-20 23:20:14 +02:00
|
|
|
* Parse one name-value pair as an authentication option into the given
|
|
|
|
* HbaLine. Return true if we successfully parse the option, false if we
|
2017-01-31 00:00:26 +01:00
|
|
|
* 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.
|
2001-07-30 16:50:24 +02:00
|
|
|
*/
|
|
|
|
static bool
|
2017-01-31 00:00:26 +01:00
|
|
|
parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline,
|
|
|
|
int elevel, char **err_msg)
|
2011-06-20 23:20:14 +02:00
|
|
|
{
|
2017-01-31 00:00:26 +01:00
|
|
|
int line_num = hbaline->linenumber;
|
2022-10-26 04:36:21 +02:00
|
|
|
char *file_name = hbaline->sourcefile;
|
2017-01-31 00:00:26 +01:00
|
|
|
|
2012-12-04 12:41:21 +01:00
|
|
|
#ifdef USE_LDAP
|
2012-12-04 05:29:56 +01:00
|
|
|
hbaline->ldapscope = LDAP_SCOPE_SUBTREE;
|
2012-12-04 12:41:21 +01:00
|
|
|
#endif
|
2012-12-04 05:29:56 +01:00
|
|
|
|
2011-06-20 23:20:14 +02:00
|
|
|
if (strcmp(name, "map") == 0)
|
|
|
|
{
|
|
|
|
if (hbaline->auth_method != uaIdent &&
|
|
|
|
hbaline->auth_method != uaPeer &&
|
|
|
|
hbaline->auth_method != uaGSS &&
|
|
|
|
hbaline->auth_method != uaSSPI &&
|
|
|
|
hbaline->auth_method != uaCert)
|
2014-01-15 17:24:01 +01:00
|
|
|
INVALID_AUTH_OPTION("map", gettext_noop("ident, peer, gssapi, sspi, and cert"));
|
2011-06-20 23:20:14 +02:00
|
|
|
hbaline->usermap = pstrdup(val);
|
|
|
|
}
|
|
|
|
else if (strcmp(name, "clientcert") == 0)
|
|
|
|
{
|
|
|
|
if (hbaline->conntype != ctHostSSL)
|
|
|
|
{
|
2017-01-31 00:00:26 +01:00
|
|
|
ereport(elevel,
|
2011-06-20 23:20:14 +02:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
|
|
|
errmsg("clientcert can only be configured for \"hostssl\" rows"),
|
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2017-01-31 00:00:26 +01:00
|
|
|
*err_msg = "clientcert can only be configured for \"hostssl\" rows";
|
2011-06-20 23:20:14 +02:00
|
|
|
return false;
|
|
|
|
}
|
2020-10-05 21:48:40 +02:00
|
|
|
|
|
|
|
if (strcmp(val, "verify-full") == 0)
|
2019-03-09 21:09:10 +01:00
|
|
|
{
|
|
|
|
hbaline->clientcert = clientCertFull;
|
|
|
|
}
|
2020-10-05 21:48:40 +02:00
|
|
|
else if (strcmp(val, "verify-ca") == 0)
|
2011-06-20 23:20:14 +02:00
|
|
|
{
|
|
|
|
if (hbaline->auth_method == uaCert)
|
|
|
|
{
|
2017-01-31 00:00:26 +01:00
|
|
|
ereport(elevel,
|
2011-06-20 23:20:14 +02:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
2020-10-05 21:48:40 +02:00
|
|
|
errmsg("clientcert only accepts \"verify-full\" when using \"cert\" authentication"),
|
2011-06-20 23:20:14 +02:00
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2020-10-05 21:48:40 +02:00
|
|
|
*err_msg = "clientcert can only be set to \"verify-full\" when using \"cert\" authentication";
|
2011-06-20 23:20:14 +02:00
|
|
|
return false;
|
|
|
|
}
|
2020-10-05 21:48:40 +02:00
|
|
|
|
|
|
|
hbaline->clientcert = clientCertCA;
|
2019-03-09 21:09:10 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ereport(elevel,
|
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
|
|
|
errmsg("invalid value for clientcert: \"%s\"", val),
|
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2019-03-09 21:09:10 +01:00
|
|
|
return false;
|
2011-06-20 23:20:14 +02:00
|
|
|
}
|
|
|
|
}
|
2021-03-29 21:31:22 +02:00
|
|
|
else if (strcmp(name, "clientname") == 0)
|
|
|
|
{
|
|
|
|
if (hbaline->conntype != ctHostSSL)
|
|
|
|
{
|
|
|
|
ereport(elevel,
|
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
|
|
|
errmsg("clientname can only be configured for \"hostssl\" rows"),
|
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2021-03-29 21:31:22 +02:00
|
|
|
*err_msg = "clientname can only be configured for \"hostssl\" rows";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strcmp(val, "CN") == 0)
|
|
|
|
{
|
|
|
|
hbaline->clientcertname = clientCertCN;
|
|
|
|
}
|
|
|
|
else if (strcmp(val, "DN") == 0)
|
|
|
|
{
|
|
|
|
hbaline->clientcertname = clientCertDN;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ereport(elevel,
|
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
|
|
|
errmsg("invalid value for clientname: \"%s\"", val),
|
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2021-03-29 21:31:22 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2011-06-20 23:20:14 +02:00
|
|
|
else if (strcmp(name, "pamservice") == 0)
|
|
|
|
{
|
|
|
|
REQUIRE_AUTH_OPTION(uaPAM, "pamservice", "pam");
|
|
|
|
hbaline->pamservice = pstrdup(val);
|
|
|
|
}
|
2016-04-08 16:45:16 +02:00
|
|
|
else if (strcmp(name, "pam_use_hostname") == 0)
|
|
|
|
{
|
|
|
|
REQUIRE_AUTH_OPTION(uaPAM, "pam_use_hostname", "pam");
|
|
|
|
if (strcmp(val, "1") == 0)
|
|
|
|
hbaline->pam_use_hostname = true;
|
|
|
|
else
|
|
|
|
hbaline->pam_use_hostname = false;
|
|
|
|
}
|
2012-12-04 05:29:56 +01:00
|
|
|
else if (strcmp(name, "ldapurl") == 0)
|
|
|
|
{
|
2012-12-04 12:41:21 +01:00
|
|
|
#ifdef LDAP_API_FEATURE_X_OPENLDAP
|
2012-12-04 05:29:56 +01:00
|
|
|
LDAPURLDesc *urldata;
|
|
|
|
int rc;
|
2012-12-04 12:41:21 +01:00
|
|
|
#endif
|
2012-12-04 05:29:56 +01:00
|
|
|
|
|
|
|
REQUIRE_AUTH_OPTION(uaLDAP, "ldapurl", "ldap");
|
|
|
|
#ifdef LDAP_API_FEATURE_X_OPENLDAP
|
|
|
|
rc = ldap_url_parse(val, &urldata);
|
|
|
|
if (rc != LDAP_SUCCESS)
|
|
|
|
{
|
2017-01-31 00:00:26 +01:00
|
|
|
ereport(elevel,
|
2012-12-04 05:29:56 +01:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
|
|
|
errmsg("could not parse LDAP URL \"%s\": %s", val, ldap_err2string(rc))));
|
2017-01-31 00:00:26 +01:00
|
|
|
*err_msg = psprintf("could not parse LDAP URL \"%s\": %s",
|
|
|
|
val, ldap_err2string(rc));
|
2012-12-04 05:29:56 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-01-03 16:00:08 +01:00
|
|
|
if (strcmp(urldata->lud_scheme, "ldap") != 0 &&
|
|
|
|
strcmp(urldata->lud_scheme, "ldaps") != 0)
|
2012-12-04 05:29:56 +01:00
|
|
|
{
|
2017-01-31 00:00:26 +01:00
|
|
|
ereport(elevel,
|
2012-12-04 05:29:56 +01:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
|
|
|
errmsg("unsupported LDAP URL scheme: %s", urldata->lud_scheme)));
|
2017-01-31 00:00:26 +01:00
|
|
|
*err_msg = psprintf("unsupported LDAP URL scheme: %s",
|
|
|
|
urldata->lud_scheme);
|
2012-12-04 05:29:56 +01:00
|
|
|
ldap_free_urldesc(urldata);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-01-03 16:00:08 +01:00
|
|
|
if (urldata->lud_scheme)
|
|
|
|
hbaline->ldapscheme = pstrdup(urldata->lud_scheme);
|
2017-11-10 20:21:32 +01:00
|
|
|
if (urldata->lud_host)
|
|
|
|
hbaline->ldapserver = pstrdup(urldata->lud_host);
|
2012-12-04 05:29:56 +01:00
|
|
|
hbaline->ldapport = urldata->lud_port;
|
2017-11-10 20:21:32 +01:00
|
|
|
if (urldata->lud_dn)
|
|
|
|
hbaline->ldapbasedn = pstrdup(urldata->lud_dn);
|
2012-12-04 05:29:56 +01:00
|
|
|
|
|
|
|
if (urldata->lud_attrs)
|
|
|
|
hbaline->ldapsearchattribute = pstrdup(urldata->lud_attrs[0]); /* only use first one */
|
|
|
|
hbaline->ldapscope = urldata->lud_scope;
|
|
|
|
if (urldata->lud_filter)
|
2017-09-12 15:46:14 +02:00
|
|
|
hbaline->ldapsearchfilter = pstrdup(urldata->lud_filter);
|
2012-12-04 05:29:56 +01:00
|
|
|
ldap_free_urldesc(urldata);
|
|
|
|
#else /* not OpenLDAP */
|
2017-01-31 00:00:26 +01:00
|
|
|
ereport(elevel,
|
2012-12-04 05:29:56 +01:00
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("LDAP URLs not supported on this platform")));
|
2017-01-31 00:00:26 +01:00
|
|
|
*err_msg = "LDAP URLs not supported on this platform";
|
2012-12-04 05:29:56 +01:00
|
|
|
#endif /* not OpenLDAP */
|
|
|
|
}
|
2011-06-20 23:20:14 +02:00
|
|
|
else if (strcmp(name, "ldaptls") == 0)
|
|
|
|
{
|
|
|
|
REQUIRE_AUTH_OPTION(uaLDAP, "ldaptls", "ldap");
|
|
|
|
if (strcmp(val, "1") == 0)
|
|
|
|
hbaline->ldaptls = true;
|
|
|
|
else
|
|
|
|
hbaline->ldaptls = false;
|
|
|
|
}
|
2018-01-03 16:00:08 +01:00
|
|
|
else if (strcmp(name, "ldapscheme") == 0)
|
|
|
|
{
|
|
|
|
REQUIRE_AUTH_OPTION(uaLDAP, "ldapscheme", "ldap");
|
|
|
|
if (strcmp(val, "ldap") != 0 && strcmp(val, "ldaps") != 0)
|
|
|
|
ereport(elevel,
|
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
|
|
|
errmsg("invalid ldapscheme value: \"%s\"", val),
|
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2018-01-03 16:00:08 +01:00
|
|
|
hbaline->ldapscheme = pstrdup(val);
|
|
|
|
}
|
2011-06-20 23:20:14 +02:00
|
|
|
else if (strcmp(name, "ldapserver") == 0)
|
|
|
|
{
|
|
|
|
REQUIRE_AUTH_OPTION(uaLDAP, "ldapserver", "ldap");
|
|
|
|
hbaline->ldapserver = pstrdup(val);
|
|
|
|
}
|
|
|
|
else if (strcmp(name, "ldapport") == 0)
|
|
|
|
{
|
|
|
|
REQUIRE_AUTH_OPTION(uaLDAP, "ldapport", "ldap");
|
|
|
|
hbaline->ldapport = atoi(val);
|
|
|
|
if (hbaline->ldapport == 0)
|
|
|
|
{
|
2017-01-31 00:00:26 +01:00
|
|
|
ereport(elevel,
|
2011-06-20 23:20:14 +02:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
|
|
|
errmsg("invalid LDAP port number: \"%s\"", val),
|
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2017-01-31 00:00:26 +01:00
|
|
|
*err_msg = psprintf("invalid LDAP port number: \"%s\"", val);
|
2011-06-20 23:20:14 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (strcmp(name, "ldapbinddn") == 0)
|
|
|
|
{
|
|
|
|
REQUIRE_AUTH_OPTION(uaLDAP, "ldapbinddn", "ldap");
|
|
|
|
hbaline->ldapbinddn = pstrdup(val);
|
|
|
|
}
|
|
|
|
else if (strcmp(name, "ldapbindpasswd") == 0)
|
|
|
|
{
|
|
|
|
REQUIRE_AUTH_OPTION(uaLDAP, "ldapbindpasswd", "ldap");
|
|
|
|
hbaline->ldapbindpasswd = pstrdup(val);
|
|
|
|
}
|
|
|
|
else if (strcmp(name, "ldapsearchattribute") == 0)
|
|
|
|
{
|
|
|
|
REQUIRE_AUTH_OPTION(uaLDAP, "ldapsearchattribute", "ldap");
|
|
|
|
hbaline->ldapsearchattribute = pstrdup(val);
|
|
|
|
}
|
2017-09-12 15:46:14 +02:00
|
|
|
else if (strcmp(name, "ldapsearchfilter") == 0)
|
|
|
|
{
|
|
|
|
REQUIRE_AUTH_OPTION(uaLDAP, "ldapsearchfilter", "ldap");
|
|
|
|
hbaline->ldapsearchfilter = pstrdup(val);
|
|
|
|
}
|
2011-06-20 23:20:14 +02:00
|
|
|
else if (strcmp(name, "ldapbasedn") == 0)
|
|
|
|
{
|
|
|
|
REQUIRE_AUTH_OPTION(uaLDAP, "ldapbasedn", "ldap");
|
|
|
|
hbaline->ldapbasedn = pstrdup(val);
|
|
|
|
}
|
|
|
|
else if (strcmp(name, "ldapprefix") == 0)
|
|
|
|
{
|
|
|
|
REQUIRE_AUTH_OPTION(uaLDAP, "ldapprefix", "ldap");
|
|
|
|
hbaline->ldapprefix = pstrdup(val);
|
|
|
|
}
|
|
|
|
else if (strcmp(name, "ldapsuffix") == 0)
|
|
|
|
{
|
|
|
|
REQUIRE_AUTH_OPTION(uaLDAP, "ldapsuffix", "ldap");
|
|
|
|
hbaline->ldapsuffix = pstrdup(val);
|
|
|
|
}
|
|
|
|
else if (strcmp(name, "krb_realm") == 0)
|
|
|
|
{
|
2014-01-15 17:24:01 +01:00
|
|
|
if (hbaline->auth_method != uaGSS &&
|
2011-06-20 23:20:14 +02:00
|
|
|
hbaline->auth_method != uaSSPI)
|
2014-01-15 17:24:01 +01:00
|
|
|
INVALID_AUTH_OPTION("krb_realm", gettext_noop("gssapi and sspi"));
|
2011-06-20 23:20:14 +02:00
|
|
|
hbaline->krb_realm = pstrdup(val);
|
|
|
|
}
|
|
|
|
else if (strcmp(name, "include_realm") == 0)
|
|
|
|
{
|
2014-01-15 17:24:01 +01:00
|
|
|
if (hbaline->auth_method != uaGSS &&
|
2011-06-20 23:20:14 +02:00
|
|
|
hbaline->auth_method != uaSSPI)
|
2014-01-15 17:24:01 +01:00
|
|
|
INVALID_AUTH_OPTION("include_realm", gettext_noop("gssapi and sspi"));
|
2011-06-20 23:20:14 +02:00
|
|
|
if (strcmp(val, "1") == 0)
|
|
|
|
hbaline->include_realm = true;
|
|
|
|
else
|
|
|
|
hbaline->include_realm = false;
|
|
|
|
}
|
2016-04-08 20:23:52 +02:00
|
|
|
else if (strcmp(name, "compat_realm") == 0)
|
|
|
|
{
|
|
|
|
if (hbaline->auth_method != uaSSPI)
|
|
|
|
INVALID_AUTH_OPTION("compat_realm", gettext_noop("sspi"));
|
|
|
|
if (strcmp(val, "1") == 0)
|
|
|
|
hbaline->compat_realm = true;
|
|
|
|
else
|
|
|
|
hbaline->compat_realm = false;
|
|
|
|
}
|
|
|
|
else if (strcmp(name, "upn_username") == 0)
|
|
|
|
{
|
|
|
|
if (hbaline->auth_method != uaSSPI)
|
|
|
|
INVALID_AUTH_OPTION("upn_username", gettext_noop("sspi"));
|
|
|
|
if (strcmp(val, "1") == 0)
|
|
|
|
hbaline->upn_username = true;
|
|
|
|
else
|
|
|
|
hbaline->upn_username = false;
|
|
|
|
}
|
2017-03-22 17:55:16 +01:00
|
|
|
else if (strcmp(name, "radiusservers") == 0)
|
2011-06-20 23:20:14 +02:00
|
|
|
{
|
|
|
|
struct addrinfo *gai_result;
|
|
|
|
struct addrinfo hints;
|
|
|
|
int ret;
|
2017-03-22 17:55:16 +01:00
|
|
|
List *parsed_servers;
|
|
|
|
ListCell *l;
|
|
|
|
char *dupval = pstrdup(val);
|
2011-06-20 23:20:14 +02:00
|
|
|
|
2017-03-22 17:55:16 +01:00
|
|
|
REQUIRE_AUTH_OPTION(uaRADIUS, "radiusservers", "radius");
|
2011-06-20 23:20:14 +02:00
|
|
|
|
2019-11-13 19:41:04 +01:00
|
|
|
if (!SplitGUCList(dupval, ',', &parsed_servers))
|
2011-06-20 23:20:14 +02:00
|
|
|
{
|
2017-03-22 17:55:16 +01:00
|
|
|
/* syntax error in list */
|
2017-01-31 00:00:26 +01:00
|
|
|
ereport(elevel,
|
2011-06-20 23:20:14 +02:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
2017-03-22 17:55:16 +01:00
|
|
|
errmsg("could not parse RADIUS server list \"%s\"",
|
|
|
|
val),
|
2011-06-20 23:20:14 +02:00
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2011-06-20 23:20:14 +02:00
|
|
|
return false;
|
|
|
|
}
|
2017-03-22 17:55:16 +01:00
|
|
|
|
|
|
|
/* For each entry in the list, translate it */
|
|
|
|
foreach(l, parsed_servers)
|
|
|
|
{
|
|
|
|
MemSet(&hints, 0, sizeof(hints));
|
|
|
|
hints.ai_socktype = SOCK_DGRAM;
|
|
|
|
hints.ai_family = AF_UNSPEC;
|
|
|
|
|
|
|
|
ret = pg_getaddrinfo_all((char *) lfirst(l), 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",
|
|
|
|
(char *) lfirst(l), gai_strerror(ret)),
|
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2017-03-22 17:55:16 +01:00
|
|
|
if (gai_result)
|
|
|
|
pg_freeaddrinfo_all(hints.ai_family, gai_result);
|
|
|
|
|
|
|
|
list_free(parsed_servers);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
pg_freeaddrinfo_all(hints.ai_family, gai_result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* All entries are OK, so store them */
|
|
|
|
hbaline->radiusservers = parsed_servers;
|
|
|
|
hbaline->radiusservers_s = pstrdup(val);
|
2011-06-20 23:20:14 +02:00
|
|
|
}
|
2017-03-22 17:55:16 +01:00
|
|
|
else if (strcmp(name, "radiusports") == 0)
|
2011-06-20 23:20:14 +02:00
|
|
|
{
|
2017-03-22 17:55:16 +01:00
|
|
|
List *parsed_ports;
|
|
|
|
ListCell *l;
|
|
|
|
char *dupval = pstrdup(val);
|
|
|
|
|
|
|
|
REQUIRE_AUTH_OPTION(uaRADIUS, "radiusports", "radius");
|
|
|
|
|
2019-11-13 19:41:04 +01:00
|
|
|
if (!SplitGUCList(dupval, ',', &parsed_ports))
|
2011-06-20 23:20:14 +02:00
|
|
|
{
|
2017-01-31 00:00:26 +01:00
|
|
|
ereport(elevel,
|
2011-06-20 23:20:14 +02:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
2017-03-22 17:55:16 +01:00
|
|
|
errmsg("could not parse RADIUS port list \"%s\"",
|
|
|
|
val),
|
2011-06-20 23:20:14 +02:00
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2017-01-31 00:00:26 +01:00
|
|
|
*err_msg = psprintf("invalid RADIUS port number: \"%s\"", val);
|
2011-06-20 23:20:14 +02:00
|
|
|
return false;
|
|
|
|
}
|
2017-03-22 17:55:16 +01:00
|
|
|
|
|
|
|
foreach(l, parsed_ports)
|
|
|
|
{
|
|
|
|
if (atoi(lfirst(l)) == 0)
|
|
|
|
{
|
|
|
|
ereport(elevel,
|
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
|
|
|
errmsg("invalid RADIUS port number: \"%s\"", val),
|
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2017-03-22 17:55:16 +01:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
hbaline->radiusports = parsed_ports;
|
|
|
|
hbaline->radiusports_s = pstrdup(val);
|
2011-06-20 23:20:14 +02:00
|
|
|
}
|
2017-03-22 17:55:16 +01:00
|
|
|
else if (strcmp(name, "radiussecrets") == 0)
|
2011-06-20 23:20:14 +02:00
|
|
|
{
|
2017-03-22 17:55:16 +01:00
|
|
|
List *parsed_secrets;
|
|
|
|
char *dupval = pstrdup(val);
|
|
|
|
|
|
|
|
REQUIRE_AUTH_OPTION(uaRADIUS, "radiussecrets", "radius");
|
|
|
|
|
2019-11-13 19:41:04 +01:00
|
|
|
if (!SplitGUCList(dupval, ',', &parsed_secrets))
|
2017-03-22 17:55:16 +01:00
|
|
|
{
|
|
|
|
/* syntax error in list */
|
|
|
|
ereport(elevel,
|
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
|
|
|
errmsg("could not parse RADIUS secret list \"%s\"",
|
|
|
|
val),
|
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2017-03-22 17:55:16 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
hbaline->radiussecrets = parsed_secrets;
|
|
|
|
hbaline->radiussecrets_s = pstrdup(val);
|
2011-06-20 23:20:14 +02:00
|
|
|
}
|
2017-03-22 17:55:16 +01:00
|
|
|
else if (strcmp(name, "radiusidentifiers") == 0)
|
2011-06-20 23:20:14 +02:00
|
|
|
{
|
2017-03-22 17:55:16 +01:00
|
|
|
List *parsed_identifiers;
|
|
|
|
char *dupval = pstrdup(val);
|
|
|
|
|
|
|
|
REQUIRE_AUTH_OPTION(uaRADIUS, "radiusidentifiers", "radius");
|
|
|
|
|
2019-11-13 19:41:04 +01:00
|
|
|
if (!SplitGUCList(dupval, ',', &parsed_identifiers))
|
2017-03-22 17:55:16 +01:00
|
|
|
{
|
|
|
|
/* syntax error in list */
|
|
|
|
ereport(elevel,
|
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
|
|
|
errmsg("could not parse RADIUS identifiers list \"%s\"",
|
|
|
|
val),
|
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2017-03-22 17:55:16 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
hbaline->radiusidentifiers = parsed_identifiers;
|
|
|
|
hbaline->radiusidentifiers_s = pstrdup(val);
|
2011-06-20 23:20:14 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-01-31 00:00:26 +01:00
|
|
|
ereport(elevel,
|
2011-06-20 23:20:14 +02:00
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
|
|
|
errmsg("unrecognized authentication option name: \"%s\"",
|
|
|
|
name),
|
|
|
|
errcontext("line %d of configuration file \"%s\"",
|
2022-10-26 04:36:21 +02:00
|
|
|
line_num, file_name)));
|
2017-01-31 00:00:26 +01:00
|
|
|
*err_msg = psprintf("unrecognized authentication option name: \"%s\"",
|
|
|
|
name);
|
2011-06-20 23:20:14 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Scan the pre-parsed hba file, looking for a match to the port's connection
|
|
|
|
* request.
|
|
|
|
*/
|
|
|
|
static void
|
2001-07-30 16:50:24 +02:00
|
|
|
check_hba(hbaPort *port)
|
1997-03-12 22:23:16 +01:00
|
|
|
{
|
2009-08-29 21:26:52 +02:00
|
|
|
Oid roleid;
|
2004-05-26 06:41:50 +02:00
|
|
|
ListCell *line;
|
2008-09-15 14:32:57 +02:00
|
|
|
HbaLine *hba;
|
1999-05-25 18:15:34 +02:00
|
|
|
|
2009-08-29 21:26:52 +02:00
|
|
|
/* Get the target role's OID. Note we do not error out for bad role. */
|
2010-08-05 16:45:09 +02:00
|
|
|
roleid = get_role_oid(port->user_name, true);
|
2009-08-29 21:26:52 +02:00
|
|
|
|
2008-09-15 14:32:57 +02:00
|
|
|
foreach(line, parsed_hba_lines)
|
2001-07-30 16:50:24 +02:00
|
|
|
{
|
2008-09-15 14:32:57 +02:00
|
|
|
hba = (HbaLine *) lfirst(line);
|
1998-01-26 02:42:53 +01:00
|
|
|
|
2008-09-15 14:32:57 +02:00
|
|
|
/* Check connection type */
|
|
|
|
if (hba->conntype == ctLocal)
|
|
|
|
{
|
2022-02-15 10:03:52 +01:00
|
|
|
if (port->raddr.addr.ss_family != AF_UNIX)
|
2008-09-15 14:32:57 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-02-15 10:03:52 +01:00
|
|
|
if (port->raddr.addr.ss_family == AF_UNIX)
|
2008-09-15 14:32:57 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Check SSL state */
|
Break out OpenSSL-specific code to separate files.
This refactoring is in preparation for adding support for other SSL
implementations, with no user-visible effects. There are now two #defines,
USE_OPENSSL which is defined when building with OpenSSL, and USE_SSL which
is defined when building with any SSL implementation. Currently, OpenSSL is
the only implementation so the two #defines go together, but USE_SSL is
supposed to be used for implementation-independent code.
The libpq SSL code is changed to use a custom BIO, which does all the raw
I/O, like we've been doing in the backend for a long time. That makes it
possible to use MSG_NOSIGNAL to block SIGPIPE when using SSL, which avoids
a couple of syscall for each send(). Probably doesn't make much performance
difference in practice - the SSL encryption is expensive enough to mask the
effect - but it was a natural result of this refactoring.
Based on a patch by Martijn van Oosterhout from 2006. Briefly reviewed by
Alvaro Herrera, Andreas Karlsson, Jeff Janes.
2014-08-11 10:54:19 +02:00
|
|
|
if (port->ssl_in_use)
|
2008-09-15 14:32:57 +02:00
|
|
|
{
|
|
|
|
/* Connection is SSL, match both "host" and "hostssl" */
|
|
|
|
if (hba->conntype == ctHostNoSSL)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Connection is not SSL, match both "host" and "hostnossl" */
|
|
|
|
if (hba->conntype == ctHostSSL)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
GSSAPI encryption support
On both the frontend and backend, prepare for GSSAPI encryption
support by moving common code for error handling into a separate file.
Fix a TODO for handling multiple status messages in the process.
Eliminate the OIDs, which have not been needed for some time.
Add frontend and backend encryption support functions. Keep the
context initiation for authentication-only separate on both the
frontend and backend in order to avoid concerns about changing the
requested flags to include encryption support.
In postmaster, pull GSSAPI authorization checking into a shared
function. Also share the initiator name between the encryption and
non-encryption codepaths.
For HBA, add "hostgssenc" and "hostnogssenc" entries that behave
similarly to their SSL counterparts. "hostgssenc" requires either
"gss", "trust", or "reject" for its authentication.
Similarly, add a "gssencmode" parameter to libpq. Supported values are
"disable", "require", and "prefer". Notably, negotiation will only be
attempted if credentials can be acquired. Move credential acquisition
into its own function to support this behavior.
Add a simple pg_stat_gssapi view similar to pg_stat_ssl, for monitoring
if GSSAPI authentication was used, what principal was used, and if
encryption is being used on the connection.
Finally, add documentation for everything new, and update existing
documentation on connection security.
Thanks to Michael Paquier for the Windows fixes.
Author: Robbie Harwood, with changes to the read/write functions by me.
Reviewed in various forms and at different times by: Michael Paquier,
Andres Freund, David Steele.
Discussion: https://www.postgresql.org/message-id/flat/jlg1tgq1ktm.fsf@thriss.redhat.com
2019-04-03 21:02:33 +02:00
|
|
|
/* Check GSSAPI state */
|
|
|
|
#ifdef ENABLE_GSS
|
2020-12-28 23:44:17 +01:00
|
|
|
if (port->gss && port->gss->enc &&
|
|
|
|
hba->conntype == ctHostNoGSS)
|
GSSAPI encryption support
On both the frontend and backend, prepare for GSSAPI encryption
support by moving common code for error handling into a separate file.
Fix a TODO for handling multiple status messages in the process.
Eliminate the OIDs, which have not been needed for some time.
Add frontend and backend encryption support functions. Keep the
context initiation for authentication-only separate on both the
frontend and backend in order to avoid concerns about changing the
requested flags to include encryption support.
In postmaster, pull GSSAPI authorization checking into a shared
function. Also share the initiator name between the encryption and
non-encryption codepaths.
For HBA, add "hostgssenc" and "hostnogssenc" entries that behave
similarly to their SSL counterparts. "hostgssenc" requires either
"gss", "trust", or "reject" for its authentication.
Similarly, add a "gssencmode" parameter to libpq. Supported values are
"disable", "require", and "prefer". Notably, negotiation will only be
attempted if credentials can be acquired. Move credential acquisition
into its own function to support this behavior.
Add a simple pg_stat_gssapi view similar to pg_stat_ssl, for monitoring
if GSSAPI authentication was used, what principal was used, and if
encryption is being used on the connection.
Finally, add documentation for everything new, and update existing
documentation on connection security.
Thanks to Michael Paquier for the Windows fixes.
Author: Robbie Harwood, with changes to the read/write functions by me.
Reviewed in various forms and at different times by: Michael Paquier,
Andres Freund, David Steele.
Discussion: https://www.postgresql.org/message-id/flat/jlg1tgq1ktm.fsf@thriss.redhat.com
2019-04-03 21:02:33 +02:00
|
|
|
continue;
|
2020-12-28 23:44:17 +01:00
|
|
|
else if (!(port->gss && port->gss->enc) &&
|
|
|
|
hba->conntype == ctHostGSS)
|
GSSAPI encryption support
On both the frontend and backend, prepare for GSSAPI encryption
support by moving common code for error handling into a separate file.
Fix a TODO for handling multiple status messages in the process.
Eliminate the OIDs, which have not been needed for some time.
Add frontend and backend encryption support functions. Keep the
context initiation for authentication-only separate on both the
frontend and backend in order to avoid concerns about changing the
requested flags to include encryption support.
In postmaster, pull GSSAPI authorization checking into a shared
function. Also share the initiator name between the encryption and
non-encryption codepaths.
For HBA, add "hostgssenc" and "hostnogssenc" entries that behave
similarly to their SSL counterparts. "hostgssenc" requires either
"gss", "trust", or "reject" for its authentication.
Similarly, add a "gssencmode" parameter to libpq. Supported values are
"disable", "require", and "prefer". Notably, negotiation will only be
attempted if credentials can be acquired. Move credential acquisition
into its own function to support this behavior.
Add a simple pg_stat_gssapi view similar to pg_stat_ssl, for monitoring
if GSSAPI authentication was used, what principal was used, and if
encryption is being used on the connection.
Finally, add documentation for everything new, and update existing
documentation on connection security.
Thanks to Michael Paquier for the Windows fixes.
Author: Robbie Harwood, with changes to the read/write functions by me.
Reviewed in various forms and at different times by: Michael Paquier,
Andres Freund, David Steele.
Discussion: https://www.postgresql.org/message-id/flat/jlg1tgq1ktm.fsf@thriss.redhat.com
2019-04-03 21:02:33 +02:00
|
|
|
continue;
|
|
|
|
#else
|
|
|
|
if (hba->conntype == ctHostGSS)
|
|
|
|
continue;
|
|
|
|
#endif
|
|
|
|
|
2008-09-15 14:32:57 +02:00
|
|
|
/* Check IP address */
|
2009-10-01 03:58:58 +02:00
|
|
|
switch (hba->ip_cmp_method)
|
2008-09-15 14:32:57 +02:00
|
|
|
{
|
2009-10-01 03:58:58 +02:00
|
|
|
case ipCmpMask:
|
2010-10-15 21:53:39 +02:00
|
|
|
if (hba->hostname)
|
|
|
|
{
|
|
|
|
if (!check_hostname(port,
|
|
|
|
hba->hostname))
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!check_ip(&port->raddr,
|
|
|
|
(struct sockaddr *) &hba->addr,
|
|
|
|
(struct sockaddr *) &hba->mask))
|
|
|
|
continue;
|
|
|
|
}
|
2009-10-01 03:58:58 +02:00
|
|
|
break;
|
2010-10-18 21:14:47 +02:00
|
|
|
case ipCmpAll:
|
|
|
|
break;
|
2009-10-01 03:58:58 +02:00
|
|
|
case ipCmpSameHost:
|
|
|
|
case ipCmpSameNet:
|
|
|
|
if (!check_same_host_or_net(&port->raddr,
|
|
|
|
hba->ip_cmp_method))
|
|
|
|
continue;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* shouldn't get here, but deem it no-match if so */
|
2008-09-15 14:32:57 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} /* != ctLocal */
|
|
|
|
|
|
|
|
/* Check database and role */
|
2009-08-29 21:26:52 +02:00
|
|
|
if (!check_db(port->database_name, port->user_name, roleid,
|
2011-06-20 23:20:14 +02:00
|
|
|
hba->databases))
|
2008-09-15 14:32:57 +02:00
|
|
|
continue;
|
|
|
|
|
Support the same patterns for pg-user in pg_ident.conf as in pg_hba.conf
While pg_hba.conf has support for non-literal username matches, and
this commit extends the capabilities that are supported for the
PostgreSQL user listed in an ident entry part of pg_ident.conf, with
support for:
1. The "all" keyword, where all the requested users are allowed.
2. Membership checks using the + prefix.
3. Using a regex to match against multiple roles.
1. is a feature that has been requested by Jelte Fennema, 2. something
that has been mentioned independently by Andrew Dunstan, and 3. is
something I came up with while discussing how to extend the first one,
whose implementation is facilitated by 8fea868.
This allows matching certain system users against many different
postgres users with a single line in pg_ident.conf. Without this, one
would need one line for each of the postgres users that a system user
can log in as, which can be cumbersome to maintain.
Tests are added to the TAP test of peer authentication to provide
coverage for all that.
Note that this introduces a set of backward-incompatible changes to be
able to detect the new patterns, for the following cases:
- A role named "all".
- A role prefixed with '+' characters, which is something that would not
have worked in HBA entries anyway.
- A role prefixed by a slash character, similarly to 8fea868.
Any of these can be still be handled by using quotes in the Postgres
role defined in an ident entry.
A huge advantage of this change is that the code applies the same checks
for the Postgres roles in HBA and ident entries, via the common routine
check_role().
**This compatibility change should be mentioned in the release notes.**
Author: Jelte Fennema
Discussion: https://postgr.es/m/DBBPR83MB0507FEC2E8965012990A80D0F7FC9@DBBPR83MB0507.EURPRD83.prod.outlook.com
2023-01-20 03:21:55 +01:00
|
|
|
if (!check_role(port->user_name, roleid, hba->roles, false))
|
2008-09-15 14:32:57 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Found a record that matched! */
|
|
|
|
port->hba = hba;
|
2011-06-20 23:20:14 +02:00
|
|
|
return;
|
1998-01-27 04:25:14 +01:00
|
|
|
}
|
2008-09-15 14:32:57 +02:00
|
|
|
|
2010-04-19 21:02:18 +02:00
|
|
|
/* If no matching entry was found, then implicitly reject. */
|
2008-09-15 14:32:57 +02:00
|
|
|
hba = palloc0(sizeof(HbaLine));
|
2010-04-19 21:02:18 +02:00
|
|
|
hba->auth_method = uaImplicitReject;
|
2008-09-15 14:32:57 +02:00
|
|
|
port->hba = hba;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read the config file and create a List of HbaLine records for the contents.
|
|
|
|
*
|
2011-10-19 02:09:18 +02:00
|
|
|
* The configuration is read into a temporary list, and if any parse error
|
|
|
|
* occurs the old list is kept in place and false is returned. Only if the
|
|
|
|
* whole file parses OK is the list replaced, and the function returns true.
|
|
|
|
*
|
|
|
|
* On a false result, caller will take care of reporting a FATAL error in case
|
|
|
|
* this is the initial startup. If it happens on reload, we just keep running
|
|
|
|
* with the old data.
|
2008-09-15 14:32:57 +02:00
|
|
|
*/
|
|
|
|
bool
|
2001-08-01 00:55:45 +02:00
|
|
|
load_hba(void)
|
2001-07-30 16:50:24 +02:00
|
|
|
{
|
2004-10-10 01:13:22 +02:00
|
|
|
FILE *file;
|
2008-09-15 14:32:57 +02:00
|
|
|
List *hba_lines = NIL;
|
2017-01-27 19:43:00 +01:00
|
|
|
ListCell *line;
|
2008-09-15 14:32:57 +02:00
|
|
|
List *new_parsed_lines = NIL;
|
2009-03-07 22:28:00 +01:00
|
|
|
bool ok = true;
|
2011-06-20 23:20:14 +02:00
|
|
|
MemoryContext oldcxt;
|
|
|
|
MemoryContext hbacxt;
|
2001-10-25 07:50:21 +02:00
|
|
|
|
Invent open_auth_file() in hba.c to refactor authentication file opening
This adds a check on the recursion depth when including authentication
configuration files, something that has never been done when processing
'@' files for database and user name lists in pg_hba.conf. On HEAD,
this was leading to a rather confusing error, as of:
FATAL: exceeded maxAllocatedDescs (NN) while trying to open file "/path/blah.conf"
This refactors the code so as the error reported is now the following,
which is the same as for GUCs:
FATAL: could not open file "/path/blah.conf": maximum nesting depth exceeded
This reduces a bit the verbosity of the error message used for files
included in user and database lists, reporting only the file name of
what's failing to load, without mentioning the relative or absolute path
specified after '@' in a HBA file. The absolute path is built upon what
'@' defines anyway, so there is no actual loss of information. This
makes the future inclusion logic much simpler. A follow-up patch will
add an error context to be able to track on which line of which file the
inclusion is failing, to close the loop, providing all the information
needed to know the full chain of events.
This logic has been extracted from a larger patch written by Julien,
rewritten by me to have a unique code path calling AllocateFile() on
authentication files, and is useful on its own. This new interface
will be used later for authentication files included with
@include[_dir,_if_exists], in a follow-up patch.
Author: Michael Paquier, Julien Rouhaud
Discussion: https://www.postgresql.org/message-id/Y2xUBJ+S+Z0zbxRW@paquier.xyz
2022-11-14 02:21:42 +01:00
|
|
|
file = open_auth_file(HbaFileName, LOG, 0, NULL);
|
2002-04-04 06:25:54 +02:00
|
|
|
if (file == NULL)
|
2009-03-04 09:43:15 +01:00
|
|
|
{
|
Invent open_auth_file() in hba.c to refactor authentication file opening
This adds a check on the recursion depth when including authentication
configuration files, something that has never been done when processing
'@' files for database and user name lists in pg_hba.conf. On HEAD,
this was leading to a rather confusing error, as of:
FATAL: exceeded maxAllocatedDescs (NN) while trying to open file "/path/blah.conf"
This refactors the code so as the error reported is now the following,
which is the same as for GUCs:
FATAL: could not open file "/path/blah.conf": maximum nesting depth exceeded
This reduces a bit the verbosity of the error message used for files
included in user and database lists, reporting only the file name of
what's failing to load, without mentioning the relative or absolute path
specified after '@' in a HBA file. The absolute path is built upon what
'@' defines anyway, so there is no actual loss of information. This
makes the future inclusion logic much simpler. A follow-up patch will
add an error context to be able to track on which line of which file the
inclusion is failing, to close the loop, providing all the information
needed to know the full chain of events.
This logic has been extracted from a larger patch written by Julien,
rewritten by me to have a unique code path calling AllocateFile() on
authentication files, and is useful on its own. This new interface
will be used later for authentication files included with
@include[_dir,_if_exists], in a follow-up patch.
Author: Michael Paquier, Julien Rouhaud
Discussion: https://www.postgresql.org/message-id/Y2xUBJ+S+Z0zbxRW@paquier.xyz
2022-11-14 02:21:42 +01:00
|
|
|
/* error already logged */
|
2009-03-04 09:43:15 +01:00
|
|
|
return false;
|
|
|
|
}
|
2002-12-14 19:49:37 +01:00
|
|
|
|
2022-11-24 00:21:55 +01:00
|
|
|
tokenize_auth_file(HbaFileName, file, &hba_lines, LOG, 0);
|
2008-09-15 14:32:57 +02:00
|
|
|
|
|
|
|
/* Now parse all the lines */
|
2015-07-02 00:55:39 +02:00
|
|
|
Assert(PostmasterContext);
|
|
|
|
hbacxt = AllocSetContextCreate(PostmasterContext,
|
2011-06-20 23:20:14 +02:00
|
|
|
"hba parser context",
|
Add macros to make AllocSetContextCreate() calls simpler and safer.
I found that half a dozen (nearly 5%) of our AllocSetContextCreate calls
had typos in the context-sizing parameters. While none of these led to
especially significant problems, they did create minor inefficiencies,
and it's now clear that expecting people to copy-and-paste those calls
accurately is not a great idea. Let's reduce the risk of future errors
by introducing single macros that encapsulate the common use-cases.
Three such macros are enough to cover all but two special-purpose contexts;
those two calls can be left as-is, I think.
While this patch doesn't in itself improve matters for third-party
extensions, it doesn't break anything for them either, and they can
gradually adopt the simplified notation over time.
In passing, change TopMemoryContext to use the default allocation
parameters. Formerly it could only be extended 8K at a time. That was
probably reasonable when this code was written; but nowadays we create
many more contexts than we did then, so that it's not unusual to have a
couple hundred K in TopMemoryContext, even without considering various
dubious code that sticks other things there. There seems no good reason
not to let it use growing blocks like most other contexts.
Back-patch to 9.6, mostly because that's still close enough to HEAD that
it's easy to do so, and keeping the branches in sync can be expected to
avoid some future back-patching pain. The bugs fixed by these changes
don't seem to be significant enough to justify fixing them further back.
Discussion: <21072.1472321324@sss.pgh.pa.us>
2016-08-27 23:50:38 +02:00
|
|
|
ALLOCSET_SMALL_SIZES);
|
2011-06-20 23:20:14 +02:00
|
|
|
oldcxt = MemoryContextSwitchTo(hbacxt);
|
2017-01-27 19:43:00 +01:00
|
|
|
foreach(line, hba_lines)
|
2008-09-15 14:32:57 +02:00
|
|
|
{
|
Refactor code related to pg_hba_file_rules() into new file
hba.c is growing big, and more contents are planned for it. In order to
prepare for this future work, this commit moves all the code related to
the system function processing the contents of pg_hba.conf,
pg_hba_file_rules() to a new file called hbafuncs.c, which will be used
as the location for the SQL portion of the authentication file parsing.
While on it, HbaToken, the structure holding a string token lexed from a
configuration file related to authentication, is renamed to a more
generic AuthToken, as it gets used not only for pg_hba.conf, but also
for pg_ident.conf. TokenizedLine is now named TokenizedAuthLine.
The size of hba.c is reduced by ~12%.
Author: Julien Rouhaud
Reviewed-by: Aleksander Alekseev, Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-03-24 04:42:30 +01:00
|
|
|
TokenizedAuthLine *tok_line = (TokenizedAuthLine *) lfirst(line);
|
2008-09-15 14:32:57 +02:00
|
|
|
HbaLine *newline;
|
|
|
|
|
2017-01-31 00:00:26 +01:00
|
|
|
/* don't parse lines that already have errors */
|
|
|
|
if (tok_line->err_msg != NULL)
|
2008-09-15 14:32:57 +02:00
|
|
|
{
|
2017-01-31 00:00:26 +01:00
|
|
|
ok = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((newline = parse_hba_line(tok_line, LOG)) == NULL)
|
|
|
|
{
|
|
|
|
/* Parse error; remember there's trouble */
|
2009-10-03 22:04:39 +02:00
|
|
|
ok = false;
|
2009-03-07 22:28:00 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Keep parsing the rest of the file so we can report errors on
|
2017-01-31 00:00:26 +01:00
|
|
|
* more than the first line. Error has already been logged, no
|
|
|
|
* need for more chatter here.
|
2009-03-07 22:28:00 +01:00
|
|
|
*/
|
|
|
|
continue;
|
2008-09-15 14:32:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
new_parsed_lines = lappend(new_parsed_lines, newline);
|
|
|
|
}
|
|
|
|
|
2011-10-19 02:09:18 +02:00
|
|
|
/*
|
|
|
|
* A valid HBA file must have at least one entry; else there's no way to
|
|
|
|
* connect to the postmaster. But only complain about this if we didn't
|
|
|
|
* already have parsing errors.
|
|
|
|
*/
|
|
|
|
if (ok && new_parsed_lines == NIL)
|
|
|
|
{
|
|
|
|
ereport(LOG,
|
|
|
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
|
|
|
errmsg("configuration file \"%s\" contains no entries",
|
|
|
|
HbaFileName)));
|
|
|
|
ok = false;
|
|
|
|
}
|
|
|
|
|
2011-06-20 23:20:14 +02:00
|
|
|
/* Free tokenizer memory */
|
2022-11-24 00:21:55 +01:00
|
|
|
free_auth_file(file, 0);
|
2011-06-20 23:20:14 +02:00
|
|
|
MemoryContextSwitchTo(oldcxt);
|
2009-10-03 22:04:39 +02:00
|
|
|
|
2009-03-07 22:28:00 +01:00
|
|
|
if (!ok)
|
|
|
|
{
|
Add support for regexps on database and user entries in pg_hba.conf
As of this commit, any database or user entry beginning with a slash (/)
is considered as a regular expression. This is particularly useful for
users, as now there is no clean way to match pattern on multiple HBA
lines. For example, a user name mapping with a regular expression needs
first to match with a HBA line, and we would skip the follow-up HBA
entries if the ident regexp does *not* match with what has matched in
the HBA line.
pg_hba.conf is able to handle multiple databases and roles with a
comma-separated list of these, hence individual regular expressions that
include commas need to be double-quoted.
At authentication time, user and database names are now checked in the
following order:
- Arbitrary keywords (like "all", the ones beginning by '+' for
membership check), that we know will never have a regexp. A fancy case
is for physical WAL senders, we *have* to only match "replication" for
the database.
- Regular expression matching.
- Exact match.
The previous logic did the same, but without the regexp step.
We have discussed as well the possibility to support regexp pattern
matching for host names, but these happen to lead to tricky issues based
on what I understand, particularly with host entries that have CIDRs.
This commit relies heavily on the refactoring done in a903971 and
fc579e1, so as the amount of code required to compile and execute
regular expressions is now minimal. When parsing pg_hba.conf, all the
computed regexps needs to explicitely free()'d, same as pg_ident.conf.
Documentation and TAP tests are added to cover this feature, including
cases where the regexps use commas (for clarity in the docs, coverage
for the parsing logic in the tests).
Note that this introduces a breakage with older versions, where a
database or user name beginning with a slash are treated as something to
check for an equal match. Per discussion, we have discarded this as
being much of an issue in practice as it would require a cluster to
have database and/or role names that begin with a slash, as well as HBA
entries using these. Hence, the consistency gained with regexps in
pg_ident.conf is more appealing in the long term.
**This compatibility change should be mentioned in the release notes.**
Author: Bertrand Drouvot
Reviewed-by: Jacob Champion, Tom Lane, Michael Paquier
Discussion: https://postgr.es/m/fff0d7c1-8ad4-76a1-9db3-0ab6ec338bf7@amazon.com
2022-10-24 04:45:31 +02:00
|
|
|
/*
|
2023-05-19 23:24:48 +02:00
|
|
|
* File contained one or more errors, so bail out.
|
|
|
|
* MemoryContextDelete is enough to clean up everything, including
|
|
|
|
* regexes.
|
Add support for regexps on database and user entries in pg_hba.conf
As of this commit, any database or user entry beginning with a slash (/)
is considered as a regular expression. This is particularly useful for
users, as now there is no clean way to match pattern on multiple HBA
lines. For example, a user name mapping with a regular expression needs
first to match with a HBA line, and we would skip the follow-up HBA
entries if the ident regexp does *not* match with what has matched in
the HBA line.
pg_hba.conf is able to handle multiple databases and roles with a
comma-separated list of these, hence individual regular expressions that
include commas need to be double-quoted.
At authentication time, user and database names are now checked in the
following order:
- Arbitrary keywords (like "all", the ones beginning by '+' for
membership check), that we know will never have a regexp. A fancy case
is for physical WAL senders, we *have* to only match "replication" for
the database.
- Regular expression matching.
- Exact match.
The previous logic did the same, but without the regexp step.
We have discussed as well the possibility to support regexp pattern
matching for host names, but these happen to lead to tricky issues based
on what I understand, particularly with host entries that have CIDRs.
This commit relies heavily on the refactoring done in a903971 and
fc579e1, so as the amount of code required to compile and execute
regular expressions is now minimal. When parsing pg_hba.conf, all the
computed regexps needs to explicitely free()'d, same as pg_ident.conf.
Documentation and TAP tests are added to cover this feature, including
cases where the regexps use commas (for clarity in the docs, coverage
for the parsing logic in the tests).
Note that this introduces a breakage with older versions, where a
database or user name beginning with a slash are treated as something to
check for an equal match. Per discussion, we have discarded this as
being much of an issue in practice as it would require a cluster to
have database and/or role names that begin with a slash, as well as HBA
entries using these. Hence, the consistency gained with regexps in
pg_ident.conf is more appealing in the long term.
**This compatibility change should be mentioned in the release notes.**
Author: Bertrand Drouvot
Reviewed-by: Jacob Champion, Tom Lane, Michael Paquier
Discussion: https://postgr.es/m/fff0d7c1-8ad4-76a1-9db3-0ab6ec338bf7@amazon.com
2022-10-24 04:45:31 +02:00
|
|
|
*/
|
2011-06-20 23:20:14 +02:00
|
|
|
MemoryContextDelete(hbacxt);
|
2009-03-07 22:28:00 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-09-15 14:32:57 +02:00
|
|
|
/* Loaded new file successfully, replace the one we use */
|
2011-06-20 23:20:14 +02:00
|
|
|
if (parsed_hba_context != NULL)
|
|
|
|
MemoryContextDelete(parsed_hba_context);
|
|
|
|
parsed_hba_context = hbacxt;
|
2008-09-15 14:32:57 +02:00
|
|
|
parsed_hba_lines = new_parsed_lines;
|
|
|
|
|
|
|
|
return true;
|
1996-10-12 09:47:12 +02:00
|
|
|
}
|
|
|
|
|
2017-01-31 00:00:26 +01:00
|
|
|
|
2001-07-30 16:50:24 +02:00
|
|
|
/*
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
* Parse one tokenised line from the ident config file and store the result in
|
2017-01-27 19:43:00 +01:00
|
|
|
* an IdentLine structure.
|
2001-08-01 00:55:45 +02:00
|
|
|
*
|
2022-03-29 03:15:48 +02:00
|
|
|
* If parsing fails, log a message at ereport level elevel, store an error
|
|
|
|
* string in tok_line->err_msg and return NULL.
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
*
|
|
|
|
* If ident_user is a regular expression (ie. begins with a slash), it is
|
|
|
|
* compiled and stored in IdentLine structure.
|
|
|
|
*
|
|
|
|
* 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.
|
2001-07-30 16:50:24 +02:00
|
|
|
*/
|
2022-03-29 03:15:48 +02:00
|
|
|
IdentLine *
|
|
|
|
parse_ident_line(TokenizedAuthLine *tok_line, int elevel)
|
2001-07-30 16:50:24 +02:00
|
|
|
{
|
2017-01-27 19:43:00 +01:00
|
|
|
int line_num = tok_line->line_num;
|
2022-10-26 04:36:21 +02:00
|
|
|
char *file_name = tok_line->file_name;
|
2022-03-29 03:15:48 +02:00
|
|
|
char **err_msg = &tok_line->err_msg;
|
2011-06-20 23:20:14 +02:00
|
|
|
ListCell *field;
|
|
|
|
List *tokens;
|
Refactor code related to pg_hba_file_rules() into new file
hba.c is growing big, and more contents are planned for it. In order to
prepare for this future work, this commit moves all the code related to
the system function processing the contents of pg_hba.conf,
pg_hba_file_rules() to a new file called hbafuncs.c, which will be used
as the location for the SQL portion of the authentication file parsing.
While on it, HbaToken, the structure holding a string token lexed from a
configuration file related to authentication, is renamed to a more
generic AuthToken, as it gets used not only for pg_hba.conf, but also
for pg_ident.conf. TokenizedLine is now named TokenizedAuthLine.
The size of hba.c is reduced by ~12%.
Author: Julien Rouhaud
Reviewed-by: Aleksander Alekseev, Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-03-24 04:42:30 +01:00
|
|
|
AuthToken *token;
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
IdentLine *parsedline;
|
2001-07-30 16:50:24 +02:00
|
|
|
|
2017-01-27 19:43:00 +01:00
|
|
|
Assert(tok_line->fields != NIL);
|
|
|
|
field = list_head(tok_line->fields);
|
2001-08-01 00:55:45 +02:00
|
|
|
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
parsedline = palloc0(sizeof(IdentLine));
|
2017-01-27 19:43:00 +01:00
|
|
|
parsedline->linenumber = line_num;
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
|
2001-08-01 00:55:45 +02:00
|
|
|
/* Get the map token (must exist) */
|
2011-06-20 23:20:14 +02:00
|
|
|
tokens = lfirst(field);
|
|
|
|
IDENT_MULTI_VALUE(tokens);
|
|
|
|
token = linitial(tokens);
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
parsedline->usermap = pstrdup(token->string);
|
2001-07-30 16:50:24 +02:00
|
|
|
|
2005-06-21 03:20:09 +02:00
|
|
|
/* Get the ident user token */
|
Represent Lists as expansible arrays, not chains of cons-cells.
Originally, Postgres Lists were a more or less exact reimplementation of
Lisp lists, which consist of chains of separately-allocated cons cells,
each having a value and a next-cell link. We'd hacked that once before
(commit d0b4399d8) to add a separate List header, but the data was still
in cons cells. That makes some operations -- notably list_nth() -- O(N),
and it's bulky because of the next-cell pointers and per-cell palloc
overhead, and it's very cache-unfriendly if the cons cells end up
scattered around rather than being adjacent.
In this rewrite, we still have List headers, but the data is in a
resizable array of values, with no next-cell links. Now we need at
most two palloc's per List, and often only one, since we can allocate
some values in the same palloc call as the List header. (Of course,
extending an existing List may require repalloc's to enlarge the array.
But this involves just O(log N) allocations not O(N).)
Of course this is not without downsides. The key difficulty is that
addition or deletion of a list entry may now cause other entries to
move, which it did not before.
For example, that breaks foreach() and sister macros, which historically
used a pointer to the current cons-cell as loop state. We can repair
those macros transparently by making their actual loop state be an
integer list index; the exposed "ListCell *" pointer is no longer state
carried across loop iterations, but is just a derived value. (In
practice, modern compilers can optimize things back to having just one
loop state value, at least for simple cases with inline loop bodies.)
In principle, this is a semantics change for cases where the loop body
inserts or deletes list entries ahead of the current loop index; but
I found no such cases in the Postgres code.
The change is not at all transparent for code that doesn't use foreach()
but chases lists "by hand" using lnext(). The largest share of such
code in the backend is in loops that were maintaining "prev" and "next"
variables in addition to the current-cell pointer, in order to delete
list cells efficiently using list_delete_cell(). However, we no longer
need a previous-cell pointer to delete a list cell efficiently. Keeping
a next-cell pointer doesn't work, as explained above, but we can improve
matters by changing such code to use a regular foreach() loop and then
using the new macro foreach_delete_current() to delete the current cell.
(This macro knows how to update the associated foreach loop's state so
that no cells will be missed in the traversal.)
There remains a nontrivial risk of code assuming that a ListCell *
pointer will remain good over an operation that could now move the list
contents. To help catch such errors, list.c can be compiled with a new
define symbol DEBUG_LIST_MEMORY_USAGE that forcibly moves list contents
whenever that could possibly happen. This makes list operations
significantly more expensive so it's not normally turned on (though it
is on by default if USE_VALGRIND is on).
There are two notable API differences from the previous code:
* lnext() now requires the List's header pointer in addition to the
current cell's address.
* list_delete_cell() no longer requires a previous-cell argument.
These changes are somewhat unfortunate, but on the other hand code using
either function needs inspection to see if it is assuming anything
it shouldn't, so it's not all bad.
Programmers should be aware of these significant performance changes:
* list_nth() and related functions are now O(1); so there's no
major access-speed difference between a list and an array.
* Inserting or deleting a list element now takes time proportional to
the distance to the end of the list, due to moving the array elements.
(However, it typically *doesn't* require palloc or pfree, so except in
long lists it's probably still faster than before.) Notably, lcons()
used to be about the same cost as lappend(), but that's no longer true
if the list is long. Code that uses lcons() and list_delete_first()
to maintain a stack might usefully be rewritten to push and pop at the
end of the list rather than the beginning.
* There are now list_insert_nth...() and list_delete_nth...() functions
that add or remove a list cell identified by index. These have the
data-movement penalty explained above, but there's no search penalty.
* list_concat() and variants now copy the second list's data into
storage belonging to the first list, so there is no longer any
sharing of cells between the input lists. The second argument is
now declared "const List *" to reflect that it isn't changed.
This patch just does the minimum needed to get the new implementation
in place and fix bugs exposed by the regression tests. As suggested
by the foregoing, there's a fair amount of followup work remaining to
do.
Also, the ENABLE_LIST_COMPAT macros are finally removed in this
commit. Code using those should have been gone a dozen years ago.
Patch by me; thanks to David Rowley, Jesper Pedersen, and others
for review.
Discussion: https://postgr.es/m/11587.1550975080@sss.pgh.pa.us
2019-07-15 19:41:58 +02:00
|
|
|
field = lnext(tok_line->fields, field);
|
2011-06-20 23:20:14 +02:00
|
|
|
IDENT_FIELD_ABSENT(field);
|
|
|
|
tokens = lfirst(field);
|
|
|
|
IDENT_MULTI_VALUE(tokens);
|
|
|
|
token = linitial(tokens);
|
Refactor regular expression handling in hba.c
AuthToken gains a regular expression, and IdentLine is changed so as it
uses an AuthToken rather than tracking separately the ident user string
used for the regex compilation and its generated regex_t. In the case
of pg_ident.conf, a set of AuthTokens is built in the pre-parsing phase
of the file, and an extra regular expression is compiled when building
the list of IdentLines, after checking the sanity of the fields in a
pre-parsed entry.
The logic in charge of computing and executing regular expressions is
now done in a new set of routines called respectively
regcomp_auth_token() and regexec_auth_token() that are wrappers around
pg_regcomp() and pg_regexec(), working on AuthTokens. While on it, this
patch adds a routine able to free an AuthToken, free_auth_token(), to
simplify a bit the logic around the requirement of using a specific free
routine for computed regular expressions. Note that there are no
functional or behavior changes introduced by this commit.
The goal of this patch is to ease the use of regular expressions with
more items of pg_hba.conf (user list, database list, potentially
hostnames) where AuthTokens are used extensively. This will be tackled
later in a separate patch.
Author: Bertrand Drouvot, Michael Paquier
Discussion: https://postgr.es/m/fff0d7c1-8ad4-76a1-9db3-0ab6ec338bf7@amazon.com
2022-10-19 03:08:49 +02:00
|
|
|
|
|
|
|
/* Copy the ident user token */
|
2023-01-12 06:23:20 +01:00
|
|
|
parsedline->system_user = copy_auth_token(token);
|
2001-07-30 16:50:24 +02:00
|
|
|
|
2005-06-28 07:09:14 +02:00
|
|
|
/* Get the PG rolename token */
|
Represent Lists as expansible arrays, not chains of cons-cells.
Originally, Postgres Lists were a more or less exact reimplementation of
Lisp lists, which consist of chains of separately-allocated cons cells,
each having a value and a next-cell link. We'd hacked that once before
(commit d0b4399d8) to add a separate List header, but the data was still
in cons cells. That makes some operations -- notably list_nth() -- O(N),
and it's bulky because of the next-cell pointers and per-cell palloc
overhead, and it's very cache-unfriendly if the cons cells end up
scattered around rather than being adjacent.
In this rewrite, we still have List headers, but the data is in a
resizable array of values, with no next-cell links. Now we need at
most two palloc's per List, and often only one, since we can allocate
some values in the same palloc call as the List header. (Of course,
extending an existing List may require repalloc's to enlarge the array.
But this involves just O(log N) allocations not O(N).)
Of course this is not without downsides. The key difficulty is that
addition or deletion of a list entry may now cause other entries to
move, which it did not before.
For example, that breaks foreach() and sister macros, which historically
used a pointer to the current cons-cell as loop state. We can repair
those macros transparently by making their actual loop state be an
integer list index; the exposed "ListCell *" pointer is no longer state
carried across loop iterations, but is just a derived value. (In
practice, modern compilers can optimize things back to having just one
loop state value, at least for simple cases with inline loop bodies.)
In principle, this is a semantics change for cases where the loop body
inserts or deletes list entries ahead of the current loop index; but
I found no such cases in the Postgres code.
The change is not at all transparent for code that doesn't use foreach()
but chases lists "by hand" using lnext(). The largest share of such
code in the backend is in loops that were maintaining "prev" and "next"
variables in addition to the current-cell pointer, in order to delete
list cells efficiently using list_delete_cell(). However, we no longer
need a previous-cell pointer to delete a list cell efficiently. Keeping
a next-cell pointer doesn't work, as explained above, but we can improve
matters by changing such code to use a regular foreach() loop and then
using the new macro foreach_delete_current() to delete the current cell.
(This macro knows how to update the associated foreach loop's state so
that no cells will be missed in the traversal.)
There remains a nontrivial risk of code assuming that a ListCell *
pointer will remain good over an operation that could now move the list
contents. To help catch such errors, list.c can be compiled with a new
define symbol DEBUG_LIST_MEMORY_USAGE that forcibly moves list contents
whenever that could possibly happen. This makes list operations
significantly more expensive so it's not normally turned on (though it
is on by default if USE_VALGRIND is on).
There are two notable API differences from the previous code:
* lnext() now requires the List's header pointer in addition to the
current cell's address.
* list_delete_cell() no longer requires a previous-cell argument.
These changes are somewhat unfortunate, but on the other hand code using
either function needs inspection to see if it is assuming anything
it shouldn't, so it's not all bad.
Programmers should be aware of these significant performance changes:
* list_nth() and related functions are now O(1); so there's no
major access-speed difference between a list and an array.
* Inserting or deleting a list element now takes time proportional to
the distance to the end of the list, due to moving the array elements.
(However, it typically *doesn't* require palloc or pfree, so except in
long lists it's probably still faster than before.) Notably, lcons()
used to be about the same cost as lappend(), but that's no longer true
if the list is long. Code that uses lcons() and list_delete_first()
to maintain a stack might usefully be rewritten to push and pop at the
end of the list rather than the beginning.
* There are now list_insert_nth...() and list_delete_nth...() functions
that add or remove a list cell identified by index. These have the
data-movement penalty explained above, but there's no search penalty.
* list_concat() and variants now copy the second list's data into
storage belonging to the first list, so there is no longer any
sharing of cells between the input lists. The second argument is
now declared "const List *" to reflect that it isn't changed.
This patch just does the minimum needed to get the new implementation
in place and fix bugs exposed by the regression tests. As suggested
by the foregoing, there's a fair amount of followup work remaining to
do.
Also, the ENABLE_LIST_COMPAT macros are finally removed in this
commit. Code using those should have been gone a dozen years ago.
Patch by me; thanks to David Rowley, Jesper Pedersen, and others
for review.
Discussion: https://postgr.es/m/11587.1550975080@sss.pgh.pa.us
2019-07-15 19:41:58 +02:00
|
|
|
field = lnext(tok_line->fields, field);
|
2011-06-20 23:20:14 +02:00
|
|
|
IDENT_FIELD_ABSENT(field);
|
|
|
|
tokens = lfirst(field);
|
|
|
|
IDENT_MULTI_VALUE(tokens);
|
|
|
|
token = linitial(tokens);
|
2023-01-16 05:58:07 +01:00
|
|
|
parsedline->pg_user = copy_auth_token(token);
|
2008-11-28 15:26:58 +01:00
|
|
|
|
Refactor regular expression handling in hba.c
AuthToken gains a regular expression, and IdentLine is changed so as it
uses an AuthToken rather than tracking separately the ident user string
used for the regex compilation and its generated regex_t. In the case
of pg_ident.conf, a set of AuthTokens is built in the pre-parsing phase
of the file, and an extra regular expression is compiled when building
the list of IdentLines, after checking the sanity of the fields in a
pre-parsed entry.
The logic in charge of computing and executing regular expressions is
now done in a new set of routines called respectively
regcomp_auth_token() and regexec_auth_token() that are wrappers around
pg_regcomp() and pg_regexec(), working on AuthTokens. While on it, this
patch adds a routine able to free an AuthToken, free_auth_token(), to
simplify a bit the logic around the requirement of using a specific free
routine for computed regular expressions. Note that there are no
functional or behavior changes introduced by this commit.
The goal of this patch is to ease the use of regular expressions with
more items of pg_hba.conf (user list, database list, potentially
hostnames) where AuthTokens are used extensively. This will be tackled
later in a separate patch.
Author: Bertrand Drouvot, Michael Paquier
Discussion: https://postgr.es/m/fff0d7c1-8ad4-76a1-9db3-0ab6ec338bf7@amazon.com
2022-10-19 03:08:49 +02:00
|
|
|
/*
|
|
|
|
* Now that the field validation is done, compile a regex from the user
|
Support the same patterns for pg-user in pg_ident.conf as in pg_hba.conf
While pg_hba.conf has support for non-literal username matches, and
this commit extends the capabilities that are supported for the
PostgreSQL user listed in an ident entry part of pg_ident.conf, with
support for:
1. The "all" keyword, where all the requested users are allowed.
2. Membership checks using the + prefix.
3. Using a regex to match against multiple roles.
1. is a feature that has been requested by Jelte Fennema, 2. something
that has been mentioned independently by Andrew Dunstan, and 3. is
something I came up with while discussing how to extend the first one,
whose implementation is facilitated by 8fea868.
This allows matching certain system users against many different
postgres users with a single line in pg_ident.conf. Without this, one
would need one line for each of the postgres users that a system user
can log in as, which can be cumbersome to maintain.
Tests are added to the TAP test of peer authentication to provide
coverage for all that.
Note that this introduces a set of backward-incompatible changes to be
able to detect the new patterns, for the following cases:
- A role named "all".
- A role prefixed with '+' characters, which is something that would not
have worked in HBA entries anyway.
- A role prefixed by a slash character, similarly to 8fea868.
Any of these can be still be handled by using quotes in the Postgres
role defined in an ident entry.
A huge advantage of this change is that the code applies the same checks
for the Postgres roles in HBA and ident entries, via the common routine
check_role().
**This compatibility change should be mentioned in the release notes.**
Author: Jelte Fennema
Discussion: https://postgr.es/m/DBBPR83MB0507FEC2E8965012990A80D0F7FC9@DBBPR83MB0507.EURPRD83.prod.outlook.com
2023-01-20 03:21:55 +01:00
|
|
|
* tokens, if necessary.
|
Refactor regular expression handling in hba.c
AuthToken gains a regular expression, and IdentLine is changed so as it
uses an AuthToken rather than tracking separately the ident user string
used for the regex compilation and its generated regex_t. In the case
of pg_ident.conf, a set of AuthTokens is built in the pre-parsing phase
of the file, and an extra regular expression is compiled when building
the list of IdentLines, after checking the sanity of the fields in a
pre-parsed entry.
The logic in charge of computing and executing regular expressions is
now done in a new set of routines called respectively
regcomp_auth_token() and regexec_auth_token() that are wrappers around
pg_regcomp() and pg_regexec(), working on AuthTokens. While on it, this
patch adds a routine able to free an AuthToken, free_auth_token(), to
simplify a bit the logic around the requirement of using a specific free
routine for computed regular expressions. Note that there are no
functional or behavior changes introduced by this commit.
The goal of this patch is to ease the use of regular expressions with
more items of pg_hba.conf (user list, database list, potentially
hostnames) where AuthTokens are used extensively. This will be tackled
later in a separate patch.
Author: Bertrand Drouvot, Michael Paquier
Discussion: https://postgr.es/m/fff0d7c1-8ad4-76a1-9db3-0ab6ec338bf7@amazon.com
2022-10-19 03:08:49 +02:00
|
|
|
*/
|
2023-01-12 06:23:20 +01:00
|
|
|
if (regcomp_auth_token(parsedline->system_user, file_name, line_num,
|
2022-10-21 02:55:56 +02:00
|
|
|
err_msg, elevel))
|
2008-10-23 15:31:10 +02:00
|
|
|
{
|
2022-10-21 02:55:56 +02:00
|
|
|
/* err_msg includes the error to report */
|
Refactor regular expression handling in hba.c
AuthToken gains a regular expression, and IdentLine is changed so as it
uses an AuthToken rather than tracking separately the ident user string
used for the regex compilation and its generated regex_t. In the case
of pg_ident.conf, a set of AuthTokens is built in the pre-parsing phase
of the file, and an extra regular expression is compiled when building
the list of IdentLines, after checking the sanity of the fields in a
pre-parsed entry.
The logic in charge of computing and executing regular expressions is
now done in a new set of routines called respectively
regcomp_auth_token() and regexec_auth_token() that are wrappers around
pg_regcomp() and pg_regexec(), working on AuthTokens. While on it, this
patch adds a routine able to free an AuthToken, free_auth_token(), to
simplify a bit the logic around the requirement of using a specific free
routine for computed regular expressions. Note that there are no
functional or behavior changes introduced by this commit.
The goal of this patch is to ease the use of regular expressions with
more items of pg_hba.conf (user list, database list, potentially
hostnames) where AuthTokens are used extensively. This will be tackled
later in a separate patch.
Author: Bertrand Drouvot, Michael Paquier
Discussion: https://postgr.es/m/fff0d7c1-8ad4-76a1-9db3-0ab6ec338bf7@amazon.com
2022-10-19 03:08:49 +02:00
|
|
|
return NULL;
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
}
|
|
|
|
|
Support the same patterns for pg-user in pg_ident.conf as in pg_hba.conf
While pg_hba.conf has support for non-literal username matches, and
this commit extends the capabilities that are supported for the
PostgreSQL user listed in an ident entry part of pg_ident.conf, with
support for:
1. The "all" keyword, where all the requested users are allowed.
2. Membership checks using the + prefix.
3. Using a regex to match against multiple roles.
1. is a feature that has been requested by Jelte Fennema, 2. something
that has been mentioned independently by Andrew Dunstan, and 3. is
something I came up with while discussing how to extend the first one,
whose implementation is facilitated by 8fea868.
This allows matching certain system users against many different
postgres users with a single line in pg_ident.conf. Without this, one
would need one line for each of the postgres users that a system user
can log in as, which can be cumbersome to maintain.
Tests are added to the TAP test of peer authentication to provide
coverage for all that.
Note that this introduces a set of backward-incompatible changes to be
able to detect the new patterns, for the following cases:
- A role named "all".
- A role prefixed with '+' characters, which is something that would not
have worked in HBA entries anyway.
- A role prefixed by a slash character, similarly to 8fea868.
Any of these can be still be handled by using quotes in the Postgres
role defined in an ident entry.
A huge advantage of this change is that the code applies the same checks
for the Postgres roles in HBA and ident entries, via the common routine
check_role().
**This compatibility change should be mentioned in the release notes.**
Author: Jelte Fennema
Discussion: https://postgr.es/m/DBBPR83MB0507FEC2E8965012990A80D0F7FC9@DBBPR83MB0507.EURPRD83.prod.outlook.com
2023-01-20 03:21:55 +01:00
|
|
|
if (regcomp_auth_token(parsedline->pg_user, file_name, line_num,
|
|
|
|
err_msg, elevel))
|
|
|
|
{
|
|
|
|
/* err_msg includes the error to report */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
return parsedline;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Process one line from the parsed ident config lines.
|
|
|
|
*
|
2023-01-12 06:23:20 +01:00
|
|
|
* Compare input parsed ident line to the needed map, pg_user and system_user.
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
* *found_p and *error_p are set according to our results.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
check_ident_usermap(IdentLine *identLine, const char *usermap_name,
|
2023-01-12 06:23:20 +01:00
|
|
|
const char *pg_user, const char *system_user,
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
bool case_insensitive, bool *found_p, bool *error_p)
|
|
|
|
{
|
Support the same patterns for pg-user in pg_ident.conf as in pg_hba.conf
While pg_hba.conf has support for non-literal username matches, and
this commit extends the capabilities that are supported for the
PostgreSQL user listed in an ident entry part of pg_ident.conf, with
support for:
1. The "all" keyword, where all the requested users are allowed.
2. Membership checks using the + prefix.
3. Using a regex to match against multiple roles.
1. is a feature that has been requested by Jelte Fennema, 2. something
that has been mentioned independently by Andrew Dunstan, and 3. is
something I came up with while discussing how to extend the first one,
whose implementation is facilitated by 8fea868.
This allows matching certain system users against many different
postgres users with a single line in pg_ident.conf. Without this, one
would need one line for each of the postgres users that a system user
can log in as, which can be cumbersome to maintain.
Tests are added to the TAP test of peer authentication to provide
coverage for all that.
Note that this introduces a set of backward-incompatible changes to be
able to detect the new patterns, for the following cases:
- A role named "all".
- A role prefixed with '+' characters, which is something that would not
have worked in HBA entries anyway.
- A role prefixed by a slash character, similarly to 8fea868.
Any of these can be still be handled by using quotes in the Postgres
role defined in an ident entry.
A huge advantage of this change is that the code applies the same checks
for the Postgres roles in HBA and ident entries, via the common routine
check_role().
**This compatibility change should be mentioned in the release notes.**
Author: Jelte Fennema
Discussion: https://postgr.es/m/DBBPR83MB0507FEC2E8965012990A80D0F7FC9@DBBPR83MB0507.EURPRD83.prod.outlook.com
2023-01-20 03:21:55 +01:00
|
|
|
Oid roleid;
|
|
|
|
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
*found_p = false;
|
|
|
|
*error_p = false;
|
|
|
|
|
|
|
|
if (strcmp(identLine->usermap, usermap_name) != 0)
|
|
|
|
/* Line does not match the map name we're looking for, so just abort */
|
|
|
|
return;
|
|
|
|
|
Support the same patterns for pg-user in pg_ident.conf as in pg_hba.conf
While pg_hba.conf has support for non-literal username matches, and
this commit extends the capabilities that are supported for the
PostgreSQL user listed in an ident entry part of pg_ident.conf, with
support for:
1. The "all" keyword, where all the requested users are allowed.
2. Membership checks using the + prefix.
3. Using a regex to match against multiple roles.
1. is a feature that has been requested by Jelte Fennema, 2. something
that has been mentioned independently by Andrew Dunstan, and 3. is
something I came up with while discussing how to extend the first one,
whose implementation is facilitated by 8fea868.
This allows matching certain system users against many different
postgres users with a single line in pg_ident.conf. Without this, one
would need one line for each of the postgres users that a system user
can log in as, which can be cumbersome to maintain.
Tests are added to the TAP test of peer authentication to provide
coverage for all that.
Note that this introduces a set of backward-incompatible changes to be
able to detect the new patterns, for the following cases:
- A role named "all".
- A role prefixed with '+' characters, which is something that would not
have worked in HBA entries anyway.
- A role prefixed by a slash character, similarly to 8fea868.
Any of these can be still be handled by using quotes in the Postgres
role defined in an ident entry.
A huge advantage of this change is that the code applies the same checks
for the Postgres roles in HBA and ident entries, via the common routine
check_role().
**This compatibility change should be mentioned in the release notes.**
Author: Jelte Fennema
Discussion: https://postgr.es/m/DBBPR83MB0507FEC2E8965012990A80D0F7FC9@DBBPR83MB0507.EURPRD83.prod.outlook.com
2023-01-20 03:21:55 +01:00
|
|
|
/* Get the target role's OID. Note we do not error out for bad role. */
|
|
|
|
roleid = get_role_oid(pg_user, true);
|
|
|
|
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
/* Match? */
|
2023-01-12 06:23:20 +01:00
|
|
|
if (token_has_regexp(identLine->system_user))
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
{
|
|
|
|
/*
|
Refactor regular expression handling in hba.c
AuthToken gains a regular expression, and IdentLine is changed so as it
uses an AuthToken rather than tracking separately the ident user string
used for the regex compilation and its generated regex_t. In the case
of pg_ident.conf, a set of AuthTokens is built in the pre-parsing phase
of the file, and an extra regular expression is compiled when building
the list of IdentLines, after checking the sanity of the fields in a
pre-parsed entry.
The logic in charge of computing and executing regular expressions is
now done in a new set of routines called respectively
regcomp_auth_token() and regexec_auth_token() that are wrappers around
pg_regcomp() and pg_regexec(), working on AuthTokens. While on it, this
patch adds a routine able to free an AuthToken, free_auth_token(), to
simplify a bit the logic around the requirement of using a specific free
routine for computed regular expressions. Note that there are no
functional or behavior changes introduced by this commit.
The goal of this patch is to ease the use of regular expressions with
more items of pg_hba.conf (user list, database list, potentially
hostnames) where AuthTokens are used extensively. This will be tackled
later in a separate patch.
Author: Bertrand Drouvot, Michael Paquier
Discussion: https://postgr.es/m/fff0d7c1-8ad4-76a1-9db3-0ab6ec338bf7@amazon.com
2022-10-19 03:08:49 +02:00
|
|
|
* Process the system username as a regular expression that returns
|
|
|
|
* exactly one match. This is replaced for \1 in the database username
|
|
|
|
* string, if present.
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
*/
|
|
|
|
int r;
|
|
|
|
regmatch_t matches[2];
|
|
|
|
char *ofs;
|
Support the same patterns for pg-user in pg_ident.conf as in pg_hba.conf
While pg_hba.conf has support for non-literal username matches, and
this commit extends the capabilities that are supported for the
PostgreSQL user listed in an ident entry part of pg_ident.conf, with
support for:
1. The "all" keyword, where all the requested users are allowed.
2. Membership checks using the + prefix.
3. Using a regex to match against multiple roles.
1. is a feature that has been requested by Jelte Fennema, 2. something
that has been mentioned independently by Andrew Dunstan, and 3. is
something I came up with while discussing how to extend the first one,
whose implementation is facilitated by 8fea868.
This allows matching certain system users against many different
postgres users with a single line in pg_ident.conf. Without this, one
would need one line for each of the postgres users that a system user
can log in as, which can be cumbersome to maintain.
Tests are added to the TAP test of peer authentication to provide
coverage for all that.
Note that this introduces a set of backward-incompatible changes to be
able to detect the new patterns, for the following cases:
- A role named "all".
- A role prefixed with '+' characters, which is something that would not
have worked in HBA entries anyway.
- A role prefixed by a slash character, similarly to 8fea868.
Any of these can be still be handled by using quotes in the Postgres
role defined in an ident entry.
A huge advantage of this change is that the code applies the same checks
for the Postgres roles in HBA and ident entries, via the common routine
check_role().
**This compatibility change should be mentioned in the release notes.**
Author: Jelte Fennema
Discussion: https://postgr.es/m/DBBPR83MB0507FEC2E8965012990A80D0F7FC9@DBBPR83MB0507.EURPRD83.prod.outlook.com
2023-01-20 03:21:55 +01:00
|
|
|
AuthToken *expanded_pg_user_token;
|
|
|
|
bool created_temporary_token = false;
|
2008-11-28 15:26:58 +01:00
|
|
|
|
2023-01-12 06:23:20 +01:00
|
|
|
r = regexec_auth_token(system_user, identLine->system_user, 2, matches);
|
2008-11-28 15:26:58 +01:00
|
|
|
if (r)
|
|
|
|
{
|
|
|
|
char errstr[100];
|
|
|
|
|
|
|
|
if (r != REG_NOMATCH)
|
|
|
|
{
|
|
|
|
/* REG_NOMATCH is not an error, everything else is */
|
2023-01-12 06:23:20 +01:00
|
|
|
pg_regerror(r, identLine->system_user->regex, errstr, sizeof(errstr));
|
2009-06-24 15:39:42 +02:00
|
|
|
ereport(LOG,
|
2008-11-28 15:26:58 +01:00
|
|
|
(errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
|
2010-05-26 18:43:13 +02:00
|
|
|
errmsg("regular expression match for \"%s\" failed: %s",
|
2023-01-12 06:23:20 +01:00
|
|
|
identLine->system_user->string + 1, errstr)));
|
2008-11-28 15:26:58 +01:00
|
|
|
*error_p = true;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
Support the same patterns for pg-user in pg_ident.conf as in pg_hba.conf
While pg_hba.conf has support for non-literal username matches, and
this commit extends the capabilities that are supported for the
PostgreSQL user listed in an ident entry part of pg_ident.conf, with
support for:
1. The "all" keyword, where all the requested users are allowed.
2. Membership checks using the + prefix.
3. Using a regex to match against multiple roles.
1. is a feature that has been requested by Jelte Fennema, 2. something
that has been mentioned independently by Andrew Dunstan, and 3. is
something I came up with while discussing how to extend the first one,
whose implementation is facilitated by 8fea868.
This allows matching certain system users against many different
postgres users with a single line in pg_ident.conf. Without this, one
would need one line for each of the postgres users that a system user
can log in as, which can be cumbersome to maintain.
Tests are added to the TAP test of peer authentication to provide
coverage for all that.
Note that this introduces a set of backward-incompatible changes to be
able to detect the new patterns, for the following cases:
- A role named "all".
- A role prefixed with '+' characters, which is something that would not
have worked in HBA entries anyway.
- A role prefixed by a slash character, similarly to 8fea868.
Any of these can be still be handled by using quotes in the Postgres
role defined in an ident entry.
A huge advantage of this change is that the code applies the same checks
for the Postgres roles in HBA and ident entries, via the common routine
check_role().
**This compatibility change should be mentioned in the release notes.**
Author: Jelte Fennema
Discussion: https://postgr.es/m/DBBPR83MB0507FEC2E8965012990A80D0F7FC9@DBBPR83MB0507.EURPRD83.prod.outlook.com
2023-01-20 03:21:55 +01:00
|
|
|
/*
|
|
|
|
* Replace \1 with the first captured group unless the field already
|
|
|
|
* has some special meaning, like a group membership or a regexp-based
|
|
|
|
* check.
|
|
|
|
*/
|
|
|
|
if (!token_is_member_check(identLine->pg_user) &&
|
|
|
|
!token_has_regexp(identLine->pg_user) &&
|
|
|
|
(ofs = strstr(identLine->pg_user->string, "\\1")) != NULL)
|
2008-11-28 15:26:58 +01:00
|
|
|
{
|
Support the same patterns for pg-user in pg_ident.conf as in pg_hba.conf
While pg_hba.conf has support for non-literal username matches, and
this commit extends the capabilities that are supported for the
PostgreSQL user listed in an ident entry part of pg_ident.conf, with
support for:
1. The "all" keyword, where all the requested users are allowed.
2. Membership checks using the + prefix.
3. Using a regex to match against multiple roles.
1. is a feature that has been requested by Jelte Fennema, 2. something
that has been mentioned independently by Andrew Dunstan, and 3. is
something I came up with while discussing how to extend the first one,
whose implementation is facilitated by 8fea868.
This allows matching certain system users against many different
postgres users with a single line in pg_ident.conf. Without this, one
would need one line for each of the postgres users that a system user
can log in as, which can be cumbersome to maintain.
Tests are added to the TAP test of peer authentication to provide
coverage for all that.
Note that this introduces a set of backward-incompatible changes to be
able to detect the new patterns, for the following cases:
- A role named "all".
- A role prefixed with '+' characters, which is something that would not
have worked in HBA entries anyway.
- A role prefixed by a slash character, similarly to 8fea868.
Any of these can be still be handled by using quotes in the Postgres
role defined in an ident entry.
A huge advantage of this change is that the code applies the same checks
for the Postgres roles in HBA and ident entries, via the common routine
check_role().
**This compatibility change should be mentioned in the release notes.**
Author: Jelte Fennema
Discussion: https://postgr.es/m/DBBPR83MB0507FEC2E8965012990A80D0F7FC9@DBBPR83MB0507.EURPRD83.prod.outlook.com
2023-01-20 03:21:55 +01:00
|
|
|
char *expanded_pg_user;
|
Replace a bunch more uses of strncpy() with safer coding.
strncpy() has a well-deserved reputation for being unsafe, so make an
effort to get rid of nearly all occurrences in HEAD.
A large fraction of the remaining uses were passing length less than or
equal to the known strlen() of the source, in which case no null-padding
can occur and the behavior is equivalent to memcpy(), though doubtless
slower and certainly harder to reason about. So just use memcpy() in
these cases.
In other cases, use either StrNCpy() or strlcpy() as appropriate (depending
on whether padding to the full length of the destination buffer seems
useful).
I left a few strncpy() calls alone in the src/timezone/ code, to keep it
in sync with upstream (the IANA tzcode distribution). There are also a
few such calls in ecpg that could possibly do with more analysis.
AFAICT, none of these changes are more than cosmetic, except for the four
occurrences in fe-secure-openssl.c, which are in fact buggy: an overlength
source leads to a non-null-terminated destination buffer and ensuing
misbehavior. These don't seem like security issues, first because no stack
clobber is possible and second because if your values of sslcert etc are
coming from untrusted sources then you've got problems way worse than this.
Still, it's undesirable to have unpredictable behavior for overlength
inputs, so back-patch those four changes to all active branches.
2015-01-24 19:05:42 +01:00
|
|
|
int offset;
|
|
|
|
|
2008-11-28 15:26:58 +01:00
|
|
|
/* substitution of the first argument requested */
|
|
|
|
if (matches[1].rm_so < 0)
|
2009-06-24 15:39:42 +02:00
|
|
|
{
|
|
|
|
ereport(LOG,
|
2008-11-28 15:26:58 +01:00
|
|
|
(errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
|
2009-03-25 15:12:02 +01:00
|
|
|
errmsg("regular expression \"%s\" has no subexpressions as requested by backreference in \"%s\"",
|
2023-01-16 05:58:07 +01:00
|
|
|
identLine->system_user->string + 1, identLine->pg_user->string)));
|
2009-06-24 15:39:42 +02:00
|
|
|
*error_p = true;
|
|
|
|
return;
|
|
|
|
}
|
2009-06-11 16:49:15 +02:00
|
|
|
|
2008-11-28 15:26:58 +01:00
|
|
|
/*
|
|
|
|
* length: original length minus length of \1 plus length of match
|
|
|
|
* plus null terminator
|
|
|
|
*/
|
2023-01-16 05:58:07 +01:00
|
|
|
expanded_pg_user = palloc0(strlen(identLine->pg_user->string) - 2 + (matches[1].rm_eo - matches[1].rm_so) + 1);
|
|
|
|
offset = ofs - identLine->pg_user->string;
|
|
|
|
memcpy(expanded_pg_user, identLine->pg_user->string, offset);
|
2023-01-12 06:23:20 +01:00
|
|
|
memcpy(expanded_pg_user + offset,
|
|
|
|
system_user + matches[1].rm_so,
|
2008-11-28 15:26:58 +01:00
|
|
|
matches[1].rm_eo - matches[1].rm_so);
|
2023-01-12 06:23:20 +01:00
|
|
|
strcat(expanded_pg_user, ofs + 2);
|
2008-11-28 15:26:58 +01:00
|
|
|
|
Support the same patterns for pg-user in pg_ident.conf as in pg_hba.conf
While pg_hba.conf has support for non-literal username matches, and
this commit extends the capabilities that are supported for the
PostgreSQL user listed in an ident entry part of pg_ident.conf, with
support for:
1. The "all" keyword, where all the requested users are allowed.
2. Membership checks using the + prefix.
3. Using a regex to match against multiple roles.
1. is a feature that has been requested by Jelte Fennema, 2. something
that has been mentioned independently by Andrew Dunstan, and 3. is
something I came up with while discussing how to extend the first one,
whose implementation is facilitated by 8fea868.
This allows matching certain system users against many different
postgres users with a single line in pg_ident.conf. Without this, one
would need one line for each of the postgres users that a system user
can log in as, which can be cumbersome to maintain.
Tests are added to the TAP test of peer authentication to provide
coverage for all that.
Note that this introduces a set of backward-incompatible changes to be
able to detect the new patterns, for the following cases:
- A role named "all".
- A role prefixed with '+' characters, which is something that would not
have worked in HBA entries anyway.
- A role prefixed by a slash character, similarly to 8fea868.
Any of these can be still be handled by using quotes in the Postgres
role defined in an ident entry.
A huge advantage of this change is that the code applies the same checks
for the Postgres roles in HBA and ident entries, via the common routine
check_role().
**This compatibility change should be mentioned in the release notes.**
Author: Jelte Fennema
Discussion: https://postgr.es/m/DBBPR83MB0507FEC2E8965012990A80D0F7FC9@DBBPR83MB0507.EURPRD83.prod.outlook.com
2023-01-20 03:21:55 +01:00
|
|
|
/*
|
|
|
|
* Mark the token as quoted, so it will only be compared literally
|
|
|
|
* and not for some special meaning, such as "all" or a group
|
|
|
|
* membership check.
|
|
|
|
*/
|
|
|
|
expanded_pg_user_token = make_auth_token(expanded_pg_user, true);
|
|
|
|
created_temporary_token = true;
|
|
|
|
pfree(expanded_pg_user);
|
2008-11-28 15:26:58 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
Support the same patterns for pg-user in pg_ident.conf as in pg_hba.conf
While pg_hba.conf has support for non-literal username matches, and
this commit extends the capabilities that are supported for the
PostgreSQL user listed in an ident entry part of pg_ident.conf, with
support for:
1. The "all" keyword, where all the requested users are allowed.
2. Membership checks using the + prefix.
3. Using a regex to match against multiple roles.
1. is a feature that has been requested by Jelte Fennema, 2. something
that has been mentioned independently by Andrew Dunstan, and 3. is
something I came up with while discussing how to extend the first one,
whose implementation is facilitated by 8fea868.
This allows matching certain system users against many different
postgres users with a single line in pg_ident.conf. Without this, one
would need one line for each of the postgres users that a system user
can log in as, which can be cumbersome to maintain.
Tests are added to the TAP test of peer authentication to provide
coverage for all that.
Note that this introduces a set of backward-incompatible changes to be
able to detect the new patterns, for the following cases:
- A role named "all".
- A role prefixed with '+' characters, which is something that would not
have worked in HBA entries anyway.
- A role prefixed by a slash character, similarly to 8fea868.
Any of these can be still be handled by using quotes in the Postgres
role defined in an ident entry.
A huge advantage of this change is that the code applies the same checks
for the Postgres roles in HBA and ident entries, via the common routine
check_role().
**This compatibility change should be mentioned in the release notes.**
Author: Jelte Fennema
Discussion: https://postgr.es/m/DBBPR83MB0507FEC2E8965012990A80D0F7FC9@DBBPR83MB0507.EURPRD83.prod.outlook.com
2023-01-20 03:21:55 +01:00
|
|
|
expanded_pg_user_token = identLine->pg_user;
|
2008-11-28 15:26:58 +01:00
|
|
|
}
|
Support the same patterns for pg-user in pg_ident.conf as in pg_hba.conf
While pg_hba.conf has support for non-literal username matches, and
this commit extends the capabilities that are supported for the
PostgreSQL user listed in an ident entry part of pg_ident.conf, with
support for:
1. The "all" keyword, where all the requested users are allowed.
2. Membership checks using the + prefix.
3. Using a regex to match against multiple roles.
1. is a feature that has been requested by Jelte Fennema, 2. something
that has been mentioned independently by Andrew Dunstan, and 3. is
something I came up with while discussing how to extend the first one,
whose implementation is facilitated by 8fea868.
This allows matching certain system users against many different
postgres users with a single line in pg_ident.conf. Without this, one
would need one line for each of the postgres users that a system user
can log in as, which can be cumbersome to maintain.
Tests are added to the TAP test of peer authentication to provide
coverage for all that.
Note that this introduces a set of backward-incompatible changes to be
able to detect the new patterns, for the following cases:
- A role named "all".
- A role prefixed with '+' characters, which is something that would not
have worked in HBA entries anyway.
- A role prefixed by a slash character, similarly to 8fea868.
Any of these can be still be handled by using quotes in the Postgres
role defined in an ident entry.
A huge advantage of this change is that the code applies the same checks
for the Postgres roles in HBA and ident entries, via the common routine
check_role().
**This compatibility change should be mentioned in the release notes.**
Author: Jelte Fennema
Discussion: https://postgr.es/m/DBBPR83MB0507FEC2E8965012990A80D0F7FC9@DBBPR83MB0507.EURPRD83.prod.outlook.com
2023-01-20 03:21:55 +01:00
|
|
|
|
|
|
|
/* check the Postgres user */
|
|
|
|
*found_p = check_role(pg_user, roleid,
|
|
|
|
list_make1(expanded_pg_user_token),
|
|
|
|
case_insensitive);
|
|
|
|
|
|
|
|
if (created_temporary_token)
|
|
|
|
free_auth_token(expanded_pg_user_token);
|
2008-11-28 15:26:58 +01:00
|
|
|
|
|
|
|
return;
|
2008-10-23 15:31:10 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
Support the same patterns for pg-user in pg_ident.conf as in pg_hba.conf
While pg_hba.conf has support for non-literal username matches, and
this commit extends the capabilities that are supported for the
PostgreSQL user listed in an ident entry part of pg_ident.conf, with
support for:
1. The "all" keyword, where all the requested users are allowed.
2. Membership checks using the + prefix.
3. Using a regex to match against multiple roles.
1. is a feature that has been requested by Jelte Fennema, 2. something
that has been mentioned independently by Andrew Dunstan, and 3. is
something I came up with while discussing how to extend the first one,
whose implementation is facilitated by 8fea868.
This allows matching certain system users against many different
postgres users with a single line in pg_ident.conf. Without this, one
would need one line for each of the postgres users that a system user
can log in as, which can be cumbersome to maintain.
Tests are added to the TAP test of peer authentication to provide
coverage for all that.
Note that this introduces a set of backward-incompatible changes to be
able to detect the new patterns, for the following cases:
- A role named "all".
- A role prefixed with '+' characters, which is something that would not
have worked in HBA entries anyway.
- A role prefixed by a slash character, similarly to 8fea868.
Any of these can be still be handled by using quotes in the Postgres
role defined in an ident entry.
A huge advantage of this change is that the code applies the same checks
for the Postgres roles in HBA and ident entries, via the common routine
check_role().
**This compatibility change should be mentioned in the release notes.**
Author: Jelte Fennema
Discussion: https://postgr.es/m/DBBPR83MB0507FEC2E8965012990A80D0F7FC9@DBBPR83MB0507.EURPRD83.prod.outlook.com
2023-01-20 03:21:55 +01:00
|
|
|
/*
|
|
|
|
* Not a regular expression, so make a complete match. If the system
|
|
|
|
* user does not match, just leave.
|
|
|
|
*/
|
2008-11-28 15:26:58 +01:00
|
|
|
if (case_insensitive)
|
|
|
|
{
|
Support the same patterns for pg-user in pg_ident.conf as in pg_hba.conf
While pg_hba.conf has support for non-literal username matches, and
this commit extends the capabilities that are supported for the
PostgreSQL user listed in an ident entry part of pg_ident.conf, with
support for:
1. The "all" keyword, where all the requested users are allowed.
2. Membership checks using the + prefix.
3. Using a regex to match against multiple roles.
1. is a feature that has been requested by Jelte Fennema, 2. something
that has been mentioned independently by Andrew Dunstan, and 3. is
something I came up with while discussing how to extend the first one,
whose implementation is facilitated by 8fea868.
This allows matching certain system users against many different
postgres users with a single line in pg_ident.conf. Without this, one
would need one line for each of the postgres users that a system user
can log in as, which can be cumbersome to maintain.
Tests are added to the TAP test of peer authentication to provide
coverage for all that.
Note that this introduces a set of backward-incompatible changes to be
able to detect the new patterns, for the following cases:
- A role named "all".
- A role prefixed with '+' characters, which is something that would not
have worked in HBA entries anyway.
- A role prefixed by a slash character, similarly to 8fea868.
Any of these can be still be handled by using quotes in the Postgres
role defined in an ident entry.
A huge advantage of this change is that the code applies the same checks
for the Postgres roles in HBA and ident entries, via the common routine
check_role().
**This compatibility change should be mentioned in the release notes.**
Author: Jelte Fennema
Discussion: https://postgr.es/m/DBBPR83MB0507FEC2E8965012990A80D0F7FC9@DBBPR83MB0507.EURPRD83.prod.outlook.com
2023-01-20 03:21:55 +01:00
|
|
|
if (!token_matches_insensitive(identLine->system_user,
|
|
|
|
system_user))
|
|
|
|
return;
|
2008-11-28 15:26:58 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
Support the same patterns for pg-user in pg_ident.conf as in pg_hba.conf
While pg_hba.conf has support for non-literal username matches, and
this commit extends the capabilities that are supported for the
PostgreSQL user listed in an ident entry part of pg_ident.conf, with
support for:
1. The "all" keyword, where all the requested users are allowed.
2. Membership checks using the + prefix.
3. Using a regex to match against multiple roles.
1. is a feature that has been requested by Jelte Fennema, 2. something
that has been mentioned independently by Andrew Dunstan, and 3. is
something I came up with while discussing how to extend the first one,
whose implementation is facilitated by 8fea868.
This allows matching certain system users against many different
postgres users with a single line in pg_ident.conf. Without this, one
would need one line for each of the postgres users that a system user
can log in as, which can be cumbersome to maintain.
Tests are added to the TAP test of peer authentication to provide
coverage for all that.
Note that this introduces a set of backward-incompatible changes to be
able to detect the new patterns, for the following cases:
- A role named "all".
- A role prefixed with '+' characters, which is something that would not
have worked in HBA entries anyway.
- A role prefixed by a slash character, similarly to 8fea868.
Any of these can be still be handled by using quotes in the Postgres
role defined in an ident entry.
A huge advantage of this change is that the code applies the same checks
for the Postgres roles in HBA and ident entries, via the common routine
check_role().
**This compatibility change should be mentioned in the release notes.**
Author: Jelte Fennema
Discussion: https://postgr.es/m/DBBPR83MB0507FEC2E8965012990A80D0F7FC9@DBBPR83MB0507.EURPRD83.prod.outlook.com
2023-01-20 03:21:55 +01:00
|
|
|
if (!token_matches(identLine->system_user, system_user))
|
|
|
|
return;
|
2008-11-28 15:26:58 +01:00
|
|
|
}
|
Support the same patterns for pg-user in pg_ident.conf as in pg_hba.conf
While pg_hba.conf has support for non-literal username matches, and
this commit extends the capabilities that are supported for the
PostgreSQL user listed in an ident entry part of pg_ident.conf, with
support for:
1. The "all" keyword, where all the requested users are allowed.
2. Membership checks using the + prefix.
3. Using a regex to match against multiple roles.
1. is a feature that has been requested by Jelte Fennema, 2. something
that has been mentioned independently by Andrew Dunstan, and 3. is
something I came up with while discussing how to extend the first one,
whose implementation is facilitated by 8fea868.
This allows matching certain system users against many different
postgres users with a single line in pg_ident.conf. Without this, one
would need one line for each of the postgres users that a system user
can log in as, which can be cumbersome to maintain.
Tests are added to the TAP test of peer authentication to provide
coverage for all that.
Note that this introduces a set of backward-incompatible changes to be
able to detect the new patterns, for the following cases:
- A role named "all".
- A role prefixed with '+' characters, which is something that would not
have worked in HBA entries anyway.
- A role prefixed by a slash character, similarly to 8fea868.
Any of these can be still be handled by using quotes in the Postgres
role defined in an ident entry.
A huge advantage of this change is that the code applies the same checks
for the Postgres roles in HBA and ident entries, via the common routine
check_role().
**This compatibility change should be mentioned in the release notes.**
Author: Jelte Fennema
Discussion: https://postgr.es/m/DBBPR83MB0507FEC2E8965012990A80D0F7FC9@DBBPR83MB0507.EURPRD83.prod.outlook.com
2023-01-20 03:21:55 +01:00
|
|
|
|
|
|
|
/* check the Postgres user */
|
|
|
|
*found_p = check_role(pg_user, roleid,
|
|
|
|
list_make1(identLine->pg_user),
|
|
|
|
case_insensitive);
|
2008-10-23 15:31:10 +02:00
|
|
|
}
|
2001-07-30 16:50:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2001-08-01 00:55:45 +02:00
|
|
|
* Scan the (pre-parsed) ident usermap file line by line, looking for a match
|
|
|
|
*
|
2023-01-12 06:23:20 +01:00
|
|
|
* See if the system user with ident username "system_user" is allowed to act as
|
|
|
|
* Postgres user "pg_user" according to usermap "usermap_name".
|
2001-08-01 00:55:45 +02:00
|
|
|
*
|
2008-09-15 14:32:57 +02:00
|
|
|
* Special case: Usermap NULL, equivalent to what was previously called
|
2010-03-24 18:05:45 +01:00
|
|
|
* "sameuser" or "samerole", means don't look in the usermap file.
|
2023-01-12 06:23:20 +01:00
|
|
|
* That's an implied map wherein "pg_user" must be identical to
|
|
|
|
* "system_user" in order to be authorized.
|
2001-08-01 00:55:45 +02:00
|
|
|
*
|
2008-10-23 15:31:10 +02:00
|
|
|
* Iff authorized, return STATUS_OK, otherwise return STATUS_ERROR.
|
2001-07-30 16:50:24 +02:00
|
|
|
*/
|
2008-10-23 15:31:10 +02:00
|
|
|
int
|
|
|
|
check_usermap(const char *usermap_name,
|
2023-01-12 06:23:20 +01:00
|
|
|
const char *pg_user,
|
|
|
|
const char *system_user,
|
2008-10-23 15:31:10 +02:00
|
|
|
bool case_insensitive)
|
2001-07-30 16:50:24 +02:00
|
|
|
{
|
|
|
|
bool found_entry = false,
|
|
|
|
error = false;
|
|
|
|
|
2003-04-18 00:26:02 +02:00
|
|
|
if (usermap_name == NULL || usermap_name[0] == '\0')
|
2001-07-30 16:50:24 +02:00
|
|
|
{
|
2008-10-23 15:31:10 +02:00
|
|
|
if (case_insensitive)
|
|
|
|
{
|
2023-01-12 06:23:20 +01:00
|
|
|
if (pg_strcasecmp(pg_user, system_user) == 0)
|
2008-10-23 15:31:10 +02:00
|
|
|
return STATUS_OK;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-01-12 06:23:20 +01:00
|
|
|
if (strcmp(pg_user, system_user) == 0)
|
2008-10-23 15:31:10 +02:00
|
|
|
return STATUS_OK;
|
|
|
|
}
|
|
|
|
ereport(LOG,
|
2010-03-21 01:17:59 +01:00
|
|
|
(errmsg("provided user name (%s) and authenticated user name (%s) do not match",
|
2023-01-12 06:23:20 +01:00
|
|
|
pg_user, system_user)));
|
2008-10-23 15:31:10 +02:00
|
|
|
return STATUS_ERROR;
|
2001-07-30 16:50:24 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
ListCell *line_cell;
|
2004-05-26 06:41:50 +02:00
|
|
|
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
foreach(line_cell, parsed_ident_lines)
|
2001-07-30 16:50:24 +02:00
|
|
|
{
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
check_ident_usermap(lfirst(line_cell), usermap_name,
|
2023-01-12 06:23:20 +01:00
|
|
|
pg_user, system_user, case_insensitive,
|
2004-05-26 06:41:50 +02:00
|
|
|
&found_entry, &error);
|
2001-07-30 16:50:24 +02:00
|
|
|
if (found_entry || error)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2008-10-23 15:31:10 +02:00
|
|
|
if (!found_entry && !error)
|
|
|
|
{
|
|
|
|
ereport(LOG,
|
2010-05-26 18:43:13 +02:00
|
|
|
(errmsg("no match in usermap \"%s\" for user \"%s\" authenticated as \"%s\"",
|
2023-01-12 06:23:20 +01:00
|
|
|
usermap_name, pg_user, system_user)));
|
2008-10-23 15:31:10 +02:00
|
|
|
}
|
|
|
|
return found_entry ? STATUS_OK : STATUS_ERROR;
|
2001-07-30 16:50:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
* Read the ident config file and create a List of IdentLine records for
|
|
|
|
* the contents.
|
2011-06-20 23:20:14 +02:00
|
|
|
*
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
* This works the same as load_hba(), but for the user config file.
|
2001-07-30 16:50:24 +02:00
|
|
|
*/
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
bool
|
2001-08-01 00:55:45 +02:00
|
|
|
load_ident(void)
|
1996-10-12 09:47:12 +02:00
|
|
|
{
|
2004-10-10 01:13:22 +02:00
|
|
|
FILE *file;
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
List *ident_lines = NIL;
|
2023-04-14 00:27:44 +02:00
|
|
|
ListCell *line_cell;
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
List *new_parsed_lines = NIL;
|
|
|
|
bool ok = true;
|
|
|
|
MemoryContext oldcxt;
|
|
|
|
MemoryContext ident_context;
|
|
|
|
IdentLine *newline;
|
2001-07-30 16:50:24 +02:00
|
|
|
|
Invent open_auth_file() in hba.c to refactor authentication file opening
This adds a check on the recursion depth when including authentication
configuration files, something that has never been done when processing
'@' files for database and user name lists in pg_hba.conf. On HEAD,
this was leading to a rather confusing error, as of:
FATAL: exceeded maxAllocatedDescs (NN) while trying to open file "/path/blah.conf"
This refactors the code so as the error reported is now the following,
which is the same as for GUCs:
FATAL: could not open file "/path/blah.conf": maximum nesting depth exceeded
This reduces a bit the verbosity of the error message used for files
included in user and database lists, reporting only the file name of
what's failing to load, without mentioning the relative or absolute path
specified after '@' in a HBA file. The absolute path is built upon what
'@' defines anyway, so there is no actual loss of information. This
makes the future inclusion logic much simpler. A follow-up patch will
add an error context to be able to track on which line of which file the
inclusion is failing, to close the loop, providing all the information
needed to know the full chain of events.
This logic has been extracted from a larger patch written by Julien,
rewritten by me to have a unique code path calling AllocateFile() on
authentication files, and is useful on its own. This new interface
will be used later for authentication files included with
@include[_dir,_if_exists], in a follow-up patch.
Author: Michael Paquier, Julien Rouhaud
Discussion: https://www.postgresql.org/message-id/Y2xUBJ+S+Z0zbxRW@paquier.xyz
2022-11-14 02:21:42 +01:00
|
|
|
/* not FATAL ... we just won't do any special ident maps */
|
|
|
|
file = open_auth_file(IdentFileName, LOG, 0, NULL);
|
2001-07-30 16:50:24 +02:00
|
|
|
if (file == NULL)
|
|
|
|
{
|
Invent open_auth_file() in hba.c to refactor authentication file opening
This adds a check on the recursion depth when including authentication
configuration files, something that has never been done when processing
'@' files for database and user name lists in pg_hba.conf. On HEAD,
this was leading to a rather confusing error, as of:
FATAL: exceeded maxAllocatedDescs (NN) while trying to open file "/path/blah.conf"
This refactors the code so as the error reported is now the following,
which is the same as for GUCs:
FATAL: could not open file "/path/blah.conf": maximum nesting depth exceeded
This reduces a bit the verbosity of the error message used for files
included in user and database lists, reporting only the file name of
what's failing to load, without mentioning the relative or absolute path
specified after '@' in a HBA file. The absolute path is built upon what
'@' defines anyway, so there is no actual loss of information. This
makes the future inclusion logic much simpler. A follow-up patch will
add an error context to be able to track on which line of which file the
inclusion is failing, to close the loop, providing all the information
needed to know the full chain of events.
This logic has been extracted from a larger patch written by Julien,
rewritten by me to have a unique code path calling AllocateFile() on
authentication files, and is useful on its own. This new interface
will be used later for authentication files included with
@include[_dir,_if_exists], in a follow-up patch.
Author: Michael Paquier, Julien Rouhaud
Discussion: https://www.postgresql.org/message-id/Y2xUBJ+S+Z0zbxRW@paquier.xyz
2022-11-14 02:21:42 +01:00
|
|
|
/* error already logged */
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
return false;
|
2001-07-30 16:50:24 +02:00
|
|
|
}
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
|
2022-11-24 00:21:55 +01:00
|
|
|
tokenize_auth_file(IdentFileName, file, &ident_lines, LOG, 0);
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
|
|
|
|
/* Now parse all the lines */
|
2015-07-02 00:55:39 +02:00
|
|
|
Assert(PostmasterContext);
|
|
|
|
ident_context = AllocSetContextCreate(PostmasterContext,
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
"ident parser context",
|
Add macros to make AllocSetContextCreate() calls simpler and safer.
I found that half a dozen (nearly 5%) of our AllocSetContextCreate calls
had typos in the context-sizing parameters. While none of these led to
especially significant problems, they did create minor inefficiencies,
and it's now clear that expecting people to copy-and-paste those calls
accurately is not a great idea. Let's reduce the risk of future errors
by introducing single macros that encapsulate the common use-cases.
Three such macros are enough to cover all but two special-purpose contexts;
those two calls can be left as-is, I think.
While this patch doesn't in itself improve matters for third-party
extensions, it doesn't break anything for them either, and they can
gradually adopt the simplified notation over time.
In passing, change TopMemoryContext to use the default allocation
parameters. Formerly it could only be extended 8K at a time. That was
probably reasonable when this code was written; but nowadays we create
many more contexts than we did then, so that it's not unusual to have a
couple hundred K in TopMemoryContext, even without considering various
dubious code that sticks other things there. There seems no good reason
not to let it use growing blocks like most other contexts.
Back-patch to 9.6, mostly because that's still close enough to HEAD that
it's easy to do so, and keeping the branches in sync can be expected to
avoid some future back-patching pain. The bugs fixed by these changes
don't seem to be significant enough to justify fixing them further back.
Discussion: <21072.1472321324@sss.pgh.pa.us>
2016-08-27 23:50:38 +02:00
|
|
|
ALLOCSET_SMALL_SIZES);
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
oldcxt = MemoryContextSwitchTo(ident_context);
|
2017-01-27 19:43:00 +01:00
|
|
|
foreach(line_cell, ident_lines)
|
2001-07-30 16:50:24 +02:00
|
|
|
{
|
Refactor code related to pg_hba_file_rules() into new file
hba.c is growing big, and more contents are planned for it. In order to
prepare for this future work, this commit moves all the code related to
the system function processing the contents of pg_hba.conf,
pg_hba_file_rules() to a new file called hbafuncs.c, which will be used
as the location for the SQL portion of the authentication file parsing.
While on it, HbaToken, the structure holding a string token lexed from a
configuration file related to authentication, is renamed to a more
generic AuthToken, as it gets used not only for pg_hba.conf, but also
for pg_ident.conf. TokenizedLine is now named TokenizedAuthLine.
The size of hba.c is reduced by ~12%.
Author: Julien Rouhaud
Reviewed-by: Aleksander Alekseev, Michael Paquier
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya@jrouhaud
2022-03-24 04:42:30 +01:00
|
|
|
TokenizedAuthLine *tok_line = (TokenizedAuthLine *) lfirst(line_cell);
|
2017-01-27 19:43:00 +01:00
|
|
|
|
2017-01-31 00:00:26 +01:00
|
|
|
/* don't parse lines that already have errors */
|
|
|
|
if (tok_line->err_msg != NULL)
|
|
|
|
{
|
|
|
|
ok = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2022-03-29 03:15:48 +02:00
|
|
|
if ((newline = parse_ident_line(tok_line, LOG)) == NULL)
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
{
|
2017-01-31 00:00:26 +01:00
|
|
|
/* Parse error; remember there's trouble */
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
ok = false;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Keep parsing the rest of the file so we can report errors on
|
2017-01-31 00:00:26 +01:00
|
|
|
* more than the first line. Error has already been logged, no
|
|
|
|
* need for more chatter here.
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
*/
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
new_parsed_lines = lappend(new_parsed_lines, newline);
|
2001-07-30 16:50:24 +02:00
|
|
|
}
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
|
|
|
|
/* Free tokenizer memory */
|
2022-11-24 00:21:55 +01:00
|
|
|
free_auth_file(file, 0);
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
MemoryContextSwitchTo(oldcxt);
|
|
|
|
|
|
|
|
if (!ok)
|
|
|
|
{
|
2017-01-31 00:00:26 +01:00
|
|
|
/*
|
2023-05-19 23:24:48 +02:00
|
|
|
* File contained one or more errors, so bail out.
|
|
|
|
* MemoryContextDelete is enough to clean up everything, including
|
|
|
|
* regexes.
|
2017-01-31 00:00:26 +01:00
|
|
|
*/
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
MemoryContextDelete(ident_context);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Loaded new file successfully, replace the one we use */
|
2013-10-24 13:03:26 +02:00
|
|
|
if (parsed_ident_context != NULL)
|
|
|
|
MemoryContextDelete(parsed_ident_context);
|
|
|
|
|
Parse pg_ident.conf when it's loaded, keeping it in memory in parsed format.
Similar changes were done to pg_hba.conf earlier already, this commit makes
pg_ident.conf to behave the same as pg_hba.conf.
This has two user-visible effects. First, if pg_ident.conf contains multiple
errors, the whole file is parsed at postmaster startup time and all the
errors are immediately reported. Before this patch, the file was parsed and
the errors were reported only when someone tries to connect using an
authentication method that uses the file, and the parsing stopped on first
error. Second, if you SIGHUP to reload the config files, and the new
pg_ident.conf file contains an error, the error is logged but the old file
stays in effect.
Also, regular expressions in pg_ident.conf are now compiled only once when
the file is loaded, rather than every time the a user is authenticated. That
should speed up authentication if you have a lot of regexps in the file.
Amit Kapila
2012-09-21 16:41:22 +02:00
|
|
|
parsed_ident_context = ident_context;
|
|
|
|
parsed_ident_lines = new_parsed_lines;
|
|
|
|
|
|
|
|
return true;
|
2001-07-30 16:50:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1996-10-12 09:47:12 +02:00
|
|
|
|
2001-07-30 16:50:24 +02:00
|
|
|
/*
|
|
|
|
* Determine what authentication method should be used when accessing database
|
2001-08-01 00:55:45 +02:00
|
|
|
* "database" from frontend "raddr", user "user". Return the method and
|
|
|
|
* an optional argument (stored in fields of *port), and STATUS_OK.
|
|
|
|
*
|
2011-06-20 23:20:14 +02:00
|
|
|
* If the file does not contain any entry matching the request, we return
|
|
|
|
* method = uaImplicitReject.
|
2001-07-30 16:50:24 +02:00
|
|
|
*/
|
2011-06-20 23:20:14 +02:00
|
|
|
void
|
2001-07-30 16:50:24 +02:00
|
|
|
hba_getauthmethod(hbaPort *port)
|
1996-10-12 09:47:12 +02:00
|
|
|
{
|
2011-06-20 23:20:14 +02:00
|
|
|
check_hba(port);
|
2001-07-30 16:50:24 +02:00
|
|
|
}
|
Add some information about authenticated identity via log_connections
The "authenticated identity" is the string used by an authentication
method to identify a particular user. In many common cases, this is the
same as the PostgreSQL username, but for some third-party authentication
methods, the identifier in use may be shortened or otherwise translated
(e.g. through pg_ident user mappings) before the server stores it.
To help administrators see who has actually interacted with the system,
this commit adds the capability to store the original identity when
authentication succeeds within the backend's Port, and generates a log
entry when log_connections is enabled. The log entries generated look
something like this (where a local user named "foouser" is connecting to
the database as the database user called "admin"):
LOG: connection received: host=[local]
LOG: connection authenticated: identity="foouser" method=peer (/data/pg_hba.conf:88)
LOG: connection authorized: user=admin database=postgres application_name=psql
Port->authn_id is set according to the authentication method:
bsd: the PostgreSQL username (aka the local username)
cert: the client's Subject DN
gss: the user principal
ident: the remote username
ldap: the final bind DN
pam: the PostgreSQL username (aka PAM username)
password (and all pw-challenge methods): the PostgreSQL username
peer: the peer's pw_name
radius: the PostgreSQL username (aka the RADIUS username)
sspi: either the down-level (SAM-compatible) logon name, if
compat_realm=1, or the User Principal Name if compat_realm=0
The trust auth method does not set an authenticated identity. Neither
does clientcert=verify-full.
Port->authn_id could be used for other purposes, like a superuser-only
extra column in pg_stat_activity, but this is left as future work.
PostgresNode::connect_{ok,fails}() have been modified to let tests check
the backend log files for required or prohibited patterns, using the
new log_like and log_unlike parameters. This uses a method based on a
truncation of the existing server log file, like issues_sql_like().
Tests are added to the ldap, kerberos, authentication and SSL test
suites.
Author: Jacob Champion
Reviewed-by: Stephen Frost, Magnus Hagander, Tom Lane, Michael Paquier
Discussion: https://postgr.es/m/c55788dd1773c521c862e8e0dddb367df51222be.camel@vmware.com
2021-04-07 03:16:39 +02:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Return the name of the auth method in use ("gss", "md5", "trust", etc.).
|
|
|
|
*
|
|
|
|
* The return value is statically allocated (see the UserAuthName array) and
|
|
|
|
* should not be freed.
|
|
|
|
*/
|
|
|
|
const char *
|
2021-04-07 14:21:19 +02:00
|
|
|
hba_authname(UserAuth auth_method)
|
Add some information about authenticated identity via log_connections
The "authenticated identity" is the string used by an authentication
method to identify a particular user. In many common cases, this is the
same as the PostgreSQL username, but for some third-party authentication
methods, the identifier in use may be shortened or otherwise translated
(e.g. through pg_ident user mappings) before the server stores it.
To help administrators see who has actually interacted with the system,
this commit adds the capability to store the original identity when
authentication succeeds within the backend's Port, and generates a log
entry when log_connections is enabled. The log entries generated look
something like this (where a local user named "foouser" is connecting to
the database as the database user called "admin"):
LOG: connection received: host=[local]
LOG: connection authenticated: identity="foouser" method=peer (/data/pg_hba.conf:88)
LOG: connection authorized: user=admin database=postgres application_name=psql
Port->authn_id is set according to the authentication method:
bsd: the PostgreSQL username (aka the local username)
cert: the client's Subject DN
gss: the user principal
ident: the remote username
ldap: the final bind DN
pam: the PostgreSQL username (aka PAM username)
password (and all pw-challenge methods): the PostgreSQL username
peer: the peer's pw_name
radius: the PostgreSQL username (aka the RADIUS username)
sspi: either the down-level (SAM-compatible) logon name, if
compat_realm=1, or the User Principal Name if compat_realm=0
The trust auth method does not set an authenticated identity. Neither
does clientcert=verify-full.
Port->authn_id could be used for other purposes, like a superuser-only
extra column in pg_stat_activity, but this is left as future work.
PostgresNode::connect_{ok,fails}() have been modified to let tests check
the backend log files for required or prohibited patterns, using the
new log_like and log_unlike parameters. This uses a method based on a
truncation of the existing server log file, like issues_sql_like().
Tests are added to the ldap, kerberos, authentication and SSL test
suites.
Author: Jacob Champion
Reviewed-by: Stephen Frost, Magnus Hagander, Tom Lane, Michael Paquier
Discussion: https://postgr.es/m/c55788dd1773c521c862e8e0dddb367df51222be.camel@vmware.com
2021-04-07 03:16:39 +02:00
|
|
|
{
|
|
|
|
return UserAuthName[auth_method];
|
|
|
|
}
|