#include "postgres.h"#include <ctype.h>#include <pwd.h>#include <fcntl.h>#include <sys/param.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <unistd.h>#include "catalog/pg_collation.h"#include "libpq/ip.h"#include "libpq/libpq.h"#include "postmaster/postmaster.h"#include "regex/regex.h"#include "replication/walsender.h"#include "storage/fd.h"#include "utils/acl.h"#include "utils/guc.h"#include "utils/lsyscache.h"#include "utils/memutils.h"
Go to the source code of this file.
Data Structures | |
| struct | check_network_data |
| struct | HbaToken |
Defines | |
| #define | atooid(x) ((Oid) strtoul((x), NULL, 10)) |
| #define | atoxid(x) ((TransactionId) strtoul((x), NULL, 10)) |
| #define | MAX_TOKEN 256 |
| #define | MAX_LINE 8192 |
| #define | token_is_keyword(t, k) (!t->quoted && strcmp(t->string, k) == 0) |
| #define | token_matches(t, k) (strcmp(t->string, k) == 0) |
| #define | INVALID_AUTH_OPTION(optname, validmethods) |
| #define | REQUIRE_AUTH_OPTION(methodval, optname, validmethods) |
| #define | MANDATORY_AUTH_ARG(argvar, argname, authname) |
| #define | IDENT_FIELD_ABSENT(field) |
| #define | IDENT_MULTI_VALUE(tokens) |
Typedefs | |
| typedef struct check_network_data | check_network_data |
| typedef struct HbaToken | HbaToken |
Functions | |
| static MemoryContext | tokenize_file (const char *filename, FILE *file, List **lines, List **line_nums, List **raw_lines) |
| static List * | tokenize_inc_file (List *tokens, const char *outer_filename, const char *inc_filename) |
| static bool | parse_hba_auth_opt (char *name, char *val, HbaLine *hbaline, int line_num) |
| bool | pg_isblank (const char c) |
| static bool | next_token (char **lineptr, char *buf, int bufsz, bool *initial_quote, bool *terminating_comma) |
| static HbaToken * | make_hba_token (char *token, bool quoted) |
| static HbaToken * | copy_hba_token (HbaToken *in) |
| static List * | next_field_expand (const char *filename, char **lineptr) |
| static bool | is_member (Oid userid, const char *role) |
| static bool | check_role (const char *role, Oid roleid, List *tokens) |
| static bool | check_db (const char *dbname, const char *role, Oid roleid, List *tokens) |
| static bool | ipv4eq (struct sockaddr_in *a, struct sockaddr_in *b) |
| static bool | hostname_match (const char *pattern, const char *actual_hostname) |
| static bool | check_hostname (hbaPort *port, const char *hostname) |
| static bool | check_ip (SockAddr *raddr, struct sockaddr *addr, struct sockaddr *mask) |
| static void | check_network_callback (struct sockaddr *addr, struct sockaddr *netmask, void *cb_data) |
| static bool | check_same_host_or_net (SockAddr *raddr, IPCompareMethod method) |
| static HbaLine * | parse_hba_line (List *line, int line_num, char *raw_line) |
| static void | check_hba (hbaPort *port) |
| bool | load_hba (void) |
| static IdentLine * | parse_ident_line (List *line, int line_number) |
| static void | check_ident_usermap (IdentLine *identLine, const char *usermap_name, const char *pg_role, const char *ident_user, bool case_insensitive, bool *found_p, bool *error_p) |
| int | check_usermap (const char *usermap_name, const char *pg_role, const char *auth_user, bool case_insensitive) |
| bool | load_ident (void) |
| void | hba_getauthmethod (hbaPort *port) |
Variables | |
| static List * | parsed_hba_lines = NIL |
| static MemoryContext | parsed_hba_context = NULL |
| static List * | parsed_ident_lines = NIL |
| static MemoryContext | parsed_ident_context = NULL |
| #define atoxid | ( | x | ) | ((TransactionId) strtoul((x), NULL, 10)) |
| #define IDENT_FIELD_ABSENT | ( | field | ) |
do {\ if (!field) { \ ereport(LOG, \ (errcode(ERRCODE_CONFIG_FILE_ERROR), \ errmsg("missing entry in file \"%s\" at end of line %d", \ IdentFileName, line_number))); \ return NULL; \ } \ } while (0);
Definition at line 806 of file hba.c.
Referenced by parse_ident_line().
| #define IDENT_MULTI_VALUE | ( | tokens | ) |
do {\ if (tokens->length > 1) { \ ereport(LOG, \ (errcode(ERRCODE_CONFIG_FILE_ERROR), \ errmsg("multiple values in ident field"), \ errcontext("line %d of configuration file \"%s\"", \ line_number, IdentFileName))); \ return NULL; \ } \ } while (0);
Definition at line 816 of file hba.c.
Referenced by parse_ident_line().
| #define INVALID_AUTH_OPTION | ( | optname, | ||
| validmethods | ||||
| ) |
do {\ ereport(LOG, \ (errcode(ERRCODE_CONFIG_FILE_ERROR), \ /* translator: the second %s is a list of auth methods */ \ errmsg("authentication option \"%s\" is only valid for authentication methods %s", \ optname, _(validmethods)), \ errcontext("line %d of configuration file \"%s\"", \ line_num, HbaFileName))); \ return false; \ } while (0);
Definition at line 769 of file hba.c.
Referenced by parse_hba_auth_opt().
| #define MANDATORY_AUTH_ARG | ( | argvar, | ||
| argname, | ||||
| authname | ||||
| ) |
do {\ if (argvar == NULL) {\ ereport(LOG, \ (errcode(ERRCODE_CONFIG_FILE_ERROR), \ errmsg("authentication method \"%s\" requires argument \"%s\" to be set", \ authname, argname), \ errcontext("line %d of configuration file \"%s\"", \ line_num, HbaFileName))); \ return NULL; \ } \ } while (0);
Definition at line 785 of file hba.c.
Referenced by parse_hba_line().
| #define MAX_LINE 8192 |
Definition at line 53 of file hba.c.
Referenced by tokenize_file().
| #define REQUIRE_AUTH_OPTION | ( | methodval, | ||
| optname, | ||||
| validmethods | ||||
| ) |
do {\ if (hbaline->auth_method != methodval) \ INVALID_AUTH_OPTION(optname, validmethods); \ } while (0);
Definition at line 780 of file hba.c.
Referenced by parse_hba_auth_opt().
| #define token_is_keyword | ( | t, | ||
| k | ||||
| ) | (!t->quoted && strcmp(t->string, k) == 0) |
Definition at line 64 of file hba.c.
Referenced by check_db(), check_role(), and parse_hba_line().
| #define token_matches | ( | t, | ||
| k | ||||
| ) | (strcmp(t->string, k) == 0) |
Definition at line 65 of file hba.c.
Referenced by check_db(), and check_role().
| typedef struct check_network_data check_network_data |
Definition at line 508 of file hba.c.
References am_walsender, is_member(), lfirst, token_is_keyword, and token_matches.
Referenced by check_hba().
{
ListCell *cell;
HbaToken *tok;
foreach(cell, tokens)
{
tok = lfirst(cell);
if (am_walsender)
{
/* walsender connections can only match replication keyword */
if (token_is_keyword(tok, "replication"))
return true;
}
else if (token_is_keyword(tok, "all"))
return true;
else if (token_is_keyword(tok, "sameuser"))
{
if (strcmp(dbname, role) == 0)
return true;
}
else if (token_is_keyword(tok, "samegroup") ||
token_is_keyword(tok, "samerole"))
{
if (is_member(roleid, dbname))
return true;
}
else if (token_is_keyword(tok, "replication"))
continue; /* never match this if not walsender */
else if (token_matches(tok, dbname))
return true;
}
return false;
}
| static void check_hba | ( | hbaPort * | port | ) | [static] |
Definition at line 1675 of file hba.c.
References HbaLine::addr, SockAddr::addr, HbaLine::auth_method, check_db(), check_hostname(), check_ip(), check_role(), check_same_host_or_net(), HbaLine::conntype, ctHostNoSSL, ctHostSSL, ctLocal, Port::database_name, HbaLine::databases, get_role_oid(), Port::hba, HbaLine::hostname, HbaLine::ip_cmp_method, ipCmpAll, ipCmpMask, ipCmpSameHost, ipCmpSameNet, IS_AF_UNIX, lfirst, HbaLine::mask, palloc0(), Port::raddr, HbaLine::roles, and Port::user_name.
Referenced by hba_getauthmethod().
{
Oid roleid;
ListCell *line;
HbaLine *hba;
/* Get the target role's OID. Note we do not error out for bad role. */
roleid = get_role_oid(port->user_name, true);
foreach(line, parsed_hba_lines)
{
hba = (HbaLine *) lfirst(line);
/* Check connection type */
if (hba->conntype == ctLocal)
{
if (!IS_AF_UNIX(port->raddr.addr.ss_family))
continue;
}
else
{
if (IS_AF_UNIX(port->raddr.addr.ss_family))
continue;
/* Check SSL state */
#ifdef USE_SSL
if (port->ssl)
{
/* 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;
}
#else
/* No SSL support, so reject "hostssl" lines */
if (hba->conntype == ctHostSSL)
continue;
#endif
/* Check IP address */
switch (hba->ip_cmp_method)
{
case ipCmpMask:
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;
}
break;
case ipCmpAll:
break;
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 */
continue;
}
} /* != ctLocal */
/* Check database and role */
if (!check_db(port->database_name, port->user_name, roleid,
hba->databases))
continue;
if (!check_role(port->user_name, roleid, hba->roles))
continue;
/* Found a record that matched! */
port->hba = hba;
return;
}
/* If no matching entry was found, then implicitly reject. */
hba = palloc0(sizeof(HbaLine));
hba->auth_method = uaImplicitReject;
port->hba = hba;
}
Definition at line 588 of file hba.c.
References SockAddr::addr, addrinfo::ai_addr, addrinfo::ai_next, DEBUG2, elog, ereport, errmsg(), ERROR, freeaddrinfo, gai_strerror, getaddrinfo, hostname_match(), ipv4eq(), NULL, pg_getnameinfo_all(), pstrdup(), Port::raddr, Port::remote_hostname, Port::remote_hostname_resolv, and SockAddr::salen.
Referenced by check_hba().
{
struct addrinfo *gai_result,
*gai;
int ret;
bool found;
/* Lookup remote host name if not already done */
if (!port->remote_hostname)
{
char remote_hostname[NI_MAXHOST];
if (pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
remote_hostname, sizeof(remote_hostname),
NULL, 0,
0) != 0)
return false;
port->remote_hostname = pstrdup(remote_hostname);
}
if (!hostname_match(hostname, port->remote_hostname))
return false;
/* Lookup IP from host name and check against original IP */
if (port->remote_hostname_resolv == +1)
return true;
if (port->remote_hostname_resolv == -1)
return false;
ret = getaddrinfo(port->remote_hostname, NULL, NULL, &gai_result);
if (ret != 0)
ereport(ERROR,
(errmsg("could not translate host name \"%s\" to address: %s",
port->remote_hostname, gai_strerror(ret))));
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;
}
}
#ifdef HAVE_IPV6
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;
}
}
#endif
}
}
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;
}
| static void check_ident_usermap | ( | IdentLine * | identLine, | |
| const char * | usermap_name, | |||
| const char * | pg_role, | |||
| const char * | ident_user, | |||
| bool | case_insensitive, | |||
| bool * | found_p, | |||
| bool * | error_p | |||
| ) | [static] |
Definition at line 1967 of file hba.c.
References ereport, errcode(), errmsg(), IdentLine::ident_user, LOG, NULL, palloc(), palloc0(), pfree(), pg_mb2wchar_with_len(), pg_regerror(), pg_regexec(), IdentLine::pg_role, pg_strcasecmp(), pstrdup(), IdentLine::re, REG_NOMATCH, regmatch_t::rm_eo, regmatch_t::rm_so, and IdentLine::usermap.
Referenced by check_usermap().
{
*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;
/* Match? */
if (identLine->ident_user[0] == '/')
{
/*
* When system username starts with a slash, treat it as a regular
* expression. In this case, we 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.
*/
int r;
regmatch_t matches[2];
pg_wchar *wstr;
int wlen;
char *ofs;
char *regexp_pgrole;
wstr = palloc((strlen(ident_user) + 1) * sizeof(pg_wchar));
wlen = pg_mb2wchar_with_len(ident_user, wstr, strlen(ident_user));
r = pg_regexec(&identLine->re, wstr, wlen, 0, NULL, 2, matches, 0);
if (r)
{
char errstr[100];
if (r != REG_NOMATCH)
{
/* REG_NOMATCH is not an error, everything else is */
pg_regerror(r, &identLine->re, errstr, sizeof(errstr));
ereport(LOG,
(errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
errmsg("regular expression match for \"%s\" failed: %s",
identLine->ident_user + 1, errstr)));
*error_p = true;
}
pfree(wstr);
return;
}
pfree(wstr);
if ((ofs = strstr(identLine->pg_role, "\\1")) != NULL)
{
/* substitution of the first argument requested */
if (matches[1].rm_so < 0)
{
ereport(LOG,
(errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
errmsg("regular expression \"%s\" has no subexpressions as requested by backreference in \"%s\"",
identLine->ident_user + 1, identLine->pg_role)));
*error_p = true;
return;
}
/*
* length: original length minus length of \1 plus length of match
* plus null terminator
*/
regexp_pgrole = palloc0(strlen(identLine->pg_role) - 2 + (matches[1].rm_eo - matches[1].rm_so) + 1);
strncpy(regexp_pgrole, identLine->pg_role, (ofs - identLine->pg_role));
memcpy(regexp_pgrole + strlen(regexp_pgrole),
ident_user + matches[1].rm_so,
matches[1].rm_eo - matches[1].rm_so);
strcat(regexp_pgrole, ofs + 2);
}
else
{
/* no substitution, so copy the match */
regexp_pgrole = pstrdup(identLine->pg_role);
}
/*
* now check if the username actually matched what the user is trying
* to connect as
*/
if (case_insensitive)
{
if (pg_strcasecmp(regexp_pgrole, pg_role) == 0)
*found_p = true;
}
else
{
if (strcmp(regexp_pgrole, pg_role) == 0)
*found_p = true;
}
pfree(regexp_pgrole);
return;
}
else
{
/* Not regular expression, so make complete match */
if (case_insensitive)
{
if (pg_strcasecmp(identLine->pg_role, pg_role) == 0 &&
pg_strcasecmp(identLine->ident_user, ident_user) == 0)
*found_p = true;
}
else
{
if (strcmp(identLine->pg_role, pg_role) == 0 &&
strcmp(identLine->ident_user, ident_user) == 0)
*found_p = true;
}
}
return;
}
Definition at line 669 of file hba.c.
References SockAddr::addr, and pg_range_sockaddr().
Referenced by check_hba(), and check_network_callback().
{
if (raddr->addr.ss_family == addr->sa_family)
{
/* Same address family */
if (!pg_range_sockaddr(&raddr->addr,
(struct sockaddr_storage *) addr,
(struct sockaddr_storage *) mask))
return false;
}
#ifdef HAVE_IPV6
else if (addr->sa_family == AF_INET &&
raddr->addr.ss_family == AF_INET6)
{
/*
* If we're connected on IPv6 but the file specifies an IPv4 address
* to match against, promote the latter to an IPv6 address before
* trying to match the client's address.
*/
struct sockaddr_storage addrcopy,
maskcopy;
memcpy(&addrcopy, &addr, sizeof(addrcopy));
memcpy(&maskcopy, &mask, sizeof(maskcopy));
pg_promote_v4_to_v6_addr(&addrcopy);
pg_promote_v4_to_v6_mask(&maskcopy);
if (!pg_range_sockaddr(&raddr->addr, &addrcopy, &maskcopy))
return false;
}
#endif /* HAVE_IPV6 */
else
{
/* Wrong address family, no IPV6 */
return false;
}
return true;
}
| static void check_network_callback | ( | struct sockaddr * | addr, | |
| struct sockaddr * | netmask, | |||
| void * | cb_data | |||
| ) | [static] |
Definition at line 713 of file hba.c.
References check_ip(), ipCmpSameHost, check_network_data::method, NULL, pg_sockaddr_cidr_mask(), check_network_data::raddr, and check_network_data::result.
Referenced by check_same_host_or_net().
{
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);
}
}
Definition at line 484 of file hba.c.
References is_member(), lfirst, HbaToken::quoted, HbaToken::string, token_is_keyword, and token_matches.
{
ListCell *cell;
HbaToken *tok;
foreach(cell, tokens)
{
tok = lfirst(cell);
if (!tok->quoted && tok->string[0] == '+')
{
if (is_member(roleid, tok->string + 1))
return true;
}
else if (token_matches(tok, role) ||
token_is_keyword(tok, "all"))
return true;
}
return false;
}
| static bool check_same_host_or_net | ( | SockAddr * | raddr, | |
| IPCompareMethod | method | |||
| ) | [static] |
Definition at line 740 of file hba.c.
References check_network_callback(), elog, LOG, check_network_data::method, pg_foreach_ifaddr(), check_network_data::raddr, and check_network_data::result.
Referenced by check_hba().
{
check_network_data cn;
cn.method = method;
cn.raddr = raddr;
cn.result = false;
errno = 0;
if (pg_foreach_ifaddr(check_network_callback, &cn) < 0)
{
elog(LOG, "error enumerating network interfaces: %m");
return false;
}
return cn.result;
}
| int check_usermap | ( | const char * | usermap_name, | |
| const char * | pg_role, | |||
| const char * | auth_user, | |||
| bool | case_insensitive | |||
| ) |
Definition at line 2100 of file hba.c.
References check_ident_usermap(), ereport, errmsg(), error(), lfirst, LOG, NULL, pg_strcasecmp(), and STATUS_OK.
Referenced by ident_inet().
{
bool found_entry = false,
error = false;
if (usermap_name == NULL || usermap_name[0] == '\0')
{
if (case_insensitive)
{
if (pg_strcasecmp(pg_role, auth_user) == 0)
return STATUS_OK;
}
else
{
if (strcmp(pg_role, auth_user) == 0)
return STATUS_OK;
}
ereport(LOG,
(errmsg("provided user name (%s) and authenticated user name (%s) do not match",
pg_role, auth_user)));
return STATUS_ERROR;
}
else
{
ListCell *line_cell;
foreach(line_cell, parsed_ident_lines)
{
check_ident_usermap(lfirst(line_cell), usermap_name,
pg_role, auth_user, case_insensitive,
&found_entry, &error);
if (found_entry || error)
break;
}
}
if (!found_entry && !error)
{
ereport(LOG,
(errmsg("no match in usermap \"%s\" for user \"%s\" authenticated as \"%s\"",
usermap_name, pg_role, auth_user)));
}
return found_entry ? STATUS_OK : STATUS_ERROR;
}
Definition at line 253 of file hba.c.
References make_hba_token(), HbaToken::quoted, and HbaToken::string.
Referenced by parse_hba_line(), and tokenize_inc_file().
{
HbaToken *out = make_hba_token(in->string, in->quoted);
return out;
}
| void hba_getauthmethod | ( | hbaPort * | port | ) |
Definition at line 2265 of file hba.c.
References check_hba().
Referenced by ClientAuthentication().
{
check_hba(port);
}
| static bool hostname_match | ( | const char * | pattern, | |
| const char * | actual_hostname | |||
| ) | [static] |
Definition at line 568 of file hba.c.
References pg_strcasecmp().
Referenced by check_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);
}
| static bool ipv4eq | ( | struct sockaddr_in * | a, | |
| struct sockaddr_in * | b | |||
| ) | [static] |
Definition at line 544 of file hba.c.
Referenced by check_hostname().
{
return (a->sin_addr.s_addr == b->sin_addr.s_addr);
}
Definition at line 460 of file hba.c.
References get_role_oid(), is_member_of_role_nosuper(), and OidIsValid.
Referenced by check_db(), and check_role().
{
Oid roleid;
if (!OidIsValid(userid))
return false; /* if user not exist, say "no" */
roleid = get_role_oid(role, true);
if (!OidIsValid(roleid))
return false; /* if target role not exist, say "no" */
/*
* 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);
}
| bool load_hba | ( | void | ) |
Definition at line 1782 of file hba.c.
References AllocateFile(), ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, AllocSetContextCreate(), ereport, errcode(), errcode_for_file_access(), errmsg(), forthree, FreeFile(), HbaFileName, lappend(), lfirst, lfirst_int, LOG, MemoryContextDelete(), MemoryContextReset(), MemoryContextSwitchTo(), NIL, NULL, parse_hba_line(), tokenize_file(), and TopMemoryContext.
Referenced by PerformAuthentication(), PostmasterMain(), and SIGHUP_handler().
{
FILE *file;
List *hba_lines = NIL;
List *hba_line_nums = NIL;
List *hba_raw_lines = NIL;
ListCell *line,
*line_num,
*raw_line;
List *new_parsed_lines = NIL;
bool ok = true;
MemoryContext linecxt;
MemoryContext oldcxt;
MemoryContext hbacxt;
file = AllocateFile(HbaFileName, "r");
if (file == NULL)
{
ereport(LOG,
(errcode_for_file_access(),
errmsg("could not open configuration file \"%s\": %m",
HbaFileName)));
return false;
}
linecxt = tokenize_file(HbaFileName, file, &hba_lines, &hba_line_nums, &hba_raw_lines);
FreeFile(file);
/* Now parse all the lines */
hbacxt = AllocSetContextCreate(TopMemoryContext,
"hba parser context",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
oldcxt = MemoryContextSwitchTo(hbacxt);
forthree(line, hba_lines, line_num, hba_line_nums, raw_line, hba_raw_lines)
{
HbaLine *newline;
if ((newline = parse_hba_line(lfirst(line), lfirst_int(line_num), lfirst(raw_line))) == NULL)
{
/*
* Parse error in the file, so indicate there's a problem. NB: a
* problem in a line will free the memory for all previous lines
* as well!
*/
MemoryContextReset(hbacxt);
new_parsed_lines = NIL;
ok = false;
/*
* Keep parsing the rest of the file so we can report errors on
* more than the first row. Error has already been reported in the
* parsing function, so no need to log it here.
*/
continue;
}
new_parsed_lines = lappend(new_parsed_lines, newline);
}
/*
* 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;
}
/* Free tokenizer memory */
MemoryContextDelete(linecxt);
MemoryContextSwitchTo(oldcxt);
if (!ok)
{
/* File contained one or more errors, so bail out */
MemoryContextDelete(hbacxt);
return false;
}
/* Loaded new file successfully, replace the one we use */
if (parsed_hba_context != NULL)
MemoryContextDelete(parsed_hba_context);
parsed_hba_context = hbacxt;
parsed_hba_lines = new_parsed_lines;
return true;
}
| bool load_ident | ( | void | ) |
Definition at line 2155 of file hba.c.
References AllocateFile(), ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, AllocSetContextCreate(), ereport, errcode_for_file_access(), errmsg(), forboth, FreeFile(), IdentLine::ident_user, IdentFileName, lappend(), lfirst, lfirst_int, LOG, MemoryContextDelete(), MemoryContextReset(), MemoryContextSwitchTo(), NULL, parse_ident_line(), pg_regfree(), IdentLine::re, tokenize_file(), and TopMemoryContext.
Referenced by PerformAuthentication(), PostmasterMain(), and SIGHUP_handler().
{
FILE *file;
List *ident_lines = NIL;
List *ident_line_nums = NIL;
ListCell *line_cell,
*num_cell,
*parsed_line_cell;
List *new_parsed_lines = NIL;
bool ok = true;
MemoryContext linecxt;
MemoryContext oldcxt;
MemoryContext ident_context;
IdentLine *newline;
file = AllocateFile(IdentFileName, "r");
if (file == NULL)
{
/* not fatal ... we just won't do any special ident maps */
ereport(LOG,
(errcode_for_file_access(),
errmsg("could not open usermap file \"%s\": %m",
IdentFileName)));
return false;
}
linecxt = tokenize_file(IdentFileName, file, &ident_lines, &ident_line_nums, NULL);
FreeFile(file);
/* Now parse all the lines */
ident_context = AllocSetContextCreate(TopMemoryContext,
"ident parser context",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
oldcxt = MemoryContextSwitchTo(ident_context);
forboth(line_cell, ident_lines, num_cell, ident_line_nums)
{
if ((newline = parse_ident_line(lfirst(line_cell), lfirst_int(num_cell))) == NULL)
{
/*
* Parse error in the file, so indicate there's a problem. Free
* all the memory and regular expressions of lines parsed so far.
*/
foreach(parsed_line_cell, new_parsed_lines)
{
newline = (IdentLine *) lfirst(parsed_line_cell);
if (newline->ident_user[0] == '/')
pg_regfree(&newline->re);
}
MemoryContextReset(ident_context);
new_parsed_lines = NIL;
ok = false;
/*
* Keep parsing the rest of the file so we can report errors on
* more than the first row. Error has already been reported in the
* parsing function, so no need to log it here.
*/
continue;
}
new_parsed_lines = lappend(new_parsed_lines, newline);
}
/* Free tokenizer memory */
MemoryContextDelete(linecxt);
MemoryContextSwitchTo(oldcxt);
if (!ok)
{
/* File contained one or more errors, so bail out */
foreach(parsed_line_cell, new_parsed_lines)
{
newline = (IdentLine *) lfirst(parsed_line_cell);
if (newline->ident_user[0] == '/')
pg_regfree(&newline->re);
}
MemoryContextDelete(ident_context);
return false;
}
/* Loaded new file successfully, replace the one we use */
if (parsed_ident_lines != NULL)
{
foreach(parsed_line_cell, parsed_ident_lines)
{
newline = (IdentLine *) lfirst(parsed_line_cell);
if (newline->ident_user[0] == '/')
pg_regfree(&newline->re);
}
MemoryContextDelete(parsed_ident_context);
}
parsed_ident_context = ident_context;
parsed_ident_lines = new_parsed_lines;
return true;
}
Definition at line 235 of file hba.c.
References palloc(), HbaToken::quoted, and HbaToken::string.
Referenced by copy_hba_token(), and next_field_expand().
| static List* next_field_expand | ( | const char * | filename, | |
| char ** | lineptr | |||
| ) | [static] |
Definition at line 268 of file hba.c.
References buf, lappend(), make_hba_token(), next_token(), and tokenize_inc_file().
Referenced by tokenize_file().
{
char buf[MAX_TOKEN];
bool trailing_comma;
bool initial_quote;
List *tokens = NIL;
do
{
if (!next_token(lineptr, buf, sizeof(buf), &initial_quote, &trailing_comma))
break;
/* Is this referencing a file? */
if (!initial_quote && buf[0] == '@' && buf[1] != '\0')
tokens = tokenize_inc_file(tokens, filename, buf + 1);
else
tokens = lappend(tokens, make_hba_token(buf, initial_quote));
} while (trailing_comma);
return tokens;
}
| static bool next_token | ( | char ** | lineptr, | |
| char * | buf, | |||
| int | bufsz, | |||
| bool * | initial_quote, | |||
| bool * | terminating_comma | |||
| ) | [static] |
Definition at line 139 of file hba.c.
References Assert, ereport, errcode(), errmsg(), LOG, and pg_isblank().
Referenced by next_field_expand().
{
int c;
char *start_buf = buf;
char *end_buf = buf + (bufsz - 2);
bool in_quote = false;
bool was_quote = false;
bool saw_quote = false;
/* end_buf reserves two bytes to ensure we can append \n and \0 */
Assert(end_buf > start_buf);
*initial_quote = false;
*terminating_comma = false;
/* Move over initial whitespace and commas */
while ((c = (*(*lineptr)++)) != '\0' && (pg_isblank(c) || c == ','))
;
if (c == '\0' || c == '\n')
{
*buf = '\0';
return false;
}
/*
* Build a token in buf of next characters up to EOF, EOL, unquoted comma,
* or unquoted whitespace.
*/
while (c != '\0' && c != '\n' &&
(!pg_isblank(c) || in_quote))
{
/* skip comments to EOL */
if (c == '#' && !in_quote)
{
while ((c = (*(*lineptr)++)) != '\0' && c != '\n')
;
/* If only comment, consume EOL too; return EOL */
if (c != '\0' && buf == start_buf)
(*lineptr)++;
break;
}
if (buf >= end_buf)
{
*buf = '\0';
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("authentication file token too long, skipping: \"%s\"",
start_buf)));
/* Discard remainder of line */
while ((c = (*(*lineptr)++)) != '\0' && c != '\n')
;
break;
}
/* we do not pass back the comma in the token */
if (c == ',' && !in_quote)
{
*terminating_comma = true;
break;
}
if (c != '"' || was_quote)
*buf++ = c;
/* Literal double-quote is two double-quotes */
if (in_quote && c == '"')
was_quote = !was_quote;
else
was_quote = false;
if (c == '"')
{
in_quote = !in_quote;
saw_quote = true;
if (buf == start_buf)
*initial_quote = true;
}
c = *(*lineptr)++;
}
/*
* Put back the char right after the token (critical in case it is EOL,
* since we need to detect end-of-line at next call).
*/
(*lineptr)--;
*buf = '\0';
return (saw_quote || buf > start_buf);
}
| static bool parse_hba_auth_opt | ( | char * | name, | |
| char * | val, | |||
| HbaLine * | hbaline, | |||
| int | line_num | |||
| ) | [static] |
Definition at line 1410 of file hba.c.
References addrinfo::ai_family, addrinfo::ai_socktype, HbaLine::auth_method, HbaLine::clientcert, HbaLine::conntype, ctHostSSL, ereport, errcode(), errcontext, errhint(), errmsg(), gai_strerror, gettext_noop, HbaFileName, HbaLine::include_realm, INVALID_AUTH_OPTION, HbaLine::krb_realm, HbaLine::krb_server_hostname, HbaLine::ldapbasedn, HbaLine::ldapbinddn, HbaLine::ldapbindpasswd, HbaLine::ldapport, HbaLine::ldapprefix, HbaLine::ldapscope, HbaLine::ldapsearchattribute, HbaLine::ldapserver, HbaLine::ldapsuffix, HbaLine::ldaptls, LOG, MemSet, NULL, HbaLine::pamservice, pg_freeaddrinfo_all(), pg_getaddrinfo_all(), pstrdup(), HbaLine::radiusidentifier, HbaLine::radiusport, HbaLine::radiussecret, HbaLine::radiusserver, REQUIRE_AUTH_OPTION, secure_loaded_verify_locations(), uaCert, uaGSS, uaIdent, uaKrb5, uaLDAP, uaPAM, uaPeer, uaRADIUS, uaSSPI, and HbaLine::usermap.
Referenced by parse_hba_line().
{
#ifdef USE_LDAP
hbaline->ldapscope = LDAP_SCOPE_SUBTREE;
#endif
if (strcmp(name, "map") == 0)
{
if (hbaline->auth_method != uaIdent &&
hbaline->auth_method != uaPeer &&
hbaline->auth_method != uaKrb5 &&
hbaline->auth_method != uaGSS &&
hbaline->auth_method != uaSSPI &&
hbaline->auth_method != uaCert)
INVALID_AUTH_OPTION("map", gettext_noop("ident, peer, krb5, gssapi, sspi, and cert"));
hbaline->usermap = pstrdup(val);
}
else if (strcmp(name, "clientcert") == 0)
{
/*
* Since we require ctHostSSL, this really can never happen on
* non-SSL-enabled builds, so don't bother checking for USE_SSL.
*/
if (hbaline->conntype != ctHostSSL)
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("clientcert can only be configured for \"hostssl\" rows"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return false;
}
if (strcmp(val, "1") == 0)
{
if (!secure_loaded_verify_locations())
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("client certificates can only be checked if a root certificate store is available"),
errhint("Make sure the configuration parameter \"ssl_ca_file\" is set."),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return false;
}
hbaline->clientcert = true;
}
else
{
if (hbaline->auth_method == uaCert)
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("clientcert can not be set to 0 when using \"cert\" authentication"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return false;
}
hbaline->clientcert = false;
}
}
else if (strcmp(name, "pamservice") == 0)
{
REQUIRE_AUTH_OPTION(uaPAM, "pamservice", "pam");
hbaline->pamservice = pstrdup(val);
}
else if (strcmp(name, "ldapurl") == 0)
{
#ifdef LDAP_API_FEATURE_X_OPENLDAP
LDAPURLDesc *urldata;
int rc;
#endif
REQUIRE_AUTH_OPTION(uaLDAP, "ldapurl", "ldap");
#ifdef LDAP_API_FEATURE_X_OPENLDAP
rc = ldap_url_parse(val, &urldata);
if (rc != LDAP_SUCCESS)
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("could not parse LDAP URL \"%s\": %s", val, ldap_err2string(rc))));
return false;
}
if (strcmp(urldata->lud_scheme, "ldap") != 0)
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("unsupported LDAP URL scheme: %s", urldata->lud_scheme)));
ldap_free_urldesc(urldata);
return false;
}
hbaline->ldapserver = pstrdup(urldata->lud_host);
hbaline->ldapport = urldata->lud_port;
hbaline->ldapbasedn = pstrdup(urldata->lud_dn);
if (urldata->lud_attrs)
hbaline->ldapsearchattribute = pstrdup(urldata->lud_attrs[0]); /* only use first one */
hbaline->ldapscope = urldata->lud_scope;
if (urldata->lud_filter)
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("filters not supported in LDAP URLs")));
ldap_free_urldesc(urldata);
return false;
}
ldap_free_urldesc(urldata);
#else /* not OpenLDAP */
ereport(LOG,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("LDAP URLs not supported on this platform")));
#endif /* not OpenLDAP */
}
else if (strcmp(name, "ldaptls") == 0)
{
REQUIRE_AUTH_OPTION(uaLDAP, "ldaptls", "ldap");
if (strcmp(val, "1") == 0)
hbaline->ldaptls = true;
else
hbaline->ldaptls = false;
}
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)
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid LDAP port number: \"%s\"", val),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return false;
}
}
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);
}
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_server_hostname") == 0)
{
REQUIRE_AUTH_OPTION(uaKrb5, "krb_server_hostname", "krb5");
hbaline->krb_server_hostname = pstrdup(val);
}
else if (strcmp(name, "krb_realm") == 0)
{
if (hbaline->auth_method != uaKrb5 &&
hbaline->auth_method != uaGSS &&
hbaline->auth_method != uaSSPI)
INVALID_AUTH_OPTION("krb_realm", gettext_noop("krb5, gssapi, and sspi"));
hbaline->krb_realm = pstrdup(val);
}
else if (strcmp(name, "include_realm") == 0)
{
if (hbaline->auth_method != uaKrb5 &&
hbaline->auth_method != uaGSS &&
hbaline->auth_method != uaSSPI)
INVALID_AUTH_OPTION("include_realm", gettext_noop("krb5, gssapi, and sspi"));
if (strcmp(val, "1") == 0)
hbaline->include_realm = true;
else
hbaline->include_realm = false;
}
else if (strcmp(name, "radiusserver") == 0)
{
struct addrinfo *gai_result;
struct addrinfo hints;
int ret;
REQUIRE_AUTH_OPTION(uaRADIUS, "radiusserver", "radius");
MemSet(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_DGRAM;
hints.ai_family = AF_UNSPEC;
ret = pg_getaddrinfo_all(val, NULL, &hints, &gai_result);
if (ret || !gai_result)
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("could not translate RADIUS server name \"%s\" to address: %s",
val, gai_strerror(ret)),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
if (gai_result)
pg_freeaddrinfo_all(hints.ai_family, gai_result);
return false;
}
pg_freeaddrinfo_all(hints.ai_family, gai_result);
hbaline->radiusserver = pstrdup(val);
}
else if (strcmp(name, "radiusport") == 0)
{
REQUIRE_AUTH_OPTION(uaRADIUS, "radiusport", "radius");
hbaline->radiusport = atoi(val);
if (hbaline->radiusport == 0)
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid RADIUS port number: \"%s\"", val),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return false;
}
}
else if (strcmp(name, "radiussecret") == 0)
{
REQUIRE_AUTH_OPTION(uaRADIUS, "radiussecret", "radius");
hbaline->radiussecret = pstrdup(val);
}
else if (strcmp(name, "radiusidentifier") == 0)
{
REQUIRE_AUTH_OPTION(uaRADIUS, "radiusidentifier", "radius");
hbaline->radiusidentifier = pstrdup(val);
}
else
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("unrecognized authentication option name: \"%s\"",
name),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return false;
}
return true;
}
Definition at line 840 of file hba.c.
References HbaLine::addr, addrinfo::ai_addr, addrinfo::ai_addrlen, addrinfo::ai_canonname, addrinfo::ai_family, addrinfo::ai_flags, addrinfo::ai_next, addrinfo::ai_protocol, addrinfo::ai_socktype, HbaLine::auth_method, HbaLine::clientcert, HbaLine::conntype, copy_hba_token(), ctHostSSL, ctLocal, HbaLine::databases, Db_user_namespace, EAI_NONAME, EnableSSL, ereport, errcode(), errcontext, errhint(), errmsg(), gai_strerror, HbaFileName, HbaLine::hostname, HbaLine::ip_cmp_method, lappend(), HbaLine::ldapbasedn, HbaLine::ldapbinddn, HbaLine::ldapbindpasswd, HbaLine::ldapprefix, HbaLine::ldapsearchattribute, HbaLine::ldapserver, HbaLine::ldapsuffix, List::length, lfirst, HbaLine::linenumber, linitial, list_head(), lnext, LOG, MANDATORY_AUTH_ARG, HbaLine::mask, NULL, palloc0(), parse_hba_auth_opt(), pfree(), pg_freeaddrinfo_all(), pg_getaddrinfo_all(), pg_sockaddr_cidr_mask(), pstrdup(), HbaLine::radiussecret, HbaLine::radiusserver, HbaLine::rawline, HbaLine::roles, HbaToken::string, token_is_keyword, uaCert, uaGSS, uaIdent, uaKrb5, uaLDAP, uaPeer, uaRADIUS, and val.
Referenced by load_hba().
{
char *str;
struct addrinfo *gai_result;
struct addrinfo hints;
int ret;
char *cidr_slash;
char *unsupauth;
ListCell *field;
List *tokens;
ListCell *tokencell;
HbaToken *token;
HbaLine *parsedline;
parsedline = palloc0(sizeof(HbaLine));
parsedline->linenumber = line_num;
parsedline->rawline = pstrdup(raw_line);
/* Check the record type. */
field = list_head(line);
tokens = lfirst(field);
if (tokens->length > 1)
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("multiple values specified for connection type"),
errhint("Specify exactly one connection type per line."),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
token = linitial(tokens);
if (strcmp(token->string, "local") == 0)
{
#ifdef HAVE_UNIX_SOCKETS
parsedline->conntype = ctLocal;
#else
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("local connections are not supported by this build"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
#endif
}
else if (strcmp(token->string, "host") == 0 ||
strcmp(token->string, "hostssl") == 0 ||
strcmp(token->string, "hostnossl") == 0)
{
if (token->string[4] == 's') /* "hostssl" */
{
/* SSL support must be actually active, else complain */
#ifdef USE_SSL
if (EnableSSL)
parsedline->conntype = ctHostSSL;
else
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("hostssl requires SSL to be turned on"),
errhint("Set ssl = on in postgresql.conf."),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
#else
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("hostssl is not supported by this build"),
errhint("Compile with --with-openssl to use SSL connections."),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
#endif
}
#ifdef USE_SSL
else if (token->string[4] == 'n') /* "hostnossl" */
{
parsedline->conntype = ctHostNoSSL;
}
#endif
else
{
/* "host", or "hostnossl" and SSL support not built in */
parsedline->conntype = ctHost;
}
} /* record type */
else
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid connection type \"%s\"",
token->string),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
/* Get the databases. */
field = lnext(field);
if (!field)
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("end-of-line before database specification"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
parsedline->databases = NIL;
tokens = lfirst(field);
foreach(tokencell, tokens)
{
parsedline->databases = lappend(parsedline->databases,
copy_hba_token(lfirst(tokencell)));
}
/* Get the roles. */
field = lnext(field);
if (!field)
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("end-of-line before role specification"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
parsedline->roles = NIL;
tokens = lfirst(field);
foreach(tokencell, tokens)
{
parsedline->roles = lappend(parsedline->roles,
copy_hba_token(lfirst(tokencell)));
}
if (parsedline->conntype != ctLocal)
{
/* Read the IP address field. (with or without CIDR netmask) */
field = lnext(field);
if (!field)
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("end-of-line before IP address specification"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
tokens = lfirst(field);
if (tokens->length > 1)
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("multiple values specified for host address"),
errhint("Specify one address range per line."),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
token = linitial(tokens);
if (token_is_keyword(token, "all"))
{
parsedline->ip_cmp_method = ipCmpAll;
}
else if (token_is_keyword(token, "samehost"))
{
/* Any IP on this host is allowed to connect */
parsedline->ip_cmp_method = ipCmpSameHost;
}
else if (token_is_keyword(token, "samenet"))
{
/* Any IP on the host's subnets is allowed to connect */
parsedline->ip_cmp_method = ipCmpSameNet;
}
else
{
/* IP and netmask are specified */
parsedline->ip_cmp_method = ipCmpMask;
/* need a modifiable copy of token */
str = pstrdup(token->string);
/* Check if it has a CIDR suffix and if so isolate it */
cidr_slash = strchr(str, '/');
if (cidr_slash)
*cidr_slash = '\0';
/* Get the IP address either way */
hints.ai_flags = AI_NUMERICHOST;
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = 0;
hints.ai_protocol = 0;
hints.ai_addrlen = 0;
hints.ai_canonname = NULL;
hints.ai_addr = NULL;
hints.ai_next = NULL;
ret = pg_getaddrinfo_all(str, NULL, &hints, &gai_result);
if (ret == 0 && gai_result)
memcpy(&parsedline->addr, gai_result->ai_addr,
gai_result->ai_addrlen);
else if (ret == EAI_NONAME)
parsedline->hostname = str;
else
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid IP address \"%s\": %s",
str, gai_strerror(ret)),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
if (gai_result)
pg_freeaddrinfo_all(hints.ai_family, gai_result);
return NULL;
}
pg_freeaddrinfo_all(hints.ai_family, gai_result);
/* Get the netmask */
if (cidr_slash)
{
if (parsedline->hostname)
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("specifying both host name and CIDR mask is invalid: \"%s\"",
token->string),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
if (pg_sockaddr_cidr_mask(&parsedline->mask, cidr_slash + 1,
parsedline->addr.ss_family) < 0)
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid CIDR mask in address \"%s\"",
token->string),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
pfree(str);
}
else if (!parsedline->hostname)
{
/* Read the mask field. */
pfree(str);
field = lnext(field);
if (!field)
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("end-of-line before netmask specification"),
errhint("Specify an address range in CIDR notation, or provide a separate netmask."),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
tokens = lfirst(field);
if (tokens->length > 1)
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("multiple values specified for netmask"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
token = linitial(tokens);
ret = pg_getaddrinfo_all(token->string, NULL,
&hints, &gai_result);
if (ret || !gai_result)
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid IP mask \"%s\": %s",
token->string, gai_strerror(ret)),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
if (gai_result)
pg_freeaddrinfo_all(hints.ai_family, gai_result);
return NULL;
}
memcpy(&parsedline->mask, gai_result->ai_addr,
gai_result->ai_addrlen);
pg_freeaddrinfo_all(hints.ai_family, gai_result);
if (parsedline->addr.ss_family != parsedline->mask.ss_family)
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("IP address and mask do not match"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
}
}
} /* != ctLocal */
/* Get the authentication method */
field = lnext(field);
if (!field)
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("end-of-line before authentication method"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
tokens = lfirst(field);
if (tokens->length > 1)
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("multiple values specified for authentication type"),
errhint("Specify exactly one authentication type per line."),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
token = linitial(tokens);
unsupauth = NULL;
if (strcmp(token->string, "trust") == 0)
parsedline->auth_method = uaTrust;
else if (strcmp(token->string, "ident") == 0)
parsedline->auth_method = uaIdent;
else if (strcmp(token->string, "peer") == 0)
parsedline->auth_method = uaPeer;
else if (strcmp(token->string, "password") == 0)
parsedline->auth_method = uaPassword;
else if (strcmp(token->string, "krb5") == 0)
#ifdef KRB5
parsedline->auth_method = uaKrb5;
#else
unsupauth = "krb5";
#endif
else if (strcmp(token->string, "gss") == 0)
#ifdef ENABLE_GSS
parsedline->auth_method = uaGSS;
#else
unsupauth = "gss";
#endif
else if (strcmp(token->string, "sspi") == 0)
#ifdef ENABLE_SSPI
parsedline->auth_method = uaSSPI;
#else
unsupauth = "sspi";
#endif
else if (strcmp(token->string, "reject") == 0)
parsedline->auth_method = uaReject;
else if (strcmp(token->string, "md5") == 0)
{
if (Db_user_namespace)
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("MD5 authentication is not supported when \"db_user_namespace\" is enabled"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
parsedline->auth_method = uaMD5;
}
else if (strcmp(token->string, "pam") == 0)
#ifdef USE_PAM
parsedline->auth_method = uaPAM;
#else
unsupauth = "pam";
#endif
else if (strcmp(token->string, "ldap") == 0)
#ifdef USE_LDAP
parsedline->auth_method = uaLDAP;
#else
unsupauth = "ldap";
#endif
else if (strcmp(token->string, "cert") == 0)
#ifdef USE_SSL
parsedline->auth_method = uaCert;
#else
unsupauth = "cert";
#endif
else if (strcmp(token->string, "radius") == 0)
parsedline->auth_method = uaRADIUS;
else
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid authentication method \"%s\"",
token->string),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
if (unsupauth)
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid authentication method \"%s\": not supported by this build",
token->string),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
/*
* 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;
/* Invalid authentication combinations */
if (parsedline->conntype == ctLocal &&
parsedline->auth_method == uaKrb5)
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("krb5 authentication is not supported on local sockets"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
if (parsedline->conntype == ctLocal &&
parsedline->auth_method == uaGSS)
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("gssapi authentication is not supported on local sockets"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
if (parsedline->conntype != ctLocal &&
parsedline->auth_method == uaPeer)
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("peer authentication is only supported on local sockets"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
/*
* SSPI authentication can never be enabled on ctLocal connections,
* because it's only supported on Windows, where ctLocal isn't supported.
*/
if (parsedline->conntype != ctHostSSL &&
parsedline->auth_method == uaCert)
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("cert authentication is only supported on hostssl connections"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
/* Parse remaining arguments */
while ((field = lnext(field)) != NULL)
{
tokens = lfirst(field);
foreach(tokencell, tokens)
{
char *val;
token = lfirst(tokencell);
str = pstrdup(token->string);
val = strchr(str, '=');
if (val == NULL)
{
/*
* Got something that's not a name=value pair.
*/
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("authentication option not in name=value format: %s", token->string),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
*val++ = '\0'; /* str now holds "name", val holds "value" */
if (!parse_hba_auth_opt(str, val, parsedline, line_num))
/* parse_hba_auth_opt already logged the error message */
return NULL;
pfree(str);
}
}
/*
* Check if the selected authentication method has any mandatory arguments
* that are not set.
*/
if (parsedline->auth_method == uaLDAP)
{
MANDATORY_AUTH_ARG(parsedline->ldapserver, "ldapserver", "ldap");
/*
* LDAP can operate in two modes: either with a direct bind, using
* ldapprefix and ldapsuffix, or using a search+bind, using
* ldapbasedn, ldapbinddn, ldapbindpasswd and ldapsearchattribute.
* Disallow mixing these parameters.
*/
if (parsedline->ldapprefix || parsedline->ldapsuffix)
{
if (parsedline->ldapbasedn ||
parsedline->ldapbinddn ||
parsedline->ldapbindpasswd ||
parsedline->ldapsearchattribute)
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("cannot use ldapbasedn, ldapbinddn, ldapbindpasswd, ldapsearchattribute, or ldapurl together with ldapprefix"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
}
else if (!parsedline->ldapbasedn)
{
ereport(LOG,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("authentication method \"ldap\" requires argument \"ldapbasedn\", \"ldapprefix\", or \"ldapsuffix\" to be set"),
errcontext("line %d of configuration file \"%s\"",
line_num, HbaFileName)));
return NULL;
}
}
if (parsedline->auth_method == uaRADIUS)
{
MANDATORY_AUTH_ARG(parsedline->radiusserver, "radiusserver", "radius");
MANDATORY_AUTH_ARG(parsedline->radiussecret, "radiussecret", "radius");
}
/*
* Enforce any parameters implied by other settings.
*/
if (parsedline->auth_method == uaCert)
{
parsedline->clientcert = true;
}
return parsedline;
}
Definition at line 1891 of file hba.c.
References Assert, C_COLLATION_OID, ereport, errcode(), errmsg(), IDENT_FIELD_ABSENT, IDENT_MULTI_VALUE, IdentLine::ident_user, lfirst, IdentLine::linenumber, linitial, list_head(), lnext, LOG, NIL, palloc(), palloc0(), pfree(), pg_mb2wchar_with_len(), pg_regcomp(), pg_regerror(), IdentLine::pg_role, pstrdup(), IdentLine::re, REG_ADVANCED, HbaToken::string, and IdentLine::usermap.
Referenced by load_ident().
{
ListCell *field;
List *tokens;
HbaToken *token;
IdentLine *parsedline;
Assert(line != NIL);
field = list_head(line);
parsedline = palloc0(sizeof(IdentLine));
parsedline->linenumber = line_number;
/* Get the map token (must exist) */
tokens = lfirst(field);
IDENT_MULTI_VALUE(tokens);
token = linitial(tokens);
parsedline->usermap = pstrdup(token->string);
/* Get the ident user token */
field = lnext(field);
IDENT_FIELD_ABSENT(field);
tokens = lfirst(field);
IDENT_MULTI_VALUE(tokens);
token = linitial(tokens);
parsedline->ident_user = pstrdup(token->string);
/* Get the PG rolename token */
field = lnext(field);
IDENT_FIELD_ABSENT(field);
tokens = lfirst(field);
IDENT_MULTI_VALUE(tokens);
token = linitial(tokens);
parsedline->pg_role = pstrdup(token->string);
if (parsedline->ident_user[0] == '/')
{
/*
* When system username starts with a slash, treat it as a regular
* expression. Pre-compile it.
*/
int r;
pg_wchar *wstr;
int wlen;
wstr = palloc((strlen(parsedline->ident_user + 1) + 1) * sizeof(pg_wchar));
wlen = pg_mb2wchar_with_len(parsedline->ident_user + 1,
wstr, strlen(parsedline->ident_user + 1));
r = pg_regcomp(&parsedline->re, wstr, wlen, REG_ADVANCED, C_COLLATION_OID);
if (r)
{
char errstr[100];
pg_regerror(r, &parsedline->re, errstr, sizeof(errstr));
ereport(LOG,
(errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
errmsg("invalid regular expression \"%s\": %s",
parsedline->ident_user + 1, errstr)));
pfree(wstr);
return NULL;
}
pfree(wstr);
}
return parsedline;
}
| bool pg_isblank | ( | const char | c | ) |
Definition at line 108 of file hba.c.
Referenced by interpret_ident_response(), and next_token().
| static MemoryContext tokenize_file | ( | const char * | filename, | |
| FILE * | file, | |||
| List ** | lines, | |||
| List ** | line_nums, | |||
| List ** | raw_lines | |||
| ) | [static] |
Definition at line 380 of file hba.c.
References ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, AllocSetContextCreate(), ereport, errcode(), errcontext, errmsg(), ERROR, lappend(), lappend_int(), list_length(), MAX_LINE, MemoryContextSwitchTo(), next_field_expand(), NIL, pstrdup(), and TopMemoryContext.
Referenced by load_hba(), load_ident(), and tokenize_inc_file().
{
List *current_line = NIL;
List *current_field = NIL;
int line_number = 1;
MemoryContext linecxt;
MemoryContext oldcxt;
linecxt = AllocSetContextCreate(TopMemoryContext,
"tokenize file cxt",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
oldcxt = MemoryContextSwitchTo(linecxt);
*lines = *line_nums = NIL;
while (!feof(file) && !ferror(file))
{
char rawline[MAX_LINE];
char *lineptr;
if (!fgets(rawline, sizeof(rawline), file))
break;
if (strlen(rawline) == MAX_LINE-1)
/* Line too long! */
ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("authentication file line too long"),
errcontext("line %d of configuration file \"%s\"",
line_number, filename)));
/* Strip trailing linebreak from rawline */
while (rawline[strlen(rawline)-1] == '\n' ||
rawline[strlen(rawline)-1] == '\r')
rawline[strlen(rawline)-1] = '\0';
lineptr = rawline;
while (strlen(lineptr) > 0)
{
current_field = next_field_expand(filename, &lineptr);
/* add tokens to list, unless we are at EOL or comment start */
if (list_length(current_field) > 0)
{
if (current_line == NIL)
{
/* make a new line List, record its line number */
current_line = lappend(current_line, current_field);
*lines = lappend(*lines, current_line);
*line_nums = lappend_int(*line_nums, line_number);
if (raw_lines)
*raw_lines = lappend(*raw_lines, pstrdup(rawline));
}
else
{
/* append tokens to current line's list */
current_line = lappend(current_line, current_field);
}
}
}
/* we are at real or logical EOL, so force a new line List */
current_line = NIL;
line_number++;
}
MemoryContextSwitchTo(oldcxt);
return linecxt;
}
| static List * tokenize_inc_file | ( | List * | tokens, | |
| const char * | outer_filename, | |||
| const char * | inc_filename | |||
| ) | [static] |
Definition at line 300 of file hba.c.
References AllocateFile(), canonicalize_path(), copy_hba_token(), ereport, errcode_for_file_access(), errmsg(), FreeFile(), get_parent_directory(), is_absolute_path, join_path_components(), lappend(), lfirst, LOG, MemoryContextDelete(), NULL, palloc(), pfree(), pstrdup(), and tokenize_file().
Referenced by next_field_expand().
{
char *inc_fullname;
FILE *inc_file;
List *inc_lines;
List *inc_line_nums;
ListCell *inc_line;
MemoryContext linecxt;
if (is_absolute_path(inc_filename))
{
/* absolute path is taken as-is */
inc_fullname = pstrdup(inc_filename);
}
else
{
/* relative path is relative to dir of calling file */
inc_fullname = (char *) palloc(strlen(outer_filename) + 1 +
strlen(inc_filename) + 1);
strcpy(inc_fullname, outer_filename);
get_parent_directory(inc_fullname);
join_path_components(inc_fullname, inc_fullname, inc_filename);
canonicalize_path(inc_fullname);
}
inc_file = AllocateFile(inc_fullname, "r");
if (inc_file == NULL)
{
ereport(LOG,
(errcode_for_file_access(),
errmsg("could not open secondary authentication file \"@%s\" as \"%s\": %m",
inc_filename, inc_fullname)));
pfree(inc_fullname);
return tokens;
}
/* There is possible recursion here if the file contains @ */
linecxt = tokenize_file(inc_fullname, inc_file, &inc_lines, &inc_line_nums, NULL);
FreeFile(inc_file);
pfree(inc_fullname);
foreach(inc_line, inc_lines)
{
List *inc_fields = lfirst(inc_line);
ListCell *inc_field;
foreach(inc_field, inc_fields)
{
List *inc_tokens = lfirst(inc_field);
ListCell *inc_token;
foreach(inc_token, inc_tokens)
{
HbaToken *token = lfirst(inc_token);
tokens = lappend(tokens, copy_hba_token(token));
}
}
}
MemoryContextDelete(linecxt);
return tokens;
}
MemoryContext parsed_hba_context = NULL [static] |
List* parsed_hba_lines = NIL [static] |
MemoryContext parsed_ident_context = NULL [static] |
List* parsed_ident_lines = NIL [static] |
1.7.1