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_member_check(t)   (!t->quoted && t->string[0] == '+')
 
#define token_is_keyword(t, k)   (!t->quoted && strcmp(t->string, k) == 0)
 
#define token_matches(t, k)   (strcmp(t->string, k) == 0)
 
#define token_matches_insensitive(t, k)   (pg_strcasecmp(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

 StaticAssertDecl (lengthof(UserAuthName)==USER_AUTH_LAST+1, "UserAuthName[] must match the UserAuth enum")
 
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, bool case_insensitive)
 
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_user, const char *system_user, bool case_insensitive, bool *found_p, bool *error_p)
 
int check_usermap (const char *usermap_name, const char *pg_user, const char *system_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:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define errcontext
Definition: elog.h:196
char * pstrdup(const char *in)
Definition: mcxt.c:1624

Definition at line 1338 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 1351 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:91
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46

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

◆ token_is_member_check

#define token_is_member_check (   t)    (!t->quoted && t->string[0] == '+')

Definition at line 76 of file hba.c.

◆ token_matches

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

Definition at line 78 of file hba.c.

◆ token_matches_insensitive

#define token_matches_insensitive (   t,
 
)    (pg_strcasecmp(t->string, k) == 0)

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

1044 {
1045  ListCell *cell;
1046  AuthToken *tok;
1047 
1048  foreach(cell, tokens)
1049  {
1050  tok = lfirst(cell);
1051  if (am_walsender && !am_db_walsender)
1052  {
1053  /*
1054  * physical replication walsender connections can only match
1055  * replication keyword
1056  */
1057  if (token_is_keyword(tok, "replication"))
1058  return true;
1059  }
1060  else if (token_is_keyword(tok, "all"))
1061  return true;
1062  else if (token_is_keyword(tok, "sameuser"))
1063  {
1064  if (strcmp(dbname, role) == 0)
1065  return true;
1066  }
1067  else if (token_is_keyword(tok, "samegroup") ||
1068  token_is_keyword(tok, "samerole"))
1069  {
1070  if (is_member(roleid, dbname))
1071  return true;
1072  }
1073  else if (token_is_keyword(tok, "replication"))
1074  continue; /* never match this if not walsender */
1075  else if (token_has_regexp(tok))
1076  {
1077  if (regexec_auth_token(dbname, tok, 0, NULL) == REG_OKAY)
1078  return true;
1079  }
1080  else if (token_matches(tok, dbname))
1081  return true;
1082  }
1083  return false;
1084 }
static bool is_member(Oid userid, const char *role)
Definition: hba.c:975
#define token_is_keyword(t, k)
Definition: hba.c:77
static int regexec_auth_token(const char *match, AuthToken *token, size_t nmatch, regmatch_t pmatch[])
Definition: hba.c:405
#define token_has_regexp(t)
Definition: hba.c:75
#define token_matches(t, k)
Definition: hba.c:78
#define lfirst(lc)
Definition: pg_list.h:172
#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 2537 of file hba.c.

2538 {
2539  Oid roleid;
2540  ListCell *line;
2541  HbaLine *hba;
2542 
2543  /* Get the target role's OID. Note we do not error out for bad role. */
2544  roleid = get_role_oid(port->user_name, true);
2545 
2546  foreach(line, parsed_hba_lines)
2547  {
2548  hba = (HbaLine *) lfirst(line);
2549 
2550  /* Check connection type */
2551  if (hba->conntype == ctLocal)
2552  {
2553  if (port->raddr.addr.ss_family != AF_UNIX)
2554  continue;
2555  }
2556  else
2557  {
2558  if (port->raddr.addr.ss_family == AF_UNIX)
2559  continue;
2560 
2561  /* Check SSL state */
2562  if (port->ssl_in_use)
2563  {
2564  /* Connection is SSL, match both "host" and "hostssl" */
2565  if (hba->conntype == ctHostNoSSL)
2566  continue;
2567  }
2568  else
2569  {
2570  /* Connection is not SSL, match both "host" and "hostnossl" */
2571  if (hba->conntype == ctHostSSL)
2572  continue;
2573  }
2574 
2575  /* Check GSSAPI state */
2576 #ifdef ENABLE_GSS
2577  if (port->gss && port->gss->enc &&
2578  hba->conntype == ctHostNoGSS)
2579  continue;
2580  else if (!(port->gss && port->gss->enc) &&
2581  hba->conntype == ctHostGSS)
2582  continue;
2583 #else
2584  if (hba->conntype == ctHostGSS)
2585  continue;
2586 #endif
2587 
2588  /* Check IP address */
2589  switch (hba->ip_cmp_method)
2590  {
2591  case ipCmpMask:
2592  if (hba->hostname)
2593  {
2594  if (!check_hostname(port,
2595  hba->hostname))
2596  continue;
2597  }
2598  else
2599  {
2600  if (!check_ip(&port->raddr,
2601  (struct sockaddr *) &hba->addr,
2602  (struct sockaddr *) &hba->mask))
2603  continue;
2604  }
2605  break;
2606  case ipCmpAll:
2607  break;
2608  case ipCmpSameHost:
2609  case ipCmpSameNet:
2610  if (!check_same_host_or_net(&port->raddr,
2611  hba->ip_cmp_method))
2612  continue;
2613  break;
2614  default:
2615  /* shouldn't get here, but deem it no-match if so */
2616  continue;
2617  }
2618  } /* != ctLocal */
2619 
2620  /* Check database and role */
2621  if (!check_db(port->database_name, port->user_name, roleid,
2622  hba->databases))
2623  continue;
2624 
2625  if (!check_role(port->user_name, roleid, hba->roles, false))
2626  continue;
2627 
2628  /* Found a record that matched! */
2629  port->hba = hba;
2630  return;
2631  }
2632 
2633  /* If no matching entry was found, then implicitly reject. */
2634  hba = palloc0(sizeof(HbaLine));
2636  port->hba = hba;
2637 }
Oid get_role_oid(const char *rolname, bool missing_ok)
Definition: acl.c:5255
static bool check_role(const char *role, Oid roleid, List *tokens, bool case_insensitive)
Definition: hba.c:1004
static bool check_ip(SockAddr *raddr, struct sockaddr *addr, struct sockaddr *mask)
Definition: hba.c:1219
static bool check_same_host_or_net(SockAddr *raddr, IPCompareMethod method)
Definition: hba.c:1260
static bool check_hostname(hbaPort *port, const char *hostname)
Definition: hba.c:1128
static List * parsed_hba_lines
Definition: hba.c:92
static bool check_db(const char *dbname, const char *role, Oid roleid, List *tokens)
Definition: hba.c:1043
@ 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:1241
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 1128 of file hba.c.

1129 {
1130  struct addrinfo *gai_result,
1131  *gai;
1132  int ret;
1133  bool found;
1134 
1135  /* Quick out if remote host name already known bad */
1136  if (port->remote_hostname_resolv < 0)
1137  return false;
1138 
1139  /* Lookup remote host name if not already done */
1140  if (!port->remote_hostname)
1141  {
1142  char remote_hostname[NI_MAXHOST];
1143 
1144  ret = pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
1145  remote_hostname, sizeof(remote_hostname),
1146  NULL, 0,
1147  NI_NAMEREQD);
1148  if (ret != 0)
1149  {
1150  /* remember failure; don't complain in the postmaster log yet */
1151  port->remote_hostname_resolv = -2;
1152  port->remote_hostname_errcode = ret;
1153  return false;
1154  }
1155 
1156  port->remote_hostname = pstrdup(remote_hostname);
1157  }
1158 
1159  /* Now see if remote host name matches this pg_hba line */
1160  if (!hostname_match(hostname, port->remote_hostname))
1161  return false;
1162 
1163  /* If we already verified the forward lookup, we're done */
1164  if (port->remote_hostname_resolv == +1)
1165  return true;
1166 
1167  /* Lookup IP from host name and check against original IP */
1168  ret = getaddrinfo(port->remote_hostname, NULL, NULL, &gai_result);
1169  if (ret != 0)
1170  {
1171  /* remember failure; don't complain in the postmaster log yet */
1172  port->remote_hostname_resolv = -2;
1173  port->remote_hostname_errcode = ret;
1174  return false;
1175  }
1176 
1177  found = false;
1178  for (gai = gai_result; gai; gai = gai->ai_next)
1179  {
1180  if (gai->ai_addr->sa_family == port->raddr.addr.ss_family)
1181  {
1182  if (gai->ai_addr->sa_family == AF_INET)
1183  {
1184  if (ipv4eq((struct sockaddr_in *) gai->ai_addr,
1185  (struct sockaddr_in *) &port->raddr.addr))
1186  {
1187  found = true;
1188  break;
1189  }
1190  }
1191  else if (gai->ai_addr->sa_family == AF_INET6)
1192  {
1193  if (ipv6eq((struct sockaddr_in6 *) gai->ai_addr,
1194  (struct sockaddr_in6 *) &port->raddr.addr))
1195  {
1196  found = true;
1197  break;
1198  }
1199  }
1200  }
1201  }
1202 
1203  if (gai_result)
1204  freeaddrinfo(gai_result);
1205 
1206  if (!found)
1207  elog(DEBUG2, "pg_hba.conf host name \"%s\" rejected because address resolution did not return a match with IP address of client",
1208  hostname);
1209 
1210  port->remote_hostname_resolv = found ? +1 : -1;
1211 
1212  return found;
1213 }
#define DEBUG2
Definition: elog.h:29
static bool hostname_match(const char *pattern, const char *actual_hostname)
Definition: hba.c:1108
static bool ipv4eq(struct sockaddr_in *a, struct sockaddr_in *b)
Definition: hba.c:1087
static bool ipv6eq(struct sockaddr_in6 *a, struct sockaddr_in6 *b)
Definition: hba.c:1093
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_user,
const char *  system_user,
bool  case_insensitive,
bool found_p,
bool error_p 
)
static

Definition at line 2841 of file hba.c.

2844 {
2845  Oid roleid;
2846 
2847  *found_p = false;
2848  *error_p = false;
2849 
2850  if (strcmp(identLine->usermap, usermap_name) != 0)
2851  /* Line does not match the map name we're looking for, so just abort */
2852  return;
2853 
2854  /* Get the target role's OID. Note we do not error out for bad role. */
2855  roleid = get_role_oid(pg_user, true);
2856 
2857  /* Match? */
2858  if (token_has_regexp(identLine->system_user))
2859  {
2860  /*
2861  * Process the system username as a regular expression that returns
2862  * exactly one match. This is replaced for \1 in the database username
2863  * string, if present.
2864  */
2865  int r;
2866  regmatch_t matches[2];
2867  char *ofs;
2868  AuthToken *expanded_pg_user_token;
2869  bool created_temporary_token = false;
2870 
2871  r = regexec_auth_token(system_user, identLine->system_user, 2, matches);
2872  if (r)
2873  {
2874  char errstr[100];
2875 
2876  if (r != REG_NOMATCH)
2877  {
2878  /* REG_NOMATCH is not an error, everything else is */
2879  pg_regerror(r, identLine->system_user->regex, errstr, sizeof(errstr));
2880  ereport(LOG,
2881  (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
2882  errmsg("regular expression match for \"%s\" failed: %s",
2883  identLine->system_user->string + 1, errstr)));
2884  *error_p = true;
2885  }
2886  return;
2887  }
2888 
2889  /*
2890  * Replace \1 with the first captured group unless the field already
2891  * has some special meaning, like a group membership or a regexp-based
2892  * check.
2893  */
2894  if (!token_is_member_check(identLine->pg_user) &&
2895  !token_has_regexp(identLine->pg_user) &&
2896  (ofs = strstr(identLine->pg_user->string, "\\1")) != NULL)
2897  {
2898  char *expanded_pg_user;
2899  int offset;
2900 
2901  /* substitution of the first argument requested */
2902  if (matches[1].rm_so < 0)
2903  {
2904  ereport(LOG,
2905  (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
2906  errmsg("regular expression \"%s\" has no subexpressions as requested by backreference in \"%s\"",
2907  identLine->system_user->string + 1, identLine->pg_user->string)));
2908  *error_p = true;
2909  return;
2910  }
2911 
2912  /*
2913  * length: original length minus length of \1 plus length of match
2914  * plus null terminator
2915  */
2916  expanded_pg_user = palloc0(strlen(identLine->pg_user->string) - 2 + (matches[1].rm_eo - matches[1].rm_so) + 1);
2917  offset = ofs - identLine->pg_user->string;
2918  memcpy(expanded_pg_user, identLine->pg_user->string, offset);
2919  memcpy(expanded_pg_user + offset,
2920  system_user + matches[1].rm_so,
2921  matches[1].rm_eo - matches[1].rm_so);
2922  strcat(expanded_pg_user, ofs + 2);
2923 
2924  /*
2925  * Mark the token as quoted, so it will only be compared literally
2926  * and not for some special meaning, such as "all" or a group
2927  * membership check.
2928  */
2929  expanded_pg_user_token = make_auth_token(expanded_pg_user, true);
2930  created_temporary_token = true;
2931  pfree(expanded_pg_user);
2932  }
2933  else
2934  {
2935  expanded_pg_user_token = identLine->pg_user;
2936  }
2937 
2938  /* check the Postgres user */
2939  *found_p = check_role(pg_user, roleid,
2940  list_make1(expanded_pg_user_token),
2941  case_insensitive);
2942 
2943  if (created_temporary_token)
2944  free_auth_token(expanded_pg_user_token);
2945 
2946  return;
2947  }
2948  else
2949  {
2950  /*
2951  * Not a regular expression, so make a complete match. If the system
2952  * user does not match, just leave.
2953  */
2954  if (case_insensitive)
2955  {
2956  if (!token_matches_insensitive(identLine->system_user,
2957  system_user))
2958  return;
2959  }
2960  else
2961  {
2962  if (!token_matches(identLine->system_user, system_user))
2963  return;
2964  }
2965 
2966  /* check the Postgres user */
2967  *found_p = check_role(pg_user, roleid,
2968  list_make1(identLine->pg_user),
2969  case_insensitive);
2970  }
2971 }
#define LOG
Definition: elog.h:31
#define ereport(elevel,...)
Definition: elog.h:149
#define token_is_member_check(t)
Definition: hba.c:76
#define token_matches_insensitive(t, k)
Definition: hba.c:79
static void free_auth_token(AuthToken *token)
Definition: hba.c:313
static AuthToken * make_auth_token(const char *token, bool quoted)
Definition: hba.c:292
void pfree(void *pointer)
Definition: mcxt.c:1436
Datum system_user(PG_FUNCTION_ARGS)
Definition: miscinit.c:879
#define list_make1(x1)
Definition: pg_list.h:212
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
AuthToken * pg_user
Definition: hba.h:146
AuthToken * system_user
Definition: hba.h:145
char * usermap
Definition: hba.h:144

References check_role(), ereport, errcode(), errmsg(), free_auth_token(), get_role_oid(), list_make1, LOG, make_auth_token(), palloc0(), pfree(), pg_regerror(), IdentLine::pg_user, REG_NOMATCH, AuthToken::regex, regexec_auth_token(), regmatch_t::rm_eo, regmatch_t::rm_so, AuthToken::string, system_user(), IdentLine::system_user, token_has_regexp, token_is_member_check, token_matches, token_matches_insensitive, 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 1219 of file hba.c.

1220 {
1221  if (raddr->addr.ss_family == addr->sa_family &&
1222  pg_range_sockaddr(&raddr->addr,
1223  (struct sockaddr_storage *) addr,
1224  (struct sockaddr_storage *) mask))
1225  return true;
1226  return false;
1227 }
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 1233 of file hba.c.

1235 {
1236  check_network_data *cn = (check_network_data *) cb_data;
1237  struct sockaddr_storage mask;
1238 
1239  /* Already found a match? */
1240  if (cn->result)
1241  return;
1242 
1243  if (cn->method == ipCmpSameHost)
1244  {
1245  /* Make an all-ones netmask of appropriate length for family */
1246  pg_sockaddr_cidr_mask(&mask, NULL, addr->sa_family);
1247  cn->result = check_ip(cn->raddr, addr, (struct sockaddr *) &mask);
1248  }
1249  else
1250  {
1251  /* Use the netmask of the interface itself */
1252  cn->result = check_ip(cn->raddr, addr, netmask);
1253  }
1254 }
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,
bool  case_insensitive 
)
static

Definition at line 1004 of file hba.c.

1005 {
1006  ListCell *cell;
1007  AuthToken *tok;
1008 
1009  foreach(cell, tokens)
1010  {
1011  tok = lfirst(cell);
1012  if (token_is_member_check(tok))
1013  {
1014  if (is_member(roleid, tok->string + 1))
1015  return true;
1016  }
1017  else if (token_is_keyword(tok, "all"))
1018  return true;
1019  else if (token_has_regexp(tok))
1020  {
1021  if (regexec_auth_token(role, tok, 0, NULL) == REG_OKAY)
1022  return true;
1023  }
1024  else if (case_insensitive)
1025  {
1026  if (token_matches_insensitive(tok, role))
1027  return true;
1028  }
1029  else if (token_matches(tok, role))
1030  return true;
1031  }
1032  return false;
1033 }

References is_member(), lfirst, REG_OKAY, regexec_auth_token(), AuthToken::string, token_has_regexp, token_is_keyword, token_is_member_check, token_matches, and token_matches_insensitive.

Referenced by check_hba(), and check_ident_usermap().

◆ check_same_host_or_net()

static bool check_same_host_or_net ( SockAddr raddr,
IPCompareMethod  method 
)
static

Definition at line 1260 of file hba.c.

1261 {
1262  check_network_data cn;
1263 
1264  cn.method = method;
1265  cn.raddr = raddr;
1266  cn.result = false;
1267 
1268  errno = 0;
1270  {
1271  ereport(LOG,
1272  (errmsg("error enumerating network interfaces: %m")));
1273  return false;
1274  }
1275 
1276  return cn.result;
1277 }
static void check_network_callback(struct sockaddr *addr, struct sockaddr *netmask, void *cb_data)
Definition: hba.c:1233
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_user,
const char *  system_user,
bool  case_insensitive 
)

Definition at line 2988 of file hba.c.

2992 {
2993  bool found_entry = false,
2994  error = false;
2995 
2996  if (usermap_name == NULL || usermap_name[0] == '\0')
2997  {
2998  if (case_insensitive)
2999  {
3000  if (pg_strcasecmp(pg_user, system_user) == 0)
3001  return STATUS_OK;
3002  }
3003  else
3004  {
3005  if (strcmp(pg_user, system_user) == 0)
3006  return STATUS_OK;
3007  }
3008  ereport(LOG,
3009  (errmsg("provided user name (%s) and authenticated user name (%s) do not match",
3010  pg_user, system_user)));
3011  return STATUS_ERROR;
3012  }
3013  else
3014  {
3015  ListCell *line_cell;
3016 
3017  foreach(line_cell, parsed_ident_lines)
3018  {
3019  check_ident_usermap(lfirst(line_cell), usermap_name,
3020  pg_user, system_user, case_insensitive,
3021  &found_entry, &error);
3022  if (found_entry || error)
3023  break;
3024  }
3025  }
3026  if (!found_entry && !error)
3027  {
3028  ereport(LOG,
3029  (errmsg("no match in usermap \"%s\" for user \"%s\" authenticated as \"%s\"",
3030  usermap_name, pg_user, system_user)));
3031  }
3032  return found_entry ? STATUS_OK : STATUS_ERROR;
3033 }
#define STATUS_OK
Definition: c.h:1159
#define STATUS_ERROR
Definition: c.h:1160
static List * parsed_ident_lines
Definition: hba.c:104
static void check_ident_usermap(IdentLine *identLine, const char *usermap_name, const char *pg_user, const char *system_user, bool case_insensitive, bool *found_p, bool *error_p)
Definition: hba.c:2841
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
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, STATUS_OK, and system_user().

Referenced by auth_peer(), and ident_inet().

◆ copy_auth_token()

static AuthToken* copy_auth_token ( AuthToken in)
static

Definition at line 347 of file hba.c.

348 {
349  AuthToken *out = make_auth_token(in->string, in->quoted);
350 
351  return out;
352 }
bool quoted
Definition: hba.h:90

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

627 {
628  FreeFile(file);
629 
630  /* If this is the last cleanup, remove the tokenization context */
631  if (depth == CONF_FILE_START_DEPTH)
632  {
634  tokenize_context = NULL;
635  }
636 }
#define CONF_FILE_START_DEPTH
Definition: conffiles.h:17
int FreeFile(FILE *file)
Definition: fd.c:2582
static MemoryContext tokenize_context
Definition: hba.c:86
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:387

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

314 {
315  if (token_has_regexp(token))
316  pg_regfree(token->regex);
317 }
#define token
Definition: indent_globs.h:126
void pg_regfree(regex_t *re)
Definition: regfree.c:49

References pg_regfree(), token, and token_has_regexp.

Referenced by check_ident_usermap(), free_hba_line(), and load_ident().

◆ free_hba_line()

static void free_hba_line ( HbaLine line)
static

Definition at line 324 of file hba.c.

325 {
326  ListCell *cell;
327 
328  foreach(cell, line->roles)
329  {
330  AuthToken *tok = lfirst(cell);
331 
332  free_auth_token(tok);
333  }
334 
335  foreach(cell, line->databases)
336  {
337  AuthToken *tok = lfirst(cell);
338 
339  free_auth_token(tok);
340  }
341 }

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

3163 {
3164  return UserAuthName[auth_method];
3165 }
static const char *const UserAuthName[]
Definition: hba.c:113

References UserAuthName.

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

◆ hba_getauthmethod()

void hba_getauthmethod ( hbaPort port)

Definition at line 3149 of file hba.c.

3150 {
3151  check_hba(port);
3152 }
static void check_hba(hbaPort *port)
Definition: hba.c:2537

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

1109 {
1110  if (pattern[0] == '.') /* suffix match */
1111  {
1112  size_t plen = strlen(pattern);
1113  size_t hlen = strlen(actual_hostname);
1114 
1115  if (hlen < plen)
1116  return false;
1117 
1118  return (pg_strcasecmp(pattern, actual_hostname + (hlen - plen)) == 0);
1119  }
1120  else
1121  return (pg_strcasecmp(pattern, actual_hostname) == 0);
1122 }

References pg_strcasecmp().

Referenced by check_hostname().

◆ ipv4eq()

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

Definition at line 1087 of file hba.c.

1088 {
1089  return (a->sin_addr.s_addr == b->sin_addr.s_addr);
1090 }
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 1093 of file hba.c.

1094 {
1095  int i;
1096 
1097  for (i = 0; i < 16; i++)
1098  if (a->sin6_addr.s6_addr[i] != b->sin6_addr.s6_addr[i])
1099  return false;
1100 
1101  return true;
1102 }
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 975 of file hba.c.

976 {
977  Oid roleid;
978 
979  if (!OidIsValid(userid))
980  return false; /* if user not exist, say "no" */
981 
982  roleid = get_role_oid(role, true);
983 
984  if (!OidIsValid(roleid))
985  return false; /* if target role not exist, say "no" */
986 
987  /*
988  * See if user is directly or indirectly a member of role. For this
989  * purpose, a superuser is not considered to be automatically a member of
990  * the role, so group auth only applies to explicit membership.
991  */
992  return is_member_of_role_nosuper(userid, roleid);
993 }
bool is_member_of_role_nosuper(Oid member, Oid role)
Definition: acl.c:5077
#define OidIsValid(objectId)
Definition: c.h:759

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

2652 {
2653  FILE *file;
2654  List *hba_lines = NIL;
2655  ListCell *line;
2656  List *new_parsed_lines = NIL;
2657  bool ok = true;
2658  MemoryContext oldcxt;
2659  MemoryContext hbacxt;
2660 
2661  file = open_auth_file(HbaFileName, LOG, 0, NULL);
2662  if (file == NULL)
2663  {
2664  /* error already logged */
2665  return false;
2666  }
2667 
2668  tokenize_auth_file(HbaFileName, file, &hba_lines, LOG, 0);
2669 
2670  /* Now parse all the lines */
2673  "hba parser context",
2675  oldcxt = MemoryContextSwitchTo(hbacxt);
2676  foreach(line, hba_lines)
2677  {
2678  TokenizedAuthLine *tok_line = (TokenizedAuthLine *) lfirst(line);
2679  HbaLine *newline;
2680 
2681  /* don't parse lines that already have errors */
2682  if (tok_line->err_msg != NULL)
2683  {
2684  ok = false;
2685  continue;
2686  }
2687 
2688  if ((newline = parse_hba_line(tok_line, LOG)) == NULL)
2689  {
2690  /* Parse error; remember there's trouble */
2691  ok = false;
2692 
2693  /*
2694  * Keep parsing the rest of the file so we can report errors on
2695  * more than the first line. Error has already been logged, no
2696  * need for more chatter here.
2697  */
2698  continue;
2699  }
2700 
2701  new_parsed_lines = lappend(new_parsed_lines, newline);
2702  }
2703 
2704  /*
2705  * A valid HBA file must have at least one entry; else there's no way to
2706  * connect to the postmaster. But only complain about this if we didn't
2707  * already have parsing errors.
2708  */
2709  if (ok && new_parsed_lines == NIL)
2710  {
2711  ereport(LOG,
2712  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2713  errmsg("configuration file \"%s\" contains no entries",
2714  HbaFileName)));
2715  ok = false;
2716  }
2717 
2718  /* Free tokenizer memory */
2719  free_auth_file(file, 0);
2720  MemoryContextSwitchTo(oldcxt);
2721 
2722  if (!ok)
2723  {
2724  /*
2725  * File contained one or more errors, so bail out, first being careful
2726  * to clean up whatever we allocated. Most stuff will go away via
2727  * MemoryContextDelete, but we have to clean up regexes explicitly.
2728  */
2729  foreach(line, new_parsed_lines)
2730  {
2731  HbaLine *newline = (HbaLine *) lfirst(line);
2732 
2734  }
2735  MemoryContextDelete(hbacxt);
2736  return false;
2737  }
2738 
2739  /* Loaded new file successfully, replace the one we use */
2740  if (parsed_hba_lines != NIL)
2741  {
2742  foreach(line, parsed_hba_lines)
2743  {
2744  HbaLine *newline = (HbaLine *) lfirst(line);
2745 
2747  }
2748  }
2749  if (parsed_hba_context != NULL)
2751  parsed_hba_context = hbacxt;
2752  parsed_hba_lines = new_parsed_lines;
2753 
2754  return true;
2755 }
char * HbaFileName
Definition: guc_tables.c:511
FILE * open_auth_file(const char *filename, int elevel, int depth, char **err_msg)
Definition: hba.c:651
static void free_hba_line(HbaLine *line)
Definition: hba.c:324
static MemoryContext parsed_hba_context
Definition: hba.c:93
void free_auth_file(FILE *file, int depth)
Definition: hba.c:626
HbaLine * parse_hba_line(TokenizedAuthLine *tok_line, int elevel)
Definition: hba.c:1378
void tokenize_auth_file(const char *filename, FILE *file, List **tok_lines, int elevel, int depth)
Definition: hba.c:742
#define newline
Definition: indent_codes.h:35
Assert(fmt[strlen(fmt) - 1] !='\n')
List * lappend(List *list, void *datum)
Definition: list.c:338
MemoryContext PostmasterContext
Definition: mcxt.c:143
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:163
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:138
#define NIL
Definition: pg_list.h:68
Definition: pg_list.h:54
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 process_pm_reload_request().

◆ load_ident()

bool load_ident ( void  )

Definition at line 3043 of file hba.c.

3044 {
3045  FILE *file;
3046  List *ident_lines = NIL;
3047  ListCell *line_cell,
3048  *parsed_line_cell;
3049  List *new_parsed_lines = NIL;
3050  bool ok = true;
3051  MemoryContext oldcxt;
3052  MemoryContext ident_context;
3053  IdentLine *newline;
3054 
3055  /* not FATAL ... we just won't do any special ident maps */
3056  file = open_auth_file(IdentFileName, LOG, 0, NULL);
3057  if (file == NULL)
3058  {
3059  /* error already logged */
3060  return false;
3061  }
3062 
3063  tokenize_auth_file(IdentFileName, file, &ident_lines, LOG, 0);
3064 
3065  /* Now parse all the lines */
3067  ident_context = AllocSetContextCreate(PostmasterContext,
3068  "ident parser context",
3070  oldcxt = MemoryContextSwitchTo(ident_context);
3071  foreach(line_cell, ident_lines)
3072  {
3073  TokenizedAuthLine *tok_line = (TokenizedAuthLine *) lfirst(line_cell);
3074 
3075  /* don't parse lines that already have errors */
3076  if (tok_line->err_msg != NULL)
3077  {
3078  ok = false;
3079  continue;
3080  }
3081 
3082  if ((newline = parse_ident_line(tok_line, LOG)) == NULL)
3083  {
3084  /* Parse error; remember there's trouble */
3085  ok = false;
3086 
3087  /*
3088  * Keep parsing the rest of the file so we can report errors on
3089  * more than the first line. Error has already been logged, no
3090  * need for more chatter here.
3091  */
3092  continue;
3093  }
3094 
3095  new_parsed_lines = lappend(new_parsed_lines, newline);
3096  }
3097 
3098  /* Free tokenizer memory */
3099  free_auth_file(file, 0);
3100  MemoryContextSwitchTo(oldcxt);
3101 
3102  if (!ok)
3103  {
3104  /*
3105  * File contained one or more errors, so bail out, first being careful
3106  * to clean up whatever we allocated. Most stuff will go away via
3107  * MemoryContextDelete, but we have to clean up regexes explicitly.
3108  */
3109  foreach(parsed_line_cell, new_parsed_lines)
3110  {
3111  newline = (IdentLine *) lfirst(parsed_line_cell);
3112  free_auth_token(newline->system_user);
3113  free_auth_token(newline->pg_user);
3114  }
3115  MemoryContextDelete(ident_context);
3116  return false;
3117  }
3118 
3119  /* Loaded new file successfully, replace the one we use */
3120  if (parsed_ident_lines != NIL)
3121  {
3122  foreach(parsed_line_cell, parsed_ident_lines)
3123  {
3124  newline = (IdentLine *) lfirst(parsed_line_cell);
3125  free_auth_token(newline->system_user);
3126  free_auth_token(newline->pg_user);
3127  }
3128  }
3129  if (parsed_ident_context != NULL)
3131 
3132  parsed_ident_context = ident_context;
3133  parsed_ident_lines = new_parsed_lines;
3134 
3135  return true;
3136 }
char * IdentFileName
Definition: guc_tables.c:512
IdentLine * parse_ident_line(TokenizedAuthLine *tok_line, int elevel)
Definition: hba.c:2773
static MemoryContext parsed_ident_context
Definition: hba.c:105
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 process_pm_reload_request().

◆ make_auth_token()

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

Definition at line 292 of file hba.c.

293 {
294  AuthToken *authtoken;
295  int toklen;
296 
297  toklen = strlen(token);
298  /* we copy string into same palloc block as the struct */
299  authtoken = (AuthToken *) palloc0(sizeof(AuthToken) + toklen + 1);
300  authtoken->string = (char *) authtoken + sizeof(AuthToken);
301  authtoken->quoted = quoted;
302  authtoken->regex = NULL;
303  memcpy(authtoken->string, token, toklen + 1);
304 
305  return authtoken;
306 }

References palloc0(), AuthToken::quoted, AuthToken::regex, AuthToken::string, and token.

Referenced by check_ident_usermap(), 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 438 of file hba.c.

440 {
441  char buf[MAX_TOKEN];
442  bool trailing_comma;
443  bool initial_quote;
444  List *tokens = NIL;
445 
446  do
447  {
448  if (!next_token(lineptr, buf, sizeof(buf),
449  &initial_quote, &trailing_comma,
450  elevel, err_msg))
451  break;
452 
453  /* Is this referencing a file? */
454  if (!initial_quote && buf[0] == '@' && buf[1] != '\0')
455  tokens = tokenize_expand_file(tokens, filename, buf + 1,
456  elevel, depth + 1, err_msg);
457  else
458  {
459  MemoryContext oldcxt;
460 
461  /*
462  * lappend() may do its own allocations, so move to the context
463  * for the list of tokens.
464  */
466  tokens = lappend(tokens, make_auth_token(buf, initial_quote));
467  MemoryContextSwitchTo(oldcxt);
468  }
469  } while (trailing_comma && (*err_msg == NULL));
470 
471  return tokens;
472 }
static bool next_token(char **lineptr, char *buf, int bufsz, bool *initial_quote, bool *terminating_comma, int elevel, char **err_msg)
Definition: hba.c:199
#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:549
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 199 of file hba.c.

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

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

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

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

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

2774 {
2775  int line_num = tok_line->line_num;
2776  char *file_name = tok_line->file_name;
2777  char **err_msg = &tok_line->err_msg;
2778  ListCell *field;
2779  List *tokens;
2780  AuthToken *token;
2781  IdentLine *parsedline;
2782 
2783  Assert(tok_line->fields != NIL);
2784  field = list_head(tok_line->fields);
2785 
2786  parsedline = palloc0(sizeof(IdentLine));
2787  parsedline->linenumber = line_num;
2788 
2789  /* Get the map token (must exist) */
2790  tokens = lfirst(field);
2791  IDENT_MULTI_VALUE(tokens);
2792  token = linitial(tokens);
2793  parsedline->usermap = pstrdup(token->string);
2794 
2795  /* Get the ident user token */
2796  field = lnext(tok_line->fields, field);
2797  IDENT_FIELD_ABSENT(field);
2798  tokens = lfirst(field);
2799  IDENT_MULTI_VALUE(tokens);
2800  token = linitial(tokens);
2801 
2802  /* Copy the ident user token */
2803  parsedline->system_user = copy_auth_token(token);
2804 
2805  /* Get the PG rolename token */
2806  field = lnext(tok_line->fields, field);
2807  IDENT_FIELD_ABSENT(field);
2808  tokens = lfirst(field);
2809  IDENT_MULTI_VALUE(tokens);
2810  token = linitial(tokens);
2811  parsedline->pg_user = copy_auth_token(token);
2812 
2813  /*
2814  * Now that the field validation is done, compile a regex from the user
2815  * tokens, if necessary.
2816  */
2817  if (regcomp_auth_token(parsedline->system_user, file_name, line_num,
2818  err_msg, elevel))
2819  {
2820  /* err_msg includes the error to report */
2821  return NULL;
2822  }
2823 
2824  if (regcomp_auth_token(parsedline->pg_user, file_name, line_num,
2825  err_msg, elevel))
2826  {
2827  /* err_msg includes the error to report */
2828  return NULL;
2829  }
2830 
2831  return parsedline;
2832 }
#define IDENT_FIELD_ABSENT(field)
Definition: hba.c:1338
#define IDENT_MULTI_VALUE(tokens)
Definition: hba.c:1351
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_user, pstrdup(), regcomp_auth_token(), IdentLine::system_user, token, and IdentLine::usermap.

Referenced by fill_ident_view(), and load_ident().

◆ pg_isblank()

bool pg_isblank ( const char  c)

Definition at line 156 of file hba.c.

157 {
158  return c == ' ' || c == '\t' || c == '\r';
159 }

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

362 {
363  pg_wchar *wstr;
364  int wlen;
365  int rc;
366 
367  Assert(token->regex == NULL);
368 
369  if (token->string[0] != '/')
370  return 0; /* nothing to compile */
371 
372  token->regex = (regex_t *) palloc0(sizeof(regex_t));
373  wstr = palloc((strlen(token->string + 1) + 1) * sizeof(pg_wchar));
374  wlen = pg_mb2wchar_with_len(token->string + 1,
375  wstr, strlen(token->string + 1));
376 
377  rc = pg_regcomp(token->regex, wstr, wlen, REG_ADVANCED, C_COLLATION_OID);
378 
379  if (rc)
380  {
381  char errstr[100];
382 
383  pg_regerror(rc, token->regex, errstr, sizeof(errstr));
384  ereport(elevel,
385  (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
386  errmsg("invalid regular expression \"%s\": %s",
387  token->string + 1, errstr),
388  errcontext("line %d of configuration file \"%s\"",
389  line_num, filename)));
390 
391  *err_msg = psprintf("invalid regular expression \"%s\": %s",
392  token->string + 1, errstr);
393  }
394 
395  pfree(wstr);
396  return rc;
397 }
unsigned int pg_wchar
Definition: mbprint.c:31
int pg_mb2wchar_with_len(const char *from, pg_wchar *to, int len)
Definition: mbutils.c:987
void * palloc(Size size)
Definition: mcxt.c:1210
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, and token.

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

407 {
408  pg_wchar *wmatchstr;
409  int wmatchlen;
410  int r;
411 
412  Assert(token->string[0] == '/' && token->regex);
413 
414  wmatchstr = palloc((strlen(match) + 1) * sizeof(pg_wchar));
415  wmatchlen = pg_mb2wchar_with_len(match, wmatchstr, strlen(match));
416 
417  r = pg_regexec(token->regex, wmatchstr, wmatchlen, 0, NULL, nmatch, pmatch, 0);
418 
419  pfree(wmatchstr);
420  return r;
421 }
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(), and token.

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

◆ StaticAssertDecl()

StaticAssertDecl ( lengthof(UserAuthName = =USER_AUTH_LAST+1,
"UserAuthName []must match the UserAuth enum"   
)

◆ tokenize_auth_file()

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

Definition at line 742 of file hba.c.

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

714 {
716 
717  errcontext("line %d of configuration file \"%s\"",
718  callback_arg->linenum, callback_arg->filename);
719 }
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 549 of file hba.c.

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

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

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

Referenced by load_hba().

◆ parsed_hba_lines

List* parsed_hba_lines = NIL
static

Definition at line 92 of file hba.c.

Referenced by check_hba(), and load_hba().

◆ parsed_ident_context

MemoryContext parsed_ident_context = NULL
static

Definition at line 105 of file hba.c.

Referenced by load_ident().

◆ parsed_ident_lines

List* parsed_ident_lines = NIL
static

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

Referenced by hba_authname().