PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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 charhba_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)
 
FILEopen_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

◆ ClientCertMode

◆ ClientCertName

◆ ConnType

◆ HbaLine

◆ IdentLine

◆ IPCompareMethod

◆ Port

Definition at line 173 of file hba.h.

◆ TokenizedAuthLine

◆ 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

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

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 
)
extern

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 {
3009
3011 {
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 }
3026}
#define STATUS_OK
Definition c.h:1158
#define STATUS_ERROR
Definition c.h:1159
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)
static int fb(int x)
static void error(void)

References check_ident_usermap(), ereport, errmsg(), error(), fb(), 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 
)
extern

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 {
578 }
579}
#define CONF_FILE_START_DEPTH
Definition conffiles.h:17
int FreeFile(FILE *file)
Definition fd.c:2823
static MemoryContext tokenize_context
Definition hba.c:80
void MemoryContextDelete(MemoryContext context)
Definition mcxt.c:472

References CONF_FILE_START_DEPTH, fb(), 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)
extern

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)
extern

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  )
extern

Definition at line 2642 of file hba.c.

2643{
2644 FILE *file;
2645 List *hba_lines = NIL;
2646 ListCell *line;
2648 bool ok = true;
2651
2652 file = open_auth_file(HbaFileName, LOG, 0, NULL);
2653 if (file == NULL)
2654 {
2655 /* error already logged */
2656 return false;
2657 }
2658
2660
2661 /* Now parse all the lines */
2664 "hba parser context",
2667 foreach(line, hba_lines)
2668 {
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
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,
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);
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 */
2720 return false;
2721 }
2722
2723 /* Loaded new file successfully, replace the one we use */
2724 if (parsed_hba_context != NULL)
2728
2729 return true;
2730}
#define Assert(condition)
Definition c.h:873
int errcode(int sqlerrcode)
Definition elog.c:863
char * HbaFileName
Definition guc_tables.c:557
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
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

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate, Assert, ereport, errcode(), errmsg(), fb(), 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  )
extern

Definition at line 3036 of file hba.c.

3037{
3038 FILE *file;
3039 List *ident_lines = NIL;
3042 bool ok = true;
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
3056
3057 /* Now parse all the lines */
3060 "ident parser context",
3063 foreach(line_cell, ident_lines)
3064 {
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
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
3088 }
3089
3090 /* Free tokenizer memory */
3091 free_auth_file(file, 0);
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 */
3101 return false;
3102 }
3103
3104 /* Loaded new file successfully, replace the one we use */
3107
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

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate, Assert, fb(), 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 
)
extern

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 {
628 *err_msg = psprintf("could not open file \"%s\": %m",
629 filename);
630 }
631 /* the caller may care about some specific 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:2624
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(), fb(), 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 
)
extern

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;
1341
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,
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 }
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,
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,
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,
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,
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,
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 {
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,
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 {
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,
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,
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 }
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
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,
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)
1568 return NULL;
1569 }
1570
1572
1573 /* Get the netmask */
1574 if (cidr_slash)
1575 {
1576 if (parsedline->hostname)
1577 {
1578 ereport(elevel,
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
1590 parsedline->addr.ss_family) < 0)
1591 {
1592 ereport(elevel,
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,
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,
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 }
1633
1634 ret = pg_getaddrinfo_all(token->string, NULL,
1635 &hints, &gai_result);
1636 if (ret || !gai_result)
1637 {
1638 ereport(elevel,
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)
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;
1655
1656 if (parsedline->addr.ss_family != parsedline->mask.ss_family)
1657 {
1658 ereport(elevel,
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,
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,
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 }
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,
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,
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,
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,
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,
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
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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
#define palloc0_object(type)
Definition fe_memutils.h:75
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
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:1781
void pfree(void *pointer)
Definition mcxt.c:1616
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 errcode)

References Assert, check_oauth_validator(), clientCertFull, copy_auth_token(), ctHost, ctHostGSS, ctHostNoGSS, ctHostNoSSL, ctHostSSL, ctLocal, EnableSSL, ereport, errcode(), errcontext, errhint(), errmsg(), fb(), gai_strerror(), ipCmpAll, ipCmpMask, ipCmpSameHost, ipCmpSameNet, lappend(), lfirst, linitial, list_head(), list_length(), lnext(), MANDATORY_AUTH_ARG, NIL, palloc0_object, parse_hba_auth_opt(), pfree(), pg_freeaddrinfo_all(), pg_getaddrinfo_all(), pg_sockaddr_cidr_mask(), psprintf(), pstrdup(), regcomp_auth_token(), str, token, token_is_keyword, uaBSD, uaCert, uaGSS, uaIdent, uaLDAP, uaMD5, uaOAuth, uaPAM, uaPassword, uaPeer, uaRADIUS, uaReject, uaSCRAM, uaSSPI, uaTrust, and val.

Referenced by fill_hba_view(), and load_hba().

◆ parse_ident_line()

IdentLine * parse_ident_line ( TokenizedAuthLine tok_line,
int  elevel 
)
extern

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;
2757
2758 Assert(tok_line->fields != NIL);
2759 field = list_head(tok_line->fields);
2760
2762 parsedline->linenumber = line_num;
2763
2764 /* Get the map token (must exist) */
2765 tokens = lfirst(field);
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);
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);
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

References Assert, copy_auth_token(), fb(), IDENT_FIELD_ABSENT, IDENT_MULTI_VALUE, lfirst, linitial, list_head(), lnext(), NIL, palloc0_object, pstrdup(), regcomp_auth_token(), and token.

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 
)
extern

Definition at line 688 of file hba.c.

690{
691 int line_number = 1;
694 MemoryContext funccxt; /* context of this function's caller */
696 tokenize_error_callback_arg callback_arg;
697
699
700 callback_arg.filename = filename;
701 callback_arg.linenum = line_number;
702
704 tokenerrcontext.arg = &callback_arg;
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",
716
718
719 if (depth == CONF_FILE_START_DEPTH)
720 *tok_lines = NIL;
721
722 while (!feof(file) && !ferror(file))
723 {
726 char *lineptr;
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';
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)));
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 {
778
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 */
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
809
810 if (strcmp(first->string, "include") == 0)
811 {
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;
830
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
841 for (int i = 0; i < num_filenames; i++)
842 {
844 elevel, depth + 1, false, &err_msg);
845 /* cumulate errors if any */
846 if (err_msg)
847 {
848 if (err_buf.len > 0)
851 }
852 }
853
854 /* clean up things */
855 for (int i = 0; i < num_filenames; i++)
856 pfree(filenames[i]);
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
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
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 */
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;
902
904 line_number += continuations + 1;
905 callback_arg.linenum = line_number;
906 }
907
910
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)
#define linitial_node(type, l)
Definition pg_list.h:181
#define lsecond_node(type, l)
Definition pg_list.h:186
static char buf[DEFAULT_XLOG_SEG_SIZE]
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
const char * filename
Definition hba.c:65

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate, appendStringInfoChar(), appendStringInfoString(), Assert, buf, CONF_FILE_START_DEPTH, CurrentMemoryContext, ereport, errcode_for_file_access(), errmsg(), error_context_stack, fb(), tokenize_error_callback_arg::filename, filename, GetConfFilesInDir(), i, initStringInfo(), lappend(), tokenize_error_callback_arg::linenum, linitial, linitial_node, list_length(), lsecond_node, MemoryContextDelete(), MemoryContextSwitchTo(), next_field_expand(), NIL, palloc0_object, pfree(), pg_get_line_append(), pg_strip_crlf(), ErrorContextCallback::previous, psprintf(), pstrdup(), 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().