Message fixes
[PostgreSQL.git] / src / backend / libpq / hba.c
blob825509ff21f57cbdad969c992d2faef15c74695d
1 /*-------------------------------------------------------------------------
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).
8 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
9 * Portions Copyright (c) 1994, Regents of the University of California
12 * IDENTIFICATION
13 * $PostgreSQL$
15 *-------------------------------------------------------------------------
17 #include "postgres.h"
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>
28 #include "libpq/ip.h"
29 #include "libpq/libpq.h"
30 #include "regex/regex.h"
31 #include "storage/fd.h"
32 #include "utils/flatfiles.h"
33 #include "utils/guc.h"
37 #define atooid(x) ((Oid) strtoul((x), NULL, 10))
38 #define atoxid(x) ((TransactionId) strtoul((x), NULL, 10))
40 /* This is used to separate values in multi-valued column strings */
41 #define MULTI_VALUE_SEP "\001"
43 #define MAX_TOKEN 256
45 /* pre-parsed content of HBA config file */
46 static List *parsed_hba_lines = NIL;
49 * These variables hold the pre-parsed contents of the ident
50 * configuration files, as well as the flat auth file.
51 * Each is a list of sublists, one sublist for
52 * each (non-empty, non-comment) line of the file. Each sublist's
53 * first item is an integer line number (so we can give somewhat-useful
54 * location info in error messages). Remaining items are palloc'd strings,
55 * one string per token on the line. Note there will always be at least
56 * one token, since blank lines are not entered in the data structure.
59 /* pre-parsed content of ident usermap file and corresponding line #s */
60 static List *ident_lines = NIL;
61 static List *ident_line_nums = NIL;
63 /* pre-parsed content of flat auth file and corresponding line #s */
64 static List *role_lines = NIL;
65 static List *role_line_nums = NIL;
67 /* sorted entries so we can do binary search lookups */
68 static List **role_sorted = NULL; /* sorted role list, for bsearch() */
69 static int role_length;
71 static void tokenize_file(const char *filename, FILE *file,
72 List **lines, List **line_nums);
73 static char *tokenize_inc_file(const char *outer_filename,
74 const char *inc_filename);
77 * isblank() exists in the ISO C99 spec, but it's not very portable yet,
78 * so provide our own version.
80 bool
81 pg_isblank(const char c)
83 return c == ' ' || c == '\t' || c == '\r';
88 * Grab one token out of fp. Tokens are strings of non-blank
89 * characters bounded by blank characters, commas, beginning of line, and
90 * end of line. Blank means space or tab. Tokens can be delimited by
91 * double quotes (this allows the inclusion of blanks, but not newlines).
93 * The token, if any, is returned at *buf (a buffer of size bufsz).
95 * If successful: store null-terminated token at *buf and return TRUE.
96 * If no more tokens on line: set *buf = '\0' and return FALSE.
98 * Leave file positioned at the character immediately after the token or EOF,
99 * whichever comes first. If no more tokens on line, position the file to the
100 * beginning of the next line or EOF, whichever comes first.
102 * Handle comments. Treat unquoted keywords that might be role names or
103 * database names specially, by appending a newline to them. Also, when
104 * a token is terminated by a comma, the comma is included in the returned
105 * token.
107 static bool
108 next_token(FILE *fp, char *buf, int bufsz)
110 int c;
111 char *start_buf = buf;
112 char *end_buf = buf + (bufsz - 2);
113 bool in_quote = false;
114 bool was_quote = false;
115 bool saw_quote = false;
117 Assert(end_buf > start_buf);
119 /* Move over initial whitespace and commas */
120 while ((c = getc(fp)) != EOF && (pg_isblank(c) || c == ','))
123 if (c == EOF || c == '\n')
125 *buf = '\0';
126 return false;
130 * Build a token in buf of next characters up to EOF, EOL, unquoted comma,
131 * or unquoted whitespace.
133 while (c != EOF && c != '\n' &&
134 (!pg_isblank(c) || in_quote))
136 /* skip comments to EOL */
137 if (c == '#' && !in_quote)
139 while ((c = getc(fp)) != EOF && c != '\n')
141 /* If only comment, consume EOL too; return EOL */
142 if (c != EOF && buf == start_buf)
143 c = getc(fp);
144 break;
147 if (buf >= end_buf)
149 *buf = '\0';
150 ereport(LOG,
151 (errcode(ERRCODE_CONFIG_FILE_ERROR),
152 errmsg("authentication file token too long, skipping: \"%s\"",
153 start_buf)));
154 /* Discard remainder of line */
155 while ((c = getc(fp)) != EOF && c != '\n')
157 break;
160 if (c != '"' || was_quote)
161 *buf++ = c;
163 /* We pass back the comma so the caller knows there is more */
164 if (c == ',' && !in_quote)
165 break;
167 /* Literal double-quote is two double-quotes */
168 if (in_quote && c == '"')
169 was_quote = !was_quote;
170 else
171 was_quote = false;
173 if (c == '"')
175 in_quote = !in_quote;
176 saw_quote = true;
179 c = getc(fp);
183 * Put back the char right after the token (critical in case it is EOL,
184 * since we need to detect end-of-line at next call).
186 if (c != EOF)
187 ungetc(c, fp);
189 *buf = '\0';
191 if (!saw_quote &&
192 (strcmp(start_buf, "all") == 0 ||
193 strcmp(start_buf, "sameuser") == 0 ||
194 strcmp(start_buf, "samegroup") == 0 ||
195 strcmp(start_buf, "samerole") == 0))
197 /* append newline to a magical keyword */
198 *buf++ = '\n';
199 *buf = '\0';
202 return (saw_quote || buf > start_buf);
206 * Tokenize file and handle file inclusion and comma lists. We have
207 * to break apart the commas to expand any file names then
208 * reconstruct with commas.
210 * The result is a palloc'd string, or NULL if we have reached EOL.
212 static char *
213 next_token_expand(const char *filename, FILE *file)
215 char buf[MAX_TOKEN];
216 char *comma_str = pstrdup("");
217 bool got_something = false;
218 bool trailing_comma;
219 char *incbuf;
220 int needed;
224 if (!next_token(file, buf, sizeof(buf)))
225 break;
227 got_something = true;
229 if (strlen(buf) > 0 && buf[strlen(buf) - 1] == ',')
231 trailing_comma = true;
232 buf[strlen(buf) - 1] = '\0';
234 else
235 trailing_comma = false;
237 /* Is this referencing a file? */
238 if (buf[0] == '@')
239 incbuf = tokenize_inc_file(filename, buf + 1);
240 else
241 incbuf = pstrdup(buf);
243 needed = strlen(comma_str) + strlen(incbuf) + 1;
244 if (trailing_comma)
245 needed++;
246 comma_str = repalloc(comma_str, needed);
247 strcat(comma_str, incbuf);
248 if (trailing_comma)
249 strcat(comma_str, MULTI_VALUE_SEP);
250 pfree(incbuf);
251 } while (trailing_comma);
253 if (!got_something)
255 pfree(comma_str);
256 return NULL;
259 return comma_str;
264 * Free memory used by lines/tokens (i.e., structure built by tokenize_file)
266 static void
267 free_lines(List **lines, List **line_nums)
270 * Either both must be non-NULL, or both must be NULL
272 Assert((*lines != NIL && *line_nums != NIL) ||
273 (*lines == NIL && *line_nums == NIL));
275 if (*lines)
278 * "lines" is a list of lists; each of those sublists consists of
279 * palloc'ed tokens, so we want to free each pointed-to token in a
280 * sublist, followed by the sublist itself, and finally the whole
281 * list.
283 ListCell *line;
285 foreach(line, *lines)
287 List *ln = lfirst(line);
288 ListCell *token;
290 foreach(token, ln)
291 pfree(lfirst(token));
292 /* free the sublist structure itself */
293 list_free(ln);
295 /* free the list structure itself */
296 list_free(*lines);
297 /* clear the static variable */
298 *lines = NIL;
301 if (*line_nums)
303 list_free(*line_nums);
304 *line_nums = NIL;
309 static char *
310 tokenize_inc_file(const char *outer_filename,
311 const char *inc_filename)
313 char *inc_fullname;
314 FILE *inc_file;
315 List *inc_lines;
316 List *inc_line_nums;
317 ListCell *line;
318 char *comma_str;
320 if (is_absolute_path(inc_filename))
322 /* absolute path is taken as-is */
323 inc_fullname = pstrdup(inc_filename);
325 else
327 /* relative path is relative to dir of calling file */
328 inc_fullname = (char *) palloc(strlen(outer_filename) + 1 +
329 strlen(inc_filename) + 1);
330 strcpy(inc_fullname, outer_filename);
331 get_parent_directory(inc_fullname);
332 join_path_components(inc_fullname, inc_fullname, inc_filename);
333 canonicalize_path(inc_fullname);
336 inc_file = AllocateFile(inc_fullname, "r");
337 if (inc_file == NULL)
339 ereport(LOG,
340 (errcode_for_file_access(),
341 errmsg("could not open secondary authentication file \"@%s\" as \"%s\": %m",
342 inc_filename, inc_fullname)));
343 pfree(inc_fullname);
345 /* return single space, it matches nothing */
346 return pstrdup(" ");
349 /* There is possible recursion here if the file contains @ */
350 tokenize_file(inc_fullname, inc_file, &inc_lines, &inc_line_nums);
352 FreeFile(inc_file);
353 pfree(inc_fullname);
355 /* Create comma-separated string from List */
356 comma_str = pstrdup("");
357 foreach(line, inc_lines)
359 List *token_list = (List *) lfirst(line);
360 ListCell *token;
362 foreach(token, token_list)
364 int oldlen = strlen(comma_str);
365 int needed;
367 needed = oldlen + strlen(lfirst(token)) + 1;
368 if (oldlen > 0)
369 needed++;
370 comma_str = repalloc(comma_str, needed);
371 if (oldlen > 0)
372 strcat(comma_str, MULTI_VALUE_SEP);
373 strcat(comma_str, lfirst(token));
377 free_lines(&inc_lines, &inc_line_nums);
379 /* if file is empty, return single space rather than empty string */
380 if (strlen(comma_str) == 0)
382 pfree(comma_str);
383 return pstrdup(" ");
386 return comma_str;
391 * Tokenize the given file, storing the resulting data into two lists:
392 * a list of sublists, each sublist containing the tokens in a line of
393 * the file, and a list of line numbers.
395 * filename must be the absolute path to the target file.
397 static void
398 tokenize_file(const char *filename, FILE *file,
399 List **lines, List **line_nums)
401 List *current_line = NIL;
402 int line_number = 1;
403 char *buf;
405 *lines = *line_nums = NIL;
407 while (!feof(file))
409 buf = next_token_expand(filename, file);
411 /* add token to list, unless we are at EOL or comment start */
412 if (buf)
414 if (current_line == NIL)
416 /* make a new line List, record its line number */
417 current_line = lappend(current_line, buf);
418 *lines = lappend(*lines, current_line);
419 *line_nums = lappend_int(*line_nums, line_number);
421 else
423 /* append token to current line's list */
424 current_line = lappend(current_line, buf);
427 else
429 /* we are at real or logical EOL, so force a new line List */
430 current_line = NIL;
431 /* Advance line number whenever we reach EOL */
432 line_number++;
438 * Compare two lines based on their role/member names.
440 * Used for bsearch() lookup.
442 static int
443 role_bsearch_cmp(const void *role, const void *list)
445 char *role2 = linitial(*(List **) list);
447 return strcmp(role, role2);
452 * Lookup a role name in the pg_auth file
454 List **
455 get_role_line(const char *role)
457 /* On some versions of Solaris, bsearch of zero items dumps core */
458 if (role_length == 0)
459 return NULL;
461 return (List **) bsearch((void *) role,
462 (void *) role_sorted,
463 role_length,
464 sizeof(List *),
465 role_bsearch_cmp);
470 * Does user belong to role?
472 * user is always the name given as the attempted login identifier.
473 * We check to see if it is a member of the specified role name.
475 static bool
476 is_member(const char *user, const char *role)
478 List **line;
479 ListCell *line_item;
481 if ((line = get_role_line(user)) == NULL)
482 return false; /* if user not exist, say "no" */
484 /* A user always belongs to its own role */
485 if (strcmp(user, role) == 0)
486 return true;
489 * skip over the role name, password, valuntil, examine all the membership
490 * entries
492 if (list_length(*line) < 4)
493 return false;
494 for_each_cell(line_item, lnext(lnext(lnext(list_head(*line)))))
496 if (strcmp((char *) lfirst(line_item), role) == 0)
497 return true;
500 return false;
504 * Check comma-separated list for a match to role, allowing group names.
506 * NB: param_str is destructively modified! In current usage, this is
507 * okay only because this code is run after forking off from the postmaster,
508 * and so it doesn't matter that we clobber the stored hba info.
510 static bool
511 check_role(const char *role, char *param_str)
513 char *tok;
515 for (tok = strtok(param_str, MULTI_VALUE_SEP);
516 tok != NULL;
517 tok = strtok(NULL, MULTI_VALUE_SEP))
519 if (tok[0] == '+')
521 if (is_member(role, tok + 1))
522 return true;
524 else if (strcmp(tok, role) == 0 ||
525 strcmp(tok, "all\n") == 0)
526 return true;
529 return false;
533 * Check to see if db/role combination matches param string.
535 * NB: param_str is destructively modified! In current usage, this is
536 * okay only because this code is run after forking off from the postmaster,
537 * and so it doesn't matter that we clobber the stored hba info.
539 static bool
540 check_db(const char *dbname, const char *role, char *param_str)
542 char *tok;
544 for (tok = strtok(param_str, MULTI_VALUE_SEP);
545 tok != NULL;
546 tok = strtok(NULL, MULTI_VALUE_SEP))
548 if (strcmp(tok, "all\n") == 0)
549 return true;
550 else if (strcmp(tok, "sameuser\n") == 0)
552 if (strcmp(dbname, role) == 0)
553 return true;
555 else if (strcmp(tok, "samegroup\n") == 0 ||
556 strcmp(tok, "samerole\n") == 0)
558 if (is_member(role, dbname))
559 return true;
561 else if (strcmp(tok, dbname) == 0)
562 return true;
564 return false;
569 * Macros used to check and report on invalid configuration options.
570 * INVALID_AUTH_OPTION = reports when an option is specified for a method where it's
571 * not supported.
572 * REQUIRE_AUTH_OPTION = same as INVALID_AUTH_OPTION, except it also checks if the
573 * method is actually the one specified. Used as a shortcut when
574 * the option is only valid for one authentication method.
575 * MANDATORY_AUTH_ARG = check if a required option is set for an authentication method,
576 * reporting error if it's not.
578 #define INVALID_AUTH_OPTION(optname, validmethods) do {\
579 ereport(LOG, \
580 (errcode(ERRCODE_CONFIG_FILE_ERROR), \
581 /* translator: the second %s is a list of auth methods */ \
582 errmsg("authentication option \"%s\" is only valid for authentication methods %s", \
583 optname, _(validmethods)), \
584 errcontext("line %d of configuration file \"%s\"", \
585 line_num, HbaFileName))); \
586 return false; \
587 } while (0);
589 #define REQUIRE_AUTH_OPTION(methodval, optname, validmethods) do {\
590 if (parsedline->auth_method != methodval) \
591 INVALID_AUTH_OPTION(optname, validmethods); \
592 } while (0);
594 #define MANDATORY_AUTH_ARG(argvar, argname, authname) do {\
595 if (argvar == NULL) {\
596 ereport(LOG, \
597 (errcode(ERRCODE_CONFIG_FILE_ERROR), \
598 errmsg("authentication method \"%s\" requires argument \"%s\" to be set", \
599 authname, argname), \
600 errcontext("line %d of configuration file \"%s\"", \
601 line_num, HbaFileName))); \
602 return false; \
604 } while (0);
608 * Parse one line in the hba config file and store the result in
609 * a HbaLine structure.
611 static bool
612 parse_hba_line(List *line, int line_num, HbaLine *parsedline)
614 char *token;
615 struct addrinfo *gai_result;
616 struct addrinfo hints;
617 int ret;
618 char *cidr_slash;
619 char *unsupauth;
620 ListCell *line_item;
622 line_item = list_head(line);
624 parsedline->linenumber = line_num;
626 /* Check the record type. */
627 token = lfirst(line_item);
628 if (strcmp(token, "local") == 0)
630 parsedline->conntype = ctLocal;
632 else if (strcmp(token, "host") == 0
633 || strcmp(token, "hostssl") == 0
634 || strcmp(token, "hostnossl") == 0)
637 if (token[4] == 's') /* "hostssl" */
639 #ifdef USE_SSL
640 parsedline->conntype = ctHostSSL;
641 #else
642 ereport(LOG,
643 (errcode(ERRCODE_CONFIG_FILE_ERROR),
644 errmsg("hostssl not supported on this platform"),
645 errhint("compile with --enable-ssl to use SSL connections"),
646 errcontext("line %d of configuration file \"%s\"",
647 line_num, HbaFileName)));
648 return false;
649 #endif
651 #ifdef USE_SSL
652 else if (token[4] == 'n') /* "hostnossl" */
654 parsedline->conntype = ctHostNoSSL;
656 #endif
657 else
659 /* "host", or "hostnossl" and SSL support not built in */
660 parsedline->conntype = ctHost;
662 } /* record type */
663 else
665 ereport(LOG,
666 (errcode(ERRCODE_CONFIG_FILE_ERROR),
667 errmsg("invalid connection type \"%s\"",
668 token),
669 errcontext("line %d of configuration file \"%s\"",
670 line_num, HbaFileName)));
671 return false;
674 /* Get the database. */
675 line_item = lnext(line_item);
676 if (!line_item)
678 ereport(LOG,
679 (errcode(ERRCODE_CONFIG_FILE_ERROR),
680 errmsg("end-of-line before database specification"),
681 errcontext("line %d of configuration file \"%s\"",
682 line_num, HbaFileName)));
683 return false;
685 parsedline->database = pstrdup(lfirst(line_item));
687 /* Get the role. */
688 line_item = lnext(line_item);
689 if (!line_item)
691 ereport(LOG,
692 (errcode(ERRCODE_CONFIG_FILE_ERROR),
693 errmsg("end-of-line before role specification"),
694 errcontext("line %d of configuration file \"%s\"",
695 line_num, HbaFileName)));
696 return false;
698 parsedline->role = pstrdup(lfirst(line_item));
700 if (parsedline->conntype != ctLocal)
702 /* Read the IP address field. (with or without CIDR netmask) */
703 line_item = lnext(line_item);
704 if (!line_item)
706 ereport(LOG,
707 (errcode(ERRCODE_CONFIG_FILE_ERROR),
708 errmsg("end-of-line before IP address specification"),
709 errcontext("line %d of configuration file \"%s\"",
710 line_num, HbaFileName)));
711 return false;
713 token = pstrdup(lfirst(line_item));
715 /* Check if it has a CIDR suffix and if so isolate it */
716 cidr_slash = strchr(token, '/');
717 if (cidr_slash)
718 *cidr_slash = '\0';
720 /* Get the IP address either way */
721 hints.ai_flags = AI_NUMERICHOST;
722 hints.ai_family = PF_UNSPEC;
723 hints.ai_socktype = 0;
724 hints.ai_protocol = 0;
725 hints.ai_addrlen = 0;
726 hints.ai_canonname = NULL;
727 hints.ai_addr = NULL;
728 hints.ai_next = NULL;
730 ret = pg_getaddrinfo_all(token, NULL, &hints, &gai_result);
731 if (ret || !gai_result)
733 ereport(LOG,
734 (errcode(ERRCODE_CONFIG_FILE_ERROR),
735 errmsg("invalid IP address \"%s\": %s",
736 token, gai_strerror(ret)),
737 errcontext("line %d of configuration file \"%s\"",
738 line_num, HbaFileName)));
739 if (cidr_slash)
740 *cidr_slash = '/';
741 if (gai_result)
742 pg_freeaddrinfo_all(hints.ai_family, gai_result);
743 return false;
746 if (cidr_slash)
747 *cidr_slash = '/';
749 memcpy(&parsedline->addr, gai_result->ai_addr, gai_result->ai_addrlen);
750 pg_freeaddrinfo_all(hints.ai_family, gai_result);
752 /* Get the netmask */
753 if (cidr_slash)
755 if (pg_sockaddr_cidr_mask(&parsedline->mask, cidr_slash + 1,
756 parsedline->addr.ss_family) < 0)
758 ereport(LOG,
759 (errcode(ERRCODE_CONFIG_FILE_ERROR),
760 errmsg("invalid CIDR mask in address \"%s\"",
761 token),
762 errcontext("line %d of configuration file \"%s\"",
763 line_num, HbaFileName)));
764 return false;
767 else
769 /* Read the mask field. */
770 line_item = lnext(line_item);
771 if (!line_item)
773 ereport(LOG,
774 (errcode(ERRCODE_CONFIG_FILE_ERROR),
775 errmsg("end-of-line before netmask specification"),
776 errcontext("line %d of configuration file \"%s\"",
777 line_num, HbaFileName)));
778 return false;
780 token = lfirst(line_item);
782 ret = pg_getaddrinfo_all(token, NULL, &hints, &gai_result);
783 if (ret || !gai_result)
785 ereport(LOG,
786 (errcode(ERRCODE_CONFIG_FILE_ERROR),
787 errmsg("invalid IP mask \"%s\": %s",
788 token, gai_strerror(ret)),
789 errcontext("line %d of configuration file \"%s\"",
790 line_num, HbaFileName)));
791 if (gai_result)
792 pg_freeaddrinfo_all(hints.ai_family, gai_result);
793 return false;
796 memcpy(&parsedline->mask, gai_result->ai_addr, gai_result->ai_addrlen);
797 pg_freeaddrinfo_all(hints.ai_family, gai_result);
799 if (parsedline->addr.ss_family != parsedline->mask.ss_family)
801 ereport(LOG,
802 (errcode(ERRCODE_CONFIG_FILE_ERROR),
803 errmsg("IP address and mask do not match in file \"%s\" line %d",
804 HbaFileName, line_num)));
805 return false;
808 } /* != ctLocal */
810 /* Get the authentication method */
811 line_item = lnext(line_item);
812 if (!line_item)
814 ereport(LOG,
815 (errcode(ERRCODE_CONFIG_FILE_ERROR),
816 errmsg("end-of-line before authentication method"),
817 errcontext("line %d of configuration file \"%s\"",
818 line_num, HbaFileName)));
819 return false;
821 token = lfirst(line_item);
823 unsupauth = NULL;
824 if (strcmp(token, "trust") == 0)
825 parsedline->auth_method = uaTrust;
826 else if (strcmp(token, "ident") == 0)
827 parsedline->auth_method = uaIdent;
828 else if (strcmp(token, "password") == 0)
829 parsedline->auth_method = uaPassword;
830 else if (strcmp(token, "krb5") == 0)
831 #ifdef KRB5
832 parsedline->auth_method = uaKrb5;
833 #else
834 unsupauth = "krb5";
835 #endif
836 else if (strcmp(token, "gss") == 0)
837 #ifdef ENABLE_GSS
838 parsedline->auth_method = uaGSS;
839 #else
840 unsupauth = "gss";
841 #endif
842 else if (strcmp(token, "sspi") == 0)
843 #ifdef ENABLE_SSPI
844 parsedline->auth_method = uaSSPI;
845 #else
846 unsupauth = "sspi";
847 #endif
848 else if (strcmp(token, "reject") == 0)
849 parsedline->auth_method = uaReject;
850 else if (strcmp(token, "md5") == 0)
852 if (Db_user_namespace)
854 ereport(LOG,
855 (errcode(ERRCODE_CONFIG_FILE_ERROR),
856 errmsg("MD5 authentication is not supported when \"db_user_namespace\" is enabled")));
857 return false;
859 parsedline->auth_method = uaMD5;
861 else if (strcmp(token, "pam") == 0)
862 #ifdef USE_PAM
863 parsedline->auth_method = uaPAM;
864 #else
865 unsupauth = "pam";
866 #endif
867 else if (strcmp(token, "ldap") == 0)
868 #ifdef USE_LDAP
869 parsedline->auth_method = uaLDAP;
870 #else
871 unsupauth = "ldap";
872 #endif
873 else if (strcmp(token, "cert") == 0)
874 #ifdef USE_SSL
875 parsedline->auth_method = uaCert;
876 #else
877 unsupauth = "cert";
878 #endif
879 else
881 ereport(LOG,
882 (errcode(ERRCODE_CONFIG_FILE_ERROR),
883 errmsg("invalid authentication method \"%s\"",
884 token),
885 errcontext("line %d of configuration file \"%s\"",
886 line_num, HbaFileName)));
887 return false;
890 if (unsupauth)
892 ereport(LOG,
893 (errcode(ERRCODE_CONFIG_FILE_ERROR),
894 errmsg("invalid authentication method \"%s\": not supported on this platform",
895 token),
896 errcontext("line %d of configuration file \"%s\"",
897 line_num, HbaFileName)));
898 return false;
901 /* Invalid authentication combinations */
902 if (parsedline->conntype == ctLocal &&
903 parsedline->auth_method == uaKrb5)
905 ereport(LOG,
906 (errcode(ERRCODE_CONFIG_FILE_ERROR),
907 errmsg("krb5 authentication is not supported on local sockets"),
908 errcontext("line %d of configuration file \"%s\"",
909 line_num, HbaFileName)));
910 return false;
913 if (parsedline->conntype != ctHostSSL &&
914 parsedline->auth_method == uaCert)
916 ereport(LOG,
917 (errcode(ERRCODE_CONFIG_FILE_ERROR),
918 errmsg("cert authentication is only supported on hostssl connections"),
919 errcontext("line %d of configuration file \"%s\"",
920 line_num, HbaFileName)));
921 return false;
924 /* Parse remaining arguments */
925 while ((line_item = lnext(line_item)) != NULL)
927 char *c;
929 token = lfirst(line_item);
931 c = strchr(token, '=');
932 if (c == NULL)
935 * Got something that's not a name=value pair.
937 * XXX: attempt to do some backwards compatible parsing here?
939 ereport(LOG,
940 (errcode(ERRCODE_CONFIG_FILE_ERROR),
941 errmsg("authentication option not in name=value format: %s", token),
942 errcontext("line %d of configuration file \"%s\"",
943 line_num, HbaFileName)));
944 return false;
946 else
948 *c++ = '\0'; /* token now holds "name", c holds "value" */
949 if (strcmp(token, "map") == 0)
951 if (parsedline->auth_method != uaIdent &&
952 parsedline->auth_method != uaKrb5 &&
953 parsedline->auth_method != uaGSS &&
954 parsedline->auth_method != uaSSPI &&
955 parsedline->auth_method != uaCert)
956 INVALID_AUTH_OPTION("map", gettext_noop("ident, krb5, gssapi, sspi and cert"));
957 parsedline->usermap = pstrdup(c);
959 else if (strcmp(token, "clientcert") == 0)
962 * Since we require ctHostSSL, this really can never happen on
963 * non-SSL-enabled builds, so don't bother checking for
964 * USE_SSL.
966 if (parsedline->conntype != ctHostSSL)
968 ereport(LOG,
969 (errcode(ERRCODE_CONFIG_FILE_ERROR),
970 errmsg("clientcert can only be configured for \"hostssl\" rows"),
971 errcontext("line %d of configuration file \"%s\"",
972 line_num, HbaFileName)));
973 return false;
975 if (strcmp(c, "1") == 0)
977 if (!secure_loaded_verify_locations())
979 ereport(LOG,
980 (errcode(ERRCODE_CONFIG_FILE_ERROR),
981 errmsg("client certificates can only be checked if a root certificate store is available"),
982 errdetail("make sure the root certificate store is present and readable"),
983 errcontext("line %d of configuration file \"%s\"",
984 line_num, HbaFileName)));
985 return false;
987 parsedline->clientcert = true;
989 else
991 if (parsedline->auth_method == uaCert)
993 ereport(LOG,
994 (errcode(ERRCODE_CONFIG_FILE_ERROR),
995 errmsg("clientcert can not be set to 0 when using \"cert\" authentication"),
996 errcontext("line %d of configuration file \"%s\"",
997 line_num, HbaFileName)));
998 return false;
1000 parsedline->clientcert = false;
1003 else if (strcmp(token, "pamservice") == 0)
1005 REQUIRE_AUTH_OPTION(uaPAM, "pamservice", "pam");
1006 parsedline->pamservice = pstrdup(c);
1008 else if (strcmp(token, "ldaptls") == 0)
1010 REQUIRE_AUTH_OPTION(uaLDAP, "ldaptls", "ldap");
1011 if (strcmp(c, "1") == 0)
1012 parsedline->ldaptls = true;
1013 else
1014 parsedline->ldaptls = false;
1016 else if (strcmp(token, "ldapserver") == 0)
1018 REQUIRE_AUTH_OPTION(uaLDAP, "ldapserver", "ldap");
1019 parsedline->ldapserver = pstrdup(c);
1021 else if (strcmp(token, "ldapport") == 0)
1023 REQUIRE_AUTH_OPTION(uaLDAP, "ldapport", "ldap");
1024 parsedline->ldapport = atoi(c);
1025 if (parsedline->ldapport == 0)
1027 ereport(LOG,
1028 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1029 errmsg("invalid LDAP port number: \"%s\"", c),
1030 errcontext("line %d of configuration file \"%s\"",
1031 line_num, HbaFileName)));
1032 return false;
1035 else if (strcmp(token, "ldapprefix") == 0)
1037 REQUIRE_AUTH_OPTION(uaLDAP, "ldapprefix", "ldap");
1038 parsedline->ldapprefix = pstrdup(c);
1040 else if (strcmp(token, "ldapsuffix") == 0)
1042 REQUIRE_AUTH_OPTION(uaLDAP, "ldapsuffix", "ldap");
1043 parsedline->ldapsuffix = pstrdup(c);
1045 else if (strcmp(token, "krb_server_hostname") == 0)
1047 REQUIRE_AUTH_OPTION(uaKrb5, "krb_server_hostname", "krb5");
1048 parsedline->krb_server_hostname = pstrdup(c);
1050 else if (strcmp(token, "krb_realm") == 0)
1052 if (parsedline->auth_method != uaKrb5 &&
1053 parsedline->auth_method != uaGSS &&
1054 parsedline->auth_method != uaSSPI)
1055 INVALID_AUTH_OPTION("krb_realm", gettext_noop("krb5, gssapi and sspi"));
1056 parsedline->krb_realm = pstrdup(c);
1058 else if (strcmp(token, "include_realm") == 0)
1060 if (parsedline->auth_method != uaKrb5 &&
1061 parsedline->auth_method != uaGSS &&
1062 parsedline->auth_method != uaSSPI)
1063 INVALID_AUTH_OPTION("include_realm", gettext_noop("krb5, gssapi and sspi"));
1064 if (strcmp(c, "1") == 0)
1065 parsedline->include_realm = true;
1066 else
1067 parsedline->include_realm = false;
1069 else
1071 ereport(LOG,
1072 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1073 errmsg("unknown authentication option name: \"%s\"", token),
1074 errcontext("line %d of configuration file \"%s\"",
1075 line_num, HbaFileName)));
1076 return false;
1082 * Check if the selected authentication method has any mandatory arguments
1083 * that are not set.
1085 if (parsedline->auth_method == uaLDAP)
1087 MANDATORY_AUTH_ARG(parsedline->ldapserver, "ldapserver", "ldap");
1091 * Enforce any parameters implied by other settings.
1093 if (parsedline->auth_method == uaCert)
1095 parsedline->clientcert = true;
1098 return true;
1103 * Scan the (pre-parsed) hba file line by line, looking for a match
1104 * to the port's connection request.
1106 static bool
1107 check_hba(hbaPort *port)
1109 ListCell *line;
1110 HbaLine *hba;
1112 foreach(line, parsed_hba_lines)
1114 hba = (HbaLine *) lfirst(line);
1116 /* Check connection type */
1117 if (hba->conntype == ctLocal)
1119 if (!IS_AF_UNIX(port->raddr.addr.ss_family))
1120 continue;
1122 else
1124 if (IS_AF_UNIX(port->raddr.addr.ss_family))
1125 continue;
1127 /* Check SSL state */
1128 #ifdef USE_SSL
1129 if (port->ssl)
1131 /* Connection is SSL, match both "host" and "hostssl" */
1132 if (hba->conntype == ctHostNoSSL)
1133 continue;
1135 else
1137 /* Connection is not SSL, match both "host" and "hostnossl" */
1138 if (hba->conntype == ctHostSSL)
1139 continue;
1141 #else
1142 /* No SSL support, so reject "hostssl" lines */
1143 if (hba->conntype == ctHostSSL)
1144 continue;
1145 #endif
1147 /* Check IP address */
1148 if (port->raddr.addr.ss_family == hba->addr.ss_family)
1150 if (!pg_range_sockaddr(&port->raddr.addr, &hba->addr, &hba->mask))
1151 continue;
1153 #ifdef HAVE_IPV6
1154 else if (hba->addr.ss_family == AF_INET &&
1155 port->raddr.addr.ss_family == AF_INET6)
1158 * Wrong address family. We allow only one case: if the file
1159 * has IPv4 and the port is IPv6, promote the file address to
1160 * IPv6 and try to match that way.
1162 struct sockaddr_storage addrcopy,
1163 maskcopy;
1165 memcpy(&addrcopy, &hba->addr, sizeof(addrcopy));
1166 memcpy(&maskcopy, &hba->mask, sizeof(maskcopy));
1167 pg_promote_v4_to_v6_addr(&addrcopy);
1168 pg_promote_v4_to_v6_mask(&maskcopy);
1170 if (!pg_range_sockaddr(&port->raddr.addr, &addrcopy, &maskcopy))
1171 continue;
1173 #endif /* HAVE_IPV6 */
1174 else
1175 /* Wrong address family, no IPV6 */
1176 continue;
1177 } /* != ctLocal */
1179 /* Check database and role */
1180 if (!check_db(port->database_name, port->user_name, hba->database))
1181 continue;
1183 if (!check_role(port->user_name, hba->role))
1184 continue;
1186 /* Found a record that matched! */
1187 port->hba = hba;
1188 return true;
1191 /* If no matching entry was found, synthesize 'reject' entry. */
1192 hba = palloc0(sizeof(HbaLine));
1193 hba->auth_method = uaReject;
1194 port->hba = hba;
1195 return true;
1198 * XXX: Return false only happens if we have a parsing error, which we can
1199 * no longer have (parsing now in postmaster). Consider changing API.
1205 * Load role/password mapping file
1207 void
1208 load_role(void)
1210 char *filename;
1211 FILE *role_file;
1213 /* Discard any old data */
1214 if (role_lines || role_line_nums)
1215 free_lines(&role_lines, &role_line_nums);
1216 if (role_sorted)
1217 pfree(role_sorted);
1218 role_sorted = NULL;
1219 role_length = 0;
1221 /* Read in the file contents */
1222 filename = auth_getflatfilename();
1223 role_file = AllocateFile(filename, "r");
1225 if (role_file == NULL)
1227 /* no complaint if not there */
1228 if (errno != ENOENT)
1229 ereport(LOG,
1230 (errcode_for_file_access(),
1231 errmsg("could not open file \"%s\": %m", filename)));
1232 pfree(filename);
1233 return;
1236 tokenize_file(filename, role_file, &role_lines, &role_line_nums);
1238 FreeFile(role_file);
1239 pfree(filename);
1241 /* create array for binary searching */
1242 role_length = list_length(role_lines);
1243 if (role_length)
1245 int i = 0;
1246 ListCell *line;
1248 /* We assume the flat file was written already-sorted */
1249 role_sorted = palloc(role_length * sizeof(List *));
1250 foreach(line, role_lines)
1251 role_sorted[i++] = lfirst(line);
1256 * Free the contents of a hba record
1258 static void
1259 free_hba_record(HbaLine *record)
1261 if (record->database)
1262 pfree(record->database);
1263 if (record->role)
1264 pfree(record->role);
1265 if (record->pamservice)
1266 pfree(record->pamservice);
1267 if (record->ldapserver)
1268 pfree(record->ldapserver);
1269 if (record->ldapprefix)
1270 pfree(record->ldapprefix);
1271 if (record->ldapsuffix)
1272 pfree(record->ldapsuffix);
1273 if (record->krb_server_hostname)
1274 pfree(record->krb_server_hostname);
1275 if (record->krb_realm)
1276 pfree(record->krb_realm);
1280 * Free all records on the parsed HBA list
1282 static void
1283 clean_hba_list(List *lines)
1285 ListCell *line;
1287 foreach(line, lines)
1289 HbaLine *parsed = (HbaLine *) lfirst(line);
1291 if (parsed)
1292 free_hba_record(parsed);
1294 list_free(lines);
1298 * Read the config file and create a List of HbaLine records for the contents.
1300 * The configuration is read into a temporary list, and if any parse error occurs
1301 * the old list is kept in place and false is returned. Only if the whole file
1302 * parses Ok is the list replaced, and the function returns true.
1304 bool
1305 load_hba(void)
1307 FILE *file;
1308 List *hba_lines = NIL;
1309 List *hba_line_nums = NIL;
1310 ListCell *line,
1311 *line_num;
1312 List *new_parsed_lines = NIL;
1313 bool ok = true;
1315 file = AllocateFile(HbaFileName, "r");
1316 if (file == NULL)
1318 ereport(LOG,
1319 (errcode_for_file_access(),
1320 errmsg("could not open configuration file \"%s\": %m",
1321 HbaFileName)));
1324 * Caller will take care of making this a FATAL error in case this is
1325 * the initial startup. If it happens on reload, we just keep the old
1326 * version around.
1328 return false;
1331 tokenize_file(HbaFileName, file, &hba_lines, &hba_line_nums);
1332 FreeFile(file);
1334 /* Now parse all the lines */
1335 forboth(line, hba_lines, line_num, hba_line_nums)
1337 HbaLine *newline;
1339 newline = palloc0(sizeof(HbaLine));
1341 if (!parse_hba_line(lfirst(line), lfirst_int(line_num), newline))
1343 /* Parse error in the file, so indicate there's a problem */
1344 free_hba_record(newline);
1345 pfree(newline);
1348 * Keep parsing the rest of the file so we can report errors on
1349 * more than the first row. Error has already been reported in the
1350 * parsing function, so no need to log it here.
1352 ok = false;
1353 continue;
1356 new_parsed_lines = lappend(new_parsed_lines, newline);
1359 if (!ok)
1361 /* Parsing failed at one or more rows, so bail out */
1362 clean_hba_list(new_parsed_lines);
1363 return false;
1366 /* Loaded new file successfully, replace the one we use */
1367 clean_hba_list(parsed_hba_lines);
1368 parsed_hba_lines = new_parsed_lines;
1370 /* Free the temporary lists */
1371 free_lines(&hba_lines, &hba_line_nums);
1373 return true;
1377 * Read and parse one line from the flat pg_database file.
1379 * Returns TRUE on success, FALSE if EOF; bad data causes elog(FATAL).
1381 * Output parameters:
1382 * dbname: gets database name (must be of size NAMEDATALEN bytes)
1383 * dboid: gets database OID
1384 * dbtablespace: gets database's default tablespace's OID
1385 * dbfrozenxid: gets database's frozen XID
1387 * This is not much related to the other functions in hba.c, but we put it
1388 * here because it uses the next_token() infrastructure.
1390 bool
1391 read_pg_database_line(FILE *fp, char *dbname, Oid *dboid,
1392 Oid *dbtablespace, TransactionId *dbfrozenxid)
1394 char buf[MAX_TOKEN];
1396 if (feof(fp))
1397 return false;
1398 if (!next_token(fp, buf, sizeof(buf)))
1399 return false;
1400 if (strlen(buf) >= NAMEDATALEN)
1401 elog(FATAL, "bad data in flat pg_database file");
1402 strcpy(dbname, buf);
1403 next_token(fp, buf, sizeof(buf));
1404 if (!isdigit((unsigned char) buf[0]))
1405 elog(FATAL, "bad data in flat pg_database file");
1406 *dboid = atooid(buf);
1407 next_token(fp, buf, sizeof(buf));
1408 if (!isdigit((unsigned char) buf[0]))
1409 elog(FATAL, "bad data in flat pg_database file");
1410 *dbtablespace = atooid(buf);
1411 next_token(fp, buf, sizeof(buf));
1412 if (!isdigit((unsigned char) buf[0]))
1413 elog(FATAL, "bad data in flat pg_database file");
1414 *dbfrozenxid = atoxid(buf);
1415 /* expect EOL next */
1416 if (next_token(fp, buf, sizeof(buf)))
1417 elog(FATAL, "bad data in flat pg_database file");
1418 return true;
1422 * Process one line from the ident config file.
1424 * Take the line and compare it to the needed map, pg_role and ident_user.
1425 * *found_p and *error_p are set according to our results.
1427 static void
1428 parse_ident_usermap(List *line, int line_number, const char *usermap_name,
1429 const char *pg_role, const char *ident_user,
1430 bool case_insensitive, bool *found_p, bool *error_p)
1432 ListCell *line_item;
1433 char *token;
1434 char *file_map;
1435 char *file_pgrole;
1436 char *file_ident_user;
1438 *found_p = false;
1439 *error_p = false;
1441 Assert(line != NIL);
1442 line_item = list_head(line);
1444 /* Get the map token (must exist) */
1445 token = lfirst(line_item);
1446 file_map = token;
1448 /* Get the ident user token */
1449 line_item = lnext(line_item);
1450 if (!line_item)
1451 goto ident_syntax;
1452 token = lfirst(line_item);
1453 file_ident_user = token;
1455 /* Get the PG rolename token */
1456 line_item = lnext(line_item);
1457 if (!line_item)
1458 goto ident_syntax;
1459 token = lfirst(line_item);
1460 file_pgrole = token;
1462 if (strcmp(file_map, usermap_name) != 0)
1463 /* Line does not match the map name we're looking for, so just abort */
1464 return;
1466 /* Match? */
1467 if (file_ident_user[0] == '/')
1470 * When system username starts with a slash, treat it as a regular
1471 * expression. In this case, we process the system username as a
1472 * regular expression that returns exactly one match. This is replaced
1473 * for \1 in the database username string, if present.
1475 int r;
1476 regex_t re;
1477 regmatch_t matches[2];
1478 pg_wchar *wstr;
1479 int wlen;
1480 char *ofs;
1481 char *regexp_pgrole;
1483 wstr = palloc((strlen(file_ident_user + 1) + 1) * sizeof(pg_wchar));
1484 wlen = pg_mb2wchar_with_len(file_ident_user + 1, wstr, strlen(file_ident_user + 1));
1487 * XXX: Major room for optimization: regexps could be compiled when
1488 * the file is loaded and then re-used in every connection.
1490 r = pg_regcomp(&re, wstr, wlen, REG_ADVANCED);
1491 if (r)
1493 char errstr[100];
1495 pg_regerror(r, &re, errstr, sizeof(errstr));
1496 ereport(ERROR,
1497 (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
1498 errmsg("invalid regular expression \"%s\": %s", file_ident_user + 1, errstr)));
1500 pfree(wstr);
1501 *error_p = true;
1502 return;
1504 pfree(wstr);
1506 wstr = palloc((strlen(ident_user) + 1) * sizeof(pg_wchar));
1507 wlen = pg_mb2wchar_with_len(ident_user, wstr, strlen(ident_user));
1509 r = pg_regexec(&re, wstr, wlen, 0, NULL, 2, matches, 0);
1510 if (r)
1512 char errstr[100];
1514 if (r != REG_NOMATCH)
1516 /* REG_NOMATCH is not an error, everything else is */
1517 pg_regerror(r, &re, errstr, sizeof(errstr));
1518 ereport(ERROR,
1519 (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
1520 errmsg("regular expression match for \"%s\" failed: %s", file_ident_user + 1, errstr)));
1521 *error_p = true;
1524 pfree(wstr);
1525 pg_regfree(&re);
1526 return;
1528 pfree(wstr);
1530 if ((ofs = strstr(file_pgrole, "\\1")) != NULL)
1532 /* substitution of the first argument requested */
1533 if (matches[1].rm_so < 0)
1534 ereport(ERROR,
1535 (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
1536 errmsg("regular expression \"%s\" has no subexpressions as requested by backreference in \"%s\"",
1537 file_ident_user + 1, file_pgrole)));
1540 * length: original length minus length of \1 plus length of match
1541 * plus null terminator
1543 regexp_pgrole = palloc0(strlen(file_pgrole) - 2 + (matches[1].rm_eo - matches[1].rm_so) + 1);
1544 strncpy(regexp_pgrole, file_pgrole, (ofs - file_pgrole));
1545 memcpy(regexp_pgrole + strlen(regexp_pgrole),
1546 ident_user + matches[1].rm_so,
1547 matches[1].rm_eo - matches[1].rm_so);
1548 strcat(regexp_pgrole, ofs + 2);
1550 else
1552 /* no substitution, so copy the match */
1553 regexp_pgrole = pstrdup(file_pgrole);
1556 pg_regfree(&re);
1559 * now check if the username actually matched what the user is trying
1560 * to connect as
1562 if (case_insensitive)
1564 if (pg_strcasecmp(regexp_pgrole, pg_role) == 0)
1565 *found_p = true;
1567 else
1569 if (strcmp(regexp_pgrole, pg_role) == 0)
1570 *found_p = true;
1572 pfree(regexp_pgrole);
1574 return;
1576 else
1578 /* Not regular expression, so make complete match */
1579 if (case_insensitive)
1581 if (pg_strcasecmp(file_pgrole, pg_role) == 0 &&
1582 pg_strcasecmp(file_ident_user, ident_user) == 0)
1583 *found_p = true;
1585 else
1587 if (strcmp(file_pgrole, pg_role) == 0 &&
1588 strcmp(file_ident_user, ident_user) == 0)
1589 *found_p = true;
1593 return;
1595 ident_syntax:
1596 ereport(LOG,
1597 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1598 errmsg("missing entry in file \"%s\" at end of line %d",
1599 IdentFileName, line_number)));
1600 *error_p = true;
1605 * Scan the (pre-parsed) ident usermap file line by line, looking for a match
1607 * See if the user with ident username "ident_user" is allowed to act
1608 * as Postgres user "pgrole" according to usermap "usermap_name".
1610 * Special case: Usermap NULL, equivalent to what was previously called
1611 * "sameuser" or "samerole", don't look in the usermap
1612 * file. That's an implied map where "pgrole" must be identical to
1613 * "ident_user" in order to be authorized.
1615 * Iff authorized, return STATUS_OK, otherwise return STATUS_ERROR.
1618 check_usermap(const char *usermap_name,
1619 const char *pg_role,
1620 const char *auth_user,
1621 bool case_insensitive)
1623 bool found_entry = false,
1624 error = false;
1626 if (usermap_name == NULL || usermap_name[0] == '\0')
1628 if (case_insensitive)
1630 if (pg_strcasecmp(pg_role, auth_user) == 0)
1631 return STATUS_OK;
1633 else
1635 if (strcmp(pg_role, auth_user) == 0)
1636 return STATUS_OK;
1638 ereport(LOG,
1639 (errmsg("provided username (%s) and authenticated username (%s) don't match",
1640 auth_user, pg_role)));
1641 return STATUS_ERROR;
1643 else
1645 ListCell *line_cell,
1646 *num_cell;
1648 forboth(line_cell, ident_lines, num_cell, ident_line_nums)
1650 parse_ident_usermap(lfirst(line_cell), lfirst_int(num_cell),
1651 usermap_name, pg_role, auth_user, case_insensitive,
1652 &found_entry, &error);
1653 if (found_entry || error)
1654 break;
1657 if (!found_entry && !error)
1659 ereport(LOG,
1660 (errmsg("no match in usermap for user \"%s\" authenticated as \"%s\"",
1661 pg_role, auth_user),
1662 errcontext("usermap \"%s\"", usermap_name)));
1664 return found_entry ? STATUS_OK : STATUS_ERROR;
1669 * Read the ident config file and create a List of Lists of tokens in the file.
1671 void
1672 load_ident(void)
1674 FILE *file;
1676 if (ident_lines || ident_line_nums)
1677 free_lines(&ident_lines, &ident_line_nums);
1679 file = AllocateFile(IdentFileName, "r");
1680 if (file == NULL)
1682 /* not fatal ... we just won't do any special ident maps */
1683 ereport(LOG,
1684 (errcode_for_file_access(),
1685 errmsg("could not open Ident usermap file \"%s\": %m",
1686 IdentFileName)));
1688 else
1690 tokenize_file(IdentFileName, file, &ident_lines, &ident_line_nums);
1691 FreeFile(file);
1698 * Determine what authentication method should be used when accessing database
1699 * "database" from frontend "raddr", user "user". Return the method and
1700 * an optional argument (stored in fields of *port), and STATUS_OK.
1702 * Note that STATUS_ERROR indicates a problem with the hba config file.
1703 * If the file is OK but does not contain any entry matching the request,
1704 * we return STATUS_OK and method = uaReject.
1707 hba_getauthmethod(hbaPort *port)
1709 if (check_hba(port))
1710 return STATUS_OK;
1711 else
1712 return STATUS_ERROR;