]> granicus.if.org Git - postgresql/blob - src/backend/libpq/hba.c
828f6dcc8e1653ad25f206f9d10b55006466b2e1
[postgresql] / src / backend / libpq / hba.c
1 /*-------------------------------------------------------------------------
2  *
3  * hba.c
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).
7  *
8  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
9  * Portions Copyright (c) 1994, Regents of the University of California
10  *
11  *
12  * IDENTIFICATION
13  *        src/backend/libpq/hba.c
14  *
15  *-------------------------------------------------------------------------
16  */
17 #include "postgres.h"
18
19 #include <ctype.h>
20 #include <pwd.h>
21 #include <fcntl.h>
22 #include <sys/param.h>
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26 #include <unistd.h>
27
28 #include "catalog/pg_collation.h"
29 #include "libpq/ip.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"
39
40
41 #define atooid(x)  ((Oid) strtoul((x), NULL, 10))
42 #define atoxid(x)  ((TransactionId) strtoul((x), NULL, 10))
43
44 #define MAX_TOKEN       256
45
46 /* callback data for check_network_callback */
47 typedef struct check_network_data
48 {
49         IPCompareMethod method;         /* test method */
50         SockAddr   *raddr;                      /* client's actual address */
51         bool            result;                 /* set to true if match */
52 } check_network_data;
53
54
55 #define token_is_keyword(t, k)  (!t->quoted && strcmp(t->string, k) == 0)
56 #define token_matches(t, k)  (strcmp(t->string, k) == 0)
57
58 /*
59  * A single string token lexed from the HBA config file, together with whether
60  * the token had been quoted.
61  */
62 typedef struct HbaToken
63 {
64         char       *string;
65         bool            quoted;
66 } HbaToken;
67
68 /*
69  * pre-parsed content of HBA config file: list of HbaLine structs.
70  * parsed_hba_context is the memory context where it lives.
71  */
72 static List *parsed_hba_lines = NIL;
73 static MemoryContext parsed_hba_context = NULL;
74
75 /*
76  * These variables hold the pre-parsed contents of the ident usermap
77  * configuration file.  ident_lines is a triple-nested list of lines, fields
78  * and tokens, as returned by tokenize_file.  There will be one line in
79  * ident_lines for each (non-empty, non-comment) line of the file.      Note there
80  * will always be at least one field, since blank lines are not entered in the
81  * data structure.      ident_line_nums is an integer list containing the actual
82  * line number for each line represented in ident_lines.  ident_context is
83  * the memory context holding all this.
84  */
85 static List *ident_lines = NIL;
86 static List *ident_line_nums = NIL;
87 static MemoryContext ident_context = NULL;
88
89
90 static MemoryContext tokenize_file(const char *filename, FILE *file,
91                           List **lines, List **line_nums);
92 static List *tokenize_inc_file(List *tokens, const char *outer_filename,
93                                   const char *inc_filename);
94 static bool parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline,
95                                    int line_num);
96
97 /*
98  * isblank() exists in the ISO C99 spec, but it's not very portable yet,
99  * so provide our own version.
100  */
101 bool
102 pg_isblank(const char c)
103 {
104         return c == ' ' || c == '\t' || c == '\r';
105 }
106
107
108 /*
109  * Grab one token out of fp. Tokens are strings of non-blank
110  * characters bounded by blank characters, commas, beginning of line, and
111  * end of line. Blank means space or tab. Tokens can be delimited by
112  * double quotes (this allows the inclusion of blanks, but not newlines).
113  *
114  * The token, if any, is returned at *buf (a buffer of size bufsz).
115  * Also, we set *initial_quote to indicate whether there was quoting before
116  * the first character.  (We use that to prevent "@x" from being treated
117  * as a file inclusion request.  Note that @"x" should be so treated;
118  * we want to allow that to support embedded spaces in file paths.)
119  * We set *terminating_comma to indicate whether the token is terminated by a
120  * comma (which is not returned.)
121  *
122  * If successful: store null-terminated token at *buf and return TRUE.
123  * If no more tokens on line: set *buf = '\0' and return FALSE.
124  *
125  * Leave file positioned at the character immediately after the token or EOF,
126  * whichever comes first. If no more tokens on line, position the file to the
127  * beginning of the next line or EOF, whichever comes first.
128  *
129  * Handle comments.
130  */
131 static bool
132 next_token(FILE *fp, char *buf, int bufsz, bool *initial_quote,
133                    bool *terminating_comma)
134 {
135         int                     c;
136         char       *start_buf = buf;
137         char       *end_buf = buf + (bufsz - 2);
138         bool            in_quote = false;
139         bool            was_quote = false;
140         bool            saw_quote = false;
141
142         /* end_buf reserves two bytes to ensure we can append \n and \0 */
143         Assert(end_buf > start_buf);
144
145         *initial_quote = false;
146         *terminating_comma = false;
147
148         /* Move over initial whitespace and commas */
149         while ((c = getc(fp)) != EOF && (pg_isblank(c) || c == ','))
150                 ;
151
152         if (c == EOF || c == '\n')
153         {
154                 *buf = '\0';
155                 return false;
156         }
157
158         /*
159          * Build a token in buf of next characters up to EOF, EOL, unquoted comma,
160          * or unquoted whitespace.
161          */
162         while (c != EOF && c != '\n' &&
163                    (!pg_isblank(c) || in_quote))
164         {
165                 /* skip comments to EOL */
166                 if (c == '#' && !in_quote)
167                 {
168                         while ((c = getc(fp)) != EOF && c != '\n')
169                                 ;
170                         /* If only comment, consume EOL too; return EOL */
171                         if (c != EOF && buf == start_buf)
172                                 c = getc(fp);
173                         break;
174                 }
175
176                 if (buf >= end_buf)
177                 {
178                         *buf = '\0';
179                         ereport(LOG,
180                                         (errcode(ERRCODE_CONFIG_FILE_ERROR),
181                            errmsg("authentication file token too long, skipping: \"%s\"",
182                                           start_buf)));
183                         /* Discard remainder of line */
184                         while ((c = getc(fp)) != EOF && c != '\n')
185                                 ;
186                         break;
187                 }
188
189                 /* we do not pass back the comma in the token */
190                 if (c == ',' && !in_quote)
191                 {
192                         *terminating_comma = true;
193                         break;
194                 }
195
196                 if (c != '"' || was_quote)
197                         *buf++ = c;
198
199                 /* Literal double-quote is two double-quotes */
200                 if (in_quote && c == '"')
201                         was_quote = !was_quote;
202                 else
203                         was_quote = false;
204
205                 if (c == '"')
206                 {
207                         in_quote = !in_quote;
208                         saw_quote = true;
209                         if (buf == start_buf)
210                                 *initial_quote = true;
211                 }
212
213                 c = getc(fp);
214         }
215
216         /*
217          * Put back the char right after the token (critical in case it is EOL,
218          * since we need to detect end-of-line at next call).
219          */
220         if (c != EOF)
221                 ungetc(c, fp);
222
223         *buf = '\0';
224
225         return (saw_quote || buf > start_buf);
226 }
227
228 static HbaToken *
229 make_hba_token(char *token, bool quoted)
230 {
231         HbaToken   *hbatoken;
232         int                     toklen;
233
234         toklen = strlen(token);
235         hbatoken = (HbaToken *) palloc(sizeof(HbaToken) + toklen + 1);
236         hbatoken->string = (char *) hbatoken + sizeof(HbaToken);
237         hbatoken->quoted = quoted;
238         memcpy(hbatoken->string, token, toklen + 1);
239
240         return hbatoken;
241 }
242
243 /*
244  * Copy a HbaToken struct into freshly palloc'd memory.
245  */
246 static HbaToken *
247 copy_hba_token(HbaToken *in)
248 {
249         HbaToken   *out = make_hba_token(in->string, in->quoted);
250
251         return out;
252 }
253
254
255 /*
256  * Tokenize one HBA field from a file, handling file inclusion and comma lists.
257  *
258  * The result is a List of HbaToken structs for each individual token,
259  * or NIL if we reached EOL.
260  */
261 static List *
262 next_field_expand(const char *filename, FILE *file)
263 {
264         char            buf[MAX_TOKEN];
265         bool            trailing_comma;
266         bool            initial_quote;
267         List       *tokens = NIL;
268
269         do
270         {
271                 if (!next_token(file, buf, sizeof(buf), &initial_quote, &trailing_comma))
272                         break;
273
274                 /* Is this referencing a file? */
275                 if (!initial_quote && buf[0] == '@' && buf[1] != '\0')
276                         tokens = tokenize_inc_file(tokens, filename, buf + 1);
277                 else
278                         tokens = lappend(tokens, make_hba_token(buf, initial_quote));
279         } while (trailing_comma);
280
281         return tokens;
282 }
283
284 /*
285  * tokenize_inc_file
286  *              Expand a file included from another file into an hba "field"
287  *
288  * Opens and tokenises a file included from another HBA config file with @,
289  * and returns all values found therein as a flat list of HbaTokens.  If a
290  * @-token is found, recursively expand it.  The given token list is used as
291  * initial contents of list (so foo,bar,@baz does what you expect).
292  */
293 static List *
294 tokenize_inc_file(List *tokens,
295                                   const char *outer_filename,
296                                   const char *inc_filename)
297 {
298         char       *inc_fullname;
299         FILE       *inc_file;
300         List       *inc_lines;
301         List       *inc_line_nums;
302         ListCell   *inc_line;
303         MemoryContext linecxt;
304
305         if (is_absolute_path(inc_filename))
306         {
307                 /* absolute path is taken as-is */
308                 inc_fullname = pstrdup(inc_filename);
309         }
310         else
311         {
312                 /* relative path is relative to dir of calling file */
313                 inc_fullname = (char *) palloc(strlen(outer_filename) + 1 +
314                                                                            strlen(inc_filename) + 1);
315                 strcpy(inc_fullname, outer_filename);
316                 get_parent_directory(inc_fullname);
317                 join_path_components(inc_fullname, inc_fullname, inc_filename);
318                 canonicalize_path(inc_fullname);
319         }
320
321         inc_file = AllocateFile(inc_fullname, "r");
322         if (inc_file == NULL)
323         {
324                 ereport(LOG,
325                                 (errcode_for_file_access(),
326                                  errmsg("could not open secondary authentication file \"@%s\" as \"%s\": %m",
327                                                 inc_filename, inc_fullname)));
328                 pfree(inc_fullname);
329                 return tokens;
330         }
331
332         /* There is possible recursion here if the file contains @ */
333         linecxt = tokenize_file(inc_fullname, inc_file, &inc_lines, &inc_line_nums);
334
335         FreeFile(inc_file);
336         pfree(inc_fullname);
337
338         foreach(inc_line, inc_lines)
339         {
340                 List       *inc_fields = lfirst(inc_line);
341                 ListCell   *inc_field;
342
343                 foreach(inc_field, inc_fields)
344                 {
345                         List       *inc_tokens = lfirst(inc_field);
346                         ListCell   *inc_token;
347
348                         foreach(inc_token, inc_tokens)
349                         {
350                                 HbaToken   *token = lfirst(inc_token);
351
352                                 tokens = lappend(tokens, copy_hba_token(token));
353                         }
354                 }
355         }
356
357         MemoryContextDelete(linecxt);
358         return tokens;
359 }
360
361 /*
362  * Tokenize the given file, storing the resulting data into two Lists: a
363  * List of lines, and a List of line numbers.
364  *
365  * The list of lines is a triple-nested List structure.  Each line is a List of
366  * fields, and each field is a List of HbaTokens.
367  *
368  * filename must be the absolute path to the target file.
369  *
370  * Return value is a memory context which contains all memory allocated by
371  * this function.
372  */
373 static MemoryContext
374 tokenize_file(const char *filename, FILE *file,
375                           List **lines, List **line_nums)
376 {
377         List       *current_line = NIL;
378         List       *current_field = NIL;
379         int                     line_number = 1;
380         MemoryContext linecxt;
381         MemoryContext oldcxt;
382
383         linecxt = AllocSetContextCreate(TopMemoryContext,
384                                                                         "tokenize file cxt",
385                                                                         ALLOCSET_DEFAULT_MINSIZE,
386                                                                         ALLOCSET_DEFAULT_INITSIZE,
387                                                                         ALLOCSET_DEFAULT_MAXSIZE);
388         oldcxt = MemoryContextSwitchTo(linecxt);
389
390         *lines = *line_nums = NIL;
391
392         while (!feof(file) && !ferror(file))
393         {
394                 current_field = next_field_expand(filename, file);
395
396                 /* add tokens to list, unless we are at EOL or comment start */
397                 if (list_length(current_field) > 0)
398                 {
399                         if (current_line == NIL)
400                         {
401                                 /* make a new line List, record its line number */
402                                 current_line = lappend(current_line, current_field);
403                                 *lines = lappend(*lines, current_line);
404                                 *line_nums = lappend_int(*line_nums, line_number);
405                         }
406                         else
407                         {
408                                 /* append tokens to current line's list */
409                                 current_line = lappend(current_line, current_field);
410                         }
411                 }
412                 else
413                 {
414                         /* we are at real or logical EOL, so force a new line List */
415                         current_line = NIL;
416                         line_number++;
417                 }
418         }
419
420         MemoryContextSwitchTo(oldcxt);
421
422         return linecxt;
423 }
424
425
426 /*
427  * Does user belong to role?
428  *
429  * userid is the OID of the role given as the attempted login identifier.
430  * We check to see if it is a member of the specified role name.
431  */
432 static bool
433 is_member(Oid userid, const char *role)
434 {
435         Oid                     roleid;
436
437         if (!OidIsValid(userid))
438                 return false;                   /* if user not exist, say "no" */
439
440         roleid = get_role_oid(role, true);
441
442         if (!OidIsValid(roleid))
443                 return false;                   /* if target role not exist, say "no" */
444
445         /*
446          * See if user is directly or indirectly a member of role. For this
447          * purpose, a superuser is not considered to be automatically a member of
448          * the role, so group auth only applies to explicit membership.
449          */
450         return is_member_of_role_nosuper(userid, roleid);
451 }
452
453 /*
454  * Check HbaToken list for a match to role, allowing group names.
455  */
456 static bool
457 check_role(const char *role, Oid roleid, List *tokens)
458 {
459         ListCell   *cell;
460         HbaToken   *tok;
461
462         foreach(cell, tokens)
463         {
464                 tok = lfirst(cell);
465                 if (!tok->quoted && tok->string[0] == '+')
466                 {
467                         if (is_member(roleid, tok->string + 1))
468                                 return true;
469                 }
470                 else if (token_matches(tok, role) ||
471                                  token_is_keyword(tok, "all"))
472                         return true;
473         }
474         return false;
475 }
476
477 /*
478  * Check to see if db/role combination matches HbaToken list.
479  */
480 static bool
481 check_db(const char *dbname, const char *role, Oid roleid, List *tokens)
482 {
483         ListCell   *cell;
484         HbaToken   *tok;
485
486         foreach(cell, tokens)
487         {
488                 tok = lfirst(cell);
489                 if (am_walsender)
490                 {
491                         /* walsender connections can only match replication keyword */
492                         if (token_is_keyword(tok, "replication"))
493                                 return true;
494                 }
495                 else if (token_is_keyword(tok, "all"))
496                         return true;
497                 else if (token_is_keyword(tok, "sameuser"))
498                 {
499                         if (strcmp(dbname, role) == 0)
500                                 return true;
501                 }
502                 else if (token_is_keyword(tok, "samegroup") ||
503                                  token_is_keyword(tok, "samerole"))
504                 {
505                         if (is_member(roleid, dbname))
506                                 return true;
507                 }
508                 else if (token_is_keyword(tok, "replication"))
509                         continue;                       /* never match this if not walsender */
510                 else if (token_matches(tok, dbname))
511                         return true;
512         }
513         return false;
514 }
515
516 static bool
517 ipv4eq(struct sockaddr_in * a, struct sockaddr_in * b)
518 {
519         return (a->sin_addr.s_addr == b->sin_addr.s_addr);
520 }
521
522 #ifdef HAVE_IPV6
523
524 static bool
525 ipv6eq(struct sockaddr_in6 * a, struct sockaddr_in6 * b)
526 {
527         int                     i;
528
529         for (i = 0; i < 16; i++)
530                 if (a->sin6_addr.s6_addr[i] != b->sin6_addr.s6_addr[i])
531                         return false;
532
533         return true;
534 }
535 #endif   /* HAVE_IPV6 */
536
537 /*
538  * Check whether host name matches pattern.
539  */
540 static bool
541 hostname_match(const char *pattern, const char *actual_hostname)
542 {
543         if (pattern[0] == '.')          /* suffix match */
544         {
545                 size_t          plen = strlen(pattern);
546                 size_t          hlen = strlen(actual_hostname);
547
548                 if (hlen < plen)
549                         return false;
550
551                 return (pg_strcasecmp(pattern, actual_hostname + (hlen - plen)) == 0);
552         }
553         else
554                 return (pg_strcasecmp(pattern, actual_hostname) == 0);
555 }
556
557 /*
558  * Check to see if a connecting IP matches a given host name.
559  */
560 static bool
561 check_hostname(hbaPort *port, const char *hostname)
562 {
563         struct addrinfo *gai_result,
564                            *gai;
565         int                     ret;
566         bool            found;
567
568         /* Lookup remote host name if not already done */
569         if (!port->remote_hostname)
570         {
571                 char            remote_hostname[NI_MAXHOST];
572
573                 if (pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
574                                                            remote_hostname, sizeof(remote_hostname),
575                                                            NULL, 0,
576                                                            0) != 0)
577                         return false;
578
579                 port->remote_hostname = pstrdup(remote_hostname);
580         }
581
582         if (!hostname_match(hostname, port->remote_hostname))
583                 return false;
584
585         /* Lookup IP from host name and check against original IP */
586
587         if (port->remote_hostname_resolv == +1)
588                 return true;
589         if (port->remote_hostname_resolv == -1)
590                 return false;
591
592         ret = getaddrinfo(port->remote_hostname, NULL, NULL, &gai_result);
593         if (ret != 0)
594                 ereport(ERROR,
595                                 (errmsg("could not translate host name \"%s\" to address: %s",
596                                                 port->remote_hostname, gai_strerror(ret))));
597
598         found = false;
599         for (gai = gai_result; gai; gai = gai->ai_next)
600         {
601                 if (gai->ai_addr->sa_family == port->raddr.addr.ss_family)
602                 {
603                         if (gai->ai_addr->sa_family == AF_INET)
604                         {
605                                 if (ipv4eq((struct sockaddr_in *) gai->ai_addr,
606                                                    (struct sockaddr_in *) & port->raddr.addr))
607                                 {
608                                         found = true;
609                                         break;
610                                 }
611                         }
612 #ifdef HAVE_IPV6
613                         else if (gai->ai_addr->sa_family == AF_INET6)
614                         {
615                                 if (ipv6eq((struct sockaddr_in6 *) gai->ai_addr,
616                                                    (struct sockaddr_in6 *) & port->raddr.addr))
617                                 {
618                                         found = true;
619                                         break;
620                                 }
621                         }
622 #endif
623                 }
624         }
625
626         if (gai_result)
627                 freeaddrinfo(gai_result);
628
629         if (!found)
630                 elog(DEBUG2, "pg_hba.conf host name \"%s\" rejected because address resolution did not return a match with IP address of client",
631                          hostname);
632
633         port->remote_hostname_resolv = found ? +1 : -1;
634
635         return found;
636 }
637
638 /*
639  * Check to see if a connecting IP matches the given address and netmask.
640  */
641 static bool
642 check_ip(SockAddr *raddr, struct sockaddr * addr, struct sockaddr * mask)
643 {
644         if (raddr->addr.ss_family == addr->sa_family)
645         {
646                 /* Same address family */
647                 if (!pg_range_sockaddr(&raddr->addr,
648                                                            (struct sockaddr_storage *) addr,
649                                                            (struct sockaddr_storage *) mask))
650                         return false;
651         }
652 #ifdef HAVE_IPV6
653         else if (addr->sa_family == AF_INET &&
654                          raddr->addr.ss_family == AF_INET6)
655         {
656                 /*
657                  * If we're connected on IPv6 but the file specifies an IPv4 address
658                  * to match against, promote the latter to an IPv6 address before
659                  * trying to match the client's address.
660                  */
661                 struct sockaddr_storage addrcopy,
662                                         maskcopy;
663
664                 memcpy(&addrcopy, &addr, sizeof(addrcopy));
665                 memcpy(&maskcopy, &mask, sizeof(maskcopy));
666                 pg_promote_v4_to_v6_addr(&addrcopy);
667                 pg_promote_v4_to_v6_mask(&maskcopy);
668
669                 if (!pg_range_sockaddr(&raddr->addr, &addrcopy, &maskcopy))
670                         return false;
671         }
672 #endif   /* HAVE_IPV6 */
673         else
674         {
675                 /* Wrong address family, no IPV6 */
676                 return false;
677         }
678
679         return true;
680 }
681
682 /*
683  * pg_foreach_ifaddr callback: does client addr match this machine interface?
684  */
685 static void
686 check_network_callback(struct sockaddr * addr, struct sockaddr * netmask,
687                                            void *cb_data)
688 {
689         check_network_data *cn = (check_network_data *) cb_data;
690         struct sockaddr_storage mask;
691
692         /* Already found a match? */
693         if (cn->result)
694                 return;
695
696         if (cn->method == ipCmpSameHost)
697         {
698                 /* Make an all-ones netmask of appropriate length for family */
699                 pg_sockaddr_cidr_mask(&mask, NULL, addr->sa_family);
700                 cn->result = check_ip(cn->raddr, addr, (struct sockaddr *) & mask);
701         }
702         else
703         {
704                 /* Use the netmask of the interface itself */
705                 cn->result = check_ip(cn->raddr, addr, netmask);
706         }
707 }
708
709 /*
710  * Use pg_foreach_ifaddr to check a samehost or samenet match
711  */
712 static bool
713 check_same_host_or_net(SockAddr *raddr, IPCompareMethod method)
714 {
715         check_network_data cn;
716
717         cn.method = method;
718         cn.raddr = raddr;
719         cn.result = false;
720
721         errno = 0;
722         if (pg_foreach_ifaddr(check_network_callback, &cn) < 0)
723         {
724                 elog(LOG, "error enumerating network interfaces: %m");
725                 return false;
726         }
727
728         return cn.result;
729 }
730
731
732 /*
733  * Macros used to check and report on invalid configuration options.
734  * INVALID_AUTH_OPTION = reports when an option is specified for a method where it's
735  *                                               not supported.
736  * REQUIRE_AUTH_OPTION = same as INVALID_AUTH_OPTION, except it also checks if the
737  *                                               method is actually the one specified. Used as a shortcut when
738  *                                               the option is only valid for one authentication method.
739  * MANDATORY_AUTH_ARG  = check if a required option is set for an authentication method,
740  *                                               reporting error if it's not.
741  */
742 #define INVALID_AUTH_OPTION(optname, validmethods) do {\
743         ereport(LOG, \
744                         (errcode(ERRCODE_CONFIG_FILE_ERROR), \
745                          /* translator: the second %s is a list of auth methods */ \
746                          errmsg("authentication option \"%s\" is only valid for authentication methods %s", \
747                                         optname, _(validmethods)), \
748                          errcontext("line %d of configuration file \"%s\"", \
749                                         line_num, HbaFileName))); \
750         return false; \
751 } while (0);
752
753 #define REQUIRE_AUTH_OPTION(methodval, optname, validmethods) do {\
754         if (hbaline->auth_method != methodval) \
755                 INVALID_AUTH_OPTION(optname, validmethods); \
756 } while (0);
757
758 #define MANDATORY_AUTH_ARG(argvar, argname, authname) do {\
759         if (argvar == NULL) {\
760                 ereport(LOG, \
761                                 (errcode(ERRCODE_CONFIG_FILE_ERROR), \
762                                  errmsg("authentication method \"%s\" requires argument \"%s\" to be set", \
763                                                 authname, argname), \
764                                  errcontext("line %d of configuration file \"%s\"", \
765                                                 line_num, HbaFileName))); \
766                 return false; \
767         } \
768 } while (0);
769
770 /*
771  * IDENT_FIELD_ABSENT:
772  * Throw an error and exit the function if the given ident field ListCell is
773  * not populated.
774  *
775  * IDENT_MULTI_VALUE:
776  * Throw an error and exit the function if the given ident token List has more
777  * than one element.
778  */
779 #define IDENT_FIELD_ABSENT(field) do {\
780         if (!field) { \
781                 ereport(LOG, \
782                                 (errcode(ERRCODE_CONFIG_FILE_ERROR), \
783                                  errmsg("missing entry in file \"%s\" at end of line %d", \
784                                                 IdentFileName, line_number))); \
785                 *error_p = true; \
786                 return; \
787         } \
788 } while (0);
789
790 #define IDENT_MULTI_VALUE(tokens) do {\
791         if (tokens->length > 1) { \
792                 ereport(LOG, \
793                                 (errcode(ERRCODE_CONFIG_FILE_ERROR), \
794                                  errmsg("multiple values in ident field"), \
795                                  errcontext("line %d of configuration file \"%s\"", \
796                                                 line_number, IdentFileName))); \
797                 *error_p = true; \
798                 return; \
799         } \
800 } while (0);
801
802
803 /*
804  * Parse one tokenised line from the hba config file and store the result in a
805  * HbaLine structure, or NULL if parsing fails.
806  *
807  * The tokenised line is a List of fields, each field being a List of
808  * HbaTokens.
809  *
810  * Note: this function leaks memory when an error occurs.  Caller is expected
811  * to have set a memory context that will be reset if this function returns
812  * NULL.
813  */
814 static HbaLine *
815 parse_hba_line(List *line, int line_num)
816 {
817         char       *str;
818         struct addrinfo *gai_result;
819         struct addrinfo hints;
820         int                     ret;
821         char       *cidr_slash;
822         char       *unsupauth;
823         ListCell   *field;
824         List       *tokens;
825         ListCell   *tokencell;
826         HbaToken   *token;
827         HbaLine    *parsedline;
828
829         parsedline = palloc0(sizeof(HbaLine));
830         parsedline->linenumber = line_num;
831
832         /* Check the record type. */
833         field = list_head(line);
834         tokens = lfirst(field);
835         if (tokens->length > 1)
836         {
837                 ereport(LOG,
838                                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
839                                  errmsg("multiple values specified for connection type"),
840                                  errhint("Specify exactly one connection type per line."),
841                                  errcontext("line %d of configuration file \"%s\"",
842                                                         line_num, HbaFileName)));
843                 return NULL;
844         }
845         token = linitial(tokens);
846         if (strcmp(token->string, "local") == 0)
847         {
848 #ifdef HAVE_UNIX_SOCKETS
849                 parsedline->conntype = ctLocal;
850 #else
851                 ereport(LOG,
852                                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
853                                  errmsg("local connections are not supported by this build"),
854                                  errcontext("line %d of configuration file \"%s\"",
855                                                         line_num, HbaFileName)));
856                 return NULL;
857 #endif
858         }
859         else if (strcmp(token->string, "host") == 0 ||
860                          strcmp(token->string, "hostssl") == 0 ||
861                          strcmp(token->string, "hostnossl") == 0)
862         {
863
864                 if (token->string[4] == 's')    /* "hostssl" */
865                 {
866                         /* SSL support must be actually active, else complain */
867 #ifdef USE_SSL
868                         if (EnableSSL)
869                                 parsedline->conntype = ctHostSSL;
870                         else
871                         {
872                                 ereport(LOG,
873                                                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
874                                                  errmsg("hostssl requires SSL to be turned on"),
875                                                  errhint("Set ssl = on in postgresql.conf."),
876                                                  errcontext("line %d of configuration file \"%s\"",
877                                                                         line_num, HbaFileName)));
878                                 return NULL;
879                         }
880 #else
881                         ereport(LOG,
882                                         (errcode(ERRCODE_CONFIG_FILE_ERROR),
883                                          errmsg("hostssl is not supported by this build"),
884                           errhint("Compile with --with-openssl to use SSL connections."),
885                                          errcontext("line %d of configuration file \"%s\"",
886                                                                 line_num, HbaFileName)));
887                         return NULL;
888 #endif
889                 }
890 #ifdef USE_SSL
891                 else if (token->string[4] == 'n')               /* "hostnossl" */
892                 {
893                         parsedline->conntype = ctHostNoSSL;
894                 }
895 #endif
896                 else
897                 {
898                         /* "host", or "hostnossl" and SSL support not built in */
899                         parsedline->conntype = ctHost;
900                 }
901         }                                                       /* record type */
902         else
903         {
904                 ereport(LOG,
905                                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
906                                  errmsg("invalid connection type \"%s\"",
907                                                 token->string),
908                                  errcontext("line %d of configuration file \"%s\"",
909                                                         line_num, HbaFileName)));
910                 return NULL;
911         }
912
913         /* Get the databases. */
914         field = lnext(field);
915         if (!field)
916         {
917                 ereport(LOG,
918                                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
919                                  errmsg("end-of-line before database specification"),
920                                  errcontext("line %d of configuration file \"%s\"",
921                                                         line_num, HbaFileName)));
922                 return NULL;
923         }
924         parsedline->databases = NIL;
925         tokens = lfirst(field);
926         foreach(tokencell, tokens)
927         {
928                 parsedline->databases = lappend(parsedline->databases,
929                                                                                 copy_hba_token(lfirst(tokencell)));
930         }
931
932         /* Get the roles. */
933         field = lnext(field);
934         if (!field)
935         {
936                 ereport(LOG,
937                                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
938                                  errmsg("end-of-line before role specification"),
939                                  errcontext("line %d of configuration file \"%s\"",
940                                                         line_num, HbaFileName)));
941                 return NULL;
942         }
943         parsedline->roles = NIL;
944         tokens = lfirst(field);
945         foreach(tokencell, tokens)
946         {
947                 parsedline->roles = lappend(parsedline->roles,
948                                                                         copy_hba_token(lfirst(tokencell)));
949         }
950
951         if (parsedline->conntype != ctLocal)
952         {
953                 /* Read the IP address field. (with or without CIDR netmask) */
954                 field = lnext(field);
955                 if (!field)
956                 {
957                         ereport(LOG,
958                                         (errcode(ERRCODE_CONFIG_FILE_ERROR),
959                                          errmsg("end-of-line before IP address specification"),
960                                          errcontext("line %d of configuration file \"%s\"",
961                                                                 line_num, HbaFileName)));
962                         return NULL;
963                 }
964                 tokens = lfirst(field);
965                 if (tokens->length > 1)
966                 {
967                         ereport(LOG,
968                                         (errcode(ERRCODE_CONFIG_FILE_ERROR),
969                                          errmsg("multiple values specified for host address"),
970                                          errhint("Specify one address range per line."),
971                                          errcontext("line %d of configuration file \"%s\"",
972                                                                 line_num, HbaFileName)));
973                         return NULL;
974                 }
975                 token = linitial(tokens);
976
977                 if (token_is_keyword(token, "all"))
978                 {
979                         parsedline->ip_cmp_method = ipCmpAll;
980                 }
981                 else if (token_is_keyword(token, "samehost"))
982                 {
983                         /* Any IP on this host is allowed to connect */
984                         parsedline->ip_cmp_method = ipCmpSameHost;
985                 }
986                 else if (token_is_keyword(token, "samenet"))
987                 {
988                         /* Any IP on the host's subnets is allowed to connect */
989                         parsedline->ip_cmp_method = ipCmpSameNet;
990                 }
991                 else
992                 {
993                         /* IP and netmask are specified */
994                         parsedline->ip_cmp_method = ipCmpMask;
995
996                         /* need a modifiable copy of token */
997                         str = pstrdup(token->string);
998
999                         /* Check if it has a CIDR suffix and if so isolate it */
1000                         cidr_slash = strchr(str, '/');
1001                         if (cidr_slash)
1002                                 *cidr_slash = '\0';
1003
1004                         /* Get the IP address either way */
1005                         hints.ai_flags = AI_NUMERICHOST;
1006                         hints.ai_family = PF_UNSPEC;
1007                         hints.ai_socktype = 0;
1008                         hints.ai_protocol = 0;
1009                         hints.ai_addrlen = 0;
1010                         hints.ai_canonname = NULL;
1011                         hints.ai_addr = NULL;
1012                         hints.ai_next = NULL;
1013
1014                         ret = pg_getaddrinfo_all(str, NULL, &hints, &gai_result);
1015                         if (ret == 0 && gai_result)
1016                                 memcpy(&parsedline->addr, gai_result->ai_addr,
1017                                            gai_result->ai_addrlen);
1018                         else if (ret == EAI_NONAME)
1019                                 parsedline->hostname = str;
1020                         else
1021                         {
1022                                 ereport(LOG,
1023                                                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1024                                                  errmsg("invalid IP address \"%s\": %s",
1025                                                                 str, gai_strerror(ret)),
1026                                                  errcontext("line %d of configuration file \"%s\"",
1027                                                                         line_num, HbaFileName)));
1028                                 if (gai_result)
1029                                         pg_freeaddrinfo_all(hints.ai_family, gai_result);
1030                                 return NULL;
1031                         }
1032
1033                         pg_freeaddrinfo_all(hints.ai_family, gai_result);
1034
1035                         /* Get the netmask */
1036                         if (cidr_slash)
1037                         {
1038                                 if (parsedline->hostname)
1039                                 {
1040                                         ereport(LOG,
1041                                                         (errcode(ERRCODE_CONFIG_FILE_ERROR),
1042                                                          errmsg("specifying both host name and CIDR mask is invalid: \"%s\"",
1043                                                                         token->string),
1044                                                    errcontext("line %d of configuration file \"%s\"",
1045                                                                           line_num, HbaFileName)));
1046                                         return NULL;
1047                                 }
1048
1049                                 if (pg_sockaddr_cidr_mask(&parsedline->mask, cidr_slash + 1,
1050                                                                                   parsedline->addr.ss_family) < 0)
1051                                 {
1052                                         ereport(LOG,
1053                                                         (errcode(ERRCODE_CONFIG_FILE_ERROR),
1054                                                          errmsg("invalid CIDR mask in address \"%s\"",
1055                                                                         token->string),
1056                                                    errcontext("line %d of configuration file \"%s\"",
1057                                                                           line_num, HbaFileName)));
1058                                         return NULL;
1059                                 }
1060                                 pfree(str);
1061                         }
1062                         else if (!parsedline->hostname)
1063                         {
1064                                 /* Read the mask field. */
1065                                 pfree(str);
1066                                 field = lnext(field);
1067                                 if (!field)
1068                                 {
1069                                         ereport(LOG,
1070                                                         (errcode(ERRCODE_CONFIG_FILE_ERROR),
1071                                                   errmsg("end-of-line before netmask specification"),
1072                                                          errhint("Specify an address range in CIDR notation, or provide a separate netmask."),
1073                                                    errcontext("line %d of configuration file \"%s\"",
1074                                                                           line_num, HbaFileName)));
1075                                         return NULL;
1076                                 }
1077                                 tokens = lfirst(field);
1078                                 if (tokens->length > 1)
1079                                 {
1080                                         ereport(LOG,
1081                                                         (errcode(ERRCODE_CONFIG_FILE_ERROR),
1082                                                          errmsg("multiple values specified for netmask"),
1083                                                    errcontext("line %d of configuration file \"%s\"",
1084                                                                           line_num, HbaFileName)));
1085                                         return NULL;
1086                                 }
1087                                 token = linitial(tokens);
1088
1089                                 ret = pg_getaddrinfo_all(token->string, NULL,
1090                                                                                  &hints, &gai_result);
1091                                 if (ret || !gai_result)
1092                                 {
1093                                         ereport(LOG,
1094                                                         (errcode(ERRCODE_CONFIG_FILE_ERROR),
1095                                                          errmsg("invalid IP mask \"%s\": %s",
1096                                                                         token->string, gai_strerror(ret)),
1097                                                    errcontext("line %d of configuration file \"%s\"",
1098                                                                           line_num, HbaFileName)));
1099                                         if (gai_result)
1100                                                 pg_freeaddrinfo_all(hints.ai_family, gai_result);
1101                                         return NULL;
1102                                 }
1103
1104                                 memcpy(&parsedline->mask, gai_result->ai_addr,
1105                                            gai_result->ai_addrlen);
1106                                 pg_freeaddrinfo_all(hints.ai_family, gai_result);
1107
1108                                 if (parsedline->addr.ss_family != parsedline->mask.ss_family)
1109                                 {
1110                                         ereport(LOG,
1111                                                         (errcode(ERRCODE_CONFIG_FILE_ERROR),
1112                                                          errmsg("IP address and mask do not match"),
1113                                                    errcontext("line %d of configuration file \"%s\"",
1114                                                                           line_num, HbaFileName)));
1115                                         return NULL;
1116                                 }
1117                         }
1118                 }
1119         }                                                       /* != ctLocal */
1120
1121         /* Get the authentication method */
1122         field = lnext(field);
1123         if (!field)
1124         {
1125                 ereport(LOG,
1126                                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1127                                  errmsg("end-of-line before authentication method"),
1128                                  errcontext("line %d of configuration file \"%s\"",
1129                                                         line_num, HbaFileName)));
1130                 return NULL;
1131         }
1132         tokens = lfirst(field);
1133         if (tokens->length > 1)
1134         {
1135                 ereport(LOG,
1136                                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1137                                  errmsg("multiple values specified for authentication type"),
1138                                  errhint("Specify exactly one authentication type per line."),
1139                                  errcontext("line %d of configuration file \"%s\"",
1140                                                         line_num, HbaFileName)));
1141                 return NULL;
1142         }
1143         token = linitial(tokens);
1144
1145         unsupauth = NULL;
1146         if (strcmp(token->string, "trust") == 0)
1147                 parsedline->auth_method = uaTrust;
1148         else if (strcmp(token->string, "ident") == 0)
1149                 parsedline->auth_method = uaIdent;
1150         else if (strcmp(token->string, "peer") == 0)
1151                 parsedline->auth_method = uaPeer;
1152         else if (strcmp(token->string, "password") == 0)
1153                 parsedline->auth_method = uaPassword;
1154         else if (strcmp(token->string, "krb5") == 0)
1155 #ifdef KRB5
1156                 parsedline->auth_method = uaKrb5;
1157 #else
1158                 unsupauth = "krb5";
1159 #endif
1160         else if (strcmp(token->string, "gss") == 0)
1161 #ifdef ENABLE_GSS
1162                 parsedline->auth_method = uaGSS;
1163 #else
1164                 unsupauth = "gss";
1165 #endif
1166         else if (strcmp(token->string, "sspi") == 0)
1167 #ifdef ENABLE_SSPI
1168                 parsedline->auth_method = uaSSPI;
1169 #else
1170                 unsupauth = "sspi";
1171 #endif
1172         else if (strcmp(token->string, "reject") == 0)
1173                 parsedline->auth_method = uaReject;
1174         else if (strcmp(token->string, "md5") == 0)
1175         {
1176                 if (Db_user_namespace)
1177                 {
1178                         ereport(LOG,
1179                                         (errcode(ERRCODE_CONFIG_FILE_ERROR),
1180                                          errmsg("MD5 authentication is not supported when \"db_user_namespace\" is enabled"),
1181                                          errcontext("line %d of configuration file \"%s\"",
1182                                                                 line_num, HbaFileName)));
1183                         return NULL;
1184                 }
1185                 parsedline->auth_method = uaMD5;
1186         }
1187         else if (strcmp(token->string, "pam") == 0)
1188 #ifdef USE_PAM
1189                 parsedline->auth_method = uaPAM;
1190 #else
1191                 unsupauth = "pam";
1192 #endif
1193         else if (strcmp(token->string, "ldap") == 0)
1194 #ifdef USE_LDAP
1195                 parsedline->auth_method = uaLDAP;
1196 #else
1197                 unsupauth = "ldap";
1198 #endif
1199         else if (strcmp(token->string, "cert") == 0)
1200 #ifdef USE_SSL
1201                 parsedline->auth_method = uaCert;
1202 #else
1203                 unsupauth = "cert";
1204 #endif
1205         else if (strcmp(token->string, "radius") == 0)
1206                 parsedline->auth_method = uaRADIUS;
1207         else
1208         {
1209                 ereport(LOG,
1210                                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1211                                  errmsg("invalid authentication method \"%s\"",
1212                                                 token->string),
1213                                  errcontext("line %d of configuration file \"%s\"",
1214                                                         line_num, HbaFileName)));
1215                 return NULL;
1216         }
1217
1218         if (unsupauth)
1219         {
1220                 ereport(LOG,
1221                                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1222                                  errmsg("invalid authentication method \"%s\": not supported by this build",
1223                                                 token->string),
1224                                  errcontext("line %d of configuration file \"%s\"",
1225                                                         line_num, HbaFileName)));
1226                 return NULL;
1227         }
1228
1229         /*
1230          * XXX: When using ident on local connections, change it to peer, for
1231          * backwards compatibility.
1232          */
1233         if (parsedline->conntype == ctLocal &&
1234                 parsedline->auth_method == uaIdent)
1235                 parsedline->auth_method = uaPeer;
1236
1237         /* Invalid authentication combinations */
1238         if (parsedline->conntype == ctLocal &&
1239                 parsedline->auth_method == uaKrb5)
1240         {
1241                 ereport(LOG,
1242                                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1243                          errmsg("krb5 authentication is not supported on local sockets"),
1244                                  errcontext("line %d of configuration file \"%s\"",
1245                                                         line_num, HbaFileName)));
1246                 return NULL;
1247         }
1248
1249         if (parsedline->conntype == ctLocal &&
1250                 parsedline->auth_method == uaGSS)
1251         {
1252                 ereport(LOG,
1253                                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1254                    errmsg("gssapi authentication is not supported on local sockets"),
1255                                  errcontext("line %d of configuration file \"%s\"",
1256                                                         line_num, HbaFileName)));
1257                 return NULL;
1258         }
1259
1260         if (parsedline->conntype != ctLocal &&
1261                 parsedline->auth_method == uaPeer)
1262         {
1263                 ereport(LOG,
1264                                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1265                         errmsg("peer authentication is only supported on local sockets"),
1266                                  errcontext("line %d of configuration file \"%s\"",
1267                                                         line_num, HbaFileName)));
1268                 return NULL;
1269         }
1270
1271         /*
1272          * SSPI authentication can never be enabled on ctLocal connections,
1273          * because it's only supported on Windows, where ctLocal isn't supported.
1274          */
1275
1276
1277         if (parsedline->conntype != ctHostSSL &&
1278                 parsedline->auth_method == uaCert)
1279         {
1280                 ereport(LOG,
1281                                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1282                                  errmsg("cert authentication is only supported on hostssl connections"),
1283                                  errcontext("line %d of configuration file \"%s\"",
1284                                                         line_num, HbaFileName)));
1285                 return NULL;
1286         }
1287
1288         /* Parse remaining arguments */
1289         while ((field = lnext(field)) != NULL)
1290         {
1291                 tokens = lfirst(field);
1292                 foreach(tokencell, tokens)
1293                 {
1294                         char       *val;
1295
1296                         token = lfirst(tokencell);
1297
1298                         str = pstrdup(token->string);
1299                         val = strchr(str, '=');
1300                         if (val == NULL)
1301                         {
1302                                 /*
1303                                  * Got something that's not a name=value pair.
1304                                  */
1305                                 ereport(LOG,
1306                                                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1307                                                  errmsg("authentication option not in name=value format: %s", token->string),
1308                                                  errcontext("line %d of configuration file \"%s\"",
1309                                                                         line_num, HbaFileName)));
1310                                 return NULL;
1311                         }
1312
1313                         *val++ = '\0';          /* str now holds "name", val holds "value" */
1314                         if (!parse_hba_auth_opt(str, val, parsedline, line_num))
1315                                 /* parse_hba_auth_opt already logged the error message */
1316                                 return NULL;
1317                         pfree(str);
1318                 }
1319         }
1320
1321         /*
1322          * Check if the selected authentication method has any mandatory arguments
1323          * that are not set.
1324          */
1325         if (parsedline->auth_method == uaLDAP)
1326         {
1327                 MANDATORY_AUTH_ARG(parsedline->ldapserver, "ldapserver", "ldap");
1328
1329                 /*
1330                  * LDAP can operate in two modes: either with a direct bind, using
1331                  * ldapprefix and ldapsuffix, or using a search+bind, using
1332                  * ldapbasedn, ldapbinddn, ldapbindpasswd and ldapsearchattribute.
1333                  * Disallow mixing these parameters.
1334                  */
1335                 if (parsedline->ldapprefix || parsedline->ldapsuffix)
1336                 {
1337                         if (parsedline->ldapbasedn ||
1338                                 parsedline->ldapbinddn ||
1339                                 parsedline->ldapbindpasswd ||
1340                                 parsedline->ldapsearchattribute)
1341                         {
1342                                 ereport(LOG,
1343                                                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1344                                                  errmsg("cannot use ldapbasedn, ldapbinddn, ldapbindpasswd, or ldapsearchattribute together with ldapprefix"),
1345                                                  errcontext("line %d of configuration file \"%s\"",
1346                                                                         line_num, HbaFileName)));
1347                                 return NULL;
1348                         }
1349                 }
1350                 else if (!parsedline->ldapbasedn)
1351                 {
1352                         ereport(LOG,
1353                                         (errcode(ERRCODE_CONFIG_FILE_ERROR),
1354                                          errmsg("authentication method \"ldap\" requires argument \"ldapbasedn\", \"ldapprefix\", or \"ldapsuffix\" to be set"),
1355                                          errcontext("line %d of configuration file \"%s\"",
1356                                                                 line_num, HbaFileName)));
1357                         return NULL;
1358                 }
1359         }
1360
1361         if (parsedline->auth_method == uaRADIUS)
1362         {
1363                 MANDATORY_AUTH_ARG(parsedline->radiusserver, "radiusserver", "radius");
1364                 MANDATORY_AUTH_ARG(parsedline->radiussecret, "radiussecret", "radius");
1365         }
1366
1367         /*
1368          * Enforce any parameters implied by other settings.
1369          */
1370         if (parsedline->auth_method == uaCert)
1371         {
1372                 parsedline->clientcert = true;
1373         }
1374
1375         return parsedline;
1376 }
1377
1378 /*
1379  * Parse one name-value pair as an authentication option into the given
1380  * HbaLine.  Return true if we successfully parse the option, false if we
1381  * encounter an error.
1382  */
1383 static bool
1384 parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline, int line_num)
1385 {
1386         if (strcmp(name, "map") == 0)
1387         {
1388                 if (hbaline->auth_method != uaIdent &&
1389                         hbaline->auth_method != uaPeer &&
1390                         hbaline->auth_method != uaKrb5 &&
1391                         hbaline->auth_method != uaGSS &&
1392                         hbaline->auth_method != uaSSPI &&
1393                         hbaline->auth_method != uaCert)
1394                         INVALID_AUTH_OPTION("map", gettext_noop("ident, peer, krb5, gssapi, sspi, and cert"));
1395                 hbaline->usermap = pstrdup(val);
1396         }
1397         else if (strcmp(name, "clientcert") == 0)
1398         {
1399                 /*
1400                  * Since we require ctHostSSL, this really can never happen on
1401                  * non-SSL-enabled builds, so don't bother checking for USE_SSL.
1402                  */
1403                 if (hbaline->conntype != ctHostSSL)
1404                 {
1405                         ereport(LOG,
1406                                         (errcode(ERRCODE_CONFIG_FILE_ERROR),
1407                         errmsg("clientcert can only be configured for \"hostssl\" rows"),
1408                                          errcontext("line %d of configuration file \"%s\"",
1409                                                                 line_num, HbaFileName)));
1410                         return false;
1411                 }
1412                 if (strcmp(val, "1") == 0)
1413                 {
1414                         if (!secure_loaded_verify_locations())
1415                         {
1416                                 ereport(LOG,
1417                                                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1418                                                  errmsg("client certificates can only be checked if a root certificate store is available"),
1419                                                  errhint("Make sure the configuration parameter \"ssl_ca_file\" is set."),
1420                                                  errcontext("line %d of configuration file \"%s\"",
1421                                                                         line_num, HbaFileName)));
1422                                 return false;
1423                         }
1424                         hbaline->clientcert = true;
1425                 }
1426                 else
1427                 {
1428                         if (hbaline->auth_method == uaCert)
1429                         {
1430                                 ereport(LOG,
1431                                                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1432                                                  errmsg("clientcert can not be set to 0 when using \"cert\" authentication"),
1433                                                  errcontext("line %d of configuration file \"%s\"",
1434                                                                         line_num, HbaFileName)));
1435                                 return false;
1436                         }
1437                         hbaline->clientcert = false;
1438                 }
1439         }
1440         else if (strcmp(name, "pamservice") == 0)
1441         {
1442                 REQUIRE_AUTH_OPTION(uaPAM, "pamservice", "pam");
1443                 hbaline->pamservice = pstrdup(val);
1444         }
1445         else if (strcmp(name, "ldaptls") == 0)
1446         {
1447                 REQUIRE_AUTH_OPTION(uaLDAP, "ldaptls", "ldap");
1448                 if (strcmp(val, "1") == 0)
1449                         hbaline->ldaptls = true;
1450                 else
1451                         hbaline->ldaptls = false;
1452         }
1453         else if (strcmp(name, "ldapserver") == 0)
1454         {
1455                 REQUIRE_AUTH_OPTION(uaLDAP, "ldapserver", "ldap");
1456                 hbaline->ldapserver = pstrdup(val);
1457         }
1458         else if (strcmp(name, "ldapport") == 0)
1459         {
1460                 REQUIRE_AUTH_OPTION(uaLDAP, "ldapport", "ldap");
1461                 hbaline->ldapport = atoi(val);
1462                 if (hbaline->ldapport == 0)
1463                 {
1464                         ereport(LOG,
1465                                         (errcode(ERRCODE_CONFIG_FILE_ERROR),
1466                                          errmsg("invalid LDAP port number: \"%s\"", val),
1467                                          errcontext("line %d of configuration file \"%s\"",
1468                                                                 line_num, HbaFileName)));
1469                         return false;
1470                 }
1471         }
1472         else if (strcmp(name, "ldapbinddn") == 0)
1473         {
1474                 REQUIRE_AUTH_OPTION(uaLDAP, "ldapbinddn", "ldap");
1475                 hbaline->ldapbinddn = pstrdup(val);
1476         }
1477         else if (strcmp(name, "ldapbindpasswd") == 0)
1478         {
1479                 REQUIRE_AUTH_OPTION(uaLDAP, "ldapbindpasswd", "ldap");
1480                 hbaline->ldapbindpasswd = pstrdup(val);
1481         }
1482         else if (strcmp(name, "ldapsearchattribute") == 0)
1483         {
1484                 REQUIRE_AUTH_OPTION(uaLDAP, "ldapsearchattribute", "ldap");
1485                 hbaline->ldapsearchattribute = pstrdup(val);
1486         }
1487         else if (strcmp(name, "ldapbasedn") == 0)
1488         {
1489                 REQUIRE_AUTH_OPTION(uaLDAP, "ldapbasedn", "ldap");
1490                 hbaline->ldapbasedn = pstrdup(val);
1491         }
1492         else if (strcmp(name, "ldapprefix") == 0)
1493         {
1494                 REQUIRE_AUTH_OPTION(uaLDAP, "ldapprefix", "ldap");
1495                 hbaline->ldapprefix = pstrdup(val);
1496         }
1497         else if (strcmp(name, "ldapsuffix") == 0)
1498         {
1499                 REQUIRE_AUTH_OPTION(uaLDAP, "ldapsuffix", "ldap");
1500                 hbaline->ldapsuffix = pstrdup(val);
1501         }
1502         else if (strcmp(name, "krb_server_hostname") == 0)
1503         {
1504                 REQUIRE_AUTH_OPTION(uaKrb5, "krb_server_hostname", "krb5");
1505                 hbaline->krb_server_hostname = pstrdup(val);
1506         }
1507         else if (strcmp(name, "krb_realm") == 0)
1508         {
1509                 if (hbaline->auth_method != uaKrb5 &&
1510                         hbaline->auth_method != uaGSS &&
1511                         hbaline->auth_method != uaSSPI)
1512                         INVALID_AUTH_OPTION("krb_realm", gettext_noop("krb5, gssapi, and sspi"));
1513                 hbaline->krb_realm = pstrdup(val);
1514         }
1515         else if (strcmp(name, "include_realm") == 0)
1516         {
1517                 if (hbaline->auth_method != uaKrb5 &&
1518                         hbaline->auth_method != uaGSS &&
1519                         hbaline->auth_method != uaSSPI)
1520                         INVALID_AUTH_OPTION("include_realm", gettext_noop("krb5, gssapi, and sspi"));
1521                 if (strcmp(val, "1") == 0)
1522                         hbaline->include_realm = true;
1523                 else
1524                         hbaline->include_realm = false;
1525         }
1526         else if (strcmp(name, "radiusserver") == 0)
1527         {
1528                 struct addrinfo *gai_result;
1529                 struct addrinfo hints;
1530                 int                     ret;
1531
1532                 REQUIRE_AUTH_OPTION(uaRADIUS, "radiusserver", "radius");
1533
1534                 MemSet(&hints, 0, sizeof(hints));
1535                 hints.ai_socktype = SOCK_DGRAM;
1536                 hints.ai_family = AF_UNSPEC;
1537
1538                 ret = pg_getaddrinfo_all(val, NULL, &hints, &gai_result);
1539                 if (ret || !gai_result)
1540                 {
1541                         ereport(LOG,
1542                                         (errcode(ERRCODE_CONFIG_FILE_ERROR),
1543                                          errmsg("could not translate RADIUS server name \"%s\" to address: %s",
1544                                                         val, gai_strerror(ret)),
1545                                          errcontext("line %d of configuration file \"%s\"",
1546                                                                 line_num, HbaFileName)));
1547                         if (gai_result)
1548                                 pg_freeaddrinfo_all(hints.ai_family, gai_result);
1549                         return false;
1550                 }
1551                 pg_freeaddrinfo_all(hints.ai_family, gai_result);
1552                 hbaline->radiusserver = pstrdup(val);
1553         }
1554         else if (strcmp(name, "radiusport") == 0)
1555         {
1556                 REQUIRE_AUTH_OPTION(uaRADIUS, "radiusport", "radius");
1557                 hbaline->radiusport = atoi(val);
1558                 if (hbaline->radiusport == 0)
1559                 {
1560                         ereport(LOG,
1561                                         (errcode(ERRCODE_CONFIG_FILE_ERROR),
1562                                          errmsg("invalid RADIUS port number: \"%s\"", val),
1563                                          errcontext("line %d of configuration file \"%s\"",
1564                                                                 line_num, HbaFileName)));
1565                         return false;
1566                 }
1567         }
1568         else if (strcmp(name, "radiussecret") == 0)
1569         {
1570                 REQUIRE_AUTH_OPTION(uaRADIUS, "radiussecret", "radius");
1571                 hbaline->radiussecret = pstrdup(val);
1572         }
1573         else if (strcmp(name, "radiusidentifier") == 0)
1574         {
1575                 REQUIRE_AUTH_OPTION(uaRADIUS, "radiusidentifier", "radius");
1576                 hbaline->radiusidentifier = pstrdup(val);
1577         }
1578         else
1579         {
1580                 ereport(LOG,
1581                                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1582                                  errmsg("unrecognized authentication option name: \"%s\"",
1583                                                 name),
1584                                  errcontext("line %d of configuration file \"%s\"",
1585                                                         line_num, HbaFileName)));
1586                 return false;
1587         }
1588         return true;
1589 }
1590
1591 /*
1592  *      Scan the pre-parsed hba file, looking for a match to the port's connection
1593  *      request.
1594  */
1595 static void
1596 check_hba(hbaPort *port)
1597 {
1598         Oid                     roleid;
1599         ListCell   *line;
1600         HbaLine    *hba;
1601
1602         /* Get the target role's OID.  Note we do not error out for bad role. */
1603         roleid = get_role_oid(port->user_name, true);
1604
1605         foreach(line, parsed_hba_lines)
1606         {
1607                 hba = (HbaLine *) lfirst(line);
1608
1609                 /* Check connection type */
1610                 if (hba->conntype == ctLocal)
1611                 {
1612                         if (!IS_AF_UNIX(port->raddr.addr.ss_family))
1613                                 continue;
1614                 }
1615                 else
1616                 {
1617                         if (IS_AF_UNIX(port->raddr.addr.ss_family))
1618                                 continue;
1619
1620                         /* Check SSL state */
1621 #ifdef USE_SSL
1622                         if (port->ssl)
1623                         {
1624                                 /* Connection is SSL, match both "host" and "hostssl" */
1625                                 if (hba->conntype == ctHostNoSSL)
1626                                         continue;
1627                         }
1628                         else
1629                         {
1630                                 /* Connection is not SSL, match both "host" and "hostnossl" */
1631                                 if (hba->conntype == ctHostSSL)
1632                                         continue;
1633                         }
1634 #else
1635                         /* No SSL support, so reject "hostssl" lines */
1636                         if (hba->conntype == ctHostSSL)
1637                                 continue;
1638 #endif
1639
1640                         /* Check IP address */
1641                         switch (hba->ip_cmp_method)
1642                         {
1643                                 case ipCmpMask:
1644                                         if (hba->hostname)
1645                                         {
1646                                                 if (!check_hostname(port,
1647                                                                                         hba->hostname))
1648                                                         continue;
1649                                         }
1650                                         else
1651                                         {
1652                                                 if (!check_ip(&port->raddr,
1653                                                                           (struct sockaddr *) & hba->addr,
1654                                                                           (struct sockaddr *) & hba->mask))
1655                                                         continue;
1656                                         }
1657                                         break;
1658                                 case ipCmpAll:
1659                                         break;
1660                                 case ipCmpSameHost:
1661                                 case ipCmpSameNet:
1662                                         if (!check_same_host_or_net(&port->raddr,
1663                                                                                                 hba->ip_cmp_method))
1664                                                 continue;
1665                                         break;
1666                                 default:
1667                                         /* shouldn't get here, but deem it no-match if so */
1668                                         continue;
1669                         }
1670                 }                                               /* != ctLocal */
1671
1672                 /* Check database and role */
1673                 if (!check_db(port->database_name, port->user_name, roleid,
1674                                           hba->databases))
1675                         continue;
1676
1677                 if (!check_role(port->user_name, roleid, hba->roles))
1678                         continue;
1679
1680                 /* Found a record that matched! */
1681                 port->hba = hba;
1682                 return;
1683         }
1684
1685         /* If no matching entry was found, then implicitly reject. */
1686         hba = palloc0(sizeof(HbaLine));
1687         hba->auth_method = uaImplicitReject;
1688         port->hba = hba;
1689 }
1690
1691 /*
1692  * Read the config file and create a List of HbaLine records for the contents.
1693  *
1694  * The configuration is read into a temporary list, and if any parse error
1695  * occurs the old list is kept in place and false is returned.  Only if the
1696  * whole file parses OK is the list replaced, and the function returns true.
1697  *
1698  * On a false result, caller will take care of reporting a FATAL error in case
1699  * this is the initial startup.  If it happens on reload, we just keep running
1700  * with the old data.
1701  */
1702 bool
1703 load_hba(void)
1704 {
1705         FILE       *file;
1706         List       *hba_lines = NIL;
1707         List       *hba_line_nums = NIL;
1708         ListCell   *line,
1709                            *line_num;
1710         List       *new_parsed_lines = NIL;
1711         bool            ok = true;
1712         MemoryContext linecxt;
1713         MemoryContext oldcxt;
1714         MemoryContext hbacxt;
1715
1716         file = AllocateFile(HbaFileName, "r");
1717         if (file == NULL)
1718         {
1719                 ereport(LOG,
1720                                 (errcode_for_file_access(),
1721                                  errmsg("could not open configuration file \"%s\": %m",
1722                                                 HbaFileName)));
1723                 return false;
1724         }
1725
1726         linecxt = tokenize_file(HbaFileName, file, &hba_lines, &hba_line_nums);
1727         FreeFile(file);
1728
1729         /* Now parse all the lines */
1730         hbacxt = AllocSetContextCreate(TopMemoryContext,
1731                                                                    "hba parser context",
1732                                                                    ALLOCSET_DEFAULT_MINSIZE,
1733                                                                    ALLOCSET_DEFAULT_MINSIZE,
1734                                                                    ALLOCSET_DEFAULT_MAXSIZE);
1735         oldcxt = MemoryContextSwitchTo(hbacxt);
1736         forboth(line, hba_lines, line_num, hba_line_nums)
1737         {
1738                 HbaLine    *newline;
1739
1740                 if ((newline = parse_hba_line(lfirst(line), lfirst_int(line_num))) == NULL)
1741                 {
1742                         /*
1743                          * Parse error in the file, so indicate there's a problem.  NB: a
1744                          * problem in a line will free the memory for all previous lines
1745                          * as well!
1746                          */
1747                         MemoryContextReset(hbacxt);
1748                         new_parsed_lines = NIL;
1749                         ok = false;
1750
1751                         /*
1752                          * Keep parsing the rest of the file so we can report errors on
1753                          * more than the first row. Error has already been reported in the
1754                          * parsing function, so no need to log it here.
1755                          */
1756                         continue;
1757                 }
1758
1759                 new_parsed_lines = lappend(new_parsed_lines, newline);
1760         }
1761
1762         /*
1763          * A valid HBA file must have at least one entry; else there's no way to
1764          * connect to the postmaster.  But only complain about this if we didn't
1765          * already have parsing errors.
1766          */
1767         if (ok && new_parsed_lines == NIL)
1768         {
1769                 ereport(LOG,
1770                                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1771                                  errmsg("configuration file \"%s\" contains no entries",
1772                                                 HbaFileName)));
1773                 ok = false;
1774         }
1775
1776         /* Free tokenizer memory */
1777         MemoryContextDelete(linecxt);
1778         MemoryContextSwitchTo(oldcxt);
1779
1780         if (!ok)
1781         {
1782                 /* File contained one or more errors, so bail out */
1783                 MemoryContextDelete(hbacxt);
1784                 return false;
1785         }
1786
1787         /* Loaded new file successfully, replace the one we use */
1788         if (parsed_hba_context != NULL)
1789                 MemoryContextDelete(parsed_hba_context);
1790         parsed_hba_context = hbacxt;
1791         parsed_hba_lines = new_parsed_lines;
1792
1793         return true;
1794 }
1795
1796 /*
1797  *      Process one line from the ident config file.
1798  *
1799  *      Take the line and compare it to the needed map, pg_role and ident_user.
1800  *      *found_p and *error_p are set according to our results.
1801  */
1802 static void
1803 parse_ident_usermap(List *line, int line_number, const char *usermap_name,
1804                                         const char *pg_role, const char *ident_user,
1805                                         bool case_insensitive, bool *found_p, bool *error_p)
1806 {
1807         ListCell   *field;
1808         List       *tokens;
1809         HbaToken   *token;
1810         char       *file_map;
1811         char       *file_pgrole;
1812         char       *file_ident_user;
1813
1814         *found_p = false;
1815         *error_p = false;
1816
1817         Assert(line != NIL);
1818         field = list_head(line);
1819
1820         /* Get the map token (must exist) */
1821         tokens = lfirst(field);
1822         IDENT_MULTI_VALUE(tokens);
1823         token = linitial(tokens);
1824         file_map = token->string;
1825
1826         /* Get the ident user token */
1827         field = lnext(field);
1828         IDENT_FIELD_ABSENT(field);
1829         tokens = lfirst(field);
1830         IDENT_MULTI_VALUE(tokens);
1831         token = linitial(tokens);
1832         file_ident_user = token->string;
1833
1834         /* Get the PG rolename token */
1835         field = lnext(field);
1836         IDENT_FIELD_ABSENT(field);
1837         tokens = lfirst(field);
1838         IDENT_MULTI_VALUE(tokens);
1839         token = linitial(tokens);
1840         file_pgrole = token->string;
1841
1842         if (strcmp(file_map, usermap_name) != 0)
1843                 /* Line does not match the map name we're looking for, so just abort */
1844                 return;
1845
1846         /* Match? */
1847         if (file_ident_user[0] == '/')
1848         {
1849                 /*
1850                  * When system username starts with a slash, treat it as a regular
1851                  * expression. In this case, we process the system username as a
1852                  * regular expression that returns exactly one match. This is replaced
1853                  * for \1 in the database username string, if present.
1854                  */
1855                 int                     r;
1856                 regex_t         re;
1857                 regmatch_t      matches[2];
1858                 pg_wchar   *wstr;
1859                 int                     wlen;
1860                 char       *ofs;
1861                 char       *regexp_pgrole;
1862
1863                 wstr = palloc((strlen(file_ident_user + 1) + 1) * sizeof(pg_wchar));
1864                 wlen = pg_mb2wchar_with_len(file_ident_user + 1, wstr, strlen(file_ident_user + 1));
1865
1866                 /*
1867                  * XXX: Major room for optimization: regexps could be compiled when
1868                  * the file is loaded and then re-used in every connection.
1869                  */
1870                 r = pg_regcomp(&re, wstr, wlen, REG_ADVANCED, C_COLLATION_OID);
1871                 if (r)
1872                 {
1873                         char            errstr[100];
1874
1875                         pg_regerror(r, &re, errstr, sizeof(errstr));
1876                         ereport(LOG,
1877                                         (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
1878                                          errmsg("invalid regular expression \"%s\": %s",
1879                                                         file_ident_user + 1, errstr)));
1880
1881                         pfree(wstr);
1882                         *error_p = true;
1883                         return;
1884                 }
1885                 pfree(wstr);
1886
1887                 wstr = palloc((strlen(ident_user) + 1) * sizeof(pg_wchar));
1888                 wlen = pg_mb2wchar_with_len(ident_user, wstr, strlen(ident_user));
1889
1890                 r = pg_regexec(&re, wstr, wlen, 0, NULL, 2, matches, 0);
1891                 if (r)
1892                 {
1893                         char            errstr[100];
1894
1895                         if (r != REG_NOMATCH)
1896                         {
1897                                 /* REG_NOMATCH is not an error, everything else is */
1898                                 pg_regerror(r, &re, errstr, sizeof(errstr));
1899                                 ereport(LOG,
1900                                                 (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
1901                                          errmsg("regular expression match for \"%s\" failed: %s",
1902                                                         file_ident_user + 1, errstr)));
1903                                 *error_p = true;
1904                         }
1905
1906                         pfree(wstr);
1907                         pg_regfree(&re);
1908                         return;
1909                 }
1910                 pfree(wstr);
1911
1912                 if ((ofs = strstr(file_pgrole, "\\1")) != NULL)
1913                 {
1914                         /* substitution of the first argument requested */
1915                         if (matches[1].rm_so < 0)
1916                         {
1917                                 ereport(LOG,
1918                                                 (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
1919                                                  errmsg("regular expression \"%s\" has no subexpressions as requested by backreference in \"%s\"",
1920                                                                 file_ident_user + 1, file_pgrole)));
1921                                 pg_regfree(&re);
1922                                 *error_p = true;
1923                                 return;
1924                         }
1925
1926                         /*
1927                          * length: original length minus length of \1 plus length of match
1928                          * plus null terminator
1929                          */
1930                         regexp_pgrole = palloc0(strlen(file_pgrole) - 2 + (matches[1].rm_eo - matches[1].rm_so) + 1);
1931                         strncpy(regexp_pgrole, file_pgrole, (ofs - file_pgrole));
1932                         memcpy(regexp_pgrole + strlen(regexp_pgrole),
1933                                    ident_user + matches[1].rm_so,
1934                                    matches[1].rm_eo - matches[1].rm_so);
1935                         strcat(regexp_pgrole, ofs + 2);
1936                 }
1937                 else
1938                 {
1939                         /* no substitution, so copy the match */
1940                         regexp_pgrole = pstrdup(file_pgrole);
1941                 }
1942
1943                 pg_regfree(&re);
1944
1945                 /*
1946                  * now check if the username actually matched what the user is trying
1947                  * to connect as
1948                  */
1949                 if (case_insensitive)
1950                 {
1951                         if (pg_strcasecmp(regexp_pgrole, pg_role) == 0)
1952                                 *found_p = true;
1953                 }
1954                 else
1955                 {
1956                         if (strcmp(regexp_pgrole, pg_role) == 0)
1957                                 *found_p = true;
1958                 }
1959                 pfree(regexp_pgrole);
1960
1961                 return;
1962         }
1963         else
1964         {
1965                 /* Not regular expression, so make complete match */
1966                 if (case_insensitive)
1967                 {
1968                         if (pg_strcasecmp(file_pgrole, pg_role) == 0 &&
1969                                 pg_strcasecmp(file_ident_user, ident_user) == 0)
1970                                 *found_p = true;
1971                 }
1972                 else
1973                 {
1974                         if (strcmp(file_pgrole, pg_role) == 0 &&
1975                                 strcmp(file_ident_user, ident_user) == 0)
1976                                 *found_p = true;
1977                 }
1978         }
1979         return;
1980 }
1981
1982
1983 /*
1984  *      Scan the (pre-parsed) ident usermap file line by line, looking for a match
1985  *
1986  *      See if the user with ident username "auth_user" is allowed to act
1987  *      as Postgres user "pg_role" according to usermap "usermap_name".
1988  *
1989  *      Special case: Usermap NULL, equivalent to what was previously called
1990  *      "sameuser" or "samerole", means don't look in the usermap file.
1991  *      That's an implied map wherein "pg_role" must be identical to
1992  *      "auth_user" in order to be authorized.
1993  *
1994  *      Iff authorized, return STATUS_OK, otherwise return STATUS_ERROR.
1995  */
1996 int
1997 check_usermap(const char *usermap_name,
1998                           const char *pg_role,
1999                           const char *auth_user,
2000                           bool case_insensitive)
2001 {
2002         bool            found_entry = false,
2003                                 error = false;
2004
2005         if (usermap_name == NULL || usermap_name[0] == '\0')
2006         {
2007                 if (case_insensitive)
2008                 {
2009                         if (pg_strcasecmp(pg_role, auth_user) == 0)
2010                                 return STATUS_OK;
2011                 }
2012                 else
2013                 {
2014                         if (strcmp(pg_role, auth_user) == 0)
2015                                 return STATUS_OK;
2016                 }
2017                 ereport(LOG,
2018                                 (errmsg("provided user name (%s) and authenticated user name (%s) do not match",
2019                                                 pg_role, auth_user)));
2020                 return STATUS_ERROR;
2021         }
2022         else
2023         {
2024                 ListCell   *line_cell,
2025                                    *num_cell;
2026
2027                 forboth(line_cell, ident_lines, num_cell, ident_line_nums)
2028                 {
2029                         parse_ident_usermap(lfirst(line_cell), lfirst_int(num_cell),
2030                                                   usermap_name, pg_role, auth_user, case_insensitive,
2031                                                                 &found_entry, &error);
2032                         if (found_entry || error)
2033                                 break;
2034                 }
2035         }
2036         if (!found_entry && !error)
2037         {
2038                 ereport(LOG,
2039                                 (errmsg("no match in usermap \"%s\" for user \"%s\" authenticated as \"%s\"",
2040                                                 usermap_name, pg_role, auth_user)));
2041         }
2042         return found_entry ? STATUS_OK : STATUS_ERROR;
2043 }
2044
2045
2046 /*
2047  * Read the ident config file and populate ident_lines and ident_line_nums.
2048  *
2049  * Like parsed_hba_lines, ident_lines is a triple-nested List of lines, fields
2050  * and tokens.
2051  */
2052 void
2053 load_ident(void)
2054 {
2055         FILE       *file;
2056
2057         if (ident_context != NULL)
2058         {
2059                 MemoryContextDelete(ident_context);
2060                 ident_context = NULL;
2061         }
2062
2063         file = AllocateFile(IdentFileName, "r");
2064         if (file == NULL)
2065         {
2066                 /* not fatal ... we just won't do any special ident maps */
2067                 ereport(LOG,
2068                                 (errcode_for_file_access(),
2069                                  errmsg("could not open usermap file \"%s\": %m",
2070                                                 IdentFileName)));
2071         }
2072         else
2073         {
2074                 ident_context = tokenize_file(IdentFileName, file, &ident_lines,
2075                                                                           &ident_line_nums);
2076                 FreeFile(file);
2077         }
2078 }
2079
2080
2081
2082 /*
2083  *      Determine what authentication method should be used when accessing database
2084  *      "database" from frontend "raddr", user "user".  Return the method and
2085  *      an optional argument (stored in fields of *port), and STATUS_OK.
2086  *
2087  *      If the file does not contain any entry matching the request, we return
2088  *      method = uaImplicitReject.
2089  */
2090 void
2091 hba_getauthmethod(hbaPort *port)
2092 {
2093         check_hba(port);
2094 }