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   uaPeer /* Must be last value of this enum */
 

Typedefs

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

Enumerations

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

Functions

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

Macro Definition Documentation

◆ USER_AUTH_LAST

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

Definition at line 42 of file hba.h.

Typedef Documentation

◆ AuthToken

typedef struct AuthToken AuthToken

◆ ClientCertMode

◆ ClientCertName

◆ ConnType

typedef enum ConnType ConnType

◆ HbaLine

typedef struct HbaLine HbaLine

◆ hbaPort

typedef struct Port hbaPort

Definition at line 168 of file hba.h.

◆ IdentLine

typedef struct IdentLine IdentLine

◆ IPCompareMethod

◆ TokenizedAuthLine

◆ UserAuth

typedef enum UserAuth UserAuth

Enumeration Type Documentation

◆ ClientCertMode

Enumerator
clientCertOff 
clientCertCA 
clientCertFull 

Definition at line 67 of file hba.h.

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

◆ ClientCertName

Enumerator
clientCertCN 
clientCertDN 

Definition at line 74 of file hba.h.

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

◆ ConnType

enum ConnType
Enumerator
ctLocal 
ctHost 
ctHostSSL 
ctHostNoSSL 
ctHostGSS 
ctHostNoGSS 

Definition at line 57 of file hba.h.

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

◆ IPCompareMethod

Enumerator
ipCmpMask 
ipCmpSameHost 
ipCmpSameNet 
ipCmpAll 

Definition at line 49 of file hba.h.

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

◆ UserAuth

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

Definition at line 25 of file hba.h.

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

Function Documentation

◆ check_usermap()

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

Definition at line 2908 of file hba.c.

2912{
2913 bool found_entry = false,
2914 error = false;
2915
2916 if (usermap_name == NULL || usermap_name[0] == '\0')
2917 {
2918 if (case_insensitive)
2919 {
2920 if (pg_strcasecmp(pg_user, system_user) == 0)
2921 return STATUS_OK;
2922 }
2923 else
2924 {
2925 if (strcmp(pg_user, system_user) == 0)
2926 return STATUS_OK;
2927 }
2928 ereport(LOG,
2929 (errmsg("provided user name (%s) and authenticated user name (%s) do not match",
2930 pg_user, system_user)));
2931 return STATUS_ERROR;
2932 }
2933 else
2934 {
2935 ListCell *line_cell;
2936
2937 foreach(line_cell, parsed_ident_lines)
2938 {
2939 check_ident_usermap(lfirst(line_cell), usermap_name,
2940 pg_user, system_user, case_insensitive,
2941 &found_entry, &error);
2942 if (found_entry || error)
2943 break;
2944 }
2945 }
2946 if (!found_entry && !error)
2947 {
2948 ereport(LOG,
2949 (errmsg("no match in usermap \"%s\" for user \"%s\" authenticated as \"%s\"",
2950 usermap_name, pg_user, system_user)));
2951 }
2952 return found_entry ? STATUS_OK : STATUS_ERROR;
2953}
#define STATUS_OK
Definition: c.h:1126
#define STATUS_ERROR
Definition: c.h:1127
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define LOG
Definition: elog.h:31
#define ereport(elevel,...)
Definition: elog.h:149
static List * parsed_ident_lines
Definition: hba.c:92
static void check_ident_usermap(IdentLine *identLine, const char *usermap_name, const char *pg_user, const char *system_user, bool case_insensitive, bool *found_p, bool *error_p)
Definition: hba.c:2761
Datum system_user(PG_FUNCTION_ARGS)
Definition: miscinit.c:946
#define lfirst(lc)
Definition: pg_list.h:172
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
static void error(void)
Definition: sql-dyntest.c:147

References check_ident_usermap(), ereport, errmsg(), error(), lfirst, LOG, parsed_ident_lines, pg_strcasecmp(), STATUS_ERROR, STATUS_OK, and system_user().

Referenced by auth_peer(), and ident_inet().

◆ free_auth_file()

void free_auth_file ( FILE *  file,
int  depth 
)

Definition at line 570 of file hba.c.

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

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

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

◆ hba_authname()

const char * hba_authname ( UserAuth  auth_method)

Definition at line 3065 of file hba.c.

3066{
3067 return UserAuthName[auth_method];
3068}
static const char *const UserAuthName[]
Definition: hba.c:101

References UserAuthName.

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

◆ hba_getauthmethod()

void hba_getauthmethod ( hbaPort port)

Definition at line 3052 of file hba.c.

3053{
3054 check_hba(port);
3055}
static void check_hba(hbaPort *port)
Definition: hba.c:2473
static int port
Definition: pg_regress.c:115

References check_hba(), and port.

Referenced by ClientAuthentication().

◆ load_hba()

bool load_hba ( void  )

Definition at line 2587 of file hba.c.

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

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

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

◆ load_ident()

bool load_ident ( void  )

Definition at line 2963 of file hba.c.

2964{
2965 FILE *file;
2966 List *ident_lines = NIL;
2967 ListCell *line_cell;
2968 List *new_parsed_lines = NIL;
2969 bool ok = true;
2970 MemoryContext oldcxt;
2971 MemoryContext ident_context;
2973
2974 /* not FATAL ... we just won't do any special ident maps */
2975 file = open_auth_file(IdentFileName, LOG, 0, NULL);
2976 if (file == NULL)
2977 {
2978 /* error already logged */
2979 return false;
2980 }
2981
2982 tokenize_auth_file(IdentFileName, file, &ident_lines, LOG, 0);
2983
2984 /* Now parse all the lines */
2987 "ident parser context",
2989 oldcxt = MemoryContextSwitchTo(ident_context);
2990 foreach(line_cell, ident_lines)
2991 {
2992 TokenizedAuthLine *tok_line = (TokenizedAuthLine *) lfirst(line_cell);
2993
2994 /* don't parse lines that already have errors */
2995 if (tok_line->err_msg != NULL)
2996 {
2997 ok = false;
2998 continue;
2999 }
3000
3001 if ((newline = parse_ident_line(tok_line, LOG)) == NULL)
3002 {
3003 /* Parse error; remember there's trouble */
3004 ok = false;
3005
3006 /*
3007 * Keep parsing the rest of the file so we can report errors on
3008 * more than the first line. Error has already been logged, no
3009 * need for more chatter here.
3010 */
3011 continue;
3012 }
3013
3014 new_parsed_lines = lappend(new_parsed_lines, newline);
3015 }
3016
3017 /* Free tokenizer memory */
3018 free_auth_file(file, 0);
3019 MemoryContextSwitchTo(oldcxt);
3020
3021 if (!ok)
3022 {
3023 /*
3024 * File contained one or more errors, so bail out. MemoryContextDelete
3025 * is enough to clean up everything, including regexes.
3026 */
3027 MemoryContextDelete(ident_context);
3028 return false;
3029 }
3030
3031 /* Loaded new file successfully, replace the one we use */
3032 if (parsed_ident_context != NULL)
3034
3035 parsed_ident_context = ident_context;
3036 parsed_ident_lines = new_parsed_lines;
3037
3038 return true;
3039}
char * IdentFileName
Definition: guc_tables.c:540
static MemoryContext parsed_ident_context
Definition: hba.c:93
IdentLine * parse_ident_line(TokenizedAuthLine *tok_line, int elevel)
Definition: hba.c:2693
Definition: hba.h:141

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

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

◆ open_auth_file()

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

Definition at line 595 of file hba.c.

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

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

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

Referenced by fill_hba_view(), and load_hba().

◆ parse_ident_line()

IdentLine * parse_ident_line ( TokenizedAuthLine tok_line,
int  elevel 
)

Definition at line 2693 of file hba.c.

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

References Assert, copy_auth_token(), TokenizedAuthLine::err_msg, TokenizedAuthLine::fields, TokenizedAuthLine::file_name, IDENT_FIELD_ABSENT, IDENT_MULTI_VALUE, lfirst, TokenizedAuthLine::line_num, IdentLine::linenumber, linitial, list_head(), lnext(), NIL, palloc0(), IdentLine::pg_user, pstrdup(), regcomp_auth_token(), IdentLine::system_user, token, and IdentLine::usermap.

Referenced by fill_ident_view(), and load_ident().

◆ pg_isblank()

bool pg_isblank ( const char  c)

Definition at line 144 of file hba.c.

145{
146 return c == ' ' || c == '\t' || c == '\r';
147}
char * c

Referenced by interpret_ident_response(), and next_token().

◆ tokenize_auth_file()

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

Definition at line 689 of file hba.c.

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

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

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