PostgreSQL Source Code  git master
hba.h File Reference
#include "libpq/pqcomm.h"
#include "nodes/pg_list.h"
#include "regex/regex.h"
Include dependency graph for hba.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  AuthToken
 
struct  HbaLine
 
struct  IdentLine
 
struct  TokenizedAuthLine
 

Macros

#define USER_AUTH_LAST   uaPeer /* Must be last value of this enum */
 

Typedefs

typedef enum UserAuth UserAuth
 
typedef enum IPCompareMethod IPCompareMethod
 
typedef enum ConnType ConnType
 
typedef enum ClientCertMode ClientCertMode
 
typedef enum ClientCertName ClientCertName
 
typedef struct AuthToken AuthToken
 
typedef struct HbaLine HbaLine
 
typedef struct IdentLine IdentLine
 
typedef struct TokenizedAuthLine TokenizedAuthLine
 
typedef struct Port hbaPort
 

Enumerations

enum  UserAuth {
  uaReject , uaImplicitReject , uaTrust , uaIdent ,
  uaPassword , uaMD5 , uaSCRAM , uaGSS ,
  uaSSPI , uaPAM , uaBSD , uaLDAP ,
  uaCert , uaRADIUS
}
 
enum  IPCompareMethod { ipCmpMask , ipCmpSameHost , ipCmpSameNet , ipCmpAll }
 
enum  ConnType {
  ctLocal , ctHost , ctHostSSL , ctHostNoSSL ,
  ctHostGSS , ctHostNoGSS
}
 
enum  ClientCertMode { clientCertOff , clientCertCA , clientCertFull }
 
enum  ClientCertName { clientCertCN , clientCertDN }
 

Functions

bool load_hba (void)
 
bool load_ident (void)
 
const char * hba_authname (UserAuth auth_method)
 
void hba_getauthmethod (hbaPort *port)
 
int check_usermap (const char *usermap_name, const char *pg_user, const char *system_user, bool case_insensitive)
 
HbaLineparse_hba_line (TokenizedAuthLine *tok_line, int elevel)
 
IdentLineparse_ident_line (TokenizedAuthLine *tok_line, int elevel)
 
bool pg_isblank (const char c)
 
FILE * open_auth_file (const char *filename, int elevel, int depth, char **err_msg)
 
void free_auth_file (FILE *file, int depth)
 
void tokenize_auth_file (const char *filename, FILE *file, List **tok_lines, int elevel, int depth)
 

Macro Definition Documentation

◆ USER_AUTH_LAST

#define USER_AUTH_LAST   uaPeer /* Must be last value of this enum */

Definition at line 42 of file hba.h.

Typedef Documentation

◆ AuthToken

typedef struct AuthToken AuthToken

◆ ClientCertMode

◆ ClientCertName

◆ ConnType

typedef enum ConnType ConnType

◆ HbaLine

typedef struct HbaLine HbaLine

◆ hbaPort

typedef struct Port hbaPort

Definition at line 1 of file hba.h.

◆ IdentLine

typedef struct IdentLine IdentLine

◆ IPCompareMethod

◆ TokenizedAuthLine

◆ UserAuth

typedef enum UserAuth UserAuth

Enumeration Type Documentation

◆ ClientCertMode

Enumerator
clientCertOff 
clientCertCA 
clientCertFull 

Definition at line 67 of file hba.h.

68 {
ClientCertMode
Definition: hba.h:68
@ clientCertOff
Definition: hba.h:69
@ clientCertFull
Definition: hba.h:71
@ clientCertCA
Definition: hba.h:70

◆ ClientCertName

Enumerator
clientCertCN 
clientCertDN 

Definition at line 74 of file hba.h.

75 {
ClientCertName
Definition: hba.h:75
@ clientCertDN
Definition: hba.h:77
@ clientCertCN
Definition: hba.h:76

◆ ConnType

enum ConnType
Enumerator
ctLocal 
ctHost 
ctHostSSL 
ctHostNoSSL 
ctHostGSS 
ctHostNoGSS 

Definition at line 57 of file hba.h.

58 {
59  ctLocal,
60  ctHost,
61  ctHostSSL,
63  ctHostGSS,
65 } ConnType;
ConnType
Definition: hba.h:58
@ ctHostNoGSS
Definition: hba.h:64
@ ctHostSSL
Definition: hba.h:61
@ ctHostNoSSL
Definition: hba.h:62
@ ctHost
Definition: hba.h:60
@ ctHostGSS
Definition: hba.h:63
@ ctLocal
Definition: hba.h:59

◆ IPCompareMethod

Enumerator
ipCmpMask 
ipCmpSameHost 
ipCmpSameNet 
ipCmpAll 

Definition at line 49 of file hba.h.

50 {
51  ipCmpMask,
54  ipCmpAll
IPCompareMethod
Definition: hba.h:50
@ ipCmpAll
Definition: hba.h:54
@ ipCmpSameNet
Definition: hba.h:53
@ ipCmpMask
Definition: hba.h:51
@ ipCmpSameHost
Definition: hba.h:52

◆ UserAuth

enum UserAuth
Enumerator
uaReject 
uaImplicitReject 
uaTrust 
uaIdent 
uaPassword 
uaMD5 
uaSCRAM 
uaGSS 
uaSSPI 
uaPAM 
uaBSD 
uaLDAP 
uaCert 
uaRADIUS 

Definition at line 25 of file hba.h.

26 {
27  uaReject,
28  uaImplicitReject, /* Not a user-visible option */
29  uaTrust,
30  uaIdent,
31  uaPassword,
32  uaMD5,
33  uaSCRAM,
34  uaGSS,
35  uaSSPI,
36  uaPAM,
37  uaBSD,
38  uaLDAP,
39  uaCert,
40  uaRADIUS,
41  uaPeer
42 #define USER_AUTH_LAST uaPeer /* Must be last value of this enum */
43 } UserAuth;
UserAuth
Definition: hba.h:26
@ uaBSD
Definition: hba.h:37
@ uaLDAP
Definition: hba.h:38
@ uaPAM
Definition: hba.h:36
@ uaPassword
Definition: hba.h:31
@ uaCert
Definition: hba.h:39
@ uaMD5
Definition: hba.h:32
@ uaReject
Definition: hba.h:27
@ uaGSS
Definition: hba.h:34
@ uaSCRAM
Definition: hba.h:33
@ uaImplicitReject
Definition: hba.h:28
@ uaRADIUS
Definition: hba.h:40
@ uaIdent
Definition: hba.h:30
@ uaTrust
Definition: hba.h:29
@ uaSSPI
Definition: hba.h:35

Function Documentation

◆ check_usermap()

int check_usermap ( const char *  usermap_name,
const char *  pg_user,
const char *  system_user,
bool  case_insensitive 
)

Definition at line 2909 of file hba.c.

2913 {
2914  bool found_entry = false,
2915  error = false;
2916 
2917  if (usermap_name == NULL || usermap_name[0] == '\0')
2918  {
2919  if (case_insensitive)
2920  {
2921  if (pg_strcasecmp(pg_user, system_user) == 0)
2922  return STATUS_OK;
2923  }
2924  else
2925  {
2926  if (strcmp(pg_user, system_user) == 0)
2927  return STATUS_OK;
2928  }
2929  ereport(LOG,
2930  (errmsg("provided user name (%s) and authenticated user name (%s) do not match",
2931  pg_user, system_user)));
2932  return STATUS_ERROR;
2933  }
2934  else
2935  {
2936  ListCell *line_cell;
2937 
2938  foreach(line_cell, parsed_ident_lines)
2939  {
2940  check_ident_usermap(lfirst(line_cell), usermap_name,
2941  pg_user, system_user, case_insensitive,
2942  &found_entry, &error);
2943  if (found_entry || error)
2944  break;
2945  }
2946  }
2947  if (!found_entry && !error)
2948  {
2949  ereport(LOG,
2950  (errmsg("no match in usermap \"%s\" for user \"%s\" authenticated as \"%s\"",
2951  usermap_name, pg_user, system_user)));
2952  }
2953  return found_entry ? STATUS_OK : STATUS_ERROR;
2954 }
#define STATUS_OK
Definition: c.h:1182
#define STATUS_ERROR
Definition: c.h:1183
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define LOG
Definition: elog.h:31
#define ereport(elevel,...)
Definition: elog.h:149
static List * parsed_ident_lines
Definition: hba.c:97
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:2762
Datum system_user(PG_FUNCTION_ARGS)
Definition: miscinit.c:877
#define lfirst(lc)
Definition: pg_list.h:172
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().

◆ free_auth_file()

void free_auth_file ( FILE *  file,
int  depth 
)

Definition at line 575 of file hba.c.

576 {
577  FreeFile(file);
578 
579  /* If this is the last cleanup, remove the tokenization context */
580  if (depth == CONF_FILE_START_DEPTH)
581  {
583  tokenize_context = NULL;
584  }
585 }
#define CONF_FILE_START_DEPTH
Definition: conffiles.h:17
int FreeFile(FILE *file)
Definition: fd.c:2726
static MemoryContext tokenize_context
Definition: hba.c:84
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:403

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().

◆ hba_authname()

const char* hba_authname ( UserAuth  auth_method)

Definition at line 3066 of file hba.c.

3067 {
3068  return UserAuthName[auth_method];
3069 }
static const char *const UserAuthName[]
Definition: hba.c:106

References UserAuthName.

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

◆ hba_getauthmethod()

void hba_getauthmethod ( hbaPort port)

Definition at line 3053 of file hba.c.

3054 {
3055  check_hba(port);
3056 }
static void check_hba(hbaPort *port)
Definition: hba.c:2474
static int port
Definition: pg_regress.c:109

References check_hba(), and port.

Referenced by ClientAuthentication().

◆ load_hba()

bool load_hba ( void  )

Definition at line 2588 of file hba.c.

2589 {
2590  FILE *file;
2591  List *hba_lines = NIL;
2592  ListCell *line;
2593  List *new_parsed_lines = NIL;
2594  bool ok = true;
2595  MemoryContext oldcxt;
2596  MemoryContext hbacxt;
2597 
2598  file = open_auth_file(HbaFileName, LOG, 0, NULL);
2599  if (file == NULL)
2600  {
2601  /* error already logged */
2602  return false;
2603  }
2604 
2605  tokenize_auth_file(HbaFileName, file, &hba_lines, LOG, 0);
2606 
2607  /* Now parse all the lines */
2610  "hba parser context",
2612  oldcxt = MemoryContextSwitchTo(hbacxt);
2613  foreach(line, hba_lines)
2614  {
2615  TokenizedAuthLine *tok_line = (TokenizedAuthLine *) lfirst(line);
2616  HbaLine *newline;
2617 
2618  /* don't parse lines that already have errors */
2619  if (tok_line->err_msg != NULL)
2620  {
2621  ok = false;
2622  continue;
2623  }
2624 
2625  if ((newline = parse_hba_line(tok_line, LOG)) == NULL)
2626  {
2627  /* Parse error; remember there's trouble */
2628  ok = false;
2629 
2630  /*
2631  * Keep parsing the rest of the file so we can report errors on
2632  * more than the first line. Error has already been logged, no
2633  * need for more chatter here.
2634  */
2635  continue;
2636  }
2637 
2638  new_parsed_lines = lappend(new_parsed_lines, newline);
2639  }
2640 
2641  /*
2642  * A valid HBA file must have at least one entry; else there's no way to
2643  * connect to the postmaster. But only complain about this if we didn't
2644  * already have parsing errors.
2645  */
2646  if (ok && new_parsed_lines == NIL)
2647  {
2648  ereport(LOG,
2649  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2650  errmsg("configuration file \"%s\" contains no entries",
2651  HbaFileName)));
2652  ok = false;
2653  }
2654 
2655  /* Free tokenizer memory */
2656  free_auth_file(file, 0);
2657  MemoryContextSwitchTo(oldcxt);
2658 
2659  if (!ok)
2660  {
2661  /*
2662  * File contained one or more errors, so bail out. MemoryContextDelete
2663  * is enough to clean up everything, including regexes.
2664  */
2665  MemoryContextDelete(hbacxt);
2666  return false;
2667  }
2668 
2669  /* Loaded new file successfully, replace the one we use */
2670  if (parsed_hba_context != NULL)
2672  parsed_hba_context = hbacxt;
2673  parsed_hba_lines = new_parsed_lines;
2674 
2675  return true;
2676 }
int errcode(int sqlerrcode)
Definition: elog.c:858
char * HbaFileName
Definition: guc_tables.c:537
FILE * open_auth_file(const char *filename, int elevel, int depth, char **err_msg)
Definition: hba.c:600
static MemoryContext parsed_hba_context
Definition: hba.c:91
void free_auth_file(FILE *file, int depth)
Definition: hba.c:575
HbaLine * parse_hba_line(TokenizedAuthLine *tok_line, int elevel)
Definition: hba.c:1327
static List * parsed_hba_lines
Definition: hba.c:90
void tokenize_auth_file(const char *filename, FILE *file, List **tok_lines, int elevel, int depth)
Definition: hba.c:691
#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: hba.h:95
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(), 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 2964 of file hba.c.

2965 {
2966  FILE *file;
2967  List *ident_lines = NIL;
2968  ListCell *line_cell;
2969  List *new_parsed_lines = NIL;
2970  bool ok = true;
2971  MemoryContext oldcxt;
2972  MemoryContext ident_context;
2973  IdentLine *newline;
2974 
2975  /* not FATAL ... we just won't do any special ident maps */
2976  file = open_auth_file(IdentFileName, LOG, 0, NULL);
2977  if (file == NULL)
2978  {
2979  /* error already logged */
2980  return false;
2981  }
2982 
2983  tokenize_auth_file(IdentFileName, file, &ident_lines, LOG, 0);
2984 
2985  /* Now parse all the lines */
2987  ident_context = AllocSetContextCreate(PostmasterContext,
2988  "ident parser context",
2990  oldcxt = MemoryContextSwitchTo(ident_context);
2991  foreach(line_cell, ident_lines)
2992  {
2993  TokenizedAuthLine *tok_line = (TokenizedAuthLine *) lfirst(line_cell);
2994 
2995  /* don't parse lines that already have errors */
2996  if (tok_line->err_msg != NULL)
2997  {
2998  ok = false;
2999  continue;
3000  }
3001 
3002  if ((newline = parse_ident_line(tok_line, LOG)) == NULL)
3003  {
3004  /* Parse error; remember there's trouble */
3005  ok = false;
3006 
3007  /*
3008  * Keep parsing the rest of the file so we can report errors on
3009  * more than the first line. Error has already been logged, no
3010  * need for more chatter here.
3011  */
3012  continue;
3013  }
3014 
3015  new_parsed_lines = lappend(new_parsed_lines, newline);
3016  }
3017 
3018  /* Free tokenizer memory */
3019  free_auth_file(file, 0);
3020  MemoryContextSwitchTo(oldcxt);
3021 
3022  if (!ok)
3023  {
3024  /*
3025  * File contained one or more errors, so bail out. MemoryContextDelete
3026  * is enough to clean up everything, including regexes.
3027  */
3028  MemoryContextDelete(ident_context);
3029  return false;
3030  }
3031 
3032  /* Loaded new file successfully, replace the one we use */
3033  if (parsed_ident_context != NULL)
3035 
3036  parsed_ident_context = ident_context;
3037  parsed_ident_lines = new_parsed_lines;
3038 
3039  return true;
3040 }
char * IdentFileName
Definition: guc_tables.c:538
IdentLine * parse_ident_line(TokenizedAuthLine *tok_line, int elevel)
Definition: hba.c:2694
static MemoryContext parsed_ident_context
Definition: hba.c:98
Definition: hba.h:141

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate, Assert(), TokenizedAuthLine::err_msg, free_auth_file(), 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().

◆ open_auth_file()

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

Definition at line 600 of file hba.c.

602 {
603  FILE *file;
604 
605  /*
606  * Reject too-deep include nesting depth. This is just a safety check to
607  * avoid dumping core due to stack overflow if an include file loops back
608  * to itself. The maximum nesting depth is pretty arbitrary.
609  */
610  if (depth > CONF_FILE_MAX_DEPTH)
611  {
612  ereport(elevel,
614  errmsg("could not open file \"%s\": maximum nesting depth exceeded",
615  filename)));
616  if (err_msg)
617  *err_msg = psprintf("could not open file \"%s\": maximum nesting depth exceeded",
618  filename);
619  return NULL;
620  }
621 
622  file = AllocateFile(filename, "r");
623  if (file == NULL)
624  {
625  int save_errno = errno;
626 
627  ereport(elevel,
629  errmsg("could not open file \"%s\": %m",
630  filename)));
631  if (err_msg)
632  *err_msg = psprintf("could not open file \"%s\": %s",
633  filename, strerror(save_errno));
634  /* the caller may care about some specific errno */
635  errno = save_errno;
636  return NULL;
637  }
638 
639  /*
640  * When opening the top-level file, create the memory context used for the
641  * tokenization. This will be closed with this file when coming back to
642  * this level of cleanup.
643  */
644  if (depth == CONF_FILE_START_DEPTH)
645  {
646  /*
647  * A context may be present, but assume that it has been eliminated
648  * already.
649  */
651  "tokenize_context",
653  }
654 
655  return file;
656 }
#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:2528
MemoryContext CurrentMemoryContext
Definition: mcxt.c:135
#define ALLOCSET_START_SMALL_SIZES
Definition: memutils.h:170
static char * filename
Definition: pg_dumpall.c:119
#define strerror
Definition: port.h:251
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46

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_line()

HbaLine* parse_hba_line ( TokenizedAuthLine tok_line,
int  elevel 
)

Definition at line 1327 of file hba.c.

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

2695 {
2696  int line_num = tok_line->line_num;
2697  char *file_name = tok_line->file_name;
2698  char **err_msg = &tok_line->err_msg;
2699  ListCell *field;
2700  List *tokens;
2701  AuthToken *token;
2702  IdentLine *parsedline;
2703 
2704  Assert(tok_line->fields != NIL);
2705  field = list_head(tok_line->fields);
2706 
2707  parsedline = palloc0(sizeof(IdentLine));
2708  parsedline->linenumber = line_num;
2709 
2710  /* Get the map token (must exist) */
2711  tokens = lfirst(field);
2712  IDENT_MULTI_VALUE(tokens);
2713  token = linitial(tokens);
2714  parsedline->usermap = pstrdup(token->string);
2715 
2716  /* Get the ident user token */
2717  field = lnext(tok_line->fields, field);
2718  IDENT_FIELD_ABSENT(field);
2719  tokens = lfirst(field);
2720  IDENT_MULTI_VALUE(tokens);
2721  token = linitial(tokens);
2722 
2723  /* Copy the ident user token */
2724  parsedline->system_user = copy_auth_token(token);
2725 
2726  /* Get the PG rolename token */
2727  field = lnext(tok_line->fields, field);
2728  IDENT_FIELD_ABSENT(field);
2729  tokens = lfirst(field);
2730  IDENT_MULTI_VALUE(tokens);
2731  token = linitial(tokens);
2732  parsedline->pg_user = copy_auth_token(token);
2733 
2734  /*
2735  * Now that the field validation is done, compile a regex from the user
2736  * tokens, if necessary.
2737  */
2738  if (regcomp_auth_token(parsedline->system_user, file_name, line_num,
2739  err_msg, elevel))
2740  {
2741  /* err_msg includes the error to report */
2742  return NULL;
2743  }
2744 
2745  if (regcomp_auth_token(parsedline->pg_user, file_name, line_num,
2746  err_msg, elevel))
2747  {
2748  /* err_msg includes the error to report */
2749  return NULL;
2750  }
2751 
2752  return parsedline;
2753 }
#define IDENT_FIELD_ABSENT(field)
Definition: hba.c:1287
#define IDENT_MULTI_VALUE(tokens)
Definition: hba.c:1300
AuthToken * pg_user
Definition: hba.h:146
AuthToken * system_user
Definition: hba.h:145
char * usermap
Definition: hba.h:144
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 149 of file hba.c.

150 {
151  return c == ' ' || c == '\t' || c == '\r';
152 }
char * c

Referenced by interpret_ident_response(), and next_token().

◆ tokenize_auth_file()

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

Definition at line 691 of file hba.c.

693 {
694  int line_number = 1;
696  MemoryContext linecxt;
697  MemoryContext funccxt; /* context of this function's caller */
698  ErrorContextCallback tokenerrcontext;
699  tokenize_error_callback_arg callback_arg;
700 
702 
703  callback_arg.filename = filename;
704  callback_arg.linenum = line_number;
705 
706  tokenerrcontext.callback = tokenize_error_callback;
707  tokenerrcontext.arg = (void *) &callback_arg;
708  tokenerrcontext.previous = error_context_stack;
709  error_context_stack = &tokenerrcontext;
710 
711  /*
712  * Do all the local tokenization in its own context, to ease the cleanup
713  * of any memory allocated while tokenizing.
714  */
716  "tokenize_auth_file",
718  funccxt = MemoryContextSwitchTo(linecxt);
719 
721 
722  if (depth == CONF_FILE_START_DEPTH)
723  *tok_lines = NIL;
724 
725  while (!feof(file) && !ferror(file))
726  {
727  TokenizedAuthLine *tok_line;
728  MemoryContext oldcxt;
729  char *lineptr;
730  List *current_line = NIL;
731  char *err_msg = NULL;
732  int last_backslash_buflen = 0;
733  int continuations = 0;
734 
735  /* Collect the next input line, handling backslash continuations */
737 
738  while (pg_get_line_append(file, &buf, NULL))
739  {
740  /* Strip trailing newline, including \r in case we're on Windows */
741  buf.len = pg_strip_crlf(buf.data);
742 
743  /*
744  * Check for backslash continuation. The backslash must be after
745  * the last place we found a continuation, else two backslashes
746  * followed by two \n's would behave surprisingly.
747  */
748  if (buf.len > last_backslash_buflen &&
749  buf.data[buf.len - 1] == '\\')
750  {
751  /* Continuation, so strip it and keep reading */
752  buf.data[--buf.len] = '\0';
753  last_backslash_buflen = buf.len;
754  continuations++;
755  continue;
756  }
757 
758  /* Nope, so we have the whole line */
759  break;
760  }
761 
762  if (ferror(file))
763  {
764  /* I/O error! */
765  int save_errno = errno;
766 
767  ereport(elevel,
769  errmsg("could not read file \"%s\": %m", filename)));
770  err_msg = psprintf("could not read file \"%s\": %s",
771  filename, strerror(save_errno));
772  break;
773  }
774 
775  /* Parse fields */
776  lineptr = buf.data;
777  while (*lineptr && err_msg == NULL)
778  {
779  List *current_field;
780 
781  current_field = next_field_expand(filename, &lineptr,
782  elevel, depth, &err_msg);
783  /* add field to line, unless we are at EOL or comment start */
784  if (current_field != NIL)
785  {
786  /*
787  * lappend() may do its own allocations, so move to the
788  * context for the list of tokens.
789  */
791  current_line = lappend(current_line, current_field);
792  MemoryContextSwitchTo(oldcxt);
793  }
794  }
795 
796  /*
797  * Reached EOL; no need to emit line to TokenizedAuthLine list if it's
798  * boring.
799  */
800  if (current_line == NIL && err_msg == NULL)
801  goto next_line;
802 
803  /* If the line is valid, check if that's an include directive */
804  if (err_msg == NULL && list_length(current_line) == 2)
805  {
806  AuthToken *first,
807  *second;
808 
809  first = linitial(linitial_node(List, current_line));
810  second = linitial(lsecond_node(List, current_line));
811 
812  if (strcmp(first->string, "include") == 0)
813  {
814  tokenize_include_file(filename, second->string, tok_lines,
815  elevel, depth + 1, false, &err_msg);
816 
817  if (err_msg)
818  goto process_line;
819 
820  /*
821  * tokenize_auth_file() has taken care of creating the
822  * TokenizedAuthLines.
823  */
824  goto next_line;
825  }
826  else if (strcmp(first->string, "include_dir") == 0)
827  {
828  char **filenames;
829  char *dir_name = second->string;
830  int num_filenames;
831  StringInfoData err_buf;
832 
833  filenames = GetConfFilesInDir(dir_name, filename, elevel,
834  &num_filenames, &err_msg);
835 
836  if (!filenames)
837  {
838  /* the error is in err_msg, so create an entry */
839  goto process_line;
840  }
841 
842  initStringInfo(&err_buf);
843  for (int i = 0; i < num_filenames; i++)
844  {
845  tokenize_include_file(filename, filenames[i], tok_lines,
846  elevel, depth + 1, false, &err_msg);
847  /* cumulate errors if any */
848  if (err_msg)
849  {
850  if (err_buf.len > 0)
851  appendStringInfoChar(&err_buf, '\n');
852  appendStringInfoString(&err_buf, err_msg);
853  }
854  }
855 
856  /* clean up things */
857  for (int i = 0; i < num_filenames; i++)
858  pfree(filenames[i]);
859  pfree(filenames);
860 
861  /*
862  * If there were no errors, the line is fully processed,
863  * bypass the general TokenizedAuthLine processing.
864  */
865  if (err_buf.len == 0)
866  goto next_line;
867 
868  /* Otherwise, process the cumulated errors, if any. */
869  err_msg = err_buf.data;
870  goto process_line;
871  }
872  else if (strcmp(first->string, "include_if_exists") == 0)
873  {
874 
875  tokenize_include_file(filename, second->string, tok_lines,
876  elevel, depth + 1, true, &err_msg);
877  if (err_msg)
878  goto process_line;
879 
880  /*
881  * tokenize_auth_file() has taken care of creating the
882  * TokenizedAuthLines.
883  */
884  goto next_line;
885  }
886  }
887 
888 process_line:
889 
890  /*
891  * General processing: report the error if any and emit line to the
892  * TokenizedAuthLine. This is saved in the memory context dedicated
893  * to this list.
894  */
896  tok_line = (TokenizedAuthLine *) palloc0(sizeof(TokenizedAuthLine));
897  tok_line->fields = current_line;
898  tok_line->file_name = pstrdup(filename);
899  tok_line->line_num = line_number;
900  tok_line->raw_line = pstrdup(buf.data);
901  tok_line->err_msg = err_msg ? pstrdup(err_msg) : NULL;
902  *tok_lines = lappend(*tok_lines, tok_line);
903  MemoryContextSwitchTo(oldcxt);
904 
905 next_line:
906  line_number += continuations + 1;
907  callback_arg.linenum = line_number;
908  }
909 
910  MemoryContextSwitchTo(funccxt);
911  MemoryContextDelete(linecxt);
912 
913  error_context_stack = tokenerrcontext.previous;
914 }
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:384
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:443
static void tokenize_error_callback(void *arg)
Definition: hba.c:662
int i
Definition: isn.c:73
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
static char * buf
Definition: pg_test_fsync.c:67
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
char * string
Definition: hba.h:89
struct ErrorContextCallback * previous
Definition: elog.h:295
void(* callback)(void *arg)
Definition: elog.h:296
const char * filename
Definition: hba.c:69

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().