PostgreSQL Source Code  git master
hba.c File Reference
#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 "access/htup_details.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_type.h"
#include "common/ip.h"
#include "common/string.h"
#include "funcapi.h"
#include "libpq/ifaddr.h"
#include "libpq/libpq.h"
#include "miscadmin.h"
#include "postmaster/postmaster.h"
#include "regex/regex.h"
#include "replication/walsender.h"
#include "storage/fd.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/guc.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/varlena.h"
Include dependency graph for hba.c:

Go to the source code of this file.

Data Structures

struct  check_network_data
 

Macros

#define MAX_TOKEN   256
 
#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
 

Functions

static Listtokenize_inc_file (List *tokens, const char *outer_filename, const char *inc_filename, int elevel, char **err_msg)
 
static bool parse_hba_auth_opt (char *name, char *val, HbaLine *hbaline, int elevel, char **err_msg)
 
bool pg_isblank (const char c)
 
static bool next_token (char **lineptr, char *buf, int bufsz, bool *initial_quote, bool *terminating_comma, int elevel, char **err_msg)
 
static AuthTokenmake_auth_token (const char *token, bool quoted)
 
static AuthTokencopy_auth_token (AuthToken *in)
 
static Listnext_field_expand (const char *filename, char **lineptr, int elevel, char **err_msg)
 
MemoryContext tokenize_auth_file (const char *filename, FILE *file, List **tok_lines, int elevel)
 
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)
 
HbaLineparse_hba_line (TokenizedAuthLine *tok_line, int elevel)
 
static void check_hba (hbaPort *port)
 
bool load_hba (void)
 
IdentLineparse_ident_line (TokenizedAuthLine *tok_line, int elevel)
 
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)
 
const char * hba_authname (UserAuth auth_method)
 

Variables

static Listparsed_hba_lines = NIL
 
static MemoryContext parsed_hba_context = NULL
 
static Listparsed_ident_lines = NIL
 
static MemoryContext parsed_ident_context = NULL
 
static const char *const UserAuthName []
 

Macro Definition Documentation

◆ IDENT_FIELD_ABSENT

#define IDENT_FIELD_ABSENT (   field)
Value:
do { \
if (!field) { \
ereport(elevel, \
(errcode(ERRCODE_CONFIG_FILE_ERROR), \
errmsg("missing entry in file \"%s\" at end of line %d", \
IdentFileName, line_num))); \
*err_msg = psprintf("missing entry at end of line"); \
return NULL; \
} \
} while (0)
int errcode(int sqlerrcode)
Definition: elog.c:693
int errmsg(const char *fmt,...)
Definition: elog.c:904
char * IdentFileName
Definition: guc.c:656
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46

Definition at line 898 of file hba.c.

◆ IDENT_MULTI_VALUE

#define IDENT_MULTI_VALUE (   tokens)
Value:
do { \
if (tokens->length > 1) { \
ereport(elevel, \
(errcode(ERRCODE_CONFIG_FILE_ERROR), \
errmsg("multiple values in ident field"), \
errcontext("line %d of configuration file \"%s\"", \
line_num, IdentFileName))); \
*err_msg = psprintf("multiple values in ident field"); \
return NULL; \
} \
} while (0)
#define errcontext
Definition: elog.h:190

Definition at line 910 of file hba.c.

◆ INVALID_AUTH_OPTION

#define INVALID_AUTH_OPTION (   optname,
  validmethods 
)
Value:
do { \
ereport(elevel, \
(errcode(ERRCODE_CONFIG_FILE_ERROR), \
/* translator: the second %s is a list of auth methods */ \
errmsg("authentication option \"%s\" is only valid for authentication methods %s", \
optname, _(validmethods)), \
errcontext("line %d of configuration file \"%s\"", \
line_num, HbaFileName))); \
*err_msg = psprintf("authentication option \"%s\" is only valid for authentication methods %s", \
optname, validmethods); \
return false; \
} while (0)
#define _(x)
Definition: elog.c:89
char * HbaFileName
Definition: guc.c:655

Definition at line 854 of file hba.c.

◆ MANDATORY_AUTH_ARG

#define MANDATORY_AUTH_ARG (   argvar,
  argname,
  authname 
)
Value:
do { \
if (argvar == NULL) { \
ereport(elevel, \
(errcode(ERRCODE_CONFIG_FILE_ERROR), \
errmsg("authentication method \"%s\" requires argument \"%s\" to be set", \
authname, argname), \
errcontext("line %d of configuration file \"%s\"", \
line_num, HbaFileName))); \
*err_msg = psprintf("authentication method \"%s\" requires argument \"%s\" to be set", \
authname, argname); \
return NULL; \
} \
} while (0)

Definition at line 874 of file hba.c.

◆ MAX_TOKEN

#define MAX_TOKEN   256

Definition at line 57 of file hba.c.

◆ REQUIRE_AUTH_OPTION

#define REQUIRE_AUTH_OPTION (   methodval,
  optname,
  validmethods 
)
Value:
do { \
if (hbaline->auth_method != methodval) \
INVALID_AUTH_OPTION(optname, validmethods); \
} while (0)

Definition at line 868 of file hba.c.

◆ token_is_keyword

#define token_is_keyword (   t,
 
)    (!t->quoted && strcmp(t->string, k) == 0)

Definition at line 68 of file hba.c.

◆ token_matches

#define token_matches (   t,
 
)    (strcmp(t->string, k) == 0)

Definition at line 69 of file hba.c.

Typedef Documentation

◆ check_network_data

Function Documentation

◆ check_db()

static bool check_db ( const char *  dbname,
const char *  role,
Oid  roleid,
List tokens 
)
static

Definition at line 603 of file hba.c.

604 {
605  ListCell *cell;
606  AuthToken *tok;
607 
608  foreach(cell, tokens)
609  {
610  tok = lfirst(cell);
612  {
613  /*
614  * physical replication walsender connections can only match
615  * replication keyword
616  */
617  if (token_is_keyword(tok, "replication"))
618  return true;
619  }
620  else if (token_is_keyword(tok, "all"))
621  return true;
622  else if (token_is_keyword(tok, "sameuser"))
623  {
624  if (strcmp(dbname, role) == 0)
625  return true;
626  }
627  else if (token_is_keyword(tok, "samegroup") ||
628  token_is_keyword(tok, "samerole"))
629  {
630  if (is_member(roleid, dbname))
631  return true;
632  }
633  else if (token_is_keyword(tok, "replication"))
634  continue; /* never match this if not walsender */
635  else if (token_matches(tok, dbname))
636  return true;
637  }
638  return false;
639 }
static bool is_member(Oid userid, const char *role)
Definition: hba.c:555
#define token_is_keyword(t, k)
Definition: hba.c:68
#define token_matches(t, k)
Definition: hba.c:69
#define lfirst(lc)
Definition: pg_list.h:169
char * dbname
Definition: streamutil.c:51
Definition: hba.h:141
bool am_walsender
Definition: walsender.c:116
bool am_db_walsender
Definition: walsender.c:119

References am_db_walsender, am_walsender, dbname, is_member(), lfirst, token_is_keyword, and token_matches.

Referenced by check_hba().

◆ check_hba()

static void check_hba ( hbaPort port)
static

Definition at line 2093 of file hba.c.

2094 {
2095  Oid roleid;
2096  ListCell *line;
2097  HbaLine *hba;
2098 
2099  /* Get the target role's OID. Note we do not error out for bad role. */
2100  roleid = get_role_oid(port->user_name, true);
2101 
2102  foreach(line, parsed_hba_lines)
2103  {
2104  hba = (HbaLine *) lfirst(line);
2105 
2106  /* Check connection type */
2107  if (hba->conntype == ctLocal)
2108  {
2109  if (port->raddr.addr.ss_family != AF_UNIX)
2110  continue;
2111  }
2112  else
2113  {
2114  if (port->raddr.addr.ss_family == AF_UNIX)
2115  continue;
2116 
2117  /* Check SSL state */
2118  if (port->ssl_in_use)
2119  {
2120  /* Connection is SSL, match both "host" and "hostssl" */
2121  if (hba->conntype == ctHostNoSSL)
2122  continue;
2123  }
2124  else
2125  {
2126  /* Connection is not SSL, match both "host" and "hostnossl" */
2127  if (hba->conntype == ctHostSSL)
2128  continue;
2129  }
2130 
2131  /* Check GSSAPI state */
2132 #ifdef ENABLE_GSS
2133  if (port->gss && port->gss->enc &&
2134  hba->conntype == ctHostNoGSS)
2135  continue;
2136  else if (!(port->gss && port->gss->enc) &&
2137  hba->conntype == ctHostGSS)
2138  continue;
2139 #else
2140  if (hba->conntype == ctHostGSS)
2141  continue;
2142 #endif
2143 
2144  /* Check IP address */
2145  switch (hba->ip_cmp_method)
2146  {
2147  case ipCmpMask:
2148  if (hba->hostname)
2149  {
2150  if (!check_hostname(port,
2151  hba->hostname))
2152  continue;
2153  }
2154  else
2155  {
2156  if (!check_ip(&port->raddr,
2157  (struct sockaddr *) &hba->addr,
2158  (struct sockaddr *) &hba->mask))
2159  continue;
2160  }
2161  break;
2162  case ipCmpAll:
2163  break;
2164  case ipCmpSameHost:
2165  case ipCmpSameNet:
2166  if (!check_same_host_or_net(&port->raddr,
2167  hba->ip_cmp_method))
2168  continue;
2169  break;
2170  default:
2171  /* shouldn't get here, but deem it no-match if so */
2172  continue;
2173  }
2174  } /* != ctLocal */
2175 
2176  /* Check database and role */
2177  if (!check_db(port->database_name, port->user_name, roleid,
2178  hba->databases))
2179  continue;
2180 
2181  if (!check_role(port->user_name, roleid, hba->roles))
2182  continue;
2183 
2184  /* Found a record that matched! */
2185  port->hba = hba;
2186  return;
2187  }
2188 
2189  /* If no matching entry was found, then implicitly reject. */
2190  hba = palloc0(sizeof(HbaLine));
2192  port->hba = hba;
2193 }
Oid get_role_oid(const char *rolname, bool missing_ok)
Definition: acl.c:5177
static bool check_ip(SockAddr *raddr, struct sockaddr *addr, struct sockaddr *mask)
Definition: hba.c:779
static bool check_same_host_or_net(SockAddr *raddr, IPCompareMethod method)
Definition: hba.c:820
static bool check_hostname(hbaPort *port, const char *hostname)
Definition: hba.c:686
static List * parsed_hba_lines
Definition: hba.c:75
static bool check_db(const char *dbname, const char *role, Oid roleid, List *tokens)
Definition: hba.c:603
static bool check_role(const char *role, Oid roleid, List *tokens)
Definition: hba.c:579
@ ipCmpAll
Definition: hba.h:54
@ ipCmpSameNet
Definition: hba.h:53
@ ipCmpMask
Definition: hba.h:51
@ ipCmpSameHost
Definition: hba.h:52
@ ctHostNoGSS
Definition: hba.h:64
@ ctHostSSL
Definition: hba.h:61
@ ctHostNoSSL
Definition: hba.h:62
@ ctHostGSS
Definition: hba.h:63
@ ctLocal
Definition: hba.h:59
@ uaImplicitReject
Definition: hba.h:28
void * palloc0(Size size)
Definition: mcxt.c:1099
static int port
Definition: pg_regress.c:92
unsigned int Oid
Definition: postgres_ext.h:31
Definition: hba.h:81
UserAuth auth_method
Definition: hba.h:93
struct sockaddr_storage mask
Definition: hba.h:89
char * hostname
Definition: hba.h:92
List * databases
Definition: hba.h:85
ConnType conntype
Definition: hba.h:84
struct sockaddr_storage addr
Definition: hba.h:87
List * roles
Definition: hba.h:86
IPCompareMethod ip_cmp_method
Definition: hba.h:91

References HbaLine::addr, HbaLine::auth_method, check_db(), check_hostname(), check_ip(), check_role(), check_same_host_or_net(), HbaLine::conntype, ctHostGSS, ctHostNoGSS, ctHostNoSSL, ctHostSSL, ctLocal, HbaLine::databases, get_role_oid(), HbaLine::hostname, HbaLine::ip_cmp_method, ipCmpAll, ipCmpMask, ipCmpSameHost, ipCmpSameNet, lfirst, HbaLine::mask, palloc0(), parsed_hba_lines, port, HbaLine::roles, and uaImplicitReject.

Referenced by hba_getauthmethod().

◆ check_hostname()

static bool check_hostname ( hbaPort port,
const char *  hostname 
)
static

Definition at line 686 of file hba.c.

687 {
688  struct addrinfo *gai_result,
689  *gai;
690  int ret;
691  bool found;
692 
693  /* Quick out if remote host name already known bad */
694  if (port->remote_hostname_resolv < 0)
695  return false;
696 
697  /* Lookup remote host name if not already done */
698  if (!port->remote_hostname)
699  {
700  char remote_hostname[NI_MAXHOST];
701 
702  ret = pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
703  remote_hostname, sizeof(remote_hostname),
704  NULL, 0,
705  NI_NAMEREQD);
706  if (ret != 0)
707  {
708  /* remember failure; don't complain in the postmaster log yet */
709  port->remote_hostname_resolv = -2;
710  port->remote_hostname_errcode = ret;
711  return false;
712  }
713 
714  port->remote_hostname = pstrdup(remote_hostname);
715  }
716 
717  /* Now see if remote host name matches this pg_hba line */
718  if (!hostname_match(hostname, port->remote_hostname))
719  return false;
720 
721  /* If we already verified the forward lookup, we're done */
722  if (port->remote_hostname_resolv == +1)
723  return true;
724 
725  /* Lookup IP from host name and check against original IP */
726  ret = getaddrinfo(port->remote_hostname, NULL, NULL, &gai_result);
727  if (ret != 0)
728  {
729  /* remember failure; don't complain in the postmaster log yet */
730  port->remote_hostname_resolv = -2;
731  port->remote_hostname_errcode = ret;
732  return false;
733  }
734 
735  found = false;
736  for (gai = gai_result; gai; gai = gai->ai_next)
737  {
738  if (gai->ai_addr->sa_family == port->raddr.addr.ss_family)
739  {
740  if (gai->ai_addr->sa_family == AF_INET)
741  {
742  if (ipv4eq((struct sockaddr_in *) gai->ai_addr,
743  (struct sockaddr_in *) &port->raddr.addr))
744  {
745  found = true;
746  break;
747  }
748  }
749 #ifdef HAVE_IPV6
750  else if (gai->ai_addr->sa_family == AF_INET6)
751  {
752  if (ipv6eq((struct sockaddr_in6 *) gai->ai_addr,
753  (struct sockaddr_in6 *) &port->raddr.addr))
754  {
755  found = true;
756  break;
757  }
758  }
759 #endif
760  }
761  }
762 
763  if (gai_result)
764  freeaddrinfo(gai_result);
765 
766  if (!found)
767  elog(DEBUG2, "pg_hba.conf host name \"%s\" rejected because address resolution did not return a match with IP address of client",
768  hostname);
769 
770  port->remote_hostname_resolv = found ? +1 : -1;
771 
772  return found;
773 }
#define DEBUG2
Definition: elog.h:23
#define elog(elevel,...)
Definition: elog.h:218
#define NI_NAMEREQD
Definition: getaddrinfo.h:84
#define getaddrinfo
Definition: getaddrinfo.h:136
#define freeaddrinfo
Definition: getaddrinfo.h:141
#define NI_MAXHOST
Definition: getaddrinfo.h:88
static bool hostname_match(const char *pattern, const char *actual_hostname)
Definition: hba.c:666
static bool ipv4eq(struct sockaddr_in *a, struct sockaddr_in *b)
Definition: hba.c:642
int pg_getnameinfo_all(const struct sockaddr_storage *addr, int salen, char *node, int nodelen, char *service, int servicelen, int flags)
Definition: ip.c:122
char * pstrdup(const char *in)
Definition: mcxt.c:1305
static char * hostname
Definition: pg_regress.c:91
struct sockaddr * ai_addr
Definition: getaddrinfo.h:105
struct addrinfo * ai_next
Definition: getaddrinfo.h:107

References addrinfo::ai_addr, addrinfo::ai_next, DEBUG2, elog, freeaddrinfo, getaddrinfo, hostname, hostname_match(), ipv4eq(), NI_MAXHOST, NI_NAMEREQD, pg_getnameinfo_all(), port, and pstrdup().

Referenced by check_hba().

◆ check_ident_usermap()

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 2396 of file hba.c.

2399 {
2400  *found_p = false;
2401  *error_p = false;
2402 
2403  if (strcmp(identLine->usermap, usermap_name) != 0)
2404  /* Line does not match the map name we're looking for, so just abort */
2405  return;
2406 
2407  /* Match? */
2408  if (identLine->ident_user[0] == '/')
2409  {
2410  /*
2411  * When system username starts with a slash, treat it as a regular
2412  * expression. In this case, we process the system username as a
2413  * regular expression that returns exactly one match. This is replaced
2414  * for \1 in the database username string, if present.
2415  */
2416  int r;
2417  regmatch_t matches[2];
2418  pg_wchar *wstr;
2419  int wlen;
2420  char *ofs;
2421  char *regexp_pgrole;
2422 
2423  wstr = palloc((strlen(ident_user) + 1) * sizeof(pg_wchar));
2424  wlen = pg_mb2wchar_with_len(ident_user, wstr, strlen(ident_user));
2425 
2426  r = pg_regexec(&identLine->re, wstr, wlen, 0, NULL, 2, matches, 0);
2427  if (r)
2428  {
2429  char errstr[100];
2430 
2431  if (r != REG_NOMATCH)
2432  {
2433  /* REG_NOMATCH is not an error, everything else is */
2434  pg_regerror(r, &identLine->re, errstr, sizeof(errstr));
2435  ereport(LOG,
2436  (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
2437  errmsg("regular expression match for \"%s\" failed: %s",
2438  identLine->ident_user + 1, errstr)));
2439  *error_p = true;
2440  }
2441 
2442  pfree(wstr);
2443  return;
2444  }
2445  pfree(wstr);
2446 
2447  if ((ofs = strstr(identLine->pg_role, "\\1")) != NULL)
2448  {
2449  int offset;
2450 
2451  /* substitution of the first argument requested */
2452  if (matches[1].rm_so < 0)
2453  {
2454  ereport(LOG,
2455  (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
2456  errmsg("regular expression \"%s\" has no subexpressions as requested by backreference in \"%s\"",
2457  identLine->ident_user + 1, identLine->pg_role)));
2458  *error_p = true;
2459  return;
2460  }
2461 
2462  /*
2463  * length: original length minus length of \1 plus length of match
2464  * plus null terminator
2465  */
2466  regexp_pgrole = palloc0(strlen(identLine->pg_role) - 2 + (matches[1].rm_eo - matches[1].rm_so) + 1);
2467  offset = ofs - identLine->pg_role;
2468  memcpy(regexp_pgrole, identLine->pg_role, offset);
2469  memcpy(regexp_pgrole + offset,
2470  ident_user + matches[1].rm_so,
2471  matches[1].rm_eo - matches[1].rm_so);
2472  strcat(regexp_pgrole, ofs + 2);
2473  }
2474  else
2475  {
2476  /* no substitution, so copy the match */
2477  regexp_pgrole = pstrdup(identLine->pg_role);
2478  }
2479 
2480  /*
2481  * now check if the username actually matched what the user is trying
2482  * to connect as
2483  */
2484  if (case_insensitive)
2485  {
2486  if (pg_strcasecmp(regexp_pgrole, pg_role) == 0)
2487  *found_p = true;
2488  }
2489  else
2490  {
2491  if (strcmp(regexp_pgrole, pg_role) == 0)
2492  *found_p = true;
2493  }
2494  pfree(regexp_pgrole);
2495 
2496  return;
2497  }
2498  else
2499  {
2500  /* Not regular expression, so make complete match */
2501  if (case_insensitive)
2502  {
2503  if (pg_strcasecmp(identLine->pg_role, pg_role) == 0 &&
2504  pg_strcasecmp(identLine->ident_user, ident_user) == 0)
2505  *found_p = true;
2506  }
2507  else
2508  {
2509  if (strcmp(identLine->pg_role, pg_role) == 0 &&
2510  strcmp(identLine->ident_user, ident_user) == 0)
2511  *found_p = true;
2512  }
2513  }
2514 }
#define LOG
Definition: elog.h:25
#define ereport(elevel,...)
Definition: elog.h:143
unsigned int pg_wchar
Definition: mbprint.c:31
int pg_mb2wchar_with_len(const char *from, pg_wchar *to, int len)
Definition: mbutils.c:929
void pfree(void *pointer)
Definition: mcxt.c:1175
void * palloc(Size size)
Definition: mcxt.c:1068
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
size_t pg_regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size)
Definition: regerror.c:60
#define REG_NOMATCH
Definition: regex.h:138
int pg_regexec(regex_t *re, const chr *string, size_t len, size_t search_start, rm_detail_t *details, size_t nmatch, regmatch_t pmatch[], int flags)
Definition: regexec.c:176
char * ident_user
Definition: hba.h:130
char * pg_role
Definition: hba.h:131
regex_t re
Definition: hba.h:132
char * usermap
Definition: hba.h:129

References ereport, errcode(), errmsg(), IdentLine::ident_user, LOG, 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().

◆ check_ip()

static bool check_ip ( SockAddr raddr,
struct sockaddr *  addr,
struct sockaddr *  mask 
)
static

Definition at line 779 of file hba.c.

780 {
781  if (raddr->addr.ss_family == addr->sa_family &&
782  pg_range_sockaddr(&raddr->addr,
783  (struct sockaddr_storage *) addr,
784  (struct sockaddr_storage *) mask))
785  return true;
786  return false;
787 }
int pg_range_sockaddr(const struct sockaddr_storage *addr, const struct sockaddr_storage *netaddr, const struct sockaddr_storage *netmask)
Definition: ifaddr.c:53
struct sockaddr_storage addr
Definition: pqcomm.h:64

References SockAddr::addr, and pg_range_sockaddr().

Referenced by check_hba(), and check_network_callback().

◆ check_network_callback()

static void check_network_callback ( struct sockaddr *  addr,
struct sockaddr *  netmask,
void *  cb_data 
)
static

Definition at line 793 of file hba.c.

795 {
796  check_network_data *cn = (check_network_data *) cb_data;
797  struct sockaddr_storage mask;
798 
799  /* Already found a match? */
800  if (cn->result)
801  return;
802 
803  if (cn->method == ipCmpSameHost)
804  {
805  /* Make an all-ones netmask of appropriate length for family */
806  pg_sockaddr_cidr_mask(&mask, NULL, addr->sa_family);
807  cn->result = check_ip(cn->raddr, addr, (struct sockaddr *) &mask);
808  }
809  else
810  {
811  /* Use the netmask of the interface itself */
812  cn->result = check_ip(cn->raddr, addr, netmask);
813  }
814 }
int pg_sockaddr_cidr_mask(struct sockaddr_storage *mask, char *numbits, int family)
Definition: ifaddr.c:115
bool result
Definition: hba.c:64
SockAddr * raddr
Definition: hba.c:63
IPCompareMethod method
Definition: hba.c:62

References check_ip(), ipCmpSameHost, check_network_data::method, pg_sockaddr_cidr_mask(), check_network_data::raddr, and check_network_data::result.

Referenced by check_same_host_or_net().

◆ check_role()

static bool check_role ( const char *  role,
Oid  roleid,
List tokens 
)
static

Definition at line 579 of file hba.c.

580 {
581  ListCell *cell;
582  AuthToken *tok;
583 
584  foreach(cell, tokens)
585  {
586  tok = lfirst(cell);
587  if (!tok->quoted && tok->string[0] == '+')
588  {
589  if (is_member(roleid, tok->string + 1))
590  return true;
591  }
592  else if (token_matches(tok, role) ||
593  token_is_keyword(tok, "all"))
594  return true;
595  }
596  return false;
597 }
char * string
Definition: hba.h:142
bool quoted
Definition: hba.h:143

References is_member(), lfirst, AuthToken::quoted, AuthToken::string, token_is_keyword, and token_matches.

Referenced by check_hba().

◆ check_same_host_or_net()

static bool check_same_host_or_net ( SockAddr raddr,
IPCompareMethod  method 
)
static

Definition at line 820 of file hba.c.

821 {
823 
824  cn.method = method;
825  cn.raddr = raddr;
826  cn.result = false;
827 
828  errno = 0;
830  {
831  ereport(LOG,
832  (errmsg("error enumerating network interfaces: %m")));
833  return false;
834  }
835 
836  return cn.result;
837 }
static void check_network_callback(struct sockaddr *addr, struct sockaddr *netmask, void *cb_data)
Definition: hba.c:793
int pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data)
Definition: ifaddr.c:559

References check_network_callback(), ereport, errmsg(), LOG, check_network_data::method, pg_foreach_ifaddr(), check_network_data::raddr, and check_network_data::result.

Referenced by check_hba().

◆ check_usermap()

int check_usermap ( const char *  usermap_name,
const char *  pg_role,
const char *  auth_user,
bool  case_insensitive 
)

Definition at line 2531 of file hba.c.

2535 {
2536  bool found_entry = false,
2537  error = false;
2538 
2539  if (usermap_name == NULL || usermap_name[0] == '\0')
2540  {
2541  if (case_insensitive)
2542  {
2543  if (pg_strcasecmp(pg_role, auth_user) == 0)
2544  return STATUS_OK;
2545  }
2546  else
2547  {
2548  if (strcmp(pg_role, auth_user) == 0)
2549  return STATUS_OK;
2550  }
2551  ereport(LOG,
2552  (errmsg("provided user name (%s) and authenticated user name (%s) do not match",
2553  pg_role, auth_user)));
2554  return STATUS_ERROR;
2555  }
2556  else
2557  {
2558  ListCell *line_cell;
2559 
2560  foreach(line_cell, parsed_ident_lines)
2561  {
2562  check_ident_usermap(lfirst(line_cell), usermap_name,
2563  pg_role, auth_user, case_insensitive,
2564  &found_entry, &error);
2565  if (found_entry || error)
2566  break;
2567  }
2568  }
2569  if (!found_entry && !error)
2570  {
2571  ereport(LOG,
2572  (errmsg("no match in usermap \"%s\" for user \"%s\" authenticated as \"%s\"",
2573  usermap_name, pg_role, auth_user)));
2574  }
2575  return found_entry ? STATUS_OK : STATUS_ERROR;
2576 }
#define STATUS_OK
Definition: c.h:1167
#define STATUS_ERROR
Definition: c.h:1168
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)
Definition: hba.c:2396
static List * parsed_ident_lines
Definition: hba.c:86
static void error(void)
Definition: sql-dyntest.c:147

References check_ident_usermap(), ereport, errmsg(), error(), lfirst, LOG, parsed_ident_lines, pg_strcasecmp(), STATUS_ERROR, and STATUS_OK.

Referenced by auth_peer(), and ident_inet().

◆ copy_auth_token()

static AuthToken* copy_auth_token ( AuthToken in)
static

Definition at line 281 of file hba.c.

282 {
283  AuthToken *out = make_auth_token(in->string, in->quoted);
284 
285  return out;
286 }
static AuthToken * make_auth_token(const char *token, bool quoted)
Definition: hba.c:262

References make_auth_token(), AuthToken::quoted, and AuthToken::string.

Referenced by parse_hba_line(), and tokenize_inc_file().

◆ hba_authname()

const char* hba_authname ( UserAuth  auth_method)

Definition at line 2710 of file hba.c.

2711 {
2712  /*
2713  * Make sure UserAuthName[] tracks additions to the UserAuth enum
2714  */
2716  "UserAuthName[] must match the UserAuth enum");
2717 
2718  return UserAuthName[auth_method];
2719 }
#define lengthof(array)
Definition: c.h:734
#define StaticAssertStmt(condition, errmessage)
Definition: c.h:918
static const char *const UserAuthName[]
Definition: hba.c:95
#define USER_AUTH_LAST
Definition: hba.h:42

References lengthof, StaticAssertStmt, USER_AUTH_LAST, and UserAuthName.

Referenced by fill_hba_line(), and set_authn_id().

◆ hba_getauthmethod()

void hba_getauthmethod ( hbaPort port)

Definition at line 2697 of file hba.c.

2698 {
2699  check_hba(port);
2700 }
static void check_hba(hbaPort *port)
Definition: hba.c:2093

References check_hba(), and port.

Referenced by ClientAuthentication().

◆ hostname_match()

static bool hostname_match ( const char *  pattern,
const char *  actual_hostname 
)
static

Definition at line 666 of file hba.c.

667 {
668  if (pattern[0] == '.') /* suffix match */
669  {
670  size_t plen = strlen(pattern);
671  size_t hlen = strlen(actual_hostname);
672 
673  if (hlen < plen)
674  return false;
675 
676  return (pg_strcasecmp(pattern, actual_hostname + (hlen - plen)) == 0);
677  }
678  else
679  return (pg_strcasecmp(pattern, actual_hostname) == 0);
680 }

References pg_strcasecmp().

Referenced by check_hostname().

◆ ipv4eq()

static bool ipv4eq ( struct sockaddr_in *  a,
struct sockaddr_in *  b 
)
static

Definition at line 642 of file hba.c.

643 {
644  return (a->sin_addr.s_addr == b->sin_addr.s_addr);
645 }
int b
Definition: isn.c:70
int a
Definition: isn.c:69

References a, and b.

Referenced by check_hostname().

◆ is_member()

static bool is_member ( Oid  userid,
const char *  role 
)
static

Definition at line 555 of file hba.c.

556 {
557  Oid roleid;
558 
559  if (!OidIsValid(userid))
560  return false; /* if user not exist, say "no" */
561 
562  roleid = get_role_oid(role, true);
563 
564  if (!OidIsValid(roleid))
565  return false; /* if target role not exist, say "no" */
566 
567  /*
568  * See if user is directly or indirectly a member of role. For this
569  * purpose, a superuser is not considered to be automatically a member of
570  * the role, so group auth only applies to explicit membership.
571  */
572  return is_member_of_role_nosuper(userid, roleid);
573 }
bool is_member_of_role_nosuper(Oid member, Oid role)
Definition: acl.c:5021
#define OidIsValid(objectId)
Definition: c.h:710

References get_role_oid(), is_member_of_role_nosuper(), and OidIsValid.

Referenced by check_db(), and check_role().

◆ load_hba()

bool load_hba ( void  )

Definition at line 2207 of file hba.c.

2208 {
2209  FILE *file;
2210  List *hba_lines = NIL;
2211  ListCell *line;
2212  List *new_parsed_lines = NIL;
2213  bool ok = true;
2214  MemoryContext linecxt;
2215  MemoryContext oldcxt;
2216  MemoryContext hbacxt;
2217 
2218  file = AllocateFile(HbaFileName, "r");
2219  if (file == NULL)
2220  {
2221  ereport(LOG,
2223  errmsg("could not open configuration file \"%s\": %m",
2224  HbaFileName)));
2225  return false;
2226  }
2227 
2228  linecxt = tokenize_auth_file(HbaFileName, file, &hba_lines, LOG);
2229  FreeFile(file);
2230 
2231  /* Now parse all the lines */
2234  "hba parser context",
2236  oldcxt = MemoryContextSwitchTo(hbacxt);
2237  foreach(line, hba_lines)
2238  {
2239  TokenizedAuthLine *tok_line = (TokenizedAuthLine *) lfirst(line);
2240  HbaLine *newline;
2241 
2242  /* don't parse lines that already have errors */
2243  if (tok_line->err_msg != NULL)
2244  {
2245  ok = false;
2246  continue;
2247  }
2248 
2249  if ((newline = parse_hba_line(tok_line, LOG)) == NULL)
2250  {
2251  /* Parse error; remember there's trouble */
2252  ok = false;
2253 
2254  /*
2255  * Keep parsing the rest of the file so we can report errors on
2256  * more than the first line. Error has already been logged, no
2257  * need for more chatter here.
2258  */
2259  continue;
2260  }
2261 
2262  new_parsed_lines = lappend(new_parsed_lines, newline);
2263  }
2264 
2265  /*
2266  * A valid HBA file must have at least one entry; else there's no way to
2267  * connect to the postmaster. But only complain about this if we didn't
2268  * already have parsing errors.
2269  */
2270  if (ok && new_parsed_lines == NIL)
2271  {
2272  ereport(LOG,
2273  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2274  errmsg("configuration file \"%s\" contains no entries",
2275  HbaFileName)));
2276  ok = false;
2277  }
2278 
2279  /* Free tokenizer memory */
2280  MemoryContextDelete(linecxt);
2281  MemoryContextSwitchTo(oldcxt);
2282 
2283  if (!ok)
2284  {
2285  /* File contained one or more errors, so bail out */
2286  MemoryContextDelete(hbacxt);
2287  return false;
2288  }
2289 
2290  /* Loaded new file successfully, replace the one we use */
2291  if (parsed_hba_context != NULL)
2293  parsed_hba_context = hbacxt;
2294  parsed_hba_lines = new_parsed_lines;
2295 
2296  return true;
2297 }
int errcode_for_file_access(void)
Definition: elog.c:716
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2461
int FreeFile(FILE *file)
Definition: fd.c:2660
static MemoryContext parsed_hba_context
Definition: hba.c:76
HbaLine * parse_hba_line(TokenizedAuthLine *tok_line, int elevel)
Definition: hba.c:937
MemoryContext tokenize_auth_file(const char *filename, FILE *file, List **tok_lines, int elevel)
Definition: hba.c:446
Assert(fmt[strlen(fmt) - 1] !='\n')
List * lappend(List *list, void *datum)
Definition: list.c:336
MemoryContext PostmasterContext
Definition: mcxt.c:50
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:218
#define AllocSetContextCreate
Definition: memutils.h:173
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:207
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define NIL
Definition: pg_list.h:65
static chr newline(void)
Definition: regc_lex.c:1001
Definition: pg_list.h:51
char * err_msg
Definition: hba.h:160

References AllocateFile(), ALLOCSET_SMALL_SIZES, AllocSetContextCreate, Assert(), ereport, TokenizedAuthLine::err_msg, errcode(), errcode_for_file_access(), errmsg(), FreeFile(), HbaFileName, lappend(), lfirst, LOG, MemoryContextDelete(), MemoryContextSwitchTo(), newline(), NIL, parse_hba_line(), parsed_hba_context, parsed_hba_lines, PostmasterContext, and tokenize_auth_file().

Referenced by PerformAuthentication(), PostmasterMain(), and SIGHUP_handler().

◆ load_ident()

bool load_ident ( void  )

Definition at line 2586 of file hba.c.

2587 {
2588  FILE *file;
2589  List *ident_lines = NIL;
2590  ListCell *line_cell,
2591  *parsed_line_cell;
2592  List *new_parsed_lines = NIL;
2593  bool ok = true;
2594  MemoryContext linecxt;
2595  MemoryContext oldcxt;
2596  MemoryContext ident_context;
2597  IdentLine *newline;
2598 
2599  file = AllocateFile(IdentFileName, "r");
2600  if (file == NULL)
2601  {
2602  /* not fatal ... we just won't do any special ident maps */
2603  ereport(LOG,
2605  errmsg("could not open usermap file \"%s\": %m",
2606  IdentFileName)));
2607  return false;
2608  }
2609 
2610  linecxt = tokenize_auth_file(IdentFileName, file, &ident_lines, LOG);
2611  FreeFile(file);
2612 
2613  /* Now parse all the lines */
2615  ident_context = AllocSetContextCreate(PostmasterContext,
2616  "ident parser context",
2618  oldcxt = MemoryContextSwitchTo(ident_context);
2619  foreach(line_cell, ident_lines)
2620  {
2621  TokenizedAuthLine *tok_line = (TokenizedAuthLine *) lfirst(line_cell);
2622 
2623  /* don't parse lines that already have errors */
2624  if (tok_line->err_msg != NULL)
2625  {
2626  ok = false;
2627  continue;
2628  }
2629 
2630  if ((newline = parse_ident_line(tok_line, LOG)) == NULL)
2631  {
2632  /* Parse error; remember there's trouble */
2633  ok = false;
2634 
2635  /*
2636  * Keep parsing the rest of the file so we can report errors on
2637  * more than the first line. Error has already been logged, no
2638  * need for more chatter here.
2639  */
2640  continue;
2641  }
2642 
2643  new_parsed_lines = lappend(new_parsed_lines, newline);
2644  }
2645 
2646  /* Free tokenizer memory */
2647  MemoryContextDelete(linecxt);
2648  MemoryContextSwitchTo(oldcxt);
2649 
2650  if (!ok)
2651  {
2652  /*
2653  * File contained one or more errors, so bail out, first being careful
2654  * to clean up whatever we allocated. Most stuff will go away via
2655  * MemoryContextDelete, but we have to clean up regexes explicitly.
2656  */
2657  foreach(parsed_line_cell, new_parsed_lines)
2658  {
2659  newline = (IdentLine *) lfirst(parsed_line_cell);
2660  if (newline->ident_user[0] == '/')
2661  pg_regfree(&newline->re);
2662  }
2663  MemoryContextDelete(ident_context);
2664  return false;
2665  }
2666 
2667  /* Loaded new file successfully, replace the one we use */
2668  if (parsed_ident_lines != NIL)
2669  {
2670  foreach(parsed_line_cell, parsed_ident_lines)
2671  {
2672  newline = (IdentLine *) lfirst(parsed_line_cell);
2673  if (newline->ident_user[0] == '/')
2674  pg_regfree(&newline->re);
2675  }
2676  }
2677  if (parsed_ident_context != NULL)
2679 
2680  parsed_ident_context = ident_context;
2681  parsed_ident_lines = new_parsed_lines;
2682 
2683  return true;
2684 }
IdentLine * parse_ident_line(TokenizedAuthLine *tok_line, int elevel)
Definition: hba.c:2315
static MemoryContext parsed_ident_context
Definition: hba.c:87
void pg_regfree(regex_t *re)
Definition: regfree.c:49
Definition: hba.h:126

References AllocateFile(), ALLOCSET_SMALL_SIZES, AllocSetContextCreate, Assert(), ereport, TokenizedAuthLine::err_msg, errcode_for_file_access(), errmsg(), FreeFile(), IdentFileName, lappend(), lfirst, LOG, MemoryContextDelete(), MemoryContextSwitchTo(), newline(), NIL, parse_ident_line(), parsed_ident_context, parsed_ident_lines, pg_regfree(), PostmasterContext, and tokenize_auth_file().

Referenced by PerformAuthentication(), PostmasterMain(), and SIGHUP_handler().

◆ make_auth_token()

static AuthToken* make_auth_token ( const char *  token,
bool  quoted 
)
static

Definition at line 262 of file hba.c.

263 {
264  AuthToken *authtoken;
265  int toklen;
266 
267  toklen = strlen(token);
268  /* we copy string into same palloc block as the struct */
269  authtoken = (AuthToken *) palloc(sizeof(AuthToken) + toklen + 1);
270  authtoken->string = (char *) authtoken + sizeof(AuthToken);
271  authtoken->quoted = quoted;
272  memcpy(authtoken->string, token, toklen + 1);
273 
274  return authtoken;
275 }

References palloc(), AuthToken::quoted, and AuthToken::string.

Referenced by copy_auth_token(), and next_field_expand().

◆ next_field_expand()

static List* next_field_expand ( const char *  filename,
char **  lineptr,
int  elevel,
char **  err_msg 
)
static

Definition at line 304 of file hba.c.

306 {
307  char buf[MAX_TOKEN];
308  bool trailing_comma;
309  bool initial_quote;
310  List *tokens = NIL;
311 
312  do
313  {
314  if (!next_token(lineptr, buf, sizeof(buf),
315  &initial_quote, &trailing_comma,
316  elevel, err_msg))
317  break;
318 
319  /* Is this referencing a file? */
320  if (!initial_quote && buf[0] == '@' && buf[1] != '\0')
321  tokens = tokenize_inc_file(tokens, filename, buf + 1,
322  elevel, err_msg);
323  else
324  tokens = lappend(tokens, make_auth_token(buf, initial_quote));
325  } while (trailing_comma && (*err_msg == NULL));
326 
327  return tokens;
328 }
static List * tokenize_inc_file(List *tokens, const char *outer_filename, const char *inc_filename, int elevel, char **err_msg)
Definition: hba.c:346
static bool next_token(char **lineptr, char *buf, int bufsz, bool *initial_quote, bool *terminating_comma, int elevel, char **err_msg)
Definition: hba.c:169
#define MAX_TOKEN
Definition: hba.c:57
static char * filename
Definition: pg_dumpall.c:94
static char * buf
Definition: pg_test_fsync.c:67

References buf, filename, lappend(), make_auth_token(), MAX_TOKEN, next_token(), NIL, and tokenize_inc_file().

Referenced by tokenize_auth_file().

◆ next_token()

static bool next_token ( char **  lineptr,
char *  buf,
int  bufsz,
bool initial_quote,
bool terminating_comma,
int  elevel,
char **  err_msg 
)
static

Definition at line 169 of file hba.c.

172 {
173  int c;
174  char *start_buf = buf;
175  char *end_buf = buf + (bufsz - 1);
176  bool in_quote = false;
177  bool was_quote = false;
178  bool saw_quote = false;
179 
180  Assert(end_buf > start_buf);
181 
182  *initial_quote = false;
183  *terminating_comma = false;
184 
185  /* Move over any whitespace and commas preceding the next token */
186  while ((c = (*(*lineptr)++)) != '\0' && (pg_isblank(c) || c == ','))
187  ;
188 
189  /*
190  * Build a token in buf of next characters up to EOL, unquoted comma, or
191  * unquoted whitespace.
192  */
193  while (c != '\0' &&
194  (!pg_isblank(c) || in_quote))
195  {
196  /* skip comments to EOL */
197  if (c == '#' && !in_quote)
198  {
199  while ((c = (*(*lineptr)++)) != '\0')
200  ;
201  break;
202  }
203 
204  if (buf >= end_buf)
205  {
206  *buf = '\0';
207  ereport(elevel,
208  (errcode(ERRCODE_CONFIG_FILE_ERROR),
209  errmsg("authentication file token too long, skipping: \"%s\"",
210  start_buf)));
211  *err_msg = "authentication file token too long";
212  /* Discard remainder of line */
213  while ((c = (*(*lineptr)++)) != '\0')
214  ;
215  /* Un-eat the '\0', in case we're called again */
216  (*lineptr)--;
217  return false;
218  }
219 
220  /* we do not pass back a terminating comma in the token */
221  if (c == ',' && !in_quote)
222  {
223  *terminating_comma = true;
224  break;
225  }
226 
227  if (c != '"' || was_quote)
228  *buf++ = c;
229 
230  /* Literal double-quote is two double-quotes */
231  if (in_quote && c == '"')
232  was_quote = !was_quote;
233  else
234  was_quote = false;
235 
236  if (c == '"')
237  {
238  in_quote = !in_quote;
239  saw_quote = true;
240  if (buf == start_buf)
241  *initial_quote = true;
242  }
243 
244  c = *(*lineptr)++;
245  }
246 
247  /*
248  * Un-eat the char right after the token (critical in case it is '\0',
249  * else next call will read past end of string).
250  */
251  (*lineptr)--;
252 
253  *buf = '\0';
254 
255  return (saw_quote || buf > start_buf);
256 }
bool pg_isblank(const char c)
Definition: hba.c:126
char * c

References Assert(), buf, ereport, errcode(), errmsg(), and pg_isblank().

Referenced by base_yylex(), filtered_base_yylex(), and next_field_expand().

◆ parse_hba_auth_opt()

static bool parse_hba_auth_opt ( char *  name,
char *  val,
HbaLine hbaline,
int  elevel,
char **  err_msg 
)
static

Definition at line 1674 of file hba.c.

1676 {
1677  int line_num = hbaline->linenumber;
1678 
1679 #ifdef USE_LDAP
1680  hbaline->ldapscope = LDAP_SCOPE_SUBTREE;
1681 #endif
1682 
1683  if (strcmp(name, "map") == 0)
1684  {
1685  if (hbaline->auth_method != uaIdent &&
1686  hbaline->auth_method != uaPeer &&
1687  hbaline->auth_method != uaGSS &&
1688  hbaline->auth_method != uaSSPI &&
1689  hbaline->auth_method != uaCert)
1690  INVALID_AUTH_OPTION("map", gettext_noop("ident, peer, gssapi, sspi, and cert"));
1691  hbaline->usermap = pstrdup(val);
1692  }
1693  else if (strcmp(name, "clientcert") == 0)
1694  {
1695  if (hbaline->conntype != ctHostSSL)
1696  {
1697  ereport(elevel,
1698  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1699  errmsg("clientcert can only be configured for \"hostssl\" rows"),
1700  errcontext("line %d of configuration file \"%s\"",
1701  line_num, HbaFileName)));
1702  *err_msg = "clientcert can only be configured for \"hostssl\" rows";
1703  return false;
1704  }
1705 
1706  if (strcmp(val, "verify-full") == 0)
1707  {
1708  hbaline->clientcert = clientCertFull;
1709  }
1710  else if (strcmp(val, "verify-ca") == 0)
1711  {
1712  if (hbaline->auth_method == uaCert)
1713  {
1714  ereport(elevel,
1715  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1716  errmsg("clientcert only accepts \"verify-full\" when using \"cert\" authentication"),
1717  errcontext("line %d of configuration file \"%s\"",
1718  line_num, HbaFileName)));
1719  *err_msg = "clientcert can only be set to \"verify-full\" when using \"cert\" authentication";
1720  return false;
1721  }
1722 
1723  hbaline->clientcert = clientCertCA;
1724  }
1725  else
1726  {
1727  ereport(elevel,
1728  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1729  errmsg("invalid value for clientcert: \"%s\"", val),
1730  errcontext("line %d of configuration file \"%s\"",
1731  line_num, HbaFileName)));
1732  return false;
1733  }
1734  }
1735  else if (strcmp(name, "clientname") == 0)
1736  {
1737  if (hbaline->conntype != ctHostSSL)
1738  {
1739  ereport(elevel,
1740  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1741  errmsg("clientname can only be configured for \"hostssl\" rows"),
1742  errcontext("line %d of configuration file \"%s\"",
1743  line_num, HbaFileName)));
1744  *err_msg = "clientname can only be configured for \"hostssl\" rows";
1745  return false;
1746  }
1747 
1748  if (strcmp(val, "CN") == 0)
1749  {
1750  hbaline->clientcertname = clientCertCN;
1751  }
1752  else if (strcmp(val, "DN") == 0)
1753  {
1754  hbaline->clientcertname = clientCertDN;
1755  }
1756  else
1757  {
1758  ereport(elevel,
1759  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1760  errmsg("invalid value for clientname: \"%s\"", val),
1761  errcontext("line %d of configuration file \"%s\"",
1762  line_num, HbaFileName)));
1763  return false;
1764  }
1765  }
1766  else if (strcmp(name, "pamservice") == 0)
1767  {
1768  REQUIRE_AUTH_OPTION(uaPAM, "pamservice", "pam");
1769  hbaline->pamservice = pstrdup(val);
1770  }
1771  else if (strcmp(name, "pam_use_hostname") == 0)
1772  {
1773  REQUIRE_AUTH_OPTION(uaPAM, "pam_use_hostname", "pam");
1774  if (strcmp(val, "1") == 0)
1775  hbaline->pam_use_hostname = true;
1776  else
1777  hbaline->pam_use_hostname = false;
1778  }
1779  else if (strcmp(name, "ldapurl") == 0)
1780  {
1781 #ifdef LDAP_API_FEATURE_X_OPENLDAP
1782  LDAPURLDesc *urldata;
1783  int rc;
1784 #endif
1785 
1786  REQUIRE_AUTH_OPTION(uaLDAP, "ldapurl", "ldap");
1787 #ifdef LDAP_API_FEATURE_X_OPENLDAP
1788  rc = ldap_url_parse(val, &urldata);
1789  if (rc != LDAP_SUCCESS)
1790  {
1791  ereport(elevel,
1792  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1793  errmsg("could not parse LDAP URL \"%s\": %s", val, ldap_err2string(rc))));
1794  *err_msg = psprintf("could not parse LDAP URL \"%s\": %s",
1795  val, ldap_err2string(rc));
1796  return false;
1797  }
1798 
1799  if (strcmp(urldata->lud_scheme, "ldap") != 0 &&
1800  strcmp(urldata->lud_scheme, "ldaps") != 0)
1801  {
1802  ereport(elevel,
1803  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1804  errmsg("unsupported LDAP URL scheme: %s", urldata->lud_scheme)));
1805  *err_msg = psprintf("unsupported LDAP URL scheme: %s",
1806  urldata->lud_scheme);
1807  ldap_free_urldesc(urldata);
1808  return false;
1809  }
1810 
1811  if (urldata->lud_scheme)
1812  hbaline->ldapscheme = pstrdup(urldata->lud_scheme);
1813  if (urldata->lud_host)
1814  hbaline->ldapserver = pstrdup(urldata->lud_host);
1815  hbaline->ldapport = urldata->lud_port;
1816  if (urldata->lud_dn)
1817  hbaline->ldapbasedn = pstrdup(urldata->lud_dn);
1818 
1819  if (urldata->lud_attrs)
1820  hbaline->ldapsearchattribute = pstrdup(urldata->lud_attrs[0]); /* only use first one */
1821  hbaline->ldapscope = urldata->lud_scope;
1822  if (urldata->lud_filter)
1823  hbaline->ldapsearchfilter = pstrdup(urldata->lud_filter);
1824  ldap_free_urldesc(urldata);
1825 #else /* not OpenLDAP */
1826  ereport(elevel,
1827  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1828  errmsg("LDAP URLs not supported on this platform")));
1829  *err_msg = "LDAP URLs not supported on this platform";
1830 #endif /* not OpenLDAP */
1831  }
1832  else if (strcmp(name, "ldaptls") == 0)
1833  {
1834  REQUIRE_AUTH_OPTION(uaLDAP, "ldaptls", "ldap");
1835  if (strcmp(val, "1") == 0)
1836  hbaline->ldaptls = true;
1837  else
1838  hbaline->ldaptls = false;
1839  }
1840  else if (strcmp(name, "ldapscheme") == 0)
1841  {
1842  REQUIRE_AUTH_OPTION(uaLDAP, "ldapscheme", "ldap");
1843  if (strcmp(val, "ldap") != 0 && strcmp(val, "ldaps") != 0)
1844  ereport(elevel,
1845  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1846  errmsg("invalid ldapscheme value: \"%s\"", val),
1847  errcontext("line %d of configuration file \"%s\"",
1848  line_num, HbaFileName)));
1849  hbaline->ldapscheme = pstrdup(val);
1850  }
1851  else if (strcmp(name, "ldapserver") == 0)
1852  {
1853  REQUIRE_AUTH_OPTION(uaLDAP, "ldapserver", "ldap");
1854  hbaline->ldapserver = pstrdup(val);
1855  }
1856  else if (strcmp(name, "ldapport") == 0)
1857  {
1858  REQUIRE_AUTH_OPTION(uaLDAP, "ldapport", "ldap");
1859  hbaline->ldapport = atoi(val);
1860  if (hbaline->ldapport == 0)
1861  {
1862  ereport(elevel,
1863  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1864  errmsg("invalid LDAP port number: \"%s\"", val),
1865  errcontext("line %d of configuration file \"%s\"",
1866  line_num, HbaFileName)));
1867  *err_msg = psprintf("invalid LDAP port number: \"%s\"", val);
1868  return false;
1869  }
1870  }
1871  else if (strcmp(name, "ldapbinddn") == 0)
1872  {
1873  REQUIRE_AUTH_OPTION(uaLDAP, "ldapbinddn", "ldap");
1874  hbaline->ldapbinddn = pstrdup(val);
1875  }
1876  else if (strcmp(name, "ldapbindpasswd") == 0)
1877  {
1878  REQUIRE_AUTH_OPTION(uaLDAP, "ldapbindpasswd", "ldap");
1879  hbaline->ldapbindpasswd = pstrdup(val);
1880  }
1881  else if (strcmp(name, "ldapsearchattribute") == 0)
1882  {
1883  REQUIRE_AUTH_OPTION(uaLDAP, "ldapsearchattribute", "ldap");
1884  hbaline->ldapsearchattribute = pstrdup(val);
1885  }
1886  else if (strcmp(name, "ldapsearchfilter") == 0)
1887  {
1888  REQUIRE_AUTH_OPTION(uaLDAP, "ldapsearchfilter", "ldap");
1889  hbaline->ldapsearchfilter = pstrdup(val);
1890  }
1891  else if (strcmp(name, "ldapbasedn") == 0)
1892  {
1893  REQUIRE_AUTH_OPTION(uaLDAP, "ldapbasedn", "ldap");
1894  hbaline->ldapbasedn = pstrdup(val);
1895  }
1896  else if (strcmp(name, "ldapprefix") == 0)
1897  {
1898  REQUIRE_AUTH_OPTION(uaLDAP, "ldapprefix", "ldap");
1899  hbaline->ldapprefix = pstrdup(val);
1900  }
1901  else if (strcmp(name, "ldapsuffix") == 0)
1902  {
1903  REQUIRE_AUTH_OPTION(uaLDAP, "ldapsuffix", "ldap");
1904  hbaline->ldapsuffix = pstrdup(val);
1905  }
1906  else if (strcmp(name, "krb_realm") == 0)
1907  {
1908  if (hbaline->auth_method != uaGSS &&
1909  hbaline->auth_method != uaSSPI)
1910  INVALID_AUTH_OPTION("krb_realm", gettext_noop("gssapi and sspi"));
1911  hbaline->krb_realm = pstrdup(val);
1912  }
1913  else if (strcmp(name, "include_realm") == 0)
1914  {
1915  if (hbaline->auth_method != uaGSS &&
1916  hbaline->auth_method != uaSSPI)
1917  INVALID_AUTH_OPTION("include_realm", gettext_noop("gssapi and sspi"));
1918  if (strcmp(val, "1") == 0)
1919  hbaline->include_realm = true;
1920  else
1921  hbaline->include_realm = false;
1922  }
1923  else if (strcmp(name, "compat_realm") == 0)
1924  {
1925  if (hbaline->auth_method != uaSSPI)
1926  INVALID_AUTH_OPTION("compat_realm", gettext_noop("sspi"));
1927  if (strcmp(val, "1") == 0)
1928  hbaline->compat_realm = true;
1929  else
1930  hbaline->compat_realm = false;
1931  }
1932  else if (strcmp(name, "upn_username") == 0)
1933  {
1934  if (hbaline->auth_method != uaSSPI)
1935  INVALID_AUTH_OPTION("upn_username", gettext_noop("sspi"));
1936  if (strcmp(val, "1") == 0)
1937  hbaline->upn_username = true;
1938  else
1939  hbaline->upn_username = false;
1940  }
1941  else if (strcmp(name, "radiusservers") == 0)
1942  {
1943  struct addrinfo *gai_result;
1944  struct addrinfo hints;
1945  int ret;
1946  List *parsed_servers;
1947  ListCell *l;
1948  char *dupval = pstrdup(val);
1949 
1950  REQUIRE_AUTH_OPTION(uaRADIUS, "radiusservers", "radius");
1951 
1952  if (!SplitGUCList(dupval, ',', &parsed_servers))
1953  {
1954  /* syntax error in list */
1955  ereport(elevel,
1956  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1957  errmsg("could not parse RADIUS server list \"%s\"",
1958  val),
1959  errcontext("line %d of configuration file \"%s\"",
1960  line_num, HbaFileName)));
1961  return false;
1962  }
1963 
1964  /* For each entry in the list, translate it */
1965  foreach(l, parsed_servers)
1966  {
1967  MemSet(&hints, 0, sizeof(hints));
1968  hints.ai_socktype = SOCK_DGRAM;
1969  hints.ai_family = AF_UNSPEC;
1970 
1971  ret = pg_getaddrinfo_all((char *) lfirst(l), NULL, &hints, &gai_result);
1972  if (ret || !gai_result)
1973  {
1974  ereport(elevel,
1975  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1976  errmsg("could not translate RADIUS server name \"%s\" to address: %s",
1977  (char *) lfirst(l), gai_strerror(ret)),
1978  errcontext("line %d of configuration file \"%s\"",
1979  line_num, HbaFileName)));
1980  if (gai_result)
1981  pg_freeaddrinfo_all(hints.ai_family, gai_result);
1982 
1983  list_free(parsed_servers);
1984  return false;
1985  }
1986  pg_freeaddrinfo_all(hints.ai_family, gai_result);
1987  }
1988 
1989  /* All entries are OK, so store them */
1990  hbaline->radiusservers = parsed_servers;
1991  hbaline->radiusservers_s = pstrdup(val);
1992  }
1993  else if (strcmp(name, "radiusports") == 0)
1994  {
1995  List *parsed_ports;
1996  ListCell *l;
1997  char *dupval = pstrdup(val);
1998 
1999  REQUIRE_AUTH_OPTION(uaRADIUS, "radiusports", "radius");
2000 
2001  if (!SplitGUCList(dupval, ',', &parsed_ports))
2002  {
2003  ereport(elevel,
2004  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2005  errmsg("could not parse RADIUS port list \"%s\"",
2006  val),
2007  errcontext("line %d of configuration file \"%s\"",
2008  line_num, HbaFileName)));
2009  *err_msg = psprintf("invalid RADIUS port number: \"%s\"", val);
2010  return false;
2011  }
2012 
2013  foreach(l, parsed_ports)
2014  {
2015  if (atoi(lfirst(l)) == 0)
2016  {
2017  ereport(elevel,
2018  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2019  errmsg("invalid RADIUS port number: \"%s\"", val),
2020  errcontext("line %d of configuration file \"%s\"",
2021  line_num, HbaFileName)));
2022 
2023  return false;
2024  }
2025  }
2026  hbaline->radiusports = parsed_ports;
2027  hbaline->radiusports_s = pstrdup(val);
2028  }
2029  else if (strcmp(name, "radiussecrets") == 0)
2030  {
2031  List *parsed_secrets;
2032  char *dupval = pstrdup(val);
2033 
2034  REQUIRE_AUTH_OPTION(uaRADIUS, "radiussecrets", "radius");
2035 
2036  if (!SplitGUCList(dupval, ',', &parsed_secrets))
2037  {
2038  /* syntax error in list */
2039  ereport(elevel,
2040  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2041  errmsg("could not parse RADIUS secret list \"%s\"",
2042  val),
2043  errcontext("line %d of configuration file \"%s\"",
2044  line_num, HbaFileName)));
2045  return false;
2046  }
2047 
2048  hbaline->radiussecrets = parsed_secrets;
2049  hbaline->radiussecrets_s = pstrdup(val);
2050  }
2051  else if (strcmp(name, "radiusidentifiers") == 0)
2052  {
2053  List *parsed_identifiers;
2054  char *dupval = pstrdup(val);
2055 
2056  REQUIRE_AUTH_OPTION(uaRADIUS, "radiusidentifiers", "radius");
2057 
2058  if (!SplitGUCList(dupval, ',', &parsed_identifiers))
2059  {
2060  /* syntax error in list */
2061  ereport(elevel,
2062  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2063  errmsg("could not parse RADIUS identifiers list \"%s\"",
2064  val),
2065  errcontext("line %d of configuration file \"%s\"",
2066  line_num, HbaFileName)));
2067  return false;
2068  }
2069 
2070  hbaline->radiusidentifiers = parsed_identifiers;
2071  hbaline->radiusidentifiers_s = pstrdup(val);
2072  }
2073  else
2074  {
2075  ereport(elevel,
2076  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2077  errmsg("unrecognized authentication option name: \"%s\"",
2078  name),
2079  errcontext("line %d of configuration file \"%s\"",
2080  line_num, HbaFileName)));
2081  *err_msg = psprintf("unrecognized authentication option name: \"%s\"",
2082  name);
2083  return false;
2084  }
2085  return true;
2086 }
#define gettext_noop(x)
Definition: c.h:1194
#define MemSet(start, val, len)
Definition: c.h:1008
const char * name
Definition: encode.c:561
#define gai_strerror
Definition: getaddrinfo.h:146
#define INVALID_AUTH_OPTION(optname, validmethods)
Definition: hba.c:854
#define REQUIRE_AUTH_OPTION(methodval, optname, validmethods)
Definition: hba.c:868
@ uaLDAP
Definition: hba.h:38
@ uaPAM
Definition: hba.h:36
@ uaCert
Definition: hba.h:39
@ uaGSS
Definition: hba.h:34
@ uaRADIUS
Definition: hba.h:40
@ uaIdent
Definition: hba.h:30
@ uaSSPI
Definition: hba.h:35
@ clientCertDN
Definition: hba.h:77
@ clientCertCN
Definition: hba.h:76
@ clientCertFull
Definition: hba.h:71
@ clientCertCA
Definition: hba.h:70
long val
Definition: informix.c:664
void pg_freeaddrinfo_all(int hint_ai_family, struct addrinfo *ai)
Definition: ip.c:88
int pg_getaddrinfo_all(const char *hostname, const char *servname, const struct addrinfo *hintp, struct addrinfo **result)
Definition: ip.c:57
void list_free(List *list)
Definition: list.c:1505
bool upn_username
Definition: hba.h:114
ClientCertName clientcertname
Definition: hba.h:110
List * radiusservers
Definition: hba.h:115
char * ldapserver
Definition: hba.h:99
bool include_realm
Definition: hba.h:112
ClientCertMode clientcert
Definition: hba.h:109
char * ldapsearchfilter
Definition: hba.h:104
char * ldapscheme
Definition: hba.h:98
char * ldapprefix
Definition: hba.h:107
List * radiussecrets
Definition: hba.h:117
char * ldapsearchattribute
Definition: hba.h:103
char * krb_realm
Definition: hba.h:111
char * ldapbasedn
Definition: hba.h:105
bool pam_use_hostname
Definition: hba.h:96
int linenumber
Definition: hba.h:82
char * radiussecrets_s
Definition: hba.h:118
List * radiusports
Definition: hba.h:121
List * radiusidentifiers
Definition: hba.h:119
char * pamservice
Definition: hba.h:95
char * usermap
Definition: hba.h:94
char * ldapsuffix
Definition: hba.h:108
int ldapport
Definition: hba.h:100
char * ldapbindpasswd
Definition: hba.h:102
char * radiusports_s
Definition: hba.h:122
char * ldapbinddn
Definition: hba.h:101
bool compat_realm
Definition: hba.h:113
int ldapscope
Definition: hba.h:106
bool ldaptls
Definition: hba.h:97
char * radiusservers_s
Definition: hba.h:116
char * radiusidentifiers_s
Definition: hba.h:120
bool SplitGUCList(char *rawstring, char separator, List **namelist)
Definition: varlena.c:3963

References addrinfo::ai_family, addrinfo::ai_socktype, HbaLine::auth_method, HbaLine::clientcert, clientCertCA, clientCertCN, clientCertDN, clientCertFull, HbaLine::clientcertname, HbaLine::compat_realm, HbaLine::conntype, ctHostSSL, ereport, errcode(), errcontext, errmsg(), gai_strerror, gettext_noop, HbaFileName, HbaLine::include_realm, INVALID_AUTH_OPTION, HbaLine::krb_realm, HbaLine::ldapbasedn, HbaLine::ldapbinddn, HbaLine::ldapbindpasswd, HbaLine::ldapport, HbaLine::ldapprefix, HbaLine::ldapscheme, HbaLine::ldapscope, HbaLine::ldapsearchattribute, HbaLine::ldapsearchfilter, HbaLine::ldapserver, HbaLine::ldapsuffix, HbaLine::ldaptls, lfirst, HbaLine::linenumber, list_free(), MemSet, name, HbaLine::pam_use_hostname, HbaLine::pamservice, pg_freeaddrinfo_all(), pg_getaddrinfo_all(), psprintf(), pstrdup(), HbaLine::radiusidentifiers, HbaLine::radiusidentifiers_s, HbaLine::radiusports, HbaLine::radiusports_s, HbaLine::radiussecrets, HbaLine::radiussecrets_s, HbaLine::radiusservers, HbaLine::radiusservers_s, REQUIRE_AUTH_OPTION, SplitGUCList(), uaCert, uaGSS, uaIdent, uaLDAP, uaPAM, uaRADIUS, uaSSPI, HbaLine::upn_username, HbaLine::usermap, and val.

Referenced by parse_hba_line().

◆ parse_hba_line()

HbaLine* parse_hba_line ( TokenizedAuthLine tok_line,
int  elevel 
)

Definition at line 937 of file hba.c.

938 {
939  int line_num = tok_line->line_num;
940  char **err_msg = &tok_line->err_msg;
941  char *str;
942  struct addrinfo *gai_result;
943  struct addrinfo hints;
944  int ret;
945  char *cidr_slash;
946  char *unsupauth;
947  ListCell *field;
948  List *tokens;
949  ListCell *tokencell;
950  AuthToken *token;
951  HbaLine *parsedline;
952 
953  parsedline = palloc0(sizeof(HbaLine));
954  parsedline->linenumber = line_num;
955  parsedline->rawline = pstrdup(tok_line->raw_line);
956 
957  /* Check the record type. */
958  Assert(tok_line->fields != NIL);
959  field = list_head(tok_line->fields);
960  tokens = lfirst(field);
961  if (tokens->length > 1)
962  {
963  ereport(elevel,
964  (errcode(ERRCODE_CONFIG_FILE_ERROR),
965  errmsg("multiple values specified for connection type"),
966  errhint("Specify exactly one connection type per line."),
967  errcontext("line %d of configuration file \"%s\"",
968  line_num, HbaFileName)));
969  *err_msg = "multiple values specified for connection type";
970  return NULL;
971  }
972  token = linitial(tokens);
973  if (strcmp(token->string, "local") == 0)
974  {
975 #ifdef HAVE_UNIX_SOCKETS
976  parsedline->conntype = ctLocal;
977 #else
978  ereport(elevel,
979  (errcode(ERRCODE_CONFIG_FILE_ERROR),
980  errmsg("local connections are not supported by this build"),
981  errcontext("line %d of configuration file \"%s\"",
982  line_num, HbaFileName)));
983  *err_msg = "local connections are not supported by this build";
984  return NULL;
985 #endif
986  }
987  else if (strcmp(token->string, "host") == 0 ||
988  strcmp(token->string, "hostssl") == 0 ||
989  strcmp(token->string, "hostnossl") == 0 ||
990  strcmp(token->string, "hostgssenc") == 0 ||
991  strcmp(token->string, "hostnogssenc") == 0)
992  {
993 
994  if (token->string[4] == 's') /* "hostssl" */
995  {
996  parsedline->conntype = ctHostSSL;
997  /* Log a warning if SSL support is not active */
998 #ifdef USE_SSL
999  if (!EnableSSL)
1000  {
1001  ereport(elevel,
1002  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1003  errmsg("hostssl record cannot match because SSL is disabled"),
1004  errhint("Set ssl = on in postgresql.conf."),
1005  errcontext("line %d of configuration file \"%s\"",
1006  line_num, HbaFileName)));
1007  *err_msg = "hostssl record cannot match because SSL is disabled";
1008  }
1009 #else
1010  ereport(elevel,
1011  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1012  errmsg("hostssl record cannot match because SSL is not supported by this build"),
1013  errcontext("line %d of configuration file \"%s\"",
1014  line_num, HbaFileName)));
1015  *err_msg = "hostssl record cannot match because SSL is not supported by this build";
1016 #endif
1017  }
1018  else if (token->string[4] == 'g') /* "hostgssenc" */
1019  {
1020  parsedline->conntype = ctHostGSS;
1021 #ifndef ENABLE_GSS
1022  ereport(elevel,
1023  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1024  errmsg("hostgssenc record cannot match because GSSAPI is not supported by this build"),
1025  errcontext("line %d of configuration file \"%s\"",
1026  line_num, HbaFileName)));
1027  *err_msg = "hostgssenc record cannot match because GSSAPI is not supported by this build";
1028 #endif
1029  }
1030  else if (token->string[4] == 'n' && token->string[6] == 's')
1031  parsedline->conntype = ctHostNoSSL;
1032  else if (token->string[4] == 'n' && token->string[6] == 'g')
1033  parsedline->conntype = ctHostNoGSS;
1034  else
1035  {
1036  /* "host" */
1037  parsedline->conntype = ctHost;
1038  }
1039  } /* record type */
1040  else
1041  {
1042  ereport(elevel,
1043  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1044  errmsg("invalid connection type \"%s\"",
1045  token->string),
1046  errcontext("line %d of configuration file \"%s\"",
1047  line_num, HbaFileName)));
1048  *err_msg = psprintf("invalid connection type \"%s\"", token->string);
1049  return NULL;
1050  }
1051 
1052  /* Get the databases. */
1053  field = lnext(tok_line->fields, field);
1054  if (!field)
1055  {
1056  ereport(elevel,
1057  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1058  errmsg("end-of-line before database specification"),
1059  errcontext("line %d of configuration file \"%s\"",
1060  line_num, HbaFileName)));
1061  *err_msg = "end-of-line before database specification";
1062  return NULL;
1063  }
1064  parsedline->databases = NIL;
1065  tokens = lfirst(field);
1066  foreach(tokencell, tokens)
1067  {
1068  parsedline->databases = lappend(parsedline->databases,
1069  copy_auth_token(lfirst(tokencell)));
1070  }
1071 
1072  /* Get the roles. */
1073  field = lnext(tok_line->fields, field);
1074  if (!field)
1075  {
1076  ereport(elevel,
1077  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1078  errmsg("end-of-line before role specification"),
1079  errcontext("line %d of configuration file \"%s\"",
1080  line_num, HbaFileName)));
1081  *err_msg = "end-of-line before role specification";
1082  return NULL;
1083  }
1084  parsedline->roles = NIL;
1085  tokens = lfirst(field);
1086  foreach(tokencell, tokens)
1087  {
1088  parsedline->roles = lappend(parsedline->roles,
1089  copy_auth_token(lfirst(tokencell)));
1090  }
1091 
1092  if (parsedline->conntype != ctLocal)
1093  {
1094  /* Read the IP address field. (with or without CIDR netmask) */
1095  field = lnext(tok_line->fields, field);
1096  if (!field)
1097  {
1098  ereport(elevel,
1099  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1100  errmsg("end-of-line before IP address specification"),
1101  errcontext("line %d of configuration file \"%s\"",
1102  line_num, HbaFileName)));
1103  *err_msg = "end-of-line before IP address specification";
1104  return NULL;
1105  }
1106  tokens = lfirst(field);
1107  if (tokens->length > 1)
1108  {
1109  ereport(elevel,
1110  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1111  errmsg("multiple values specified for host address"),
1112  errhint("Specify one address range per line."),
1113  errcontext("line %d of configuration file \"%s\"",
1114  line_num, HbaFileName)));
1115  *err_msg = "multiple values specified for host address";
1116  return NULL;
1117  }
1118  token = linitial(tokens);
1119 
1120  if (token_is_keyword(token, "all"))
1121  {
1122  parsedline->ip_cmp_method = ipCmpAll;
1123  }
1124  else if (token_is_keyword(token, "samehost"))
1125  {
1126  /* Any IP on this host is allowed to connect */
1127  parsedline->ip_cmp_method = ipCmpSameHost;
1128  }
1129  else if (token_is_keyword(token, "samenet"))
1130  {
1131  /* Any IP on the host's subnets is allowed to connect */
1132  parsedline->ip_cmp_method = ipCmpSameNet;
1133  }
1134  else
1135  {
1136  /* IP and netmask are specified */
1137  parsedline->ip_cmp_method = ipCmpMask;
1138 
1139  /* need a modifiable copy of token */
1140  str = pstrdup(token->string);
1141 
1142  /* Check if it has a CIDR suffix and if so isolate it */
1143  cidr_slash = strchr(str, '/');
1144  if (cidr_slash)
1145  *cidr_slash = '\0';
1146 
1147  /* Get the IP address either way */
1148  hints.ai_flags = AI_NUMERICHOST;
1149  hints.ai_family = AF_UNSPEC;
1150  hints.ai_socktype = 0;
1151  hints.ai_protocol = 0;
1152  hints.ai_addrlen = 0;
1153  hints.ai_canonname = NULL;
1154  hints.ai_addr = NULL;
1155  hints.ai_next = NULL;
1156 
1157  ret = pg_getaddrinfo_all(str, NULL, &hints, &gai_result);
1158  if (ret == 0 && gai_result)
1159  {
1160  memcpy(&parsedline->addr, gai_result->ai_addr,
1161  gai_result->ai_addrlen);
1162  parsedline->addrlen = gai_result->ai_addrlen;
1163  }
1164  else if (ret == EAI_NONAME)
1165  parsedline->hostname = str;
1166  else
1167  {
1168  ereport(elevel,
1169  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1170  errmsg("invalid IP address \"%s\": %s",
1171  str, gai_strerror(ret)),
1172  errcontext("line %d of configuration file \"%s\"",
1173  line_num, HbaFileName)));
1174  *err_msg = psprintf("invalid IP address \"%s\": %s",
1175  str, gai_strerror(ret));
1176  if (gai_result)
1177  pg_freeaddrinfo_all(hints.ai_family, gai_result);
1178  return NULL;
1179  }
1180 
1181  pg_freeaddrinfo_all(hints.ai_family, gai_result);
1182 
1183  /* Get the netmask */
1184  if (cidr_slash)
1185  {
1186  if (parsedline->hostname)
1187  {
1188  ereport(elevel,
1189  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1190  errmsg("specifying both host name and CIDR mask is invalid: \"%s\"",
1191  token->string),
1192  errcontext("line %d of configuration file \"%s\"",
1193  line_num, HbaFileName)));
1194  *err_msg = psprintf("specifying both host name and CIDR mask is invalid: \"%s\"",
1195  token->string);
1196  return NULL;
1197  }
1198 
1199  if (pg_sockaddr_cidr_mask(&parsedline->mask, cidr_slash + 1,
1200  parsedline->addr.ss_family) < 0)
1201  {
1202  ereport(elevel,
1203  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1204  errmsg("invalid CIDR mask in address \"%s\"",
1205  token->string),
1206  errcontext("line %d of configuration file \"%s\"",
1207  line_num, HbaFileName)));
1208  *err_msg = psprintf("invalid CIDR mask in address \"%s\"",
1209  token->string);
1210  return NULL;
1211  }
1212  parsedline->masklen = parsedline->addrlen;
1213  pfree(str);
1214  }
1215  else if (!parsedline->hostname)
1216  {
1217  /* Read the mask field. */
1218  pfree(str);
1219  field = lnext(tok_line->fields, field);
1220  if (!field)
1221  {
1222  ereport(elevel,
1223  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1224  errmsg("end-of-line before netmask specification"),
1225  errhint("Specify an address range in CIDR notation, or provide a separate netmask."),
1226  errcontext("line %d of configuration file \"%s\"",
1227  line_num, HbaFileName)));
1228  *err_msg = "end-of-line before netmask specification";
1229  return NULL;
1230  }
1231  tokens = lfirst(field);
1232  if (tokens->length > 1)
1233  {
1234  ereport(elevel,
1235  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1236  errmsg("multiple values specified for netmask"),
1237  errcontext("line %d of configuration file \"%s\"",
1238  line_num, HbaFileName)));
1239  *err_msg = "multiple values specified for netmask";
1240  return NULL;
1241  }
1242  token = linitial(tokens);
1243 
1244  ret = pg_getaddrinfo_all(token->string, NULL,
1245  &hints, &gai_result);
1246  if (ret || !gai_result)
1247  {
1248  ereport(elevel,
1249  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1250  errmsg("invalid IP mask \"%s\": %s",
1251  token->string, gai_strerror(ret)),
1252  errcontext("line %d of configuration file \"%s\"",
1253  line_num, HbaFileName)));
1254  *err_msg = psprintf("invalid IP mask \"%s\": %s",
1255  token->string, gai_strerror(ret));
1256  if (gai_result)
1257  pg_freeaddrinfo_all(hints.ai_family, gai_result);
1258  return NULL;
1259  }
1260 
1261  memcpy(&parsedline->mask, gai_result->ai_addr,
1262  gai_result->ai_addrlen);
1263  parsedline->masklen = gai_result->ai_addrlen;
1264  pg_freeaddrinfo_all(hints.ai_family, gai_result);
1265 
1266  if (parsedline->addr.ss_family != parsedline->mask.ss_family)
1267  {
1268  ereport(elevel,
1269  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1270  errmsg("IP address and mask do not match"),
1271  errcontext("line %d of configuration file \"%s\"",
1272  line_num, HbaFileName)));
1273  *err_msg = "IP address and mask do not match";
1274  return NULL;
1275  }
1276  }
1277  }
1278  } /* != ctLocal */
1279 
1280  /* Get the authentication method */
1281  field = lnext(tok_line->fields, field);
1282  if (!field)
1283  {
1284  ereport(elevel,
1285  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1286  errmsg("end-of-line before authentication method"),
1287  errcontext("line %d of configuration file \"%s\"",
1288  line_num, HbaFileName)));
1289  *err_msg = "end-of-line before authentication method";
1290  return NULL;
1291  }
1292  tokens = lfirst(field);
1293  if (tokens->length > 1)
1294  {
1295  ereport(elevel,
1296  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1297  errmsg("multiple values specified for authentication type"),
1298  errhint("Specify exactly one authentication type per line."),
1299  errcontext("line %d of configuration file \"%s\"",
1300  line_num, HbaFileName)));
1301  *err_msg = "multiple values specified for authentication type";
1302  return NULL;
1303  }
1304  token = linitial(tokens);
1305 
1306  unsupauth = NULL;
1307  if (strcmp(token->string, "trust") == 0)
1308  parsedline->auth_method = uaTrust;
1309  else if (strcmp(token->string, "ident") == 0)
1310  parsedline->auth_method = uaIdent;
1311  else if (strcmp(token->string, "peer") == 0)
1312  parsedline->auth_method = uaPeer;
1313  else if (strcmp(token->string, "password") == 0)
1314  parsedline->auth_method = uaPassword;
1315  else if (strcmp(token->string, "gss") == 0)
1316 #ifdef ENABLE_GSS
1317  parsedline->auth_method = uaGSS;
1318 #else
1319  unsupauth = "gss";
1320 #endif
1321  else if (strcmp(token->string, "sspi") == 0)
1322 #ifdef ENABLE_SSPI
1323  parsedline->auth_method = uaSSPI;
1324 #else
1325  unsupauth = "sspi";
1326 #endif
1327  else if (strcmp(token->string, "reject") == 0)
1328  parsedline->auth_method = uaReject;
1329  else if (strcmp(token->string, "md5") == 0)
1330  {
1331  if (Db_user_namespace)
1332  {
1333  ereport(elevel,
1334  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1335  errmsg("MD5 authentication is not supported when \"db_user_namespace\" is enabled"),
1336  errcontext("line %d of configuration file \"%s\"",
1337  line_num, HbaFileName)));
1338  *err_msg = "MD5 authentication is not supported when \"db_user_namespace\" is enabled";
1339  return NULL;
1340  }
1341  parsedline->auth_method = uaMD5;
1342  }
1343  else if (strcmp(token->string, "scram-sha-256") == 0)
1344  parsedline->auth_method = uaSCRAM;
1345  else if (strcmp(token->string, "pam") == 0)
1346 #ifdef USE_PAM
1347  parsedline->auth_method = uaPAM;
1348 #else
1349  unsupauth = "pam";
1350 #endif
1351  else if (strcmp(token->string, "bsd") == 0)
1352 #ifdef USE_BSD_AUTH
1353  parsedline->auth_method = uaBSD;
1354 #else
1355  unsupauth = "bsd";
1356 #endif
1357  else if (strcmp(token->string, "ldap") == 0)
1358 #ifdef USE_LDAP
1359  parsedline->auth_method = uaLDAP;
1360 #else
1361  unsupauth = "ldap";
1362 #endif
1363  else if (strcmp(token->string, "cert") == 0)
1364 #ifdef USE_SSL
1365  parsedline->auth_method = uaCert;
1366 #else
1367  unsupauth = "cert";
1368 #endif
1369  else if (strcmp(token->string, "radius") == 0)
1370  parsedline->auth_method = uaRADIUS;
1371  else
1372  {
1373  ereport(elevel,
1374  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1375  errmsg("invalid authentication method \"%s\"",
1376  token->string),
1377  errcontext("line %d of configuration file \"%s\"",
1378  line_num, HbaFileName)));
1379  *err_msg = psprintf("invalid authentication method \"%s\"",
1380  token->string);
1381  return NULL;
1382  }
1383 
1384  if (unsupauth)
1385  {
1386  ereport(elevel,
1387  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1388  errmsg("invalid authentication method \"%s\": not supported by this build",
1389  token->string),
1390  errcontext("line %d of configuration file \"%s\"",
1391  line_num, HbaFileName)));
1392  *err_msg = psprintf("invalid authentication method \"%s\": not supported by this build",
1393  token->string);
1394  return NULL;
1395  }
1396 
1397  /*
1398  * XXX: When using ident on local connections, change it to peer, for
1399  * backwards compatibility.
1400  */
1401  if (parsedline->conntype == ctLocal &&
1402  parsedline->auth_method == uaIdent)
1403  parsedline->auth_method = uaPeer;
1404 
1405  /* Invalid authentication combinations */
1406  if (parsedline->conntype == ctLocal &&
1407  parsedline->auth_method == uaGSS)
1408  {
1409  ereport(elevel,
1410  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1411  errmsg("gssapi authentication is not supported on local sockets"),
1412  errcontext("line %d of configuration file \"%s\"",
1413  line_num, HbaFileName)));
1414  *err_msg = "gssapi authentication is not supported on local sockets";
1415  return NULL;
1416  }
1417 
1418  if (parsedline->conntype != ctLocal &&
1419  parsedline->auth_method == uaPeer)
1420  {
1421  ereport(elevel,
1422  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1423  errmsg("peer authentication is only supported on local sockets"),
1424  errcontext("line %d of configuration file \"%s\"",
1425  line_num, HbaFileName)));
1426  *err_msg = "peer authentication is only supported on local sockets";
1427  return NULL;
1428  }
1429 
1430  /*
1431  * SSPI authentication can never be enabled on ctLocal connections,
1432  * because it's only supported on Windows, where ctLocal isn't supported.
1433  */
1434 
1435 
1436  if (parsedline->conntype != ctHostSSL &&
1437  parsedline->auth_method == uaCert)
1438  {
1439  ereport(elevel,
1440  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1441  errmsg("cert authentication is only supported on hostssl connections"),
1442  errcontext("line %d of configuration file \"%s\"",
1443  line_num, HbaFileName)));
1444  *err_msg = "cert authentication is only supported on hostssl connections";
1445  return NULL;
1446  }
1447 
1448  /*
1449  * For GSS and SSPI, set the default value of include_realm to true.
1450  * Having include_realm set to false is dangerous in multi-realm
1451  * situations and is generally considered bad practice. We keep the
1452  * capability around for backwards compatibility, but we might want to
1453  * remove it at some point in the future. Users who still need to strip
1454  * the realm off would be better served by using an appropriate regex in a
1455  * pg_ident.conf mapping.
1456  */
1457  if (parsedline->auth_method == uaGSS ||
1458  parsedline->auth_method == uaSSPI)
1459  parsedline->include_realm = true;
1460 
1461  /*
1462  * For SSPI, include_realm defaults to the SAM-compatible domain (aka
1463  * NetBIOS name) and user names instead of the Kerberos principal name for
1464  * compatibility.
1465  */
1466  if (parsedline->auth_method == uaSSPI)
1467  {
1468  parsedline->compat_realm = true;
1469  parsedline->upn_username = false;
1470  }
1471 
1472  /* Parse remaining arguments */
1473  while ((field = lnext(tok_line->fields, field)) != NULL)
1474  {
1475  tokens = lfirst(field);
1476  foreach(tokencell, tokens)
1477  {
1478  char *val;
1479 
1480  token = lfirst(tokencell);
1481 
1482  str = pstrdup(token->string);
1483  val = strchr(str, '=');
1484  if (val == NULL)
1485  {
1486  /*
1487  * Got something that's not a name=value pair.
1488  */
1489  ereport(elevel,
1490  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1491  errmsg("authentication option not in name=value format: %s", token->string),
1492  errcontext("line %d of configuration file \"%s\"",
1493  line_num, HbaFileName)));
1494  *err_msg = psprintf("authentication option not in name=value format: %s",
1495  token->string);
1496  return NULL;
1497  }
1498 
1499  *val++ = '\0'; /* str now holds "name", val holds "value" */
1500  if (!parse_hba_auth_opt(str, val, parsedline, elevel, err_msg))
1501  /* parse_hba_auth_opt already logged the error message */
1502  return NULL;
1503  pfree(str);
1504  }
1505  }
1506 
1507  /*
1508  * Check if the selected authentication method has any mandatory arguments
1509  * that are not set.
1510  */
1511  if (parsedline->auth_method == uaLDAP)
1512  {
1513 #ifndef HAVE_LDAP_INITIALIZE
1514  /* Not mandatory for OpenLDAP, because it can use DNS SRV records */
1515  MANDATORY_AUTH_ARG(parsedline->ldapserver, "ldapserver", "ldap");
1516 #endif
1517 
1518  /*
1519  * LDAP can operate in two modes: either with a direct bind, using
1520  * ldapprefix and ldapsuffix, or using a search+bind, using
1521  * ldapbasedn, ldapbinddn, ldapbindpasswd and one of
1522  * ldapsearchattribute or ldapsearchfilter. Disallow mixing these
1523  * parameters.
1524  */
1525  if (parsedline->ldapprefix || parsedline->ldapsuffix)
1526  {
1527  if (parsedline->ldapbasedn ||
1528  parsedline->ldapbinddn ||
1529  parsedline->ldapbindpasswd ||
1530  parsedline->ldapsearchattribute ||
1531  parsedline->ldapsearchfilter)
1532  {
1533  ereport(elevel,
1534  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1535  errmsg("cannot use ldapbasedn, ldapbinddn, ldapbindpasswd, ldapsearchattribute, ldapsearchfilter, or ldapurl together with ldapprefix"),
1536  errcontext("line %d of configuration file \"%s\"",
1537  line_num, HbaFileName)));
1538  *err_msg = "cannot use ldapbasedn, ldapbinddn, ldapbindpasswd, ldapsearchattribute, ldapsearchfilter, or ldapurl together with ldapprefix";
1539  return NULL;
1540  }
1541  }
1542  else if (!parsedline->ldapbasedn)
1543  {
1544  ereport(elevel,
1545  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1546  errmsg("authentication method \"ldap\" requires argument \"ldapbasedn\", \"ldapprefix\", or \"ldapsuffix\" to be set"),
1547  errcontext("line %d of configuration file \"%s\"",
1548  line_num, HbaFileName)));
1549  *err_msg = "authentication method \"ldap\" requires argument \"ldapbasedn\", \"ldapprefix\", or \"ldapsuffix\" to be set";
1550  return NULL;
1551  }
1552 
1553  /*
1554  * When using search+bind, you can either use a simple attribute
1555  * (defaulting to "uid") or a fully custom search filter. You can't
1556  * do both.
1557  */
1558  if (parsedline->ldapsearchattribute && parsedline->ldapsearchfilter)
1559  {
1560  ereport(elevel,
1561  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1562  errmsg("cannot use ldapsearchattribute together with ldapsearchfilter"),
1563  errcontext("line %d of configuration file \"%s\"",
1564  line_num, HbaFileName)));
1565  *err_msg = "cannot use ldapsearchattribute together with ldapsearchfilter";
1566  return NULL;
1567  }
1568  }
1569 
1570  if (parsedline->auth_method == uaRADIUS)
1571  {
1572  MANDATORY_AUTH_ARG(parsedline->radiusservers, "radiusservers", "radius");
1573  MANDATORY_AUTH_ARG(parsedline->radiussecrets, "radiussecrets", "radius");
1574 
1575  if (list_length(parsedline->radiusservers) < 1)
1576  {
1577  ereport(elevel,
1578  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1579  errmsg("list of RADIUS servers cannot be empty"),
1580  errcontext("line %d of configuration file \"%s\"",
1581  line_num, HbaFileName)));
1582  *err_msg = "list of RADIUS servers cannot be empty";
1583  return NULL;
1584  }
1585 
1586  if (list_length(parsedline->radiussecrets) < 1)
1587  {
1588  ereport(elevel,
1589  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1590  errmsg("list of RADIUS secrets cannot be empty"),
1591  errcontext("line %d of configuration file \"%s\"",
1592  line_num, HbaFileName)));
1593  *err_msg = "list of RADIUS secrets cannot be empty";
1594  return NULL;
1595  }
1596 
1597  /*
1598  * Verify length of option lists - each can be 0 (except for secrets,
1599  * but that's already checked above), 1 (use the same value
1600  * everywhere) or the same as the number of servers.
1601  */
1602  if (!(list_length(parsedline->radiussecrets) == 1 ||
1603  list_length(parsedline->radiussecrets) == list_length(parsedline->radiusservers)))
1604  {
1605  ereport(elevel,
1606  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1607  errmsg("the number of RADIUS secrets (%d) must be 1 or the same as the number of RADIUS servers (%d)",
1608  list_length(parsedline->radiussecrets),
1609  list_length(parsedline->radiusservers)),
1610  errcontext("line %d of configuration file \"%s\"",
1611  line_num, HbaFileName)));
1612  *err_msg = psprintf("the number of RADIUS secrets (%d) must be 1 or the same as the number of RADIUS servers (%d)",
1613  list_length(parsedline->radiussecrets),
1614  list_length(parsedline->radiusservers));
1615  return NULL;
1616  }
1617  if (!(list_length(parsedline->radiusports) == 0 ||
1618  list_length(parsedline->radiusports) == 1 ||
1619  list_length(parsedline->radiusports) == list_length(parsedline->radiusservers)))
1620  {
1621  ereport(elevel,
1622  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1623  errmsg("the number of RADIUS ports (%d) must be 1 or the same as the number of RADIUS servers (%d)",
1624  list_length(parsedline->radiusports),
1625  list_length(parsedline->radiusservers)),
1626  errcontext("line %d of configuration file \"%s\"",
1627  line_num, HbaFileName)));
1628  *err_msg = psprintf("the number of RADIUS ports (%d) must be 1 or the same as the number of RADIUS servers (%d)",
1629  list_length(parsedline->radiusports),
1630  list_length(parsedline->radiusservers));
1631  return NULL;
1632  }
1633  if (!(list_length(parsedline->radiusidentifiers) == 0 ||
1634  list_length(parsedline->radiusidentifiers) == 1 ||
1635  list_length(parsedline->radiusidentifiers) == list_length(parsedline->radiusservers)))
1636  {
1637  ereport(elevel,
1638  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1639  errmsg("the number of RADIUS identifiers (%d) must be 1 or the same as the number of RADIUS servers (%d)",
1640  list_length(parsedline->radiusidentifiers),
1641  list_length(parsedline->radiusservers)),
1642  errcontext("line %d of configuration file \"%s\"",
1643  line_num, HbaFileName)));
1644  *err_msg = psprintf("the number of RADIUS identifiers (%d) must be 1 or the same as the number of RADIUS servers (%d)",
1645  list_length(parsedline->radiusidentifiers),
1646  list_length(parsedline->radiusservers));
1647  return NULL;
1648  }
1649  }
1650 
1651  /*
1652  * Enforce any parameters implied by other settings.
1653  */
1654  if (parsedline->auth_method == uaCert)
1655  {
1656  /*
1657  * For auth method cert, client certificate validation is mandatory,
1658  * and it implies the level of verify-full.
1659  */
1660  parsedline->clientcert = clientCertFull;
1661  }
1662 
1663  return parsedline;
1664 }
int errhint(const char *fmt,...)
Definition: elog.c:1151
#define EAI_NONAME
Definition: getaddrinfo.h:34
#define AI_NUMERICHOST
Definition: getaddrinfo.h:73
#define MANDATORY_AUTH_ARG(argvar, argname, authname)
Definition: hba.c:874
static bool parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline, int elevel, char **err_msg)
Definition: hba.c:1674
static AuthToken * copy_auth_token(AuthToken *in)
Definition: hba.c:281
@ ctHost
Definition: hba.h:60
@ uaBSD
Definition: hba.h:37
@ uaPassword
Definition: hba.h:31
@ uaMD5
Definition: hba.h:32
@ uaReject
Definition: hba.h:27
@ uaSCRAM
Definition: hba.h:33
@ uaTrust
Definition: hba.h:29
static int list_length(const List *l)
Definition: pg_list.h:149
static ListCell * list_head(const List *l)
Definition: pg_list.h:125
#define linitial(l)
Definition: pg_list.h:174
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:322
bool Db_user_namespace
Definition: postmaster.c:243
bool EnableSSL
Definition: postmaster.c:236
int addrlen
Definition: hba.h:88
int masklen
Definition: hba.h:90
char * rawline
Definition: hba.h:83
int length
Definition: pg_list.h:53
char * raw_line
Definition: hba.h:159
int line_num
Definition: hba.h:158
List * fields
Definition: hba.h:157
size_t ai_addrlen
Definition: getaddrinfo.h:104

References HbaLine::addr, HbaLine::addrlen, addrinfo::ai_addr, addrinfo::ai_addrlen, addrinfo::ai_canonname, addrinfo::ai_family, addrinfo::ai_flags, addrinfo::ai_next, AI_NUMERICHOST, addrinfo::ai_protocol, addrinfo::ai_socktype, Assert(), HbaLine::auth_method, HbaLine::clientcert, clientCertFull, HbaLine::compat_realm, HbaLine::conntype, copy_auth_token(), ctHost, ctHostGSS, ctHostNoGSS, ctHostNoSSL, ctHostSSL, ctLocal, HbaLine::databases, Db_user_namespace, EAI_NONAME, EnableSSL, ereport, TokenizedAuthLine::err_msg, errcode(), errcontext, errhint(), errmsg(), TokenizedAuthLine::fields, gai_strerror, HbaFileName, HbaLine::hostname, HbaLine::include_realm, HbaLine::ip_cmp_method, ipCmpAll, ipCmpMask, ipCmpSameHost, ipCmpSameNet, lappend(), HbaLine::ldapbasedn, HbaLine::ldapbinddn, HbaLine::ldapbindpasswd, HbaLine::ldapprefix, HbaLine::ldapsearchattribute, HbaLine::ldapsearchfilter, HbaLine::ldapserver, HbaLine::ldapsuffix, List::length, lfirst, TokenizedAuthLine::line_num, HbaLine::linenumber, linitial, list_head(), list_length(), lnext(), MANDATORY_AUTH_ARG, HbaLine::mask, HbaLine::masklen, NIL, palloc0(), parse_hba_auth_opt(), pfree(), pg_freeaddrinfo_all(), pg_getaddrinfo_all(), pg_sockaddr_cidr_mask(), psprintf(), pstrdup(), HbaLine::radiusidentifiers, HbaLine::radiusports, HbaLine::radiussecrets, HbaLine::radiusservers, TokenizedAuthLine::raw_line, HbaLine::rawline, HbaLine::roles, generate_unaccent_rules::str, AuthToken::string, token_is_keyword, uaBSD, uaCert, uaGSS, uaIdent, uaLDAP, uaMD5, uaPAM, uaPassword, uaRADIUS, uaReject, uaSCRAM, uaSSPI, uaTrust, HbaLine::upn_username, and val.

Referenced by fill_hba_view(), and load_hba().

◆ parse_ident_line()

IdentLine* parse_ident_line ( TokenizedAuthLine tok_line,
int  elevel 
)

Definition at line 2315 of file hba.c.

2316 {
2317  int line_num = tok_line->line_num;
2318  char **err_msg = &tok_line->err_msg;
2319  ListCell *field;
2320  List *tokens;
2321  AuthToken *token;
2322  IdentLine *parsedline;
2323 
2324  Assert(tok_line->fields != NIL);
2325  field = list_head(tok_line->fields);
2326 
2327  parsedline = palloc0(sizeof(IdentLine));
2328  parsedline->linenumber = line_num;
2329 
2330  /* Get the map token (must exist) */
2331  tokens = lfirst(field);
2332  IDENT_MULTI_VALUE(tokens);
2333  token = linitial(tokens);
2334  parsedline->usermap = pstrdup(token->string);
2335 
2336  /* Get the ident user token */
2337  field = lnext(tok_line->fields, field);
2338  IDENT_FIELD_ABSENT(field);
2339  tokens = lfirst(field);
2340  IDENT_MULTI_VALUE(tokens);
2341  token = linitial(tokens);
2342  parsedline->ident_user = pstrdup(token->string);
2343 
2344  /* Get the PG rolename token */
2345  field = lnext(tok_line->fields, field);
2346  IDENT_FIELD_ABSENT(field);
2347  tokens = lfirst(field);
2348  IDENT_MULTI_VALUE(tokens);
2349  token = linitial(tokens);
2350  parsedline->pg_role = pstrdup(token->string);
2351 
2352  if (parsedline->ident_user[0] == '/')
2353  {
2354  /*
2355  * When system username starts with a slash, treat it as a regular
2356  * expression. Pre-compile it.
2357  */
2358  int r;
2359  pg_wchar *wstr;
2360  int wlen;
2361 
2362  wstr = palloc((strlen(parsedline->ident_user + 1) + 1) * sizeof(pg_wchar));
2363  wlen = pg_mb2wchar_with_len(parsedline->ident_user + 1,
2364  wstr, strlen(parsedline->ident_user + 1));
2365 
2366  r = pg_regcomp(&parsedline->re, wstr, wlen, REG_ADVANCED, C_COLLATION_OID);
2367  if (r)
2368  {
2369  char errstr[100];
2370 
2371  pg_regerror(r, &parsedline->re, errstr, sizeof(errstr));
2372  ereport(elevel,
2373  (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
2374  errmsg("invalid regular expression \"%s\": %s",
2375  parsedline->ident_user + 1, errstr)));
2376 
2377  *err_msg = psprintf("invalid regular expression \"%s\": %s",
2378  parsedline->ident_user + 1, errstr);
2379 
2380  pfree(wstr);
2381  return NULL;
2382  }
2383  pfree(wstr);
2384  }
2385 
2386  return parsedline;
2387 }
#define IDENT_FIELD_ABSENT(field)
Definition: hba.c:898
#define IDENT_MULTI_VALUE(tokens)
Definition: hba.c:910
int pg_regcomp(regex_t *re, const chr *string, size_t len, int flags, Oid collation)
Definition: regcomp.c:328
#define REG_ADVANCED
Definition: regex.h:103
int linenumber
Definition: hba.h:127

References Assert(), ereport, TokenizedAuthLine::err_msg, errcode(), errmsg(), TokenizedAuthLine::fields, IDENT_FIELD_ABSENT, IDENT_MULTI_VALUE, IdentLine::ident_user, lfirst, TokenizedAuthLine::line_num, IdentLine::linenumber, linitial, list_head(), lnext(), NIL, palloc(), palloc0(), pfree(), pg_mb2wchar_with_len(), pg_regcomp(), pg_regerror(), IdentLine::pg_role, psprintf(), pstrdup(), IdentLine::re, REG_ADVANCED, AuthToken::string, and IdentLine::usermap.

Referenced by fill_ident_view(), and load_ident().

◆ pg_isblank()

bool pg_isblank ( const char  c)

Definition at line 126 of file hba.c.

127 {
128  return c == ' ' || c == '\t' || c == '\r';
129 }

Referenced by interpret_ident_response(), and next_token().

◆ tokenize_auth_file()

MemoryContext tokenize_auth_file ( const char *  filename,
FILE *  file,
List **  tok_lines,
int  elevel 
)

Definition at line 446 of file hba.c.

448 {
449  int line_number = 1;
451  MemoryContext linecxt;
452  MemoryContext oldcxt;
453 
455  "tokenize_auth_file",
457  oldcxt = MemoryContextSwitchTo(linecxt);
458 
460 
461  *tok_lines = NIL;
462 
463  while (!feof(file) && !ferror(file))
464  {
465  char *lineptr;
466  List *current_line = NIL;
467  char *err_msg = NULL;
468  int last_backslash_buflen = 0;
469  int continuations = 0;
470 
471  /* Collect the next input line, handling backslash continuations */
473 
474  while (pg_get_line_append(file, &buf, NULL))
475  {
476  /* Strip trailing newline, including \r in case we're on Windows */
477  buf.len = pg_strip_crlf(buf.data);
478 
479  /*
480  * Check for backslash continuation. The backslash must be after
481  * the last place we found a continuation, else two backslashes
482  * followed by two \n's would behave surprisingly.
483  */
484  if (buf.len > last_backslash_buflen &&
485  buf.data[buf.len - 1] == '\\')
486  {
487  /* Continuation, so strip it and keep reading */
488  buf.data[--buf.len] = '\0';
489  last_backslash_buflen = buf.len;
490  continuations++;
491  continue;
492  }
493 
494  /* Nope, so we have the whole line */
495  break;
496  }
497 
498  if (ferror(file))
499  {
500  /* I/O error! */
501  int save_errno = errno;
502 
503  ereport(elevel,
505  errmsg("could not read file \"%s\": %m", filename)));
506  err_msg = psprintf("could not read file \"%s\": %s",
507  filename, strerror(save_errno));
508  break;
509  }
510 
511  /* Parse fields */
512  lineptr = buf.data;
513  while (*lineptr && err_msg == NULL)
514  {
515  List *current_field;
516 
517  current_field = next_field_expand(filename, &lineptr,
518  elevel, &err_msg);
519  /* add field to line, unless we are at EOL or comment start */
520  if (current_field != NIL)
521  current_line = lappend(current_line, current_field);
522  }
523 
524  /*
525  * Reached EOL; emit line to TokenizedAuthLine list unless it's boring
526  */
527  if (current_line != NIL || err_msg != NULL)
528  {
529  TokenizedAuthLine *tok_line;
530 
531  tok_line = (TokenizedAuthLine *) palloc(sizeof(TokenizedAuthLine));
532  tok_line->fields = current_line;
533  tok_line->line_num = line_number;
534  tok_line->raw_line = pstrdup(buf.data);
535  tok_line->err_msg = err_msg;
536  *tok_lines = lappend(*tok_lines, tok_line);
537  }
538 
539  line_number += continuations + 1;
540  }
541 
542  MemoryContextSwitchTo(oldcxt);
543 
544  return linecxt;
545 }
static List * next_field_expand(const char *filename, char **lineptr, int elevel, char **err_msg)
Definition: hba.c:304
MemoryContext CurrentMemoryContext
Definition: mcxt.c:42
bool pg_get_line_append(FILE *stream, StringInfo buf, PromptInterruptContext *prompt_ctx)
Definition: pg_get_line.c:124
#define strerror
Definition: port.h:238
int pg_strip_crlf(char *str)
Definition: string.c:121
void resetStringInfo(StringInfo str)
Definition: stringinfo.c:75
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate, buf, CurrentMemoryContext, ereport, TokenizedAuthLine::err_msg, errcode_for_file_access(), errmsg(), TokenizedAuthLine::fields, filename, initStringInfo(), lappend(), TokenizedAuthLine::line_num, MemoryContextSwitchTo(), next_field_expand(), NIL, palloc(), pg_get_line_append(), pg_strip_crlf(), psprintf(), pstrdup(), TokenizedAuthLine::raw_line, resetStringInfo(), and strerror.

Referenced by fill_hba_view(), fill_ident_view(), load_hba(), load_ident(), and tokenize_inc_file().

◆ tokenize_inc_file()

static List * tokenize_inc_file ( List tokens,
const char *  outer_filename,
const char *  inc_filename,
int  elevel,
char **  err_msg 
)
static

Definition at line 346 of file hba.c.

351 {
352  char *inc_fullname;
353  FILE *inc_file;
354  List *inc_lines;
355  ListCell *inc_line;
356  MemoryContext linecxt;
357 
358  if (is_absolute_path(inc_filename))
359  {
360  /* absolute path is taken as-is */
361  inc_fullname = pstrdup(inc_filename);
362  }
363  else
364  {
365  /* relative path is relative to dir of calling file */
366  inc_fullname = (char *) palloc(strlen(outer_filename) + 1 +
367  strlen(inc_filename) + 1);
368  strcpy(inc_fullname, outer_filename);
369  get_parent_directory(inc_fullname);
370  join_path_components(inc_fullname, inc_fullname, inc_filename);
371  canonicalize_path(inc_fullname);
372  }
373 
374  inc_file = AllocateFile(inc_fullname, "r");
375  if (inc_file == NULL)
376  {
377  int save_errno = errno;
378 
379  ereport(elevel,
381  errmsg("could not open secondary authentication file \"@%s\" as \"%s\": %m",
382  inc_filename, inc_fullname)));
383  *err_msg = psprintf("could not open secondary authentication file \"@%s\" as \"%s\": %s",
384  inc_filename, inc_fullname, strerror(save_errno));
385  pfree(inc_fullname);
386  return tokens;
387  }
388 
389  /* There is possible recursion here if the file contains @ */
390  linecxt = tokenize_auth_file(inc_fullname, inc_file, &inc_lines, elevel);
391 
392  FreeFile(inc_file);
393  pfree(inc_fullname);
394 
395  /* Copy all tokens found in the file and append to the tokens list */
396  foreach(inc_line, inc_lines)
397  {
398  TokenizedAuthLine *tok_line = (TokenizedAuthLine *) lfirst(inc_line);
399  ListCell *inc_field;
400 
401  /* If any line has an error, propagate that up to caller */
402  if (tok_line->err_msg)
403  {
404  *err_msg = pstrdup(tok_line->err_msg);
405  break;
406  }
407 
408  foreach(inc_field, tok_line->fields)
409  {
410  List *inc_tokens = lfirst(inc_field);
411  ListCell *inc_token;
412 
413  foreach(inc_token, inc_tokens)
414  {
415  AuthToken *token = lfirst(inc_token);
416 
417  tokens = lappend(tokens, copy_auth_token(token));
418  }
419  }
420  }
421 
422  MemoryContextDelete(linecxt);
423  return tokens;
424 }
void join_path_components(char *ret_path, const char *head, const char *tail)
Definition: path.c:219
#define is_absolute_path(filename)
Definition: port.h:89
void canonicalize_path(char *path)
Definition: path.c:264
void get_parent_directory(char *path)
Definition: path.c:977

References AllocateFile(), canonicalize_path(), copy_auth_token(), ereport, TokenizedAuthLine::err_msg, errcode_for_file_access(), errmsg(), TokenizedAuthLine::fields, FreeFile(), get_parent_directory(), is_absolute_path, join_path_components(), lappend(), lfirst, MemoryContextDelete(), palloc(), pfree(), psprintf(), pstrdup(), strerror, and tokenize_auth_file().

Referenced by next_field_expand().

Variable Documentation

◆ parsed_hba_context

MemoryContext parsed_hba_context = NULL
static

Definition at line 76 of file hba.c.

Referenced by load_hba().

◆ parsed_hba_lines

List* parsed_hba_lines = NIL
static

Definition at line 75 of file hba.c.

Referenced by check_hba(), and load_hba().

◆ parsed_ident_context

MemoryContext parsed_ident_context = NULL
static

Definition at line 87 of file hba.c.

Referenced by load_ident().

◆ parsed_ident_lines

List* parsed_ident_lines = NIL
static

Definition at line 86 of file hba.c.

Referenced by check_usermap(), and load_ident().

◆ UserAuthName

const char* const UserAuthName[]
static
Initial value:
=
{
"reject",
"implicit reject",
"trust",
"ident",
"password",
"md5",
"scram-sha-256",
"gss",
"sspi",
"pam",
"bsd",
"ldap",
"cert",
"radius",
"peer"
}

Definition at line 95 of file hba.c.

Referenced by hba_authname().