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

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

3066 {
3067  return UserAuthName[auth_method];
3068 }
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 3052 of file hba.c.

3053 {
3054  check_hba(port);
3055 }
static void check_hba(hbaPort *port)
Definition: hba.c:2473
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 2587 of file hba.c.

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

2964 {
2965  FILE *file;
2966  List *ident_lines = NIL;
2967  ListCell *line_cell;
2968  List *new_parsed_lines = NIL;
2969  bool ok = true;
2970  MemoryContext oldcxt;
2971  MemoryContext ident_context;
2972  IdentLine *newline;
2973 
2974  /* not FATAL ... we just won't do any special ident maps */
2975  file = open_auth_file(IdentFileName, LOG, 0, NULL);
2976  if (file == NULL)
2977  {
2978  /* error already logged */
2979  return false;
2980  }
2981 
2982  tokenize_auth_file(IdentFileName, file, &ident_lines, LOG, 0);
2983 
2984  /* Now parse all the lines */
2986  ident_context = AllocSetContextCreate(PostmasterContext,
2987  "ident parser context",
2989  oldcxt = MemoryContextSwitchTo(ident_context);
2990  foreach(line_cell, ident_lines)
2991  {
2992  TokenizedAuthLine *tok_line = (TokenizedAuthLine *) lfirst(line_cell);
2993 
2994  /* don't parse lines that already have errors */
2995  if (tok_line->err_msg != NULL)
2996  {
2997  ok = false;
2998  continue;
2999  }
3000 
3001  if ((newline = parse_ident_line(tok_line, LOG)) == NULL)
3002  {
3003  /* Parse error; remember there's trouble */
3004  ok = false;
3005 
3006  /*
3007  * Keep parsing the rest of the file so we can report errors on
3008  * more than the first line. Error has already been logged, no
3009  * need for more chatter here.
3010  */
3011  continue;
3012  }
3013 
3014  new_parsed_lines = lappend(new_parsed_lines, newline);
3015  }
3016 
3017  /* Free tokenizer memory */
3018  free_auth_file(file, 0);
3019  MemoryContextSwitchTo(oldcxt);
3020 
3021  if (!ok)
3022  {
3023  /*
3024  * File contained one or more errors, so bail out. MemoryContextDelete
3025  * is enough to clean up everything, including regexes.
3026  */
3027  MemoryContextDelete(ident_context);
3028  return false;
3029  }
3030 
3031  /* Loaded new file successfully, replace the one we use */
3032  if (parsed_ident_context != NULL)
3034 
3035  parsed_ident_context = ident_context;
3036  parsed_ident_lines = new_parsed_lines;
3037 
3038  return true;
3039 }
char * IdentFileName
Definition: guc_tables.c:540
IdentLine * parse_ident_line(TokenizedAuthLine *tok_line, int elevel)
Definition: hba.c:2693
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  {
628  errno = save_errno;
629  *err_msg = psprintf("could not open file \"%s\": %m",
630  filename);
631  }
632  /* the caller may care about some specific errno */
633  errno = save_errno;
634  return NULL;
635  }
636 
637  /*
638  * When opening the top-level file, create the memory context used for the
639  * tokenization. This will be closed with this file when coming back to
640  * this level of cleanup.
641  */
642  if (depth == CONF_FILE_START_DEPTH)
643  {
644  /*
645  * A context may be present, but assume that it has been eliminated
646  * already.
647  */
649  "tokenize_context",
651  }
652 
653  return file;
654 }
#define CONF_FILE_MAX_DEPTH
Definition: conffiles.h:18
int errcode_for_file_access(void)
Definition: elog.c:876
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2606
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
#define ALLOCSET_START_SMALL_SIZES
Definition: memutils.h:177
static char * filename
Definition: pg_dumpall.c:119
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(), 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 1326 of file hba.c.

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

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

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