1 /*-------------------------------------------------------------------------
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-2008, PostgreSQL Global Development Group
9 * Portions Copyright (c) 1994, Regents of the University of California
13 * $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.175 2008/11/20 20:45:30 momjian Exp $
15 *-------------------------------------------------------------------------
22 #include <sys/param.h>
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
29 #include "libpq/libpq.h"
30 #include "storage/fd.h"
31 #include "utils/flatfiles.h"
32 #include "utils/guc.h"
36 #define atooid(x) ((Oid) strtoul((x), NULL, 10))
37 #define atoxid(x) ((TransactionId) strtoul((x), NULL, 10))
39 /* This is used to separate values in multi-valued column strings */
40 #define MULTI_VALUE_SEP "\001"
44 /* pre-parsed content of HBA config file */
45 static List *parsed_hba_lines = NIL;
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.
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;
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;
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;
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);
76 * isblank() exists in the ISO C99 spec, but it's not very portable yet,
77 * so provide our own version.
80 pg_isblank(const char c)
82 return c == ' ' || c == '\t' || c == '\r';
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).
92 * The token, if any, is returned at *buf (a buffer of size bufsz).
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.
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.
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
107 next_token(FILE *fp, char *buf, int bufsz)
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;
116 Assert(end_buf > start_buf);
118 /* Move over initial whitespace and commas */
119 while ((c = getc(fp)) != EOF && (pg_isblank(c) || c == ','))
122 if (c == EOF || c == '\n')
129 * Build a token in buf of next characters up to EOF, EOL, unquoted comma,
130 * or unquoted whitespace.
132 while (c != EOF && c != '\n' &&
133 (!pg_isblank(c) || in_quote))
135 /* skip comments to EOL */
136 if (c == '#' && !in_quote)
138 while ((c = getc(fp)) != EOF && c != '\n')
140 /* If only comment, consume EOL too; return EOL */
141 if (c != EOF && buf == start_buf)
150 (errcode(ERRCODE_CONFIG_FILE_ERROR),
151 errmsg("authentication file token too long, skipping: \"%s\"",
153 /* Discard remainder of line */
154 while ((c = getc(fp)) != EOF && c != '\n')
159 if (c != '"' || was_quote)
162 /* We pass back the comma so the caller knows there is more */
163 if (c == ',' && !in_quote)
166 /* Literal double-quote is two double-quotes */
167 if (in_quote && c == '"')
168 was_quote = !was_quote;
174 in_quote = !in_quote;
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).
191 (strcmp(start_buf, "all") == 0 ||
192 strcmp(start_buf, "sameuser") == 0 ||
193 strcmp(start_buf, "samegroup") == 0 ||
194 strcmp(start_buf, "samerole") == 0))
196 /* append newline to a magical keyword */
201 return (saw_quote || buf > start_buf);
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.
209 * The result is a palloc'd string, or NULL if we have reached EOL.
212 next_token_expand(const char *filename, FILE *file)
215 char *comma_str = pstrdup("");
216 bool got_something = false;
223 if (!next_token(file, buf, sizeof(buf)))
226 got_something = true;
228 if (strlen(buf) > 0 && buf[strlen(buf) - 1] == ',')
230 trailing_comma = true;
231 buf[strlen(buf) - 1] = '\0';
234 trailing_comma = false;
236 /* Is this referencing a file? */
238 incbuf = tokenize_inc_file(filename, buf + 1);
240 incbuf = pstrdup(buf);
242 needed = strlen(comma_str) + strlen(incbuf) + 1;
245 comma_str = repalloc(comma_str, needed);
246 strcat(comma_str, incbuf);
248 strcat(comma_str, MULTI_VALUE_SEP);
250 } while (trailing_comma);
263 * Free memory used by lines/tokens (i.e., structure built by tokenize_file)
266 free_lines(List **lines, List **line_nums)
269 * Either both must be non-NULL, or both must be NULL
271 Assert((*lines != NIL && *line_nums != NIL) ||
272 (*lines == NIL && *line_nums == NIL));
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
284 foreach(line, *lines)
286 List *ln = lfirst(line);
290 pfree(lfirst(token));
291 /* free the sublist structure itself */
294 /* free the list structure itself */
296 /* clear the static variable */
302 list_free(*line_nums);
309 tokenize_inc_file(const char *outer_filename,
310 const char *inc_filename)
319 if (is_absolute_path(inc_filename))
321 /* absolute path is taken as-is */
322 inc_fullname = pstrdup(inc_filename);
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);
335 inc_file = AllocateFile(inc_fullname, "r");
336 if (inc_file == NULL)
339 (errcode_for_file_access(),
340 errmsg("could not open secondary authentication file \"@%s\" as \"%s\": %m",
341 inc_filename, inc_fullname)));
344 /* return single space, it matches nothing */
348 /* There is possible recursion here if the file contains @ */
349 tokenize_file(inc_fullname, inc_file, &inc_lines, &inc_line_nums);
354 /* Create comma-separated string from List */
355 comma_str = pstrdup("");
356 foreach(line, inc_lines)
358 List *token_list = (List *) lfirst(line);
361 foreach(token, token_list)
363 int oldlen = strlen(comma_str);
366 needed = oldlen + strlen(lfirst(token)) + 1;
369 comma_str = repalloc(comma_str, needed);
371 strcat(comma_str, MULTI_VALUE_SEP);
372 strcat(comma_str, lfirst(token));
376 free_lines(&inc_lines, &inc_line_nums);
378 /* if file is empty, return single space rather than empty string */
379 if (strlen(comma_str) == 0)
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.
394 * filename must be the absolute path to the target file.
397 tokenize_file(const char *filename, FILE *file,
398 List **lines, List **line_nums)
400 List *current_line = NIL;
404 *lines = *line_nums = NIL;
408 buf = next_token_expand(filename, file);
410 /* add token to list, unless we are at EOL or comment start */
413 if (current_line == NIL)
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);
422 /* append token to current line's list */
423 current_line = lappend(current_line, buf);
428 /* we are at real or logical EOL, so force a new line List */
430 /* Advance line number whenever we reach EOL */
437 * Compare two lines based on their role/member names.
439 * Used for bsearch() lookup.
442 role_bsearch_cmp(const void *role, const void *list)
444 char *role2 = linitial(*(List **) list);
446 return strcmp(role, role2);
451 * Lookup a role name in the pg_auth file
454 get_role_line(const char *role)
456 /* On some versions of Solaris, bsearch of zero items dumps core */
457 if (role_length == 0)
460 return (List **) bsearch((void *) role,
461 (void *) role_sorted,
469 * Does user belong to role?
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.
475 is_member(const char *user, const char *role)
480 if ((line = get_role_line(user)) == NULL)
481 return false; /* if user not exist, say "no" */
483 /* A user always belongs to its own role */
484 if (strcmp(user, role) == 0)
488 * skip over the role name, password, valuntil, examine all the membership
491 if (list_length(*line) < 4)
493 for_each_cell(line_item, lnext(lnext(lnext(list_head(*line)))))
495 if (strcmp((char *) lfirst(line_item), role) == 0)
503 * Check comma-separated list for a match to role, allowing group names.
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.
510 check_role(const char *role, char *param_str)
514 for (tok = strtok(param_str, MULTI_VALUE_SEP);
516 tok = strtok(NULL, MULTI_VALUE_SEP))
520 if (is_member(role, tok + 1))
523 else if (strcmp(tok, role) == 0 ||
524 strcmp(tok, "all\n") == 0)
532 * Check to see if db/role combination matches param string.
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.
539 check_db(const char *dbname, const char *role, char *param_str)
543 for (tok = strtok(param_str, MULTI_VALUE_SEP);
545 tok = strtok(NULL, MULTI_VALUE_SEP))
547 if (strcmp(tok, "all\n") == 0)
549 else if (strcmp(tok, "sameuser\n") == 0)
551 if (strcmp(dbname, role) == 0)
554 else if (strcmp(tok, "samegroup\n") == 0 ||
555 strcmp(tok, "samerole\n") == 0)
557 if (is_member(role, dbname))
560 else if (strcmp(tok, dbname) == 0)
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
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.
577 #define INVALID_AUTH_OPTION(optname, validmethods) do {\
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))); \
587 #define REQUIRE_AUTH_OPTION(methodval, optname, validmethods) do {\
588 if (parsedline->auth_method != methodval) \
589 INVALID_AUTH_OPTION("ldaptls", "ldap"); \
592 #define MANDATORY_AUTH_ARG(argvar, argname, authname) do {\
593 if (argvar == NULL) {\
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))); \
606 * Parse one line in the hba config file and store the result in
607 * a HbaLine structure.
610 parse_hba_line(List *line, int line_num, HbaLine *parsedline)
613 struct addrinfo *gai_result;
614 struct addrinfo hints;
620 line_item = list_head(line);
622 parsedline->linenumber = line_num;
624 /* Check the record type. */
625 token = lfirst(line_item);
626 if (strcmp(token, "local") == 0)
628 parsedline->conntype = ctLocal;
630 else if (strcmp(token, "host") == 0
631 || strcmp(token, "hostssl") == 0
632 || strcmp(token, "hostnossl") == 0)
635 if (token[4] == 's') /* "hostssl" */
638 parsedline->conntype = ctHostSSL;
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)));
650 else if (token[4] == 'n') /* "hostnossl" */
652 parsedline->conntype = ctHostNoSSL;
657 /* "host", or "hostnossl" and SSL support not built in */
658 parsedline->conntype = ctHost;
664 (errcode(ERRCODE_CONFIG_FILE_ERROR),
665 errmsg("invalid connection type \"%s\"",
667 errcontext("line %d of configuration file \"%s\"",
668 line_num, HbaFileName)));
672 /* Get the database. */
673 line_item = lnext(line_item);
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)));
683 parsedline->database = pstrdup(lfirst(line_item));
686 line_item = lnext(line_item);
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)));
696 parsedline->role = pstrdup(lfirst(line_item));
698 if (parsedline->conntype != ctLocal)
700 /* Read the IP address field. (with or without CIDR netmask) */
701 line_item = lnext(line_item);
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)));
711 token = pstrdup(lfirst(line_item));
713 /* Check if it has a CIDR suffix and if so isolate it */
714 cidr_slash = strchr(token, '/');
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;
728 ret = pg_getaddrinfo_all(token, NULL, &hints, &gai_result);
729 if (ret || !gai_result)
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)));
740 pg_freeaddrinfo_all(hints.ai_family, gai_result);
747 memcpy(&parsedline->addr, gai_result->ai_addr, gai_result->ai_addrlen);
748 pg_freeaddrinfo_all(hints.ai_family, gai_result);
750 /* Get the netmask */
753 if (pg_sockaddr_cidr_mask(&parsedline->mask, cidr_slash + 1,
754 parsedline->addr.ss_family) < 0)
757 (errcode(ERRCODE_CONFIG_FILE_ERROR),
758 errmsg("invalid CIDR mask in address \"%s\"",
760 errcontext("line %d of configuration file \"%s\"",
761 line_num, HbaFileName)));
767 /* Read the mask field. */
768 line_item = lnext(line_item);
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)));
778 token = lfirst(line_item);
780 ret = pg_getaddrinfo_all(token, NULL, &hints, &gai_result);
781 if (ret || !gai_result)
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)));
790 pg_freeaddrinfo_all(hints.ai_family, gai_result);
794 memcpy(&parsedline->mask, gai_result->ai_addr, gai_result->ai_addrlen);
795 pg_freeaddrinfo_all(hints.ai_family, gai_result);
797 if (parsedline->addr.ss_family != parsedline->mask.ss_family)
800 (errcode(ERRCODE_CONFIG_FILE_ERROR),
801 errmsg("IP address and mask do not match in file \"%s\" line %d",
802 HbaFileName, line_num)));
808 /* Get the authentication method */
809 line_item = lnext(line_item);
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)));
819 token = lfirst(line_item);
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)
830 parsedline->auth_method = uaKrb5;
834 else if (strcmp(token, "gss") == 0)
836 parsedline->auth_method = uaGSS;
840 else if (strcmp(token, "sspi") == 0)
842 parsedline->auth_method = uaSSPI;
846 else if (strcmp(token, "reject") == 0)
847 parsedline->auth_method = uaReject;
848 else if (strcmp(token, "md5") == 0)
850 if (Db_user_namespace)
853 (errcode(ERRCODE_CONFIG_FILE_ERROR),
854 errmsg("MD5 authentication is not supported when \"db_user_namespace\" is enabled")));
857 parsedline->auth_method = uaMD5;
859 else if (strcmp(token, "pam") == 0)
861 parsedline->auth_method = uaPAM;
865 else if (strcmp(token, "ldap") == 0)
867 parsedline->auth_method = uaLDAP;
871 else if (strcmp(token, "cert") == 0)
873 parsedline->auth_method = uaCert;
880 (errcode(ERRCODE_CONFIG_FILE_ERROR),
881 errmsg("invalid authentication method \"%s\"",
883 errcontext("line %d of configuration file \"%s\"",
884 line_num, HbaFileName)));
891 (errcode(ERRCODE_CONFIG_FILE_ERROR),
892 errmsg("invalid authentication method \"%s\": not supported on this platform",
894 errcontext("line %d of configuration file \"%s\"",
895 line_num, HbaFileName)));
899 /* Invalid authentication combinations */
900 if (parsedline->conntype == ctLocal &&
901 parsedline->auth_method == uaKrb5)
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)));
911 if (parsedline->conntype != ctHostSSL &&
912 parsedline->auth_method == uaCert)
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)));
922 /* Parse remaining arguments */
923 while ((line_item = lnext(line_item)) != NULL)
927 token = lfirst(line_item);
929 c = strchr(token, '=');
933 * Got something that's not a name=value pair.
935 * XXX: attempt to do some backwards compatible parsing here?
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)));
946 *c++ = '\0'; /* token now holds "name", c holds "value" */
947 if (strcmp(token, "map") == 0)
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);
957 else if (strcmp(token, "clientcert") == 0)
960 * Since we require ctHostSSL, this really can never happen on non-SSL-enabled
961 * builds, so don't bother checking for USE_SSL.
963 if (parsedline->conntype != ctHostSSL)
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)));
972 if (strcmp(c, "1") == 0)
974 if (!secure_loaded_verify_locations())
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)));
984 parsedline->clientcert = true;
988 if (parsedline->auth_method == uaCert)
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)));
997 parsedline->clientcert = false;
1000 else if (strcmp(token, "pamservice") == 0)
1002 REQUIRE_AUTH_OPTION(uaPAM, "pamservice", "pam");
1003 parsedline->pamservice = pstrdup(c);
1005 else if (strcmp(token, "ldaptls") == 0)
1007 REQUIRE_AUTH_OPTION(uaLDAP, "ldaptls", "ldap");
1008 if (strcmp(c, "1") == 0)
1009 parsedline->ldaptls = true;
1011 parsedline->ldaptls = false;
1013 else if (strcmp(token, "ldapserver") == 0)
1015 REQUIRE_AUTH_OPTION(uaLDAP, "ldapserver", "ldap");
1016 parsedline->ldapserver = pstrdup(c);
1018 else if (strcmp(token, "ldapport") == 0)
1020 REQUIRE_AUTH_OPTION(uaLDAP, "ldapport", "ldap");
1021 parsedline->ldapport = atoi(c);
1022 if (parsedline->ldapport == 0)
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)));
1032 else if (strcmp(token, "ldapprefix") == 0)
1034 REQUIRE_AUTH_OPTION(uaLDAP, "ldapprefix", "ldap");
1035 parsedline->ldapprefix = pstrdup(c);
1037 else if (strcmp(token, "ldapsuffix") == 0)
1039 REQUIRE_AUTH_OPTION(uaLDAP, "ldapsuffix", "ldap");
1040 parsedline->ldapsuffix = pstrdup(c);
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)));
1055 * Check if the selected authentication method has any mandatory arguments that
1058 if (parsedline->auth_method == uaLDAP)
1060 MANDATORY_AUTH_ARG(parsedline->ldapserver, "ldapserver", "ldap");
1064 * Enforce any parameters implied by other settings.
1066 if (parsedline->auth_method == uaCert)
1068 parsedline->clientcert = true;
1076 * Scan the (pre-parsed) hba file line by line, looking for a match
1077 * to the port's connection request.
1080 check_hba(hbaPort *port)
1085 foreach(line, parsed_hba_lines)
1087 hba = (HbaLine *) lfirst(line);
1089 /* Check connection type */
1090 if (hba->conntype == ctLocal)
1092 if (!IS_AF_UNIX(port->raddr.addr.ss_family))
1097 if (IS_AF_UNIX(port->raddr.addr.ss_family))
1100 /* Check SSL state */
1104 /* Connection is SSL, match both "host" and "hostssl" */
1105 if (hba->conntype == ctHostNoSSL)
1110 /* Connection is not SSL, match both "host" and "hostnossl" */
1111 if (hba->conntype == ctHostSSL)
1115 /* No SSL support, so reject "hostssl" lines */
1116 if (hba->conntype == ctHostSSL)
1120 /* Check IP address */
1121 if (port->raddr.addr.ss_family == hba->addr.ss_family)
1123 if (!pg_range_sockaddr(&port->raddr.addr, &hba->addr, &hba->mask))
1127 else if (hba->addr.ss_family == AF_INET &&
1128 port->raddr.addr.ss_family == AF_INET6)
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.
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);
1141 if (!pg_range_sockaddr(&port->raddr.addr, &addrcopy, &maskcopy))
1144 #endif /* HAVE_IPV6 */
1146 /* Wrong address family, no IPV6 */
1150 /* Check database and role */
1151 if (!check_db(port->database_name, port->user_name, hba->database))
1154 if (!check_role(port->user_name, hba->role))
1157 /* Found a record that matched! */
1162 /* If no matching entry was found, synthesize 'reject' entry. */
1163 hba = palloc0(sizeof(HbaLine));
1164 hba->auth_method = uaReject;
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.
1176 * Load role/password mapping file
1184 /* Discard any old data */
1185 if (role_lines || role_line_nums)
1186 free_lines(&role_lines, &role_line_nums);
1192 /* Read in the file contents */
1193 filename = auth_getflatfilename();
1194 role_file = AllocateFile(filename, "r");
1196 if (role_file == NULL)
1198 /* no complaint if not there */
1199 if (errno != ENOENT)
1201 (errcode_for_file_access(),
1202 errmsg("could not open file \"%s\": %m", filename)));
1207 tokenize_file(filename, role_file, &role_lines, &role_line_nums);
1209 FreeFile(role_file);
1212 /* create array for binary searching */
1213 role_length = list_length(role_lines);
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);
1227 * Free the contents of a hba record
1230 free_hba_record(HbaLine *record)
1232 if (record->database)
1233 pfree(record->database);
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);
1247 * Free all records on the parsed HBA list
1250 clean_hba_list(List *lines)
1254 foreach(line, lines)
1256 HbaLine *parsed = (HbaLine *)lfirst(line);
1258 free_hba_record(parsed);
1264 * Read the config file and create a List of HbaLine records for the contents.
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.
1274 List *hba_lines = NIL;
1275 List *hba_line_nums = NIL;
1276 ListCell *line, *line_num;
1277 List *new_parsed_lines = NIL;
1279 file = AllocateFile(HbaFileName, "r");
1280 /* Failure is fatal since with no HBA entries we can do nothing... */
1283 (errcode_for_file_access(),
1284 errmsg("could not open configuration file \"%s\": %m",
1287 tokenize_file(HbaFileName, file, &hba_lines, &hba_line_nums);
1290 /* Now parse all the lines */
1291 forboth(line, hba_lines, line_num, hba_line_nums)
1295 newline = palloc0(sizeof(HbaLine));
1297 if (!parse_hba_line(lfirst(line), lfirst_int(line_num), newline))
1299 /* Parse error in the file, so bail out */
1300 free_hba_record(newline);
1302 clean_hba_list(new_parsed_lines);
1303 /* Error has already been reported in the parsing function */
1307 new_parsed_lines = lappend(new_parsed_lines, newline);
1310 /* Loaded new file successfully, replace the one we use */
1311 clean_hba_list(parsed_hba_lines);
1312 parsed_hba_lines = new_parsed_lines;
1314 /* Free the temporary lists */
1315 free_lines(&hba_lines, &hba_line_nums);
1321 * Read and parse one line from the flat pg_database file.
1323 * Returns TRUE on success, FALSE if EOF; bad data causes elog(FATAL).
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
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.
1335 read_pg_database_line(FILE *fp, char *dbname, Oid *dboid,
1336 Oid *dbtablespace, TransactionId *dbfrozenxid)
1338 char buf[MAX_TOKEN];
1342 if (!next_token(fp, buf, sizeof(buf)))
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");
1366 * Process one line from the ident config file.
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.
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)
1376 ListCell *line_item;
1380 char *file_ident_user;
1385 Assert(line != NIL);
1386 line_item = list_head(line);
1388 /* Get the map token (must exist) */
1389 token = lfirst(line_item);
1392 /* Get the ident user token */
1393 line_item = lnext(line_item);
1396 token = lfirst(line_item);
1397 file_ident_user = token;
1399 /* Get the PG rolename token */
1400 line_item = lnext(line_item);
1403 token = lfirst(line_item);
1404 file_pgrole = token;
1407 if (case_insensitive)
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)
1416 if (strcmp(file_map, usermap_name) == 0 &&
1417 strcmp(file_pgrole, pg_role) == 0 &&
1418 strcmp(file_ident_user, ident_user) == 0)
1426 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1427 errmsg("missing entry in file \"%s\" at end of line %d",
1428 IdentFileName, line_number)));
1434 * Scan the (pre-parsed) ident usermap file line by line, looking for a match
1436 * See if the user with ident username "ident_user" is allowed to act
1437 * as Postgres user "pgrole" according to usermap "usermap_name".
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.
1444 * Iff authorized, return STATUS_OK, otherwise return STATUS_ERROR.
1447 check_usermap(const char *usermap_name,
1448 const char *pg_role,
1449 const char *auth_user,
1450 bool case_insensitive)
1452 bool found_entry = false,
1455 if (usermap_name == NULL || usermap_name[0] == '\0')
1457 if (case_insensitive)
1459 if (pg_strcasecmp(pg_role, auth_user) == 0)
1463 if (strcmp(pg_role, auth_user) == 0)
1467 (errmsg("provided username (%s) and authenticated username (%s) don't match",
1468 auth_user, pg_role)));
1469 return STATUS_ERROR;
1473 ListCell *line_cell,
1476 forboth(line_cell, ident_lines, num_cell, ident_line_nums)
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)
1485 if (!found_entry && !error)
1488 (errmsg("no match in usermap for user '%s' authenticated as '%s'",
1489 pg_role, auth_user),
1490 errcontext("usermap '%s'", usermap_name)));
1492 return found_entry?STATUS_OK:STATUS_ERROR;
1497 * Read the ident config file and create a List of Lists of tokens in the file.
1504 if (ident_lines || ident_line_nums)
1505 free_lines(&ident_lines, &ident_line_nums);
1507 file = AllocateFile(IdentFileName, "r");
1510 /* not fatal ... we just won't do any special ident maps */
1512 (errcode_for_file_access(),
1513 errmsg("could not open Ident usermap file \"%s\": %m",
1518 tokenize_file(IdentFileName, file, &ident_lines, &ident_line_nums);
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.
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.
1535 hba_getauthmethod(hbaPort *port)
1537 if (check_hba(port))
1540 return STATUS_ERROR;