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