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_role, const char *auth_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_role,
const char *  auth_user,
bool  case_insensitive 
)

Definition at line 2946 of file hba.c.

2950 {
2951  bool found_entry = false,
2952  error = false;
2953 
2954  if (usermap_name == NULL || usermap_name[0] == '\0')
2955  {
2956  if (case_insensitive)
2957  {
2958  if (pg_strcasecmp(pg_role, auth_user) == 0)
2959  return STATUS_OK;
2960  }
2961  else
2962  {
2963  if (strcmp(pg_role, auth_user) == 0)
2964  return STATUS_OK;
2965  }
2966  ereport(LOG,
2967  (errmsg("provided user name (%s) and authenticated user name (%s) do not match",
2968  pg_role, auth_user)));
2969  return STATUS_ERROR;
2970  }
2971  else
2972  {
2973  ListCell *line_cell;
2974 
2975  foreach(line_cell, parsed_ident_lines)
2976  {
2977  check_ident_usermap(lfirst(line_cell), usermap_name,
2978  pg_role, auth_user, case_insensitive,
2979  &found_entry, &error);
2980  if (found_entry || error)
2981  break;
2982  }
2983  }
2984  if (!found_entry && !error)
2985  {
2986  ereport(LOG,
2987  (errmsg("no match in usermap \"%s\" for user \"%s\" authenticated as \"%s\"",
2988  usermap_name, pg_role, auth_user)));
2989  }
2990  return found_entry ? STATUS_OK : STATUS_ERROR;
2991 }
#define STATUS_OK
Definition: c.h:1108
#define STATUS_ERROR
Definition: c.h:1109
int errmsg(const char *fmt,...)
Definition: elog.c:906
#define LOG
Definition: elog.h:27
#define ereport(elevel,...)
Definition: elog.h:145
static void check_ident_usermap(IdentLine *identLine, const char *usermap_name, const char *pg_role, const char *ident_user, bool case_insensitive, bool *found_p, bool *error_p)
Definition: hba.c:2820
static List * parsed_ident_lines
Definition: hba.c:102
#define lfirst(lc)
Definition: pg_list.h:170
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, and STATUS_OK.

Referenced by auth_peer(), and ident_inet().

◆ free_auth_file()

void free_auth_file ( FILE *  file,
int  depth 
)

Definition at line 618 of file hba.c.

619 {
620  FreeFile(file);
621 
622  /* If this is the last cleanup, remove the tokenization context */
623  if (depth == CONF_FILE_START_DEPTH)
624  {
626  tokenize_context = NULL;
627  }
628 }
#define CONF_FILE_START_DEPTH
Definition: conffiles.h:17
int FreeFile(FILE *file)
Definition: fd.c:2581
static MemoryContext tokenize_context
Definition: hba.c:84
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:376

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

3119 {
3120  /*
3121  * Make sure UserAuthName[] tracks additions to the UserAuth enum
3122  */
3124  "UserAuthName[] must match the UserAuth enum");
3125 
3126  return UserAuthName[auth_method];
3127 }
#define lengthof(array)
Definition: c.h:724
#define StaticAssertStmt(condition, errmessage)
Definition: c.h:869
static const char *const UserAuthName[]
Definition: hba.c:111
#define USER_AUTH_LAST
Definition: hba.h:42

References lengthof, StaticAssertStmt, USER_AUTH_LAST, and UserAuthName.

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

◆ hba_getauthmethod()

void hba_getauthmethod ( hbaPort port)

Definition at line 3105 of file hba.c.

3106 {
3107  check_hba(port);
3108 }
static void check_hba(hbaPort *port)
Definition: hba.c:2523
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 2637 of file hba.c.

2638 {
2639  FILE *file;
2640  List *hba_lines = NIL;
2641  ListCell *line;
2642  List *new_parsed_lines = NIL;
2643  bool ok = true;
2644  MemoryContext oldcxt;
2645  MemoryContext hbacxt;
2646 
2647  file = open_auth_file(HbaFileName, LOG, 0, NULL);
2648  if (file == NULL)
2649  {
2650  /* error already logged */
2651  return false;
2652  }
2653 
2654  tokenize_auth_file(HbaFileName, file, &hba_lines, LOG, 0);
2655 
2656  /* Now parse all the lines */
2659  "hba parser context",
2661  oldcxt = MemoryContextSwitchTo(hbacxt);
2662  foreach(line, hba_lines)
2663  {
2664  TokenizedAuthLine *tok_line = (TokenizedAuthLine *) lfirst(line);
2665  HbaLine *newline;
2666 
2667  /* don't parse lines that already have errors */
2668  if (tok_line->err_msg != NULL)
2669  {
2670  ok = false;
2671  continue;
2672  }
2673 
2674  if ((newline = parse_hba_line(tok_line, LOG)) == NULL)
2675  {
2676  /* Parse error; remember there's trouble */
2677  ok = false;
2678 
2679  /*
2680  * Keep parsing the rest of the file so we can report errors on
2681  * more than the first line. Error has already been logged, no
2682  * need for more chatter here.
2683  */
2684  continue;
2685  }
2686 
2687  new_parsed_lines = lappend(new_parsed_lines, newline);
2688  }
2689 
2690  /*
2691  * A valid HBA file must have at least one entry; else there's no way to
2692  * connect to the postmaster. But only complain about this if we didn't
2693  * already have parsing errors.
2694  */
2695  if (ok && new_parsed_lines == NIL)
2696  {
2697  ereport(LOG,
2698  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2699  errmsg("configuration file \"%s\" contains no entries",
2700  HbaFileName)));
2701  ok = false;
2702  }
2703 
2704  /* Free tokenizer memory */
2705  free_auth_file(file, 0);
2706  MemoryContextSwitchTo(oldcxt);
2707 
2708  if (!ok)
2709  {
2710  /*
2711  * File contained one or more errors, so bail out, first being careful
2712  * to clean up whatever we allocated. Most stuff will go away via
2713  * MemoryContextDelete, but we have to clean up regexes explicitly.
2714  */
2715  foreach(line, new_parsed_lines)
2716  {
2717  HbaLine *newline = (HbaLine *) lfirst(line);
2718 
2720  }
2721  MemoryContextDelete(hbacxt);
2722  return false;
2723  }
2724 
2725  /* Loaded new file successfully, replace the one we use */
2726  if (parsed_hba_lines != NIL)
2727  {
2728  foreach(line, parsed_hba_lines)
2729  {
2730  HbaLine *newline = (HbaLine *) lfirst(line);
2731 
2733  }
2734  }
2735  if (parsed_hba_context != NULL)
2737  parsed_hba_context = hbacxt;
2738  parsed_hba_lines = new_parsed_lines;
2739 
2740  return true;
2741 }
int errcode(int sqlerrcode)
Definition: elog.c:695
char * HbaFileName
Definition: guc_tables.c:504
FILE * open_auth_file(const char *filename, int elevel, int depth, char **err_msg)
Definition: hba.c:643
static void free_hba_line(HbaLine *line)
Definition: hba.c:316
static MemoryContext parsed_hba_context
Definition: hba.c:91
void free_auth_file(FILE *file, int depth)
Definition: hba.c:618
HbaLine * parse_hba_line(TokenizedAuthLine *tok_line, int elevel)
Definition: hba.c:1364
static List * parsed_hba_lines
Definition: hba.c:90
void tokenize_auth_file(const char *filename, FILE *file, List **tok_lines, int elevel, int depth)
Definition: hba.c:734
Assert(fmt[strlen(fmt) - 1] !='\n')
List * lappend(List *list, void *datum)
Definition: list.c:338
MemoryContext PostmasterContext
Definition: mcxt.c:132
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:163
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:135
#define NIL
Definition: pg_list.h:66
static chr newline(void)
Definition: regc_lex.c:1002
Definition: hba.h:95
Definition: pg_list.h:52
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 SIGHUP_handler().

◆ load_ident()

bool load_ident ( void  )

Definition at line 3001 of file hba.c.

3002 {
3003  FILE *file;
3004  List *ident_lines = NIL;
3005  ListCell *line_cell,
3006  *parsed_line_cell;
3007  List *new_parsed_lines = NIL;
3008  bool ok = true;
3009  MemoryContext oldcxt;
3010  MemoryContext ident_context;
3011  IdentLine *newline;
3012 
3013  /* not FATAL ... we just won't do any special ident maps */
3014  file = open_auth_file(IdentFileName, LOG, 0, NULL);
3015  if (file == NULL)
3016  {
3017  /* error already logged */
3018  return false;
3019  }
3020 
3021  tokenize_auth_file(IdentFileName, file, &ident_lines, LOG, 0);
3022 
3023  /* Now parse all the lines */
3025  ident_context = AllocSetContextCreate(PostmasterContext,
3026  "ident parser context",
3028  oldcxt = MemoryContextSwitchTo(ident_context);
3029  foreach(line_cell, ident_lines)
3030  {
3031  TokenizedAuthLine *tok_line = (TokenizedAuthLine *) lfirst(line_cell);
3032 
3033  /* don't parse lines that already have errors */
3034  if (tok_line->err_msg != NULL)
3035  {
3036  ok = false;
3037  continue;
3038  }
3039 
3040  if ((newline = parse_ident_line(tok_line, LOG)) == NULL)
3041  {
3042  /* Parse error; remember there's trouble */
3043  ok = false;
3044 
3045  /*
3046  * Keep parsing the rest of the file so we can report errors on
3047  * more than the first line. Error has already been logged, no
3048  * need for more chatter here.
3049  */
3050  continue;
3051  }
3052 
3053  new_parsed_lines = lappend(new_parsed_lines, newline);
3054  }
3055 
3056  /* Free tokenizer memory */
3057  free_auth_file(file, 0);
3058  MemoryContextSwitchTo(oldcxt);
3059 
3060  if (!ok)
3061  {
3062  /*
3063  * File contained one or more errors, so bail out, first being careful
3064  * to clean up whatever we allocated. Most stuff will go away via
3065  * MemoryContextDelete, but we have to clean up regexes explicitly.
3066  */
3067  foreach(parsed_line_cell, new_parsed_lines)
3068  {
3069  newline = (IdentLine *) lfirst(parsed_line_cell);
3070  free_auth_token(newline->token);
3071  }
3072  MemoryContextDelete(ident_context);
3073  return false;
3074  }
3075 
3076  /* Loaded new file successfully, replace the one we use */
3077  if (parsed_ident_lines != NIL)
3078  {
3079  foreach(parsed_line_cell, parsed_ident_lines)
3080  {
3081  newline = (IdentLine *) lfirst(parsed_line_cell);
3082  free_auth_token(newline->token);
3083  }
3084  }
3085  if (parsed_ident_context != NULL)
3087 
3088  parsed_ident_context = ident_context;
3089  parsed_ident_lines = new_parsed_lines;
3090 
3091  return true;
3092 }
char * IdentFileName
Definition: guc_tables.c:505
IdentLine * parse_ident_line(TokenizedAuthLine *tok_line, int elevel)
Definition: hba.c:2759
static MemoryContext parsed_ident_context
Definition: hba.c:103
static void free_auth_token(AuthToken *token)
Definition: hba.c:305
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 SIGHUP_handler().

◆ open_auth_file()

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

Definition at line 643 of file hba.c.

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

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

2760 {
2761  int line_num = tok_line->line_num;
2762  char *file_name = tok_line->file_name;
2763  char **err_msg = &tok_line->err_msg;
2764  ListCell *field;
2765  List *tokens;
2766  AuthToken *token;
2767  IdentLine *parsedline;
2768 
2769  Assert(tok_line->fields != NIL);
2770  field = list_head(tok_line->fields);
2771 
2772  parsedline = palloc0(sizeof(IdentLine));
2773  parsedline->linenumber = line_num;
2774 
2775  /* Get the map token (must exist) */
2776  tokens = lfirst(field);
2777  IDENT_MULTI_VALUE(tokens);
2778  token = linitial(tokens);
2779  parsedline->usermap = pstrdup(token->string);
2780 
2781  /* Get the ident user token */
2782  field = lnext(tok_line->fields, field);
2783  IDENT_FIELD_ABSENT(field);
2784  tokens = lfirst(field);
2785  IDENT_MULTI_VALUE(tokens);
2786  token = linitial(tokens);
2787 
2788  /* Copy the ident user token */
2789  parsedline->token = copy_auth_token(token);
2790 
2791  /* Get the PG rolename token */
2792  field = lnext(tok_line->fields, field);
2793  IDENT_FIELD_ABSENT(field);
2794  tokens = lfirst(field);
2795  IDENT_MULTI_VALUE(tokens);
2796  token = linitial(tokens);
2797  parsedline->pg_role = pstrdup(token->string);
2798 
2799  /*
2800  * Now that the field validation is done, compile a regex from the user
2801  * token, if necessary.
2802  */
2803  if (regcomp_auth_token(parsedline->token, file_name, line_num,
2804  err_msg, elevel))
2805  {
2806  /* err_msg includes the error to report */
2807  return NULL;
2808  }
2809 
2810  return parsedline;
2811 }
#define IDENT_FIELD_ABSENT(field)
Definition: hba.c:1324
#define IDENT_MULTI_VALUE(tokens)
Definition: hba.c:1337
char * pg_role
Definition: hba.h:145
AuthToken * token
Definition: hba.h:146
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_role, pstrdup(), regcomp_auth_token(), AuthToken::string, IdentLine::token, and IdentLine::usermap.

Referenced by fill_ident_view(), and load_ident().

◆ pg_isblank()

bool pg_isblank ( const char  c)

Definition at line 148 of file hba.c.

149 {
150  return c == ' ' || c == '\t' || c == '\r';
151 }
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 734 of file hba.c.

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