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   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 Port
 

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 (Port *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)
 
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

◆ IdentLine

typedef struct IdentLine IdentLine

◆ IPCompareMethod

◆ Port

typedef struct Port Port

Definition at line 173 of file hba.h.

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

2985{
2986 bool found_entry = false,
2987 error = false;
2988
2989 if (usermap_name == NULL || usermap_name[0] == '\0')
2990 {
2991 if (case_insensitive)
2992 {
2993 if (pg_strcasecmp(pg_user, system_user) == 0)
2994 return STATUS_OK;
2995 }
2996 else
2997 {
2998 if (strcmp(pg_user, system_user) == 0)
2999 return STATUS_OK;
3000 }
3001 ereport(LOG,
3002 (errmsg("provided user name (%s) and authenticated user name (%s) do not match",
3003 pg_user, system_user)));
3004 return STATUS_ERROR;
3005 }
3006 else
3007 {
3008 ListCell *line_cell;
3009
3010 foreach(line_cell, parsed_ident_lines)
3011 {
3012 check_ident_usermap(lfirst(line_cell), usermap_name,
3013 pg_user, system_user, case_insensitive,
3014 &found_entry, &error);
3015 if (found_entry || error)
3016 break;
3017 }
3018 }
3019 if (!found_entry && !error)
3020 {
3021 ereport(LOG,
3022 (errmsg("no match in usermap \"%s\" for user \"%s\" authenticated as \"%s\"",
3023 usermap_name, pg_user, system_user)));
3024 }
3025 return found_entry ? STATUS_OK : STATUS_ERROR;
3026}
#define STATUS_OK
Definition: c.h:1157
#define STATUS_ERROR
Definition: c.h:1158
int errmsg(const char *fmt,...)
Definition: elog.c:1080
#define LOG
Definition: elog.h:31
#define ereport(elevel,...)
Definition: elog.h:150
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:2816
Datum system_user(PG_FUNCTION_ARGS)
Definition: miscinit.c:898
#define lfirst(lc)
Definition: pg_list.h:172
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:32
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 569 of file hba.c.

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

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

3139{
3140 return UserAuthName[auth_method];
3141}
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 ( Port port)

Definition at line 3125 of file hba.c.

3126{
3127 check_hba(port);
3128}
static void check_hba(Port *port)
Definition: hba.c:2528
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 2642 of file hba.c.

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

3037{
3038 FILE *file;
3039 List *ident_lines = NIL;
3040 ListCell *line_cell;
3041 List *new_parsed_lines = NIL;
3042 bool ok = true;
3043 MemoryContext oldcxt;
3044 MemoryContext ident_context;
3046
3047 /* not FATAL ... we just won't do any special ident maps */
3048 file = open_auth_file(IdentFileName, LOG, 0, NULL);
3049 if (file == NULL)
3050 {
3051 /* error already logged */
3052 return false;
3053 }
3054
3055 tokenize_auth_file(IdentFileName, file, &ident_lines, LOG, 0);
3056
3057 /* Now parse all the lines */
3060 "ident parser context",
3062 oldcxt = MemoryContextSwitchTo(ident_context);
3063 foreach(line_cell, ident_lines)
3064 {
3065 TokenizedAuthLine *tok_line = (TokenizedAuthLine *) lfirst(line_cell);
3066
3067 /* don't parse lines that already have errors */
3068 if (tok_line->err_msg != NULL)
3069 {
3070 ok = false;
3071 continue;
3072 }
3073
3074 if ((newline = parse_ident_line(tok_line, LOG)) == NULL)
3075 {
3076 /* Parse error; remember there's trouble */
3077 ok = false;
3078
3079 /*
3080 * Keep parsing the rest of the file so we can report errors on
3081 * more than the first line. Error has already been logged, no
3082 * need for more chatter here.
3083 */
3084 continue;
3085 }
3086
3087 new_parsed_lines = lappend(new_parsed_lines, newline);
3088 }
3089
3090 /* Free tokenizer memory */
3091 free_auth_file(file, 0);
3092 MemoryContextSwitchTo(oldcxt);
3093
3094 if (!ok)
3095 {
3096 /*
3097 * File contained one or more errors, so bail out. MemoryContextDelete
3098 * is enough to clean up everything, including regexes.
3099 */
3100 MemoryContextDelete(ident_context);
3101 return false;
3102 }
3103
3104 /* Loaded new file successfully, replace the one we use */
3105 if (parsed_ident_context != NULL)
3107
3108 parsed_ident_context = ident_context;
3109 parsed_ident_lines = new_parsed_lines;
3110
3111 return true;
3112}
char * IdentFileName
Definition: guc_tables.c:558
static MemoryContext parsed_ident_context
Definition: hba.c:94
IdentLine * parse_ident_line(TokenizedAuthLine *tok_line, int elevel)
Definition: hba.c:2748
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 594 of file hba.c.

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

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

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

◆ tokenize_auth_file()

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

Definition at line 688 of file hba.c.

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