PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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   uaOAuth /* Must be last value of this enum */
 

Typedefs

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

Enumerations

enum  UserAuth {
  uaReject , uaImplicitReject , uaTrust , uaIdent ,
  uaPassword , uaMD5 , uaSCRAM , uaGSS ,
  uaSSPI , uaPAM , uaBSD , uaLDAP ,
  uaCert , uaRADIUS , uaPeer , uaOAuth
}
 
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   uaOAuth /* Must be last value of this enum */

Definition at line 43 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 173 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 68 of file hba.h.

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

◆ ClientCertName

Enumerator
clientCertCN 
clientCertDN 

Definition at line 75 of file hba.h.

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

◆ ConnType

enum ConnType
Enumerator
ctLocal 
ctHost 
ctHostSSL 
ctHostNoSSL 
ctHostGSS 
ctHostNoGSS 

Definition at line 58 of file hba.h.

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

◆ IPCompareMethod

Enumerator
ipCmpMask 
ipCmpSameHost 
ipCmpSameNet 
ipCmpAll 

Definition at line 50 of file hba.h.

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

◆ UserAuth

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

Definition at line 25 of file hba.h.

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

2970{
2971 bool found_entry = false,
2972 error = false;
2973
2974 if (usermap_name == NULL || usermap_name[0] == '\0')
2975 {
2976 if (case_insensitive)
2977 {
2978 if (pg_strcasecmp(pg_user, system_user) == 0)
2979 return STATUS_OK;
2980 }
2981 else
2982 {
2983 if (strcmp(pg_user, system_user) == 0)
2984 return STATUS_OK;
2985 }
2986 ereport(LOG,
2987 (errmsg("provided user name (%s) and authenticated user name (%s) do not match",
2988 pg_user, system_user)));
2989 return STATUS_ERROR;
2990 }
2991 else
2992 {
2993 ListCell *line_cell;
2994
2995 foreach(line_cell, parsed_ident_lines)
2996 {
2997 check_ident_usermap(lfirst(line_cell), usermap_name,
2998 pg_user, system_user, case_insensitive,
2999 &found_entry, &error);
3000 if (found_entry || error)
3001 break;
3002 }
3003 }
3004 if (!found_entry && !error)
3005 {
3006 ereport(LOG,
3007 (errmsg("no match in usermap \"%s\" for user \"%s\" authenticated as \"%s\"",
3008 usermap_name, pg_user, system_user)));
3009 }
3010 return found_entry ? STATUS_OK : STATUS_ERROR;
3011}
#define STATUS_OK
Definition: c.h:1140
#define STATUS_ERROR
Definition: c.h:1141
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define LOG
Definition: elog.h:31
#define ereport(elevel,...)
Definition: elog.h:149
static List * parsed_ident_lines
Definition: hba.c:93
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:2819
Datum system_user(PG_FUNCTION_ARGS)
Definition: miscinit.c:949
#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(), ident_inet(), and validate().

◆ free_auth_file()

void free_auth_file ( FILE *  file,
int  depth 
)

Definition at line 572 of file hba.c.

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

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

3124{
3125 return UserAuthName[auth_method];
3126}
static const char *const UserAuthName[]
Definition: hba.c:102

References UserAuthName.

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

◆ hba_getauthmethod()

void hba_getauthmethod ( hbaPort port)

Definition at line 3110 of file hba.c.

3111{
3112 check_hba(port);
3113}
static void check_hba(hbaPort *port)
Definition: hba.c:2531
static int port
Definition: pg_regress.c:115

References check_hba(), and port.

Referenced by ClientAuthentication().

◆ load_hba()

bool load_hba ( void  )

Definition at line 2645 of file hba.c.

2646{
2647 FILE *file;
2648 List *hba_lines = NIL;
2649 ListCell *line;
2650 List *new_parsed_lines = NIL;
2651 bool ok = true;
2652 MemoryContext oldcxt;
2653 MemoryContext hbacxt;
2654
2655 file = open_auth_file(HbaFileName, LOG, 0, NULL);
2656 if (file == NULL)
2657 {
2658 /* error already logged */
2659 return false;
2660 }
2661
2662 tokenize_auth_file(HbaFileName, file, &hba_lines, LOG, 0);
2663
2664 /* Now parse all the lines */
2667 "hba parser context",
2669 oldcxt = MemoryContextSwitchTo(hbacxt);
2670 foreach(line, hba_lines)
2671 {
2672 TokenizedAuthLine *tok_line = (TokenizedAuthLine *) lfirst(line);
2674
2675 /* don't parse lines that already have errors */
2676 if (tok_line->err_msg != NULL)
2677 {
2678 ok = false;
2679 continue;
2680 }
2681
2682 if ((newline = parse_hba_line(tok_line, LOG)) == NULL)
2683 {
2684 /* Parse error; remember there's trouble */
2685 ok = false;
2686
2687 /*
2688 * Keep parsing the rest of the file so we can report errors on
2689 * more than the first line. Error has already been logged, no
2690 * need for more chatter here.
2691 */
2692 continue;
2693 }
2694
2695 new_parsed_lines = lappend(new_parsed_lines, newline);
2696 }
2697
2698 /*
2699 * A valid HBA file must have at least one entry; else there's no way to
2700 * connect to the postmaster. But only complain about this if we didn't
2701 * already have parsing errors.
2702 */
2703 if (ok && new_parsed_lines == NIL)
2704 {
2705 ereport(LOG,
2706 (errcode(ERRCODE_CONFIG_FILE_ERROR),
2707 errmsg("configuration file \"%s\" contains no entries",
2708 HbaFileName)));
2709 ok = false;
2710 }
2711
2712 /* Free tokenizer memory */
2713 free_auth_file(file, 0);
2714 MemoryContextSwitchTo(oldcxt);
2715
2716 if (!ok)
2717 {
2718 /*
2719 * File contained one or more errors, so bail out. MemoryContextDelete
2720 * is enough to clean up everything, including regexes.
2721 */
2722 MemoryContextDelete(hbacxt);
2723 return false;
2724 }
2725
2726 /* Loaded new file successfully, replace the one we use */
2727 if (parsed_hba_context != NULL)
2729 parsed_hba_context = hbacxt;
2730 parsed_hba_lines = new_parsed_lines;
2731
2732 return true;
2733}
int errcode(int sqlerrcode)
Definition: elog.c:854
char * HbaFileName
Definition: guc_tables.c:556
Assert(PointerIsAligned(start, uint64))
HbaLine * parse_hba_line(TokenizedAuthLine *tok_line, int elevel)
Definition: hba.c:1328
static MemoryContext parsed_hba_context
Definition: hba.c:87
void free_auth_file(FILE *file, int depth)
Definition: hba.c:572
static List * parsed_hba_lines
Definition: hba.c:86
void tokenize_auth_file(const char *filename, FILE *file, List **tok_lines, int elevel, int depth)
Definition: hba.c:691
FILE * open_auth_file(const char *filename, int elevel, int depth, char **err_msg)
Definition: hba.c:597
#define newline
Definition: indent_codes.h:35
List * lappend(List *list, void *datum)
Definition: list.c:339
MemoryContext PostmasterContext
Definition: mcxt.c:167
#define AllocSetContextCreate
Definition: memutils.h:149
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:190
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
#define NIL
Definition: pg_list.h:68
Definition: hba.h:96
Definition: pg_list.h:54
char * err_msg
Definition: hba.h:169

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate, Assert(), ereport, TokenizedAuthLine::err_msg, errcode(), errmsg(), free_auth_file(), HbaFileName, lappend(), lfirst, LOG, MemoryContextDelete(), MemoryContextSwitchTo(), newline, NIL, open_auth_file(), parse_hba_line(), parsed_hba_context, parsed_hba_lines, PostmasterContext, and tokenize_auth_file().

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

◆ load_ident()

bool load_ident ( void  )

Definition at line 3021 of file hba.c.

3022{
3023 FILE *file;
3024 List *ident_lines = NIL;
3025 ListCell *line_cell;
3026 List *new_parsed_lines = NIL;
3027 bool ok = true;
3028 MemoryContext oldcxt;
3029 MemoryContext ident_context;
3031
3032 /* not FATAL ... we just won't do any special ident maps */
3033 file = open_auth_file(IdentFileName, LOG, 0, NULL);
3034 if (file == NULL)
3035 {
3036 /* error already logged */
3037 return false;
3038 }
3039
3040 tokenize_auth_file(IdentFileName, file, &ident_lines, LOG, 0);
3041
3042 /* Now parse all the lines */
3045 "ident parser context",
3047 oldcxt = MemoryContextSwitchTo(ident_context);
3048 foreach(line_cell, ident_lines)
3049 {
3050 TokenizedAuthLine *tok_line = (TokenizedAuthLine *) lfirst(line_cell);
3051
3052 /* don't parse lines that already have errors */
3053 if (tok_line->err_msg != NULL)
3054 {
3055 ok = false;
3056 continue;
3057 }
3058
3059 if ((newline = parse_ident_line(tok_line, LOG)) == NULL)
3060 {
3061 /* Parse error; remember there's trouble */
3062 ok = false;
3063
3064 /*
3065 * Keep parsing the rest of the file so we can report errors on
3066 * more than the first line. Error has already been logged, no
3067 * need for more chatter here.
3068 */
3069 continue;
3070 }
3071
3072 new_parsed_lines = lappend(new_parsed_lines, newline);
3073 }
3074
3075 /* Free tokenizer memory */
3076 free_auth_file(file, 0);
3077 MemoryContextSwitchTo(oldcxt);
3078
3079 if (!ok)
3080 {
3081 /*
3082 * File contained one or more errors, so bail out. MemoryContextDelete
3083 * is enough to clean up everything, including regexes.
3084 */
3085 MemoryContextDelete(ident_context);
3086 return false;
3087 }
3088
3089 /* Loaded new file successfully, replace the one we use */
3090 if (parsed_ident_context != NULL)
3092
3093 parsed_ident_context = ident_context;
3094 parsed_ident_lines = new_parsed_lines;
3095
3096 return true;
3097}
char * IdentFileName
Definition: guc_tables.c:557
static MemoryContext parsed_ident_context
Definition: hba.c:94
IdentLine * parse_ident_line(TokenizedAuthLine *tok_line, int elevel)
Definition: hba.c:2751
Definition: hba.h:146

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

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

◆ open_auth_file()

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

Definition at line 597 of file hba.c.

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

References AllocateFile(), ALLOCSET_START_SMALL_SIZES, AllocSetContextCreate, CONF_FILE_MAX_DEPTH, CONF_FILE_START_DEPTH, CurrentMemoryContext, ereport, errcode_for_file_access(), errmsg(), filename, psprintf(), and tokenize_context.

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

◆ parse_hba_line()

HbaLine * parse_hba_line ( TokenizedAuthLine tok_line,
int  elevel 
)

Definition at line 1328 of file hba.c.

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

References HbaLine::addr, HbaLine::addrlen, Assert(), HbaLine::auth_method, check_oauth_validator(), HbaLine::clientcert, clientCertFull, HbaLine::compat_realm, HbaLine::conntype, copy_auth_token(), ctHost, ctHostGSS, ctHostNoGSS, ctHostNoSSL, ctHostSSL, ctLocal, HbaLine::databases, EnableSSL, ereport, TokenizedAuthLine::err_msg, errcode(), errcontext, errhint(), errmsg(), TokenizedAuthLine::fields, TokenizedAuthLine::file_name, gai_strerror(), HbaLine::hostname, HbaLine::include_realm, HbaLine::ip_cmp_method, ipCmpAll, ipCmpMask, ipCmpSameHost, ipCmpSameNet, lappend(), HbaLine::ldapbasedn, HbaLine::ldapbinddn, HbaLine::ldapbindpasswd, HbaLine::ldapprefix, HbaLine::ldapsearchattribute, HbaLine::ldapsearchfilter, HbaLine::ldapserver, HbaLine::ldapsuffix, List::length, lfirst, TokenizedAuthLine::line_num, HbaLine::linenumber, linitial, list_head(), list_length(), lnext(), MANDATORY_AUTH_ARG, HbaLine::mask, HbaLine::masklen, NIL, HbaLine::oauth_issuer, HbaLine::oauth_scope, HbaLine::oauth_skip_usermap, palloc0(), parse_hba_auth_opt(), pfree(), pg_freeaddrinfo_all(), pg_getaddrinfo_all(), pg_sockaddr_cidr_mask(), psprintf(), pstrdup(), HbaLine::radiusidentifiers, HbaLine::radiusports, HbaLine::radiussecrets, HbaLine::radiusservers, TokenizedAuthLine::raw_line, HbaLine::rawline, regcomp_auth_token(), HbaLine::roles, HbaLine::sourcefile, str, token, token_is_keyword, uaBSD, uaCert, uaGSS, uaIdent, uaLDAP, uaMD5, uaOAuth, uaPAM, uaPassword, uaPeer, uaRADIUS, uaReject, uaSCRAM, uaSSPI, uaTrust, HbaLine::upn_username, HbaLine::usermap, 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 2751 of file hba.c.

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

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

147{
148 return c == ' ' || c == '\t' || c == '\r';
149}
char * c

Referenced by interpret_ident_response(), and next_token().

◆ tokenize_auth_file()

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

Definition at line 691 of file hba.c.

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

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

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