/* callback data for check_network_callback */ typedefstruct check_network_data
{
IPCompareMethod method; /* test method */
SockAddr *raddr; /* client's actual address */ bool result; /* set to true if match */
} check_network_data;
typedefstruct
{ constchar *filename; int linenum;
} tokenize_error_callback_arg;
/* *MakesureUserAuthName[]tracksadditionstotheUserAuthenum
*/
StaticAssertDecl(lengthof(UserAuthName) == USER_AUTH_LAST + 1, "UserAuthName[] must match the UserAuth enum");
static List *tokenize_expand_file(List *tokens, constchar *outer_filename, constchar *inc_filename, int elevel, int depth, char **err_msg); staticbool parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline, int elevel, char **err_msg); staticint regcomp_auth_token(AuthToken *token, char *filename, int line_num, char **err_msg, int elevel); staticint regexec_auth_token(constchar *match, AuthToken *token,
size_t nmatch, regmatch_t pmatch[]); staticvoid tokenize_error_callback(void *arg);
/* *isblank()existsintheISOC99spec,butit'snotveryportableyet, *soprovideourownversion.
*/ bool
pg_isblank(constchar c)
{ return c == ' ' || c == '\t' || c == '\r';
}
/* If this is the last cleanup, remove the tokenization context */ if (depth == CONF_FILE_START_DEPTH)
{
MemoryContextDelete(tokenize_context);
tokenize_context = NULL;
}
}
/* *Rejecttoo-deepincludenestingdepth.Thisisjustasafetycheckto *avoiddumpingcoreduetostackoverflowifanincludefileloopsback *toitself.Themaximumnestingdepthisprettyarbitrary.
*/ if (depth > CONF_FILE_MAX_DEPTH)
{
ereport(elevel,
(errcode_for_file_access(),
errmsg("could not open file \"%s\": maximum nesting depth exceeded",
filename))); if (err_msg)
*err_msg = psprintf("could not open file \"%s\": maximum nesting depth exceeded",
filename); return NULL;
}
file = AllocateFile(filename, "r"); if (file == NULL)
{ int save_errno = errno;
ereport(elevel,
(errcode_for_file_access(),
errmsg("could not open file \"%s\": %m",
filename))); if (err_msg)
{
errno = save_errno;
*err_msg = psprintf("could not open file \"%s\": %m",
filename);
} /* the caller may care about some specific errno */
errno = save_errno; return NULL;
}
/* Now see if remote host name matches this pg_hba line */ if (!hostname_match(hostname, port->remote_hostname)) returnfalse;
/* If we already verified the forward lookup, we're done */ if (port->remote_hostname_resolv == +1) returntrue;
/* Lookup IP from host name and check against original IP */
ret = getaddrinfo(port->remote_hostname, NULL, NULL, &gai_result); if (ret != 0)
{ /* remember failure; don't complain in the postmaster log yet */
port->remote_hostname_resolv = -2;
port->remote_hostname_errcode = ret; returnfalse;
}
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;
}
} elseif (gai->ai_addr->sa_family == AF_INET6)
{ if (ipv6eq((struct sockaddr_in6 *) gai->ai_addr,
(struct sockaddr_in6 *) &port->raddr.addr))
{
found = true; break;
}
}
}
}
if (gai_result)
freeaddrinfo(gai_result);
if (!found)
elog(DEBUG2, "pg_hba.conf host name \"%s\" rejected because address resolution did not return a match with IP address of client",
hostname);
/* 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);
}
}
/* Check the record type. */
Assert(tok_line->fields != NIL);
field = list_head(tok_line->fields);
tokens = lfirst(field); if (tokens->length > 1)
{
ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("multiple values specified for connection type"),
errhint("Specify exactly one connection type per line."),
errcontext("line %d of configuration file \"%s\"",
line_num, file_name)));
*err_msg = "multiple values specified for connection type"; return NULL;
}
token = linitial(tokens); if (strcmp(token->string, "local") == 0)
{
parsedline->conntype = ctLocal;
} elseif (strcmp(token->string, "host") == 0 ||
strcmp(token->string, "hostssl") == 0 ||
strcmp(token->string, "hostnossl") == 0 ||
strcmp(token->string, "hostgssenc") == 0 ||
strcmp(token->string, "hostnogssenc") == 0)
{
if (token->string[4] == 's') /* "hostssl" */
{
parsedline->conntype = ctHostSSL; /* Log a warning if SSL support is not active */ #ifdef USE_SSL if (!EnableSSL)
{
ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("hostssl record cannot match because SSL is disabled"),
errhint("Set \"ssl = on\" in postgresql.conf."),
errcontext("line %d of configuration file \"%s\"",
line_num, file_name)));
*err_msg = "hostssl record cannot match because SSL is disabled";
} #else
ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("hostssl record cannot match because SSL is not supported by this build"),
errcontext("line %d of configuration file \"%s\"",
line_num, file_name)));
*err_msg = "hostssl record cannot match because SSL is not supported by this build"; #endif
} elseif (token->string[4] == 'g') /* "hostgssenc" */
{
parsedline->conntype = ctHostGSS; #ifndef ENABLE_GSS
ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("hostgssenc record cannot match because GSSAPI is not supported by this build"),
errcontext("line %d of configuration file \"%s\"",
line_num, file_name)));
*err_msg = "hostgssenc record cannot match because GSSAPI is not supported by this build"; #endif
} elseif (token->string[4] == 'n' && token->string[6] == 's')
parsedline->conntype = ctHostNoSSL; elseif (token->string[4] == 'n' && token->string[6] == 'g')
parsedline->conntype = ctHostNoGSS; else
{ /* "host" */
parsedline->conntype = ctHost;
}
} /* record type */ else
{
ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid connection type \"%s\"",
token->string),
errcontext("line %d of configuration file \"%s\"",
line_num, file_name)));
*err_msg = psprintf("invalid connection type \"%s\"", token->string); return NULL;
}
/* Get the databases. */
field = lnext(tok_line->fields, field); if (!field)
{
ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("end-of-line before database specification"),
errcontext("line %d of configuration file \"%s\"",
line_num, file_name)));
*err_msg = "end-of-line before database specification"; return NULL;
}
parsedline->databases = NIL;
tokens = lfirst(field);
foreach(tokencell, tokens)
{
AuthToken *tok = copy_auth_token(lfirst(tokencell));
/* Compile a regexp for the database token, if necessary */ if (regcomp_auth_token(tok, file_name, line_num, err_msg, elevel)) return NULL;
if (parsedline->conntype != ctLocal)
{ /* Read the IP address field. (with or without CIDR netmask) */
field = lnext(tok_line->fields, field); if (!field)
{
ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("end-of-line before IP address specification"),
errcontext("line %d of configuration file \"%s\"",
line_num, file_name)));
*err_msg = "end-of-line before IP address specification"; return NULL;
}
tokens = lfirst(field); if (tokens->length > 1)
{
ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("multiple values specified for host address"),
errhint("Specify one address range per line."),
errcontext("line %d of configuration file \"%s\"",
line_num, file_name)));
*err_msg = "multiple values specified for host address"; return NULL;
}
token = linitial(tokens);
if (token_is_keyword(token, "all"))
{
parsedline->ip_cmp_method = ipCmpAll;
} elseif (token_is_keyword(token, "samehost"))
{ /* Any IP on this host is allowed to connect */
parsedline->ip_cmp_method = ipCmpSameHost;
} elseif (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 = AF_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;
/* Get the netmask */ if (cidr_slash)
{ if (parsedline->hostname)
{
ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("specifying both host name and CIDR mask is invalid: \"%s\"",
token->string),
errcontext("line %d of configuration file \"%s\"",
line_num, file_name)));
*err_msg = psprintf("specifying both host name and CIDR mask is invalid: \"%s\"",
token->string); return NULL;
}
if (pg_sockaddr_cidr_mask(&parsedline->mask, cidr_slash + 1,
parsedline->addr.ss_family) < 0)
{
ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid CIDR mask in address \"%s\"",
token->string),
errcontext("line %d of configuration file \"%s\"",
line_num, file_name)));
*err_msg = psprintf("invalid CIDR mask in address \"%s\"",
token->string); return NULL;
}
parsedline->masklen = parsedline->addrlen;
pfree(str);
} elseif (!parsedline->hostname)
{ /* Read the mask field. */
pfree(str);
field = lnext(tok_line->fields, field); if (!field)
{
ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("end-of-line before netmask specification"),
errhint("Specify an address range in CIDR notation, or provide a separate netmask."),
errcontext("line %d of configuration file \"%s\"",
line_num, file_name)));
*err_msg = "end-of-line before netmask specification"; return NULL;
}
tokens = lfirst(field); if (tokens->length > 1)
{
ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("multiple values specified for netmask"),
errcontext("line %d of configuration file \"%s\"",
line_num, file_name)));
*err_msg = "multiple values specified for netmask"; return NULL;
}
token = linitial(tokens);
ret = pg_getaddrinfo_all(token->string, NULL,
&hints, &gai_result); if (ret || !gai_result)
{
ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid IP mask \"%s\": %s",
token->string, gai_strerror(ret)),
errcontext("line %d of configuration file \"%s\"",
line_num, file_name)));
*err_msg = psprintf("invalid IP mask \"%s\": %s",
token->string, gai_strerror(ret)); if (gai_result)
pg_freeaddrinfo_all(hints.ai_family, gai_result); return NULL;
}
if (unsupauth)
{
ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid authentication method \"%s\": not supported by this build",
token->string),
errcontext("line %d of configuration file \"%s\"",
line_num, file_name)));
*err_msg = psprintf("invalid authentication method \"%s\": not supported by this build",
token->string); return NULL;
}
/* Invalid authentication combinations */ if (parsedline->conntype == ctLocal &&
parsedline->auth_method == uaGSS)
{
ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("gssapi authentication is not supported on local sockets"),
errcontext("line %d of configuration file \"%s\"",
line_num, file_name)));
*err_msg = "gssapi authentication is not supported on local sockets"; return NULL;
}
if (parsedline->conntype != ctLocal &&
parsedline->auth_method == uaPeer)
{
ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("peer authentication is only supported on local sockets"),
errcontext("line %d of configuration file \"%s\"",
line_num, file_name)));
*err_msg = "peer authentication is only supported on local sockets"; return NULL;
}
if (parsedline->conntype != ctHostSSL &&
parsedline->auth_method == uaCert)
{
ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("cert authentication is only supported on hostssl connections"),
errcontext("line %d of configuration file \"%s\"",
line_num, file_name)));
*err_msg = "cert authentication is only supported on hostssl connections"; return NULL;
}
str = pstrdup(token->string);
val = strchr(str, '='); if (val == NULL)
{ /* *Gotsomethingthat'snotaname=valuepair.
*/
ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("authentication option not in name=value format: %s", token->string),
errcontext("line %d of configuration file \"%s\"",
line_num, file_name)));
*err_msg = psprintf("authentication option not in name=value format: %s",
token->string); return NULL;
}
*val++ = '\0'; /* str now holds "name", val holds "value" */ if (!parse_hba_auth_opt(str, val, parsedline, elevel, err_msg)) /* parse_hba_auth_opt already logged the error message */ return NULL;
pfree(str);
}
}
/* *Checkiftheselectedauthenticationmethodhasanymandatoryarguments *thatarenotset.
*/ if (parsedline->auth_method == uaLDAP)
{ #ifndef HAVE_LDAP_INITIALIZE /* Not mandatory for OpenLDAP, because it can use DNS SRV records */
MANDATORY_AUTH_ARG(parsedline->ldapserver, "ldapserver", "ldap"); #endif
/* *LDAPcanoperateintwomodes:eitherwithadirectbind,using *ldapprefixandldapsuffix,orusingasearch+bind,using *ldapbasedn,ldapbinddn,ldapbindpasswdandoneof *ldapsearchattributeorldapsearchfilter.Disallowmixingthese *parameters.
*/ if (parsedline->ldapprefix || parsedline->ldapsuffix)
{ if (parsedline->ldapbasedn ||
parsedline->ldapbinddn ||
parsedline->ldapbindpasswd ||
parsedline->ldapsearchattribute ||
parsedline->ldapsearchfilter)
{
ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("cannot mix options for simple bind and search+bind modes"),
errcontext("line %d of configuration file \"%s\"",
line_num, file_name)));
*err_msg = "cannot mix options for simple bind and search+bind modes"; return NULL;
}
} elseif (!parsedline->ldapbasedn)
{
ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("authentication method \"ldap\" requires argument \"ldapbasedn\", \"ldapprefix\", or \"ldapsuffix\" to be set"),
errcontext("line %d of configuration file \"%s\"",
line_num, file_name)));
*err_msg = "authentication method \"ldap\" requires argument \"ldapbasedn\", \"ldapprefix\", or \"ldapsuffix\" to be set"; return NULL;
}
/* *Whenusingsearch+bind,youcaneitheruseasimpleattribute *(defaultingto"uid")orafullycustomsearchfilter.Youcan't *doboth.
*/ if (parsedline->ldapsearchattribute && parsedline->ldapsearchfilter)
{
ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("cannot use ldapsearchattribute together with ldapsearchfilter"),
errcontext("line %d of configuration file \"%s\"",
line_num, file_name)));
*err_msg = "cannot use ldapsearchattribute together with ldapsearchfilter"; return NULL;
}
}
if (parsedline->radiusservers == NIL)
{
ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("list of RADIUS servers cannot be empty"),
errcontext("line %d of configuration file \"%s\"",
line_num, file_name)));
*err_msg = "list of RADIUS servers cannot be empty"; return NULL;
}
if (parsedline->radiussecrets == NIL)
{
ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("list of RADIUS secrets cannot be empty"),
errcontext("line %d of configuration file \"%s\"",
line_num, file_name)));
*err_msg = "list of RADIUS secrets cannot be empty"; return NULL;
}
/* *Verifylengthofoptionlists-eachcanbe0(exceptforsecrets, *butthat'salreadycheckedabove),1(usethesamevalue *everywhere)orthesameasthenumberofservers.
*/ if (!(list_length(parsedline->radiussecrets) == 1 ||
list_length(parsedline->radiussecrets) == list_length(parsedline->radiusservers)))
{
ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("the number of RADIUS secrets (%d) must be 1 or the same as the number of RADIUS servers (%d)",
list_length(parsedline->radiussecrets),
list_length(parsedline->radiusservers)),
errcontext("line %d of configuration file \"%s\"",
line_num, file_name)));
*err_msg = psprintf("the number of RADIUS secrets (%d) must be 1 or the same as the number of RADIUS servers (%d)",
list_length(parsedline->radiussecrets),
list_length(parsedline->radiusservers)); return NULL;
} if (!(list_length(parsedline->radiusports) == 0 ||
list_length(parsedline->radiusports) == 1 ||
list_length(parsedline->radiusports) == list_length(parsedline->radiusservers)))
{
ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("the number of RADIUS ports (%d) must be 1 or the same as the number of RADIUS servers (%d)",
list_length(parsedline->radiusports),
list_length(parsedline->radiusservers)),
errcontext("line %d of configuration file \"%s\"",
line_num, file_name)));
*err_msg = psprintf("the number of RADIUS ports (%d) must be 1 or the same as the number of RADIUS servers (%d)",
list_length(parsedline->radiusports),
list_length(parsedline->radiusservers)); return NULL;
} if (!(list_length(parsedline->radiusidentifiers) == 0 ||
list_length(parsedline->radiusidentifiers) == 1 ||
list_length(parsedline->radiusidentifiers) == list_length(parsedline->radiusservers)))
{
ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("the number of RADIUS identifiers (%d) must be 1 or the same as the number of RADIUS servers (%d)",
list_length(parsedline->radiusidentifiers),
list_length(parsedline->radiusservers)),
errcontext("line %d of configuration file \"%s\"",
line_num, file_name)));
*err_msg = psprintf("the number of RADIUS identifiers (%d) must be 1 or the same as the number of RADIUS servers (%d)",
list_length(parsedline->radiusidentifiers),
list_length(parsedline->radiusservers)); return NULL;
}
}
/* Ensure a validator library is set and permitted by the config. */ if (!check_oauth_validator(parsedline, elevel, err_msg)) return NULL;
/* *Supplyingausermapcombinedwiththeoptiontoskipusermappingis *nonsensicalandindicatesaconfigurationerror.
*/ if (parsedline->oauth_skip_usermap && parsedline->usermap != NULL)
{
ereport(elevel,
errcode(ERRCODE_CONFIG_FILE_ERROR), /* translator: strings are replaced with hba options */
errmsg("%s cannot be used in combination with %s", "map", "delegate_ident_mapping"),
errcontext("line %d of configuration file \"%s\"",
line_num, file_name));
*err_msg = "map cannot be used in combination with delegate_ident_mapping"; return NULL;
}
}
if (strcmp(name, "map") == 0)
{ if (hbaline->auth_method != uaIdent &&
hbaline->auth_method != uaPeer &&
hbaline->auth_method != uaGSS &&
hbaline->auth_method != uaSSPI &&
hbaline->auth_method != uaCert &&
hbaline->auth_method != uaOAuth)
INVALID_AUTH_OPTION("map", gettext_noop("ident, peer, gssapi, sspi, cert, and oauth"));
hbaline->usermap = pstrdup(val);
} elseif (strcmp(name, "clientcert") == 0)
{ if (hbaline->conntype != ctHostSSL)
{
ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("clientcert can only be configured for \"hostssl\" rows"),
errcontext("line %d of configuration file \"%s\"",
line_num, file_name)));
*err_msg = "clientcert can only be configured for \"hostssl\" rows"; returnfalse;
}
if (strcmp(val, "verify-full") == 0)
{
hbaline->clientcert = clientCertFull;
} elseif (strcmp(val, "verify-ca") == 0)
{ if (hbaline->auth_method == uaCert)
{
ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("clientcert only accepts \"verify-full\" when using \"cert\" authentication"),
errcontext("line %d of configuration file \"%s\"",
line_num, file_name)));
*err_msg = "clientcert can only be set to \"verify-full\" when using \"cert\" authentication"; returnfalse;
}
hbaline->clientcert = clientCertCA;
} else
{
ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("invalid value for clientcert: \"%s\"", val),
errcontext("line %d of configuration file \"%s\"",
line_num, file_name))); returnfalse;
}
} elseif (strcmp(name, "clientname") == 0)
{ if (hbaline->conntype != ctHostSSL)
{
ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("clientname can only be configured for \"hostssl\" rows"),
errcontext("line %d of configuration file \"%s\"",
line_num, file_name)));
*err_msg = "clientname can only be configured for \"hostssl\" rows"; returnfalse;
}
if (!SplitGUCList(dupval, ',', &parsed_servers))
{ /* syntax error in list */
ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("could not parse RADIUS server list \"%s\"",
val),
errcontext("line %d of configuration file \"%s\"",
line_num, file_name))); returnfalse;
}
/* For each entry in the list, translate it */
foreach(l, parsed_servers)
{
MemSet(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_DGRAM;
hints.ai_family = AF_UNSPEC;
ret = pg_getaddrinfo_all((char *) lfirst(l), NULL, &hints, &gai_result); if (ret || !gai_result)
{
ereport(elevel,
(errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("could not translate RADIUS server name \"%s\" to address: %s",
(char *) lfirst(l), gai_strerror(ret)),
errcontext("line %d of configuration file \"%s\"",
line_num, file_name))); if (gai_result)
pg_freeaddrinfo_all(hints.ai_family, gai_result);
/* All entries are OK, so store them */
hbaline->radiusservers = parsed_servers;
hbaline->radiusservers_s = pstrdup(val);
} elseif (strcmp(name, "radiusports") == 0)
{
List *parsed_ports;
ListCell *l; char *dupval = pstrdup(val);
/* Check connection type */ if (hba->conntype == ctLocal)
{ if (port->raddr.addr.ss_family != AF_UNIX) continue;
} else
{ if (port->raddr.addr.ss_family == AF_UNIX) continue;
/* Check SSL state */ if (port->ssl_in_use)
{ /* 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;
}
/* 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, false)) 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;
}
if (!ok)
{ /* *Filecontainedoneormoreerrors,sobailout.MemoryContextDelete *isenoughtocleanupeverything,includingregexes.
*/
MemoryContextDelete(hbacxt); returnfalse;
}
/* 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;
/* 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(tok_line->fields, field);
IDENT_FIELD_ABSENT(field);
tokens = lfirst(field);
IDENT_MULTI_VALUE(tokens);
token = linitial(tokens);
/* Copy the ident user token */
parsedline->system_user = copy_auth_token(token);
/* Get the PG rolename token */
field = lnext(tok_line->fields, field);
IDENT_FIELD_ABSENT(field);
tokens = lfirst(field);
IDENT_MULTI_VALUE(tokens);
token = linitial(tokens);
parsedline->pg_user = copy_auth_token(token);
/* *Nowthatthefieldvalidationisdone,compilearegexfromtheuser *tokens,ifnecessary.
*/ if (regcomp_auth_token(parsedline->system_user, file_name, line_num,
err_msg, elevel))
{ /* err_msg includes the error to report */ return NULL;
}
if (regcomp_auth_token(parsedline->pg_user, file_name, line_num,
err_msg, elevel))
{ /* err_msg includes the error to report */ return 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->system_user->string + 1, identLine->pg_user->string)));
*error_p = true; return;
}
if (usermap_name == NULL || usermap_name[0] == '\0')
{ if (case_insensitive)
{ if (pg_strcasecmp(pg_user, system_user) == 0) return STATUS_OK;
} else
{ if (strcmp(pg_user, system_user) == 0) return STATUS_OK;
}
ereport(LOG,
(errmsg("provided user name (%s) and authenticated user name (%s) do not match",
pg_user, system_user))); return STATUS_ERROR;
} else
{
ListCell *line_cell;
foreach(line_cell, parsed_ident_lines)
{
check_ident_usermap(lfirst(line_cell), usermap_name,
pg_user, system_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_user, system_user)));
} return found_entry ? STATUS_OK : STATUS_ERROR;
}
/* not FATAL ... we just won't do any special ident maps */
file = open_auth_file(IdentFileName, LOG, 0, NULL); if (file == NULL)
{ /* error already logged */ returnfalse;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.