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 <netdb.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/conffiles.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
 
struct  tokenize_error_callback_arg
 

Macros

#define MAX_TOKEN   256
 
#define token_has_regexp(t)   (t->regex != NULL)
 
#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_expand_file (List *tokens, const char *outer_filename, const char *inc_filename, int elevel, int depth, char **err_msg)
 
static bool parse_hba_auth_opt (char *name, char *val, HbaLine *hbaline, int elevel, char **err_msg)
 
static int regcomp_auth_token (AuthToken *token, char *filename, int line_num, char **err_msg, int elevel)
 
static int regexec_auth_token (const char *match, AuthToken *token, size_t nmatch, regmatch_t pmatch[])
 
static void tokenize_error_callback (void *arg)
 
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 void free_auth_token (AuthToken *token)
 
static void free_hba_line (HbaLine *line)
 
static AuthTokencopy_auth_token (AuthToken *in)
 
static Listnext_field_expand (const char *filename, char **lineptr, int elevel, int depth, char **err_msg)
 
static void tokenize_include_file (const char *outer_filename, const char *inc_filename, List **tok_lines, int elevel, int depth, bool missing_ok, char **err_msg)
 
void free_auth_file (FILE *file, int depth)
 
FILE * open_auth_file (const char *filename, int elevel, int depth, char **err_msg)
 
void tokenize_auth_file (const char *filename, FILE *file, List **tok_lines, int elevel, int depth)
 
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 ipv6eq (struct sockaddr_in6 *a, struct sockaddr_in6 *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 MemoryContext tokenize_context = NULL
 
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 at end of line"), \
errcontext("line %d of configuration file \"%s\"", \
line_num, file_name))); \
*err_msg = pstrdup("missing entry at end of line"); \
return NULL; \
} \
} while (0)
int errcode(int sqlerrcode)
Definition: elog.c:735
int errmsg(const char *fmt,...)
Definition: elog.c:946
#define errcontext
Definition: elog.h:192
char * pstrdup(const char *in)
Definition: mcxt.c:1483

Definition at line 1324 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, file_name))); \
*err_msg = pstrdup("multiple values in ident field"); \
return NULL; \
} \
} while (0)

Definition at line 1337 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, file_name))); \
*err_msg = psprintf("authentication option \"%s\" is only valid for authentication methods %s", \
optname, validmethods); \
return false; \
} while (0)
#define _(x)
Definition: elog.c:90
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46

Definition at line 1280 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, file_name))); \
*err_msg = psprintf("authentication method \"%s\" requires argument \"%s\" to be set", \
authname, argname); \
return NULL; \
} \
} while (0)

Definition at line 1300 of file hba.c.

◆ MAX_TOKEN

#define MAX_TOKEN   256

Definition at line 59 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 1294 of file hba.c.

◆ token_has_regexp

#define token_has_regexp (   t)    (t->regex != NULL)

Definition at line 75 of file hba.c.

◆ token_is_keyword

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

Definition at line 76 of file hba.c.

◆ token_matches

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

Definition at line 77 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 1029 of file hba.c.

1030 {
1031  ListCell *cell;
1032  AuthToken *tok;
1033 
1034  foreach(cell, tokens)
1035  {
1036  tok = lfirst(cell);
1037  if (am_walsender && !am_db_walsender)
1038  {
1039  /*
1040  * physical replication walsender connections can only match
1041  * replication keyword
1042  */
1043  if (token_is_keyword(tok, "replication"))
1044  return true;
1045  }
1046  else if (token_is_keyword(tok, "all"))
1047  return true;
1048  else if (token_is_keyword(tok, "sameuser"))
1049  {
1050  if (strcmp(dbname, role) == 0)
1051  return true;
1052  }
1053  else if (token_is_keyword(tok, "samegroup") ||
1054  token_is_keyword(tok, "samerole"))
1055  {
1056  if (is_member(roleid, dbname))
1057  return true;
1058  }
1059  else if (token_is_keyword(tok, "replication"))
1060  continue; /* never match this if not walsender */
1061  else if (token_has_regexp(tok))
1062  {
1063  if (regexec_auth_token(dbname, tok, 0, NULL) == REG_OKAY)
1064  return true;
1065  }
1066  else if (token_matches(tok, dbname))
1067  return true;
1068  }
1069  return false;
1070 }
static bool is_member(Oid userid, const char *role)
Definition: hba.c:967
#define token_is_keyword(t, k)
Definition: hba.c:76
static int regexec_auth_token(const char *match, AuthToken *token, size_t nmatch, regmatch_t pmatch[])
Definition: hba.c:397
#define token_has_regexp(t)
Definition: hba.c:75
#define token_matches(t, k)
Definition: hba.c:77
#define lfirst(lc)
Definition: pg_list.h:170
#define REG_OKAY
Definition: regex.h:137
char * dbname
Definition: streamutil.c:51
Definition: hba.h:88
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, REG_OKAY, regexec_auth_token(), token_has_regexp, token_is_keyword, and token_matches.

Referenced by check_hba().

◆ check_hba()

static void check_hba ( hbaPort port)
static

Definition at line 2523 of file hba.c.

2524 {
2525  Oid roleid;
2526  ListCell *line;
2527  HbaLine *hba;
2528 
2529  /* Get the target role's OID. Note we do not error out for bad role. */
2530  roleid = get_role_oid(port->user_name, true);
2531 
2532  foreach(line, parsed_hba_lines)
2533  {
2534  hba = (HbaLine *) lfirst(line);
2535 
2536  /* Check connection type */
2537  if (hba->conntype == ctLocal)
2538  {
2539  if (port->raddr.addr.ss_family != AF_UNIX)
2540  continue;
2541  }
2542  else
2543  {
2544  if (port->raddr.addr.ss_family == AF_UNIX)
2545  continue;
2546 
2547  /* Check SSL state */
2548  if (port->ssl_in_use)
2549  {
2550  /* Connection is SSL, match both "host" and "hostssl" */
2551  if (hba->conntype == ctHostNoSSL)
2552  continue;
2553  }
2554  else
2555  {
2556  /* Connection is not SSL, match both "host" and "hostnossl" */
2557  if (hba->conntype == ctHostSSL)
2558  continue;
2559  }
2560 
2561  /* Check GSSAPI state */
2562 #ifdef ENABLE_GSS
2563  if (port->gss && port->gss->enc &&
2564  hba->conntype == ctHostNoGSS)
2565  continue;
2566  else if (!(port->gss && port->gss->enc) &&
2567  hba->conntype == ctHostGSS)
2568  continue;
2569 #else
2570  if (hba->conntype == ctHostGSS)
2571  continue;
2572 #endif
2573 
2574  /* Check IP address */
2575  switch (hba->ip_cmp_method)
2576  {
2577  case ipCmpMask:
2578  if (hba->hostname)
2579  {
2580  if (!check_hostname(port,
2581  hba->hostname))
2582  continue;
2583  }
2584  else
2585  {
2586  if (!check_ip(&port->raddr,
2587  (struct sockaddr *) &hba->addr,
2588  (struct sockaddr *) &hba->mask))
2589  continue;
2590  }
2591  break;
2592  case ipCmpAll:
2593  break;
2594  case ipCmpSameHost:
2595  case ipCmpSameNet:
2596  if (!check_same_host_or_net(&port->raddr,
2597  hba->ip_cmp_method))
2598  continue;
2599  break;
2600  default:
2601  /* shouldn't get here, but deem it no-match if so */
2602  continue;
2603  }
2604  } /* != ctLocal */
2605 
2606  /* Check database and role */
2607  if (!check_db(port->database_name, port->user_name, roleid,
2608  hba->databases))
2609  continue;
2610 
2611  if (!check_role(port->user_name, roleid, hba->roles))
2612  continue;
2613 
2614  /* Found a record that matched! */
2615  port->hba = hba;
2616  return;
2617  }
2618 
2619  /* If no matching entry was found, then implicitly reject. */
2620  hba = palloc0(sizeof(HbaLine));
2622  port->hba = hba;
2623 }
Oid get_role_oid(const char *rolname, bool missing_ok)
Definition: acl.c:5235
static bool check_ip(SockAddr *raddr, struct sockaddr *addr, struct sockaddr *mask)
Definition: hba.c:1205
static bool check_same_host_or_net(SockAddr *raddr, IPCompareMethod method)
Definition: hba.c:1246
static bool check_hostname(hbaPort *port, const char *hostname)
Definition: hba.c:1114
static List * parsed_hba_lines
Definition: hba.c:90
static bool check_db(const char *dbname, const char *role, Oid roleid, List *tokens)
Definition: hba.c:1029
static bool check_role(const char *role, Oid roleid, List *tokens)
Definition: hba.c:995
@ 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:1230
static int port
Definition: pg_regress.c:90
unsigned int Oid
Definition: postgres_ext.h:31
Definition: hba.h:95
UserAuth auth_method
Definition: hba.h:108
struct sockaddr_storage mask
Definition: hba.h:104
char * hostname
Definition: hba.h:107
List * databases
Definition: hba.h:100
ConnType conntype
Definition: hba.h:99
struct sockaddr_storage addr
Definition: hba.h:102
List * roles
Definition: hba.h:101
IPCompareMethod ip_cmp_method
Definition: hba.h:106

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

1115 {
1116  struct addrinfo *gai_result,
1117  *gai;
1118  int ret;
1119  bool found;
1120 
1121  /* Quick out if remote host name already known bad */
1122  if (port->remote_hostname_resolv < 0)
1123  return false;
1124 
1125  /* Lookup remote host name if not already done */
1126  if (!port->remote_hostname)
1127  {
1128  char remote_hostname[NI_MAXHOST];
1129 
1130  ret = pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
1131  remote_hostname, sizeof(remote_hostname),
1132  NULL, 0,
1133  NI_NAMEREQD);
1134  if (ret != 0)
1135  {
1136  /* remember failure; don't complain in the postmaster log yet */
1137  port->remote_hostname_resolv = -2;
1138  port->remote_hostname_errcode = ret;
1139  return false;
1140  }
1141 
1142  port->remote_hostname = pstrdup(remote_hostname);
1143  }
1144 
1145  /* Now see if remote host name matches this pg_hba line */
1146  if (!hostname_match(hostname, port->remote_hostname))
1147  return false;
1148 
1149  /* If we already verified the forward lookup, we're done */
1150  if (port->remote_hostname_resolv == +1)
1151  return true;
1152 
1153  /* Lookup IP from host name and check against original IP */
1154  ret = getaddrinfo(port->remote_hostname, NULL, NULL, &gai_result);
1155  if (ret != 0)
1156  {
1157  /* remember failure; don't complain in the postmaster log yet */
1158  port->remote_hostname_resolv = -2;
1159  port->remote_hostname_errcode = ret;
1160  return false;
1161  }
1162 
1163  found = false;
1164  for (gai = gai_result; gai; gai = gai->ai_next)
1165  {
1166  if (gai->ai_addr->sa_family == port->raddr.addr.ss_family)
1167  {
1168  if (gai->ai_addr->sa_family == AF_INET)
1169  {
1170  if (ipv4eq((struct sockaddr_in *) gai->ai_addr,
1171  (struct sockaddr_in *) &port->raddr.addr))
1172  {
1173  found = true;
1174  break;
1175  }
1176  }
1177  else if (gai->ai_addr->sa_family == AF_INET6)
1178  {
1179  if (ipv6eq((struct sockaddr_in6 *) gai->ai_addr,
1180  (struct sockaddr_in6 *) &port->raddr.addr))
1181  {
1182  found = true;
1183  break;
1184  }
1185  }
1186  }
1187  }
1188 
1189  if (gai_result)
1190  freeaddrinfo(gai_result);
1191 
1192  if (!found)
1193  elog(DEBUG2, "pg_hba.conf host name \"%s\" rejected because address resolution did not return a match with IP address of client",
1194  hostname);
1195 
1196  port->remote_hostname_resolv = found ? +1 : -1;
1197 
1198  return found;
1199 }
#define DEBUG2
Definition: elog.h:25
static bool hostname_match(const char *pattern, const char *actual_hostname)
Definition: hba.c:1094
static bool ipv4eq(struct sockaddr_in *a, struct sockaddr_in *b)
Definition: hba.c:1073
static bool ipv6eq(struct sockaddr_in6 *a, struct sockaddr_in6 *b)
Definition: hba.c:1079
int pg_getnameinfo_all(const struct sockaddr_storage *addr, int salen, char *node, int nodelen, char *service, int servicelen, int flags)
Definition: ip.c:114
static char * hostname
Definition: pg_regress.c:89

References DEBUG2, elog(), hostname, hostname_match(), ipv4eq(), ipv6eq(), 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 2820 of file hba.c.

2823 {
2824  *found_p = false;
2825  *error_p = false;
2826 
2827  if (strcmp(identLine->usermap, usermap_name) != 0)
2828  /* Line does not match the map name we're looking for, so just abort */
2829  return;
2830 
2831  /* Match? */
2832  if (token_has_regexp(identLine->token))
2833  {
2834  /*
2835  * Process the system username as a regular expression that returns
2836  * exactly one match. This is replaced for \1 in the database username
2837  * string, if present.
2838  */
2839  int r;
2840  regmatch_t matches[2];
2841  char *ofs;
2842  char *regexp_pgrole;
2843 
2844  r = regexec_auth_token(ident_user, identLine->token, 2, matches);
2845  if (r)
2846  {
2847  char errstr[100];
2848 
2849  if (r != REG_NOMATCH)
2850  {
2851  /* REG_NOMATCH is not an error, everything else is */
2852  pg_regerror(r, identLine->token->regex, errstr, sizeof(errstr));
2853  ereport(LOG,
2854  (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
2855  errmsg("regular expression match for \"%s\" failed: %s",
2856  identLine->token->string + 1, errstr)));
2857  *error_p = true;
2858  }
2859  return;
2860  }
2861 
2862  if ((ofs = strstr(identLine->pg_role, "\\1")) != NULL)
2863  {
2864  int offset;
2865 
2866  /* substitution of the first argument requested */
2867  if (matches[1].rm_so < 0)
2868  {
2869  ereport(LOG,
2870  (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
2871  errmsg("regular expression \"%s\" has no subexpressions as requested by backreference in \"%s\"",
2872  identLine->token->string + 1, identLine->pg_role)));
2873  *error_p = true;
2874  return;
2875  }
2876 
2877  /*
2878  * length: original length minus length of \1 plus length of match
2879  * plus null terminator
2880  */
2881  regexp_pgrole = palloc0(strlen(identLine->pg_role) - 2 + (matches[1].rm_eo - matches[1].rm_so) + 1);
2882  offset = ofs - identLine->pg_role;
2883  memcpy(regexp_pgrole, identLine->pg_role, offset);
2884  memcpy(regexp_pgrole + offset,
2885  ident_user + matches[1].rm_so,
2886  matches[1].rm_eo - matches[1].rm_so);
2887  strcat(regexp_pgrole, ofs + 2);
2888  }
2889  else
2890  {
2891  /* no substitution, so copy the match */
2892  regexp_pgrole = pstrdup(identLine->pg_role);
2893  }
2894 
2895  /*
2896  * now check if the username actually matched what the user is trying
2897  * to connect as
2898  */
2899  if (case_insensitive)
2900  {
2901  if (pg_strcasecmp(regexp_pgrole, pg_role) == 0)
2902  *found_p = true;
2903  }
2904  else
2905  {
2906  if (strcmp(regexp_pgrole, pg_role) == 0)
2907  *found_p = true;
2908  }
2909  pfree(regexp_pgrole);
2910 
2911  return;
2912  }
2913  else
2914  {
2915  /* Not regular expression, so make complete match */
2916  if (case_insensitive)
2917  {
2918  if (pg_strcasecmp(identLine->pg_role, pg_role) == 0 &&
2919  pg_strcasecmp(identLine->token->string, ident_user) == 0)
2920  *found_p = true;
2921  }
2922  else
2923  {
2924  if (strcmp(identLine->pg_role, pg_role) == 0 &&
2925  strcmp(identLine->token->string, ident_user) == 0)
2926  *found_p = true;
2927  }
2928  }
2929 }
#define LOG
Definition: elog.h:27
#define ereport(elevel,...)
Definition: elog.h:145
void pfree(void *pointer)
Definition: mcxt.c:1306
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
regex_t * regex
Definition: hba.h:91
char * string
Definition: hba.h:89
char * pg_role
Definition: hba.h:145
AuthToken * token
Definition: hba.h:146
char * usermap
Definition: hba.h:144

References ereport, errcode(), errmsg(), LOG, palloc0(), pfree(), pg_regerror(), IdentLine::pg_role, pg_strcasecmp(), pstrdup(), REG_NOMATCH, AuthToken::regex, regexec_auth_token(), regmatch_t::rm_eo, regmatch_t::rm_so, AuthToken::string, IdentLine::token, token_has_regexp, 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 1205 of file hba.c.

1206 {
1207  if (raddr->addr.ss_family == addr->sa_family &&
1208  pg_range_sockaddr(&raddr->addr,
1209  (struct sockaddr_storage *) addr,
1210  (struct sockaddr_storage *) mask))
1211  return true;
1212  return false;
1213 }
int pg_range_sockaddr(const struct sockaddr_storage *addr, const struct sockaddr_storage *netaddr, const struct sockaddr_storage *netmask)
Definition: ifaddr.c:49
struct sockaddr_storage addr
Definition: pqcomm.h:26

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

1221 {
1222  check_network_data *cn = (check_network_data *) cb_data;
1223  struct sockaddr_storage mask;
1224 
1225  /* Already found a match? */
1226  if (cn->result)
1227  return;
1228 
1229  if (cn->method == ipCmpSameHost)
1230  {
1231  /* Make an all-ones netmask of appropriate length for family */
1232  pg_sockaddr_cidr_mask(&mask, NULL, addr->sa_family);
1233  cn->result = check_ip(cn->raddr, addr, (struct sockaddr *) &mask);
1234  }
1235  else
1236  {
1237  /* Use the netmask of the interface itself */
1238  cn->result = check_ip(cn->raddr, addr, netmask);
1239  }
1240 }
int pg_sockaddr_cidr_mask(struct sockaddr_storage *mask, char *numbits, int family)
Definition: ifaddr.c:105
bool result
Definition: hba.c:66
SockAddr * raddr
Definition: hba.c:65
IPCompareMethod method
Definition: hba.c:64

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

996 {
997  ListCell *cell;
998  AuthToken *tok;
999 
1000  foreach(cell, tokens)
1001  {
1002  tok = lfirst(cell);
1003  if (!tok->quoted && tok->string[0] == '+')
1004  {
1005  if (is_member(roleid, tok->string + 1))
1006  return true;
1007  }
1008  else if (token_is_keyword(tok, "all"))
1009  return true;
1010  else if (token_has_regexp(tok))
1011  {
1012  if (regexec_auth_token(role, tok, 0, NULL) == REG_OKAY)
1013  return true;
1014  }
1015  else if (token_matches(tok, role))
1016  return true;
1017  }
1018  return false;
1019 }
bool quoted
Definition: hba.h:90

References is_member(), lfirst, AuthToken::quoted, REG_OKAY, regexec_auth_token(), AuthToken::string, token_has_regexp, 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 1246 of file hba.c.

1247 {
1248  check_network_data cn;
1249 
1250  cn.method = method;
1251  cn.raddr = raddr;
1252  cn.result = false;
1253 
1254  errno = 0;
1256  {
1257  ereport(LOG,
1258  (errmsg("error enumerating network interfaces: %m")));
1259  return false;
1260  }
1261 
1262  return cn.result;
1263 }
static void check_network_callback(struct sockaddr *addr, struct sockaddr *netmask, void *cb_data)
Definition: hba.c:1219
int pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data)
Definition: ifaddr.c:425

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

2950 {
2951  bool found_entry = false,
2952  error = false;
2953 
2954  if (usermap_name == NULL || usermap_name[0] == '\0')
2955  {
2956  if (case_insensitive)
2957  {
2958  if (pg_strcasecmp(pg_role, auth_user) == 0)
2959  return STATUS_OK;
2960  }
2961  else
2962  {
2963  if (strcmp(pg_role, auth_user) == 0)
2964  return STATUS_OK;
2965  }
2966  ereport(LOG,
2967  (errmsg("provided user name (%s) and authenticated user name (%s) do not match",
2968  pg_role, auth_user)));
2969  return STATUS_ERROR;
2970  }
2971  else
2972  {
2973  ListCell *line_cell;
2974 
2975  foreach(line_cell, parsed_ident_lines)
2976  {
2977  check_ident_usermap(lfirst(line_cell), usermap_name,
2978  pg_role, auth_user, case_insensitive,
2979  &found_entry, &error);
2980  if (found_entry || error)
2981  break;
2982  }
2983  }
2984  if (!found_entry && !error)
2985  {
2986  ereport(LOG,
2987  (errmsg("no match in usermap \"%s\" for user \"%s\" authenticated as \"%s\"",
2988  usermap_name, pg_role, auth_user)));
2989  }
2990  return found_entry ? STATUS_OK : STATUS_ERROR;
2991 }
#define STATUS_OK
Definition: c.h:1108
#define STATUS_ERROR
Definition: c.h:1109
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:2820
static List * parsed_ident_lines
Definition: hba.c:102
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 339 of file hba.c.

340 {
341  AuthToken *out = make_auth_token(in->string, in->quoted);
342 
343  return out;
344 }
static AuthToken * make_auth_token(const char *token, bool quoted)
Definition: hba.c:284

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

Referenced by parse_hba_line(), and parse_ident_line().

◆ free_auth_file()

void free_auth_file ( FILE *  file,
int  depth 
)

Definition at line 618 of file hba.c.

619 {
620  FreeFile(file);
621 
622  /* If this is the last cleanup, remove the tokenization context */
623  if (depth == CONF_FILE_START_DEPTH)
624  {
626  tokenize_context = NULL;
627  }
628 }
#define CONF_FILE_START_DEPTH
Definition: conffiles.h:17
int FreeFile(FILE *file)
Definition: fd.c:2581
static MemoryContext tokenize_context
Definition: hba.c:84
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:376

References CONF_FILE_START_DEPTH, FreeFile(), MemoryContextDelete(), and tokenize_context.

Referenced by fill_hba_view(), fill_ident_view(), load_hba(), load_ident(), tokenize_expand_file(), and tokenize_include_file().

◆ free_auth_token()

static void free_auth_token ( AuthToken token)
static

Definition at line 305 of file hba.c.

306 {
307  if (token_has_regexp(token))
308  pg_regfree(token->regex);
309 }
void pg_regfree(regex_t *re)
Definition: regfree.c:49

References pg_regfree(), AuthToken::regex, and token_has_regexp.

Referenced by free_hba_line(), and load_ident().

◆ free_hba_line()

static void free_hba_line ( HbaLine line)
static

Definition at line 316 of file hba.c.

317 {
318  ListCell *cell;
319 
320  foreach(cell, line->roles)
321  {
322  AuthToken *tok = lfirst(cell);
323 
324  free_auth_token(tok);
325  }
326 
327  foreach(cell, line->databases)
328  {
329  AuthToken *tok = lfirst(cell);
330 
331  free_auth_token(tok);
332  }
333 }
static void free_auth_token(AuthToken *token)
Definition: hba.c:305

References HbaLine::databases, free_auth_token(), lfirst, and HbaLine::roles.

Referenced by load_hba().

◆ hba_authname()

const char* hba_authname ( UserAuth  auth_method)

Definition at line 3118 of file hba.c.

3119 {
3120  /*
3121  * Make sure UserAuthName[] tracks additions to the UserAuth enum
3122  */
3124  "UserAuthName[] must match the UserAuth enum");
3125 
3126  return UserAuthName[auth_method];
3127 }
#define lengthof(array)
Definition: c.h:724
#define StaticAssertStmt(condition, errmessage)
Definition: c.h:869
static const char *const UserAuthName[]
Definition: hba.c:111
#define USER_AUTH_LAST
Definition: hba.h:42

References lengthof, StaticAssertStmt, USER_AUTH_LAST, and UserAuthName.

Referenced by fill_hba_line(), InitPostgres(), ParallelWorkerMain(), and set_authn_id().

◆ hba_getauthmethod()

void hba_getauthmethod ( hbaPort port)

Definition at line 3105 of file hba.c.

3106 {
3107  check_hba(port);
3108 }
static void check_hba(hbaPort *port)
Definition: hba.c:2523

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

1095 {
1096  if (pattern[0] == '.') /* suffix match */
1097  {
1098  size_t plen = strlen(pattern);
1099  size_t hlen = strlen(actual_hostname);
1100 
1101  if (hlen < plen)
1102  return false;
1103 
1104  return (pg_strcasecmp(pattern, actual_hostname + (hlen - plen)) == 0);
1105  }
1106  else
1107  return (pg_strcasecmp(pattern, actual_hostname) == 0);
1108 }

References pg_strcasecmp().

Referenced by check_hostname().

◆ ipv4eq()

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

Definition at line 1073 of file hba.c.

1074 {
1075  return (a->sin_addr.s_addr == b->sin_addr.s_addr);
1076 }
int b
Definition: isn.c:70
int a
Definition: isn.c:69

References a, and b.

Referenced by check_hostname().

◆ ipv6eq()

static bool ipv6eq ( struct sockaddr_in6 *  a,
struct sockaddr_in6 *  b 
)
static

Definition at line 1079 of file hba.c.

1080 {
1081  int i;
1082 
1083  for (i = 0; i < 16; i++)
1084  if (a->sin6_addr.s6_addr[i] != b->sin6_addr.s6_addr[i])
1085  return false;
1086 
1087  return true;
1088 }
int i
Definition: isn.c:73

References a, b, and i.

Referenced by check_hostname().

◆ is_member()

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

Definition at line 967 of file hba.c.

968 {
969  Oid roleid;
970 
971  if (!OidIsValid(userid))
972  return false; /* if user not exist, say "no" */
973 
974  roleid = get_role_oid(role, true);
975 
976  if (!OidIsValid(roleid))
977  return false; /* if target role not exist, say "no" */
978 
979  /*
980  * See if user is directly or indirectly a member of role. For this
981  * purpose, a superuser is not considered to be automatically a member of
982  * the role, so group auth only applies to explicit membership.
983  */
984  return is_member_of_role_nosuper(userid, roleid);
985 }
bool is_member_of_role_nosuper(Oid member, Oid role)
Definition: acl.c:5057
#define OidIsValid(objectId)
Definition: c.h:711

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

2638 {
2639  FILE *file;
2640  List *hba_lines = NIL;
2641  ListCell *line;
2642  List *new_parsed_lines = NIL;
2643  bool ok = true;
2644  MemoryContext oldcxt;
2645  MemoryContext hbacxt;
2646 
2647  file = open_auth_file(HbaFileName, LOG, 0, NULL);
2648  if (file == NULL)
2649  {
2650  /* error already logged */
2651  return false;
2652  }
2653 
2654  tokenize_auth_file(HbaFileName, file, &hba_lines, LOG, 0);
2655 
2656  /* Now parse all the lines */
2659  "hba parser context",
2661  oldcxt = MemoryContextSwitchTo(hbacxt);
2662  foreach(line, hba_lines)
2663  {
2664  TokenizedAuthLine *tok_line = (TokenizedAuthLine *) lfirst(line);
2665  HbaLine *newline;
2666 
2667  /* don't parse lines that already have errors */
2668  if (tok_line->err_msg != NULL)
2669  {
2670  ok = false;
2671  continue;
2672  }
2673 
2674  if ((newline = parse_hba_line(tok_line, LOG)) == NULL)
2675  {
2676  /* Parse error; remember there's trouble */
2677  ok = false;
2678 
2679  /*
2680  * Keep parsing the rest of the file so we can report errors on
2681  * more than the first line. Error has already been logged, no
2682  * need for more chatter here.
2683  */
2684  continue;
2685  }
2686 
2687  new_parsed_lines = lappend(new_parsed_lines, newline);
2688  }
2689 
2690  /*
2691  * A valid HBA file must have at least one entry; else there's no way to
2692  * connect to the postmaster. But only complain about this if we didn't
2693  * already have parsing errors.
2694  */
2695  if (ok && new_parsed_lines == NIL)
2696  {
2697  ereport(LOG,
2698  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2699  errmsg("configuration file \"%s\" contains no entries",
2700  HbaFileName)));
2701  ok = false;
2702  }
2703 
2704  /* Free tokenizer memory */
2705  free_auth_file(file, 0);
2706  MemoryContextSwitchTo(oldcxt);
2707 
2708  if (!ok)
2709  {
2710  /*
2711  * File contained one or more errors, so bail out, first being careful
2712  * to clean up whatever we allocated. Most stuff will go away via
2713  * MemoryContextDelete, but we have to clean up regexes explicitly.
2714  */
2715  foreach(line, new_parsed_lines)
2716  {
2717  HbaLine *newline = (HbaLine *) lfirst(line);
2718 
2720  }
2721  MemoryContextDelete(hbacxt);
2722  return false;
2723  }
2724 
2725  /* Loaded new file successfully, replace the one we use */
2726  if (parsed_hba_lines != NIL)
2727  {
2728  foreach(line, parsed_hba_lines)
2729  {
2730  HbaLine *newline = (HbaLine *) lfirst(line);
2731 
2733  }
2734  }
2735  if (parsed_hba_context != NULL)
2737  parsed_hba_context = hbacxt;
2738  parsed_hba_lines = new_parsed_lines;
2739 
2740  return true;
2741 }
char * HbaFileName
Definition: guc_tables.c:504
FILE * open_auth_file(const char *filename, int elevel, int depth, char **err_msg)
Definition: hba.c:643
static void free_hba_line(HbaLine *line)
Definition: hba.c:316
static MemoryContext parsed_hba_context
Definition: hba.c:91
void free_auth_file(FILE *file, int depth)
Definition: hba.c:618
HbaLine * parse_hba_line(TokenizedAuthLine *tok_line, int elevel)
Definition: hba.c:1364
void tokenize_auth_file(const char *filename, FILE *file, List **tok_lines, int elevel, int depth)
Definition: hba.c:734
Assert(fmt[strlen(fmt) - 1] !='\n')
List * lappend(List *list, void *datum)
Definition: list.c:338
MemoryContext PostmasterContext
Definition: mcxt.c:132
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:163
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:135
#define NIL
Definition: pg_list.h:66
static chr newline(void)
Definition: regc_lex.c:1002
Definition: pg_list.h:52
char * err_msg
Definition: hba.h:164

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate, Assert(), ereport, TokenizedAuthLine::err_msg, errcode(), errmsg(), free_auth_file(), free_hba_line(), HbaFileName, lappend(), lfirst, LOG, MemoryContextDelete(), MemoryContextSwitchTo(), newline(), NIL, open_auth_file(), 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 3001 of file hba.c.

3002 {
3003  FILE *file;
3004  List *ident_lines = NIL;
3005  ListCell *line_cell,
3006  *parsed_line_cell;
3007  List *new_parsed_lines = NIL;
3008  bool ok = true;
3009  MemoryContext oldcxt;
3010  MemoryContext ident_context;
3011  IdentLine *newline;
3012 
3013  /* not FATAL ... we just won't do any special ident maps */
3014  file = open_auth_file(IdentFileName, LOG, 0, NULL);
3015  if (file == NULL)
3016  {
3017  /* error already logged */
3018  return false;
3019  }
3020 
3021  tokenize_auth_file(IdentFileName, file, &ident_lines, LOG, 0);
3022 
3023  /* Now parse all the lines */
3025  ident_context = AllocSetContextCreate(PostmasterContext,
3026  "ident parser context",
3028  oldcxt = MemoryContextSwitchTo(ident_context);
3029  foreach(line_cell, ident_lines)
3030  {
3031  TokenizedAuthLine *tok_line = (TokenizedAuthLine *) lfirst(line_cell);
3032 
3033  /* don't parse lines that already have errors */
3034  if (tok_line->err_msg != NULL)
3035  {
3036  ok = false;
3037  continue;
3038  }
3039 
3040  if ((newline = parse_ident_line(tok_line, LOG)) == NULL)
3041  {
3042  /* Parse error; remember there's trouble */
3043  ok = false;
3044 
3045  /*
3046  * Keep parsing the rest of the file so we can report errors on
3047  * more than the first line. Error has already been logged, no
3048  * need for more chatter here.
3049  */
3050  continue;
3051  }
3052 
3053  new_parsed_lines = lappend(new_parsed_lines, newline);
3054  }
3055 
3056  /* Free tokenizer memory */
3057  free_auth_file(file, 0);
3058  MemoryContextSwitchTo(oldcxt);
3059 
3060  if (!ok)
3061  {
3062  /*
3063  * File contained one or more errors, so bail out, first being careful
3064  * to clean up whatever we allocated. Most stuff will go away via
3065  * MemoryContextDelete, but we have to clean up regexes explicitly.
3066  */
3067  foreach(parsed_line_cell, new_parsed_lines)
3068  {
3069  newline = (IdentLine *) lfirst(parsed_line_cell);
3070  free_auth_token(newline->token);
3071  }
3072  MemoryContextDelete(ident_context);
3073  return false;
3074  }
3075 
3076  /* Loaded new file successfully, replace the one we use */
3077  if (parsed_ident_lines != NIL)
3078  {
3079  foreach(parsed_line_cell, parsed_ident_lines)
3080  {
3081  newline = (IdentLine *) lfirst(parsed_line_cell);
3082  free_auth_token(newline->token);
3083  }
3084  }
3085  if (parsed_ident_context != NULL)
3087 
3088  parsed_ident_context = ident_context;
3089  parsed_ident_lines = new_parsed_lines;
3090 
3091  return true;
3092 }
char * IdentFileName
Definition: guc_tables.c:505
IdentLine * parse_ident_line(TokenizedAuthLine *tok_line, int elevel)
Definition: hba.c:2759
static MemoryContext parsed_ident_context
Definition: hba.c:103
Definition: hba.h:141

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate, Assert(), TokenizedAuthLine::err_msg, free_auth_file(), free_auth_token(), IdentFileName, lappend(), lfirst, LOG, MemoryContextDelete(), MemoryContextSwitchTo(), newline(), NIL, open_auth_file(), parse_ident_line(), parsed_ident_context, parsed_ident_lines, 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 284 of file hba.c.

285 {
286  AuthToken *authtoken;
287  int toklen;
288 
289  toklen = strlen(token);
290  /* we copy string into same palloc block as the struct */
291  authtoken = (AuthToken *) palloc0(sizeof(AuthToken) + toklen + 1);
292  authtoken->string = (char *) authtoken + sizeof(AuthToken);
293  authtoken->quoted = quoted;
294  authtoken->regex = NULL;
295  memcpy(authtoken->string, token, toklen + 1);
296 
297  return authtoken;
298 }

References palloc0(), AuthToken::quoted, AuthToken::regex, 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,
int  depth,
char **  err_msg 
)
static

Definition at line 430 of file hba.c.

432 {
433  char buf[MAX_TOKEN];
434  bool trailing_comma;
435  bool initial_quote;
436  List *tokens = NIL;
437 
438  do
439  {
440  if (!next_token(lineptr, buf, sizeof(buf),
441  &initial_quote, &trailing_comma,
442  elevel, err_msg))
443  break;
444 
445  /* Is this referencing a file? */
446  if (!initial_quote && buf[0] == '@' && buf[1] != '\0')
447  tokens = tokenize_expand_file(tokens, filename, buf + 1,
448  elevel, depth + 1, err_msg);
449  else
450  {
451  MemoryContext oldcxt;
452 
453  /*
454  * lappend() may do its own allocations, so move to the context
455  * for the list of tokens.
456  */
458  tokens = lappend(tokens, make_auth_token(buf, initial_quote));
459  MemoryContextSwitchTo(oldcxt);
460  }
461  } while (trailing_comma && (*err_msg == NULL));
462 
463  return tokens;
464 }
static bool next_token(char **lineptr, char *buf, int bufsz, bool *initial_quote, bool *terminating_comma, int elevel, char **err_msg)
Definition: hba.c:191
#define MAX_TOKEN
Definition: hba.c:59
static List * tokenize_expand_file(List *tokens, const char *outer_filename, const char *inc_filename, int elevel, int depth, char **err_msg)
Definition: hba.c:541
static char * filename
Definition: pg_dumpall.c:119
static char * buf
Definition: pg_test_fsync.c:67

References buf, filename, lappend(), make_auth_token(), MAX_TOKEN, MemoryContextSwitchTo(), next_token(), NIL, tokenize_context, and tokenize_expand_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 191 of file hba.c.

194 {
195  int c;
196  char *start_buf = buf;
197  char *end_buf = buf + (bufsz - 1);
198  bool in_quote = false;
199  bool was_quote = false;
200  bool saw_quote = false;
201 
202  Assert(end_buf > start_buf);
203 
204  *initial_quote = false;
205  *terminating_comma = false;
206 
207  /* Move over any whitespace and commas preceding the next token */
208  while ((c = (*(*lineptr)++)) != '\0' && (pg_isblank(c) || c == ','))
209  ;
210 
211  /*
212  * Build a token in buf of next characters up to EOL, unquoted comma, or
213  * unquoted whitespace.
214  */
215  while (c != '\0' &&
216  (!pg_isblank(c) || in_quote))
217  {
218  /* skip comments to EOL */
219  if (c == '#' && !in_quote)
220  {
221  while ((c = (*(*lineptr)++)) != '\0')
222  ;
223  break;
224  }
225 
226  if (buf >= end_buf)
227  {
228  *buf = '\0';
229  ereport(elevel,
230  (errcode(ERRCODE_CONFIG_FILE_ERROR),
231  errmsg("authentication file token too long, skipping: \"%s\"",
232  start_buf)));
233  *err_msg = "authentication file token too long";
234  /* Discard remainder of line */
235  while ((c = (*(*lineptr)++)) != '\0')
236  ;
237  /* Un-eat the '\0', in case we're called again */
238  (*lineptr)--;
239  return false;
240  }
241 
242  /* we do not pass back a terminating comma in the token */
243  if (c == ',' && !in_quote)
244  {
245  *terminating_comma = true;
246  break;
247  }
248 
249  if (c != '"' || was_quote)
250  *buf++ = c;
251 
252  /* Literal double-quote is two double-quotes */
253  if (in_quote && c == '"')
254  was_quote = !was_quote;
255  else
256  was_quote = false;
257 
258  if (c == '"')
259  {
260  in_quote = !in_quote;
261  saw_quote = true;
262  if (buf == start_buf)
263  *initial_quote = true;
264  }
265 
266  c = *(*lineptr)++;
267  }
268 
269  /*
270  * Un-eat the char right after the token (critical in case it is '\0',
271  * else next call will read past end of string).
272  */
273  (*lineptr)--;
274 
275  *buf = '\0';
276 
277  return (saw_quote || buf > start_buf);
278 }
bool pg_isblank(const char c)
Definition: hba.c:148
char * c

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

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

◆ open_auth_file()

FILE* open_auth_file ( const char *  filename,
int  elevel,
int  depth,
char **  err_msg 
)

Definition at line 643 of file hba.c.

645 {
646  FILE *file;
647 
648  /*
649  * Reject too-deep include nesting depth. This is just a safety check to
650  * avoid dumping core due to stack overflow if an include file loops back
651  * to itself. The maximum nesting depth is pretty arbitrary.
652  */
653  if (depth > CONF_FILE_MAX_DEPTH)
654  {
655  ereport(elevel,
657  errmsg("could not open file \"%s\": maximum nesting depth exceeded",
658  filename)));
659  if (err_msg)
660  *err_msg = psprintf("could not open file \"%s\": maximum nesting depth exceeded",
661  filename);
662  return NULL;
663  }
664 
665  file = AllocateFile(filename, "r");
666  if (file == NULL)
667  {
668  int save_errno = errno;
669 
670  ereport(elevel,
672  errmsg("could not open file \"%s\": %m",
673  filename)));
674  if (err_msg)
675  *err_msg = psprintf("could not open file \"%s\": %s",
676  filename, strerror(save_errno));
677  /* the caller may care about some specific errno */
678  errno = save_errno;
679  return NULL;
680  }
681 
682  /*
683  * When opening the top-level file, create the memory context used for the
684  * tokenization. This will be closed with this file when coming back to
685  * this level of cleanup.
686  */
687  if (depth == CONF_FILE_START_DEPTH)
688  {
689  /*
690  * A context may be present, but assume that it has been eliminated
691  * already.
692  */
694  "tokenize_context",
696  }
697 
698  return file;
699 }
#define CONF_FILE_MAX_DEPTH
Definition: conffiles.h:18
int errcode_for_file_access(void)
Definition: elog.c:758
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2383
MemoryContext CurrentMemoryContext
Definition: mcxt.c:124
#define ALLOCSET_START_SMALL_SIZES
Definition: memutils.h:170
#define strerror
Definition: port.h:251

References AllocateFile(), ALLOCSET_START_SMALL_SIZES, AllocSetContextCreate, CONF_FILE_MAX_DEPTH, CONF_FILE_START_DEPTH, CurrentMemoryContext, ereport, errcode_for_file_access(), errmsg(), filename, psprintf(), strerror, and tokenize_context.

Referenced by fill_hba_view(), fill_ident_view(), load_hba(), load_ident(), tokenize_expand_file(), and tokenize_include_file().

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

2105 {
2106  int line_num = hbaline->linenumber;
2107  char *file_name = hbaline->sourcefile;
2108 
2109 #ifdef USE_LDAP
2110  hbaline->ldapscope = LDAP_SCOPE_SUBTREE;
2111 #endif
2112 
2113  if (strcmp(name, "map") == 0)
2114  {
2115  if (hbaline->auth_method != uaIdent &&
2116  hbaline->auth_method != uaPeer &&
2117  hbaline->auth_method != uaGSS &&
2118  hbaline->auth_method != uaSSPI &&
2119  hbaline->auth_method != uaCert)
2120  INVALID_AUTH_OPTION("map", gettext_noop("ident, peer, gssapi, sspi, and cert"));
2121  hbaline->usermap = pstrdup(val);
2122  }
2123  else if (strcmp(name, "clientcert") == 0)
2124  {
2125  if (hbaline->conntype != ctHostSSL)
2126  {
2127  ereport(elevel,
2128  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2129  errmsg("clientcert can only be configured for \"hostssl\" rows"),
2130  errcontext("line %d of configuration file \"%s\"",
2131  line_num, file_name)));
2132  *err_msg = "clientcert can only be configured for \"hostssl\" rows";
2133  return false;
2134  }
2135 
2136  if (strcmp(val, "verify-full") == 0)
2137  {
2138  hbaline->clientcert = clientCertFull;
2139  }
2140  else if (strcmp(val, "verify-ca") == 0)
2141  {
2142  if (hbaline->auth_method == uaCert)
2143  {
2144  ereport(elevel,
2145  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2146  errmsg("clientcert only accepts \"verify-full\" when using \"cert\" authentication"),
2147  errcontext("line %d of configuration file \"%s\"",
2148  line_num, file_name)));
2149  *err_msg = "clientcert can only be set to \"verify-full\" when using \"cert\" authentication";
2150  return false;
2151  }
2152 
2153  hbaline->clientcert = clientCertCA;
2154  }
2155  else
2156  {
2157  ereport(elevel,
2158  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2159  errmsg("invalid value for clientcert: \"%s\"", val),
2160  errcontext("line %d of configuration file \"%s\"",
2161  line_num, file_name)));
2162  return false;
2163  }
2164  }
2165  else if (strcmp(name, "clientname") == 0)
2166  {
2167  if (hbaline->conntype != ctHostSSL)
2168  {
2169  ereport(elevel,
2170  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2171  errmsg("clientname can only be configured for \"hostssl\" rows"),
2172  errcontext("line %d of configuration file \"%s\"",
2173  line_num, file_name)));
2174  *err_msg = "clientname can only be configured for \"hostssl\" rows";
2175  return false;
2176  }
2177 
2178  if (strcmp(val, "CN") == 0)
2179  {
2180  hbaline->clientcertname = clientCertCN;
2181  }
2182  else if (strcmp(val, "DN") == 0)
2183  {
2184  hbaline->clientcertname = clientCertDN;
2185  }
2186  else
2187  {
2188  ereport(elevel,
2189  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2190  errmsg("invalid value for clientname: \"%s\"", val),
2191  errcontext("line %d of configuration file \"%s\"",
2192  line_num, file_name)));
2193  return false;
2194  }
2195  }
2196  else if (strcmp(name, "pamservice") == 0)
2197  {
2198  REQUIRE_AUTH_OPTION(uaPAM, "pamservice", "pam");
2199  hbaline->pamservice = pstrdup(val);
2200  }
2201  else if (strcmp(name, "pam_use_hostname") == 0)
2202  {
2203  REQUIRE_AUTH_OPTION(uaPAM, "pam_use_hostname", "pam");
2204  if (strcmp(val, "1") == 0)
2205  hbaline->pam_use_hostname = true;
2206  else
2207  hbaline->pam_use_hostname = false;
2208  }
2209  else if (strcmp(name, "ldapurl") == 0)
2210  {
2211 #ifdef LDAP_API_FEATURE_X_OPENLDAP
2212  LDAPURLDesc *urldata;
2213  int rc;
2214 #endif
2215 
2216  REQUIRE_AUTH_OPTION(uaLDAP, "ldapurl", "ldap");
2217 #ifdef LDAP_API_FEATURE_X_OPENLDAP
2218  rc = ldap_url_parse(val, &urldata);
2219  if (rc != LDAP_SUCCESS)
2220  {
2221  ereport(elevel,
2222  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2223  errmsg("could not parse LDAP URL \"%s\": %s", val, ldap_err2string(rc))));
2224  *err_msg = psprintf("could not parse LDAP URL \"%s\": %s",
2225  val, ldap_err2string(rc));
2226  return false;
2227  }
2228 
2229  if (strcmp(urldata->lud_scheme, "ldap") != 0 &&
2230  strcmp(urldata->lud_scheme, "ldaps") != 0)
2231  {
2232  ereport(elevel,
2233  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2234  errmsg("unsupported LDAP URL scheme: %s", urldata->lud_scheme)));
2235  *err_msg = psprintf("unsupported LDAP URL scheme: %s",
2236  urldata->lud_scheme);
2237  ldap_free_urldesc(urldata);
2238  return false;
2239  }
2240 
2241  if (urldata->lud_scheme)
2242  hbaline->ldapscheme = pstrdup(urldata->lud_scheme);
2243  if (urldata->lud_host)
2244  hbaline->ldapserver = pstrdup(urldata->lud_host);
2245  hbaline->ldapport = urldata->lud_port;
2246  if (urldata->lud_dn)
2247  hbaline->ldapbasedn = pstrdup(urldata->lud_dn);
2248 
2249  if (urldata->lud_attrs)
2250  hbaline->ldapsearchattribute = pstrdup(urldata->lud_attrs[0]); /* only use first one */
2251  hbaline->ldapscope = urldata->lud_scope;
2252  if (urldata->lud_filter)
2253  hbaline->ldapsearchfilter = pstrdup(urldata->lud_filter);
2254  ldap_free_urldesc(urldata);
2255 #else /* not OpenLDAP */
2256  ereport(elevel,
2257  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2258  errmsg("LDAP URLs not supported on this platform")));
2259  *err_msg = "LDAP URLs not supported on this platform";
2260 #endif /* not OpenLDAP */
2261  }
2262  else if (strcmp(name, "ldaptls") == 0)
2263  {
2264  REQUIRE_AUTH_OPTION(uaLDAP, "ldaptls", "ldap");
2265  if (strcmp(val, "1") == 0)
2266  hbaline->ldaptls = true;
2267  else
2268  hbaline->ldaptls = false;
2269  }
2270  else if (strcmp(name, "ldapscheme") == 0)
2271  {
2272  REQUIRE_AUTH_OPTION(uaLDAP, "ldapscheme", "ldap");
2273  if (strcmp(val, "ldap") != 0 && strcmp(val, "ldaps") != 0)
2274  ereport(elevel,
2275  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2276  errmsg("invalid ldapscheme value: \"%s\"", val),
2277  errcontext("line %d of configuration file \"%s\"",
2278  line_num, file_name)));
2279  hbaline->ldapscheme = pstrdup(val);
2280  }
2281  else if (strcmp(name, "ldapserver") == 0)
2282  {
2283  REQUIRE_AUTH_OPTION(uaLDAP, "ldapserver", "ldap");
2284  hbaline->ldapserver = pstrdup(val);
2285  }
2286  else if (strcmp(name, "ldapport") == 0)
2287  {
2288  REQUIRE_AUTH_OPTION(uaLDAP, "ldapport", "ldap");
2289  hbaline->ldapport = atoi(val);
2290  if (hbaline->ldapport == 0)
2291  {
2292  ereport(elevel,
2293  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2294  errmsg("invalid LDAP port number: \"%s\"", val),
2295  errcontext("line %d of configuration file \"%s\"",
2296  line_num, file_name)));
2297  *err_msg = psprintf("invalid LDAP port number: \"%s\"", val);
2298  return false;
2299  }
2300  }
2301  else if (strcmp(name, "ldapbinddn") == 0)
2302  {
2303  REQUIRE_AUTH_OPTION(uaLDAP, "ldapbinddn", "ldap");
2304  hbaline->ldapbinddn = pstrdup(val);
2305  }
2306  else if (strcmp(name, "ldapbindpasswd") == 0)
2307  {
2308  REQUIRE_AUTH_OPTION(uaLDAP, "ldapbindpasswd", "ldap");
2309  hbaline->ldapbindpasswd = pstrdup(val);
2310  }
2311  else if (strcmp(name, "ldapsearchattribute") == 0)
2312  {
2313  REQUIRE_AUTH_OPTION(uaLDAP, "ldapsearchattribute", "ldap");
2314  hbaline->ldapsearchattribute = pstrdup(val);
2315  }
2316  else if (strcmp(name, "ldapsearchfilter") == 0)
2317  {
2318  REQUIRE_AUTH_OPTION(uaLDAP, "ldapsearchfilter", "ldap");
2319  hbaline->ldapsearchfilter = pstrdup(val);
2320  }
2321  else if (strcmp(name, "ldapbasedn") == 0)
2322  {
2323  REQUIRE_AUTH_OPTION(uaLDAP, "ldapbasedn", "ldap");
2324  hbaline->ldapbasedn = pstrdup(val);
2325  }
2326  else if (strcmp(name, "ldapprefix") == 0)
2327  {
2328  REQUIRE_AUTH_OPTION(uaLDAP, "ldapprefix", "ldap");
2329  hbaline->ldapprefix = pstrdup(val);
2330  }
2331  else if (strcmp(name, "ldapsuffix") == 0)
2332  {
2333  REQUIRE_AUTH_OPTION(uaLDAP, "ldapsuffix", "ldap");
2334  hbaline->ldapsuffix = pstrdup(val);
2335  }
2336  else if (strcmp(name, "krb_realm") == 0)
2337  {
2338  if (hbaline->auth_method != uaGSS &&
2339  hbaline->auth_method != uaSSPI)
2340  INVALID_AUTH_OPTION("krb_realm", gettext_noop("gssapi and sspi"));
2341  hbaline->krb_realm = pstrdup(val);
2342  }
2343  else if (strcmp(name, "include_realm") == 0)
2344  {
2345  if (hbaline->auth_method != uaGSS &&
2346  hbaline->auth_method != uaSSPI)
2347  INVALID_AUTH_OPTION("include_realm", gettext_noop("gssapi and sspi"));
2348  if (strcmp(val, "1") == 0)
2349  hbaline->include_realm = true;
2350  else
2351  hbaline->include_realm = false;
2352  }
2353  else if (strcmp(name, "compat_realm") == 0)
2354  {
2355  if (hbaline->auth_method != uaSSPI)
2356  INVALID_AUTH_OPTION("compat_realm", gettext_noop("sspi"));
2357  if (strcmp(val, "1") == 0)
2358  hbaline->compat_realm = true;
2359  else
2360  hbaline->compat_realm = false;
2361  }
2362  else if (strcmp(name, "upn_username") == 0)
2363  {
2364  if (hbaline->auth_method != uaSSPI)
2365  INVALID_AUTH_OPTION("upn_username", gettext_noop("sspi"));
2366  if (strcmp(val, "1") == 0)
2367  hbaline->upn_username = true;
2368  else
2369  hbaline->upn_username = false;
2370  }
2371  else if (strcmp(name, "radiusservers") == 0)
2372  {
2373  struct addrinfo *gai_result;
2374  struct addrinfo hints;
2375  int ret;
2376  List *parsed_servers;
2377  ListCell *l;
2378  char *dupval = pstrdup(val);
2379 
2380  REQUIRE_AUTH_OPTION(uaRADIUS, "radiusservers", "radius");
2381 
2382  if (!SplitGUCList(dupval, ',', &parsed_servers))
2383  {
2384  /* syntax error in list */
2385  ereport(elevel,
2386  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2387  errmsg("could not parse RADIUS server list \"%s\"",
2388  val),
2389  errcontext("line %d of configuration file \"%s\"",
2390  line_num, file_name)));
2391  return false;
2392  }
2393 
2394  /* For each entry in the list, translate it */
2395  foreach(l, parsed_servers)
2396  {
2397  MemSet(&hints, 0, sizeof(hints));
2398  hints.ai_socktype = SOCK_DGRAM;
2399  hints.ai_family = AF_UNSPEC;
2400 
2401  ret = pg_getaddrinfo_all((char *) lfirst(l), NULL, &hints, &gai_result);
2402  if (ret || !gai_result)
2403  {
2404  ereport(elevel,
2405  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2406  errmsg("could not translate RADIUS server name \"%s\" to address: %s",
2407  (char *) lfirst(l), gai_strerror(ret)),
2408  errcontext("line %d of configuration file \"%s\"",
2409  line_num, file_name)));
2410  if (gai_result)
2411  pg_freeaddrinfo_all(hints.ai_family, gai_result);
2412 
2413  list_free(parsed_servers);
2414  return false;
2415  }
2416  pg_freeaddrinfo_all(hints.ai_family, gai_result);
2417  }
2418 
2419  /* All entries are OK, so store them */
2420  hbaline->radiusservers = parsed_servers;
2421  hbaline->radiusservers_s = pstrdup(val);
2422  }
2423  else if (strcmp(name, "radiusports") == 0)
2424  {
2425  List *parsed_ports;
2426  ListCell *l;
2427  char *dupval = pstrdup(val);
2428 
2429  REQUIRE_AUTH_OPTION(uaRADIUS, "radiusports", "radius");
2430 
2431  if (!SplitGUCList(dupval, ',', &parsed_ports))
2432  {
2433  ereport(elevel,
2434  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2435  errmsg("could not parse RADIUS port list \"%s\"",
2436  val),
2437  errcontext("line %d of configuration file \"%s\"",
2438  line_num, file_name)));
2439  *err_msg = psprintf("invalid RADIUS port number: \"%s\"", val);
2440  return false;
2441  }
2442 
2443  foreach(l, parsed_ports)
2444  {
2445  if (atoi(lfirst(l)) == 0)
2446  {
2447  ereport(elevel,
2448  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2449  errmsg("invalid RADIUS port number: \"%s\"", val),
2450  errcontext("line %d of configuration file \"%s\"",
2451  line_num, file_name)));
2452 
2453  return false;
2454  }
2455  }
2456  hbaline->radiusports = parsed_ports;
2457  hbaline->radiusports_s = pstrdup(val);
2458  }
2459  else if (strcmp(name, "radiussecrets") == 0)
2460  {
2461  List *parsed_secrets;
2462  char *dupval = pstrdup(val);
2463 
2464  REQUIRE_AUTH_OPTION(uaRADIUS, "radiussecrets", "radius");
2465 
2466  if (!SplitGUCList(dupval, ',', &parsed_secrets))
2467  {
2468  /* syntax error in list */
2469  ereport(elevel,
2470  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2471  errmsg("could not parse RADIUS secret list \"%s\"",
2472  val),
2473  errcontext("line %d of configuration file \"%s\"",
2474  line_num, file_name)));
2475  return false;
2476  }
2477 
2478  hbaline->radiussecrets = parsed_secrets;
2479  hbaline->radiussecrets_s = pstrdup(val);
2480  }
2481  else if (strcmp(name, "radiusidentifiers") == 0)
2482  {
2483  List *parsed_identifiers;
2484  char *dupval = pstrdup(val);
2485 
2486  REQUIRE_AUTH_OPTION(uaRADIUS, "radiusidentifiers", "radius");
2487 
2488  if (!SplitGUCList(dupval, ',', &parsed_identifiers))
2489  {
2490  /* syntax error in list */
2491  ereport(elevel,
2492  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2493  errmsg("could not parse RADIUS identifiers list \"%s\"",
2494  val),
2495  errcontext("line %d of configuration file \"%s\"",
2496  line_num, file_name)));
2497  return false;
2498  }
2499 
2500  hbaline->radiusidentifiers = parsed_identifiers;
2501  hbaline->radiusidentifiers_s = pstrdup(val);
2502  }
2503  else
2504  {
2505  ereport(elevel,
2506  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2507  errmsg("unrecognized authentication option name: \"%s\"",
2508  name),
2509  errcontext("line %d of configuration file \"%s\"",
2510  line_num, file_name)));
2511  *err_msg = psprintf("unrecognized authentication option name: \"%s\"",
2512  name);
2513  return false;
2514  }
2515  return true;
2516 }
#define gettext_noop(x)
Definition: c.h:1135
#define MemSet(start, val, len)
Definition: c.h:953
const char * name
Definition: encode.c:561
#define INVALID_AUTH_OPTION(optname, validmethods)
Definition: hba.c:1280
#define REQUIRE_AUTH_OPTION(methodval, optname, validmethods)
Definition: hba.c:1294
@ 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:82
int pg_getaddrinfo_all(const char *hostname, const char *servname, const struct addrinfo *hintp, struct addrinfo **result)
Definition: ip.c:53
void list_free(List *list)
Definition: list.c:1545
bool upn_username
Definition: hba.h:129
char * sourcefile
Definition: hba.h:96
ClientCertName clientcertname
Definition: hba.h:125
List * radiusservers
Definition: hba.h:130
char * ldapserver
Definition: hba.h:114
bool include_realm
Definition: hba.h:127
ClientCertMode clientcert
Definition: hba.h:124
char * ldapsearchfilter
Definition: hba.h:119
char * ldapscheme
Definition: hba.h:113
char * ldapprefix
Definition: hba.h:122
List * radiussecrets
Definition: hba.h:132
char * ldapsearchattribute
Definition: hba.h:118
char * krb_realm
Definition: hba.h:126
char * ldapbasedn
Definition: hba.h:120
bool pam_use_hostname
Definition: hba.h:111
int linenumber
Definition: hba.h:97
char * radiussecrets_s
Definition: hba.h:133
List * radiusports
Definition: hba.h:136
List * radiusidentifiers
Definition: hba.h:134
char * pamservice
Definition: hba.h:110
char * usermap
Definition: hba.h:109
char * ldapsuffix
Definition: hba.h:123
int ldapport
Definition: hba.h:115
char * ldapbindpasswd
Definition: hba.h:117
char * radiusports_s
Definition: hba.h:137
char * ldapbinddn
Definition: hba.h:116
bool compat_realm
Definition: hba.h:128
int ldapscope
Definition: hba.h:121
bool ldaptls
Definition: hba.h:112
char * radiusservers_s
Definition: hba.h:131
char * radiusidentifiers_s
Definition: hba.h:135
bool SplitGUCList(char *rawstring, char separator, List **namelist)
Definition: varlena.c:3960

References HbaLine::auth_method, HbaLine::clientcert, clientCertCA, clientCertCN, clientCertDN, clientCertFull, HbaLine::clientcertname, HbaLine::compat_realm, HbaLine::conntype, ctHostSSL, ereport, errcode(), errcontext, errmsg(), gettext_noop, 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, HbaLine::sourcefile, 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 1364 of file hba.c.

1365 {
1366  int line_num = tok_line->line_num;
1367  char *file_name = tok_line->file_name;
1368  char **err_msg = &tok_line->err_msg;
1369  char *str;
1370  struct addrinfo *gai_result;
1371  struct addrinfo hints;
1372  int ret;
1373  char *cidr_slash;
1374  char *unsupauth;
1375  ListCell *field;
1376  List *tokens;
1377  ListCell *tokencell;
1378  AuthToken *token;
1379  HbaLine *parsedline;
1380 
1381  parsedline = palloc0(sizeof(HbaLine));
1382  parsedline->sourcefile = pstrdup(file_name);
1383  parsedline->linenumber = line_num;
1384  parsedline->rawline = pstrdup(tok_line->raw_line);
1385 
1386  /* Check the record type. */
1387  Assert(tok_line->fields != NIL);
1388  field = list_head(tok_line->fields);
1389  tokens = lfirst(field);
1390  if (tokens->length > 1)
1391  {
1392  ereport(elevel,
1393  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1394  errmsg("multiple values specified for connection type"),
1395  errhint("Specify exactly one connection type per line."),
1396  errcontext("line %d of configuration file \"%s\"",
1397  line_num, file_name)));
1398  *err_msg = "multiple values specified for connection type";
1399  return NULL;
1400  }
1401  token = linitial(tokens);
1402  if (strcmp(token->string, "local") == 0)
1403  {
1404  parsedline->conntype = ctLocal;
1405  }
1406  else if (strcmp(token->string, "host") == 0 ||
1407  strcmp(token->string, "hostssl") == 0 ||
1408  strcmp(token->string, "hostnossl") == 0 ||
1409  strcmp(token->string, "hostgssenc") == 0 ||
1410  strcmp(token->string, "hostnogssenc") == 0)
1411  {
1412 
1413  if (token->string[4] == 's') /* "hostssl" */
1414  {
1415  parsedline->conntype = ctHostSSL;
1416  /* Log a warning if SSL support is not active */
1417 #ifdef USE_SSL
1418  if (!EnableSSL)
1419  {
1420  ereport(elevel,
1421  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1422  errmsg("hostssl record cannot match because SSL is disabled"),
1423  errhint("Set ssl = on in postgresql.conf."),
1424  errcontext("line %d of configuration file \"%s\"",
1425  line_num, file_name)));
1426  *err_msg = "hostssl record cannot match because SSL is disabled";
1427  }
1428 #else
1429  ereport(elevel,
1430  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1431  errmsg("hostssl record cannot match because SSL is not supported by this build"),
1432  errcontext("line %d of configuration file \"%s\"",
1433  line_num, file_name)));
1434  *err_msg = "hostssl record cannot match because SSL is not supported by this build";
1435 #endif
1436  }
1437  else if (token->string[4] == 'g') /* "hostgssenc" */
1438  {
1439  parsedline->conntype = ctHostGSS;
1440 #ifndef ENABLE_GSS
1441  ereport(elevel,
1442  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1443  errmsg("hostgssenc record cannot match because GSSAPI is not supported by this build"),
1444  errcontext("line %d of configuration file \"%s\"",
1445  line_num, file_name)));
1446  *err_msg = "hostgssenc record cannot match because GSSAPI is not supported by this build";
1447 #endif
1448  }
1449  else if (token->string[4] == 'n' && token->string[6] == 's')
1450  parsedline->conntype = ctHostNoSSL;
1451  else if (token->string[4] == 'n' && token->string[6] == 'g')
1452  parsedline->conntype = ctHostNoGSS;
1453  else
1454  {
1455  /* "host" */
1456  parsedline->conntype = ctHost;
1457  }
1458  } /* record type */
1459  else
1460  {
1461  ereport(elevel,
1462  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1463  errmsg("invalid connection type \"%s\"",
1464  token->string),
1465  errcontext("line %d of configuration file \"%s\"",
1466  line_num, file_name)));
1467  *err_msg = psprintf("invalid connection type \"%s\"", token->string);
1468  return NULL;
1469  }
1470 
1471  /* Get the databases. */
1472  field = lnext(tok_line->fields, field);
1473  if (!field)
1474  {
1475  ereport(elevel,
1476  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1477  errmsg("end-of-line before database specification"),
1478  errcontext("line %d of configuration file \"%s\"",
1479  line_num, file_name)));
1480  *err_msg = "end-of-line before database specification";
1481  return NULL;
1482  }
1483  parsedline->databases = NIL;
1484  tokens = lfirst(field);
1485  foreach(tokencell, tokens)
1486  {
1487  AuthToken *tok = copy_auth_token(lfirst(tokencell));
1488 
1489  /* Compile a regexp for the database token, if necessary */
1490  if (regcomp_auth_token(tok, file_name, line_num, err_msg, elevel))
1491  return NULL;
1492 
1493  parsedline->databases = lappend(parsedline->databases, tok);
1494  }
1495 
1496  /* Get the roles. */
1497  field = lnext(tok_line->fields, field);
1498  if (!field)
1499  {
1500  ereport(elevel,
1501  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1502  errmsg("end-of-line before role specification"),
1503  errcontext("line %d of configuration file \"%s\"",
1504  line_num, file_name)));
1505  *err_msg = "end-of-line before role specification";
1506  return NULL;
1507  }
1508  parsedline->roles = NIL;
1509  tokens = lfirst(field);
1510  foreach(tokencell, tokens)
1511  {
1512  AuthToken *tok = copy_auth_token(lfirst(tokencell));
1513 
1514  /* Compile a regexp from the role token, if necessary */
1515  if (regcomp_auth_token(tok, file_name, line_num, err_msg, elevel))
1516  return NULL;
1517 
1518  parsedline->roles = lappend(parsedline->roles, tok);
1519  }
1520 
1521  if (parsedline->conntype != ctLocal)
1522  {
1523  /* Read the IP address field. (with or without CIDR netmask) */
1524  field = lnext(tok_line->fields, field);
1525  if (!field)
1526  {
1527  ereport(elevel,
1528  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1529  errmsg("end-of-line before IP address specification"),
1530  errcontext("line %d of configuration file \"%s\"",
1531  line_num, file_name)));
1532  *err_msg = "end-of-line before IP address specification";
1533  return NULL;
1534  }
1535  tokens = lfirst(field);
1536  if (tokens->length > 1)
1537  {
1538  ereport(elevel,
1539  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1540  errmsg("multiple values specified for host address"),
1541  errhint("Specify one address range per line."),
1542  errcontext("line %d of configuration file \"%s\"",
1543  line_num, file_name)));
1544  *err_msg = "multiple values specified for host address";
1545  return NULL;
1546  }
1547  token = linitial(tokens);
1548 
1549  if (token_is_keyword(token, "all"))
1550  {
1551  parsedline->ip_cmp_method = ipCmpAll;
1552  }
1553  else if (token_is_keyword(token, "samehost"))
1554  {
1555  /* Any IP on this host is allowed to connect */
1556  parsedline->ip_cmp_method = ipCmpSameHost;
1557  }
1558  else if (token_is_keyword(token, "samenet"))
1559  {
1560  /* Any IP on the host's subnets is allowed to connect */
1561  parsedline->ip_cmp_method = ipCmpSameNet;
1562  }
1563  else
1564  {
1565  /* IP and netmask are specified */
1566  parsedline->ip_cmp_method = ipCmpMask;
1567 
1568  /* need a modifiable copy of token */
1569  str = pstrdup(token->string);
1570 
1571  /* Check if it has a CIDR suffix and if so isolate it */
1572  cidr_slash = strchr(str, '/');
1573  if (cidr_slash)
1574  *cidr_slash = '\0';
1575 
1576  /* Get the IP address either way */
1577  hints.ai_flags = AI_NUMERICHOST;
1578  hints.ai_family = AF_UNSPEC;
1579  hints.ai_socktype = 0;
1580  hints.ai_protocol = 0;
1581  hints.ai_addrlen = 0;
1582  hints.ai_canonname = NULL;
1583  hints.ai_addr = NULL;
1584  hints.ai_next = NULL;
1585 
1586  ret = pg_getaddrinfo_all(str, NULL, &hints, &gai_result);
1587  if (ret == 0 && gai_result)
1588  {
1589  memcpy(&parsedline->addr, gai_result->ai_addr,
1590  gai_result->ai_addrlen);
1591  parsedline->addrlen = gai_result->ai_addrlen;
1592  }
1593  else if (ret == EAI_NONAME)
1594  parsedline->hostname = str;
1595  else
1596  {
1597  ereport(elevel,
1598  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1599  errmsg("invalid IP address \"%s\": %s",
1600  str, gai_strerror(ret)),
1601  errcontext("line %d of configuration file \"%s\"",
1602  line_num, file_name)));
1603  *err_msg = psprintf("invalid IP address \"%s\": %s",
1604  str, gai_strerror(ret));
1605  if (gai_result)
1606  pg_freeaddrinfo_all(hints.ai_family, gai_result);
1607  return NULL;
1608  }
1609 
1610  pg_freeaddrinfo_all(hints.ai_family, gai_result);
1611 
1612  /* Get the netmask */
1613  if (cidr_slash)
1614  {
1615  if (parsedline->hostname)
1616  {
1617  ereport(elevel,
1618  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1619  errmsg("specifying both host name and CIDR mask is invalid: \"%s\"",
1620  token->string),
1621  errcontext("line %d of configuration file \"%s\"",
1622  line_num, file_name)));
1623  *err_msg = psprintf("specifying both host name and CIDR mask is invalid: \"%s\"",
1624  token->string);
1625  return NULL;
1626  }
1627 
1628  if (pg_sockaddr_cidr_mask(&parsedline->mask, cidr_slash + 1,
1629  parsedline->addr.ss_family) < 0)
1630  {
1631  ereport(elevel,
1632  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1633  errmsg("invalid CIDR mask in address \"%s\"",
1634  token->string),
1635  errcontext("line %d of configuration file \"%s\"",
1636  line_num, file_name)));
1637  *err_msg = psprintf("invalid CIDR mask in address \"%s\"",
1638  token->string);
1639  return NULL;
1640  }
1641  parsedline->masklen = parsedline->addrlen;
1642  pfree(str);
1643  }
1644  else if (!parsedline->hostname)
1645  {
1646  /* Read the mask field. */
1647  pfree(str);
1648  field = lnext(tok_line->fields, field);
1649  if (!field)
1650  {
1651  ereport(elevel,
1652  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1653  errmsg("end-of-line before netmask specification"),
1654  errhint("Specify an address range in CIDR notation, or provide a separate netmask."),
1655  errcontext("line %d of configuration file \"%s\"",
1656  line_num, file_name)));
1657  *err_msg = "end-of-line before netmask specification";
1658  return NULL;
1659  }
1660  tokens = lfirst(field);
1661  if (tokens->length > 1)
1662  {
1663  ereport(elevel,
1664  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1665  errmsg("multiple values specified for netmask"),
1666  errcontext("line %d of configuration file \"%s\"",
1667  line_num, file_name)));
1668  *err_msg = "multiple values specified for netmask";
1669  return NULL;
1670  }
1671  token = linitial(tokens);
1672 
1673  ret = pg_getaddrinfo_all(token->string, NULL,
1674  &hints, &gai_result);
1675  if (ret || !gai_result)
1676  {
1677  ereport(elevel,
1678  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1679  errmsg("invalid IP mask \"%s\": %s",
1680  token->string, gai_strerror(ret)),
1681  errcontext("line %d of configuration file \"%s\"",
1682  line_num, file_name)));
1683  *err_msg = psprintf("invalid IP mask \"%s\": %s",
1684  token->string, gai_strerror(ret));
1685  if (gai_result)
1686  pg_freeaddrinfo_all(hints.ai_family, gai_result);
1687  return NULL;
1688  }
1689 
1690  memcpy(&parsedline->mask, gai_result->ai_addr,
1691  gai_result->ai_addrlen);
1692  parsedline->masklen = gai_result->ai_addrlen;
1693  pg_freeaddrinfo_all(hints.ai_family, gai_result);
1694 
1695  if (parsedline->addr.ss_family != parsedline->mask.ss_family)
1696  {
1697  ereport(elevel,
1698  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1699  errmsg("IP address and mask do not match"),
1700  errcontext("line %d of configuration file \"%s\"",
1701  line_num, file_name)));
1702  *err_msg = "IP address and mask do not match";
1703  return NULL;
1704  }
1705  }
1706  }
1707  } /* != ctLocal */
1708 
1709  /* Get the authentication method */
1710  field = lnext(tok_line->fields, field);
1711  if (!field)
1712  {
1713  ereport(elevel,
1714  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1715  errmsg("end-of-line before authentication method"),
1716  errcontext("line %d of configuration file \"%s\"",
1717  line_num, file_name)));
1718  *err_msg = "end-of-line before authentication method";
1719  return NULL;
1720  }
1721  tokens = lfirst(field);
1722  if (tokens->length > 1)
1723  {
1724  ereport(elevel,
1725  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1726  errmsg("multiple values specified for authentication type"),
1727  errhint("Specify exactly one authentication type per line."),
1728  errcontext("line %d of configuration file \"%s\"",
1729  line_num, file_name)));
1730  *err_msg = "multiple values specified for authentication type";
1731  return NULL;
1732  }
1733  token = linitial(tokens);
1734 
1735  unsupauth = NULL;
1736  if (strcmp(token->string, "trust") == 0)
1737  parsedline->auth_method = uaTrust;
1738  else if (strcmp(token->string, "ident") == 0)
1739  parsedline->auth_method = uaIdent;
1740  else if (strcmp(token->string, "peer") == 0)
1741  parsedline->auth_method = uaPeer;
1742  else if (strcmp(token->string, "password") == 0)
1743  parsedline->auth_method = uaPassword;
1744  else if (strcmp(token->string, "gss") == 0)
1745 #ifdef ENABLE_GSS
1746  parsedline->auth_method = uaGSS;
1747 #else
1748  unsupauth = "gss";
1749 #endif
1750  else if (strcmp(token->string, "sspi") == 0)
1751 #ifdef ENABLE_SSPI
1752  parsedline->auth_method = uaSSPI;
1753 #else
1754  unsupauth = "sspi";
1755 #endif
1756  else if (strcmp(token->string, "reject") == 0)
1757  parsedline->auth_method = uaReject;
1758  else if (strcmp(token->string, "md5") == 0)
1759  {
1760  if (Db_user_namespace)
1761  {
1762  ereport(elevel,
1763  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1764  errmsg("MD5 authentication is not supported when \"db_user_namespace\" is enabled"),
1765  errcontext("line %d of configuration file \"%s\"",
1766  line_num, file_name)));
1767  *err_msg = "MD5 authentication is not supported when \"db_user_namespace\" is enabled";
1768  return NULL;
1769  }
1770  parsedline->auth_method = uaMD5;
1771  }
1772  else if (strcmp(token->string, "scram-sha-256") == 0)
1773  parsedline->auth_method = uaSCRAM;
1774  else if (strcmp(token->string, "pam") == 0)
1775 #ifdef USE_PAM
1776  parsedline->auth_method = uaPAM;
1777 #else
1778  unsupauth = "pam";
1779 #endif
1780  else if (strcmp(token->string, "bsd") == 0)
1781 #ifdef USE_BSD_AUTH
1782  parsedline->auth_method = uaBSD;
1783 #else
1784  unsupauth = "bsd";
1785 #endif
1786  else if (strcmp(token->string, "ldap") == 0)
1787 #ifdef USE_LDAP
1788  parsedline->auth_method = uaLDAP;
1789 #else
1790  unsupauth = "ldap";
1791 #endif
1792  else if (strcmp(token->string, "cert") == 0)
1793 #ifdef USE_SSL
1794  parsedline->auth_method = uaCert;
1795 #else
1796  unsupauth = "cert";
1797 #endif
1798  else if (strcmp(token->string, "radius") == 0)
1799  parsedline->auth_method = uaRADIUS;
1800  else
1801  {
1802  ereport(elevel,
1803  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1804  errmsg("invalid authentication method \"%s\"",
1805  token->string),
1806  errcontext("line %d of configuration file \"%s\"",
1807  line_num, file_name)));
1808  *err_msg = psprintf("invalid authentication method \"%s\"",
1809  token->string);
1810  return NULL;
1811  }
1812 
1813  if (unsupauth)
1814  {
1815  ereport(elevel,
1816  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1817  errmsg("invalid authentication method \"%s\": not supported by this build",
1818  token->string),
1819  errcontext("line %d of configuration file \"%s\"",
1820  line_num, file_name)));
1821  *err_msg = psprintf("invalid authentication method \"%s\": not supported by this build",
1822  token->string);
1823  return NULL;
1824  }
1825 
1826  /*
1827  * XXX: When using ident on local connections, change it to peer, for
1828  * backwards compatibility.
1829  */
1830  if (parsedline->conntype == ctLocal &&
1831  parsedline->auth_method == uaIdent)
1832  parsedline->auth_method = uaPeer;
1833 
1834  /* Invalid authentication combinations */
1835  if (parsedline->conntype == ctLocal &&
1836  parsedline->auth_method == uaGSS)
1837  {
1838  ereport(elevel,
1839  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1840  errmsg("gssapi authentication is not supported on local sockets"),
1841  errcontext("line %d of configuration file \"%s\"",
1842  line_num, file_name)));
1843  *err_msg = "gssapi authentication is not supported on local sockets";
1844  return NULL;
1845  }
1846 
1847  if (parsedline->conntype != ctLocal &&
1848  parsedline->auth_method == uaPeer)
1849  {
1850  ereport(elevel,
1851  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1852  errmsg("peer authentication is only supported on local sockets"),
1853  errcontext("line %d of configuration file \"%s\"",
1854  line_num, file_name)));
1855  *err_msg = "peer authentication is only supported on local sockets";
1856  return NULL;
1857  }
1858 
1859  /*
1860  * SSPI authentication can never be enabled on ctLocal connections,
1861  * because it's only supported on Windows, where ctLocal isn't supported.
1862  */
1863 
1864 
1865  if (parsedline->conntype != ctHostSSL &&
1866  parsedline->auth_method == uaCert)
1867  {
1868  ereport(elevel,
1869  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1870  errmsg("cert authentication is only supported on hostssl connections"),
1871  errcontext("line %d of configuration file \"%s\"",
1872  line_num, file_name)));
1873  *err_msg = "cert authentication is only supported on hostssl connections";
1874  return NULL;
1875  }
1876 
1877  /*
1878  * For GSS and SSPI, set the default value of include_realm to true.
1879  * Having include_realm set to false is dangerous in multi-realm
1880  * situations and is generally considered bad practice. We keep the
1881  * capability around for backwards compatibility, but we might want to
1882  * remove it at some point in the future. Users who still need to strip
1883  * the realm off would be better served by using an appropriate regex in a
1884  * pg_ident.conf mapping.
1885  */
1886  if (parsedline->auth_method == uaGSS ||
1887  parsedline->auth_method == uaSSPI)
1888  parsedline->include_realm = true;
1889 
1890  /*
1891  * For SSPI, include_realm defaults to the SAM-compatible domain (aka
1892  * NetBIOS name) and user names instead of the Kerberos principal name for
1893  * compatibility.
1894  */
1895  if (parsedline->auth_method == uaSSPI)
1896  {
1897  parsedline->compat_realm = true;
1898  parsedline->upn_username = false;
1899  }
1900 
1901  /* Parse remaining arguments */
1902  while ((field = lnext(tok_line->fields, field)) != NULL)
1903  {
1904  tokens = lfirst(field);
1905  foreach(tokencell, tokens)
1906  {
1907  char *val;
1908 
1909  token = lfirst(tokencell);
1910 
1911  str = pstrdup(token->string);
1912  val = strchr(str, '=');
1913  if (val == NULL)
1914  {
1915  /*
1916  * Got something that's not a name=value pair.
1917  */
1918  ereport(elevel,
1919  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1920  errmsg("authentication option not in name=value format: %s", token->string),
1921  errcontext("line %d of configuration file \"%s\"",
1922  line_num, file_name)));
1923  *err_msg = psprintf("authentication option not in name=value format: %s",
1924  token->string);
1925  return NULL;
1926  }
1927 
1928  *val++ = '\0'; /* str now holds "name", val holds "value" */
1929  if (!parse_hba_auth_opt(str, val, parsedline, elevel, err_msg))
1930  /* parse_hba_auth_opt already logged the error message */
1931  return NULL;
1932  pfree(str);
1933  }
1934  }
1935 
1936  /*
1937  * Check if the selected authentication method has any mandatory arguments
1938  * that are not set.
1939  */
1940  if (parsedline->auth_method == uaLDAP)
1941  {
1942 #ifndef HAVE_LDAP_INITIALIZE
1943  /* Not mandatory for OpenLDAP, because it can use DNS SRV records */
1944  MANDATORY_AUTH_ARG(parsedline->ldapserver, "ldapserver", "ldap");
1945 #endif
1946 
1947  /*
1948  * LDAP can operate in two modes: either with a direct bind, using
1949  * ldapprefix and ldapsuffix, or using a search+bind, using
1950  * ldapbasedn, ldapbinddn, ldapbindpasswd and one of
1951  * ldapsearchattribute or ldapsearchfilter. Disallow mixing these
1952  * parameters.
1953  */
1954  if (parsedline->ldapprefix || parsedline->ldapsuffix)
1955  {
1956  if (parsedline->ldapbasedn ||
1957  parsedline->ldapbinddn ||
1958  parsedline->ldapbindpasswd ||
1959  parsedline->ldapsearchattribute ||
1960  parsedline->ldapsearchfilter)
1961  {
1962  ereport(elevel,
1963  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1964  errmsg("cannot use ldapbasedn, ldapbinddn, ldapbindpasswd, ldapsearchattribute, ldapsearchfilter, or ldapurl together with ldapprefix"),
1965  errcontext("line %d of configuration file \"%s\"",
1966  line_num, file_name)));
1967  *err_msg = "cannot use ldapbasedn, ldapbinddn, ldapbindpasswd, ldapsearchattribute, ldapsearchfilter, or ldapurl together with ldapprefix";
1968  return NULL;
1969  }
1970  }
1971  else if (!parsedline->ldapbasedn)
1972  {
1973  ereport(elevel,
1974  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1975  errmsg("authentication method \"ldap\" requires argument \"ldapbasedn\", \"ldapprefix\", or \"ldapsuffix\" to be set"),
1976  errcontext("line %d of configuration file \"%s\"",
1977  line_num, file_name)));
1978  *err_msg = "authentication method \"ldap\" requires argument \"ldapbasedn\", \"ldapprefix\", or \"ldapsuffix\" to be set";
1979  return NULL;
1980  }
1981 
1982  /*
1983  * When using search+bind, you can either use a simple attribute
1984  * (defaulting to "uid") or a fully custom search filter. You can't
1985  * do both.
1986  */
1987  if (parsedline->ldapsearchattribute && parsedline->ldapsearchfilter)
1988  {
1989  ereport(elevel,
1990  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1991  errmsg("cannot use ldapsearchattribute together with ldapsearchfilter"),
1992  errcontext("line %d of configuration file \"%s\"",
1993  line_num, file_name)));
1994  *err_msg = "cannot use ldapsearchattribute together with ldapsearchfilter";
1995  return NULL;
1996  }
1997  }
1998 
1999  if (parsedline->auth_method == uaRADIUS)
2000  {
2001  MANDATORY_AUTH_ARG(parsedline->radiusservers, "radiusservers", "radius");
2002  MANDATORY_AUTH_ARG(parsedline->radiussecrets, "radiussecrets", "radius");
2003 
2004  if (parsedline->radiusservers == NIL)
2005  {
2006  ereport(elevel,
2007  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2008  errmsg("list of RADIUS servers cannot be empty"),
2009  errcontext("line %d of configuration file \"%s\"",
2010  line_num, file_name)));
2011  *err_msg = "list of RADIUS servers cannot be empty";
2012  return NULL;
2013  }
2014 
2015  if (parsedline->radiussecrets == NIL)
2016  {
2017  ereport(elevel,
2018  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2019  errmsg("list of RADIUS secrets cannot be empty"),
2020  errcontext("line %d of configuration file \"%s\"",
2021  line_num, file_name)));
2022  *err_msg = "list of RADIUS secrets cannot be empty";
2023  return NULL;
2024  }
2025 
2026  /*
2027  * Verify length of option lists - each can be 0 (except for secrets,
2028  * but that's already checked above), 1 (use the same value
2029  * everywhere) or the same as the number of servers.
2030  */
2031  if (!(list_length(parsedline->radiussecrets) == 1 ||
2032  list_length(parsedline->radiussecrets) == list_length(parsedline->radiusservers)))
2033  {
2034  ereport(elevel,
2035  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2036  errmsg("the number of RADIUS secrets (%d) must be 1 or the same as the number of RADIUS servers (%d)",
2037  list_length(parsedline->radiussecrets),
2038  list_length(parsedline->radiusservers)),
2039  errcontext("line %d of configuration file \"%s\"",
2040  line_num, file_name)));
2041  *err_msg = psprintf("the number of RADIUS secrets (%d) must be 1 or the same as the number of RADIUS servers (%d)",
2042  list_length(parsedline->radiussecrets),
2043  list_length(parsedline->radiusservers));
2044  return NULL;
2045  }
2046  if (!(list_length(parsedline->radiusports) == 0 ||
2047  list_length(parsedline->radiusports) == 1 ||
2048  list_length(parsedline->radiusports) == list_length(parsedline->radiusservers)))
2049  {
2050  ereport(elevel,
2051  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2052  errmsg("the number of RADIUS ports (%d) must be 1 or the same as the number of RADIUS servers (%d)",
2053  list_length(parsedline->radiusports),
2054  list_length(parsedline->radiusservers)),
2055  errcontext("line %d of configuration file \"%s\"",
2056  line_num, file_name)));
2057  *err_msg = psprintf("the number of RADIUS ports (%d) must be 1 or the same as the number of RADIUS servers (%d)",
2058  list_length(parsedline->radiusports),
2059  list_length(parsedline->radiusservers));
2060  return NULL;
2061  }
2062  if (!(list_length(parsedline->radiusidentifiers) == 0 ||
2063  list_length(parsedline->radiusidentifiers) == 1 ||
2064  list_length(parsedline->radiusidentifiers) == list_length(parsedline->radiusservers)))
2065  {
2066  ereport(elevel,
2067  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2068  errmsg("the number of RADIUS identifiers (%d) must be 1 or the same as the number of RADIUS servers (%d)",
2069  list_length(parsedline->radiusidentifiers),
2070  list_length(parsedline->radiusservers)),
2071  errcontext("line %d of configuration file \"%s\"",
2072  line_num, file_name)));
2073  *err_msg = psprintf("the number of RADIUS identifiers (%d) must be 1 or the same as the number of RADIUS servers (%d)",
2074  list_length(parsedline->radiusidentifiers),
2075  list_length(parsedline->radiusservers));
2076  return NULL;
2077  }
2078  }
2079 
2080  /*
2081  * Enforce any parameters implied by other settings.
2082  */
2083  if (parsedline->auth_method == uaCert)
2084  {
2085  /*
2086  * For auth method cert, client certificate validation is mandatory,
2087  * and it implies the level of verify-full.
2088  */
2089  parsedline->clientcert = clientCertFull;
2090  }
2091 
2092  return parsedline;
2093 }
int errhint(const char *fmt,...)
Definition: elog.c:1193
#define MANDATORY_AUTH_ARG(argvar, argname, authname)
Definition: hba.c:1300
static bool parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline, int elevel, char **err_msg)
Definition: hba.c:2103
static int regcomp_auth_token(AuthToken *token, char *filename, int line_num, char **err_msg, int elevel)
Definition: hba.c:352
static AuthToken * copy_auth_token(AuthToken *in)
Definition: hba.c:339
@ 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:150
static ListCell * list_head(const List *l)
Definition: pg_list.h:126
#define linitial(l)
Definition: pg_list.h:176
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:341
bool Db_user_namespace
Definition: postmaster.c:230
bool EnableSSL
Definition: postmaster.c:223
int addrlen
Definition: hba.h:103
int masklen
Definition: hba.h:105
char * rawline
Definition: hba.h:98
int length
Definition: pg_list.h:54
char * raw_line
Definition: hba.h:163
int line_num
Definition: hba.h:162
char * file_name
Definition: hba.h:161
List * fields
Definition: hba.h:160

References HbaLine::addr, HbaLine::addrlen, 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, EnableSSL, ereport, TokenizedAuthLine::err_msg, errcode(), errcontext, errhint(), errmsg(), TokenizedAuthLine::fields, TokenizedAuthLine::file_name, 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, regcomp_auth_token(), HbaLine::roles, HbaLine::sourcefile, 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 2759 of file hba.c.

2760 {
2761  int line_num = tok_line->line_num;
2762  char *file_name = tok_line->file_name;
2763  char **err_msg = &tok_line->err_msg;
2764  ListCell *field;
2765  List *tokens;
2766  AuthToken *token;
2767  IdentLine *parsedline;
2768 
2769  Assert(tok_line->fields != NIL);
2770  field = list_head(tok_line->fields);
2771 
2772  parsedline = palloc0(sizeof(IdentLine));
2773  parsedline->linenumber = line_num;
2774 
2775  /* Get the map token (must exist) */
2776  tokens = lfirst(field);
2777  IDENT_MULTI_VALUE(tokens);
2778  token = linitial(tokens);
2779  parsedline->usermap = pstrdup(token->string);
2780 
2781  /* Get the ident user token */
2782  field = lnext(tok_line->fields, field);
2783  IDENT_FIELD_ABSENT(field);
2784  tokens = lfirst(field);
2785  IDENT_MULTI_VALUE(tokens);
2786  token = linitial(tokens);
2787 
2788  /* Copy the ident user token */
2789  parsedline->token = copy_auth_token(token);
2790 
2791  /* Get the PG rolename token */
2792  field = lnext(tok_line->fields, field);
2793  IDENT_FIELD_ABSENT(field);
2794  tokens = lfirst(field);
2795  IDENT_MULTI_VALUE(tokens);
2796  token = linitial(tokens);
2797  parsedline->pg_role = pstrdup(token->string);
2798 
2799  /*
2800  * Now that the field validation is done, compile a regex from the user
2801  * token, if necessary.
2802  */
2803  if (regcomp_auth_token(parsedline->token, file_name, line_num,
2804  err_msg, elevel))
2805  {
2806  /* err_msg includes the error to report */
2807  return NULL;
2808  }
2809 
2810  return parsedline;
2811 }
#define IDENT_FIELD_ABSENT(field)
Definition: hba.c:1324
#define IDENT_MULTI_VALUE(tokens)
Definition: hba.c:1337
int linenumber
Definition: hba.h:142

References Assert(), copy_auth_token(), TokenizedAuthLine::err_msg, TokenizedAuthLine::fields, TokenizedAuthLine::file_name, IDENT_FIELD_ABSENT, IDENT_MULTI_VALUE, lfirst, TokenizedAuthLine::line_num, IdentLine::linenumber, linitial, list_head(), lnext(), NIL, palloc0(), IdentLine::pg_role, pstrdup(), regcomp_auth_token(), AuthToken::string, IdentLine::token, and IdentLine::usermap.

Referenced by fill_ident_view(), and load_ident().

◆ pg_isblank()

bool pg_isblank ( const char  c)

Definition at line 148 of file hba.c.

149 {
150  return c == ' ' || c == '\t' || c == '\r';
151 }

Referenced by interpret_ident_response(), and next_token().

◆ regcomp_auth_token()

static int regcomp_auth_token ( AuthToken token,
char *  filename,
int  line_num,
char **  err_msg,
int  elevel 
)
static

Definition at line 352 of file hba.c.

354 {
355  pg_wchar *wstr;
356  int wlen;
357  int rc;
358 
359  Assert(token->regex == NULL);
360 
361  if (token->string[0] != '/')
362  return 0; /* nothing to compile */
363 
364  token->regex = (regex_t *) palloc0(sizeof(regex_t));
365  wstr = palloc((strlen(token->string + 1) + 1) * sizeof(pg_wchar));
366  wlen = pg_mb2wchar_with_len(token->string + 1,
367  wstr, strlen(token->string + 1));
368 
369  rc = pg_regcomp(token->regex, wstr, wlen, REG_ADVANCED, C_COLLATION_OID);
370 
371  if (rc)
372  {
373  char errstr[100];
374 
375  pg_regerror(rc, token->regex, errstr, sizeof(errstr));
376  ereport(elevel,
377  (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
378  errmsg("invalid regular expression \"%s\": %s",
379  token->string + 1, errstr),
380  errcontext("line %d of configuration file \"%s\"",
381  line_num, filename)));
382 
383  *err_msg = psprintf("invalid regular expression \"%s\": %s",
384  token->string + 1, errstr);
385  }
386 
387  pfree(wstr);
388  return rc;
389 }
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 * palloc(Size size)
Definition: mcxt.c:1199
int pg_regcomp(regex_t *re, const chr *string, size_t len, int flags, Oid collation)
Definition: regcomp.c:372
#define REG_ADVANCED
Definition: regex.h:103
Definition: regex.h:56

References Assert(), ereport, errcode(), errcontext, errmsg(), filename, palloc(), palloc0(), pfree(), pg_mb2wchar_with_len(), pg_regcomp(), pg_regerror(), psprintf(), REG_ADVANCED, AuthToken::regex, and AuthToken::string.

Referenced by parse_hba_line(), and parse_ident_line().

◆ regexec_auth_token()

static int regexec_auth_token ( const char *  match,
AuthToken token,
size_t  nmatch,
regmatch_t  pmatch[] 
)
static

Definition at line 397 of file hba.c.

399 {
400  pg_wchar *wmatchstr;
401  int wmatchlen;
402  int r;
403 
404  Assert(token->string[0] == '/' && token->regex);
405 
406  wmatchstr = palloc((strlen(match) + 1) * sizeof(pg_wchar));
407  wmatchlen = pg_mb2wchar_with_len(match, wmatchstr, strlen(match));
408 
409  r = pg_regexec(token->regex, wmatchstr, wmatchlen, 0, NULL, nmatch, pmatch, 0);
410 
411  pfree(wmatchstr);
412  return r;
413 }
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:185

References Assert(), palloc(), pfree(), pg_mb2wchar_with_len(), pg_regexec(), AuthToken::regex, and AuthToken::string.

Referenced by check_db(), check_ident_usermap(), and check_role().

◆ tokenize_auth_file()

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

Definition at line 734 of file hba.c.

736 {
737  int line_number = 1;
739  MemoryContext linecxt;
740  MemoryContext funccxt; /* context of this function's caller */
741  ErrorContextCallback tokenerrcontext;
742  tokenize_error_callback_arg callback_arg;
743 
745 
746  callback_arg.filename = filename;
747  callback_arg.linenum = line_number;
748 
749  tokenerrcontext.callback = tokenize_error_callback;
750  tokenerrcontext.arg = (void *) &callback_arg;
751  tokenerrcontext.previous = error_context_stack;
752  error_context_stack = &tokenerrcontext;
753 
754  /*
755  * Do all the local tokenization in its own context, to ease the cleanup
756  * of any memory allocated while tokenizing.
757  */
759  "tokenize_auth_file",
761  funccxt = MemoryContextSwitchTo(linecxt);
762 
764 
765  if (depth == CONF_FILE_START_DEPTH)
766  *tok_lines = NIL;
767 
768  while (!feof(file) && !ferror(file))
769  {
770  TokenizedAuthLine *tok_line;
771  MemoryContext oldcxt;
772  char *lineptr;
773  List *current_line = NIL;
774  char *err_msg = NULL;
775  int last_backslash_buflen = 0;
776  int continuations = 0;
777 
778  /* Collect the next input line, handling backslash continuations */
780 
781  while (pg_get_line_append(file, &buf, NULL))
782  {
783  /* Strip trailing newline, including \r in case we're on Windows */
784  buf.len = pg_strip_crlf(buf.data);
785 
786  /*
787  * Check for backslash continuation. The backslash must be after
788  * the last place we found a continuation, else two backslashes
789  * followed by two \n's would behave surprisingly.
790  */
791  if (buf.len > last_backslash_buflen &&
792  buf.data[buf.len - 1] == '\\')
793  {
794  /* Continuation, so strip it and keep reading */
795  buf.data[--buf.len] = '\0';
796  last_backslash_buflen = buf.len;
797  continuations++;
798  continue;
799  }
800 
801  /* Nope, so we have the whole line */
802  break;
803  }
804 
805  if (ferror(file))
806  {
807  /* I/O error! */
808  int save_errno = errno;
809 
810  ereport(elevel,
812  errmsg("could not read file \"%s\": %m", filename)));
813  err_msg = psprintf("could not read file \"%s\": %s",
814  filename, strerror(save_errno));
815  break;
816  }
817 
818  /* Parse fields */
819  lineptr = buf.data;
820  while (*lineptr && err_msg == NULL)
821  {
822  List *current_field;
823 
824  current_field = next_field_expand(filename, &lineptr,
825  elevel, depth, &err_msg);
826  /* add field to line, unless we are at EOL or comment start */
827  if (current_field != NIL)
828  {
829  /*
830  * lappend() may do its own allocations, so move to the
831  * context for the list of tokens.
832  */
834  current_line = lappend(current_line, current_field);
835  MemoryContextSwitchTo(oldcxt);
836  }
837  }
838 
839  /*
840  * Reached EOL; no need to emit line to TokenizedAuthLine list if it's
841  * boring.
842  */
843  if (current_line == NIL && err_msg == NULL)
844  goto next_line;
845 
846  /* If the line is valid, check if that's an include directive */
847  if (err_msg == NULL && list_length(current_line) == 2)
848  {
849  AuthToken *first,
850  *second;
851 
852  first = linitial(linitial_node(List, current_line));
853  second = linitial(lsecond_node(List, current_line));
854 
855  if (strcmp(first->string, "include") == 0)
856  {
857  tokenize_include_file(filename, second->string, tok_lines,
858  elevel, depth + 1, false, &err_msg);
859 
860  if (err_msg)
861  goto process_line;
862 
863  /*
864  * tokenize_auth_file() has taken care of creating the
865  * TokenizedAuthLines.
866  */
867  goto next_line;
868  }
869  else if (strcmp(first->string, "include_dir") == 0)
870  {
871  char **filenames;
872  char *dir_name = second->string;
873  int num_filenames;
874  StringInfoData err_buf;
875 
876  filenames = GetConfFilesInDir(dir_name, filename, elevel,
877  &num_filenames, &err_msg);
878 
879  if (!filenames)
880  {
881  /* the error is in err_msg, so create an entry */
882  goto process_line;
883  }
884 
885  initStringInfo(&err_buf);
886  for (int i = 0; i < num_filenames; i++)
887  {
888  tokenize_include_file(filename, filenames[i], tok_lines,
889  elevel, depth + 1, false, &err_msg);
890  /* cumulate errors if any */
891  if (err_msg)
892  {
893  if (err_buf.len > 0)
894  appendStringInfoChar(&err_buf, '\n');
895  appendStringInfoString(&err_buf, err_msg);
896  }
897  }
898 
899  /* clean up things */
900  for (int i = 0; i < num_filenames; i++)
901  pfree(filenames[i]);
902  pfree(filenames);
903 
904  /*
905  * If there were no errors, the line is fully processed,
906  * bypass the general TokenizedAuthLine processing.
907  */
908  if (err_buf.len == 0)
909  goto next_line;
910 
911  /* Otherwise, process the cumulated errors, if any. */
912  err_msg = err_buf.data;
913  goto process_line;
914  }
915  else if (strcmp(first->string, "include_if_exists") == 0)
916  {
917 
918  tokenize_include_file(filename, second->string, tok_lines,
919  elevel, depth + 1, true, &err_msg);
920  if (err_msg)
921  goto process_line;
922 
923  /*
924  * tokenize_auth_file() has taken care of creating the
925  * TokenizedAuthLines.
926  */
927  goto next_line;
928  }
929  }
930 
931 process_line:
932 
933  /*
934  * General processing: report the error if any and emit line to the
935  * TokenizedAuthLine. This is saved in the memory context dedicated
936  * to this list.
937  */
939  tok_line = (TokenizedAuthLine *) palloc0(sizeof(TokenizedAuthLine));
940  tok_line->fields = current_line;
941  tok_line->file_name = pstrdup(filename);
942  tok_line->line_num = line_number;
943  tok_line->raw_line = pstrdup(buf.data);
944  tok_line->err_msg = err_msg ? pstrdup(err_msg) : NULL;
945  *tok_lines = lappend(*tok_lines, tok_line);
946  MemoryContextSwitchTo(oldcxt);
947 
948 next_line:
949  line_number += continuations + 1;
950  callback_arg.linenum = line_number;
951  }
952 
953  MemoryContextSwitchTo(funccxt);
954  MemoryContextDelete(linecxt);
955 
956  error_context_stack = tokenerrcontext.previous;
957 }
char ** GetConfFilesInDir(const char *includedir, const char *calling_file, int elevel, int *num_filenames, char **err_msg)
Definition: conffiles.c:70
ErrorContextCallback * error_context_stack
Definition: elog.c:94
static List * next_field_expand(const char *filename, char **lineptr, int elevel, int depth, char **err_msg)
Definition: hba.c:430
static void tokenize_include_file(const char *outer_filename, const char *inc_filename, List **tok_lines, int elevel, int depth, bool missing_ok, char **err_msg)
Definition: hba.c:486
static void tokenize_error_callback(void *arg)
Definition: hba.c:705
bool pg_get_line_append(FILE *stream, StringInfo buf, PromptInterruptContext *prompt_ctx)
Definition: pg_get_line.c:124
#define linitial_node(type, l)
Definition: pg_list.h:179
#define lsecond_node(type, l)
Definition: pg_list.h:184
int pg_strip_crlf(char *str)
Definition: string.c:155
void resetStringInfo(StringInfo str)
Definition: stringinfo.c:75
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
struct ErrorContextCallback * previous
Definition: elog.h:234
void(* callback)(void *arg)
Definition: elog.h:235
const char * filename
Definition: hba.c:71

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate, appendStringInfoChar(), appendStringInfoString(), ErrorContextCallback::arg, Assert(), buf, ErrorContextCallback::callback, CONF_FILE_START_DEPTH, CurrentMemoryContext, StringInfoData::data, ereport, TokenizedAuthLine::err_msg, errcode_for_file_access(), errmsg(), error_context_stack, TokenizedAuthLine::fields, TokenizedAuthLine::file_name, tokenize_error_callback_arg::filename, filename, GetConfFilesInDir(), i, initStringInfo(), lappend(), StringInfoData::len, TokenizedAuthLine::line_num, tokenize_error_callback_arg::linenum, linitial, linitial_node, list_length(), lsecond_node, MemoryContextDelete(), MemoryContextSwitchTo(), next_field_expand(), NIL, palloc0(), pfree(), pg_get_line_append(), pg_strip_crlf(), ErrorContextCallback::previous, psprintf(), pstrdup(), TokenizedAuthLine::raw_line, resetStringInfo(), strerror, AuthToken::string, tokenize_context, tokenize_error_callback(), and tokenize_include_file().

Referenced by fill_hba_view(), fill_ident_view(), load_hba(), load_ident(), tokenize_expand_file(), and tokenize_include_file().

◆ tokenize_error_callback()

static void tokenize_error_callback ( void *  arg)
static

Definition at line 705 of file hba.c.

706 {
708 
709  errcontext("line %d of configuration file \"%s\"",
710  callback_arg->linenum, callback_arg->filename);
711 }
void * arg

References arg, errcontext, tokenize_error_callback_arg::filename, and tokenize_error_callback_arg::linenum.

Referenced by tokenize_auth_file().

◆ tokenize_expand_file()

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

Definition at line 541 of file hba.c.

547 {
548  char *inc_fullname;
549  FILE *inc_file;
550  List *inc_lines = NIL;
551  ListCell *inc_line;
552 
553  inc_fullname = AbsoluteConfigLocation(inc_filename, outer_filename);
554  inc_file = open_auth_file(inc_fullname, elevel, depth, err_msg);
555 
556  if (inc_file == NULL)
557  {
558  /* error already logged */
559  pfree(inc_fullname);
560  return tokens;
561  }
562 
563  /*
564  * There is possible recursion here if the file contains @ or an include
565  * record.
566  */
567  tokenize_auth_file(inc_fullname, inc_file, &inc_lines, elevel,
568  depth);
569 
570  pfree(inc_fullname);
571 
572  /*
573  * Move all the tokens found in the file to the tokens list. These are
574  * already saved in tokenize_context.
575  */
576  foreach(inc_line, inc_lines)
577  {
578  TokenizedAuthLine *tok_line = (TokenizedAuthLine *) lfirst(inc_line);
579  ListCell *inc_field;
580 
581  /* If any line has an error, propagate that up to caller */
582  if (tok_line->err_msg)
583  {
584  *err_msg = pstrdup(tok_line->err_msg);
585  break;
586  }
587 
588  foreach(inc_field, tok_line->fields)
589  {
590  List *inc_tokens = lfirst(inc_field);
591  ListCell *inc_token;
592 
593  foreach(inc_token, inc_tokens)
594  {
595  AuthToken *token = lfirst(inc_token);
596  MemoryContext oldcxt;
597 
598  /*
599  * lappend() may do its own allocations, so move to the
600  * context for the list of tokens.
601  */
603  tokens = lappend(tokens, token);
604  MemoryContextSwitchTo(oldcxt);
605  }
606  }
607  }
608 
609  free_auth_file(inc_file, depth);
610  return tokens;
611 }
char * AbsoluteConfigLocation(const char *location, const char *calling_file)
Definition: conffiles.c:36

References AbsoluteConfigLocation(), TokenizedAuthLine::err_msg, TokenizedAuthLine::fields, free_auth_file(), lappend(), lfirst, MemoryContextSwitchTo(), NIL, open_auth_file(), pfree(), pstrdup(), tokenize_auth_file(), and tokenize_context.

Referenced by next_field_expand().

◆ tokenize_include_file()

static void tokenize_include_file ( const char *  outer_filename,
const char *  inc_filename,
List **  tok_lines,
int  elevel,
int  depth,
bool  missing_ok,
char **  err_msg 
)
static

Definition at line 486 of file hba.c.

493 {
494  char *inc_fullname;
495  FILE *inc_file;
496 
497  inc_fullname = AbsoluteConfigLocation(inc_filename, outer_filename);
498  inc_file = open_auth_file(inc_fullname, elevel, depth, err_msg);
499 
500  if (!inc_file)
501  {
502  if (errno == ENOENT && missing_ok)
503  {
504  ereport(elevel,
505  (errmsg("skipping missing authentication file \"%s\"",
506  inc_fullname)));
507  *err_msg = NULL;
508  pfree(inc_fullname);
509  return;
510  }
511 
512  /* error in err_msg, so leave and report */
513  pfree(inc_fullname);
514  Assert(err_msg);
515  return;
516  }
517 
518  tokenize_auth_file(inc_fullname, inc_file, tok_lines, elevel,
519  depth);
520  free_auth_file(inc_file, depth);
521  pfree(inc_fullname);
522 }

References AbsoluteConfigLocation(), Assert(), ereport, errmsg(), free_auth_file(), open_auth_file(), pfree(), and tokenize_auth_file().

Referenced by tokenize_auth_file().

Variable Documentation

◆ parsed_hba_context

MemoryContext parsed_hba_context = NULL
static

Definition at line 91 of file hba.c.

Referenced by load_hba().

◆ parsed_hba_lines

List* parsed_hba_lines = NIL
static

Definition at line 90 of file hba.c.

Referenced by check_hba(), and load_hba().

◆ parsed_ident_context

MemoryContext parsed_ident_context = NULL
static

Definition at line 103 of file hba.c.

Referenced by load_ident().

◆ parsed_ident_lines

List* parsed_ident_lines = NIL
static

Definition at line 102 of file hba.c.

Referenced by check_usermap(), and load_ident().

◆ tokenize_context

MemoryContext tokenize_context = NULL
static

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

Referenced by hba_authname().