PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
hba.c File Reference
#include "postgres.h"
#include <ctype.h>
#include <pwd.h>
#include <fcntl.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include "catalog/pg_collation.h"
#include "common/ip.h"
#include "common/string.h"
#include "libpq/hba.h"
#include "libpq/ifaddr.h"
#include "libpq/libpq-be.h"
#include "libpq/oauth.h"
#include "postmaster/postmaster.h"
#include "regex/regex.h"
#include "replication/walsender.h"
#include "storage/fd.h"
#include "utils/acl.h"
#include "utils/conffiles.h"
#include "utils/guc.h"
#include "utils/memutils.h"
#include "utils/varlena.h"
Include dependency graph for hba.c:

Go to the source code of this file.

Data Structures

struct  check_network_data
 
struct  tokenize_error_callback_arg
 

Macros

#define token_has_regexp(t)   (t->regex != NULL)
 
#define token_is_member_check(t)   (!t->quoted && t->string[0] == '+')
 
#define token_is_keyword(t, k)   (!t->quoted && strcmp(t->string, k) == 0)
 
#define token_matches(t, k)   (strcmp(t->string, k) == 0)
 
#define token_matches_insensitive(t, k)   (pg_strcasecmp(t->string, k) == 0)
 
#define INVALID_AUTH_OPTION(optname, validmethods)
 
#define REQUIRE_AUTH_OPTION(methodval, optname, validmethods)
 
#define MANDATORY_AUTH_ARG(argvar, argname, authname)
 
#define IDENT_FIELD_ABSENT(field)
 
#define IDENT_MULTI_VALUE(tokens)
 

Typedefs

typedef struct check_network_data check_network_data
 

Functions

 StaticAssertDecl (lengthof(UserAuthName)==USER_AUTH_LAST+1, "UserAuthName[] must match the UserAuth enum")
 
static Listtokenize_expand_file (List *tokens, const char *outer_filename, const char *inc_filename, int elevel, int depth, char **err_msg)
 
static bool parse_hba_auth_opt (char *name, char *val, HbaLine *hbaline, int elevel, char **err_msg)
 
static int regcomp_auth_token (AuthToken *token, char *filename, int line_num, char **err_msg, int elevel)
 
static int regexec_auth_token (const char *match, AuthToken *token, size_t nmatch, regmatch_t pmatch[])
 
static void tokenize_error_callback (void *arg)
 
bool pg_isblank (const char c)
 
static bool next_token (char **lineptr, StringInfo buf, bool *initial_quote, bool *terminating_comma)
 
static AuthTokenmake_auth_token (const char *token, bool quoted)
 
static void free_auth_token (AuthToken *token)
 
static AuthTokencopy_auth_token (AuthToken *in)
 
static Listnext_field_expand (const char *filename, char **lineptr, int elevel, int depth, char **err_msg)
 
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)
 
void free_auth_file (FILE *file, int depth)
 
FILE * open_auth_file (const char *filename, int elevel, int depth, char **err_msg)
 
void tokenize_auth_file (const char *filename, FILE *file, List **tok_lines, int elevel, int depth)
 
static bool is_member (Oid userid, const char *role)
 
static bool check_role (const char *role, Oid roleid, List *tokens, bool case_insensitive)
 
static bool check_db (const char *dbname, const char *role, Oid roleid, List *tokens)
 
static bool ipv4eq (struct sockaddr_in *a, struct sockaddr_in *b)
 
static bool ipv6eq (struct sockaddr_in6 *a, struct sockaddr_in6 *b)
 
static bool hostname_match (const char *pattern, const char *actual_hostname)
 
static bool check_hostname (hbaPort *port, const char *hostname)
 
static bool check_ip (SockAddr *raddr, struct sockaddr *addr, struct sockaddr *mask)
 
static void check_network_callback (struct sockaddr *addr, struct sockaddr *netmask, void *cb_data)
 
static bool check_same_host_or_net (SockAddr *raddr, IPCompareMethod method)
 
HbaLineparse_hba_line (TokenizedAuthLine *tok_line, int elevel)
 
static void check_hba (hbaPort *port)
 
bool load_hba (void)
 
IdentLineparse_ident_line (TokenizedAuthLine *tok_line, int elevel)
 
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)
 
int check_usermap (const char *usermap_name, const char *pg_user, const char *system_user, bool case_insensitive)
 
bool load_ident (void)
 
void hba_getauthmethod (hbaPort *port)
 
const char * hba_authname (UserAuth auth_method)
 

Variables

static MemoryContext tokenize_context = NULL
 
static Listparsed_hba_lines = NIL
 
static MemoryContext parsed_hba_context = NULL
 
static Listparsed_ident_lines = NIL
 
static MemoryContext parsed_ident_context = NULL
 
static const char *const UserAuthName []
 

Macro Definition Documentation

◆ IDENT_FIELD_ABSENT

#define IDENT_FIELD_ABSENT (   field)
Value:
do { \
if (!field) { \
ereport(elevel, \
(errcode(ERRCODE_CONFIG_FILE_ERROR), \
errmsg("missing entry at end of line"), \
errcontext("line %d of configuration file \"%s\"", \
line_num, file_name))); \
*err_msg = pstrdup("missing entry at end of line"); \
return NULL; \
} \
} while (0)
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define errcontext
Definition: elog.h:197
char * pstrdup(const char *in)
Definition: mcxt.c:2325

Definition at line 1288 of file hba.c.

◆ IDENT_MULTI_VALUE

#define IDENT_MULTI_VALUE (   tokens)
Value:
do { \
if (tokens->length > 1) { \
ereport(elevel, \
(errcode(ERRCODE_CONFIG_FILE_ERROR), \
errmsg("multiple values in ident field"), \
errcontext("line %d of configuration file \"%s\"", \
line_num, file_name))); \
*err_msg = pstrdup("multiple values in ident field"); \
return NULL; \
} \
} while (0)

Definition at line 1301 of file hba.c.

◆ INVALID_AUTH_OPTION

#define INVALID_AUTH_OPTION (   optname,
  validmethods 
)
Value:
do { \
ereport(elevel, \
(errcode(ERRCODE_CONFIG_FILE_ERROR), \
/* translator: the second %s is a list of auth methods */ \
errmsg("authentication option \"%s\" is only valid for authentication methods %s", \
optname, _(validmethods)), \
errcontext("line %d of configuration file \"%s\"", \
line_num, file_name))); \
*err_msg = psprintf("authentication option \"%s\" is only valid for authentication methods %s", \
optname, validmethods); \
return false; \
} while (0)
#define _(x)
Definition: elog.c:91
char * psprintf(const char *fmt,...)
Definition: psprintf.c:43

Definition at line 1244 of file hba.c.

◆ MANDATORY_AUTH_ARG

#define MANDATORY_AUTH_ARG (   argvar,
  argname,
  authname 
)
Value:
do { \
if (argvar == NULL) { \
ereport(elevel, \
(errcode(ERRCODE_CONFIG_FILE_ERROR), \
errmsg("authentication method \"%s\" requires argument \"%s\" to be set", \
authname, argname), \
errcontext("line %d of configuration file \"%s\"", \
line_num, file_name))); \
*err_msg = psprintf("authentication method \"%s\" requires argument \"%s\" to be set", \
authname, argname); \
return NULL; \
} \
} while (0)

Definition at line 1264 of file hba.c.

◆ REQUIRE_AUTH_OPTION

#define REQUIRE_AUTH_OPTION (   methodval,
  optname,
  validmethods 
)
Value:
do { \
if (hbaline->auth_method != methodval) \
INVALID_AUTH_OPTION(optname, validmethods); \
} while (0)

Definition at line 1258 of file hba.c.

◆ token_has_regexp

#define token_has_regexp (   t)    (t->regex != NULL)

Definition at line 69 of file hba.c.

◆ token_is_keyword

#define token_is_keyword (   t,
 
)    (!t->quoted && strcmp(t->string, k) == 0)

Definition at line 71 of file hba.c.

◆ token_is_member_check

#define token_is_member_check (   t)    (!t->quoted && t->string[0] == '+')

Definition at line 70 of file hba.c.

◆ token_matches

#define token_matches (   t,
 
)    (strcmp(t->string, k) == 0)

Definition at line 72 of file hba.c.

◆ token_matches_insensitive

#define token_matches_insensitive (   t,
 
)    (pg_strcasecmp(t->string, k) == 0)

Definition at line 73 of file hba.c.

Typedef Documentation

◆ check_network_data

Function Documentation

◆ check_db()

static bool check_db ( const char *  dbname,
const char *  role,
Oid  roleid,
List tokens 
)
static

Definition at line 993 of file hba.c.

994{
995 ListCell *cell;
996 AuthToken *tok;
997
998 foreach(cell, tokens)
999 {
1000 tok = lfirst(cell);
1002 {
1003 /*
1004 * physical replication walsender connections can only match
1005 * replication keyword
1006 */
1007 if (token_is_keyword(tok, "replication"))
1008 return true;
1009 }
1010 else if (token_is_keyword(tok, "all"))
1011 return true;
1012 else if (token_is_keyword(tok, "sameuser"))
1013 {
1014 if (strcmp(dbname, role) == 0)
1015 return true;
1016 }
1017 else if (token_is_keyword(tok, "samegroup") ||
1018 token_is_keyword(tok, "samerole"))
1019 {
1020 if (is_member(roleid, dbname))
1021 return true;
1022 }
1023 else if (token_is_keyword(tok, "replication"))
1024 continue; /* never match this if not walsender */
1025 else if (token_has_regexp(tok))
1026 {
1027 if (regexec_auth_token(dbname, tok, 0, NULL) == REG_OKAY)
1028 return true;
1029 }
1030 else if (token_matches(tok, dbname))
1031 return true;
1032 }
1033 return false;
1034}
static bool is_member(Oid userid, const char *role)
Definition: hba.c:925
#define token_is_keyword(t, k)
Definition: hba.c:71
static int regexec_auth_token(const char *match, AuthToken *token, size_t nmatch, regmatch_t pmatch[])
Definition: hba.c:348
#define token_has_regexp(t)
Definition: hba.c:69
#define token_matches(t, k)
Definition: hba.c:72
#define lfirst(lc)
Definition: pg_list.h:172
#define REG_OKAY
Definition: regex.h:215
char * dbname
Definition: streamutil.c:49
Definition: hba.h:89
bool am_walsender
Definition: walsender.c:120
bool am_db_walsender
Definition: walsender.c:123

References am_db_walsender, am_walsender, dbname, is_member(), lfirst, REG_OKAY, regexec_auth_token(), token_has_regexp, token_is_keyword, and token_matches.

Referenced by check_hba().

◆ check_hba()

static void check_hba ( hbaPort port)
static

Definition at line 2531 of file hba.c.

2532{
2533 Oid roleid;
2534 ListCell *line;
2535 HbaLine *hba;
2536
2537 /* Get the target role's OID. Note we do not error out for bad role. */
2538 roleid = get_role_oid(port->user_name, true);
2539
2540 foreach(line, parsed_hba_lines)
2541 {
2542 hba = (HbaLine *) lfirst(line);
2543
2544 /* Check connection type */
2545 if (hba->conntype == ctLocal)
2546 {
2547 if (port->raddr.addr.ss_family != AF_UNIX)
2548 continue;
2549 }
2550 else
2551 {
2552 if (port->raddr.addr.ss_family == AF_UNIX)
2553 continue;
2554
2555 /* Check SSL state */
2556 if (port->ssl_in_use)
2557 {
2558 /* Connection is SSL, match both "host" and "hostssl" */
2559 if (hba->conntype == ctHostNoSSL)
2560 continue;
2561 }
2562 else
2563 {
2564 /* Connection is not SSL, match both "host" and "hostnossl" */
2565 if (hba->conntype == ctHostSSL)
2566 continue;
2567 }
2568
2569 /* Check GSSAPI state */
2570#ifdef ENABLE_GSS
2571 if (port->gss && port->gss->enc &&
2572 hba->conntype == ctHostNoGSS)
2573 continue;
2574 else if (!(port->gss && port->gss->enc) &&
2575 hba->conntype == ctHostGSS)
2576 continue;
2577#else
2578 if (hba->conntype == ctHostGSS)
2579 continue;
2580#endif
2581
2582 /* Check IP address */
2583 switch (hba->ip_cmp_method)
2584 {
2585 case ipCmpMask:
2586 if (hba->hostname)
2587 {
2588 if (!check_hostname(port,
2589 hba->hostname))
2590 continue;
2591 }
2592 else
2593 {
2594 if (!check_ip(&port->raddr,
2595 (struct sockaddr *) &hba->addr,
2596 (struct sockaddr *) &hba->mask))
2597 continue;
2598 }
2599 break;
2600 case ipCmpAll:
2601 break;
2602 case ipCmpSameHost:
2603 case ipCmpSameNet:
2604 if (!check_same_host_or_net(&port->raddr,
2605 hba->ip_cmp_method))
2606 continue;
2607 break;
2608 default:
2609 /* shouldn't get here, but deem it no-match if so */
2610 continue;
2611 }
2612 } /* != ctLocal */
2613
2614 /* Check database and role */
2615 if (!check_db(port->database_name, port->user_name, roleid,
2616 hba->databases))
2617 continue;
2618
2619 if (!check_role(port->user_name, roleid, hba->roles, false))
2620 continue;
2621
2622 /* Found a record that matched! */
2623 port->hba = hba;
2624 return;
2625 }
2626
2627 /* If no matching entry was found, then implicitly reject. */
2628 hba = palloc0(sizeof(HbaLine));
2630 port->hba = hba;
2631}
Oid get_role_oid(const char *rolname, bool missing_ok)
Definition: acl.c:5536
static bool check_role(const char *role, Oid roleid, List *tokens, bool case_insensitive)
Definition: hba.c:954
static bool check_ip(SockAddr *raddr, struct sockaddr *addr, struct sockaddr *mask)
Definition: hba.c:1169
static bool check_same_host_or_net(SockAddr *raddr, IPCompareMethod method)
Definition: hba.c:1210
static bool check_hostname(hbaPort *port, const char *hostname)
Definition: hba.c:1078
static List * parsed_hba_lines
Definition: hba.c:86
static bool check_db(const char *dbname, const char *role, Oid roleid, List *tokens)
Definition: hba.c:993
@ ipCmpAll
Definition: hba.h:55
@ ipCmpSameNet
Definition: hba.h:54
@ ipCmpMask
Definition: hba.h:52
@ ipCmpSameHost
Definition: hba.h:53
@ ctHostNoGSS
Definition: hba.h:65
@ ctHostSSL
Definition: hba.h:62
@ ctHostNoSSL
Definition: hba.h:63
@ ctHostGSS
Definition: hba.h:64
@ ctLocal
Definition: hba.h:60
@ uaImplicitReject
Definition: hba.h:28
void * palloc0(Size size)
Definition: mcxt.c:1973
static int port
Definition: pg_regress.c:115
unsigned int Oid
Definition: postgres_ext.h:30
Definition: hba.h:96
UserAuth auth_method
Definition: hba.h:109
struct sockaddr_storage mask
Definition: hba.h:105
char * hostname
Definition: hba.h:108
List * databases
Definition: hba.h:101
ConnType conntype
Definition: hba.h:100
struct sockaddr_storage addr
Definition: hba.h:103
List * roles
Definition: hba.h:102
IPCompareMethod ip_cmp_method
Definition: hba.h:107

References HbaLine::addr, HbaLine::auth_method, check_db(), check_hostname(), check_ip(), check_role(), check_same_host_or_net(), HbaLine::conntype, ctHostGSS, ctHostNoGSS, ctHostNoSSL, ctHostSSL, ctLocal, HbaLine::databases, get_role_oid(), HbaLine::hostname, HbaLine::ip_cmp_method, ipCmpAll, ipCmpMask, ipCmpSameHost, ipCmpSameNet, lfirst, HbaLine::mask, palloc0(), parsed_hba_lines, port, HbaLine::roles, and uaImplicitReject.

Referenced by hba_getauthmethod().

◆ check_hostname()

static bool check_hostname ( hbaPort port,
const char *  hostname 
)
static

Definition at line 1078 of file hba.c.

1079{
1080 struct addrinfo *gai_result,
1081 *gai;
1082 int ret;
1083 bool found;
1084
1085 /* Quick out if remote host name already known bad */
1086 if (port->remote_hostname_resolv < 0)
1087 return false;
1088
1089 /* Lookup remote host name if not already done */
1090 if (!port->remote_hostname)
1091 {
1092 char remote_hostname[NI_MAXHOST];
1093
1094 ret = pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
1095 remote_hostname, sizeof(remote_hostname),
1096 NULL, 0,
1097 NI_NAMEREQD);
1098 if (ret != 0)
1099 {
1100 /* remember failure; don't complain in the postmaster log yet */
1101 port->remote_hostname_resolv = -2;
1102 port->remote_hostname_errcode = ret;
1103 return false;
1104 }
1105
1106 port->remote_hostname = pstrdup(remote_hostname);
1107 }
1108
1109 /* Now see if remote host name matches this pg_hba line */
1110 if (!hostname_match(hostname, port->remote_hostname))
1111 return false;
1112
1113 /* If we already verified the forward lookup, we're done */
1114 if (port->remote_hostname_resolv == +1)
1115 return true;
1116
1117 /* Lookup IP from host name and check against original IP */
1118 ret = getaddrinfo(port->remote_hostname, NULL, NULL, &gai_result);
1119 if (ret != 0)
1120 {
1121 /* remember failure; don't complain in the postmaster log yet */
1122 port->remote_hostname_resolv = -2;
1123 port->remote_hostname_errcode = ret;
1124 return false;
1125 }
1126
1127 found = false;
1128 for (gai = gai_result; gai; gai = gai->ai_next)
1129 {
1130 if (gai->ai_addr->sa_family == port->raddr.addr.ss_family)
1131 {
1132 if (gai->ai_addr->sa_family == AF_INET)
1133 {
1134 if (ipv4eq((struct sockaddr_in *) gai->ai_addr,
1135 (struct sockaddr_in *) &port->raddr.addr))
1136 {
1137 found = true;
1138 break;
1139 }
1140 }
1141 else if (gai->ai_addr->sa_family == AF_INET6)
1142 {
1143 if (ipv6eq((struct sockaddr_in6 *) gai->ai_addr,
1144 (struct sockaddr_in6 *) &port->raddr.addr))
1145 {
1146 found = true;
1147 break;
1148 }
1149 }
1150 }
1151 }
1152
1153 if (gai_result)
1154 freeaddrinfo(gai_result);
1155
1156 if (!found)
1157 elog(DEBUG2, "pg_hba.conf host name \"%s\" rejected because address resolution did not return a match with IP address of client",
1158 hostname);
1159
1160 port->remote_hostname_resolv = found ? +1 : -1;
1161
1162 return found;
1163}
#define DEBUG2
Definition: elog.h:29
#define elog(elevel,...)
Definition: elog.h:225
static bool hostname_match(const char *pattern, const char *actual_hostname)
Definition: hba.c:1058
static bool ipv4eq(struct sockaddr_in *a, struct sockaddr_in *b)
Definition: hba.c:1037
static bool ipv6eq(struct sockaddr_in6 *a, struct sockaddr_in6 *b)
Definition: hba.c:1043
int pg_getnameinfo_all(const struct sockaddr_storage *addr, int salen, char *node, int nodelen, char *service, int servicelen, int flags)
Definition: ip.c:114
static char * hostname
Definition: pg_regress.c:114

References DEBUG2, elog, hostname, hostname_match(), ipv4eq(), ipv6eq(), pg_getnameinfo_all(), port, and pstrdup().

Referenced by check_hba().

◆ check_ident_usermap()

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

Definition at line 2819 of file hba.c.

2822{
2823 Oid roleid;
2824
2825 *found_p = false;
2826 *error_p = false;
2827
2828 if (strcmp(identLine->usermap, usermap_name) != 0)
2829 /* Line does not match the map name we're looking for, so just abort */
2830 return;
2831
2832 /* Get the target role's OID. Note we do not error out for bad role. */
2833 roleid = get_role_oid(pg_user, true);
2834
2835 /* Match? */
2836 if (token_has_regexp(identLine->system_user))
2837 {
2838 /*
2839 * Process the system username as a regular expression that returns
2840 * exactly one match. This is replaced for \1 in the database username
2841 * string, if present.
2842 */
2843 int r;
2844 regmatch_t matches[2];
2845 char *ofs;
2846 AuthToken *expanded_pg_user_token;
2847 bool created_temporary_token = false;
2848
2849 r = regexec_auth_token(system_user, identLine->system_user, 2, matches);
2850 if (r)
2851 {
2852 char errstr[100];
2853
2854 if (r != REG_NOMATCH)
2855 {
2856 /* REG_NOMATCH is not an error, everything else is */
2857 pg_regerror(r, identLine->system_user->regex, errstr, sizeof(errstr));
2858 ereport(LOG,
2859 (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
2860 errmsg("regular expression match for \"%s\" failed: %s",
2861 identLine->system_user->string + 1, errstr)));
2862 *error_p = true;
2863 }
2864 return;
2865 }
2866
2867 /*
2868 * Replace \1 with the first captured group unless the field already
2869 * has some special meaning, like a group membership or a regexp-based
2870 * check.
2871 */
2872 if (!token_is_member_check(identLine->pg_user) &&
2873 !token_has_regexp(identLine->pg_user) &&
2874 (ofs = strstr(identLine->pg_user->string, "\\1")) != NULL)
2875 {
2876 char *expanded_pg_user;
2877 int offset;
2878
2879 /* substitution of the first argument requested */
2880 if (matches[1].rm_so < 0)
2881 {
2882 ereport(LOG,
2883 (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
2884 errmsg("regular expression \"%s\" has no subexpressions as requested by backreference in \"%s\"",
2885 identLine->system_user->string + 1, identLine->pg_user->string)));
2886 *error_p = true;
2887 return;
2888 }
2889
2890 /*
2891 * length: original length minus length of \1 plus length of match
2892 * plus null terminator
2893 */
2894 expanded_pg_user = palloc0(strlen(identLine->pg_user->string) - 2 + (matches[1].rm_eo - matches[1].rm_so) + 1);
2895 offset = ofs - identLine->pg_user->string;
2896 memcpy(expanded_pg_user, identLine->pg_user->string, offset);
2897 memcpy(expanded_pg_user + offset,
2898 system_user + matches[1].rm_so,
2899 matches[1].rm_eo - matches[1].rm_so);
2900 strcat(expanded_pg_user, ofs + 2);
2901
2902 /*
2903 * Mark the token as quoted, so it will only be compared literally
2904 * and not for some special meaning, such as "all" or a group
2905 * membership check.
2906 */
2907 expanded_pg_user_token = make_auth_token(expanded_pg_user, true);
2908 created_temporary_token = true;
2909 pfree(expanded_pg_user);
2910 }
2911 else
2912 {
2913 expanded_pg_user_token = identLine->pg_user;
2914 }
2915
2916 /* check the Postgres user */
2917 *found_p = check_role(pg_user, roleid,
2918 list_make1(expanded_pg_user_token),
2919 case_insensitive);
2920
2921 if (created_temporary_token)
2922 free_auth_token(expanded_pg_user_token);
2923
2924 return;
2925 }
2926 else
2927 {
2928 /*
2929 * Not a regular expression, so make a complete match. If the system
2930 * user does not match, just leave.
2931 */
2932 if (case_insensitive)
2933 {
2934 if (!token_matches_insensitive(identLine->system_user,
2935 system_user))
2936 return;
2937 }
2938 else
2939 {
2940 if (!token_matches(identLine->system_user, system_user))
2941 return;
2942 }
2943
2944 /* check the Postgres user */
2945 *found_p = check_role(pg_user, roleid,
2946 list_make1(identLine->pg_user),
2947 case_insensitive);
2948 }
2949}
#define LOG
Definition: elog.h:31
#define ereport(elevel,...)
Definition: elog.h:149
static AuthToken * make_auth_token(const char *token, bool quoted)
Definition: hba.c:259
#define token_is_member_check(t)
Definition: hba.c:70
#define token_matches_insensitive(t, k)
Definition: hba.c:73
static void free_auth_token(AuthToken *token)
Definition: hba.c:280
void pfree(void *pointer)
Definition: mcxt.c:2150
Datum system_user(PG_FUNCTION_ARGS)
Definition: miscinit.c:949
#define list_make1(x1)
Definition: pg_list.h:212
size_t pg_regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size)
Definition: regerror.c:60
#define REG_NOMATCH
Definition: regex.h:216
#define regmatch_t
Definition: regex.h:246
regex_t * regex
Definition: hba.h:92
char * string
Definition: hba.h:90
AuthToken * pg_user
Definition: hba.h:151
AuthToken * system_user
Definition: hba.h:150
char * usermap
Definition: hba.h:149

References check_role(), ereport, errcode(), errmsg(), free_auth_token(), get_role_oid(), list_make1, LOG, make_auth_token(), palloc0(), pfree(), pg_regerror(), IdentLine::pg_user, REG_NOMATCH, AuthToken::regex, regexec_auth_token(), regmatch_t, AuthToken::string, system_user(), IdentLine::system_user, token_has_regexp, token_is_member_check, token_matches, token_matches_insensitive, and IdentLine::usermap.

Referenced by check_usermap().

◆ check_ip()

static bool check_ip ( SockAddr raddr,
struct sockaddr *  addr,
struct sockaddr *  mask 
)
static

Definition at line 1169 of file hba.c.

1170{
1171 if (raddr->addr.ss_family == addr->sa_family &&
1172 pg_range_sockaddr(&raddr->addr,
1173 (struct sockaddr_storage *) addr,
1174 (struct sockaddr_storage *) mask))
1175 return true;
1176 return false;
1177}
int pg_range_sockaddr(const struct sockaddr_storage *addr, const struct sockaddr_storage *netaddr, const struct sockaddr_storage *netmask)
Definition: ifaddr.c:49
struct sockaddr_storage addr
Definition: pqcomm.h:32

References SockAddr::addr, and pg_range_sockaddr().

Referenced by check_hba(), and check_network_callback().

◆ check_network_callback()

static void check_network_callback ( struct sockaddr *  addr,
struct sockaddr *  netmask,
void *  cb_data 
)
static

Definition at line 1183 of file hba.c.

1185{
1186 check_network_data *cn = (check_network_data *) cb_data;
1187 struct sockaddr_storage mask;
1188
1189 /* Already found a match? */
1190 if (cn->result)
1191 return;
1192
1193 if (cn->method == ipCmpSameHost)
1194 {
1195 /* Make an all-ones netmask of appropriate length for family */
1196 pg_sockaddr_cidr_mask(&mask, NULL, addr->sa_family);
1197 cn->result = check_ip(cn->raddr, addr, (struct sockaddr *) &mask);
1198 }
1199 else
1200 {
1201 /* Use the netmask of the interface itself */
1202 cn->result = check_ip(cn->raddr, addr, netmask);
1203 }
1204}
int pg_sockaddr_cidr_mask(struct sockaddr_storage *mask, char *numbits, int family)
Definition: ifaddr.c:105
bool result
Definition: hba.c:60
SockAddr * raddr
Definition: hba.c:59
IPCompareMethod method
Definition: hba.c:58

References check_ip(), ipCmpSameHost, check_network_data::method, pg_sockaddr_cidr_mask(), check_network_data::raddr, and check_network_data::result.

Referenced by check_same_host_or_net().

◆ check_role()

static bool check_role ( const char *  role,
Oid  roleid,
List tokens,
bool  case_insensitive 
)
static

Definition at line 954 of file hba.c.

955{
956 ListCell *cell;
957 AuthToken *tok;
958
959 foreach(cell, tokens)
960 {
961 tok = lfirst(cell);
962 if (token_is_member_check(tok))
963 {
964 if (is_member(roleid, tok->string + 1))
965 return true;
966 }
967 else if (token_is_keyword(tok, "all"))
968 return true;
969 else if (token_has_regexp(tok))
970 {
971 if (regexec_auth_token(role, tok, 0, NULL) == REG_OKAY)
972 return true;
973 }
974 else if (case_insensitive)
975 {
976 if (token_matches_insensitive(tok, role))
977 return true;
978 }
979 else if (token_matches(tok, role))
980 return true;
981 }
982 return false;
983}

References is_member(), lfirst, REG_OKAY, regexec_auth_token(), AuthToken::string, token_has_regexp, token_is_keyword, token_is_member_check, token_matches, and token_matches_insensitive.

Referenced by check_hba(), and check_ident_usermap().

◆ check_same_host_or_net()

static bool check_same_host_or_net ( SockAddr raddr,
IPCompareMethod  method 
)
static

Definition at line 1210 of file hba.c.

1211{
1213
1214 cn.method = method;
1215 cn.raddr = raddr;
1216 cn.result = false;
1217
1218 errno = 0;
1220 {
1221 ereport(LOG,
1222 (errmsg("error enumerating network interfaces: %m")));
1223 return false;
1224 }
1225
1226 return cn.result;
1227}
static void check_network_callback(struct sockaddr *addr, struct sockaddr *netmask, void *cb_data)
Definition: hba.c:1183
int pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data)
Definition: ifaddr.c:425

References check_network_callback(), ereport, errmsg(), LOG, check_network_data::method, pg_foreach_ifaddr(), check_network_data::raddr, and check_network_data::result.

Referenced by check_hba().

◆ check_usermap()

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

Definition at line 2966 of file hba.c.

2970{
2971 bool found_entry = false,
2972 error = false;
2973
2974 if (usermap_name == NULL || usermap_name[0] == '\0')
2975 {
2976 if (case_insensitive)
2977 {
2978 if (pg_strcasecmp(pg_user, system_user) == 0)
2979 return STATUS_OK;
2980 }
2981 else
2982 {
2983 if (strcmp(pg_user, system_user) == 0)
2984 return STATUS_OK;
2985 }
2986 ereport(LOG,
2987 (errmsg("provided user name (%s) and authenticated user name (%s) do not match",
2988 pg_user, system_user)));
2989 return STATUS_ERROR;
2990 }
2991 else
2992 {
2993 ListCell *line_cell;
2994
2995 foreach(line_cell, parsed_ident_lines)
2996 {
2997 check_ident_usermap(lfirst(line_cell), usermap_name,
2998 pg_user, system_user, case_insensitive,
2999 &found_entry, &error);
3000 if (found_entry || error)
3001 break;
3002 }
3003 }
3004 if (!found_entry && !error)
3005 {
3006 ereport(LOG,
3007 (errmsg("no match in usermap \"%s\" for user \"%s\" authenticated as \"%s\"",
3008 usermap_name, pg_user, system_user)));
3009 }
3010 return found_entry ? STATUS_OK : STATUS_ERROR;
3011}
#define STATUS_OK
Definition: c.h:1140
#define STATUS_ERROR
Definition: c.h:1141
static List * parsed_ident_lines
Definition: hba.c:93
static void check_ident_usermap(IdentLine *identLine, const char *usermap_name, const char *pg_user, const char *system_user, bool case_insensitive, bool *found_p, bool *error_p)
Definition: hba.c:2819
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
static void error(void)
Definition: sql-dyntest.c:147

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

Referenced by auth_peer(), ident_inet(), and validate().

◆ copy_auth_token()

static AuthToken * copy_auth_token ( AuthToken in)
static

Definition at line 290 of file hba.c.

291{
292 AuthToken *out = make_auth_token(in->string, in->quoted);
293
294 return out;
295}
bool quoted
Definition: hba.h:91

References make_auth_token(), AuthToken::quoted, and AuthToken::string.

Referenced by parse_hba_line(), and parse_ident_line().

◆ free_auth_file()

void free_auth_file ( FILE *  file,
int  depth 
)

Definition at line 572 of file hba.c.

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

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

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

◆ free_auth_token()

static void free_auth_token ( AuthToken token)
static

Definition at line 280 of file hba.c.

281{
283 pg_regfree(token->regex);
284}
void pg_regfree(regex_t *re)
Definition: regfree.c:49

References pg_regfree(), and token_has_regexp.

Referenced by check_ident_usermap().

◆ hba_authname()

const char * hba_authname ( UserAuth  auth_method)

Definition at line 3123 of file hba.c.

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

References UserAuthName.

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

◆ hba_getauthmethod()

void hba_getauthmethod ( hbaPort port)

Definition at line 3110 of file hba.c.

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

References check_hba(), and port.

Referenced by ClientAuthentication().

◆ hostname_match()

static bool hostname_match ( const char *  pattern,
const char *  actual_hostname 
)
static

Definition at line 1058 of file hba.c.

1059{
1060 if (pattern[0] == '.') /* suffix match */
1061 {
1062 size_t plen = strlen(pattern);
1063 size_t hlen = strlen(actual_hostname);
1064
1065 if (hlen < plen)
1066 return false;
1067
1068 return (pg_strcasecmp(pattern, actual_hostname + (hlen - plen)) == 0);
1069 }
1070 else
1071 return (pg_strcasecmp(pattern, actual_hostname) == 0);
1072}

References pg_strcasecmp().

Referenced by check_hostname().

◆ ipv4eq()

static bool ipv4eq ( struct sockaddr_in *  a,
struct sockaddr_in *  b 
)
static

Definition at line 1037 of file hba.c.

1038{
1039 return (a->sin_addr.s_addr == b->sin_addr.s_addr);
1040}
int b
Definition: isn.c:74
int a
Definition: isn.c:73

References a, and b.

Referenced by check_hostname().

◆ ipv6eq()

static bool ipv6eq ( struct sockaddr_in6 *  a,
struct sockaddr_in6 *  b 
)
static

Definition at line 1043 of file hba.c.

1044{
1045 int i;
1046
1047 for (i = 0; i < 16; i++)
1048 if (a->sin6_addr.s6_addr[i] != b->sin6_addr.s6_addr[i])
1049 return false;
1050
1051 return true;
1052}
int i
Definition: isn.c:77

References a, b, and i.

Referenced by check_hostname().

◆ is_member()

static bool is_member ( Oid  userid,
const char *  role 
)
static

Definition at line 925 of file hba.c.

926{
927 Oid roleid;
928
929 if (!OidIsValid(userid))
930 return false; /* if user not exist, say "no" */
931
932 roleid = get_role_oid(role, true);
933
934 if (!OidIsValid(roleid))
935 return false; /* if target role not exist, say "no" */
936
937 /*
938 * See if user is directly or indirectly a member of role. For this
939 * purpose, a superuser is not considered to be automatically a member of
940 * the role, so group auth only applies to explicit membership.
941 */
942 return is_member_of_role_nosuper(userid, roleid);
943}
bool is_member_of_role_nosuper(Oid member, Oid role)
Definition: acl.c:5376
#define OidIsValid(objectId)
Definition: c.h:746

References get_role_oid(), is_member_of_role_nosuper(), and OidIsValid.

Referenced by check_db(), and check_role().

◆ load_hba()

bool load_hba ( void  )

Definition at line 2645 of file hba.c.

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

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

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

◆ load_ident()

bool load_ident ( void  )

Definition at line 3021 of file hba.c.

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

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

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

◆ make_auth_token()

static AuthToken * make_auth_token ( const char *  token,
bool  quoted 
)
static

Definition at line 259 of file hba.c.

260{
261 AuthToken *authtoken;
262 int toklen;
263
264 toklen = strlen(token);
265 /* we copy string into same palloc block as the struct */
266 authtoken = (AuthToken *) palloc0(sizeof(AuthToken) + toklen + 1);
267 authtoken->string = (char *) authtoken + sizeof(AuthToken);
268 authtoken->quoted = quoted;
269 authtoken->regex = NULL;
270 memcpy(authtoken->string, token, toklen + 1);
271
272 return authtoken;
273}

References palloc0(), AuthToken::quoted, AuthToken::regex, and AuthToken::string.

Referenced by check_ident_usermap(), copy_auth_token(), and next_field_expand().

◆ next_field_expand()

static List * next_field_expand ( const char *  filename,
char **  lineptr,
int  elevel,
int  depth,
char **  err_msg 
)
static

Definition at line 381 of file hba.c.

383{
385 bool trailing_comma;
386 bool initial_quote;
387 List *tokens = NIL;
388
390
391 do
392 {
393 if (!next_token(lineptr, &buf,
394 &initial_quote, &trailing_comma))
395 break;
396
397 /* Is this referencing a file? */
398 if (!initial_quote && buf.len > 1 && buf.data[0] == '@')
399 tokens = tokenize_expand_file(tokens, filename, buf.data + 1,
400 elevel, depth + 1, err_msg);
401 else
402 {
403 MemoryContext oldcxt;
404
405 /*
406 * lappend() may do its own allocations, so move to the context
407 * for the list of tokens.
408 */
410 tokens = lappend(tokens, make_auth_token(buf.data, initial_quote));
411 MemoryContextSwitchTo(oldcxt);
412 }
413 } while (trailing_comma && (*err_msg == NULL));
414
415 pfree(buf.data);
416
417 return tokens;
418}
static List * tokenize_expand_file(List *tokens, const char *outer_filename, const char *inc_filename, int elevel, int depth, char **err_msg)
Definition: hba.c:495
static bool next_token(char **lineptr, StringInfo buf, bool *initial_quote, bool *terminating_comma)
Definition: hba.c:187
static char * filename
Definition: pg_dumpall.c:123
static char * buf
Definition: pg_test_fsync.c:72
void initStringInfo(StringInfo str)
Definition: stringinfo.c:97

References buf, filename, initStringInfo(), lappend(), make_auth_token(), MemoryContextSwitchTo(), next_token(), NIL, pfree(), tokenize_context, and tokenize_expand_file().

Referenced by tokenize_auth_file().

◆ next_token()

static bool next_token ( char **  lineptr,
StringInfo  buf,
bool *  initial_quote,
bool *  terminating_comma 
)
static

Definition at line 187 of file hba.c.

189{
190 int c;
191 bool in_quote = false;
192 bool was_quote = false;
193 bool saw_quote = false;
194
195 /* Initialize output parameters */
197 *initial_quote = false;
198 *terminating_comma = false;
199
200 /* Move over any whitespace and commas preceding the next token */
201 while ((c = (*(*lineptr)++)) != '\0' && (pg_isblank(c) || c == ','))
202 ;
203
204 /*
205 * Build a token in buf of next characters up to EOL, unquoted comma, or
206 * unquoted whitespace.
207 */
208 while (c != '\0' &&
209 (!pg_isblank(c) || in_quote))
210 {
211 /* skip comments to EOL */
212 if (c == '#' && !in_quote)
213 {
214 while ((c = (*(*lineptr)++)) != '\0')
215 ;
216 break;
217 }
218
219 /* we do not pass back a terminating comma in the token */
220 if (c == ',' && !in_quote)
221 {
222 *terminating_comma = true;
223 break;
224 }
225
226 if (c != '"' || was_quote)
228
229 /* Literal double-quote is two double-quotes */
230 if (in_quote && c == '"')
231 was_quote = !was_quote;
232 else
233 was_quote = false;
234
235 if (c == '"')
236 {
237 in_quote = !in_quote;
238 saw_quote = true;
239 if (buf->len == 0)
240 *initial_quote = true;
241 }
242
243 c = *(*lineptr)++;
244 }
245
246 /*
247 * Un-eat the char right after the token (critical in case it is '\0',
248 * else next call will read past end of string).
249 */
250 (*lineptr)--;
251
252 return (saw_quote || buf->len > 0);
253}
bool pg_isblank(const char c)
Definition: hba.c:146
char * c
void resetStringInfo(StringInfo str)
Definition: stringinfo.c:126
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:242

References appendStringInfoChar(), buf, pg_isblank(), and resetStringInfo().

Referenced by base_yylex(), filtered_base_yylex(), and next_field_expand().

◆ open_auth_file()

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

Definition at line 597 of file hba.c.

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

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_auth_opt()

static bool parse_hba_auth_opt ( char *  name,
char *  val,
HbaLine hbaline,
int  elevel,
char **  err_msg 
)
static

Definition at line 2087 of file hba.c.

2089{
2090 int line_num = hbaline->linenumber;
2091 char *file_name = hbaline->sourcefile;
2092
2093#ifdef USE_LDAP
2094 hbaline->ldapscope = LDAP_SCOPE_SUBTREE;
2095#endif
2096
2097 if (strcmp(name, "map") == 0)
2098 {
2099 if (hbaline->auth_method != uaIdent &&
2100 hbaline->auth_method != uaPeer &&
2101 hbaline->auth_method != uaGSS &&
2102 hbaline->auth_method != uaSSPI &&
2103 hbaline->auth_method != uaCert &&
2104 hbaline->auth_method != uaOAuth)
2105 INVALID_AUTH_OPTION("map", gettext_noop("ident, peer, gssapi, sspi, cert, and oauth"));
2106 hbaline->usermap = pstrdup(val);
2107 }
2108 else if (strcmp(name, "clientcert") == 0)
2109 {
2110 if (hbaline->conntype != ctHostSSL)
2111 {
2112 ereport(elevel,
2113 (errcode(ERRCODE_CONFIG_FILE_ERROR),
2114 errmsg("clientcert can only be configured for \"hostssl\" rows"),
2115 errcontext("line %d of configuration file \"%s\"",
2116 line_num, file_name)));
2117 *err_msg = "clientcert can only be configured for \"hostssl\" rows";
2118 return false;
2119 }
2120
2121 if (strcmp(val, "verify-full") == 0)
2122 {
2123 hbaline->clientcert = clientCertFull;
2124 }
2125 else if (strcmp(val, "verify-ca") == 0)
2126 {
2127 if (hbaline->auth_method == uaCert)
2128 {
2129 ereport(elevel,
2130 (errcode(ERRCODE_CONFIG_FILE_ERROR),
2131 errmsg("clientcert only accepts \"verify-full\" when using \"cert\" authentication"),
2132 errcontext("line %d of configuration file \"%s\"",
2133 line_num, file_name)));
2134 *err_msg = "clientcert can only be set to \"verify-full\" when using \"cert\" authentication";
2135 return false;
2136 }
2137
2138 hbaline->clientcert = clientCertCA;
2139 }
2140 else
2141 {
2142 ereport(elevel,
2143 (errcode(ERRCODE_CONFIG_FILE_ERROR),
2144 errmsg("invalid value for clientcert: \"%s\"", val),
2145 errcontext("line %d of configuration file \"%s\"",
2146 line_num, file_name)));
2147 return false;
2148 }
2149 }
2150 else if (strcmp(name, "clientname") == 0)
2151 {
2152 if (hbaline->conntype != ctHostSSL)
2153 {
2154 ereport(elevel,
2155 (errcode(ERRCODE_CONFIG_FILE_ERROR),
2156 errmsg("clientname can only be configured for \"hostssl\" rows"),
2157 errcontext("line %d of configuration file \"%s\"",
2158 line_num, file_name)));
2159 *err_msg = "clientname can only be configured for \"hostssl\" rows";
2160 return false;
2161 }
2162
2163 if (strcmp(val, "CN") == 0)
2164 {
2165 hbaline->clientcertname = clientCertCN;
2166 }
2167 else if (strcmp(val, "DN") == 0)
2168 {
2169 hbaline->clientcertname = clientCertDN;
2170 }
2171 else
2172 {
2173 ereport(elevel,
2174 (errcode(ERRCODE_CONFIG_FILE_ERROR),
2175 errmsg("invalid value for clientname: \"%s\"", val),
2176 errcontext("line %d of configuration file \"%s\"",
2177 line_num, file_name)));
2178 return false;
2179 }
2180 }
2181 else if (strcmp(name, "pamservice") == 0)
2182 {
2183 REQUIRE_AUTH_OPTION(uaPAM, "pamservice", "pam");
2184 hbaline->pamservice = pstrdup(val);
2185 }
2186 else if (strcmp(name, "pam_use_hostname") == 0)
2187 {
2188 REQUIRE_AUTH_OPTION(uaPAM, "pam_use_hostname", "pam");
2189 if (strcmp(val, "1") == 0)
2190 hbaline->pam_use_hostname = true;
2191 else
2192 hbaline->pam_use_hostname = false;
2193 }
2194 else if (strcmp(name, "ldapurl") == 0)
2195 {
2196#ifdef LDAP_API_FEATURE_X_OPENLDAP
2197 LDAPURLDesc *urldata;
2198 int rc;
2199#endif
2200
2201 REQUIRE_AUTH_OPTION(uaLDAP, "ldapurl", "ldap");
2202#ifdef LDAP_API_FEATURE_X_OPENLDAP
2203 rc = ldap_url_parse(val, &urldata);
2204 if (rc != LDAP_SUCCESS)
2205 {
2206 ereport(elevel,
2207 (errcode(ERRCODE_CONFIG_FILE_ERROR),
2208 errmsg("could not parse LDAP URL \"%s\": %s", val, ldap_err2string(rc))));
2209 *err_msg = psprintf("could not parse LDAP URL \"%s\": %s",
2210 val, ldap_err2string(rc));
2211 return false;
2212 }
2213
2214 if (strcmp(urldata->lud_scheme, "ldap") != 0 &&
2215 strcmp(urldata->lud_scheme, "ldaps") != 0)
2216 {
2217 ereport(elevel,
2218 (errcode(ERRCODE_CONFIG_FILE_ERROR),
2219 errmsg("unsupported LDAP URL scheme: %s", urldata->lud_scheme)));
2220 *err_msg = psprintf("unsupported LDAP URL scheme: %s",
2221 urldata->lud_scheme);
2222 ldap_free_urldesc(urldata);
2223 return false;
2224 }
2225
2226 if (urldata->lud_scheme)
2227 hbaline->ldapscheme = pstrdup(urldata->lud_scheme);
2228 if (urldata->lud_host)
2229 hbaline->ldapserver = pstrdup(urldata->lud_host);
2230 hbaline->ldapport = urldata->lud_port;
2231 if (urldata->lud_dn)
2232 hbaline->ldapbasedn = pstrdup(urldata->lud_dn);
2233
2234 if (urldata->lud_attrs)
2235 hbaline->ldapsearchattribute = pstrdup(urldata->lud_attrs[0]); /* only use first one */
2236 hbaline->ldapscope = urldata->lud_scope;
2237 if (urldata->lud_filter)
2238 hbaline->ldapsearchfilter = pstrdup(urldata->lud_filter);
2239 ldap_free_urldesc(urldata);
2240#else /* not OpenLDAP */
2241 ereport(elevel,
2242 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2243 errmsg("LDAP URLs not supported on this platform")));
2244 *err_msg = "LDAP URLs not supported on this platform";
2245#endif /* not OpenLDAP */
2246 }
2247 else if (strcmp(name, "ldaptls") == 0)
2248 {
2249 REQUIRE_AUTH_OPTION(uaLDAP, "ldaptls", "ldap");
2250 if (strcmp(val, "1") == 0)
2251 hbaline->ldaptls = true;
2252 else
2253 hbaline->ldaptls = false;
2254 }
2255 else if (strcmp(name, "ldapscheme") == 0)
2256 {
2257 REQUIRE_AUTH_OPTION(uaLDAP, "ldapscheme", "ldap");
2258 if (strcmp(val, "ldap") != 0 && strcmp(val, "ldaps") != 0)
2259 ereport(elevel,
2260 (errcode(ERRCODE_CONFIG_FILE_ERROR),
2261 errmsg("invalid ldapscheme value: \"%s\"", val),
2262 errcontext("line %d of configuration file \"%s\"",
2263 line_num, file_name)));
2264 hbaline->ldapscheme = pstrdup(val);
2265 }
2266 else if (strcmp(name, "ldapserver") == 0)
2267 {
2268 REQUIRE_AUTH_OPTION(uaLDAP, "ldapserver", "ldap");
2269 hbaline->ldapserver = pstrdup(val);
2270 }
2271 else if (strcmp(name, "ldapport") == 0)
2272 {
2273 REQUIRE_AUTH_OPTION(uaLDAP, "ldapport", "ldap");
2274 hbaline->ldapport = atoi(val);
2275 if (hbaline->ldapport == 0)
2276 {
2277 ereport(elevel,
2278 (errcode(ERRCODE_CONFIG_FILE_ERROR),
2279 errmsg("invalid LDAP port number: \"%s\"", val),
2280 errcontext("line %d of configuration file \"%s\"",
2281 line_num, file_name)));
2282 *err_msg = psprintf("invalid LDAP port number: \"%s\"", val);
2283 return false;
2284 }
2285 }
2286 else if (strcmp(name, "ldapbinddn") == 0)
2287 {
2288 REQUIRE_AUTH_OPTION(uaLDAP, "ldapbinddn", "ldap");
2289 hbaline->ldapbinddn = pstrdup(val);
2290 }
2291 else if (strcmp(name, "ldapbindpasswd") == 0)
2292 {
2293 REQUIRE_AUTH_OPTION(uaLDAP, "ldapbindpasswd", "ldap");
2294 hbaline->ldapbindpasswd = pstrdup(val);
2295 }
2296 else if (strcmp(name, "ldapsearchattribute") == 0)
2297 {
2298 REQUIRE_AUTH_OPTION(uaLDAP, "ldapsearchattribute", "ldap");
2299 hbaline->ldapsearchattribute = pstrdup(val);
2300 }
2301 else if (strcmp(name, "ldapsearchfilter") == 0)
2302 {
2303 REQUIRE_AUTH_OPTION(uaLDAP, "ldapsearchfilter", "ldap");
2304 hbaline->ldapsearchfilter = pstrdup(val);
2305 }
2306 else if (strcmp(name, "ldapbasedn") == 0)
2307 {
2308 REQUIRE_AUTH_OPTION(uaLDAP, "ldapbasedn", "ldap");
2309 hbaline->ldapbasedn = pstrdup(val);
2310 }
2311 else if (strcmp(name, "ldapprefix") == 0)
2312 {
2313 REQUIRE_AUTH_OPTION(uaLDAP, "ldapprefix", "ldap");
2314 hbaline->ldapprefix = pstrdup(val);
2315 }
2316 else if (strcmp(name, "ldapsuffix") == 0)
2317 {
2318 REQUIRE_AUTH_OPTION(uaLDAP, "ldapsuffix", "ldap");
2319 hbaline->ldapsuffix = pstrdup(val);
2320 }
2321 else if (strcmp(name, "krb_realm") == 0)
2322 {
2323 if (hbaline->auth_method != uaGSS &&
2324 hbaline->auth_method != uaSSPI)
2325 INVALID_AUTH_OPTION("krb_realm", gettext_noop("gssapi and sspi"));
2326 hbaline->krb_realm = pstrdup(val);
2327 }
2328 else if (strcmp(name, "include_realm") == 0)
2329 {
2330 if (hbaline->auth_method != uaGSS &&
2331 hbaline->auth_method != uaSSPI)
2332 INVALID_AUTH_OPTION("include_realm", gettext_noop("gssapi and sspi"));
2333 if (strcmp(val, "1") == 0)
2334 hbaline->include_realm = true;
2335 else
2336 hbaline->include_realm = false;
2337 }
2338 else if (strcmp(name, "compat_realm") == 0)
2339 {
2340 if (hbaline->auth_method != uaSSPI)
2341 INVALID_AUTH_OPTION("compat_realm", gettext_noop("sspi"));
2342 if (strcmp(val, "1") == 0)
2343 hbaline->compat_realm = true;
2344 else
2345 hbaline->compat_realm = false;
2346 }
2347 else if (strcmp(name, "upn_username") == 0)
2348 {
2349 if (hbaline->auth_method != uaSSPI)
2350 INVALID_AUTH_OPTION("upn_username", gettext_noop("sspi"));
2351 if (strcmp(val, "1") == 0)
2352 hbaline->upn_username = true;
2353 else
2354 hbaline->upn_username = false;
2355 }
2356 else if (strcmp(name, "radiusservers") == 0)
2357 {
2358 struct addrinfo *gai_result;
2359 struct addrinfo hints;
2360 int ret;
2361 List *parsed_servers;
2362 ListCell *l;
2363 char *dupval = pstrdup(val);
2364
2365 REQUIRE_AUTH_OPTION(uaRADIUS, "radiusservers", "radius");
2366
2367 if (!SplitGUCList(dupval, ',', &parsed_servers))
2368 {
2369 /* syntax error in list */
2370 ereport(elevel,
2371 (errcode(ERRCODE_CONFIG_FILE_ERROR),
2372 errmsg("could not parse RADIUS server list \"%s\"",
2373 val),
2374 errcontext("line %d of configuration file \"%s\"",
2375 line_num, file_name)));
2376 return false;
2377 }
2378
2379 /* For each entry in the list, translate it */
2380 foreach(l, parsed_servers)
2381 {
2382 MemSet(&hints, 0, sizeof(hints));
2383 hints.ai_socktype = SOCK_DGRAM;
2384 hints.ai_family = AF_UNSPEC;
2385
2386 ret = pg_getaddrinfo_all((char *) lfirst(l), NULL, &hints, &gai_result);
2387 if (ret || !gai_result)
2388 {
2389 ereport(elevel,
2390 (errcode(ERRCODE_CONFIG_FILE_ERROR),
2391 errmsg("could not translate RADIUS server name \"%s\" to address: %s",
2392 (char *) lfirst(l), gai_strerror(ret)),
2393 errcontext("line %d of configuration file \"%s\"",
2394 line_num, file_name)));
2395 if (gai_result)
2396 pg_freeaddrinfo_all(hints.ai_family, gai_result);
2397
2398 list_free(parsed_servers);
2399 return false;
2400 }
2401 pg_freeaddrinfo_all(hints.ai_family, gai_result);
2402 }
2403
2404 /* All entries are OK, so store them */
2405 hbaline->radiusservers = parsed_servers;
2406 hbaline->radiusservers_s = pstrdup(val);
2407 }
2408 else if (strcmp(name, "radiusports") == 0)
2409 {
2410 List *parsed_ports;
2411 ListCell *l;
2412 char *dupval = pstrdup(val);
2413
2414 REQUIRE_AUTH_OPTION(uaRADIUS, "radiusports", "radius");
2415
2416 if (!SplitGUCList(dupval, ',', &parsed_ports))
2417 {
2418 ereport(elevel,
2419 (errcode(ERRCODE_CONFIG_FILE_ERROR),
2420 errmsg("could not parse RADIUS port list \"%s\"",
2421 val),
2422 errcontext("line %d of configuration file \"%s\"",
2423 line_num, file_name)));
2424 *err_msg = psprintf("invalid RADIUS port number: \"%s\"", val);
2425 return false;
2426 }
2427
2428 foreach(l, parsed_ports)
2429 {
2430 if (atoi(lfirst(l)) == 0)
2431 {
2432 ereport(elevel,
2433 (errcode(ERRCODE_CONFIG_FILE_ERROR),
2434 errmsg("invalid RADIUS port number: \"%s\"", val),
2435 errcontext("line %d of configuration file \"%s\"",
2436 line_num, file_name)));
2437
2438 return false;
2439 }
2440 }
2441 hbaline->radiusports = parsed_ports;
2442 hbaline->radiusports_s = pstrdup(val);
2443 }
2444 else if (strcmp(name, "radiussecrets") == 0)
2445 {
2446 List *parsed_secrets;
2447 char *dupval = pstrdup(val);
2448
2449 REQUIRE_AUTH_OPTION(uaRADIUS, "radiussecrets", "radius");
2450
2451 if (!SplitGUCList(dupval, ',', &parsed_secrets))
2452 {
2453 /* syntax error in list */
2454 ereport(elevel,
2455 (errcode(ERRCODE_CONFIG_FILE_ERROR),
2456 errmsg("could not parse RADIUS secret list \"%s\"",
2457 val),
2458 errcontext("line %d of configuration file \"%s\"",
2459 line_num, file_name)));
2460 return false;
2461 }
2462
2463 hbaline->radiussecrets = parsed_secrets;
2464 hbaline->radiussecrets_s = pstrdup(val);
2465 }
2466 else if (strcmp(name, "radiusidentifiers") == 0)
2467 {
2468 List *parsed_identifiers;
2469 char *dupval = pstrdup(val);
2470
2471 REQUIRE_AUTH_OPTION(uaRADIUS, "radiusidentifiers", "radius");
2472
2473 if (!SplitGUCList(dupval, ',', &parsed_identifiers))
2474 {
2475 /* syntax error in list */
2476 ereport(elevel,
2477 (errcode(ERRCODE_CONFIG_FILE_ERROR),
2478 errmsg("could not parse RADIUS identifiers list \"%s\"",
2479 val),
2480 errcontext("line %d of configuration file \"%s\"",
2481 line_num, file_name)));
2482 return false;
2483 }
2484
2485 hbaline->radiusidentifiers = parsed_identifiers;
2486 hbaline->radiusidentifiers_s = pstrdup(val);
2487 }
2488 else if (strcmp(name, "issuer") == 0)
2489 {
2490 REQUIRE_AUTH_OPTION(uaOAuth, "issuer", "oauth");
2491 hbaline->oauth_issuer = pstrdup(val);
2492 }
2493 else if (strcmp(name, "scope") == 0)
2494 {
2495 REQUIRE_AUTH_OPTION(uaOAuth, "scope", "oauth");
2496 hbaline->oauth_scope = pstrdup(val);
2497 }
2498 else if (strcmp(name, "validator") == 0)
2499 {
2500 REQUIRE_AUTH_OPTION(uaOAuth, "validator", "oauth");
2501 hbaline->oauth_validator = pstrdup(val);
2502 }
2503 else if (strcmp(name, "delegate_ident_mapping") == 0)
2504 {
2505 REQUIRE_AUTH_OPTION(uaOAuth, "delegate_ident_mapping", "oauth");
2506 if (strcmp(val, "1") == 0)
2507 hbaline->oauth_skip_usermap = true;
2508 else
2509 hbaline->oauth_skip_usermap = false;
2510 }
2511 else
2512 {
2513 ereport(elevel,
2514 (errcode(ERRCODE_CONFIG_FILE_ERROR),
2515 errmsg("unrecognized authentication option name: \"%s\"",
2516 name),
2517 errcontext("line %d of configuration file \"%s\"",
2518 line_num, file_name)));
2519 *err_msg = psprintf("unrecognized authentication option name: \"%s\"",
2520 name);
2521 return false;
2522 }
2523 return true;
2524}
#define gettext_noop(x)
Definition: c.h:1167
#define MemSet(start, val, len)
Definition: c.h:991
#define INVALID_AUTH_OPTION(optname, validmethods)
Definition: hba.c:1244
#define REQUIRE_AUTH_OPTION(methodval, optname, validmethods)
Definition: hba.c:1258
@ uaLDAP
Definition: hba.h:38
@ uaPeer
Definition: hba.h:41
@ uaPAM
Definition: hba.h:36
@ uaCert
Definition: hba.h:39
@ uaGSS
Definition: hba.h:34
@ uaRADIUS
Definition: hba.h:40
@ uaIdent
Definition: hba.h:30
@ uaOAuth
Definition: hba.h:42
@ uaSSPI
Definition: hba.h:35
@ clientCertDN
Definition: hba.h:78
@ clientCertCN
Definition: hba.h:77
@ clientCertFull
Definition: hba.h:72
@ clientCertCA
Definition: hba.h:71
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
void list_free(List *list)
Definition: list.c:1546
const char * gai_strerror(int ecode)
bool upn_username
Definition: hba.h:130
char * sourcefile
Definition: hba.h:97
ClientCertName clientcertname
Definition: hba.h:126
List * radiusservers
Definition: hba.h:131
bool oauth_skip_usermap
Definition: hba.h:142
char * ldapserver
Definition: hba.h:115
bool include_realm
Definition: hba.h:128
ClientCertMode clientcert
Definition: hba.h:125
char * ldapsearchfilter
Definition: hba.h:120
char * ldapscheme
Definition: hba.h:114
char * oauth_issuer
Definition: hba.h:139
char * ldapprefix
Definition: hba.h:123
List * radiussecrets
Definition: hba.h:133
char * ldapsearchattribute
Definition: hba.h:119
char * krb_realm
Definition: hba.h:127
char * ldapbasedn
Definition: hba.h:121
bool pam_use_hostname
Definition: hba.h:112
int linenumber
Definition: hba.h:98
char * radiussecrets_s
Definition: hba.h:134
char * oauth_scope
Definition: hba.h:140
List * radiusports
Definition: hba.h:137
List * radiusidentifiers
Definition: hba.h:135
char * oauth_validator
Definition: hba.h:141
char * pamservice
Definition: hba.h:111
char * usermap
Definition: hba.h:110
char * ldapsuffix
Definition: hba.h:124
int ldapport
Definition: hba.h:116
char * ldapbindpasswd
Definition: hba.h:118
char * radiusports_s
Definition: hba.h:138
char * ldapbinddn
Definition: hba.h:117
bool compat_realm
Definition: hba.h:129
int ldapscope
Definition: hba.h:122
bool ldaptls
Definition: hba.h:113
char * radiusservers_s
Definition: hba.h:132
char * radiusidentifiers_s
Definition: hba.h:136
bool SplitGUCList(char *rawstring, char separator, List **namelist)
Definition: varlena.c:3773
const char * name

References HbaLine::auth_method, HbaLine::clientcert, clientCertCA, clientCertCN, clientCertDN, clientCertFull, HbaLine::clientcertname, HbaLine::compat_realm, HbaLine::conntype, ctHostSSL, ereport, errcode(), errcontext, errmsg(), gai_strerror(), gettext_noop, HbaLine::include_realm, INVALID_AUTH_OPTION, HbaLine::krb_realm, HbaLine::ldapbasedn, HbaLine::ldapbinddn, HbaLine::ldapbindpasswd, HbaLine::ldapport, HbaLine::ldapprefix, HbaLine::ldapscheme, HbaLine::ldapscope, HbaLine::ldapsearchattribute, HbaLine::ldapsearchfilter, HbaLine::ldapserver, HbaLine::ldapsuffix, HbaLine::ldaptls, lfirst, HbaLine::linenumber, list_free(), MemSet, name, HbaLine::oauth_issuer, HbaLine::oauth_scope, HbaLine::oauth_skip_usermap, HbaLine::oauth_validator, HbaLine::pam_use_hostname, HbaLine::pamservice, pg_freeaddrinfo_all(), pg_getaddrinfo_all(), psprintf(), pstrdup(), HbaLine::radiusidentifiers, HbaLine::radiusidentifiers_s, HbaLine::radiusports, HbaLine::radiusports_s, HbaLine::radiussecrets, HbaLine::radiussecrets_s, HbaLine::radiusservers, HbaLine::radiusservers_s, REQUIRE_AUTH_OPTION, HbaLine::sourcefile, SplitGUCList(), uaCert, uaGSS, uaIdent, uaLDAP, uaOAuth, uaPAM, uaPeer, uaRADIUS, uaSSPI, HbaLine::upn_username, HbaLine::usermap, and val.

Referenced by parse_hba_line().

◆ parse_hba_line()

HbaLine * parse_hba_line ( TokenizedAuthLine tok_line,
int  elevel 
)

Definition at line 1328 of file hba.c.

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

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

Referenced by fill_hba_view(), and load_hba().

◆ parse_ident_line()

IdentLine * parse_ident_line ( TokenizedAuthLine tok_line,
int  elevel 
)

Definition at line 2751 of file hba.c.

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

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

Referenced by fill_ident_view(), and load_ident().

◆ pg_isblank()

bool pg_isblank ( const char  c)

Definition at line 146 of file hba.c.

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

Referenced by interpret_ident_response(), and next_token().

◆ regcomp_auth_token()

static int regcomp_auth_token ( AuthToken token,
char *  filename,
int  line_num,
char **  err_msg,
int  elevel 
)
static

Definition at line 303 of file hba.c.

305{
306 pg_wchar *wstr;
307 int wlen;
308 int rc;
309
310 Assert(token->regex == NULL);
311
312 if (token->string[0] != '/')
313 return 0; /* nothing to compile */
314
315 token->regex = (regex_t *) palloc0(sizeof(regex_t));
316 wstr = palloc((strlen(token->string + 1) + 1) * sizeof(pg_wchar));
317 wlen = pg_mb2wchar_with_len(token->string + 1,
318 wstr, strlen(token->string + 1));
319
320 rc = pg_regcomp(token->regex, wstr, wlen, REG_ADVANCED, C_COLLATION_OID);
321
322 if (rc)
323 {
324 char errstr[100];
325
326 pg_regerror(rc, token->regex, errstr, sizeof(errstr));
327 ereport(elevel,
328 (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
329 errmsg("invalid regular expression \"%s\": %s",
330 token->string + 1, errstr),
331 errcontext("line %d of configuration file \"%s\"",
332 line_num, filename)));
333
334 *err_msg = psprintf("invalid regular expression \"%s\": %s",
335 token->string + 1, errstr);
336 }
337
338 pfree(wstr);
339 return rc;
340}
unsigned int pg_wchar
Definition: mbprint.c:31
int pg_mb2wchar_with_len(const char *from, pg_wchar *to, int len)
Definition: mbutils.c:986
void * palloc(Size size)
Definition: mcxt.c:1943
int pg_regcomp(regex_t *re, const chr *string, size_t len, int flags, Oid collation)
Definition: regcomp.c:372
#define REG_ADVANCED
Definition: regex.h:181
#define regex_t
Definition: regex.h:245

References Assert(), ereport, errcode(), errcontext, errmsg(), filename, palloc(), palloc0(), pfree(), pg_mb2wchar_with_len(), pg_regcomp(), pg_regerror(), psprintf(), REG_ADVANCED, and regex_t.

Referenced by parse_hba_line(), and parse_ident_line().

◆ regexec_auth_token()

static int regexec_auth_token ( const char *  match,
AuthToken token,
size_t  nmatch,
regmatch_t  pmatch[] 
)
static

Definition at line 348 of file hba.c.

350{
351 pg_wchar *wmatchstr;
352 int wmatchlen;
353 int r;
354
355 Assert(token->string[0] == '/' && token->regex);
356
357 wmatchstr = palloc((strlen(match) + 1) * sizeof(pg_wchar));
358 wmatchlen = pg_mb2wchar_with_len(match, wmatchstr, strlen(match));
359
360 r = pg_regexec(token->regex, wmatchstr, wmatchlen, 0, NULL, nmatch, pmatch, 0);
361
362 pfree(wmatchstr);
363 return r;
364}
int pg_regexec(regex_t *re, const chr *string, size_t len, size_t search_start, rm_detail_t *details, size_t nmatch, regmatch_t pmatch[], int flags)
Definition: regexec.c:185

References Assert(), palloc(), pfree(), pg_mb2wchar_with_len(), and pg_regexec().

Referenced by check_db(), check_ident_usermap(), and check_role().

◆ StaticAssertDecl()

StaticAssertDecl ( lengthof(UserAuthName = =USER_AUTH_LAST+1,
"UserAuthName []must match the UserAuth enum"   
)

◆ tokenize_auth_file()

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

Definition at line 691 of file hba.c.

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

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

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

◆ tokenize_error_callback()

static void tokenize_error_callback ( void *  arg)
static

Definition at line 662 of file hba.c.

663{
665
666 errcontext("line %d of configuration file \"%s\"",
667 callback_arg->linenum, callback_arg->filename);
668}
void * arg

References arg, errcontext, tokenize_error_callback_arg::filename, and tokenize_error_callback_arg::linenum.

Referenced by tokenize_auth_file().

◆ tokenize_expand_file()

static List * tokenize_expand_file ( List tokens,
const char *  outer_filename,
const char *  inc_filename,
int  elevel,
int  depth,
char **  err_msg 
)
static

Definition at line 495 of file hba.c.

501{
502 char *inc_fullname;
503 FILE *inc_file;
504 List *inc_lines = NIL;
505 ListCell *inc_line;
506
507 inc_fullname = AbsoluteConfigLocation(inc_filename, outer_filename);
508 inc_file = open_auth_file(inc_fullname, elevel, depth, err_msg);
509
510 if (inc_file == NULL)
511 {
512 /* error already logged */
513 pfree(inc_fullname);
514 return tokens;
515 }
516
517 /*
518 * There is possible recursion here if the file contains @ or an include
519 * record.
520 */
521 tokenize_auth_file(inc_fullname, inc_file, &inc_lines, elevel,
522 depth);
523
524 pfree(inc_fullname);
525
526 /*
527 * Move all the tokens found in the file to the tokens list. These are
528 * already saved in tokenize_context.
529 */
530 foreach(inc_line, inc_lines)
531 {
532 TokenizedAuthLine *tok_line = (TokenizedAuthLine *) lfirst(inc_line);
533 ListCell *inc_field;
534
535 /* If any line has an error, propagate that up to caller */
536 if (tok_line->err_msg)
537 {
538 *err_msg = pstrdup(tok_line->err_msg);
539 break;
540 }
541
542 foreach(inc_field, tok_line->fields)
543 {
544 List *inc_tokens = lfirst(inc_field);
545 ListCell *inc_token;
546
547 foreach(inc_token, inc_tokens)
548 {
549 AuthToken *token = lfirst(inc_token);
550 MemoryContext oldcxt;
551
552 /*
553 * lappend() may do its own allocations, so move to the
554 * context for the list of tokens.
555 */
557 tokens = lappend(tokens, token);
558 MemoryContextSwitchTo(oldcxt);
559 }
560 }
561 }
562
563 free_auth_file(inc_file, depth);
564 return tokens;
565}
char * AbsoluteConfigLocation(const char *location, const char *calling_file)
Definition: conffiles.c:36

References AbsoluteConfigLocation(), TokenizedAuthLine::err_msg, TokenizedAuthLine::fields, free_auth_file(), lappend(), lfirst, MemoryContextSwitchTo(), NIL, open_auth_file(), pfree(), pstrdup(), tokenize_auth_file(), and tokenize_context.

Referenced by next_field_expand().

◆ tokenize_include_file()

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

Definition at line 440 of file hba.c.

447{
448 char *inc_fullname;
449 FILE *inc_file;
450
451 inc_fullname = AbsoluteConfigLocation(inc_filename, outer_filename);
452 inc_file = open_auth_file(inc_fullname, elevel, depth, err_msg);
453
454 if (!inc_file)
455 {
456 if (errno == ENOENT && missing_ok)
457 {
458 ereport(elevel,
459 (errmsg("skipping missing authentication file \"%s\"",
460 inc_fullname)));
461 *err_msg = NULL;
462 pfree(inc_fullname);
463 return;
464 }
465
466 /* error in err_msg, so leave and report */
467 pfree(inc_fullname);
468 Assert(err_msg);
469 return;
470 }
471
472 tokenize_auth_file(inc_fullname, inc_file, tok_lines, elevel,
473 depth);
474 free_auth_file(inc_file, depth);
475 pfree(inc_fullname);
476}

References AbsoluteConfigLocation(), Assert(), ereport, errmsg(), free_auth_file(), open_auth_file(), pfree(), and tokenize_auth_file().

Referenced by tokenize_auth_file().

Variable Documentation

◆ parsed_hba_context

MemoryContext parsed_hba_context = NULL
static

Definition at line 87 of file hba.c.

Referenced by load_hba().

◆ parsed_hba_lines

List* parsed_hba_lines = NIL
static

Definition at line 86 of file hba.c.

Referenced by check_hba(), and load_hba().

◆ parsed_ident_context

MemoryContext parsed_ident_context = NULL
static

Definition at line 94 of file hba.c.

Referenced by load_ident().

◆ parsed_ident_lines

List* parsed_ident_lines = NIL
static

Definition at line 93 of file hba.c.

Referenced by check_usermap(), and load_ident().

◆ tokenize_context

MemoryContext tokenize_context = NULL
static

◆ UserAuthName

const char* const UserAuthName[]
static
Initial value:
=
{
"reject",
"implicit reject",
"trust",
"ident",
"password",
"md5",
"scram-sha-256",
"gss",
"sspi",
"pam",
"bsd",
"ldap",
"cert",
"radius",
"peer",
"oauth",
}

Definition at line 102 of file hba.c.

Referenced by hba_authname().