]> granicus.if.org Git - postgresql/blob - src/backend/libpq/hba.c
Issue a proper error message when MD5 is attempted when
[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-2008, 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.175 2008/11/20 20:45:30 momjian 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 "storage/fd.h"
31 #include "utils/flatfiles.h"
32 #include "utils/guc.h"
33
34
35
36 #define atooid(x)  ((Oid) strtoul((x), NULL, 10))
37 #define atoxid(x)  ((TransactionId) strtoul((x), NULL, 10))
38
39 /* This is used to separate values in multi-valued column strings */
40 #define MULTI_VALUE_SEP "\001"
41
42 #define MAX_TOKEN       256
43
44 /* pre-parsed content of HBA config file */
45 static List *parsed_hba_lines = NIL;
46
47 /*
48  * These variables hold the pre-parsed contents of the ident
49  * configuration files, as well as the flat auth file.
50  * Each is a list of sublists, one sublist for
51  * each (non-empty, non-comment) line of the file.      Each sublist's
52  * first item is an integer line number (so we can give somewhat-useful
53  * location info in error messages).  Remaining items are palloc'd strings,
54  * one string per token on the line.  Note there will always be at least
55  * one token, since blank lines are not entered in the data structure.
56  */
57
58 /* pre-parsed content of ident usermap file and corresponding line #s */
59 static List *ident_lines = NIL;
60 static List *ident_line_nums = NIL;
61
62 /* pre-parsed content of flat auth file and corresponding line #s */
63 static List *role_lines = NIL;
64 static List *role_line_nums = NIL;
65
66 /* sorted entries so we can do binary search lookups */
67 static List **role_sorted = NULL;               /* sorted role list, for bsearch() */
68 static int      role_length;
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  *
94  * If successful: store null-terminated token at *buf and return TRUE.
95  * If no more tokens on line: set *buf = '\0' and return FALSE.
96  *
97  * Leave file positioned at the character immediately after the token or EOF,
98  * whichever comes first. If no more tokens on line, position the file to the
99  * beginning of the next line or EOF, whichever comes first.
100  *
101  * Handle comments. Treat unquoted keywords that might be role names or
102  * database names specially, by appending a newline to them.  Also, when
103  * a token is terminated by a comma, the comma is included in the returned
104  * token.
105  */
106 static bool
107 next_token(FILE *fp, char *buf, int bufsz)
108 {
109         int                     c;
110         char       *start_buf = buf;
111         char       *end_buf = buf + (bufsz - 2);
112         bool            in_quote = false;
113         bool            was_quote = false;
114         bool            saw_quote = false;
115
116         Assert(end_buf > start_buf);
117
118         /* Move over initial whitespace and commas */
119         while ((c = getc(fp)) != EOF && (pg_isblank(c) || c == ','))
120                 ;
121
122         if (c == EOF || c == '\n')
123         {
124                 *buf = '\0';
125                 return false;
126         }
127
128         /*
129          * Build a token in buf of next characters up to EOF, EOL, unquoted comma,
130          * or unquoted whitespace.
131          */
132         while (c != EOF && c != '\n' &&
133                    (!pg_isblank(c) || in_quote))
134         {
135                 /* skip comments to EOL */
136                 if (c == '#' && !in_quote)
137                 {
138                         while ((c = getc(fp)) != EOF && c != '\n')
139                                 ;
140                         /* If only comment, consume EOL too; return EOL */
141                         if (c != EOF && buf == start_buf)
142                                 c = getc(fp);
143                         break;
144                 }
145
146                 if (buf >= end_buf)
147                 {
148                         *buf = '\0';
149                         ereport(LOG,
150                                         (errcode(ERRCODE_CONFIG_FILE_ERROR),
151                            errmsg("authentication file token too long, skipping: \"%s\"",
152                                           start_buf)));
153                         /* Discard remainder of line */
154                         while ((c = getc(fp)) != EOF && c != '\n')
155                                 ;
156                         break;
157                 }
158
159                 if (c != '"' || was_quote)
160                         *buf++ = c;
161
162                 /* We pass back the comma so the caller knows there is more */
163                 if (c == ',' && !in_quote)
164                         break;
165
166                 /* Literal double-quote is two double-quotes */
167                 if (in_quote && c == '"')
168                         was_quote = !was_quote;
169                 else
170                         was_quote = false;
171
172                 if (c == '"')
173                 {
174                         in_quote = !in_quote;
175                         saw_quote = true;
176                 }
177
178                 c = getc(fp);
179         }
180
181         /*
182          * Put back the char right after the token (critical in case it is EOL,
183          * since we need to detect end-of-line at next call).
184          */
185         if (c != EOF)
186                 ungetc(c, fp);
187
188         *buf = '\0';
189
190         if (!saw_quote &&
191                 (strcmp(start_buf, "all") == 0 ||
192                  strcmp(start_buf, "sameuser") == 0 ||
193                  strcmp(start_buf, "samegroup") == 0 ||
194                  strcmp(start_buf, "samerole") == 0))
195         {
196                 /* append newline to a magical keyword */
197                 *buf++ = '\n';
198                 *buf = '\0';
199         }
200
201         return (saw_quote || buf > start_buf);
202 }
203
204 /*
205  *       Tokenize file and handle file inclusion and comma lists. We have
206  *       to  break      apart  the      commas  to      expand  any  file names then
207  *       reconstruct with commas.
208  *
209  * The result is a palloc'd string, or NULL if we have reached EOL.
210  */
211 static char *
212 next_token_expand(const char *filename, FILE *file)
213 {
214         char            buf[MAX_TOKEN];
215         char       *comma_str = pstrdup("");
216         bool            got_something = false;
217         bool            trailing_comma;
218         char       *incbuf;
219         int                     needed;
220
221         do
222         {
223                 if (!next_token(file, buf, sizeof(buf)))
224                         break;
225
226                 got_something = true;
227
228                 if (strlen(buf) > 0 && buf[strlen(buf) - 1] == ',')
229                 {
230                         trailing_comma = true;
231                         buf[strlen(buf) - 1] = '\0';
232                 }
233                 else
234                         trailing_comma = false;
235
236                 /* Is this referencing a file? */
237                 if (buf[0] == '@')
238                         incbuf = tokenize_inc_file(filename, buf + 1);
239                 else
240                         incbuf = pstrdup(buf);
241
242                 needed = strlen(comma_str) + strlen(incbuf) + 1;
243                 if (trailing_comma)
244                         needed++;
245                 comma_str = repalloc(comma_str, needed);
246                 strcat(comma_str, incbuf);
247                 if (trailing_comma)
248                         strcat(comma_str, MULTI_VALUE_SEP);
249                 pfree(incbuf);
250         } while (trailing_comma);
251
252         if (!got_something)
253         {
254                 pfree(comma_str);
255                 return NULL;
256         }
257
258         return comma_str;
259 }
260
261
262 /*
263  * Free memory used by lines/tokens (i.e., structure built by tokenize_file)
264  */
265 static void
266 free_lines(List **lines, List **line_nums)
267 {
268         /*
269          * Either both must be non-NULL, or both must be NULL
270          */
271         Assert((*lines != NIL && *line_nums != NIL) ||
272                    (*lines == NIL && *line_nums == NIL));
273
274         if (*lines)
275         {
276                 /*
277                  * "lines" is a list of lists; each of those sublists consists of
278                  * palloc'ed tokens, so we want to free each pointed-to token in a
279                  * sublist, followed by the sublist itself, and finally the whole
280                  * list.
281                  */
282                 ListCell   *line;
283
284                 foreach(line, *lines)
285                 {
286                         List       *ln = lfirst(line);
287                         ListCell   *token;
288
289                         foreach(token, ln)
290                                 pfree(lfirst(token));
291                         /* free the sublist structure itself */
292                         list_free(ln);
293                 }
294                 /* free the list structure itself */
295                 list_free(*lines);
296                 /* clear the static variable */
297                 *lines = NIL;
298         }
299
300         if (*line_nums)
301         {
302                 list_free(*line_nums);
303                 *line_nums = NIL;
304         }
305 }
306
307
308 static char *
309 tokenize_inc_file(const char *outer_filename,
310                                   const char *inc_filename)
311 {
312         char       *inc_fullname;
313         FILE       *inc_file;
314         List       *inc_lines;
315         List       *inc_line_nums;
316         ListCell   *line;
317         char       *comma_str;
318
319         if (is_absolute_path(inc_filename))
320         {
321                 /* absolute path is taken as-is */
322                 inc_fullname = pstrdup(inc_filename);
323         }
324         else
325         {
326                 /* relative path is relative to dir of calling file */
327                 inc_fullname = (char *) palloc(strlen(outer_filename) + 1 +
328                                                                            strlen(inc_filename) + 1);
329                 strcpy(inc_fullname, outer_filename);
330                 get_parent_directory(inc_fullname);
331                 join_path_components(inc_fullname, inc_fullname, inc_filename);
332                 canonicalize_path(inc_fullname);
333         }
334
335         inc_file = AllocateFile(inc_fullname, "r");
336         if (inc_file == NULL)
337         {
338                 ereport(LOG,
339                                 (errcode_for_file_access(),
340                                  errmsg("could not open secondary authentication file \"@%s\" as \"%s\": %m",
341                                                 inc_filename, inc_fullname)));
342                 pfree(inc_fullname);
343
344                 /* return single space, it matches nothing */
345                 return pstrdup(" ");
346         }
347
348         /* There is possible recursion here if the file contains @ */
349         tokenize_file(inc_fullname, inc_file, &inc_lines, &inc_line_nums);
350
351         FreeFile(inc_file);
352         pfree(inc_fullname);
353
354         /* Create comma-separated string from List */
355         comma_str = pstrdup("");
356         foreach(line, inc_lines)
357         {
358                 List       *token_list = (List *) lfirst(line);
359                 ListCell   *token;
360
361                 foreach(token, token_list)
362                 {
363                         int                     oldlen = strlen(comma_str);
364                         int                     needed;
365
366                         needed = oldlen + strlen(lfirst(token)) + 1;
367                         if (oldlen > 0)
368                                 needed++;
369                         comma_str = repalloc(comma_str, needed);
370                         if (oldlen > 0)
371                                 strcat(comma_str, MULTI_VALUE_SEP);
372                         strcat(comma_str, lfirst(token));
373                 }
374         }
375
376         free_lines(&inc_lines, &inc_line_nums);
377
378         /* if file is empty, return single space rather than empty string */
379         if (strlen(comma_str) == 0)
380         {
381                 pfree(comma_str);
382                 return pstrdup(" ");
383         }
384
385         return comma_str;
386 }
387
388
389 /*
390  * Tokenize the given file, storing the resulting data into two lists:
391  * a list of sublists, each sublist containing the tokens in a line of
392  * the file, and a list of line numbers.
393  *
394  * filename must be the absolute path to the target file.
395  */
396 static void
397 tokenize_file(const char *filename, FILE *file,
398                           List **lines, List **line_nums)
399 {
400         List       *current_line = NIL;
401         int                     line_number = 1;
402         char       *buf;
403
404         *lines = *line_nums = NIL;
405
406         while (!feof(file))
407         {
408                 buf = next_token_expand(filename, file);
409
410                 /* add token to list, unless we are at EOL or comment start */
411                 if (buf)
412                 {
413                         if (current_line == NIL)
414                         {
415                                 /* make a new line List, record its line number */
416                                 current_line = lappend(current_line, buf);
417                                 *lines = lappend(*lines, current_line);
418                                 *line_nums = lappend_int(*line_nums, line_number);
419                         }
420                         else
421                         {
422                                 /* append token to current line's list */
423                                 current_line = lappend(current_line, buf);
424                         }
425                 }
426                 else
427                 {
428                         /* we are at real or logical EOL, so force a new line List */
429                         current_line = NIL;
430                         /* Advance line number whenever we reach EOL */
431                         line_number++;
432                 }
433         }
434 }
435
436 /*
437  * Compare two lines based on their role/member names.
438  *
439  * Used for bsearch() lookup.
440  */
441 static int
442 role_bsearch_cmp(const void *role, const void *list)
443 {
444         char       *role2 = linitial(*(List **) list);
445
446         return strcmp(role, role2);
447 }
448
449
450 /*
451  * Lookup a role name in the pg_auth file
452  */
453 List      **
454 get_role_line(const char *role)
455 {
456         /* On some versions of Solaris, bsearch of zero items dumps core */
457         if (role_length == 0)
458                 return NULL;
459
460         return (List **) bsearch((void *) role,
461                                                          (void *) role_sorted,
462                                                          role_length,
463                                                          sizeof(List *),
464                                                          role_bsearch_cmp);
465 }
466
467
468 /*
469  * Does user belong to role?
470  *
471  * user is always the name given as the attempted login identifier.
472  * We check to see if it is a member of the specified role name.
473  */
474 static bool
475 is_member(const char *user, const char *role)
476 {
477         List      **line;
478         ListCell   *line_item;
479
480         if ((line = get_role_line(user)) == NULL)
481                 return false;                   /* if user not exist, say "no" */
482
483         /* A user always belongs to its own role */
484         if (strcmp(user, role) == 0)
485                 return true;
486
487         /*
488          * skip over the role name, password, valuntil, examine all the membership
489          * entries
490          */
491         if (list_length(*line) < 4)
492                 return false;
493         for_each_cell(line_item, lnext(lnext(lnext(list_head(*line)))))
494         {
495                 if (strcmp((char *) lfirst(line_item), role) == 0)
496                         return true;
497         }
498
499         return false;
500 }
501
502 /*
503  * Check comma-separated list for a match to role, allowing group names.
504  *
505  * NB: param_str is destructively modified!  In current usage, this is
506  * okay only because this code is run after forking off from the postmaster,
507  * and so it doesn't matter that we clobber the stored hba info.
508  */
509 static bool
510 check_role(const char *role, char *param_str)
511 {
512         char       *tok;
513
514         for (tok = strtok(param_str, MULTI_VALUE_SEP);
515                  tok != NULL;
516                  tok = strtok(NULL, MULTI_VALUE_SEP))
517         {
518                 if (tok[0] == '+')
519                 {
520                         if (is_member(role, tok + 1))
521                                 return true;
522                 }
523                 else if (strcmp(tok, role) == 0 ||
524                                  strcmp(tok, "all\n") == 0)
525                         return true;
526         }
527
528         return false;
529 }
530
531 /*
532  * Check to see if db/role combination matches param string.
533  *
534  * NB: param_str is destructively modified!  In current usage, this is
535  * okay only because this code is run after forking off from the postmaster,
536  * and so it doesn't matter that we clobber the stored hba info.
537  */
538 static bool
539 check_db(const char *dbname, const char *role, char *param_str)
540 {
541         char       *tok;
542
543         for (tok = strtok(param_str, MULTI_VALUE_SEP);
544                  tok != NULL;
545                  tok = strtok(NULL, MULTI_VALUE_SEP))
546         {
547                 if (strcmp(tok, "all\n") == 0)
548                         return true;
549                 else if (strcmp(tok, "sameuser\n") == 0)
550                 {
551                         if (strcmp(dbname, role) == 0)
552                                 return true;
553                 }
554                 else if (strcmp(tok, "samegroup\n") == 0 ||
555                                  strcmp(tok, "samerole\n") == 0)
556                 {
557                         if (is_member(role, dbname))
558                                 return true;
559                 }
560                 else if (strcmp(tok, dbname) == 0)
561                         return true;
562         }
563         return false;
564 }
565
566
567 /*
568  * Macros used to check and report on invalid configuration options.
569  * INVALID_AUTH_OPTION = reports when an option is specified for a method where it's
570  *                       not supported.
571  * REQUIRE_AUTH_OPTION = same as INVALID_AUTH_OPTION, except it also checks if the
572  *                       method is actually the one specified. Used as a shortcut when
573  *                       the option is only valid for one authentication method.
574  * MANDATORY_AUTH_ARG  = check if a required option is set for an authentication method,
575  *                       reporting error if it's not.
576  */
577 #define INVALID_AUTH_OPTION(optname, validmethods) do {\
578         ereport(LOG, \
579                         (errcode(ERRCODE_CONFIG_FILE_ERROR), \
580                          errmsg("authentication option '%s' is only valid for authentication methods '%s'", \
581                                         optname, validmethods), \
582                          errcontext("line %d of configuration file \"%s\"", \
583                                         line_num, HbaFileName))); \
584         return false; \
585 } while (0);
586
587 #define REQUIRE_AUTH_OPTION(methodval, optname, validmethods) do {\
588         if (parsedline->auth_method != methodval) \
589                 INVALID_AUTH_OPTION("ldaptls", "ldap"); \
590 } while (0);
591
592 #define MANDATORY_AUTH_ARG(argvar, argname, authname) do {\
593         if (argvar == NULL) {\
594                 ereport(LOG, \
595                                 (errcode(ERRCODE_CONFIG_FILE_ERROR), \
596                                  errmsg("authentication method '%s' requires argument '%s' to be set", \
597                                                 authname, argname), \
598                                  errcontext("line %d of configuration file \"%s\"", \
599                                                 line_num, HbaFileName))); \
600                 return false; \
601         } \
602 } while (0);
603
604
605 /*
606  * Parse one line in the hba config file and store the result in
607  * a HbaLine structure.
608  */
609 static bool
610 parse_hba_line(List *line, int line_num, HbaLine *parsedline)
611 {
612         char       *token;
613         struct addrinfo *gai_result;
614         struct addrinfo hints;
615         int                     ret;
616         char       *cidr_slash;
617         char       *unsupauth;
618         ListCell   *line_item;
619
620         line_item = list_head(line);
621
622         parsedline->linenumber = line_num;
623
624         /* Check the record type. */
625         token = lfirst(line_item);
626         if (strcmp(token, "local") == 0)
627         {
628                 parsedline->conntype = ctLocal;
629         }
630         else if (strcmp(token, "host") == 0
631                          || strcmp(token, "hostssl") == 0
632                          || strcmp(token, "hostnossl") == 0)
633         {
634
635                 if (token[4] == 's')    /* "hostssl" */
636                 {
637 #ifdef USE_SSL
638                         parsedline->conntype = ctHostSSL;
639 #else
640                         ereport(LOG,
641                                         (errcode(ERRCODE_CONFIG_FILE_ERROR),
642                                          errmsg("hostssl not supported on this platform"),
643                                          errhint("compile with --enable-ssl to use SSL connections"),
644                                          errcontext("line %d of configuration file \"%s\"",
645                                                         line_num, HbaFileName)));
646                         return false;
647 #endif
648                 }
649 #ifdef USE_SSL
650                 else if (token[4] == 'n')               /* "hostnossl" */
651                 {
652                         parsedline->conntype = ctHostNoSSL;
653                 }
654 #endif
655                 else 
656                 {
657                         /* "host", or "hostnossl" and SSL support not built in */
658                         parsedline->conntype = ctHost;
659                 }
660         } /* record type */
661         else
662         {
663                 ereport(LOG,
664                                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
665                                  errmsg("invalid connection type \"%s\"",
666                                                 token),
667                                  errcontext("line %d of configuration file \"%s\"",
668                                                 line_num, HbaFileName)));
669                 return false;
670         }
671
672         /* Get the database. */
673         line_item = lnext(line_item);
674         if (!line_item)
675         {
676                 ereport(LOG,
677                                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
678                                  errmsg("end-of-line before database specification"),
679                                  errcontext("line %d of configuration file \"%s\"",
680                                                 line_num, HbaFileName)));
681                 return false;
682         }
683         parsedline->database = pstrdup(lfirst(line_item));
684
685         /* Get the role. */
686         line_item = lnext(line_item);
687         if (!line_item)
688         {
689                 ereport(LOG,
690                                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
691                                  errmsg("end-of-line before role specification"),
692                                  errcontext("line %d of configuration file \"%s\"",
693                                                 line_num, HbaFileName)));
694                 return false;
695         }
696         parsedline->role = pstrdup(lfirst(line_item));
697
698         if (parsedline->conntype != ctLocal)
699         {
700                 /* Read the IP address field. (with or without CIDR netmask) */
701                 line_item = lnext(line_item);
702                 if (!line_item)
703                 {
704                         ereport(LOG,
705                                         (errcode(ERRCODE_CONFIG_FILE_ERROR),
706                                          errmsg("end-of-line before ip address specification"),
707                                          errcontext("line %d of configuration file \"%s\"",
708                                                         line_num, HbaFileName)));
709                         return false;
710                 }
711                 token = pstrdup(lfirst(line_item));
712
713                 /* Check if it has a CIDR suffix and if so isolate it */
714                 cidr_slash = strchr(token, '/');
715                 if (cidr_slash)
716                         *cidr_slash = '\0';
717
718                 /* Get the IP address either way */
719                 hints.ai_flags = AI_NUMERICHOST;
720                 hints.ai_family = PF_UNSPEC;
721                 hints.ai_socktype = 0;
722                 hints.ai_protocol = 0;
723                 hints.ai_addrlen = 0;
724                 hints.ai_canonname = NULL;
725                 hints.ai_addr = NULL;
726                 hints.ai_next = NULL;
727
728                 ret = pg_getaddrinfo_all(token, NULL, &hints, &gai_result);
729                 if (ret || !gai_result)
730                 {
731                         ereport(LOG,
732                                         (errcode(ERRCODE_CONFIG_FILE_ERROR),
733                                          errmsg("invalid IP address \"%s\": %s",
734                                                         token, gai_strerror(ret)),
735                                          errcontext("line %d of configuration file \"%s\"",
736                                                         line_num, HbaFileName)));
737                         if (cidr_slash)
738                                 *cidr_slash = '/';
739                         if (gai_result)
740                                 pg_freeaddrinfo_all(hints.ai_family, gai_result);
741                         return false;
742                 }
743
744                 if (cidr_slash)
745                         *cidr_slash = '/';
746
747                 memcpy(&parsedline->addr, gai_result->ai_addr, gai_result->ai_addrlen);
748                 pg_freeaddrinfo_all(hints.ai_family, gai_result);
749
750                 /* Get the netmask */
751                 if (cidr_slash)
752                 {
753                         if (pg_sockaddr_cidr_mask(&parsedline->mask, cidr_slash + 1,
754                                                                           parsedline->addr.ss_family) < 0)
755                         {
756                                 ereport(LOG,
757                                                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
758                                                  errmsg("invalid CIDR mask in address \"%s\"",
759                                                                 token),
760                                                  errcontext("line %d of configuration file \"%s\"",
761                                                         line_num, HbaFileName)));
762                                 return false;
763                         }
764                 }
765                 else
766                 {
767                         /* Read the mask field. */
768                         line_item = lnext(line_item);
769                         if (!line_item)
770                         {
771                                 ereport(LOG,
772                                                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
773                                                  errmsg("end-of-line before netmask specification"),
774                                                  errcontext("line %d of configuration file \"%s\"",
775                                                                 line_num, HbaFileName)));
776                                 return false;
777                         }
778                         token = lfirst(line_item);
779
780                         ret = pg_getaddrinfo_all(token, NULL, &hints, &gai_result);
781                         if (ret || !gai_result)
782                         {
783                                 ereport(LOG,
784                                                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
785                                                  errmsg("invalid IP mask \"%s\": %s",
786                                                                 token, gai_strerror(ret)),
787                                                  errcontext("line %d of configuration file \"%s\"",
788                                                         line_num, HbaFileName)));
789                                 if (gai_result)
790                                         pg_freeaddrinfo_all(hints.ai_family, gai_result);
791                                 return false;
792                         }
793
794                         memcpy(&parsedline->mask, gai_result->ai_addr, gai_result->ai_addrlen);
795                         pg_freeaddrinfo_all(hints.ai_family, gai_result);
796
797                         if (parsedline->addr.ss_family != parsedline->mask.ss_family)
798                         {
799                                 ereport(LOG,
800                                                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
801                                                  errmsg("IP address and mask do not match in file \"%s\" line %d",
802                                                                 HbaFileName, line_num)));
803                                 return false;
804                         }
805                 }
806         } /* != ctLocal */
807
808         /* Get the authentication method */
809         line_item = lnext(line_item);
810         if (!line_item)
811         {
812                 ereport(LOG,
813                                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
814                                  errmsg("end-of-line before authentication method"),
815                                  errcontext("line %d of configuration file \"%s\"",
816                                                 line_num, HbaFileName)));
817                 return false;
818         }
819         token = lfirst(line_item);
820
821         unsupauth = NULL;
822         if (strcmp(token, "trust") == 0)
823                 parsedline->auth_method = uaTrust;
824         else if (strcmp(token, "ident") == 0)
825                 parsedline->auth_method = uaIdent;
826         else if (strcmp(token, "password") == 0)
827                 parsedline->auth_method = uaPassword;
828         else if (strcmp(token, "krb5") == 0)
829 #ifdef KRB5
830                 parsedline->auth_method = uaKrb5;
831 #else
832                 unsupauth = "krb5";
833 #endif
834         else if (strcmp(token, "gss") == 0)
835 #ifdef ENABLE_GSS
836                 parsedline->auth_method = uaGSS;
837 #else
838                 unsupauth = "gss";
839 #endif
840         else if (strcmp(token, "sspi") == 0)
841 #ifdef ENABLE_SSPI
842                 parsedline->auth_method = uaSSPI;
843 #else
844                 unsupauth = "sspi";
845 #endif
846         else if (strcmp(token, "reject") == 0)
847                 parsedline->auth_method = uaReject;
848         else if (strcmp(token, "md5") == 0)
849         {
850                 if (Db_user_namespace)
851                 {
852                         ereport(LOG,
853                                         (errcode(ERRCODE_CONFIG_FILE_ERROR),
854                                          errmsg("MD5 authentication is not supported when \"db_user_namespace\" is enabled")));
855                         return false;
856                 }
857                 parsedline->auth_method = uaMD5;
858         }
859         else if (strcmp(token, "pam") == 0)
860 #ifdef USE_PAM
861                 parsedline->auth_method = uaPAM;
862 #else
863                 unsupauth = "pam";
864 #endif
865         else if (strcmp(token, "ldap") == 0)
866 #ifdef USE_LDAP
867                 parsedline->auth_method = uaLDAP;
868 #else
869                 unsupauth = "ldap";
870 #endif
871         else if (strcmp(token, "cert") == 0)
872 #ifdef USE_SSL
873                 parsedline->auth_method = uaCert;
874 #else
875                 unsupauth = "cert";
876 #endif
877         else
878         {
879                 ereport(LOG,
880                                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
881                                  errmsg("invalid authentication method \"%s\"",
882                                                 token),
883                                  errcontext("line %d of configuration file \"%s\"",
884                                                 line_num, HbaFileName)));
885                 return false;
886         }
887
888         if (unsupauth)
889         {
890                 ereport(LOG,
891                                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
892                                  errmsg("invalid authentication method \"%s\": not supported on this platform",
893                                                 token),
894                                  errcontext("line %d of configuration file \"%s\"",
895                                                 line_num, HbaFileName)));
896                 return false;
897         }
898
899         /* Invalid authentication combinations */
900         if (parsedline->conntype == ctLocal &&
901                 parsedline->auth_method == uaKrb5)
902         {
903                 ereport(LOG,
904                                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
905                                  errmsg("krb5 authentication is not supported on local sockets"),
906                                  errcontext("line %d of configuration file \"%s\"",
907                                                 line_num, HbaFileName)));
908                 return false;
909         }
910
911         if (parsedline->conntype != ctHostSSL &&
912                 parsedline->auth_method == uaCert)
913         {
914                 ereport(LOG,
915                                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
916                                  errmsg("cert authentication is only supported on hostssl connections"),
917                                  errcontext("line %d of configuration file \"%s\"",
918                                                         line_num, HbaFileName)));
919                 return false;
920         }
921
922         /* Parse remaining arguments */
923         while ((line_item = lnext(line_item)) != NULL)
924         {
925                 char *c;
926
927                 token = lfirst(line_item);
928
929                 c = strchr(token, '=');
930                 if (c == NULL)
931                 {
932                         /*
933                          * Got something that's not a name=value pair.
934                          *
935                          * XXX: attempt to do some backwards compatible parsing here?
936                          */
937                         ereport(LOG,
938                                         (errcode(ERRCODE_CONFIG_FILE_ERROR),
939                                          errmsg("authentication option not in name=value format: %s", token),
940                                          errcontext("line %d of configuration file \"%s\"",
941                                                                 line_num, HbaFileName)));
942                         return false;
943                 }
944                 else
945                 {
946                         *c++ = '\0'; /* token now holds "name", c holds "value" */
947                         if (strcmp(token, "map") == 0)
948                         {
949                                 if (parsedline->auth_method != uaIdent &&
950                                         parsedline->auth_method != uaKrb5 &&
951                                         parsedline->auth_method != uaGSS &&
952                                         parsedline->auth_method != uaSSPI &&
953                                         parsedline->auth_method != uaCert)
954                                         INVALID_AUTH_OPTION("map", "ident, krb5, gssapi, sspi and cert");
955                                 parsedline->usermap = pstrdup(c);
956                         }
957                         else if (strcmp(token, "clientcert") == 0)
958                         {
959                                 /*
960                                  * Since we require ctHostSSL, this really can never happen on non-SSL-enabled
961                                  * builds, so don't bother checking for USE_SSL.
962                                  */
963                                 if (parsedline->conntype != ctHostSSL)
964                                 {
965                                         ereport(LOG,
966                                                         (errcode(ERRCODE_CONFIG_FILE_ERROR),
967                                                          errmsg("clientcert can only be configured for \"hostssl\" rows"),
968                                                          errcontext("line %d of configuration file \"%s\"",
969                                                                                 line_num, HbaFileName)));
970                                         return false;
971                                 }
972                                 if (strcmp(c, "1") == 0)
973                                 {
974                                         if (!secure_loaded_verify_locations())
975                                         {
976                                                 ereport(LOG,
977                                                                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
978                                                                  errmsg("client certificates can only be checked if a root certificate store is available"),
979                                                                  errdetail("make sure the root certificate store is present and readable"),
980                                                                  errcontext("line %d of configuration file \"%s\"",
981                                                                                         line_num, HbaFileName)));
982                                                 return false;
983                                         }
984                                         parsedline->clientcert = true;
985                                 }
986                                 else
987                                 {
988                                         if (parsedline->auth_method == uaCert)
989                                         {
990                                                 ereport(LOG,
991                                                                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
992                                                                  errmsg("clientcert can not be set to 0 when using \"cert\" authentication"),
993                                                                  errcontext("line %d of configuration file \"%s\"",
994                                                                                         line_num, HbaFileName)));
995                                                 return false;
996                                         }
997                                         parsedline->clientcert = false;
998                                 }
999                         }
1000                         else if (strcmp(token, "pamservice") == 0)
1001                         {
1002                                 REQUIRE_AUTH_OPTION(uaPAM, "pamservice", "pam");
1003                                 parsedline->pamservice = pstrdup(c);
1004                         }
1005                         else if (strcmp(token, "ldaptls") == 0)
1006                         {
1007                                 REQUIRE_AUTH_OPTION(uaLDAP, "ldaptls", "ldap");
1008                                 if (strcmp(c, "1") == 0)
1009                                         parsedline->ldaptls = true;
1010                                 else
1011                                         parsedline->ldaptls = false;
1012                         }
1013                         else if (strcmp(token, "ldapserver") == 0)
1014                         {
1015                                 REQUIRE_AUTH_OPTION(uaLDAP, "ldapserver", "ldap");
1016                                 parsedline->ldapserver = pstrdup(c);
1017                         }
1018                         else if (strcmp(token, "ldapport") == 0)
1019                         {
1020                                 REQUIRE_AUTH_OPTION(uaLDAP, "ldapport", "ldap");
1021                                 parsedline->ldapport = atoi(c);
1022                                 if (parsedline->ldapport == 0)
1023                                 {
1024                                         ereport(LOG,
1025                                                         (errcode(ERRCODE_CONFIG_FILE_ERROR),
1026                                                          errmsg("invalid ldap port '%s'", c),
1027                                                          errcontext("line %d of configuration file \"%s\"",
1028                                                                                 line_num, HbaFileName)));
1029                                         return false;
1030                                 }
1031                         }
1032                         else if (strcmp(token, "ldapprefix") == 0)
1033                         {
1034                                 REQUIRE_AUTH_OPTION(uaLDAP, "ldapprefix", "ldap");
1035                                 parsedline->ldapprefix = pstrdup(c);
1036                         }
1037                         else if (strcmp(token, "ldapsuffix") == 0)
1038                         {
1039                                 REQUIRE_AUTH_OPTION(uaLDAP, "ldapsuffix", "ldap");
1040                                 parsedline->ldapsuffix = pstrdup(c);
1041                         }
1042                         else
1043                         {
1044                                 ereport(LOG,
1045                                                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1046                                                  errmsg("unknown authentication option name '%s'", token),
1047                                                  errcontext("line %d of configuration file \"%s\"",
1048                                                                         line_num, HbaFileName)));
1049                                 return false;
1050                         }
1051                 }
1052         }
1053
1054         /*
1055          * Check if the selected authentication method has any mandatory arguments that
1056          * are not set.
1057          */
1058         if (parsedline->auth_method == uaLDAP)
1059         {
1060                 MANDATORY_AUTH_ARG(parsedline->ldapserver, "ldapserver", "ldap");
1061         }
1062
1063         /*
1064          * Enforce any parameters implied by other settings.
1065          */
1066         if (parsedline->auth_method == uaCert)
1067         {
1068                 parsedline->clientcert = true;
1069         }
1070         
1071         return true;
1072 }
1073
1074
1075 /*
1076  *      Scan the (pre-parsed) hba file line by line, looking for a match
1077  *      to the port's connection request.
1078  */
1079 static bool
1080 check_hba(hbaPort *port)
1081 {
1082         ListCell   *line;
1083         HbaLine    *hba;
1084
1085         foreach(line, parsed_hba_lines)
1086         {
1087                 hba = (HbaLine *) lfirst(line);
1088
1089                 /* Check connection type */
1090                 if (hba->conntype == ctLocal)
1091                 {
1092                         if (!IS_AF_UNIX(port->raddr.addr.ss_family))
1093                                 continue;
1094                 }
1095                 else
1096                 {
1097                         if (IS_AF_UNIX(port->raddr.addr.ss_family))
1098                                 continue;
1099
1100                         /* Check SSL state */
1101 #ifdef USE_SSL
1102                         if (port->ssl)
1103                         {
1104                                 /* Connection is SSL, match both "host" and "hostssl" */
1105                                 if (hba->conntype == ctHostNoSSL)
1106                                         continue;
1107                         }
1108                         else
1109                         {
1110                                 /* Connection is not SSL, match both "host" and "hostnossl" */
1111                                 if (hba->conntype == ctHostSSL)
1112                                         continue;
1113                         }
1114 #else
1115                         /* No SSL support, so reject "hostssl" lines */
1116                         if (hba->conntype == ctHostSSL)
1117                                 continue;
1118 #endif
1119
1120                         /* Check IP address */
1121                         if (port->raddr.addr.ss_family == hba->addr.ss_family)
1122                         {
1123                                 if (!pg_range_sockaddr(&port->raddr.addr, &hba->addr, &hba->mask))
1124                                         continue;
1125                         }
1126 #ifdef HAVE_IPV6
1127                         else  if (hba->addr.ss_family == AF_INET &&
1128                                           port->raddr.addr.ss_family == AF_INET6)
1129                         {
1130                                 /*
1131                                  * Wrong address family.  We allow only one case: if the file has
1132                                  * IPv4 and the port is IPv6, promote the file address to IPv6 and
1133                                  * try to match that way.
1134                                  */
1135                                 struct sockaddr_storage addrcopy, maskcopy;
1136                                 memcpy(&addrcopy, &hba->addr, sizeof(addrcopy));
1137                                 memcpy(&maskcopy, &hba->mask, sizeof(maskcopy));
1138                                 pg_promote_v4_to_v6_addr(&addrcopy);
1139                                 pg_promote_v4_to_v6_mask(&maskcopy);
1140                                 
1141                                 if (!pg_range_sockaddr(&port->raddr.addr, &addrcopy, &maskcopy))
1142                                         continue;
1143                         }
1144 #endif /* HAVE_IPV6 */
1145                         else
1146                                 /* Wrong address family, no IPV6 */
1147                                 continue;
1148                 } /* != ctLocal */
1149
1150                 /* Check database and role */
1151                 if (!check_db(port->database_name, port->user_name, hba->database))
1152                         continue;
1153
1154                 if (!check_role(port->user_name, hba->role))
1155                         continue;
1156
1157                 /* Found a record that matched! */
1158                 port->hba = hba;
1159                 return true;
1160         }
1161
1162         /* If no matching entry was found, synthesize 'reject' entry. */
1163         hba = palloc0(sizeof(HbaLine));
1164         hba->auth_method = uaReject;
1165         port->hba = hba;
1166         return true;
1167
1168         /* XXX:
1169          * Return false only happens if we have a parsing error, which we can 
1170          * no longer have (parsing now in postmaster). Consider changing API.
1171          */
1172 }
1173
1174
1175 /*
1176  *       Load role/password mapping file
1177  */
1178 void
1179 load_role(void)
1180 {
1181         char       *filename;
1182         FILE       *role_file;
1183
1184         /* Discard any old data */
1185         if (role_lines || role_line_nums)
1186                 free_lines(&role_lines, &role_line_nums);
1187         if (role_sorted)
1188                 pfree(role_sorted);
1189         role_sorted = NULL;
1190         role_length = 0;
1191
1192         /* Read in the file contents */
1193         filename = auth_getflatfilename();
1194         role_file = AllocateFile(filename, "r");
1195
1196         if (role_file == NULL)
1197         {
1198                 /* no complaint if not there */
1199                 if (errno != ENOENT)
1200                         ereport(LOG,
1201                                         (errcode_for_file_access(),
1202                                          errmsg("could not open file \"%s\": %m", filename)));
1203                 pfree(filename);
1204                 return;
1205         }
1206
1207         tokenize_file(filename, role_file, &role_lines, &role_line_nums);
1208
1209         FreeFile(role_file);
1210         pfree(filename);
1211
1212         /* create array for binary searching */
1213         role_length = list_length(role_lines);
1214         if (role_length)
1215         {
1216                 int                     i = 0;
1217                 ListCell   *line;
1218
1219                 /* We assume the flat file was written already-sorted */
1220                 role_sorted = palloc(role_length * sizeof(List *));
1221                 foreach(line, role_lines)
1222                         role_sorted[i++] = lfirst(line);
1223         }
1224 }
1225
1226 /*
1227  * Free the contents of a hba record
1228  */
1229 static void
1230 free_hba_record(HbaLine *record)
1231 {
1232         if (record->database)
1233                 pfree(record->database);
1234         if (record->role)
1235                 pfree(record->role);
1236         if (record->pamservice)
1237                 pfree(record->pamservice);
1238         if (record->ldapserver)
1239                 pfree(record->ldapserver);
1240         if (record->ldapprefix)
1241                 pfree(record->ldapprefix);
1242         if (record->ldapsuffix)
1243                 pfree(record->ldapsuffix);
1244 }
1245
1246 /*
1247  * Free all records on the parsed HBA list
1248  */
1249 static void
1250 clean_hba_list(List *lines)
1251 {
1252         ListCell        *line;
1253
1254         foreach(line, lines)
1255         {
1256                 HbaLine *parsed = (HbaLine *)lfirst(line);
1257                 if (parsed)
1258                         free_hba_record(parsed);
1259         }
1260         list_free(lines);
1261 }
1262
1263 /*
1264  * Read the config file and create a List of HbaLine records for the contents.
1265  *
1266  * The configuration is read into a temporary list, and if any parse error occurs
1267  * the old list is kept in place and false is returned. Only if the whole file
1268  * parses Ok is the list replaced, and the function returns true.
1269  */
1270 bool
1271 load_hba(void)
1272 {
1273         FILE       *file;
1274         List *hba_lines = NIL;
1275         List *hba_line_nums = NIL;
1276         ListCell   *line, *line_num;
1277         List *new_parsed_lines = NIL;
1278
1279         file = AllocateFile(HbaFileName, "r");
1280         /* Failure is fatal since with no HBA entries we can do nothing... */
1281         if (file == NULL)
1282                 ereport(FATAL,
1283                                 (errcode_for_file_access(),
1284                                  errmsg("could not open configuration file \"%s\": %m",
1285                                                 HbaFileName)));
1286
1287         tokenize_file(HbaFileName, file, &hba_lines, &hba_line_nums);
1288         FreeFile(file);
1289
1290         /* Now parse all the lines */
1291         forboth(line, hba_lines, line_num, hba_line_nums)
1292         {
1293                 HbaLine *newline;
1294
1295                 newline = palloc0(sizeof(HbaLine));
1296
1297                 if (!parse_hba_line(lfirst(line), lfirst_int(line_num), newline))
1298                 {
1299                         /* Parse error in the file, so bail out */
1300                         free_hba_record(newline);
1301                         pfree(newline);
1302                         clean_hba_list(new_parsed_lines);
1303                         /* Error has already been reported in the parsing function */
1304                         return false;
1305                 }
1306
1307                 new_parsed_lines = lappend(new_parsed_lines, newline);
1308         }
1309
1310         /* Loaded new file successfully, replace the one we use */
1311         clean_hba_list(parsed_hba_lines);
1312         parsed_hba_lines = new_parsed_lines;
1313
1314         /* Free the temporary lists */
1315         free_lines(&hba_lines, &hba_line_nums);
1316
1317         return true;
1318 }
1319
1320 /*
1321  * Read and parse one line from the flat pg_database file.
1322  *
1323  * Returns TRUE on success, FALSE if EOF; bad data causes elog(FATAL).
1324  *
1325  * Output parameters:
1326  *      dbname: gets database name (must be of size NAMEDATALEN bytes)
1327  *      dboid: gets database OID
1328  *      dbtablespace: gets database's default tablespace's OID
1329  *      dbfrozenxid: gets database's frozen XID
1330  *
1331  * This is not much related to the other functions in hba.c, but we put it
1332  * here because it uses the next_token() infrastructure.
1333  */
1334 bool
1335 read_pg_database_line(FILE *fp, char *dbname, Oid *dboid,
1336                                           Oid *dbtablespace, TransactionId *dbfrozenxid)
1337 {
1338         char            buf[MAX_TOKEN];
1339
1340         if (feof(fp))
1341                 return false;
1342         if (!next_token(fp, buf, sizeof(buf)))
1343                 return false;
1344         if (strlen(buf) >= NAMEDATALEN)
1345                 elog(FATAL, "bad data in flat pg_database file");
1346         strcpy(dbname, buf);
1347         next_token(fp, buf, sizeof(buf));
1348         if (!isdigit((unsigned char) buf[0]))
1349                 elog(FATAL, "bad data in flat pg_database file");
1350         *dboid = atooid(buf);
1351         next_token(fp, buf, sizeof(buf));
1352         if (!isdigit((unsigned char) buf[0]))
1353                 elog(FATAL, "bad data in flat pg_database file");
1354         *dbtablespace = atooid(buf);
1355         next_token(fp, buf, sizeof(buf));
1356         if (!isdigit((unsigned char) buf[0]))
1357                 elog(FATAL, "bad data in flat pg_database file");
1358         *dbfrozenxid = atoxid(buf);
1359         /* expect EOL next */
1360         if (next_token(fp, buf, sizeof(buf)))
1361                 elog(FATAL, "bad data in flat pg_database file");
1362         return true;
1363 }
1364
1365 /*
1366  *      Process one line from the ident config file.
1367  *
1368  *      Take the line and compare it to the needed map, pg_role and ident_user.
1369  *      *found_p and *error_p are set according to our results.
1370  */
1371 static void
1372 parse_ident_usermap(List *line, int line_number, const char *usermap_name,
1373                                         const char *pg_role, const char *ident_user,
1374                                         bool case_insensitive, bool *found_p, bool *error_p)
1375 {
1376         ListCell   *line_item;
1377         char       *token;
1378         char       *file_map;
1379         char       *file_pgrole;
1380         char       *file_ident_user;
1381
1382         *found_p = false;
1383         *error_p = false;
1384
1385         Assert(line != NIL);
1386         line_item = list_head(line);
1387
1388         /* Get the map token (must exist) */
1389         token = lfirst(line_item);
1390         file_map = token;
1391
1392         /* Get the ident user token */
1393         line_item = lnext(line_item);
1394         if (!line_item)
1395                 goto ident_syntax;
1396         token = lfirst(line_item);
1397         file_ident_user = token;
1398
1399         /* Get the PG rolename token */
1400         line_item = lnext(line_item);
1401         if (!line_item)
1402                 goto ident_syntax;
1403         token = lfirst(line_item);
1404         file_pgrole = token;
1405
1406         /* Match? */
1407         if (case_insensitive)
1408         {
1409                 if (strcmp(file_map, usermap_name) == 0 &&
1410                         pg_strcasecmp(file_pgrole, pg_role) == 0 &&
1411                         pg_strcasecmp(file_ident_user, ident_user) == 0)
1412                         *found_p = true;
1413         }
1414         else
1415         {
1416                 if (strcmp(file_map, usermap_name) == 0 &&
1417                         strcmp(file_pgrole, pg_role) == 0 &&
1418                         strcmp(file_ident_user, ident_user) == 0)
1419                         *found_p = true;
1420         }
1421
1422         return;
1423
1424 ident_syntax:
1425         ereport(LOG,
1426                         (errcode(ERRCODE_CONFIG_FILE_ERROR),
1427                          errmsg("missing entry in file \"%s\" at end of line %d",
1428                                         IdentFileName, line_number)));
1429         *error_p = true;
1430 }
1431
1432
1433 /*
1434  *      Scan the (pre-parsed) ident usermap file line by line, looking for a match
1435  *
1436  *      See if the user with ident username "ident_user" is allowed to act
1437  *      as Postgres user "pgrole" according to usermap "usermap_name".
1438  *
1439  *  Special case: Usermap NULL, equivalent to what was previously called
1440  *  "sameuser" or "samerole", don't look in the usermap
1441  *      file.  That's an implied map where "pgrole" must be identical to
1442  *      "ident_user" in order to be authorized.
1443  *
1444  *      Iff authorized, return STATUS_OK, otherwise return STATUS_ERROR.
1445  */
1446 int
1447 check_usermap(const char *usermap_name,
1448                                         const char *pg_role,
1449                                         const char *auth_user,
1450                                         bool case_insensitive)
1451 {
1452         bool            found_entry = false,
1453                                 error = false;
1454
1455         if (usermap_name == NULL || usermap_name[0] == '\0')
1456         {
1457                 if (case_insensitive)
1458                 {
1459                         if (pg_strcasecmp(pg_role, auth_user) == 0)
1460                                 return STATUS_OK;
1461                 }
1462                 else {
1463                         if (strcmp(pg_role, auth_user) == 0)
1464                                 return STATUS_OK;
1465                 }
1466                 ereport(LOG,
1467                                 (errmsg("provided username (%s) and authenticated username (%s) don't match",
1468                                                 auth_user, pg_role)));
1469                 return STATUS_ERROR;
1470         }
1471         else
1472         {
1473                 ListCell   *line_cell,
1474                                    *num_cell;
1475
1476                 forboth(line_cell, ident_lines, num_cell, ident_line_nums)
1477                 {
1478                         parse_ident_usermap(lfirst(line_cell), lfirst_int(num_cell),
1479                                                                 usermap_name, pg_role, auth_user, case_insensitive,
1480                                                                 &found_entry, &error);
1481                         if (found_entry || error)
1482                                 break;
1483                 }
1484         }
1485         if (!found_entry && !error)
1486         {
1487                 ereport(LOG,
1488                                 (errmsg("no match in usermap for user '%s' authenticated as '%s'",
1489                                                 pg_role, auth_user),
1490                                  errcontext("usermap '%s'", usermap_name)));
1491         }
1492         return found_entry?STATUS_OK:STATUS_ERROR;
1493 }
1494
1495
1496 /*
1497  * Read the ident config file and create a List of Lists of tokens in the file.
1498  */
1499 void
1500 load_ident(void)
1501 {
1502         FILE       *file;
1503
1504         if (ident_lines || ident_line_nums)
1505                 free_lines(&ident_lines, &ident_line_nums);
1506
1507         file = AllocateFile(IdentFileName, "r");
1508         if (file == NULL)
1509         {
1510                 /* not fatal ... we just won't do any special ident maps */
1511                 ereport(LOG,
1512                                 (errcode_for_file_access(),
1513                                  errmsg("could not open Ident usermap file \"%s\": %m",
1514                                                 IdentFileName)));
1515         }
1516         else
1517         {
1518                 tokenize_file(IdentFileName, file, &ident_lines, &ident_line_nums);
1519                 FreeFile(file);
1520         }
1521 }
1522
1523
1524
1525 /*
1526  *      Determine what authentication method should be used when accessing database
1527  *      "database" from frontend "raddr", user "user".  Return the method and
1528  *      an optional argument (stored in fields of *port), and STATUS_OK.
1529  *
1530  *      Note that STATUS_ERROR indicates a problem with the hba config file.
1531  *      If the file is OK but does not contain any entry matching the request,
1532  *      we return STATUS_OK and method = uaReject.
1533  */
1534 int
1535 hba_getauthmethod(hbaPort *port)
1536 {
1537         if (check_hba(port))
1538                 return STATUS_OK;
1539         else
1540                 return STATUS_ERROR;
1541 }