#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] |