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

Go to the source code of this file.

Data Structures

struct  AuthToken
 
struct  HbaLine
 
struct  IdentLine
 
struct  TokenizedAuthLine
 

Macros

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

Typedefs

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

Enumerations

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

Functions

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

Macro Definition Documentation

◆ USER_AUTH_LAST

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

Definition at line 42 of file hba.h.

Typedef Documentation

◆ AuthToken

typedef struct AuthToken AuthToken

◆ ClientCertMode

◆ ClientCertName

◆ ConnType

typedef enum ConnType ConnType

◆ HbaLine

typedef struct HbaLine HbaLine

◆ hbaPort

typedef struct Port hbaPort

Definition at line 1 of file hba.h.

◆ IdentLine

typedef struct IdentLine IdentLine

◆ IPCompareMethod

◆ TokenizedAuthLine

◆ UserAuth

typedef enum UserAuth UserAuth

Enumeration Type Documentation

◆ ClientCertMode

Enumerator
clientCertOff 
clientCertCA 
clientCertFull 

Definition at line 67 of file hba.h.

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

◆ ClientCertName

Enumerator
clientCertCN 
clientCertDN 

Definition at line 74 of file hba.h.

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

◆ ConnType

enum ConnType
Enumerator
ctLocal 
ctHost 
ctHostSSL 
ctHostNoSSL 
ctHostGSS 
ctHostNoGSS 

Definition at line 57 of file hba.h.

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

◆ IPCompareMethod

Enumerator
ipCmpMask 
ipCmpSameHost 
ipCmpSameNet 
ipCmpAll 

Definition at line 49 of file hba.h.

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

◆ UserAuth

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

Definition at line 25 of file hba.h.

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

Function Documentation

◆ check_usermap()

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

Definition at line 2988 of file hba.c.

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

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

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

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

◆ hba_authname()

const char* hba_authname ( UserAuth  auth_method)

Definition at line 3162 of file hba.c.

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

References UserAuthName.

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

◆ hba_getauthmethod()

void hba_getauthmethod ( hbaPort port)

Definition at line 3149 of file hba.c.

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

References check_hba(), and port.

Referenced by ClientAuthentication().

◆ load_hba()

bool load_hba ( void  )

Definition at line 2651 of file hba.c.

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

Referenced by PerformAuthentication(), PostmasterMain(), and process_pm_reload_request().

◆ load_ident()

bool load_ident ( void  )

Definition at line 3043 of file hba.c.

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

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate, Assert(), TokenizedAuthLine::err_msg, free_auth_file(), free_auth_token(), IdentFileName, lappend(), lfirst, LOG, MemoryContextDelete(), MemoryContextSwitchTo(), newline, NIL, open_auth_file(), parse_ident_line(), parsed_ident_context, parsed_ident_lines, PostmasterContext, and tokenize_auth_file().

Referenced by PerformAuthentication(), PostmasterMain(), and process_pm_reload_request().

◆ open_auth_file()

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

Definition at line 651 of file hba.c.

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

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

Referenced by fill_hba_view(), and load_hba().

◆ parse_ident_line()

IdentLine* parse_ident_line ( TokenizedAuthLine tok_line,
int  elevel 
)

Definition at line 2773 of file hba.c.

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

157 {
158  return c == ' ' || c == '\t' || c == '\r';
159 }
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 742 of file hba.c.

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

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

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