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 , uaPeer
}
 
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 
uaPeer 

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
@ uaPeer
Definition: hba.h:41
@ 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 2904 of file hba.c.

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

571 {
572  FreeFile(file);
573 
574  /* If this is the last cleanup, remove the tokenization context */
575  if (depth == CONF_FILE_START_DEPTH)
576  {
578  tokenize_context = NULL;
579  }
580 }
#define CONF_FILE_START_DEPTH
Definition: conffiles.h:17
int FreeFile(FILE *file)
Definition: fd.c:2781
static MemoryContext tokenize_context
Definition: hba.c:79
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454

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

3062 {
3063  return UserAuthName[auth_method];
3064 }
static const char *const UserAuthName[]
Definition: hba.c:101

References UserAuthName.

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

◆ hba_getauthmethod()

void hba_getauthmethod ( hbaPort port)

Definition at line 3048 of file hba.c.

3049 {
3050  check_hba(port);
3051 }
static void check_hba(hbaPort *port)
Definition: hba.c:2469
static int port
Definition: pg_regress.c:116

References check_hba(), and port.

Referenced by ClientAuthentication().

◆ load_hba()

bool load_hba ( void  )

Definition at line 2583 of file hba.c.

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

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

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

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

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

145 {
146  return c == ' ' || c == '\t' || c == '\r';
147 }
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 686 of file hba.c.

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

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