1 /*-------------------------------------------------------------------------
4 * Routines to handle host based authentication (that's the scheme
5 * wherein you authenticate a user by seeing what IP address the system
6 * says he comes from and choosing authentication method based on it).
8 * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
9 * Portions Copyright (c) 1994, Regents of the University of California
13 * src/backend/libpq/hba.c
15 *-------------------------------------------------------------------------
22 #include <sys/param.h>
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
28 #include "catalog/pg_collation.h"
30 #include "libpq/libpq.h"
31 #include "postmaster/postmaster.h"
32 #include "regex/regex.h"
33 #include "replication/walsender.h"
34 #include "storage/fd.h"
35 #include "utils/acl.h"
36 #include "utils/guc.h"
37 #include "utils/lsyscache.h"
38 #include "utils/memutils.h"
49 #define atooid(x) ((Oid) strtoul((x), NULL, 10))
50 #define atoxid(x) ((TransactionId) strtoul((x), NULL, 10))
55 /* callback data for check_network_callback */
56 typedef struct check_network_data
58 IPCompareMethod method; /* test method */
59 SockAddr *raddr; /* client's actual address */
60 bool result; /* set to true if match */
64 #define token_is_keyword(t, k) (!t->quoted && strcmp(t->string, k) == 0)
65 #define token_matches(t, k) (strcmp(t->string, k) == 0)
68 * A single string token lexed from the HBA config file, together with whether
69 * the token had been quoted.
71 typedef struct HbaToken
78 * pre-parsed content of HBA config file: list of HbaLine structs.
79 * parsed_hba_context is the memory context where it lives.
81 static List *parsed_hba_lines = NIL;
82 static MemoryContext parsed_hba_context = NULL;
85 * pre-parsed content of ident mapping file: list of IdentLine structs.
86 * parsed_ident_context is the memory context where it lives.
88 * NOTE: the IdentLine structs can contain pre-compiled regular expressions
89 * that live outside the memory context. Before destroying or resetting the
90 * memory context, they need to be expliticly free'd.
92 static List *parsed_ident_lines = NIL;
93 static MemoryContext parsed_ident_context = NULL;
96 static MemoryContext tokenize_file(const char *filename, FILE *file,
97 List **lines, List **line_nums, List **raw_lines);
98 static List *tokenize_inc_file(List *tokens, const char *outer_filename,
99 const char *inc_filename);
100 static bool parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline,
104 * isblank() exists in the ISO C99 spec, but it's not very portable yet,
105 * so provide our own version.
108 pg_isblank(const char c)
110 return c == ' ' || c == '\t' || c == '\r';
115 * Grab one token out of the string pointed to by lineptr.
116 * Tokens are strings of non-blank
117 * characters bounded by blank characters, commas, beginning of line, and
118 * end of line. Blank means space or tab. Tokens can be delimited by
119 * double quotes (this allows the inclusion of blanks, but not newlines).
121 * The token, if any, is returned at *buf (a buffer of size bufsz).
122 * Also, we set *initial_quote to indicate whether there was quoting before
123 * the first character. (We use that to prevent "@x" from being treated
124 * as a file inclusion request. Note that @"x" should be so treated;
125 * we want to allow that to support embedded spaces in file paths.)
126 * We set *terminating_comma to indicate whether the token is terminated by a
127 * comma (which is not returned.)
129 * If successful: store null-terminated token at *buf and return TRUE.
130 * If no more tokens on line: set *buf = '\0' and return FALSE.
132 * Leave file positioned at the character immediately after the token or EOF,
133 * whichever comes first. If no more tokens on line, position the file to the
134 * beginning of the next line or EOF, whichever comes first.
139 next_token(char **lineptr, char *buf, int bufsz, bool *initial_quote,
140 bool *terminating_comma)
143 char *start_buf = buf;
144 char *end_buf = buf + (bufsz - 2);
145 bool in_quote = false;
146 bool was_quote = false;
147 bool saw_quote = false;
149 /* end_buf reserves two bytes to ensure we can append \n and \0 */
150 Assert(end_buf > start_buf);
152 *initial_quote = false;
153 *terminating_comma = false;
155 /* Move over initial whitespace and commas */
156 while ((c = (*(*lineptr)++)) != '\0' && (pg_isblank(c) || c == ','))
159 if (c == '\0' || c == '\n')
166 * Build a token in buf of next characters up to EOF, EOL, unquoted comma,
167 * or unquoted whitespace.
169 while (c != '\0' && c != '\n' &&
170 (!pg_isblank(c) || in_quote))
172 /* skip comments to EOL */
173 if (c == '#' && !in_quote)
175 while ((c = (*(*lineptr)++)) != '\0' && c != '\n')
177 /* If only comment, consume EOL too; return EOL */
178 if (c != '\0' && buf == start_buf)
187 (errcode(ERRCODE_CONFIG_FILE_ERROR),
188 errmsg("authentication file token too long, skipping: \"%s\"",
190 /* Discard remainder of line */
191 while ((c = (*(*lineptr)++)) != '\0' && c != '\n')
196 /* we do not pass back the comma in the token */
197 if (c == ',' && !in_quote)
199 *terminating_comma = true;
203 if (c != '"' || was_quote)
206 /* Literal double-quote is two double-quotes */
207 if (in_quote && c == '"')
208 was_quote = !was_quote;
214 in_quote = !in_quote;
216 if (buf == start_buf)
217 *initial_quote = true;
224 * Put back the char right after the token (critical in case it is EOL,
225 * since we need to detect end-of-line at next call).
231 return (saw_quote || buf > start_buf);
235 make_hba_token(char *token, bool quoted)
240 toklen = strlen(token);
241 hbatoken = (HbaToken *) palloc(sizeof(HbaToken) + toklen + 1);
242 hbatoken->string = (char *) hbatoken + sizeof(HbaToken);
243 hbatoken->quoted = quoted;
244 memcpy(hbatoken->string, token, toklen + 1);
250 * Copy a HbaToken struct into freshly palloc'd memory.
253 copy_hba_token(HbaToken *in)
255 HbaToken *out = make_hba_token(in->string, in->quoted);
262 * Tokenize one HBA field from a line, handling file inclusion and comma lists.
264 * The result is a List of HbaToken structs for each individual token,
265 * or NIL if we reached EOL.
268 next_field_expand(const char *filename, char **lineptr)
277 if (!next_token(lineptr, buf, sizeof(buf), &initial_quote, &trailing_comma))
280 /* Is this referencing a file? */
281 if (!initial_quote && buf[0] == '@' && buf[1] != '\0')
282 tokens = tokenize_inc_file(tokens, filename, buf + 1);
284 tokens = lappend(tokens, make_hba_token(buf, initial_quote));
285 } while (trailing_comma);
292 * Expand a file included from another file into an hba "field"
294 * Opens and tokenises a file included from another HBA config file with @,
295 * and returns all values found therein as a flat list of HbaTokens. If a
296 * @-token is found, recursively expand it. The given token list is used as
297 * initial contents of list (so foo,bar,@baz does what you expect).
300 tokenize_inc_file(List *tokens,
301 const char *outer_filename,
302 const char *inc_filename)
309 MemoryContext linecxt;
311 if (is_absolute_path(inc_filename))
313 /* absolute path is taken as-is */
314 inc_fullname = pstrdup(inc_filename);
318 /* relative path is relative to dir of calling file */
319 inc_fullname = (char *) palloc(strlen(outer_filename) + 1 +
320 strlen(inc_filename) + 1);
321 strcpy(inc_fullname, outer_filename);
322 get_parent_directory(inc_fullname);
323 join_path_components(inc_fullname, inc_fullname, inc_filename);
324 canonicalize_path(inc_fullname);
327 inc_file = AllocateFile(inc_fullname, "r");
328 if (inc_file == NULL)
331 (errcode_for_file_access(),
332 errmsg("could not open secondary authentication file \"@%s\" as \"%s\": %m",
333 inc_filename, inc_fullname)));
338 /* There is possible recursion here if the file contains @ */
339 linecxt = tokenize_file(inc_fullname, inc_file, &inc_lines, &inc_line_nums, NULL);
344 foreach(inc_line, inc_lines)
346 List *inc_fields = lfirst(inc_line);
349 foreach(inc_field, inc_fields)
351 List *inc_tokens = lfirst(inc_field);
354 foreach(inc_token, inc_tokens)
356 HbaToken *token = lfirst(inc_token);
358 tokens = lappend(tokens, copy_hba_token(token));
363 MemoryContextDelete(linecxt);
368 * Tokenize the given file, storing the resulting data into three Lists: a
369 * List of lines, a List of line numbers, and a List of raw line contents.
371 * The list of lines is a triple-nested List structure. Each line is a List of
372 * fields, and each field is a List of HbaTokens.
374 * filename must be the absolute path to the target file.
376 * Return value is a memory context which contains all memory allocated by
380 tokenize_file(const char *filename, FILE *file,
381 List **lines, List **line_nums, List **raw_lines)
383 List *current_line = NIL;
384 List *current_field = NIL;
386 MemoryContext linecxt;
387 MemoryContext oldcxt;
389 linecxt = AllocSetContextCreate(TopMemoryContext,
391 ALLOCSET_DEFAULT_MINSIZE,
392 ALLOCSET_DEFAULT_INITSIZE,
393 ALLOCSET_DEFAULT_MAXSIZE);
394 oldcxt = MemoryContextSwitchTo(linecxt);
396 *lines = *line_nums = NIL;
398 while (!feof(file) && !ferror(file))
400 char rawline[MAX_LINE];
403 if (!fgets(rawline, sizeof(rawline), file))
405 if (strlen(rawline) == MAX_LINE - 1)
408 (errcode(ERRCODE_CONFIG_FILE_ERROR),
409 errmsg("authentication file line too long"),
410 errcontext("line %d of configuration file \"%s\"",
411 line_number, filename)));
413 /* Strip trailing linebreak from rawline */
414 lineptr = rawline + strlen(rawline) - 1;
415 while (lineptr >= rawline && (*lineptr == '\n' || *lineptr == '\r'))
419 while (strlen(lineptr) > 0)
421 current_field = next_field_expand(filename, &lineptr);
423 /* add tokens to list, unless we are at EOL or comment start */
424 if (list_length(current_field) > 0)
426 if (current_line == NIL)
428 /* make a new line List, record its line number */
429 current_line = lappend(current_line, current_field);
430 *lines = lappend(*lines, current_line);
431 *line_nums = lappend_int(*line_nums, line_number);
433 *raw_lines = lappend(*raw_lines, pstrdup(rawline));
437 /* append tokens to current line's list */
438 current_line = lappend(current_line, current_field);
442 /* we are at real or logical EOL, so force a new line List */
447 MemoryContextSwitchTo(oldcxt);
454 * Does user belong to role?
456 * userid is the OID of the role given as the attempted login identifier.
457 * We check to see if it is a member of the specified role name.
460 is_member(Oid userid, const char *role)
464 if (!OidIsValid(userid))
465 return false; /* if user not exist, say "no" */
467 roleid = get_role_oid(role, true);
469 if (!OidIsValid(roleid))
470 return false; /* if target role not exist, say "no" */
473 * See if user is directly or indirectly a member of role. For this
474 * purpose, a superuser is not considered to be automatically a member of
475 * the role, so group auth only applies to explicit membership.
477 return is_member_of_role_nosuper(userid, roleid);
481 * Check HbaToken list for a match to role, allowing group names.
484 check_role(const char *role, Oid roleid, List *tokens)
489 foreach(cell, tokens)
492 if (!tok->quoted && tok->string[0] == '+')
494 if (is_member(roleid, tok->string + 1))
497 else if (token_matches(tok, role) ||
498 token_is_keyword(tok, "all"))
505 * Check to see if db/role combination matches HbaToken list.
508 check_db(const char *dbname, const char *role, Oid roleid, List *tokens)
513 foreach(cell, tokens)
518 /* walsender connections can only match replication keyword */
519 if (token_is_keyword(tok, "replication"))
522 else if (token_is_keyword(tok, "all"))
524 else if (token_is_keyword(tok, "sameuser"))
526 if (strcmp(dbname, role) == 0)
529 else if (token_is_keyword(tok, "samegroup") ||
530 token_is_keyword(tok, "samerole"))
532 if (is_member(roleid, dbname))
535 else if (token_is_keyword(tok, "replication"))
536 continue; /* never match this if not walsender */
537 else if (token_matches(tok, dbname))
544 ipv4eq(struct sockaddr_in * a, struct sockaddr_in * b)
546 return (a->sin_addr.s_addr == b->sin_addr.s_addr);
552 ipv6eq(struct sockaddr_in6 * a, struct sockaddr_in6 * b)
556 for (i = 0; i < 16; i++)
557 if (a->sin6_addr.s6_addr[i] != b->sin6_addr.s6_addr[i])
562 #endif /* HAVE_IPV6 */
565 * Check whether host name matches pattern.
568 hostname_match(const char *pattern, const char *actual_hostname)
570 if (pattern[0] == '.') /* suffix match */
572 size_t plen = strlen(pattern);
573 size_t hlen = strlen(actual_hostname);
578 return (pg_strcasecmp(pattern, actual_hostname + (hlen - plen)) == 0);
581 return (pg_strcasecmp(pattern, actual_hostname) == 0);
585 * Check to see if a connecting IP matches a given host name.
588 check_hostname(hbaPort *port, const char *hostname)
590 struct addrinfo *gai_result,
595 /* Quick out if remote host name already known bad */
596 if (port->remote_hostname_resolv < 0)
599 /* Lookup remote host name if not already done */
600 if (!port->remote_hostname)
602 char remote_hostname[NI_MAXHOST];
604 ret = pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
605 remote_hostname, sizeof(remote_hostname),
610 /* remember failure; don't complain in the postmaster log yet */
611 port->remote_hostname_resolv = -2;
612 port->remote_hostname_errcode = ret;
616 port->remote_hostname = pstrdup(remote_hostname);
619 /* Now see if remote host name matches this pg_hba line */
620 if (!hostname_match(hostname, port->remote_hostname))
623 /* If we already verified the forward lookup, we're done */
624 if (port->remote_hostname_resolv == +1)
627 /* Lookup IP from host name and check against original IP */
628 ret = getaddrinfo(port->remote_hostname, NULL, NULL, &gai_result);
631 /* remember failure; don't complain in the postmaster log yet */
632 port->remote_hostname_resolv = -2;
633 port->remote_hostname_errcode = ret;
638 for (gai = gai_result; gai; gai = gai->ai_next)
640 if (gai->ai_addr->sa_family == port->raddr.addr.ss_family)
642 if (gai->ai_addr->sa_family == AF_INET)
644 if (ipv4eq((struct sockaddr_in *) gai->ai_addr,
645 (struct sockaddr_in *) & port->raddr.addr))
652 else if (gai->ai_addr->sa_family == AF_INET6)
654 if (ipv6eq((struct sockaddr_in6 *) gai->ai_addr,
655 (struct sockaddr_in6 *) & port->raddr.addr))
666 freeaddrinfo(gai_result);
669 elog(DEBUG2, "pg_hba.conf host name \"%s\" rejected because address resolution did not return a match with IP address of client",
672 port->remote_hostname_resolv = found ? +1 : -1;
678 * Check to see if a connecting IP matches the given address and netmask.
681 check_ip(SockAddr *raddr, struct sockaddr * addr, struct sockaddr * mask)
683 if (raddr->addr.ss_family == addr->sa_family)
685 /* Same address family */
686 if (!pg_range_sockaddr(&raddr->addr,
687 (struct sockaddr_storage *) addr,
688 (struct sockaddr_storage *) mask))
692 else if (addr->sa_family == AF_INET &&
693 raddr->addr.ss_family == AF_INET6)
696 * If we're connected on IPv6 but the file specifies an IPv4 address
697 * to match against, promote the latter to an IPv6 address before
698 * trying to match the client's address.
700 struct sockaddr_storage addrcopy,
703 memcpy(&addrcopy, &addr, sizeof(addrcopy));
704 memcpy(&maskcopy, &mask, sizeof(maskcopy));
705 pg_promote_v4_to_v6_addr(&addrcopy);
706 pg_promote_v4_to_v6_mask(&maskcopy);
708 if (!pg_range_sockaddr(&raddr->addr, &addrcopy, &maskcopy))
711 #endif /* HAVE_IPV6 */
714 /* Wrong address family, no IPV6 */
722 * pg_foreach_ifaddr callback: does client addr match this machine interface?
725 check_network_callback(struct sockaddr * addr, struct sockaddr * netmask,
728 check_network_data *cn = (check_network_data *) cb_data;
729 struct sockaddr_storage mask;
731 /* Already found a match? */
735 if (cn->method == ipCmpSameHost)
737 /* Make an all-ones netmask of appropriate length for family */
738 pg_sockaddr_cidr_mask(&mask, NULL, addr->sa_family);
739 cn->result = check_ip(cn->raddr, addr, (struct sockaddr *) & mask);
743 /* Use the netmask of the interface itself */
744 cn->result = check_ip(cn->raddr, addr, netmask);
749 * Use pg_foreach_ifaddr to check a samehost or samenet match
752 check_same_host_or_net(SockAddr *raddr, IPCompareMethod method)
754 check_network_data cn;
761 if (pg_foreach_ifaddr(check_network_callback, &cn) < 0)
763 elog(LOG, "error enumerating network interfaces: %m");
772 * Macros used to check and report on invalid configuration options.
773 * INVALID_AUTH_OPTION = reports when an option is specified for a method where it's
775 * REQUIRE_AUTH_OPTION = same as INVALID_AUTH_OPTION, except it also checks if the
776 * method is actually the one specified. Used as a shortcut when
777 * the option is only valid for one authentication method.
778 * MANDATORY_AUTH_ARG = check if a required option is set for an authentication method,
779 * reporting error if it's not.
781 #define INVALID_AUTH_OPTION(optname, validmethods) do {\
783 (errcode(ERRCODE_CONFIG_FILE_ERROR), \
784 /* translator: the second %s is a list of auth methods */ \
785 errmsg("authentication option \"%s\" is only valid for authentication methods %s", \
786 optname, _(validmethods)), \
787 errcontext("line %d of configuration file \"%s\"", \
788 line_num, HbaFileName))); \
792 #define REQUIRE_AUTH_OPTION(methodval, optname, validmethods) do {\
793 if (hbaline->auth_method != methodval) \
794 INVALID_AUTH_OPTION(optname, validmethods); \
797 #define MANDATORY_AUTH_ARG(argvar, argname, authname) do {\
798 if (argvar == NULL) {\
800 (errcode(ERRCODE_CONFIG_FILE_ERROR), \
801 errmsg("authentication method \"%s\" requires argument \"%s\" to be set", \
802 authname, argname), \
803 errcontext("line %d of configuration file \"%s\"", \
804 line_num, HbaFileName))); \
810 * IDENT_FIELD_ABSENT:
811 * Throw an error and exit the function if the given ident field ListCell is
815 * Throw an error and exit the function if the given ident token List has more
818 #define IDENT_FIELD_ABSENT(field) do {\
821 (errcode(ERRCODE_CONFIG_FILE_ERROR), \
822 errmsg("missing entry in file \"%s\" at end of line %d", \
823 IdentFileName, line_number))); \
828 #define IDENT_MULTI_VALUE(tokens) do {\
829 if (tokens->length > 1) { \
831 (errcode(ERRCODE_CONFIG_FILE_ERROR), \
832 errmsg("multiple values in ident field"), \
833 errcontext("line %d of configuration file \"%s\"", \
834 line_number, IdentFileName))); \
841 * Parse one tokenised line from the hba config file and store the result in a
842 * HbaLine structure, or NULL if parsing fails.
844 * The tokenised line is a List of fields, each field being a List of
847 * Note: this function leaks memory when an error occurs. Caller is expected
848 * to have set a memory context that will be reset if this function returns
852 parse_hba_line(List *line, int line_num, char *raw_line)
855 struct addrinfo *gai_result;
856 struct addrinfo hints;
866 parsedline = palloc0(sizeof(HbaLine));
867 parsedline->linenumber = line_num;
868 parsedline->rawline = pstrdup(raw_line);
870 /* Check the record type. */
871 field = list_head(line);
872 tokens = lfirst(field);
873 if (tokens->length > 1)
876 (errcode(ERRCODE_CONFIG_FILE_ERROR),
877 errmsg("multiple values specified for connection type"),
878 errhint("Specify exactly one connection type per line."),
879 errcontext("line %d of configuration file \"%s\"",
880 line_num, HbaFileName)));
883 token = linitial(tokens);
884 if (strcmp(token->string, "local") == 0)
886 #ifdef HAVE_UNIX_SOCKETS
887 parsedline->conntype = ctLocal;
890 (errcode(ERRCODE_CONFIG_FILE_ERROR),
891 errmsg("local connections are not supported by this build"),
892 errcontext("line %d of configuration file \"%s\"",
893 line_num, HbaFileName)));
897 else if (strcmp(token->string, "host") == 0 ||
898 strcmp(token->string, "hostssl") == 0 ||
899 strcmp(token->string, "hostnossl") == 0)
902 if (token->string[4] == 's') /* "hostssl" */
904 /* SSL support must be actually active, else complain */
907 parsedline->conntype = ctHostSSL;
911 (errcode(ERRCODE_CONFIG_FILE_ERROR),
912 errmsg("hostssl requires SSL to be turned on"),
913 errhint("Set ssl = on in postgresql.conf."),
914 errcontext("line %d of configuration file \"%s\"",
915 line_num, HbaFileName)));
920 (errcode(ERRCODE_CONFIG_FILE_ERROR),
921 errmsg("hostssl is not supported by this build"),
922 errhint("Compile with --with-openssl to use SSL connections."),
923 errcontext("line %d of configuration file \"%s\"",
924 line_num, HbaFileName)));
929 else if (token->string[4] == 'n') /* "hostnossl" */
931 parsedline->conntype = ctHostNoSSL;
936 /* "host", or "hostnossl" and SSL support not built in */
937 parsedline->conntype = ctHost;
943 (errcode(ERRCODE_CONFIG_FILE_ERROR),
944 errmsg("invalid connection type \"%s\"",
946 errcontext("line %d of configuration file \"%s\"",
947 line_num, HbaFileName)));
951 /* Get the databases. */
952 field = lnext(field);
956 (errcode(ERRCODE_CONFIG_FILE_ERROR),
957 errmsg("end-of-line before database specification"),
958 errcontext("line %d of configuration file \"%s\"",
959 line_num, HbaFileName)));
962 parsedline->databases = NIL;
963 tokens = lfirst(field);
964 foreach(tokencell, tokens)
966 parsedline->databases = lappend(parsedline->databases,
967 copy_hba_token(lfirst(tokencell)));
971 field = lnext(field);
975 (errcode(ERRCODE_CONFIG_FILE_ERROR),
976 errmsg("end-of-line before role specification"),
977 errcontext("line %d of configuration file \"%s\"",
978 line_num, HbaFileName)));
981 parsedline->roles = NIL;
982 tokens = lfirst(field);
983 foreach(tokencell, tokens)
985 parsedline->roles = lappend(parsedline->roles,
986 copy_hba_token(lfirst(tokencell)));
989 if (parsedline->conntype != ctLocal)
991 /* Read the IP address field. (with or without CIDR netmask) */
992 field = lnext(field);
996 (errcode(ERRCODE_CONFIG_FILE_ERROR),
997 errmsg("end-of-line before IP address specification"),
998 errcontext("line %d of configuration file \"%s\"",
999 line_num, HbaFileName)));
1002 tokens = lfirst(field);
1003 if (tokens->length > 1)
1006 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1007 errmsg("multiple values specified for host address"),
1008 errhint("Specify one address range per line."),
1009 errcontext("line %d of configuration file \"%s\"",
1010 line_num, HbaFileName)));
1013 token = linitial(tokens);
1015 if (token_is_keyword(token, "all"))
1017 parsedline->ip_cmp_method = ipCmpAll;
1019 else if (token_is_keyword(token, "samehost"))
1021 /* Any IP on this host is allowed to connect */
1022 parsedline->ip_cmp_method = ipCmpSameHost;
1024 else if (token_is_keyword(token, "samenet"))
1026 /* Any IP on the host's subnets is allowed to connect */
1027 parsedline->ip_cmp_method = ipCmpSameNet;
1031 /* IP and netmask are specified */
1032 parsedline->ip_cmp_method = ipCmpMask;
1034 /* need a modifiable copy of token */
1035 str = pstrdup(token->string);
1037 /* Check if it has a CIDR suffix and if so isolate it */
1038 cidr_slash = strchr(str, '/');
1042 /* Get the IP address either way */
1043 hints.ai_flags = AI_NUMERICHOST;
1044 hints.ai_family = AF_UNSPEC;
1045 hints.ai_socktype = 0;
1046 hints.ai_protocol = 0;
1047 hints.ai_addrlen = 0;
1048 hints.ai_canonname = NULL;
1049 hints.ai_addr = NULL;
1050 hints.ai_next = NULL;
1052 ret = pg_getaddrinfo_all(str, NULL, &hints, &gai_result);
1053 if (ret == 0 && gai_result)
1054 memcpy(&parsedline->addr, gai_result->ai_addr,
1055 gai_result->ai_addrlen);
1056 else if (ret == EAI_NONAME)
1057 parsedline->hostname = str;
1061 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1062 errmsg("invalid IP address \"%s\": %s",
1063 str, gai_strerror(ret)),
1064 errcontext("line %d of configuration file \"%s\"",
1065 line_num, HbaFileName)));
1067 pg_freeaddrinfo_all(hints.ai_family, gai_result);
1071 pg_freeaddrinfo_all(hints.ai_family, gai_result);
1073 /* Get the netmask */
1076 if (parsedline->hostname)
1079 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1080 errmsg("specifying both host name and CIDR mask is invalid: \"%s\"",
1082 errcontext("line %d of configuration file \"%s\"",
1083 line_num, HbaFileName)));
1087 if (pg_sockaddr_cidr_mask(&parsedline->mask, cidr_slash + 1,
1088 parsedline->addr.ss_family) < 0)
1091 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1092 errmsg("invalid CIDR mask in address \"%s\"",
1094 errcontext("line %d of configuration file \"%s\"",
1095 line_num, HbaFileName)));
1100 else if (!parsedline->hostname)
1102 /* Read the mask field. */
1104 field = lnext(field);
1108 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1109 errmsg("end-of-line before netmask specification"),
1110 errhint("Specify an address range in CIDR notation, or provide a separate netmask."),
1111 errcontext("line %d of configuration file \"%s\"",
1112 line_num, HbaFileName)));
1115 tokens = lfirst(field);
1116 if (tokens->length > 1)
1119 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1120 errmsg("multiple values specified for netmask"),
1121 errcontext("line %d of configuration file \"%s\"",
1122 line_num, HbaFileName)));
1125 token = linitial(tokens);
1127 ret = pg_getaddrinfo_all(token->string, NULL,
1128 &hints, &gai_result);
1129 if (ret || !gai_result)
1132 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1133 errmsg("invalid IP mask \"%s\": %s",
1134 token->string, gai_strerror(ret)),
1135 errcontext("line %d of configuration file \"%s\"",
1136 line_num, HbaFileName)));
1138 pg_freeaddrinfo_all(hints.ai_family, gai_result);
1142 memcpy(&parsedline->mask, gai_result->ai_addr,
1143 gai_result->ai_addrlen);
1144 pg_freeaddrinfo_all(hints.ai_family, gai_result);
1146 if (parsedline->addr.ss_family != parsedline->mask.ss_family)
1149 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1150 errmsg("IP address and mask do not match"),
1151 errcontext("line %d of configuration file \"%s\"",
1152 line_num, HbaFileName)));
1159 /* Get the authentication method */
1160 field = lnext(field);
1164 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1165 errmsg("end-of-line before authentication method"),
1166 errcontext("line %d of configuration file \"%s\"",
1167 line_num, HbaFileName)));
1170 tokens = lfirst(field);
1171 if (tokens->length > 1)
1174 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1175 errmsg("multiple values specified for authentication type"),
1176 errhint("Specify exactly one authentication type per line."),
1177 errcontext("line %d of configuration file \"%s\"",
1178 line_num, HbaFileName)));
1181 token = linitial(tokens);
1184 if (strcmp(token->string, "trust") == 0)
1185 parsedline->auth_method = uaTrust;
1186 else if (strcmp(token->string, "ident") == 0)
1187 parsedline->auth_method = uaIdent;
1188 else if (strcmp(token->string, "peer") == 0)
1189 parsedline->auth_method = uaPeer;
1190 else if (strcmp(token->string, "password") == 0)
1191 parsedline->auth_method = uaPassword;
1192 else if (strcmp(token->string, "gss") == 0)
1194 parsedline->auth_method = uaGSS;
1198 else if (strcmp(token->string, "sspi") == 0)
1200 parsedline->auth_method = uaSSPI;
1204 else if (strcmp(token->string, "reject") == 0)
1205 parsedline->auth_method = uaReject;
1206 else if (strcmp(token->string, "md5") == 0)
1208 if (Db_user_namespace)
1211 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1212 errmsg("MD5 authentication is not supported when \"db_user_namespace\" is enabled"),
1213 errcontext("line %d of configuration file \"%s\"",
1214 line_num, HbaFileName)));
1217 parsedline->auth_method = uaMD5;
1219 else if (strcmp(token->string, "pam") == 0)
1221 parsedline->auth_method = uaPAM;
1225 else if (strcmp(token->string, "ldap") == 0)
1227 parsedline->auth_method = uaLDAP;
1231 else if (strcmp(token->string, "cert") == 0)
1233 parsedline->auth_method = uaCert;
1237 else if (strcmp(token->string, "radius") == 0)
1238 parsedline->auth_method = uaRADIUS;
1242 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1243 errmsg("invalid authentication method \"%s\"",
1245 errcontext("line %d of configuration file \"%s\"",
1246 line_num, HbaFileName)));
1253 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1254 errmsg("invalid authentication method \"%s\": not supported by this build",
1256 errcontext("line %d of configuration file \"%s\"",
1257 line_num, HbaFileName)));
1262 * XXX: When using ident on local connections, change it to peer, for
1263 * backwards compatibility.
1265 if (parsedline->conntype == ctLocal &&
1266 parsedline->auth_method == uaIdent)
1267 parsedline->auth_method = uaPeer;
1269 /* Invalid authentication combinations */
1270 if (parsedline->conntype == ctLocal &&
1271 parsedline->auth_method == uaGSS)
1274 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1275 errmsg("gssapi authentication is not supported on local sockets"),
1276 errcontext("line %d of configuration file \"%s\"",
1277 line_num, HbaFileName)));
1281 if (parsedline->conntype != ctLocal &&
1282 parsedline->auth_method == uaPeer)
1285 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1286 errmsg("peer authentication is only supported on local sockets"),
1287 errcontext("line %d of configuration file \"%s\"",
1288 line_num, HbaFileName)));
1293 * SSPI authentication can never be enabled on ctLocal connections,
1294 * because it's only supported on Windows, where ctLocal isn't supported.
1298 if (parsedline->conntype != ctHostSSL &&
1299 parsedline->auth_method == uaCert)
1302 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1303 errmsg("cert authentication is only supported on hostssl connections"),
1304 errcontext("line %d of configuration file \"%s\"",
1305 line_num, HbaFileName)));
1309 /* Parse remaining arguments */
1310 while ((field = lnext(field)) != NULL)
1312 tokens = lfirst(field);
1313 foreach(tokencell, tokens)
1317 token = lfirst(tokencell);
1319 str = pstrdup(token->string);
1320 val = strchr(str, '=');
1324 * Got something that's not a name=value pair.
1327 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1328 errmsg("authentication option not in name=value format: %s", token->string),
1329 errcontext("line %d of configuration file \"%s\"",
1330 line_num, HbaFileName)));
1334 *val++ = '\0'; /* str now holds "name", val holds "value" */
1335 if (!parse_hba_auth_opt(str, val, parsedline, line_num))
1336 /* parse_hba_auth_opt already logged the error message */
1343 * Check if the selected authentication method has any mandatory arguments
1346 if (parsedline->auth_method == uaLDAP)
1348 MANDATORY_AUTH_ARG(parsedline->ldapserver, "ldapserver", "ldap");
1351 * LDAP can operate in two modes: either with a direct bind, using
1352 * ldapprefix and ldapsuffix, or using a search+bind, using
1353 * ldapbasedn, ldapbinddn, ldapbindpasswd and ldapsearchattribute.
1354 * Disallow mixing these parameters.
1356 if (parsedline->ldapprefix || parsedline->ldapsuffix)
1358 if (parsedline->ldapbasedn ||
1359 parsedline->ldapbinddn ||
1360 parsedline->ldapbindpasswd ||
1361 parsedline->ldapsearchattribute)
1364 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1365 errmsg("cannot use ldapbasedn, ldapbinddn, ldapbindpasswd, ldapsearchattribute, or ldapurl together with ldapprefix"),
1366 errcontext("line %d of configuration file \"%s\"",
1367 line_num, HbaFileName)));
1371 else if (!parsedline->ldapbasedn)
1374 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1375 errmsg("authentication method \"ldap\" requires argument \"ldapbasedn\", \"ldapprefix\", or \"ldapsuffix\" to be set"),
1376 errcontext("line %d of configuration file \"%s\"",
1377 line_num, HbaFileName)));
1382 if (parsedline->auth_method == uaRADIUS)
1384 MANDATORY_AUTH_ARG(parsedline->radiusserver, "radiusserver", "radius");
1385 MANDATORY_AUTH_ARG(parsedline->radiussecret, "radiussecret", "radius");
1389 * Enforce any parameters implied by other settings.
1391 if (parsedline->auth_method == uaCert)
1393 parsedline->clientcert = true;
1400 * Parse one name-value pair as an authentication option into the given
1401 * HbaLine. Return true if we successfully parse the option, false if we
1402 * encounter an error.
1405 parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline, int line_num)
1408 hbaline->ldapscope = LDAP_SCOPE_SUBTREE;
1411 if (strcmp(name, "map") == 0)
1413 if (hbaline->auth_method != uaIdent &&
1414 hbaline->auth_method != uaPeer &&
1415 hbaline->auth_method != uaGSS &&
1416 hbaline->auth_method != uaSSPI &&
1417 hbaline->auth_method != uaCert)
1418 INVALID_AUTH_OPTION("map", gettext_noop("ident, peer, gssapi, sspi, and cert"));
1419 hbaline->usermap = pstrdup(val);
1421 else if (strcmp(name, "clientcert") == 0)
1424 * Since we require ctHostSSL, this really can never happen on
1425 * non-SSL-enabled builds, so don't bother checking for USE_SSL.
1427 if (hbaline->conntype != ctHostSSL)
1430 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1431 errmsg("clientcert can only be configured for \"hostssl\" rows"),
1432 errcontext("line %d of configuration file \"%s\"",
1433 line_num, HbaFileName)));
1436 if (strcmp(val, "1") == 0)
1438 if (!secure_loaded_verify_locations())
1441 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1442 errmsg("client certificates can only be checked if a root certificate store is available"),
1443 errhint("Make sure the configuration parameter \"ssl_ca_file\" is set."),
1444 errcontext("line %d of configuration file \"%s\"",
1445 line_num, HbaFileName)));
1448 hbaline->clientcert = true;
1452 if (hbaline->auth_method == uaCert)
1455 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1456 errmsg("clientcert can not be set to 0 when using \"cert\" authentication"),
1457 errcontext("line %d of configuration file \"%s\"",
1458 line_num, HbaFileName)));
1461 hbaline->clientcert = false;
1464 else if (strcmp(name, "pamservice") == 0)
1466 REQUIRE_AUTH_OPTION(uaPAM, "pamservice", "pam");
1467 hbaline->pamservice = pstrdup(val);
1469 else if (strcmp(name, "ldapurl") == 0)
1471 #ifdef LDAP_API_FEATURE_X_OPENLDAP
1472 LDAPURLDesc *urldata;
1476 REQUIRE_AUTH_OPTION(uaLDAP, "ldapurl", "ldap");
1477 #ifdef LDAP_API_FEATURE_X_OPENLDAP
1478 rc = ldap_url_parse(val, &urldata);
1479 if (rc != LDAP_SUCCESS)
1482 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1483 errmsg("could not parse LDAP URL \"%s\": %s", val, ldap_err2string(rc))));
1487 if (strcmp(urldata->lud_scheme, "ldap") != 0)
1490 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1491 errmsg("unsupported LDAP URL scheme: %s", urldata->lud_scheme)));
1492 ldap_free_urldesc(urldata);
1496 hbaline->ldapserver = pstrdup(urldata->lud_host);
1497 hbaline->ldapport = urldata->lud_port;
1498 hbaline->ldapbasedn = pstrdup(urldata->lud_dn);
1500 if (urldata->lud_attrs)
1501 hbaline->ldapsearchattribute = pstrdup(urldata->lud_attrs[0]); /* only use first one */
1502 hbaline->ldapscope = urldata->lud_scope;
1503 if (urldata->lud_filter)
1506 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1507 errmsg("filters not supported in LDAP URLs")));
1508 ldap_free_urldesc(urldata);
1511 ldap_free_urldesc(urldata);
1512 #else /* not OpenLDAP */
1514 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1515 errmsg("LDAP URLs not supported on this platform")));
1516 #endif /* not OpenLDAP */
1518 else if (strcmp(name, "ldaptls") == 0)
1520 REQUIRE_AUTH_OPTION(uaLDAP, "ldaptls", "ldap");
1521 if (strcmp(val, "1") == 0)
1522 hbaline->ldaptls = true;
1524 hbaline->ldaptls = false;
1526 else if (strcmp(name, "ldapserver") == 0)
1528 REQUIRE_AUTH_OPTION(uaLDAP, "ldapserver", "ldap");
1529 hbaline->ldapserver = pstrdup(val);
1531 else if (strcmp(name, "ldapport") == 0)
1533 REQUIRE_AUTH_OPTION(uaLDAP, "ldapport", "ldap");
1534 hbaline->ldapport = atoi(val);
1535 if (hbaline->ldapport == 0)
1538 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1539 errmsg("invalid LDAP port number: \"%s\"", val),
1540 errcontext("line %d of configuration file \"%s\"",
1541 line_num, HbaFileName)));
1545 else if (strcmp(name, "ldapbinddn") == 0)
1547 REQUIRE_AUTH_OPTION(uaLDAP, "ldapbinddn", "ldap");
1548 hbaline->ldapbinddn = pstrdup(val);
1550 else if (strcmp(name, "ldapbindpasswd") == 0)
1552 REQUIRE_AUTH_OPTION(uaLDAP, "ldapbindpasswd", "ldap");
1553 hbaline->ldapbindpasswd = pstrdup(val);
1555 else if (strcmp(name, "ldapsearchattribute") == 0)
1557 REQUIRE_AUTH_OPTION(uaLDAP, "ldapsearchattribute", "ldap");
1558 hbaline->ldapsearchattribute = pstrdup(val);
1560 else if (strcmp(name, "ldapbasedn") == 0)
1562 REQUIRE_AUTH_OPTION(uaLDAP, "ldapbasedn", "ldap");
1563 hbaline->ldapbasedn = pstrdup(val);
1565 else if (strcmp(name, "ldapprefix") == 0)
1567 REQUIRE_AUTH_OPTION(uaLDAP, "ldapprefix", "ldap");
1568 hbaline->ldapprefix = pstrdup(val);
1570 else if (strcmp(name, "ldapsuffix") == 0)
1572 REQUIRE_AUTH_OPTION(uaLDAP, "ldapsuffix", "ldap");
1573 hbaline->ldapsuffix = pstrdup(val);
1575 else if (strcmp(name, "krb_realm") == 0)
1577 if (hbaline->auth_method != uaGSS &&
1578 hbaline->auth_method != uaSSPI)
1579 INVALID_AUTH_OPTION("krb_realm", gettext_noop("gssapi and sspi"));
1580 hbaline->krb_realm = pstrdup(val);
1582 else if (strcmp(name, "include_realm") == 0)
1584 if (hbaline->auth_method != uaGSS &&
1585 hbaline->auth_method != uaSSPI)
1586 INVALID_AUTH_OPTION("include_realm", gettext_noop("gssapi and sspi"));
1587 if (strcmp(val, "1") == 0)
1588 hbaline->include_realm = true;
1590 hbaline->include_realm = false;
1592 else if (strcmp(name, "radiusserver") == 0)
1594 struct addrinfo *gai_result;
1595 struct addrinfo hints;
1598 REQUIRE_AUTH_OPTION(uaRADIUS, "radiusserver", "radius");
1600 MemSet(&hints, 0, sizeof(hints));
1601 hints.ai_socktype = SOCK_DGRAM;
1602 hints.ai_family = AF_UNSPEC;
1604 ret = pg_getaddrinfo_all(val, NULL, &hints, &gai_result);
1605 if (ret || !gai_result)
1608 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1609 errmsg("could not translate RADIUS server name \"%s\" to address: %s",
1610 val, gai_strerror(ret)),
1611 errcontext("line %d of configuration file \"%s\"",
1612 line_num, HbaFileName)));
1614 pg_freeaddrinfo_all(hints.ai_family, gai_result);
1617 pg_freeaddrinfo_all(hints.ai_family, gai_result);
1618 hbaline->radiusserver = pstrdup(val);
1620 else if (strcmp(name, "radiusport") == 0)
1622 REQUIRE_AUTH_OPTION(uaRADIUS, "radiusport", "radius");
1623 hbaline->radiusport = atoi(val);
1624 if (hbaline->radiusport == 0)
1627 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1628 errmsg("invalid RADIUS port number: \"%s\"", val),
1629 errcontext("line %d of configuration file \"%s\"",
1630 line_num, HbaFileName)));
1634 else if (strcmp(name, "radiussecret") == 0)
1636 REQUIRE_AUTH_OPTION(uaRADIUS, "radiussecret", "radius");
1637 hbaline->radiussecret = pstrdup(val);
1639 else if (strcmp(name, "radiusidentifier") == 0)
1641 REQUIRE_AUTH_OPTION(uaRADIUS, "radiusidentifier", "radius");
1642 hbaline->radiusidentifier = pstrdup(val);
1647 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1648 errmsg("unrecognized authentication option name: \"%s\"",
1650 errcontext("line %d of configuration file \"%s\"",
1651 line_num, HbaFileName)));
1658 * Scan the pre-parsed hba file, looking for a match to the port's connection
1662 check_hba(hbaPort *port)
1668 /* Get the target role's OID. Note we do not error out for bad role. */
1669 roleid = get_role_oid(port->user_name, true);
1671 foreach(line, parsed_hba_lines)
1673 hba = (HbaLine *) lfirst(line);
1675 /* Check connection type */
1676 if (hba->conntype == ctLocal)
1678 if (!IS_AF_UNIX(port->raddr.addr.ss_family))
1683 if (IS_AF_UNIX(port->raddr.addr.ss_family))
1686 /* Check SSL state */
1690 /* Connection is SSL, match both "host" and "hostssl" */
1691 if (hba->conntype == ctHostNoSSL)
1696 /* Connection is not SSL, match both "host" and "hostnossl" */
1697 if (hba->conntype == ctHostSSL)
1701 /* No SSL support, so reject "hostssl" lines */
1702 if (hba->conntype == ctHostSSL)
1706 /* Check IP address */
1707 switch (hba->ip_cmp_method)
1712 if (!check_hostname(port,
1718 if (!check_ip(&port->raddr,
1719 (struct sockaddr *) & hba->addr,
1720 (struct sockaddr *) & hba->mask))
1728 if (!check_same_host_or_net(&port->raddr,
1729 hba->ip_cmp_method))
1733 /* shouldn't get here, but deem it no-match if so */
1738 /* Check database and role */
1739 if (!check_db(port->database_name, port->user_name, roleid,
1743 if (!check_role(port->user_name, roleid, hba->roles))
1746 /* Found a record that matched! */
1751 /* If no matching entry was found, then implicitly reject. */
1752 hba = palloc0(sizeof(HbaLine));
1753 hba->auth_method = uaImplicitReject;
1758 * Read the config file and create a List of HbaLine records for the contents.
1760 * The configuration is read into a temporary list, and if any parse error
1761 * occurs the old list is kept in place and false is returned. Only if the
1762 * whole file parses OK is the list replaced, and the function returns true.
1764 * On a false result, caller will take care of reporting a FATAL error in case
1765 * this is the initial startup. If it happens on reload, we just keep running
1766 * with the old data.
1772 List *hba_lines = NIL;
1773 List *hba_line_nums = NIL;
1774 List *hba_raw_lines = NIL;
1778 List *new_parsed_lines = NIL;
1780 MemoryContext linecxt;
1781 MemoryContext oldcxt;
1782 MemoryContext hbacxt;
1784 file = AllocateFile(HbaFileName, "r");
1788 (errcode_for_file_access(),
1789 errmsg("could not open configuration file \"%s\": %m",
1794 linecxt = tokenize_file(HbaFileName, file, &hba_lines, &hba_line_nums, &hba_raw_lines);
1797 /* Now parse all the lines */
1798 hbacxt = AllocSetContextCreate(TopMemoryContext,
1799 "hba parser context",
1800 ALLOCSET_DEFAULT_MINSIZE,
1801 ALLOCSET_DEFAULT_MINSIZE,
1802 ALLOCSET_DEFAULT_MAXSIZE);
1803 oldcxt = MemoryContextSwitchTo(hbacxt);
1804 forthree(line, hba_lines, line_num, hba_line_nums, raw_line, hba_raw_lines)
1808 if ((newline = parse_hba_line(lfirst(line), lfirst_int(line_num), lfirst(raw_line))) == NULL)
1811 * Parse error in the file, so indicate there's a problem. NB: a
1812 * problem in a line will free the memory for all previous lines
1815 MemoryContextReset(hbacxt);
1816 new_parsed_lines = NIL;
1820 * Keep parsing the rest of the file so we can report errors on
1821 * more than the first row. Error has already been reported in the
1822 * parsing function, so no need to log it here.
1827 new_parsed_lines = lappend(new_parsed_lines, newline);
1831 * A valid HBA file must have at least one entry; else there's no way to
1832 * connect to the postmaster. But only complain about this if we didn't
1833 * already have parsing errors.
1835 if (ok && new_parsed_lines == NIL)
1838 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1839 errmsg("configuration file \"%s\" contains no entries",
1844 /* Free tokenizer memory */
1845 MemoryContextDelete(linecxt);
1846 MemoryContextSwitchTo(oldcxt);
1850 /* File contained one or more errors, so bail out */
1851 MemoryContextDelete(hbacxt);
1855 /* Loaded new file successfully, replace the one we use */
1856 if (parsed_hba_context != NULL)
1857 MemoryContextDelete(parsed_hba_context);
1858 parsed_hba_context = hbacxt;
1859 parsed_hba_lines = new_parsed_lines;
1865 * Parse one tokenised line from the ident config file and store the result in
1866 * an IdentLine structure, or NULL if parsing fails.
1868 * The tokenised line is a nested List of fields and tokens.
1870 * If ident_user is a regular expression (ie. begins with a slash), it is
1871 * compiled and stored in IdentLine structure.
1873 * Note: this function leaks memory when an error occurs. Caller is expected
1874 * to have set a memory context that will be reset if this function returns
1878 parse_ident_line(List *line, int line_number)
1883 IdentLine *parsedline;
1885 Assert(line != NIL);
1886 field = list_head(line);
1888 parsedline = palloc0(sizeof(IdentLine));
1889 parsedline->linenumber = line_number;
1891 /* Get the map token (must exist) */
1892 tokens = lfirst(field);
1893 IDENT_MULTI_VALUE(tokens);
1894 token = linitial(tokens);
1895 parsedline->usermap = pstrdup(token->string);
1897 /* Get the ident user token */
1898 field = lnext(field);
1899 IDENT_FIELD_ABSENT(field);
1900 tokens = lfirst(field);
1901 IDENT_MULTI_VALUE(tokens);
1902 token = linitial(tokens);
1903 parsedline->ident_user = pstrdup(token->string);
1905 /* Get the PG rolename token */
1906 field = lnext(field);
1907 IDENT_FIELD_ABSENT(field);
1908 tokens = lfirst(field);
1909 IDENT_MULTI_VALUE(tokens);
1910 token = linitial(tokens);
1911 parsedline->pg_role = pstrdup(token->string);
1913 if (parsedline->ident_user[0] == '/')
1916 * When system username starts with a slash, treat it as a regular
1917 * expression. Pre-compile it.
1923 wstr = palloc((strlen(parsedline->ident_user + 1) + 1) * sizeof(pg_wchar));
1924 wlen = pg_mb2wchar_with_len(parsedline->ident_user + 1,
1925 wstr, strlen(parsedline->ident_user + 1));
1927 r = pg_regcomp(&parsedline->re, wstr, wlen, REG_ADVANCED, C_COLLATION_OID);
1932 pg_regerror(r, &parsedline->re, errstr, sizeof(errstr));
1934 (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
1935 errmsg("invalid regular expression \"%s\": %s",
1936 parsedline->ident_user + 1, errstr)));
1948 * Process one line from the parsed ident config lines.
1950 * Compare input parsed ident line to the needed map, pg_role and ident_user.
1951 * *found_p and *error_p are set according to our results.
1954 check_ident_usermap(IdentLine *identLine, const char *usermap_name,
1955 const char *pg_role, const char *ident_user,
1956 bool case_insensitive, bool *found_p, bool *error_p)
1961 if (strcmp(identLine->usermap, usermap_name) != 0)
1962 /* Line does not match the map name we're looking for, so just abort */
1966 if (identLine->ident_user[0] == '/')
1969 * When system username starts with a slash, treat it as a regular
1970 * expression. In this case, we process the system username as a
1971 * regular expression that returns exactly one match. This is replaced
1972 * for \1 in the database username string, if present.
1975 regmatch_t matches[2];
1979 char *regexp_pgrole;
1981 wstr = palloc((strlen(ident_user) + 1) * sizeof(pg_wchar));
1982 wlen = pg_mb2wchar_with_len(ident_user, wstr, strlen(ident_user));
1984 r = pg_regexec(&identLine->re, wstr, wlen, 0, NULL, 2, matches, 0);
1989 if (r != REG_NOMATCH)
1991 /* REG_NOMATCH is not an error, everything else is */
1992 pg_regerror(r, &identLine->re, errstr, sizeof(errstr));
1994 (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
1995 errmsg("regular expression match for \"%s\" failed: %s",
1996 identLine->ident_user + 1, errstr)));
2005 if ((ofs = strstr(identLine->pg_role, "\\1")) != NULL)
2007 /* substitution of the first argument requested */
2008 if (matches[1].rm_so < 0)
2011 (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
2012 errmsg("regular expression \"%s\" has no subexpressions as requested by backreference in \"%s\"",
2013 identLine->ident_user + 1, identLine->pg_role)));
2019 * length: original length minus length of \1 plus length of match
2020 * plus null terminator
2022 regexp_pgrole = palloc0(strlen(identLine->pg_role) - 2 + (matches[1].rm_eo - matches[1].rm_so) + 1);
2023 strncpy(regexp_pgrole, identLine->pg_role, (ofs - identLine->pg_role));
2024 memcpy(regexp_pgrole + strlen(regexp_pgrole),
2025 ident_user + matches[1].rm_so,
2026 matches[1].rm_eo - matches[1].rm_so);
2027 strcat(regexp_pgrole, ofs + 2);
2031 /* no substitution, so copy the match */
2032 regexp_pgrole = pstrdup(identLine->pg_role);
2036 * now check if the username actually matched what the user is trying
2039 if (case_insensitive)
2041 if (pg_strcasecmp(regexp_pgrole, pg_role) == 0)
2046 if (strcmp(regexp_pgrole, pg_role) == 0)
2049 pfree(regexp_pgrole);
2055 /* Not regular expression, so make complete match */
2056 if (case_insensitive)
2058 if (pg_strcasecmp(identLine->pg_role, pg_role) == 0 &&
2059 pg_strcasecmp(identLine->ident_user, ident_user) == 0)
2064 if (strcmp(identLine->pg_role, pg_role) == 0 &&
2065 strcmp(identLine->ident_user, ident_user) == 0)
2074 * Scan the (pre-parsed) ident usermap file line by line, looking for a match
2076 * See if the user with ident username "auth_user" is allowed to act
2077 * as Postgres user "pg_role" according to usermap "usermap_name".
2079 * Special case: Usermap NULL, equivalent to what was previously called
2080 * "sameuser" or "samerole", means don't look in the usermap file.
2081 * That's an implied map wherein "pg_role" must be identical to
2082 * "auth_user" in order to be authorized.
2084 * Iff authorized, return STATUS_OK, otherwise return STATUS_ERROR.
2087 check_usermap(const char *usermap_name,
2088 const char *pg_role,
2089 const char *auth_user,
2090 bool case_insensitive)
2092 bool found_entry = false,
2095 if (usermap_name == NULL || usermap_name[0] == '\0')
2097 if (case_insensitive)
2099 if (pg_strcasecmp(pg_role, auth_user) == 0)
2104 if (strcmp(pg_role, auth_user) == 0)
2108 (errmsg("provided user name (%s) and authenticated user name (%s) do not match",
2109 pg_role, auth_user)));
2110 return STATUS_ERROR;
2114 ListCell *line_cell;
2116 foreach(line_cell, parsed_ident_lines)
2118 check_ident_usermap(lfirst(line_cell), usermap_name,
2119 pg_role, auth_user, case_insensitive,
2120 &found_entry, &error);
2121 if (found_entry || error)
2125 if (!found_entry && !error)
2128 (errmsg("no match in usermap \"%s\" for user \"%s\" authenticated as \"%s\"",
2129 usermap_name, pg_role, auth_user)));
2131 return found_entry ? STATUS_OK : STATUS_ERROR;
2136 * Read the ident config file and create a List of IdentLine records for
2139 * This works the same as load_hba(), but for the user config file.
2145 List *ident_lines = NIL;
2146 List *ident_line_nums = NIL;
2147 ListCell *line_cell,
2150 List *new_parsed_lines = NIL;
2152 MemoryContext linecxt;
2153 MemoryContext oldcxt;
2154 MemoryContext ident_context;
2157 file = AllocateFile(IdentFileName, "r");
2160 /* not fatal ... we just won't do any special ident maps */
2162 (errcode_for_file_access(),
2163 errmsg("could not open usermap file \"%s\": %m",
2168 linecxt = tokenize_file(IdentFileName, file, &ident_lines, &ident_line_nums, NULL);
2171 /* Now parse all the lines */
2172 ident_context = AllocSetContextCreate(TopMemoryContext,
2173 "ident parser context",
2174 ALLOCSET_DEFAULT_MINSIZE,
2175 ALLOCSET_DEFAULT_MINSIZE,
2176 ALLOCSET_DEFAULT_MAXSIZE);
2177 oldcxt = MemoryContextSwitchTo(ident_context);
2178 forboth(line_cell, ident_lines, num_cell, ident_line_nums)
2180 if ((newline = parse_ident_line(lfirst(line_cell), lfirst_int(num_cell))) == NULL)
2183 * Parse error in the file, so indicate there's a problem. Free
2184 * all the memory and regular expressions of lines parsed so far.
2186 foreach(parsed_line_cell, new_parsed_lines)
2188 newline = (IdentLine *) lfirst(parsed_line_cell);
2189 if (newline->ident_user[0] == '/')
2190 pg_regfree(&newline->re);
2192 MemoryContextReset(ident_context);
2193 new_parsed_lines = NIL;
2197 * Keep parsing the rest of the file so we can report errors on
2198 * more than the first row. Error has already been reported in the
2199 * parsing function, so no need to log it here.
2204 new_parsed_lines = lappend(new_parsed_lines, newline);
2207 /* Free tokenizer memory */
2208 MemoryContextDelete(linecxt);
2209 MemoryContextSwitchTo(oldcxt);
2213 /* File contained one or more errors, so bail out */
2214 foreach(parsed_line_cell, new_parsed_lines)
2216 newline = (IdentLine *) lfirst(parsed_line_cell);
2217 if (newline->ident_user[0] == '/')
2218 pg_regfree(&newline->re);
2220 MemoryContextDelete(ident_context);
2224 /* Loaded new file successfully, replace the one we use */
2225 if (parsed_ident_lines != NIL)
2227 foreach(parsed_line_cell, parsed_ident_lines)
2229 newline = (IdentLine *) lfirst(parsed_line_cell);
2230 if (newline->ident_user[0] == '/')
2231 pg_regfree(&newline->re);
2234 if (parsed_ident_context != NULL)
2235 MemoryContextDelete(parsed_ident_context);
2237 parsed_ident_context = ident_context;
2238 parsed_ident_lines = new_parsed_lines;
2246 * Determine what authentication method should be used when accessing database
2247 * "database" from frontend "raddr", user "user". Return the method and
2248 * an optional argument (stored in fields of *port), and STATUS_OK.
2250 * If the file does not contain any entry matching the request, we return
2251 * method = uaImplicitReject.
2254 hba_getauthmethod(hbaPort *port)