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