PostgreSQL Source Code  git master
hba.c
Go to the documentation of this file.
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-2024, PostgreSQL Global Development Group
9  * Portions Copyright (c) 1994, Regents of the University of California
10  *
11  *
12  * IDENTIFICATION
13  * src/backend/libpq/hba.c
14  *
15  *-------------------------------------------------------------------------
16  */
17 #include "postgres.h"
18 
19 #include <ctype.h>
20 #include <pwd.h>
21 #include <fcntl.h>
22 #include <sys/param.h>
23 #include <sys/socket.h>
24 #include <netdb.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
27 #include <unistd.h>
28 
29 #include "catalog/pg_collation.h"
30 #include "common/ip.h"
31 #include "common/string.h"
32 #include "libpq/hba.h"
33 #include "libpq/ifaddr.h"
34 #include "libpq/libpq-be.h"
35 #include "postmaster/postmaster.h"
36 #include "regex/regex.h"
37 #include "replication/walsender.h"
38 #include "storage/fd.h"
39 #include "utils/acl.h"
40 #include "utils/conffiles.h"
41 #include "utils/guc.h"
42 #include "utils/memutils.h"
43 #include "utils/varlena.h"
44 
45 #ifdef USE_LDAP
46 #ifdef WIN32
47 #include <winldap.h>
48 #else
49 #include <ldap.h>
50 #endif
51 #endif
52 
53 
54 /* callback data for check_network_callback */
55 typedef struct check_network_data
56 {
57  IPCompareMethod method; /* test method */
58  SockAddr *raddr; /* client's actual address */
59  bool result; /* set to true if match */
61 
62 typedef struct
63 {
64  const char *filename;
65  int linenum;
67 
68 #define token_has_regexp(t) (t->regex != NULL)
69 #define token_is_member_check(t) (!t->quoted && t->string[0] == '+')
70 #define token_is_keyword(t, k) (!t->quoted && strcmp(t->string, k) == 0)
71 #define token_matches(t, k) (strcmp(t->string, k) == 0)
72 #define token_matches_insensitive(t,k) (pg_strcasecmp(t->string, k) == 0)
73 
74 /*
75  * Memory context holding the list of TokenizedAuthLines when parsing
76  * HBA or ident configuration files. This is created when opening the first
77  * file (depth of CONF_FILE_START_DEPTH).
78  */
80 
81 /*
82  * pre-parsed content of HBA config file: list of HbaLine structs.
83  * parsed_hba_context is the memory context where it lives.
84  */
87 
88 /*
89  * pre-parsed content of ident mapping file: list of IdentLine structs.
90  * parsed_ident_context is the memory context where it lives.
91  */
94 
95 /*
96  * The following character array represents the names of the authentication
97  * methods that are supported by PostgreSQL.
98  *
99  * Note: keep this in sync with the UserAuth enum in hba.h.
100  */
101 static const char *const UserAuthName[] =
102 {
103  "reject",
104  "implicit reject", /* Not a user-visible option */
105  "trust",
106  "ident",
107  "password",
108  "md5",
109  "scram-sha-256",
110  "gss",
111  "sspi",
112  "pam",
113  "bsd",
114  "ldap",
115  "cert",
116  "radius",
117  "peer"
118 };
119 
120 /*
121  * Make sure UserAuthName[] tracks additions to the UserAuth enum
122  */
124  "UserAuthName[] must match the UserAuth enum");
125 
126 
127 static List *tokenize_expand_file(List *tokens, const char *outer_filename,
128  const char *inc_filename, int elevel,
129  int depth, char **err_msg);
130 static bool parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline,
131  int elevel, char **err_msg);
132 static int regcomp_auth_token(AuthToken *token, char *filename, int line_num,
133  char **err_msg, int elevel);
134 static int regexec_auth_token(const char *match, AuthToken *token,
135  size_t nmatch, regmatch_t pmatch[]);
136 static void tokenize_error_callback(void *arg);
137 
138 
139 /*
140  * isblank() exists in the ISO C99 spec, but it's not very portable yet,
141  * so provide our own version.
142  */
143 bool
144 pg_isblank(const char c)
145 {
146  return c == ' ' || c == '\t' || c == '\r';
147 }
148 
149 
150 /*
151  * Grab one token out of the string pointed to by *lineptr.
152  *
153  * Tokens are strings of non-blank characters bounded by blank characters,
154  * commas, beginning of line, and end of line. Blank means space or tab.
155  *
156  * Tokens can be delimited by double quotes (this allows the inclusion of
157  * commas, blanks, and '#', but not newlines). As in SQL, write two
158  * double-quotes to represent a double quote.
159  *
160  * Comments (started by an unquoted '#') are skipped, i.e. the remainder
161  * of the line is ignored.
162  *
163  * (Note that line continuation processing happens before tokenization.
164  * Thus, if a continuation occurs within quoted text or a comment, the
165  * quoted text or comment is considered to continue to the next line.)
166  *
167  * The token, if any, is returned into buf (replacing any previous
168  * contents), and *lineptr is advanced past the token.
169  *
170  * Also, we set *initial_quote to indicate whether there was quoting before
171  * the first character. (We use that to prevent "@x" from being treated
172  * as a file inclusion request. Note that @"x" should be so treated;
173  * we want to allow that to support embedded spaces in file paths.)
174  *
175  * We set *terminating_comma to indicate whether the token is terminated by a
176  * comma (which is not returned, nor advanced over).
177  *
178  * The only possible error condition is lack of terminating quote, but we
179  * currently do not detect that, but just return the rest of the line.
180  *
181  * If successful: store dequoted token in buf and return true.
182  * If no more tokens on line: set buf to empty and return false.
183  */
184 static bool
186  bool *initial_quote, bool *terminating_comma)
187 {
188  int c;
189  bool in_quote = false;
190  bool was_quote = false;
191  bool saw_quote = false;
192 
193  /* Initialize output parameters */
195  *initial_quote = false;
196  *terminating_comma = false;
197 
198  /* Move over any whitespace and commas preceding the next token */
199  while ((c = (*(*lineptr)++)) != '\0' && (pg_isblank(c) || c == ','))
200  ;
201 
202  /*
203  * Build a token in buf of next characters up to EOL, unquoted comma, or
204  * unquoted whitespace.
205  */
206  while (c != '\0' &&
207  (!pg_isblank(c) || in_quote))
208  {
209  /* skip comments to EOL */
210  if (c == '#' && !in_quote)
211  {
212  while ((c = (*(*lineptr)++)) != '\0')
213  ;
214  break;
215  }
216 
217  /* we do not pass back a terminating comma in the token */
218  if (c == ',' && !in_quote)
219  {
220  *terminating_comma = true;
221  break;
222  }
223 
224  if (c != '"' || was_quote)
226 
227  /* Literal double-quote is two double-quotes */
228  if (in_quote && c == '"')
229  was_quote = !was_quote;
230  else
231  was_quote = false;
232 
233  if (c == '"')
234  {
235  in_quote = !in_quote;
236  saw_quote = true;
237  if (buf->len == 0)
238  *initial_quote = true;
239  }
240 
241  c = *(*lineptr)++;
242  }
243 
244  /*
245  * Un-eat the char right after the token (critical in case it is '\0',
246  * else next call will read past end of string).
247  */
248  (*lineptr)--;
249 
250  return (saw_quote || buf->len > 0);
251 }
252 
253 /*
254  * Construct a palloc'd AuthToken struct, copying the given string.
255  */
256 static AuthToken *
257 make_auth_token(const char *token, bool quoted)
258 {
259  AuthToken *authtoken;
260  int toklen;
261 
262  toklen = strlen(token);
263  /* we copy string into same palloc block as the struct */
264  authtoken = (AuthToken *) palloc0(sizeof(AuthToken) + toklen + 1);
265  authtoken->string = (char *) authtoken + sizeof(AuthToken);
266  authtoken->quoted = quoted;
267  authtoken->regex = NULL;
268  memcpy(authtoken->string, token, toklen + 1);
269 
270  return authtoken;
271 }
272 
273 /*
274  * Free an AuthToken, that may include a regular expression that needs
275  * to be cleaned up explicitly.
276  */
277 static void
279 {
280  if (token_has_regexp(token))
281  pg_regfree(token->regex);
282 }
283 
284 /*
285  * Copy a AuthToken struct into freshly palloc'd memory.
286  */
287 static AuthToken *
289 {
290  AuthToken *out = make_auth_token(in->string, in->quoted);
291 
292  return out;
293 }
294 
295 /*
296  * Compile the regular expression and store it in the AuthToken given in
297  * input. Returns the result of pg_regcomp(). On error, the details are
298  * stored in "err_msg".
299  */
300 static int
302  char **err_msg, int elevel)
303 {
304  pg_wchar *wstr;
305  int wlen;
306  int rc;
307 
308  Assert(token->regex == NULL);
309 
310  if (token->string[0] != '/')
311  return 0; /* nothing to compile */
312 
313  token->regex = (regex_t *) palloc0(sizeof(regex_t));
314  wstr = palloc((strlen(token->string + 1) + 1) * sizeof(pg_wchar));
315  wlen = pg_mb2wchar_with_len(token->string + 1,
316  wstr, strlen(token->string + 1));
317 
318  rc = pg_regcomp(token->regex, wstr, wlen, REG_ADVANCED, C_COLLATION_OID);
319 
320  if (rc)
321  {
322  char errstr[100];
323 
324  pg_regerror(rc, token->regex, errstr, sizeof(errstr));
325  ereport(elevel,
326  (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
327  errmsg("invalid regular expression \"%s\": %s",
328  token->string + 1, errstr),
329  errcontext("line %d of configuration file \"%s\"",
330  line_num, filename)));
331 
332  *err_msg = psprintf("invalid regular expression \"%s\": %s",
333  token->string + 1, errstr);
334  }
335 
336  pfree(wstr);
337  return rc;
338 }
339 
340 /*
341  * Execute a regular expression computed in an AuthToken, checking for a match
342  * with the string specified in "match". The caller may optionally give an
343  * array to store the matches. Returns the result of pg_regexec().
344  */
345 static int
346 regexec_auth_token(const char *match, AuthToken *token, size_t nmatch,
347  regmatch_t pmatch[])
348 {
349  pg_wchar *wmatchstr;
350  int wmatchlen;
351  int r;
352 
353  Assert(token->string[0] == '/' && token->regex);
354 
355  wmatchstr = palloc((strlen(match) + 1) * sizeof(pg_wchar));
356  wmatchlen = pg_mb2wchar_with_len(match, wmatchstr, strlen(match));
357 
358  r = pg_regexec(token->regex, wmatchstr, wmatchlen, 0, NULL, nmatch, pmatch, 0);
359 
360  pfree(wmatchstr);
361  return r;
362 }
363 
364 /*
365  * Tokenize one HBA field from a line, handling file inclusion and comma lists.
366  *
367  * filename: current file's pathname (needed to resolve relative pathnames)
368  * *lineptr: current line pointer, which will be advanced past field
369  *
370  * In event of an error, log a message at ereport level elevel, and also
371  * set *err_msg to a string describing the error. Note that the result
372  * may be non-NIL anyway, so *err_msg must be tested to determine whether
373  * there was an error.
374  *
375  * The result is a List of AuthToken structs, one for each token in the field,
376  * or NIL if we reached EOL.
377  */
378 static List *
379 next_field_expand(const char *filename, char **lineptr,
380  int elevel, int depth, char **err_msg)
381 {
383  bool trailing_comma;
384  bool initial_quote;
385  List *tokens = NIL;
386 
388 
389  do
390  {
391  if (!next_token(lineptr, &buf,
392  &initial_quote, &trailing_comma))
393  break;
394 
395  /* Is this referencing a file? */
396  if (!initial_quote && buf.len > 1 && buf.data[0] == '@')
397  tokens = tokenize_expand_file(tokens, filename, buf.data + 1,
398  elevel, depth + 1, err_msg);
399  else
400  {
401  MemoryContext oldcxt;
402 
403  /*
404  * lappend() may do its own allocations, so move to the context
405  * for the list of tokens.
406  */
408  tokens = lappend(tokens, make_auth_token(buf.data, initial_quote));
409  MemoryContextSwitchTo(oldcxt);
410  }
411  } while (trailing_comma && (*err_msg == NULL));
412 
413  pfree(buf.data);
414 
415  return tokens;
416 }
417 
418 /*
419  * tokenize_include_file
420  * Include a file from another file into an hba "field".
421  *
422  * Opens and tokenises a file included from another authentication file
423  * with one of the include records ("include", "include_if_exists" or
424  * "include_dir"), and assign all values found to an existing list of
425  * list of AuthTokens.
426  *
427  * All new tokens are allocated in the memory context dedicated to the
428  * tokenization, aka tokenize_context.
429  *
430  * If missing_ok is true, ignore a missing file.
431  *
432  * In event of an error, log a message at ereport level elevel, and also
433  * set *err_msg to a string describing the error. Note that the result
434  * may be non-NIL anyway, so *err_msg must be tested to determine whether
435  * there was an error.
436  */
437 static void
438 tokenize_include_file(const char *outer_filename,
439  const char *inc_filename,
440  List **tok_lines,
441  int elevel,
442  int depth,
443  bool missing_ok,
444  char **err_msg)
445 {
446  char *inc_fullname;
447  FILE *inc_file;
448 
449  inc_fullname = AbsoluteConfigLocation(inc_filename, outer_filename);
450  inc_file = open_auth_file(inc_fullname, elevel, depth, err_msg);
451 
452  if (!inc_file)
453  {
454  if (errno == ENOENT && missing_ok)
455  {
456  ereport(elevel,
457  (errmsg("skipping missing authentication file \"%s\"",
458  inc_fullname)));
459  *err_msg = NULL;
460  pfree(inc_fullname);
461  return;
462  }
463 
464  /* error in err_msg, so leave and report */
465  pfree(inc_fullname);
466  Assert(err_msg);
467  return;
468  }
469 
470  tokenize_auth_file(inc_fullname, inc_file, tok_lines, elevel,
471  depth);
472  free_auth_file(inc_file, depth);
473  pfree(inc_fullname);
474 }
475 
476 /*
477  * tokenize_expand_file
478  * Expand a file included from another file into an hba "field"
479  *
480  * Opens and tokenises a file included from another HBA config file with @,
481  * and returns all values found therein as a flat list of AuthTokens. If a
482  * @-token or include record is found, recursively expand it. The newly
483  * read tokens are appended to "tokens" (so that foo,bar,@baz does what you
484  * expect). All new tokens are allocated in the memory context dedicated
485  * to the list of TokenizedAuthLines, aka tokenize_context.
486  *
487  * In event of an error, log a message at ereport level elevel, and also
488  * set *err_msg to a string describing the error. Note that the result
489  * may be non-NIL anyway, so *err_msg must be tested to determine whether
490  * there was an error.
491  */
492 static List *
494  const char *outer_filename,
495  const char *inc_filename,
496  int elevel,
497  int depth,
498  char **err_msg)
499 {
500  char *inc_fullname;
501  FILE *inc_file;
502  List *inc_lines = NIL;
503  ListCell *inc_line;
504 
505  inc_fullname = AbsoluteConfigLocation(inc_filename, outer_filename);
506  inc_file = open_auth_file(inc_fullname, elevel, depth, err_msg);
507 
508  if (inc_file == NULL)
509  {
510  /* error already logged */
511  pfree(inc_fullname);
512  return tokens;
513  }
514 
515  /*
516  * There is possible recursion here if the file contains @ or an include
517  * record.
518  */
519  tokenize_auth_file(inc_fullname, inc_file, &inc_lines, elevel,
520  depth);
521 
522  pfree(inc_fullname);
523 
524  /*
525  * Move all the tokens found in the file to the tokens list. These are
526  * already saved in tokenize_context.
527  */
528  foreach(inc_line, inc_lines)
529  {
530  TokenizedAuthLine *tok_line = (TokenizedAuthLine *) lfirst(inc_line);
531  ListCell *inc_field;
532 
533  /* If any line has an error, propagate that up to caller */
534  if (tok_line->err_msg)
535  {
536  *err_msg = pstrdup(tok_line->err_msg);
537  break;
538  }
539 
540  foreach(inc_field, tok_line->fields)
541  {
542  List *inc_tokens = lfirst(inc_field);
543  ListCell *inc_token;
544 
545  foreach(inc_token, inc_tokens)
546  {
547  AuthToken *token = lfirst(inc_token);
548  MemoryContext oldcxt;
549 
550  /*
551  * lappend() may do its own allocations, so move to the
552  * context for the list of tokens.
553  */
555  tokens = lappend(tokens, token);
556  MemoryContextSwitchTo(oldcxt);
557  }
558  }
559  }
560 
561  free_auth_file(inc_file, depth);
562  return tokens;
563 }
564 
565 /*
566  * free_auth_file
567  * Free a file opened by open_auth_file().
568  */
569 void
570 free_auth_file(FILE *file, int depth)
571 {
572  FreeFile(file);
573 
574  /* If this is the last cleanup, remove the tokenization context */
575  if (depth == CONF_FILE_START_DEPTH)
576  {
578  tokenize_context = NULL;
579  }
580 }
581 
582 /*
583  * open_auth_file
584  * Open the given file.
585  *
586  * filename: the absolute path to the target file
587  * elevel: message logging level
588  * depth: recursion level when opening the file
589  * err_msg: details about the error
590  *
591  * Return value is the opened file. On error, returns NULL with details
592  * about the error stored in "err_msg".
593  */
594 FILE *
595 open_auth_file(const char *filename, int elevel, int depth,
596  char **err_msg)
597 {
598  FILE *file;
599 
600  /*
601  * Reject too-deep include nesting depth. This is just a safety check to
602  * avoid dumping core due to stack overflow if an include file loops back
603  * to itself. The maximum nesting depth is pretty arbitrary.
604  */
605  if (depth > CONF_FILE_MAX_DEPTH)
606  {
607  ereport(elevel,
609  errmsg("could not open file \"%s\": maximum nesting depth exceeded",
610  filename)));
611  if (err_msg)
612  *err_msg = psprintf("could not open file \"%s\": maximum nesting depth exceeded",
613  filename);
614  return NULL;
615  }
616 
617  file = AllocateFile(filename, "r");
618  if (file == NULL)
619  {
620  int save_errno = errno;
621 
622  ereport(elevel,
624  errmsg("could not open file \"%s\": %m",
625  filename)));
626  if (err_msg)
627  {
628  errno = save_errno;
629  *err_msg = psprintf("could not open file \"%s\": %m",
630  filename);
631  }
632  /* the caller may care about some specific errno */
633  errno = save_errno;
634  return NULL;
635  }
636 
637  /*
638  * When opening the top-level file, create the memory context used for the
639  * tokenization. This will be closed with this file when coming back to
640  * this level of cleanup.
641  */
642  if (depth == CONF_FILE_START_DEPTH)
643  {
644  /*
645  * A context may be present, but assume that it has been eliminated
646  * already.
647  */
649  "tokenize_context",
651  }
652 
653  return file;
654 }
655 
656 /*
657  * error context callback for tokenize_auth_file()
658  */
659 static void
661 {
663 
664  errcontext("line %d of configuration file \"%s\"",
665  callback_arg->linenum, callback_arg->filename);
666 }
667 
668 /*
669  * tokenize_auth_file
670  * Tokenize the given file.
671  *
672  * The output is a list of TokenizedAuthLine structs; see the struct definition
673  * in libpq/hba.h. This is the central piece in charge of parsing the
674  * authentication files. All the operations of this function happen in its own
675  * local memory context, easing the cleanup of anything allocated here. This
676  * matters a lot when reloading authentication files in the postmaster.
677  *
678  * filename: the absolute path to the target file
679  * file: the already-opened target file
680  * tok_lines: receives output list, saved into tokenize_context
681  * elevel: message logging level
682  * depth: level of recursion when tokenizing the target file
683  *
684  * Errors are reported by logging messages at ereport level elevel and by
685  * adding TokenizedAuthLine structs containing non-null err_msg fields to the
686  * output list.
687  */
688 void
689 tokenize_auth_file(const char *filename, FILE *file, List **tok_lines,
690  int elevel, int depth)
691 {
692  int line_number = 1;
694  MemoryContext linecxt;
695  MemoryContext funccxt; /* context of this function's caller */
696  ErrorContextCallback tokenerrcontext;
697  tokenize_error_callback_arg callback_arg;
698 
700 
701  callback_arg.filename = filename;
702  callback_arg.linenum = line_number;
703 
704  tokenerrcontext.callback = tokenize_error_callback;
705  tokenerrcontext.arg = (void *) &callback_arg;
706  tokenerrcontext.previous = error_context_stack;
707  error_context_stack = &tokenerrcontext;
708 
709  /*
710  * Do all the local tokenization in its own context, to ease the cleanup
711  * of any memory allocated while tokenizing.
712  */
714  "tokenize_auth_file",
716  funccxt = MemoryContextSwitchTo(linecxt);
717 
719 
720  if (depth == CONF_FILE_START_DEPTH)
721  *tok_lines = NIL;
722 
723  while (!feof(file) && !ferror(file))
724  {
725  TokenizedAuthLine *tok_line;
726  MemoryContext oldcxt;
727  char *lineptr;
728  List *current_line = NIL;
729  char *err_msg = NULL;
730  int last_backslash_buflen = 0;
731  int continuations = 0;
732 
733  /* Collect the next input line, handling backslash continuations */
735 
736  while (pg_get_line_append(file, &buf, NULL))
737  {
738  /* Strip trailing newline, including \r in case we're on Windows */
739  buf.len = pg_strip_crlf(buf.data);
740 
741  /*
742  * Check for backslash continuation. The backslash must be after
743  * the last place we found a continuation, else two backslashes
744  * followed by two \n's would behave surprisingly.
745  */
746  if (buf.len > last_backslash_buflen &&
747  buf.data[buf.len - 1] == '\\')
748  {
749  /* Continuation, so strip it and keep reading */
750  buf.data[--buf.len] = '\0';
751  last_backslash_buflen = buf.len;
752  continuations++;
753  continue;
754  }
755 
756  /* Nope, so we have the whole line */
757  break;
758  }
759 
760  if (ferror(file))
761  {
762  /* I/O error! */
763  int save_errno = errno;
764 
765  ereport(elevel,
767  errmsg("could not read file \"%s\": %m", filename)));
768  errno = save_errno;
769  err_msg = psprintf("could not read file \"%s\": %m",
770  filename);
771  break;
772  }
773 
774  /* Parse fields */
775  lineptr = buf.data;
776  while (*lineptr && err_msg == NULL)
777  {
778  List *current_field;
779 
780  current_field = next_field_expand(filename, &lineptr,
781  elevel, depth, &err_msg);
782  /* add field to line, unless we are at EOL or comment start */
783  if (current_field != NIL)
784  {
785  /*
786  * lappend() may do its own allocations, so move to the
787  * context for the list of tokens.
788  */
790  current_line = lappend(current_line, current_field);
791  MemoryContextSwitchTo(oldcxt);
792  }
793  }
794 
795  /*
796  * Reached EOL; no need to emit line to TokenizedAuthLine list if it's
797  * boring.
798  */
799  if (current_line == NIL && err_msg == NULL)
800  goto next_line;
801 
802  /* If the line is valid, check if that's an include directive */
803  if (err_msg == NULL && list_length(current_line) == 2)
804  {
805  AuthToken *first,
806  *second;
807 
808  first = linitial(linitial_node(List, current_line));
809  second = linitial(lsecond_node(List, current_line));
810 
811  if (strcmp(first->string, "include") == 0)
812  {
813  tokenize_include_file(filename, second->string, tok_lines,
814  elevel, depth + 1, false, &err_msg);
815 
816  if (err_msg)
817  goto process_line;
818 
819  /*
820  * tokenize_auth_file() has taken care of creating the
821  * TokenizedAuthLines.
822  */
823  goto next_line;
824  }
825  else if (strcmp(first->string, "include_dir") == 0)
826  {
827  char **filenames;
828  char *dir_name = second->string;
829  int num_filenames;
830  StringInfoData err_buf;
831 
832  filenames = GetConfFilesInDir(dir_name, filename, elevel,
833  &num_filenames, &err_msg);
834 
835  if (!filenames)
836  {
837  /* the error is in err_msg, so create an entry */
838  goto process_line;
839  }
840 
841  initStringInfo(&err_buf);
842  for (int i = 0; i < num_filenames; i++)
843  {
844  tokenize_include_file(filename, filenames[i], tok_lines,
845  elevel, depth + 1, false, &err_msg);
846  /* cumulate errors if any */
847  if (err_msg)
848  {
849  if (err_buf.len > 0)
850  appendStringInfoChar(&err_buf, '\n');
851  appendStringInfoString(&err_buf, err_msg);
852  }
853  }
854 
855  /* clean up things */
856  for (int i = 0; i < num_filenames; i++)
857  pfree(filenames[i]);
858  pfree(filenames);
859 
860  /*
861  * If there were no errors, the line is fully processed,
862  * bypass the general TokenizedAuthLine processing.
863  */
864  if (err_buf.len == 0)
865  goto next_line;
866 
867  /* Otherwise, process the cumulated errors, if any. */
868  err_msg = err_buf.data;
869  goto process_line;
870  }
871  else if (strcmp(first->string, "include_if_exists") == 0)
872  {
873 
874  tokenize_include_file(filename, second->string, tok_lines,
875  elevel, depth + 1, true, &err_msg);
876  if (err_msg)
877  goto process_line;
878 
879  /*
880  * tokenize_auth_file() has taken care of creating the
881  * TokenizedAuthLines.
882  */
883  goto next_line;
884  }
885  }
886 
887 process_line:
888 
889  /*
890  * General processing: report the error if any and emit line to the
891  * TokenizedAuthLine. This is saved in the memory context dedicated
892  * to this list.
893  */
895  tok_line = (TokenizedAuthLine *) palloc0(sizeof(TokenizedAuthLine));
896  tok_line->fields = current_line;
897  tok_line->file_name = pstrdup(filename);
898  tok_line->line_num = line_number;
899  tok_line->raw_line = pstrdup(buf.data);
900  tok_line->err_msg = err_msg ? pstrdup(err_msg) : NULL;
901  *tok_lines = lappend(*tok_lines, tok_line);
902  MemoryContextSwitchTo(oldcxt);
903 
904 next_line:
905  line_number += continuations + 1;
906  callback_arg.linenum = line_number;
907  }
908 
909  MemoryContextSwitchTo(funccxt);
910  MemoryContextDelete(linecxt);
911 
912  error_context_stack = tokenerrcontext.previous;
913 }
914 
915 
916 /*
917  * Does user belong to role?
918  *
919  * userid is the OID of the role given as the attempted login identifier.
920  * We check to see if it is a member of the specified role name.
921  */
922 static bool
923 is_member(Oid userid, const char *role)
924 {
925  Oid roleid;
926 
927  if (!OidIsValid(userid))
928  return false; /* if user not exist, say "no" */
929 
930  roleid = get_role_oid(role, true);
931 
932  if (!OidIsValid(roleid))
933  return false; /* if target role not exist, say "no" */
934 
935  /*
936  * See if user is directly or indirectly a member of role. For this
937  * purpose, a superuser is not considered to be automatically a member of
938  * the role, so group auth only applies to explicit membership.
939  */
940  return is_member_of_role_nosuper(userid, roleid);
941 }
942 
943 /*
944  * Check AuthToken list for a match to role, allowing group names.
945  *
946  * Each AuthToken listed is checked one-by-one. Keywords are processed
947  * first (these cannot have regular expressions), followed by regular
948  * expressions (if any), the case-insensitive match (if requested) and
949  * the exact match.
950  */
951 static bool
952 check_role(const char *role, Oid roleid, List *tokens, bool case_insensitive)
953 {
954  ListCell *cell;
955  AuthToken *tok;
956 
957  foreach(cell, tokens)
958  {
959  tok = lfirst(cell);
960  if (token_is_member_check(tok))
961  {
962  if (is_member(roleid, tok->string + 1))
963  return true;
964  }
965  else if (token_is_keyword(tok, "all"))
966  return true;
967  else if (token_has_regexp(tok))
968  {
969  if (regexec_auth_token(role, tok, 0, NULL) == REG_OKAY)
970  return true;
971  }
972  else if (case_insensitive)
973  {
974  if (token_matches_insensitive(tok, role))
975  return true;
976  }
977  else if (token_matches(tok, role))
978  return true;
979  }
980  return false;
981 }
982 
983 /*
984  * Check to see if db/role combination matches AuthToken list.
985  *
986  * Each AuthToken listed is checked one-by-one. Keywords are checked
987  * first (these cannot have regular expressions), followed by regular
988  * expressions (if any) and the exact match.
989  */
990 static bool
991 check_db(const char *dbname, const char *role, Oid roleid, List *tokens)
992 {
993  ListCell *cell;
994  AuthToken *tok;
995 
996  foreach(cell, tokens)
997  {
998  tok = lfirst(cell);
1000  {
1001  /*
1002  * physical replication walsender connections can only match
1003  * replication keyword
1004  */
1005  if (token_is_keyword(tok, "replication"))
1006  return true;
1007  }
1008  else if (token_is_keyword(tok, "all"))
1009  return true;
1010  else if (token_is_keyword(tok, "sameuser"))
1011  {
1012  if (strcmp(dbname, role) == 0)
1013  return true;
1014  }
1015  else if (token_is_keyword(tok, "samegroup") ||
1016  token_is_keyword(tok, "samerole"))
1017  {
1018  if (is_member(roleid, dbname))
1019  return true;
1020  }
1021  else if (token_is_keyword(tok, "replication"))
1022  continue; /* never match this if not walsender */
1023  else if (token_has_regexp(tok))
1024  {
1025  if (regexec_auth_token(dbname, tok, 0, NULL) == REG_OKAY)
1026  return true;
1027  }
1028  else if (token_matches(tok, dbname))
1029  return true;
1030  }
1031  return false;
1032 }
1033 
1034 static bool
1035 ipv4eq(struct sockaddr_in *a, struct sockaddr_in *b)
1036 {
1037  return (a->sin_addr.s_addr == b->sin_addr.s_addr);
1038 }
1039 
1040 static bool
1041 ipv6eq(struct sockaddr_in6 *a, struct sockaddr_in6 *b)
1042 {
1043  int i;
1044 
1045  for (i = 0; i < 16; i++)
1046  if (a->sin6_addr.s6_addr[i] != b->sin6_addr.s6_addr[i])
1047  return false;
1048 
1049  return true;
1050 }
1051 
1052 /*
1053  * Check whether host name matches pattern.
1054  */
1055 static bool
1056 hostname_match(const char *pattern, const char *actual_hostname)
1057 {
1058  if (pattern[0] == '.') /* suffix match */
1059  {
1060  size_t plen = strlen(pattern);
1061  size_t hlen = strlen(actual_hostname);
1062 
1063  if (hlen < plen)
1064  return false;
1065 
1066  return (pg_strcasecmp(pattern, actual_hostname + (hlen - plen)) == 0);
1067  }
1068  else
1069  return (pg_strcasecmp(pattern, actual_hostname) == 0);
1070 }
1071 
1072 /*
1073  * Check to see if a connecting IP matches a given host name.
1074  */
1075 static bool
1077 {
1078  struct addrinfo *gai_result,
1079  *gai;
1080  int ret;
1081  bool found;
1082 
1083  /* Quick out if remote host name already known bad */
1084  if (port->remote_hostname_resolv < 0)
1085  return false;
1086 
1087  /* Lookup remote host name if not already done */
1088  if (!port->remote_hostname)
1089  {
1090  char remote_hostname[NI_MAXHOST];
1091 
1092  ret = pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
1093  remote_hostname, sizeof(remote_hostname),
1094  NULL, 0,
1095  NI_NAMEREQD);
1096  if (ret != 0)
1097  {
1098  /* remember failure; don't complain in the postmaster log yet */
1099  port->remote_hostname_resolv = -2;
1100  port->remote_hostname_errcode = ret;
1101  return false;
1102  }
1103 
1104  port->remote_hostname = pstrdup(remote_hostname);
1105  }
1106 
1107  /* Now see if remote host name matches this pg_hba line */
1108  if (!hostname_match(hostname, port->remote_hostname))
1109  return false;
1110 
1111  /* If we already verified the forward lookup, we're done */
1112  if (port->remote_hostname_resolv == +1)
1113  return true;
1114 
1115  /* Lookup IP from host name and check against original IP */
1116  ret = getaddrinfo(port->remote_hostname, NULL, NULL, &gai_result);
1117  if (ret != 0)
1118  {
1119  /* remember failure; don't complain in the postmaster log yet */
1120  port->remote_hostname_resolv = -2;
1121  port->remote_hostname_errcode = ret;
1122  return false;
1123  }
1124 
1125  found = false;
1126  for (gai = gai_result; gai; gai = gai->ai_next)
1127  {
1128  if (gai->ai_addr->sa_family == port->raddr.addr.ss_family)
1129  {
1130  if (gai->ai_addr->sa_family == AF_INET)
1131  {
1132  if (ipv4eq((struct sockaddr_in *) gai->ai_addr,
1133  (struct sockaddr_in *) &port->raddr.addr))
1134  {
1135  found = true;
1136  break;
1137  }
1138  }
1139  else if (gai->ai_addr->sa_family == AF_INET6)
1140  {
1141  if (ipv6eq((struct sockaddr_in6 *) gai->ai_addr,
1142  (struct sockaddr_in6 *) &port->raddr.addr))
1143  {
1144  found = true;
1145  break;
1146  }
1147  }
1148  }
1149  }
1150 
1151  if (gai_result)
1152  freeaddrinfo(gai_result);
1153 
1154  if (!found)
1155  elog(DEBUG2, "pg_hba.conf host name \"%s\" rejected because address resolution did not return a match with IP address of client",
1156  hostname);
1157 
1158  port->remote_hostname_resolv = found ? +1 : -1;
1159 
1160  return found;
1161 }
1162 
1163 /*
1164  * Check to see if a connecting IP matches the given address and netmask.
1165  */
1166 static bool
1167 check_ip(SockAddr *raddr, struct sockaddr *addr, struct sockaddr *mask)
1168 {
1169  if (raddr->addr.ss_family == addr->sa_family &&
1170  pg_range_sockaddr(&raddr->addr,
1171  (struct sockaddr_storage *) addr,
1172  (struct sockaddr_storage *) mask))
1173  return true;
1174  return false;
1175 }
1176 
1177 /*
1178  * pg_foreach_ifaddr callback: does client addr match this machine interface?
1179  */
1180 static void
1181 check_network_callback(struct sockaddr *addr, struct sockaddr *netmask,
1182  void *cb_data)
1183 {
1184  check_network_data *cn = (check_network_data *) cb_data;
1185  struct sockaddr_storage mask;
1186 
1187  /* Already found a match? */
1188  if (cn->result)
1189  return;
1190 
1191  if (cn->method == ipCmpSameHost)
1192  {
1193  /* Make an all-ones netmask of appropriate length for family */
1194  pg_sockaddr_cidr_mask(&mask, NULL, addr->sa_family);
1195  cn->result = check_ip(cn->raddr, addr, (struct sockaddr *) &mask);
1196  }
1197  else
1198  {
1199  /* Use the netmask of the interface itself */
1200  cn->result = check_ip(cn->raddr, addr, netmask);
1201  }
1202 }
1203 
1204 /*
1205  * Use pg_foreach_ifaddr to check a samehost or samenet match
1206  */
1207 static bool
1209 {
1210  check_network_data cn;
1211 
1212  cn.method = method;
1213  cn.raddr = raddr;
1214  cn.result = false;
1215 
1216  errno = 0;
1218  {
1219  ereport(LOG,
1220  (errmsg("error enumerating network interfaces: %m")));
1221  return false;
1222  }
1223 
1224  return cn.result;
1225 }
1226 
1227 
1228 /*
1229  * Macros used to check and report on invalid configuration options.
1230  * On error: log a message at level elevel, set *err_msg, and exit the function.
1231  * These macros are not as general-purpose as they look, because they know
1232  * what the calling function's error-exit value is.
1233  *
1234  * INVALID_AUTH_OPTION = reports when an option is specified for a method where it's
1235  * not supported.
1236  * REQUIRE_AUTH_OPTION = same as INVALID_AUTH_OPTION, except it also checks if the
1237  * method is actually the one specified. Used as a shortcut when
1238  * the option is only valid for one authentication method.
1239  * MANDATORY_AUTH_ARG = check if a required option is set for an authentication method,
1240  * reporting error if it's not.
1241  */
1242 #define INVALID_AUTH_OPTION(optname, validmethods) \
1243 do { \
1244  ereport(elevel, \
1245  (errcode(ERRCODE_CONFIG_FILE_ERROR), \
1246  /* translator: the second %s is a list of auth methods */ \
1247  errmsg("authentication option \"%s\" is only valid for authentication methods %s", \
1248  optname, _(validmethods)), \
1249  errcontext("line %d of configuration file \"%s\"", \
1250  line_num, file_name))); \
1251  *err_msg = psprintf("authentication option \"%s\" is only valid for authentication methods %s", \
1252  optname, validmethods); \
1253  return false; \
1254 } while (0)
1255 
1256 #define REQUIRE_AUTH_OPTION(methodval, optname, validmethods) \
1257 do { \
1258  if (hbaline->auth_method != methodval) \
1259  INVALID_AUTH_OPTION(optname, validmethods); \
1260 } while (0)
1261 
1262 #define MANDATORY_AUTH_ARG(argvar, argname, authname) \
1263 do { \
1264  if (argvar == NULL) { \
1265  ereport(elevel, \
1266  (errcode(ERRCODE_CONFIG_FILE_ERROR), \
1267  errmsg("authentication method \"%s\" requires argument \"%s\" to be set", \
1268  authname, argname), \
1269  errcontext("line %d of configuration file \"%s\"", \
1270  line_num, file_name))); \
1271  *err_msg = psprintf("authentication method \"%s\" requires argument \"%s\" to be set", \
1272  authname, argname); \
1273  return NULL; \
1274  } \
1275 } while (0)
1276 
1277 /*
1278  * Macros for handling pg_ident problems, similar as above.
1279  *
1280  * IDENT_FIELD_ABSENT:
1281  * Reports when the given ident field ListCell is not populated.
1282  *
1283  * IDENT_MULTI_VALUE:
1284  * Reports when the given ident token List has more than one element.
1285  */
1286 #define IDENT_FIELD_ABSENT(field) \
1287 do { \
1288  if (!field) { \
1289  ereport(elevel, \
1290  (errcode(ERRCODE_CONFIG_FILE_ERROR), \
1291  errmsg("missing entry at end of line"), \
1292  errcontext("line %d of configuration file \"%s\"", \
1293  line_num, file_name))); \
1294  *err_msg = pstrdup("missing entry at end of line"); \
1295  return NULL; \
1296  } \
1297 } while (0)
1298 
1299 #define IDENT_MULTI_VALUE(tokens) \
1300 do { \
1301  if (tokens->length > 1) { \
1302  ereport(elevel, \
1303  (errcode(ERRCODE_CONFIG_FILE_ERROR), \
1304  errmsg("multiple values in ident field"), \
1305  errcontext("line %d of configuration file \"%s\"", \
1306  line_num, file_name))); \
1307  *err_msg = pstrdup("multiple values in ident field"); \
1308  return NULL; \
1309  } \
1310 } while (0)
1311 
1312 
1313 /*
1314  * Parse one tokenised line from the hba config file and store the result in a
1315  * HbaLine structure.
1316  *
1317  * If parsing fails, log a message at ereport level elevel, store an error
1318  * string in tok_line->err_msg, and return NULL. (Some non-error conditions
1319  * can also result in such messages.)
1320  *
1321  * Note: this function leaks memory when an error occurs. Caller is expected
1322  * to have set a memory context that will be reset if this function returns
1323  * NULL.
1324  */
1325 HbaLine *
1326 parse_hba_line(TokenizedAuthLine *tok_line, int elevel)
1327 {
1328  int line_num = tok_line->line_num;
1329  char *file_name = tok_line->file_name;
1330  char **err_msg = &tok_line->err_msg;
1331  char *str;
1332  struct addrinfo *gai_result;
1333  struct addrinfo hints;
1334  int ret;
1335  char *cidr_slash;
1336  char *unsupauth;
1337  ListCell *field;
1338  List *tokens;
1339  ListCell *tokencell;
1340  AuthToken *token;
1341  HbaLine *parsedline;
1342 
1343  parsedline = palloc0(sizeof(HbaLine));
1344  parsedline->sourcefile = pstrdup(file_name);
1345  parsedline->linenumber = line_num;
1346  parsedline->rawline = pstrdup(tok_line->raw_line);
1347 
1348  /* Check the record type. */
1349  Assert(tok_line->fields != NIL);
1350  field = list_head(tok_line->fields);
1351  tokens = lfirst(field);
1352  if (tokens->length > 1)
1353  {
1354  ereport(elevel,
1355  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1356  errmsg("multiple values specified for connection type"),
1357  errhint("Specify exactly one connection type per line."),
1358  errcontext("line %d of configuration file \"%s\"",
1359  line_num, file_name)));
1360  *err_msg = "multiple values specified for connection type";
1361  return NULL;
1362  }
1363  token = linitial(tokens);
1364  if (strcmp(token->string, "local") == 0)
1365  {
1366  parsedline->conntype = ctLocal;
1367  }
1368  else if (strcmp(token->string, "host") == 0 ||
1369  strcmp(token->string, "hostssl") == 0 ||
1370  strcmp(token->string, "hostnossl") == 0 ||
1371  strcmp(token->string, "hostgssenc") == 0 ||
1372  strcmp(token->string, "hostnogssenc") == 0)
1373  {
1374 
1375  if (token->string[4] == 's') /* "hostssl" */
1376  {
1377  parsedline->conntype = ctHostSSL;
1378  /* Log a warning if SSL support is not active */
1379 #ifdef USE_SSL
1380  if (!EnableSSL)
1381  {
1382  ereport(elevel,
1383  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1384  errmsg("hostssl record cannot match because SSL is disabled"),
1385  errhint("Set \"ssl = on\" in postgresql.conf."),
1386  errcontext("line %d of configuration file \"%s\"",
1387  line_num, file_name)));
1388  *err_msg = "hostssl record cannot match because SSL is disabled";
1389  }
1390 #else
1391  ereport(elevel,
1392  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1393  errmsg("hostssl record cannot match because SSL is not supported by this build"),
1394  errcontext("line %d of configuration file \"%s\"",
1395  line_num, file_name)));
1396  *err_msg = "hostssl record cannot match because SSL is not supported by this build";
1397 #endif
1398  }
1399  else if (token->string[4] == 'g') /* "hostgssenc" */
1400  {
1401  parsedline->conntype = ctHostGSS;
1402 #ifndef ENABLE_GSS
1403  ereport(elevel,
1404  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1405  errmsg("hostgssenc record cannot match because GSSAPI is not supported by this build"),
1406  errcontext("line %d of configuration file \"%s\"",
1407  line_num, file_name)));
1408  *err_msg = "hostgssenc record cannot match because GSSAPI is not supported by this build";
1409 #endif
1410  }
1411  else if (token->string[4] == 'n' && token->string[6] == 's')
1412  parsedline->conntype = ctHostNoSSL;
1413  else if (token->string[4] == 'n' && token->string[6] == 'g')
1414  parsedline->conntype = ctHostNoGSS;
1415  else
1416  {
1417  /* "host" */
1418  parsedline->conntype = ctHost;
1419  }
1420  } /* record type */
1421  else
1422  {
1423  ereport(elevel,
1424  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1425  errmsg("invalid connection type \"%s\"",
1426  token->string),
1427  errcontext("line %d of configuration file \"%s\"",
1428  line_num, file_name)));
1429  *err_msg = psprintf("invalid connection type \"%s\"", token->string);
1430  return NULL;
1431  }
1432 
1433  /* Get the databases. */
1434  field = lnext(tok_line->fields, field);
1435  if (!field)
1436  {
1437  ereport(elevel,
1438  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1439  errmsg("end-of-line before database specification"),
1440  errcontext("line %d of configuration file \"%s\"",
1441  line_num, file_name)));
1442  *err_msg = "end-of-line before database specification";
1443  return NULL;
1444  }
1445  parsedline->databases = NIL;
1446  tokens = lfirst(field);
1447  foreach(tokencell, tokens)
1448  {
1449  AuthToken *tok = copy_auth_token(lfirst(tokencell));
1450 
1451  /* Compile a regexp for the database token, if necessary */
1452  if (regcomp_auth_token(tok, file_name, line_num, err_msg, elevel))
1453  return NULL;
1454 
1455  parsedline->databases = lappend(parsedline->databases, tok);
1456  }
1457 
1458  /* Get the roles. */
1459  field = lnext(tok_line->fields, field);
1460  if (!field)
1461  {
1462  ereport(elevel,
1463  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1464  errmsg("end-of-line before role specification"),
1465  errcontext("line %d of configuration file \"%s\"",
1466  line_num, file_name)));
1467  *err_msg = "end-of-line before role specification";
1468  return NULL;
1469  }
1470  parsedline->roles = NIL;
1471  tokens = lfirst(field);
1472  foreach(tokencell, tokens)
1473  {
1474  AuthToken *tok = copy_auth_token(lfirst(tokencell));
1475 
1476  /* Compile a regexp from the role token, if necessary */
1477  if (regcomp_auth_token(tok, file_name, line_num, err_msg, elevel))
1478  return NULL;
1479 
1480  parsedline->roles = lappend(parsedline->roles, tok);
1481  }
1482 
1483  if (parsedline->conntype != ctLocal)
1484  {
1485  /* Read the IP address field. (with or without CIDR netmask) */
1486  field = lnext(tok_line->fields, field);
1487  if (!field)
1488  {
1489  ereport(elevel,
1490  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1491  errmsg("end-of-line before IP address specification"),
1492  errcontext("line %d of configuration file \"%s\"",
1493  line_num, file_name)));
1494  *err_msg = "end-of-line before IP address specification";
1495  return NULL;
1496  }
1497  tokens = lfirst(field);
1498  if (tokens->length > 1)
1499  {
1500  ereport(elevel,
1501  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1502  errmsg("multiple values specified for host address"),
1503  errhint("Specify one address range per line."),
1504  errcontext("line %d of configuration file \"%s\"",
1505  line_num, file_name)));
1506  *err_msg = "multiple values specified for host address";
1507  return NULL;
1508  }
1509  token = linitial(tokens);
1510 
1511  if (token_is_keyword(token, "all"))
1512  {
1513  parsedline->ip_cmp_method = ipCmpAll;
1514  }
1515  else if (token_is_keyword(token, "samehost"))
1516  {
1517  /* Any IP on this host is allowed to connect */
1518  parsedline->ip_cmp_method = ipCmpSameHost;
1519  }
1520  else if (token_is_keyword(token, "samenet"))
1521  {
1522  /* Any IP on the host's subnets is allowed to connect */
1523  parsedline->ip_cmp_method = ipCmpSameNet;
1524  }
1525  else
1526  {
1527  /* IP and netmask are specified */
1528  parsedline->ip_cmp_method = ipCmpMask;
1529 
1530  /* need a modifiable copy of token */
1531  str = pstrdup(token->string);
1532 
1533  /* Check if it has a CIDR suffix and if so isolate it */
1534  cidr_slash = strchr(str, '/');
1535  if (cidr_slash)
1536  *cidr_slash = '\0';
1537 
1538  /* Get the IP address either way */
1539  hints.ai_flags = AI_NUMERICHOST;
1540  hints.ai_family = AF_UNSPEC;
1541  hints.ai_socktype = 0;
1542  hints.ai_protocol = 0;
1543  hints.ai_addrlen = 0;
1544  hints.ai_canonname = NULL;
1545  hints.ai_addr = NULL;
1546  hints.ai_next = NULL;
1547 
1548  ret = pg_getaddrinfo_all(str, NULL, &hints, &gai_result);
1549  if (ret == 0 && gai_result)
1550  {
1551  memcpy(&parsedline->addr, gai_result->ai_addr,
1552  gai_result->ai_addrlen);
1553  parsedline->addrlen = gai_result->ai_addrlen;
1554  }
1555  else if (ret == EAI_NONAME)
1556  parsedline->hostname = str;
1557  else
1558  {
1559  ereport(elevel,
1560  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1561  errmsg("invalid IP address \"%s\": %s",
1562  str, gai_strerror(ret)),
1563  errcontext("line %d of configuration file \"%s\"",
1564  line_num, file_name)));
1565  *err_msg = psprintf("invalid IP address \"%s\": %s",
1566  str, gai_strerror(ret));
1567  if (gai_result)
1568  pg_freeaddrinfo_all(hints.ai_family, gai_result);
1569  return NULL;
1570  }
1571 
1572  pg_freeaddrinfo_all(hints.ai_family, gai_result);
1573 
1574  /* Get the netmask */
1575  if (cidr_slash)
1576  {
1577  if (parsedline->hostname)
1578  {
1579  ereport(elevel,
1580  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1581  errmsg("specifying both host name and CIDR mask is invalid: \"%s\"",
1582  token->string),
1583  errcontext("line %d of configuration file \"%s\"",
1584  line_num, file_name)));
1585  *err_msg = psprintf("specifying both host name and CIDR mask is invalid: \"%s\"",
1586  token->string);
1587  return NULL;
1588  }
1589 
1590  if (pg_sockaddr_cidr_mask(&parsedline->mask, cidr_slash + 1,
1591  parsedline->addr.ss_family) < 0)
1592  {
1593  ereport(elevel,
1594  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1595  errmsg("invalid CIDR mask in address \"%s\"",
1596  token->string),
1597  errcontext("line %d of configuration file \"%s\"",
1598  line_num, file_name)));
1599  *err_msg = psprintf("invalid CIDR mask in address \"%s\"",
1600  token->string);
1601  return NULL;
1602  }
1603  parsedline->masklen = parsedline->addrlen;
1604  pfree(str);
1605  }
1606  else if (!parsedline->hostname)
1607  {
1608  /* Read the mask field. */
1609  pfree(str);
1610  field = lnext(tok_line->fields, field);
1611  if (!field)
1612  {
1613  ereport(elevel,
1614  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1615  errmsg("end-of-line before netmask specification"),
1616  errhint("Specify an address range in CIDR notation, or provide a separate netmask."),
1617  errcontext("line %d of configuration file \"%s\"",
1618  line_num, file_name)));
1619  *err_msg = "end-of-line before netmask specification";
1620  return NULL;
1621  }
1622  tokens = lfirst(field);
1623  if (tokens->length > 1)
1624  {
1625  ereport(elevel,
1626  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1627  errmsg("multiple values specified for netmask"),
1628  errcontext("line %d of configuration file \"%s\"",
1629  line_num, file_name)));
1630  *err_msg = "multiple values specified for netmask";
1631  return NULL;
1632  }
1633  token = linitial(tokens);
1634 
1635  ret = pg_getaddrinfo_all(token->string, NULL,
1636  &hints, &gai_result);
1637  if (ret || !gai_result)
1638  {
1639  ereport(elevel,
1640  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1641  errmsg("invalid IP mask \"%s\": %s",
1642  token->string, gai_strerror(ret)),
1643  errcontext("line %d of configuration file \"%s\"",
1644  line_num, file_name)));
1645  *err_msg = psprintf("invalid IP mask \"%s\": %s",
1646  token->string, gai_strerror(ret));
1647  if (gai_result)
1648  pg_freeaddrinfo_all(hints.ai_family, gai_result);
1649  return NULL;
1650  }
1651 
1652  memcpy(&parsedline->mask, gai_result->ai_addr,
1653  gai_result->ai_addrlen);
1654  parsedline->masklen = gai_result->ai_addrlen;
1655  pg_freeaddrinfo_all(hints.ai_family, gai_result);
1656 
1657  if (parsedline->addr.ss_family != parsedline->mask.ss_family)
1658  {
1659  ereport(elevel,
1660  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1661  errmsg("IP address and mask do not match"),
1662  errcontext("line %d of configuration file \"%s\"",
1663  line_num, file_name)));
1664  *err_msg = "IP address and mask do not match";
1665  return NULL;
1666  }
1667  }
1668  }
1669  } /* != ctLocal */
1670 
1671  /* Get the authentication method */
1672  field = lnext(tok_line->fields, field);
1673  if (!field)
1674  {
1675  ereport(elevel,
1676  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1677  errmsg("end-of-line before authentication method"),
1678  errcontext("line %d of configuration file \"%s\"",
1679  line_num, file_name)));
1680  *err_msg = "end-of-line before authentication method";
1681  return NULL;
1682  }
1683  tokens = lfirst(field);
1684  if (tokens->length > 1)
1685  {
1686  ereport(elevel,
1687  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1688  errmsg("multiple values specified for authentication type"),
1689  errhint("Specify exactly one authentication type per line."),
1690  errcontext("line %d of configuration file \"%s\"",
1691  line_num, file_name)));
1692  *err_msg = "multiple values specified for authentication type";
1693  return NULL;
1694  }
1695  token = linitial(tokens);
1696 
1697  unsupauth = NULL;
1698  if (strcmp(token->string, "trust") == 0)
1699  parsedline->auth_method = uaTrust;
1700  else if (strcmp(token->string, "ident") == 0)
1701  parsedline->auth_method = uaIdent;
1702  else if (strcmp(token->string, "peer") == 0)
1703  parsedline->auth_method = uaPeer;
1704  else if (strcmp(token->string, "password") == 0)
1705  parsedline->auth_method = uaPassword;
1706  else if (strcmp(token->string, "gss") == 0)
1707 #ifdef ENABLE_GSS
1708  parsedline->auth_method = uaGSS;
1709 #else
1710  unsupauth = "gss";
1711 #endif
1712  else if (strcmp(token->string, "sspi") == 0)
1713 #ifdef ENABLE_SSPI
1714  parsedline->auth_method = uaSSPI;
1715 #else
1716  unsupauth = "sspi";
1717 #endif
1718  else if (strcmp(token->string, "reject") == 0)
1719  parsedline->auth_method = uaReject;
1720  else if (strcmp(token->string, "md5") == 0)
1721  parsedline->auth_method = uaMD5;
1722  else if (strcmp(token->string, "scram-sha-256") == 0)
1723  parsedline->auth_method = uaSCRAM;
1724  else if (strcmp(token->string, "pam") == 0)
1725 #ifdef USE_PAM
1726  parsedline->auth_method = uaPAM;
1727 #else
1728  unsupauth = "pam";
1729 #endif
1730  else if (strcmp(token->string, "bsd") == 0)
1731 #ifdef USE_BSD_AUTH
1732  parsedline->auth_method = uaBSD;
1733 #else
1734  unsupauth = "bsd";
1735 #endif
1736  else if (strcmp(token->string, "ldap") == 0)
1737 #ifdef USE_LDAP
1738  parsedline->auth_method = uaLDAP;
1739 #else
1740  unsupauth = "ldap";
1741 #endif
1742  else if (strcmp(token->string, "cert") == 0)
1743 #ifdef USE_SSL
1744  parsedline->auth_method = uaCert;
1745 #else
1746  unsupauth = "cert";
1747 #endif
1748  else if (strcmp(token->string, "radius") == 0)
1749  parsedline->auth_method = uaRADIUS;
1750  else
1751  {
1752  ereport(elevel,
1753  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1754  errmsg("invalid authentication method \"%s\"",
1755  token->string),
1756  errcontext("line %d of configuration file \"%s\"",
1757  line_num, file_name)));
1758  *err_msg = psprintf("invalid authentication method \"%s\"",
1759  token->string);
1760  return NULL;
1761  }
1762 
1763  if (unsupauth)
1764  {
1765  ereport(elevel,
1766  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1767  errmsg("invalid authentication method \"%s\": not supported by this build",
1768  token->string),
1769  errcontext("line %d of configuration file \"%s\"",
1770  line_num, file_name)));
1771  *err_msg = psprintf("invalid authentication method \"%s\": not supported by this build",
1772  token->string);
1773  return NULL;
1774  }
1775 
1776  /*
1777  * XXX: When using ident on local connections, change it to peer, for
1778  * backwards compatibility.
1779  */
1780  if (parsedline->conntype == ctLocal &&
1781  parsedline->auth_method == uaIdent)
1782  parsedline->auth_method = uaPeer;
1783 
1784  /* Invalid authentication combinations */
1785  if (parsedline->conntype == ctLocal &&
1786  parsedline->auth_method == uaGSS)
1787  {
1788  ereport(elevel,
1789  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1790  errmsg("gssapi authentication is not supported on local sockets"),
1791  errcontext("line %d of configuration file \"%s\"",
1792  line_num, file_name)));
1793  *err_msg = "gssapi authentication is not supported on local sockets";
1794  return NULL;
1795  }
1796 
1797  if (parsedline->conntype != ctLocal &&
1798  parsedline->auth_method == uaPeer)
1799  {
1800  ereport(elevel,
1801  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1802  errmsg("peer authentication is only supported on local sockets"),
1803  errcontext("line %d of configuration file \"%s\"",
1804  line_num, file_name)));
1805  *err_msg = "peer authentication is only supported on local sockets";
1806  return NULL;
1807  }
1808 
1809  /*
1810  * SSPI authentication can never be enabled on ctLocal connections,
1811  * because it's only supported on Windows, where ctLocal isn't supported.
1812  */
1813 
1814 
1815  if (parsedline->conntype != ctHostSSL &&
1816  parsedline->auth_method == uaCert)
1817  {
1818  ereport(elevel,
1819  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1820  errmsg("cert authentication is only supported on hostssl connections"),
1821  errcontext("line %d of configuration file \"%s\"",
1822  line_num, file_name)));
1823  *err_msg = "cert authentication is only supported on hostssl connections";
1824  return NULL;
1825  }
1826 
1827  /*
1828  * For GSS and SSPI, set the default value of include_realm to true.
1829  * Having include_realm set to false is dangerous in multi-realm
1830  * situations and is generally considered bad practice. We keep the
1831  * capability around for backwards compatibility, but we might want to
1832  * remove it at some point in the future. Users who still need to strip
1833  * the realm off would be better served by using an appropriate regex in a
1834  * pg_ident.conf mapping.
1835  */
1836  if (parsedline->auth_method == uaGSS ||
1837  parsedline->auth_method == uaSSPI)
1838  parsedline->include_realm = true;
1839 
1840  /*
1841  * For SSPI, include_realm defaults to the SAM-compatible domain (aka
1842  * NetBIOS name) and user names instead of the Kerberos principal name for
1843  * compatibility.
1844  */
1845  if (parsedline->auth_method == uaSSPI)
1846  {
1847  parsedline->compat_realm = true;
1848  parsedline->upn_username = false;
1849  }
1850 
1851  /* Parse remaining arguments */
1852  while ((field = lnext(tok_line->fields, field)) != NULL)
1853  {
1854  tokens = lfirst(field);
1855  foreach(tokencell, tokens)
1856  {
1857  char *val;
1858 
1859  token = lfirst(tokencell);
1860 
1861  str = pstrdup(token->string);
1862  val = strchr(str, '=');
1863  if (val == NULL)
1864  {
1865  /*
1866  * Got something that's not a name=value pair.
1867  */
1868  ereport(elevel,
1869  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1870  errmsg("authentication option not in name=value format: %s", token->string),
1871  errcontext("line %d of configuration file \"%s\"",
1872  line_num, file_name)));
1873  *err_msg = psprintf("authentication option not in name=value format: %s",
1874  token->string);
1875  return NULL;
1876  }
1877 
1878  *val++ = '\0'; /* str now holds "name", val holds "value" */
1879  if (!parse_hba_auth_opt(str, val, parsedline, elevel, err_msg))
1880  /* parse_hba_auth_opt already logged the error message */
1881  return NULL;
1882  pfree(str);
1883  }
1884  }
1885 
1886  /*
1887  * Check if the selected authentication method has any mandatory arguments
1888  * that are not set.
1889  */
1890  if (parsedline->auth_method == uaLDAP)
1891  {
1892 #ifndef HAVE_LDAP_INITIALIZE
1893  /* Not mandatory for OpenLDAP, because it can use DNS SRV records */
1894  MANDATORY_AUTH_ARG(parsedline->ldapserver, "ldapserver", "ldap");
1895 #endif
1896 
1897  /*
1898  * LDAP can operate in two modes: either with a direct bind, using
1899  * ldapprefix and ldapsuffix, or using a search+bind, using
1900  * ldapbasedn, ldapbinddn, ldapbindpasswd and one of
1901  * ldapsearchattribute or ldapsearchfilter. Disallow mixing these
1902  * parameters.
1903  */
1904  if (parsedline->ldapprefix || parsedline->ldapsuffix)
1905  {
1906  if (parsedline->ldapbasedn ||
1907  parsedline->ldapbinddn ||
1908  parsedline->ldapbindpasswd ||
1909  parsedline->ldapsearchattribute ||
1910  parsedline->ldapsearchfilter)
1911  {
1912  ereport(elevel,
1913  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1914  errmsg("cannot mix options for simple bind and search+bind modes"),
1915  errcontext("line %d of configuration file \"%s\"",
1916  line_num, file_name)));
1917  *err_msg = "cannot mix options for simple bind and search+bind modes";
1918  return NULL;
1919  }
1920  }
1921  else if (!parsedline->ldapbasedn)
1922  {
1923  ereport(elevel,
1924  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1925  errmsg("authentication method \"ldap\" requires argument \"ldapbasedn\", \"ldapprefix\", or \"ldapsuffix\" to be set"),
1926  errcontext("line %d of configuration file \"%s\"",
1927  line_num, file_name)));
1928  *err_msg = "authentication method \"ldap\" requires argument \"ldapbasedn\", \"ldapprefix\", or \"ldapsuffix\" to be set";
1929  return NULL;
1930  }
1931 
1932  /*
1933  * When using search+bind, you can either use a simple attribute
1934  * (defaulting to "uid") or a fully custom search filter. You can't
1935  * do both.
1936  */
1937  if (parsedline->ldapsearchattribute && parsedline->ldapsearchfilter)
1938  {
1939  ereport(elevel,
1940  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1941  errmsg("cannot use ldapsearchattribute together with ldapsearchfilter"),
1942  errcontext("line %d of configuration file \"%s\"",
1943  line_num, file_name)));
1944  *err_msg = "cannot use ldapsearchattribute together with ldapsearchfilter";
1945  return NULL;
1946  }
1947  }
1948 
1949  if (parsedline->auth_method == uaRADIUS)
1950  {
1951  MANDATORY_AUTH_ARG(parsedline->radiusservers, "radiusservers", "radius");
1952  MANDATORY_AUTH_ARG(parsedline->radiussecrets, "radiussecrets", "radius");
1953 
1954  if (parsedline->radiusservers == NIL)
1955  {
1956  ereport(elevel,
1957  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1958  errmsg("list of RADIUS servers cannot be empty"),
1959  errcontext("line %d of configuration file \"%s\"",
1960  line_num, file_name)));
1961  *err_msg = "list of RADIUS servers cannot be empty";
1962  return NULL;
1963  }
1964 
1965  if (parsedline->radiussecrets == NIL)
1966  {
1967  ereport(elevel,
1968  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1969  errmsg("list of RADIUS secrets cannot be empty"),
1970  errcontext("line %d of configuration file \"%s\"",
1971  line_num, file_name)));
1972  *err_msg = "list of RADIUS secrets cannot be empty";
1973  return NULL;
1974  }
1975 
1976  /*
1977  * Verify length of option lists - each can be 0 (except for secrets,
1978  * but that's already checked above), 1 (use the same value
1979  * everywhere) or the same as the number of servers.
1980  */
1981  if (!(list_length(parsedline->radiussecrets) == 1 ||
1982  list_length(parsedline->radiussecrets) == list_length(parsedline->radiusservers)))
1983  {
1984  ereport(elevel,
1985  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1986  errmsg("the number of RADIUS secrets (%d) must be 1 or the same as the number of RADIUS servers (%d)",
1987  list_length(parsedline->radiussecrets),
1988  list_length(parsedline->radiusservers)),
1989  errcontext("line %d of configuration file \"%s\"",
1990  line_num, file_name)));
1991  *err_msg = psprintf("the number of RADIUS secrets (%d) must be 1 or the same as the number of RADIUS servers (%d)",
1992  list_length(parsedline->radiussecrets),
1993  list_length(parsedline->radiusservers));
1994  return NULL;
1995  }
1996  if (!(list_length(parsedline->radiusports) == 0 ||
1997  list_length(parsedline->radiusports) == 1 ||
1998  list_length(parsedline->radiusports) == list_length(parsedline->radiusservers)))
1999  {
2000  ereport(elevel,
2001  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2002  errmsg("the number of RADIUS ports (%d) must be 1 or the same as the number of RADIUS servers (%d)",
2003  list_length(parsedline->radiusports),
2004  list_length(parsedline->radiusservers)),
2005  errcontext("line %d of configuration file \"%s\"",
2006  line_num, file_name)));
2007  *err_msg = psprintf("the number of RADIUS ports (%d) must be 1 or the same as the number of RADIUS servers (%d)",
2008  list_length(parsedline->radiusports),
2009  list_length(parsedline->radiusservers));
2010  return NULL;
2011  }
2012  if (!(list_length(parsedline->radiusidentifiers) == 0 ||
2013  list_length(parsedline->radiusidentifiers) == 1 ||
2014  list_length(parsedline->radiusidentifiers) == list_length(parsedline->radiusservers)))
2015  {
2016  ereport(elevel,
2017  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2018  errmsg("the number of RADIUS identifiers (%d) must be 1 or the same as the number of RADIUS servers (%d)",
2019  list_length(parsedline->radiusidentifiers),
2020  list_length(parsedline->radiusservers)),
2021  errcontext("line %d of configuration file \"%s\"",
2022  line_num, file_name)));
2023  *err_msg = psprintf("the number of RADIUS identifiers (%d) must be 1 or the same as the number of RADIUS servers (%d)",
2024  list_length(parsedline->radiusidentifiers),
2025  list_length(parsedline->radiusservers));
2026  return NULL;
2027  }
2028  }
2029 
2030  /*
2031  * Enforce any parameters implied by other settings.
2032  */
2033  if (parsedline->auth_method == uaCert)
2034  {
2035  /*
2036  * For auth method cert, client certificate validation is mandatory,
2037  * and it implies the level of verify-full.
2038  */
2039  parsedline->clientcert = clientCertFull;
2040  }
2041 
2042  return parsedline;
2043 }
2044 
2045 
2046 /*
2047  * Parse one name-value pair as an authentication option into the given
2048  * HbaLine. Return true if we successfully parse the option, false if we
2049  * encounter an error. In the event of an error, also log a message at
2050  * ereport level elevel, and store a message string into *err_msg.
2051  */
2052 static bool
2053 parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline,
2054  int elevel, char **err_msg)
2055 {
2056  int line_num = hbaline->linenumber;
2057  char *file_name = hbaline->sourcefile;
2058 
2059 #ifdef USE_LDAP
2060  hbaline->ldapscope = LDAP_SCOPE_SUBTREE;
2061 #endif
2062 
2063  if (strcmp(name, "map") == 0)
2064  {
2065  if (hbaline->auth_method != uaIdent &&
2066  hbaline->auth_method != uaPeer &&
2067  hbaline->auth_method != uaGSS &&
2068  hbaline->auth_method != uaSSPI &&
2069  hbaline->auth_method != uaCert)
2070  INVALID_AUTH_OPTION("map", gettext_noop("ident, peer, gssapi, sspi, and cert"));
2071  hbaline->usermap = pstrdup(val);
2072  }
2073  else if (strcmp(name, "clientcert") == 0)
2074  {
2075  if (hbaline->conntype != ctHostSSL)
2076  {
2077  ereport(elevel,
2078  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2079  errmsg("clientcert can only be configured for \"hostssl\" rows"),
2080  errcontext("line %d of configuration file \"%s\"",
2081  line_num, file_name)));
2082  *err_msg = "clientcert can only be configured for \"hostssl\" rows";
2083  return false;
2084  }
2085 
2086  if (strcmp(val, "verify-full") == 0)
2087  {
2088  hbaline->clientcert = clientCertFull;
2089  }
2090  else if (strcmp(val, "verify-ca") == 0)
2091  {
2092  if (hbaline->auth_method == uaCert)
2093  {
2094  ereport(elevel,
2095  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2096  errmsg("clientcert only accepts \"verify-full\" when using \"cert\" authentication"),
2097  errcontext("line %d of configuration file \"%s\"",
2098  line_num, file_name)));
2099  *err_msg = "clientcert can only be set to \"verify-full\" when using \"cert\" authentication";
2100  return false;
2101  }
2102 
2103  hbaline->clientcert = clientCertCA;
2104  }
2105  else
2106  {
2107  ereport(elevel,
2108  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2109  errmsg("invalid value for clientcert: \"%s\"", val),
2110  errcontext("line %d of configuration file \"%s\"",
2111  line_num, file_name)));
2112  return false;
2113  }
2114  }
2115  else if (strcmp(name, "clientname") == 0)
2116  {
2117  if (hbaline->conntype != ctHostSSL)
2118  {
2119  ereport(elevel,
2120  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2121  errmsg("clientname can only be configured for \"hostssl\" rows"),
2122  errcontext("line %d of configuration file \"%s\"",
2123  line_num, file_name)));
2124  *err_msg = "clientname can only be configured for \"hostssl\" rows";
2125  return false;
2126  }
2127 
2128  if (strcmp(val, "CN") == 0)
2129  {
2130  hbaline->clientcertname = clientCertCN;
2131  }
2132  else if (strcmp(val, "DN") == 0)
2133  {
2134  hbaline->clientcertname = clientCertDN;
2135  }
2136  else
2137  {
2138  ereport(elevel,
2139  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2140  errmsg("invalid value for clientname: \"%s\"", val),
2141  errcontext("line %d of configuration file \"%s\"",
2142  line_num, file_name)));
2143  return false;
2144  }
2145  }
2146  else if (strcmp(name, "pamservice") == 0)
2147  {
2148  REQUIRE_AUTH_OPTION(uaPAM, "pamservice", "pam");
2149  hbaline->pamservice = pstrdup(val);
2150  }
2151  else if (strcmp(name, "pam_use_hostname") == 0)
2152  {
2153  REQUIRE_AUTH_OPTION(uaPAM, "pam_use_hostname", "pam");
2154  if (strcmp(val, "1") == 0)
2155  hbaline->pam_use_hostname = true;
2156  else
2157  hbaline->pam_use_hostname = false;
2158  }
2159  else if (strcmp(name, "ldapurl") == 0)
2160  {
2161 #ifdef LDAP_API_FEATURE_X_OPENLDAP
2162  LDAPURLDesc *urldata;
2163  int rc;
2164 #endif
2165 
2166  REQUIRE_AUTH_OPTION(uaLDAP, "ldapurl", "ldap");
2167 #ifdef LDAP_API_FEATURE_X_OPENLDAP
2168  rc = ldap_url_parse(val, &urldata);
2169  if (rc != LDAP_SUCCESS)
2170  {
2171  ereport(elevel,
2172  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2173  errmsg("could not parse LDAP URL \"%s\": %s", val, ldap_err2string(rc))));
2174  *err_msg = psprintf("could not parse LDAP URL \"%s\": %s",
2175  val, ldap_err2string(rc));
2176  return false;
2177  }
2178 
2179  if (strcmp(urldata->lud_scheme, "ldap") != 0 &&
2180  strcmp(urldata->lud_scheme, "ldaps") != 0)
2181  {
2182  ereport(elevel,
2183  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2184  errmsg("unsupported LDAP URL scheme: %s", urldata->lud_scheme)));
2185  *err_msg = psprintf("unsupported LDAP URL scheme: %s",
2186  urldata->lud_scheme);
2187  ldap_free_urldesc(urldata);
2188  return false;
2189  }
2190 
2191  if (urldata->lud_scheme)
2192  hbaline->ldapscheme = pstrdup(urldata->lud_scheme);
2193  if (urldata->lud_host)
2194  hbaline->ldapserver = pstrdup(urldata->lud_host);
2195  hbaline->ldapport = urldata->lud_port;
2196  if (urldata->lud_dn)
2197  hbaline->ldapbasedn = pstrdup(urldata->lud_dn);
2198 
2199  if (urldata->lud_attrs)
2200  hbaline->ldapsearchattribute = pstrdup(urldata->lud_attrs[0]); /* only use first one */
2201  hbaline->ldapscope = urldata->lud_scope;
2202  if (urldata->lud_filter)
2203  hbaline->ldapsearchfilter = pstrdup(urldata->lud_filter);
2204  ldap_free_urldesc(urldata);
2205 #else /* not OpenLDAP */
2206  ereport(elevel,
2207  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2208  errmsg("LDAP URLs not supported on this platform")));
2209  *err_msg = "LDAP URLs not supported on this platform";
2210 #endif /* not OpenLDAP */
2211  }
2212  else if (strcmp(name, "ldaptls") == 0)
2213  {
2214  REQUIRE_AUTH_OPTION(uaLDAP, "ldaptls", "ldap");
2215  if (strcmp(val, "1") == 0)
2216  hbaline->ldaptls = true;
2217  else
2218  hbaline->ldaptls = false;
2219  }
2220  else if (strcmp(name, "ldapscheme") == 0)
2221  {
2222  REQUIRE_AUTH_OPTION(uaLDAP, "ldapscheme", "ldap");
2223  if (strcmp(val, "ldap") != 0 && strcmp(val, "ldaps") != 0)
2224  ereport(elevel,
2225  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2226  errmsg("invalid ldapscheme value: \"%s\"", val),
2227  errcontext("line %d of configuration file \"%s\"",
2228  line_num, file_name)));
2229  hbaline->ldapscheme = pstrdup(val);
2230  }
2231  else if (strcmp(name, "ldapserver") == 0)
2232  {
2233  REQUIRE_AUTH_OPTION(uaLDAP, "ldapserver", "ldap");
2234  hbaline->ldapserver = pstrdup(val);
2235  }
2236  else if (strcmp(name, "ldapport") == 0)
2237  {
2238  REQUIRE_AUTH_OPTION(uaLDAP, "ldapport", "ldap");
2239  hbaline->ldapport = atoi(val);
2240  if (hbaline->ldapport == 0)
2241  {
2242  ereport(elevel,
2243  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2244  errmsg("invalid LDAP port number: \"%s\"", val),
2245  errcontext("line %d of configuration file \"%s\"",
2246  line_num, file_name)));
2247  *err_msg = psprintf("invalid LDAP port number: \"%s\"", val);
2248  return false;
2249  }
2250  }
2251  else if (strcmp(name, "ldapbinddn") == 0)
2252  {
2253  REQUIRE_AUTH_OPTION(uaLDAP, "ldapbinddn", "ldap");
2254  hbaline->ldapbinddn = pstrdup(val);
2255  }
2256  else if (strcmp(name, "ldapbindpasswd") == 0)
2257  {
2258  REQUIRE_AUTH_OPTION(uaLDAP, "ldapbindpasswd", "ldap");
2259  hbaline->ldapbindpasswd = pstrdup(val);
2260  }
2261  else if (strcmp(name, "ldapsearchattribute") == 0)
2262  {
2263  REQUIRE_AUTH_OPTION(uaLDAP, "ldapsearchattribute", "ldap");
2264  hbaline->ldapsearchattribute = pstrdup(val);
2265  }
2266  else if (strcmp(name, "ldapsearchfilter") == 0)
2267  {
2268  REQUIRE_AUTH_OPTION(uaLDAP, "ldapsearchfilter", "ldap");
2269  hbaline->ldapsearchfilter = pstrdup(val);
2270  }
2271  else if (strcmp(name, "ldapbasedn") == 0)
2272  {
2273  REQUIRE_AUTH_OPTION(uaLDAP, "ldapbasedn", "ldap");
2274  hbaline->ldapbasedn = pstrdup(val);
2275  }
2276  else if (strcmp(name, "ldapprefix") == 0)
2277  {
2278  REQUIRE_AUTH_OPTION(uaLDAP, "ldapprefix", "ldap");
2279  hbaline->ldapprefix = pstrdup(val);
2280  }
2281  else if (strcmp(name, "ldapsuffix") == 0)
2282  {
2283  REQUIRE_AUTH_OPTION(uaLDAP, "ldapsuffix", "ldap");
2284  hbaline->ldapsuffix = pstrdup(val);
2285  }
2286  else if (strcmp(name, "krb_realm") == 0)
2287  {
2288  if (hbaline->auth_method != uaGSS &&
2289  hbaline->auth_method != uaSSPI)
2290  INVALID_AUTH_OPTION("krb_realm", gettext_noop("gssapi and sspi"));
2291  hbaline->krb_realm = pstrdup(val);
2292  }
2293  else if (strcmp(name, "include_realm") == 0)
2294  {
2295  if (hbaline->auth_method != uaGSS &&
2296  hbaline->auth_method != uaSSPI)
2297  INVALID_AUTH_OPTION("include_realm", gettext_noop("gssapi and sspi"));
2298  if (strcmp(val, "1") == 0)
2299  hbaline->include_realm = true;
2300  else
2301  hbaline->include_realm = false;
2302  }
2303  else if (strcmp(name, "compat_realm") == 0)
2304  {
2305  if (hbaline->auth_method != uaSSPI)
2306  INVALID_AUTH_OPTION("compat_realm", gettext_noop("sspi"));
2307  if (strcmp(val, "1") == 0)
2308  hbaline->compat_realm = true;
2309  else
2310  hbaline->compat_realm = false;
2311  }
2312  else if (strcmp(name, "upn_username") == 0)
2313  {
2314  if (hbaline->auth_method != uaSSPI)
2315  INVALID_AUTH_OPTION("upn_username", gettext_noop("sspi"));
2316  if (strcmp(val, "1") == 0)
2317  hbaline->upn_username = true;
2318  else
2319  hbaline->upn_username = false;
2320  }
2321  else if (strcmp(name, "radiusservers") == 0)
2322  {
2323  struct addrinfo *gai_result;
2324  struct addrinfo hints;
2325  int ret;
2326  List *parsed_servers;
2327  ListCell *l;
2328  char *dupval = pstrdup(val);
2329 
2330  REQUIRE_AUTH_OPTION(uaRADIUS, "radiusservers", "radius");
2331 
2332  if (!SplitGUCList(dupval, ',', &parsed_servers))
2333  {
2334  /* syntax error in list */
2335  ereport(elevel,
2336  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2337  errmsg("could not parse RADIUS server list \"%s\"",
2338  val),
2339  errcontext("line %d of configuration file \"%s\"",
2340  line_num, file_name)));
2341  return false;
2342  }
2343 
2344  /* For each entry in the list, translate it */
2345  foreach(l, parsed_servers)
2346  {
2347  MemSet(&hints, 0, sizeof(hints));
2348  hints.ai_socktype = SOCK_DGRAM;
2349  hints.ai_family = AF_UNSPEC;
2350 
2351  ret = pg_getaddrinfo_all((char *) lfirst(l), NULL, &hints, &gai_result);
2352  if (ret || !gai_result)
2353  {
2354  ereport(elevel,
2355  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2356  errmsg("could not translate RADIUS server name \"%s\" to address: %s",
2357  (char *) lfirst(l), gai_strerror(ret)),
2358  errcontext("line %d of configuration file \"%s\"",
2359  line_num, file_name)));
2360  if (gai_result)
2361  pg_freeaddrinfo_all(hints.ai_family, gai_result);
2362 
2363  list_free(parsed_servers);
2364  return false;
2365  }
2366  pg_freeaddrinfo_all(hints.ai_family, gai_result);
2367  }
2368 
2369  /* All entries are OK, so store them */
2370  hbaline->radiusservers = parsed_servers;
2371  hbaline->radiusservers_s = pstrdup(val);
2372  }
2373  else if (strcmp(name, "radiusports") == 0)
2374  {
2375  List *parsed_ports;
2376  ListCell *l;
2377  char *dupval = pstrdup(val);
2378 
2379  REQUIRE_AUTH_OPTION(uaRADIUS, "radiusports", "radius");
2380 
2381  if (!SplitGUCList(dupval, ',', &parsed_ports))
2382  {
2383  ereport(elevel,
2384  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2385  errmsg("could not parse RADIUS port list \"%s\"",
2386  val),
2387  errcontext("line %d of configuration file \"%s\"",
2388  line_num, file_name)));
2389  *err_msg = psprintf("invalid RADIUS port number: \"%s\"", val);
2390  return false;
2391  }
2392 
2393  foreach(l, parsed_ports)
2394  {
2395  if (atoi(lfirst(l)) == 0)
2396  {
2397  ereport(elevel,
2398  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2399  errmsg("invalid RADIUS port number: \"%s\"", val),
2400  errcontext("line %d of configuration file \"%s\"",
2401  line_num, file_name)));
2402 
2403  return false;
2404  }
2405  }
2406  hbaline->radiusports = parsed_ports;
2407  hbaline->radiusports_s = pstrdup(val);
2408  }
2409  else if (strcmp(name, "radiussecrets") == 0)
2410  {
2411  List *parsed_secrets;
2412  char *dupval = pstrdup(val);
2413 
2414  REQUIRE_AUTH_OPTION(uaRADIUS, "radiussecrets", "radius");
2415 
2416  if (!SplitGUCList(dupval, ',', &parsed_secrets))
2417  {
2418  /* syntax error in list */
2419  ereport(elevel,
2420  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2421  errmsg("could not parse RADIUS secret list \"%s\"",
2422  val),
2423  errcontext("line %d of configuration file \"%s\"",
2424  line_num, file_name)));
2425  return false;
2426  }
2427 
2428  hbaline->radiussecrets = parsed_secrets;
2429  hbaline->radiussecrets_s = pstrdup(val);
2430  }
2431  else if (strcmp(name, "radiusidentifiers") == 0)
2432  {
2433  List *parsed_identifiers;
2434  char *dupval = pstrdup(val);
2435 
2436  REQUIRE_AUTH_OPTION(uaRADIUS, "radiusidentifiers", "radius");
2437 
2438  if (!SplitGUCList(dupval, ',', &parsed_identifiers))
2439  {
2440  /* syntax error in list */
2441  ereport(elevel,
2442  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2443  errmsg("could not parse RADIUS identifiers list \"%s\"",
2444  val),
2445  errcontext("line %d of configuration file \"%s\"",
2446  line_num, file_name)));
2447  return false;
2448  }
2449 
2450  hbaline->radiusidentifiers = parsed_identifiers;
2451  hbaline->radiusidentifiers_s = pstrdup(val);
2452  }
2453  else
2454  {
2455  ereport(elevel,
2456  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2457  errmsg("unrecognized authentication option name: \"%s\"",
2458  name),
2459  errcontext("line %d of configuration file \"%s\"",
2460  line_num, file_name)));
2461  *err_msg = psprintf("unrecognized authentication option name: \"%s\"",
2462  name);
2463  return false;
2464  }
2465  return true;
2466 }
2467 
2468 /*
2469  * Scan the pre-parsed hba file, looking for a match to the port's connection
2470  * request.
2471  */
2472 static void
2474 {
2475  Oid roleid;
2476  ListCell *line;
2477  HbaLine *hba;
2478 
2479  /* Get the target role's OID. Note we do not error out for bad role. */
2480  roleid = get_role_oid(port->user_name, true);
2481 
2482  foreach(line, parsed_hba_lines)
2483  {
2484  hba = (HbaLine *) lfirst(line);
2485 
2486  /* Check connection type */
2487  if (hba->conntype == ctLocal)
2488  {
2489  if (port->raddr.addr.ss_family != AF_UNIX)
2490  continue;
2491  }
2492  else
2493  {
2494  if (port->raddr.addr.ss_family == AF_UNIX)
2495  continue;
2496 
2497  /* Check SSL state */
2498  if (port->ssl_in_use)
2499  {
2500  /* Connection is SSL, match both "host" and "hostssl" */
2501  if (hba->conntype == ctHostNoSSL)
2502  continue;
2503  }
2504  else
2505  {
2506  /* Connection is not SSL, match both "host" and "hostnossl" */
2507  if (hba->conntype == ctHostSSL)
2508  continue;
2509  }
2510 
2511  /* Check GSSAPI state */
2512 #ifdef ENABLE_GSS
2513  if (port->gss && port->gss->enc &&
2514  hba->conntype == ctHostNoGSS)
2515  continue;
2516  else if (!(port->gss && port->gss->enc) &&
2517  hba->conntype == ctHostGSS)
2518  continue;
2519 #else
2520  if (hba->conntype == ctHostGSS)
2521  continue;
2522 #endif
2523 
2524  /* Check IP address */
2525  switch (hba->ip_cmp_method)
2526  {
2527  case ipCmpMask:
2528  if (hba->hostname)
2529  {
2530  if (!check_hostname(port,
2531  hba->hostname))
2532  continue;
2533  }
2534  else
2535  {
2536  if (!check_ip(&port->raddr,
2537  (struct sockaddr *) &hba->addr,
2538  (struct sockaddr *) &hba->mask))
2539  continue;
2540  }
2541  break;
2542  case ipCmpAll:
2543  break;
2544  case ipCmpSameHost:
2545  case ipCmpSameNet:
2546  if (!check_same_host_or_net(&port->raddr,
2547  hba->ip_cmp_method))
2548  continue;
2549  break;
2550  default:
2551  /* shouldn't get here, but deem it no-match if so */
2552  continue;
2553  }
2554  } /* != ctLocal */
2555 
2556  /* Check database and role */
2557  if (!check_db(port->database_name, port->user_name, roleid,
2558  hba->databases))
2559  continue;
2560 
2561  if (!check_role(port->user_name, roleid, hba->roles, false))
2562  continue;
2563 
2564  /* Found a record that matched! */
2565  port->hba = hba;
2566  return;
2567  }
2568 
2569  /* If no matching entry was found, then implicitly reject. */
2570  hba = palloc0(sizeof(HbaLine));
2572  port->hba = hba;
2573 }
2574 
2575 /*
2576  * Read the config file and create a List of HbaLine records for the contents.
2577  *
2578  * The configuration is read into a temporary list, and if any parse error
2579  * occurs the old list is kept in place and false is returned. Only if the
2580  * whole file parses OK is the list replaced, and the function returns true.
2581  *
2582  * On a false result, caller will take care of reporting a FATAL error in case
2583  * this is the initial startup. If it happens on reload, we just keep running
2584  * with the old data.
2585  */
2586 bool
2588 {
2589  FILE *file;
2590  List *hba_lines = NIL;
2591  ListCell *line;
2592  List *new_parsed_lines = NIL;
2593  bool ok = true;
2594  MemoryContext oldcxt;
2595  MemoryContext hbacxt;
2596 
2597  file = open_auth_file(HbaFileName, LOG, 0, NULL);
2598  if (file == NULL)
2599  {
2600  /* error already logged */
2601  return false;
2602  }
2603 
2604  tokenize_auth_file(HbaFileName, file, &hba_lines, LOG, 0);
2605 
2606  /* Now parse all the lines */
2609  "hba parser context",
2611  oldcxt = MemoryContextSwitchTo(hbacxt);
2612  foreach(line, hba_lines)
2613  {
2614  TokenizedAuthLine *tok_line = (TokenizedAuthLine *) lfirst(line);
2615  HbaLine *newline;
2616 
2617  /* don't parse lines that already have errors */
2618  if (tok_line->err_msg != NULL)
2619  {
2620  ok = false;
2621  continue;
2622  }
2623 
2624  if ((newline = parse_hba_line(tok_line, LOG)) == NULL)
2625  {
2626  /* Parse error; remember there's trouble */
2627  ok = false;
2628 
2629  /*
2630  * Keep parsing the rest of the file so we can report errors on
2631  * more than the first line. Error has already been logged, no
2632  * need for more chatter here.
2633  */
2634  continue;
2635  }
2636 
2637  new_parsed_lines = lappend(new_parsed_lines, newline);
2638  }
2639 
2640  /*
2641  * A valid HBA file must have at least one entry; else there's no way to
2642  * connect to the postmaster. But only complain about this if we didn't
2643  * already have parsing errors.
2644  */
2645  if (ok && new_parsed_lines == NIL)
2646  {
2647  ereport(LOG,
2648  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2649  errmsg("configuration file \"%s\" contains no entries",
2650  HbaFileName)));
2651  ok = false;
2652  }
2653 
2654  /* Free tokenizer memory */
2655  free_auth_file(file, 0);
2656  MemoryContextSwitchTo(oldcxt);
2657 
2658  if (!ok)
2659  {
2660  /*
2661  * File contained one or more errors, so bail out. MemoryContextDelete
2662  * is enough to clean up everything, including regexes.
2663  */
2664  MemoryContextDelete(hbacxt);
2665  return false;
2666  }
2667 
2668  /* Loaded new file successfully, replace the one we use */
2669  if (parsed_hba_context != NULL)
2671  parsed_hba_context = hbacxt;
2672  parsed_hba_lines = new_parsed_lines;
2673 
2674  return true;
2675 }
2676 
2677 
2678 /*
2679  * Parse one tokenised line from the ident config file and store the result in
2680  * an IdentLine structure.
2681  *
2682  * If parsing fails, log a message at ereport level elevel, store an error
2683  * string in tok_line->err_msg and return NULL.
2684  *
2685  * If ident_user is a regular expression (ie. begins with a slash), it is
2686  * compiled and stored in IdentLine structure.
2687  *
2688  * Note: this function leaks memory when an error occurs. Caller is expected
2689  * to have set a memory context that will be reset if this function returns
2690  * NULL.
2691  */
2692 IdentLine *
2693 parse_ident_line(TokenizedAuthLine *tok_line, int elevel)
2694 {
2695  int line_num = tok_line->line_num;
2696  char *file_name = tok_line->file_name;
2697  char **err_msg = &tok_line->err_msg;
2698  ListCell *field;
2699  List *tokens;
2700  AuthToken *token;
2701  IdentLine *parsedline;
2702 
2703  Assert(tok_line->fields != NIL);
2704  field = list_head(tok_line->fields);
2705 
2706  parsedline = palloc0(sizeof(IdentLine));
2707  parsedline->linenumber = line_num;
2708 
2709  /* Get the map token (must exist) */
2710  tokens = lfirst(field);
2711  IDENT_MULTI_VALUE(tokens);
2712  token = linitial(tokens);
2713  parsedline->usermap = pstrdup(token->string);
2714 
2715  /* Get the ident user token */
2716  field = lnext(tok_line->fields, field);
2717  IDENT_FIELD_ABSENT(field);
2718  tokens = lfirst(field);
2719  IDENT_MULTI_VALUE(tokens);
2720  token = linitial(tokens);
2721 
2722  /* Copy the ident user token */
2723  parsedline->system_user = copy_auth_token(token);
2724 
2725  /* Get the PG rolename token */
2726  field = lnext(tok_line->fields, field);
2727  IDENT_FIELD_ABSENT(field);
2728  tokens = lfirst(field);
2729  IDENT_MULTI_VALUE(tokens);
2730  token = linitial(tokens);
2731  parsedline->pg_user = copy_auth_token(token);
2732 
2733  /*
2734  * Now that the field validation is done, compile a regex from the user
2735  * tokens, if necessary.
2736  */
2737  if (regcomp_auth_token(parsedline->system_user, file_name, line_num,
2738  err_msg, elevel))
2739  {
2740  /* err_msg includes the error to report */
2741  return NULL;
2742  }
2743 
2744  if (regcomp_auth_token(parsedline->pg_user, file_name, line_num,
2745  err_msg, elevel))
2746  {
2747  /* err_msg includes the error to report */
2748  return NULL;
2749  }
2750 
2751  return parsedline;
2752 }
2753 
2754 /*
2755  * Process one line from the parsed ident config lines.
2756  *
2757  * Compare input parsed ident line to the needed map, pg_user and system_user.
2758  * *found_p and *error_p are set according to our results.
2759  */
2760 static void
2761 check_ident_usermap(IdentLine *identLine, const char *usermap_name,
2762  const char *pg_user, const char *system_user,
2763  bool case_insensitive, bool *found_p, bool *error_p)
2764 {
2765  Oid roleid;
2766 
2767  *found_p = false;
2768  *error_p = false;
2769 
2770  if (strcmp(identLine->usermap, usermap_name) != 0)
2771  /* Line does not match the map name we're looking for, so just abort */
2772  return;
2773 
2774  /* Get the target role's OID. Note we do not error out for bad role. */
2775  roleid = get_role_oid(pg_user, true);
2776 
2777  /* Match? */
2778  if (token_has_regexp(identLine->system_user))
2779  {
2780  /*
2781  * Process the system username as a regular expression that returns
2782  * exactly one match. This is replaced for \1 in the database username
2783  * string, if present.
2784  */
2785  int r;
2786  regmatch_t matches[2];
2787  char *ofs;
2788  AuthToken *expanded_pg_user_token;
2789  bool created_temporary_token = false;
2790 
2791  r = regexec_auth_token(system_user, identLine->system_user, 2, matches);
2792  if (r)
2793  {
2794  char errstr[100];
2795 
2796  if (r != REG_NOMATCH)
2797  {
2798  /* REG_NOMATCH is not an error, everything else is */
2799  pg_regerror(r, identLine->system_user->regex, errstr, sizeof(errstr));
2800  ereport(LOG,
2801  (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
2802  errmsg("regular expression match for \"%s\" failed: %s",
2803  identLine->system_user->string + 1, errstr)));
2804  *error_p = true;
2805  }
2806  return;
2807  }
2808 
2809  /*
2810  * Replace \1 with the first captured group unless the field already
2811  * has some special meaning, like a group membership or a regexp-based
2812  * check.
2813  */
2814  if (!token_is_member_check(identLine->pg_user) &&
2815  !token_has_regexp(identLine->pg_user) &&
2816  (ofs = strstr(identLine->pg_user->string, "\\1")) != NULL)
2817  {
2818  char *expanded_pg_user;
2819  int offset;
2820 
2821  /* substitution of the first argument requested */
2822  if (matches[1].rm_so < 0)
2823  {
2824  ereport(LOG,
2825  (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
2826  errmsg("regular expression \"%s\" has no subexpressions as requested by backreference in \"%s\"",
2827  identLine->system_user->string + 1, identLine->pg_user->string)));
2828  *error_p = true;
2829  return;
2830  }
2831 
2832  /*
2833  * length: original length minus length of \1 plus length of match
2834  * plus null terminator
2835  */
2836  expanded_pg_user = palloc0(strlen(identLine->pg_user->string) - 2 + (matches[1].rm_eo - matches[1].rm_so) + 1);
2837  offset = ofs - identLine->pg_user->string;
2838  memcpy(expanded_pg_user, identLine->pg_user->string, offset);
2839  memcpy(expanded_pg_user + offset,
2840  system_user + matches[1].rm_so,
2841  matches[1].rm_eo - matches[1].rm_so);
2842  strcat(expanded_pg_user, ofs + 2);
2843 
2844  /*
2845  * Mark the token as quoted, so it will only be compared literally
2846  * and not for some special meaning, such as "all" or a group
2847  * membership check.
2848  */
2849  expanded_pg_user_token = make_auth_token(expanded_pg_user, true);
2850  created_temporary_token = true;
2851  pfree(expanded_pg_user);
2852  }
2853  else
2854  {
2855  expanded_pg_user_token = identLine->pg_user;
2856  }
2857 
2858  /* check the Postgres user */
2859  *found_p = check_role(pg_user, roleid,
2860  list_make1(expanded_pg_user_token),
2861  case_insensitive);
2862 
2863  if (created_temporary_token)
2864  free_auth_token(expanded_pg_user_token);
2865 
2866  return;
2867  }
2868  else
2869  {
2870  /*
2871  * Not a regular expression, so make a complete match. If the system
2872  * user does not match, just leave.
2873  */
2874  if (case_insensitive)
2875  {
2876  if (!token_matches_insensitive(identLine->system_user,
2877  system_user))
2878  return;
2879  }
2880  else
2881  {
2882  if (!token_matches(identLine->system_user, system_user))
2883  return;
2884  }
2885 
2886  /* check the Postgres user */
2887  *found_p = check_role(pg_user, roleid,
2888  list_make1(identLine->pg_user),
2889  case_insensitive);
2890  }
2891 }
2892 
2893 
2894 /*
2895  * Scan the (pre-parsed) ident usermap file line by line, looking for a match
2896  *
2897  * See if the system user with ident username "system_user" is allowed to act as
2898  * Postgres user "pg_user" according to usermap "usermap_name".
2899  *
2900  * Special case: Usermap NULL, equivalent to what was previously called
2901  * "sameuser" or "samerole", means don't look in the usermap file.
2902  * That's an implied map wherein "pg_user" must be identical to
2903  * "system_user" in order to be authorized.
2904  *
2905  * Iff authorized, return STATUS_OK, otherwise return STATUS_ERROR.
2906  */
2907 int
2908 check_usermap(const char *usermap_name,
2909  const char *pg_user,
2910  const char *system_user,
2911  bool case_insensitive)
2912 {
2913  bool found_entry = false,
2914  error = false;
2915 
2916  if (usermap_name == NULL || usermap_name[0] == '\0')
2917  {
2918  if (case_insensitive)
2919  {
2920  if (pg_strcasecmp(pg_user, system_user) == 0)
2921  return STATUS_OK;
2922  }
2923  else
2924  {
2925  if (strcmp(pg_user, system_user) == 0)
2926  return STATUS_OK;
2927  }
2928  ereport(LOG,
2929  (errmsg("provided user name (%s) and authenticated user name (%s) do not match",
2930  pg_user, system_user)));
2931  return STATUS_ERROR;
2932  }
2933  else
2934  {
2935  ListCell *line_cell;
2936 
2937  foreach(line_cell, parsed_ident_lines)
2938  {
2939  check_ident_usermap(lfirst(line_cell), usermap_name,
2940  pg_user, system_user, case_insensitive,
2941  &found_entry, &error);
2942  if (found_entry || error)
2943  break;
2944  }
2945  }
2946  if (!found_entry && !error)
2947  {
2948  ereport(LOG,
2949  (errmsg("no match in usermap \"%s\" for user \"%s\" authenticated as \"%s\"",
2950  usermap_name, pg_user, system_user)));
2951  }
2952  return found_entry ? STATUS_OK : STATUS_ERROR;
2953 }
2954 
2955 
2956 /*
2957  * Read the ident config file and create a List of IdentLine records for
2958  * the contents.
2959  *
2960  * This works the same as load_hba(), but for the user config file.
2961  */
2962 bool
2964 {
2965  FILE *file;
2966  List *ident_lines = NIL;
2967  ListCell *line_cell;
2968  List *new_parsed_lines = NIL;
2969  bool ok = true;
2970  MemoryContext oldcxt;
2971  MemoryContext ident_context;
2972  IdentLine *newline;
2973 
2974  /* not FATAL ... we just won't do any special ident maps */
2975  file = open_auth_file(IdentFileName, LOG, 0, NULL);
2976  if (file == NULL)
2977  {
2978  /* error already logged */
2979  return false;
2980  }
2981 
2982  tokenize_auth_file(IdentFileName, file, &ident_lines, LOG, 0);
2983 
2984  /* Now parse all the lines */
2986  ident_context = AllocSetContextCreate(PostmasterContext,
2987  "ident parser context",
2989  oldcxt = MemoryContextSwitchTo(ident_context);
2990  foreach(line_cell, ident_lines)
2991  {
2992  TokenizedAuthLine *tok_line = (TokenizedAuthLine *) lfirst(line_cell);
2993 
2994  /* don't parse lines that already have errors */
2995  if (tok_line->err_msg != NULL)
2996  {
2997  ok = false;
2998  continue;
2999  }
3000 
3001  if ((newline = parse_ident_line(tok_line, LOG)) == NULL)
3002  {
3003  /* Parse error; remember there's trouble */
3004  ok = false;
3005 
3006  /*
3007  * Keep parsing the rest of the file so we can report errors on
3008  * more than the first line. Error has already been logged, no
3009  * need for more chatter here.
3010  */
3011  continue;
3012  }
3013 
3014  new_parsed_lines = lappend(new_parsed_lines, newline);
3015  }
3016 
3017  /* Free tokenizer memory */
3018  free_auth_file(file, 0);
3019  MemoryContextSwitchTo(oldcxt);
3020 
3021  if (!ok)
3022  {
3023  /*
3024  * File contained one or more errors, so bail out. MemoryContextDelete
3025  * is enough to clean up everything, including regexes.
3026  */
3027  MemoryContextDelete(ident_context);
3028  return false;
3029  }
3030 
3031  /* Loaded new file successfully, replace the one we use */
3032  if (parsed_ident_context != NULL)
3034 
3035  parsed_ident_context = ident_context;
3036  parsed_ident_lines = new_parsed_lines;
3037 
3038  return true;
3039 }
3040 
3041 
3042 
3043 /*
3044  * Determine what authentication method should be used when accessing database
3045  * "database" from frontend "raddr", user "user". Return the method and
3046  * an optional argument (stored in fields of *port), and STATUS_OK.
3047  *
3048  * If the file does not contain any entry matching the request, we return
3049  * method = uaImplicitReject.
3050  */
3051 void
3053 {
3054  check_hba(port);
3055 }
3056 
3057 
3058 /*
3059  * Return the name of the auth method in use ("gss", "md5", "trust", etc.).
3060  *
3061  * The return value is statically allocated (see the UserAuthName array) and
3062  * should not be freed.
3063  */
3064 const char *
3066 {
3067  return UserAuthName[auth_method];
3068 }
bool is_member_of_role_nosuper(Oid member, Oid role)
Definition: acl.c:5376
Oid get_role_oid(const char *rolname, bool missing_ok)
Definition: acl.c:5554
#define STATUS_OK
Definition: c.h:1160
#define gettext_noop(x)
Definition: c.h:1187
#define Assert(condition)
Definition: c.h:849
#define lengthof(array)
Definition: c.h:779
#define MemSet(start, val, len)
Definition: c.h:1011
#define STATUS_ERROR
Definition: c.h:1161
#define OidIsValid(objectId)
Definition: c.h:766
char * AbsoluteConfigLocation(const char *location, const char *calling_file)
Definition: conffiles.c:36
char ** GetConfFilesInDir(const char *includedir, const char *calling_file, int elevel, int *num_filenames, char **err_msg)
Definition: conffiles.c:70
#define CONF_FILE_MAX_DEPTH
Definition: conffiles.h:18
#define CONF_FILE_START_DEPTH
Definition: conffiles.h:17
int errcode_for_file_access(void)
Definition: elog.c:876
ErrorContextCallback * error_context_stack
Definition: elog.c:94
int errhint(const char *fmt,...)
Definition: elog.c:1317
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define LOG
Definition: elog.h:31
#define errcontext
Definition: elog.h:196
#define DEBUG2
Definition: elog.h:29
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2606
int FreeFile(FILE *file)
Definition: fd.c:2804
char * HbaFileName
Definition: guc_tables.c:539
char * IdentFileName
Definition: guc_tables.c:540
const char * str
IdentLine * parse_ident_line(TokenizedAuthLine *tok_line, int elevel)
Definition: hba.c:2693
bool pg_isblank(const char c)
Definition: hba.c:144
FILE * open_auth_file(const char *filename, int elevel, int depth, char **err_msg)
Definition: hba.c:595
#define MANDATORY_AUTH_ARG(argvar, argname, authname)
Definition: hba.c:1262
static bool is_member(Oid userid, const char *role)
Definition: hba.c:923
static bool check_role(const char *role, Oid roleid, List *tokens, bool case_insensitive)
Definition: hba.c:952
static bool hostname_match(const char *pattern, const char *actual_hostname)
Definition: hba.c:1056
StaticAssertDecl(lengthof(UserAuthName)==USER_AUTH_LAST+1, "UserAuthName[] must match the UserAuth enum")
static List * next_field_expand(const char *filename, char **lineptr, int elevel, int depth, char **err_msg)
Definition: hba.c:379
static bool check_ip(SockAddr *raddr, struct sockaddr *addr, struct sockaddr *mask)
Definition: hba.c:1167
#define token_is_member_check(t)
Definition: hba.c:69
#define IDENT_FIELD_ABSENT(field)
Definition: hba.c:1286
#define token_is_keyword(t, k)
Definition: hba.c:70
static bool ipv4eq(struct sockaddr_in *a, struct sockaddr_in *b)
Definition: hba.c:1035
static MemoryContext parsed_ident_context
Definition: hba.c:93
#define token_matches_insensitive(t, k)
Definition: hba.c:72
bool load_ident(void)
Definition: hba.c:2963
struct check_network_data check_network_data
static bool parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline, int elevel, char **err_msg)
Definition: hba.c:2053
static bool check_same_host_or_net(SockAddr *raddr, IPCompareMethod method)
Definition: hba.c:1208
static int regcomp_auth_token(AuthToken *token, char *filename, int line_num, char **err_msg, int elevel)
Definition: hba.c:301
static MemoryContext tokenize_context
Definition: hba.c:79
static int regexec_auth_token(const char *match, AuthToken *token, size_t nmatch, regmatch_t pmatch[])
Definition: hba.c:346
static void tokenize_include_file(const char *outer_filename, const char *inc_filename, List **tok_lines, int elevel, int depth, bool missing_ok, char **err_msg)
Definition: hba.c:438
static bool check_hostname(hbaPort *port, const char *hostname)
Definition: hba.c:1076
static void tokenize_error_callback(void *arg)
Definition: hba.c:660
static void check_hba(hbaPort *port)
Definition: hba.c:2473
static void check_network_callback(struct sockaddr *addr, struct sockaddr *netmask, void *cb_data)
Definition: hba.c:1181
#define token_has_regexp(t)
Definition: hba.c:68
const char * hba_authname(UserAuth auth_method)
Definition: hba.c:3065
static MemoryContext parsed_hba_context
Definition: hba.c:86
static AuthToken * copy_auth_token(AuthToken *in)
Definition: hba.c:288
#define IDENT_MULTI_VALUE(tokens)
Definition: hba.c:1299
void hba_getauthmethod(hbaPort *port)
Definition: hba.c:3052
bool load_hba(void)
Definition: hba.c:2587
int check_usermap(const char *usermap_name, const char *pg_user, const char *system_user, bool case_insensitive)
Definition: hba.c:2908
void free_auth_file(FILE *file, int depth)
Definition: hba.c:570
static bool ipv6eq(struct sockaddr_in6 *a, struct sockaddr_in6 *b)
Definition: hba.c:1041
static List * tokenize_expand_file(List *tokens, const char *outer_filename, const char *inc_filename, int elevel, int depth, char **err_msg)
Definition: hba.c:493
static void free_auth_token(AuthToken *token)
Definition: hba.c:278
static List * parsed_ident_lines
Definition: hba.c:92
static const char *const UserAuthName[]
Definition: hba.c:101
#define token_matches(t, k)
Definition: hba.c:71
HbaLine * parse_hba_line(TokenizedAuthLine *tok_line, int elevel)
Definition: hba.c:1326
static bool next_token(char **lineptr, StringInfo buf, bool *initial_quote, bool *terminating_comma)
Definition: hba.c:185
static List * parsed_hba_lines
Definition: hba.c:85
#define INVALID_AUTH_OPTION(optname, validmethods)
Definition: hba.c:1242
static AuthToken * make_auth_token(const char *token, bool quoted)
Definition: hba.c:257
void tokenize_auth_file(const char *filename, FILE *file, List **tok_lines, int elevel, int depth)
Definition: hba.c:689
static void check_ident_usermap(IdentLine *identLine, const char *usermap_name, const char *pg_user, const char *system_user, bool case_insensitive, bool *found_p, bool *error_p)
Definition: hba.c:2761
static bool check_db(const char *dbname, const char *role, Oid roleid, List *tokens)
Definition: hba.c:991
#define REQUIRE_AUTH_OPTION(methodval, optname, validmethods)
Definition: hba.c:1256
IPCompareMethod
Definition: hba.h:50
@ ipCmpAll
Definition: hba.h:54
@ ipCmpSameNet
Definition: hba.h:53
@ ipCmpMask
Definition: hba.h:51
@ ipCmpSameHost
Definition: hba.h:52
@ ctHostNoGSS
Definition: hba.h:64
@ ctHostSSL
Definition: hba.h:61
@ ctHostNoSSL
Definition: hba.h:62
@ ctHost
Definition: hba.h:60
@ ctHostGSS
Definition: hba.h:63
@ ctLocal
Definition: hba.h:59
#define USER_AUTH_LAST
Definition: hba.h:42
UserAuth
Definition: hba.h:26
@ uaBSD
Definition: hba.h:37
@ uaLDAP
Definition: hba.h:38
@ uaPeer
Definition: hba.h:41
@ uaPAM
Definition: hba.h:36
@ uaPassword
Definition: hba.h:31
@ uaCert
Definition: hba.h:39
@ uaMD5
Definition: hba.h:32
@ uaReject
Definition: hba.h:27
@ uaGSS
Definition: hba.h:34
@ uaSCRAM
Definition: hba.h:33
@ uaImplicitReject
Definition: hba.h:28
@ uaRADIUS
Definition: hba.h:40
@ uaIdent
Definition: hba.h:30
@ uaTrust
Definition: hba.h:29
@ uaSSPI
Definition: hba.h:35
@ clientCertDN
Definition: hba.h:77
@ clientCertCN
Definition: hba.h:76
@ clientCertFull
Definition: hba.h:71
@ clientCertCA
Definition: hba.h:70
int pg_sockaddr_cidr_mask(struct sockaddr_storage *mask, char *numbits, int family)
Definition: ifaddr.c:105
int pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data)
Definition: ifaddr.c:425
int pg_range_sockaddr(const struct sockaddr_storage *addr, const struct sockaddr_storage *netaddr, const struct sockaddr_storage *netmask)
Definition: ifaddr.c:49
#define newline
Definition: indent_codes.h:35
#define token
Definition: indent_globs.h:126
long val
Definition: informix.c:689
void pg_freeaddrinfo_all(int hint_ai_family, struct addrinfo *ai)
Definition: ip.c:82
int pg_getnameinfo_all(const struct sockaddr_storage *addr, int salen, char *node, int nodelen, char *service, int servicelen, int flags)
Definition: ip.c:114
int pg_getaddrinfo_all(const char *hostname, const char *servname, const struct addrinfo *hintp, struct addrinfo **result)
Definition: ip.c:53
int b
Definition: isn.c:70
int a
Definition: isn.c:69
int i
Definition: isn.c:73
List * lappend(List *list, void *datum)
Definition: list.c:339
void list_free(List *list)
Definition: list.c:1546
unsigned int pg_wchar
Definition: mbprint.c:31
int pg_mb2wchar_with_len(const char *from, pg_wchar *to, int len)
Definition: mbutils.c:986
char * pstrdup(const char *in)
Definition: mcxt.c:1696
void pfree(void *pointer)
Definition: mcxt.c:1521
void * palloc0(Size size)
Definition: mcxt.c:1347
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
MemoryContext PostmasterContext
Definition: mcxt.c:151
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454
void * palloc(Size size)
Definition: mcxt.c:1317
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_START_SMALL_SIZES
Definition: memutils.h:177
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:170
Datum system_user(PG_FUNCTION_ARGS)
Definition: miscinit.c:891
void * arg
static char * filename
Definition: pg_dumpall.c:119
bool pg_get_line_append(FILE *stream, StringInfo buf, PromptInterruptContext *prompt_ctx)
Definition: pg_get_line.c:124
#define lfirst(lc)
Definition: pg_list.h:172
static int list_length(const List *l)
Definition: pg_list.h:152
#define linitial_node(type, l)
Definition: pg_list.h:181
#define NIL
Definition: pg_list.h:68
#define lsecond_node(type, l)
Definition: pg_list.h:186
#define list_make1(x1)
Definition: pg_list.h:212
static ListCell * list_head(const List *l)
Definition: pg_list.h:128
#define linitial(l)
Definition: pg_list.h:178
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:343
static int port
Definition: pg_regress.c:116
static char * hostname
Definition: pg_regress.c:115
static char * buf
Definition: pg_test_fsync.c:73
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
unsigned int Oid
Definition: postgres_ext.h:31
bool EnableSSL
Definition: postmaster.c:221
char * c
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
MemoryContextSwitchTo(old_ctx)
int pg_regcomp(regex_t *re, const chr *string, size_t len, int flags, Oid collation)
Definition: regcomp.c:370
size_t pg_regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size)
Definition: regerror.c:60
#define REG_NOMATCH
Definition: regex.h:216
#define REG_ADVANCED
Definition: regex.h:181
#define regmatch_t
Definition: regex.h:246
#define REG_OKAY
Definition: regex.h:215
#define regex_t
Definition: regex.h:245
int pg_regexec(regex_t *re, const chr *string, size_t len, size_t search_start, rm_detail_t *details, size_t nmatch, regmatch_t pmatch[], int flags)
Definition: regexec.c:185
void pg_regfree(regex_t *re)
Definition: regfree.c:49
const char * gai_strerror(int ecode)
static void error(void)
Definition: sql-dyntest.c:147
char * dbname
Definition: streamutil.c:52
int pg_strip_crlf(char *str)
Definition: string.c:155
void resetStringInfo(StringInfo str)
Definition: stringinfo.c:78
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:182
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:194
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
Definition: hba.h:88
regex_t * regex
Definition: hba.h:91
char * string
Definition: hba.h:89
bool quoted
Definition: hba.h:90
struct ErrorContextCallback * previous
Definition: elog.h:296
void(* callback)(void *arg)
Definition: elog.h:297
Definition: hba.h:95
UserAuth auth_method
Definition: hba.h:108
bool upn_username
Definition: hba.h:129
struct sockaddr_storage mask
Definition: hba.h:104
char * sourcefile
Definition: hba.h:96
ClientCertName clientcertname
Definition: hba.h:125
int addrlen
Definition: hba.h:103
List * radiusservers
Definition: hba.h:130
char * ldapserver
Definition: hba.h:114
bool include_realm
Definition: hba.h:127
int masklen
Definition: hba.h:105
ClientCertMode clientcert
Definition: hba.h:124
char * ldapsearchfilter
Definition: hba.h:119
char * ldapscheme
Definition: hba.h:113
char * rawline
Definition: hba.h:98
char * ldapprefix
Definition: hba.h:122
List * radiussecrets
Definition: hba.h:132
char * ldapsearchattribute
Definition: hba.h:118
char * krb_realm
Definition: hba.h:126
char * ldapbasedn
Definition: hba.h:120
bool pam_use_hostname
Definition: hba.h:111
int linenumber
Definition: hba.h:97
char * radiussecrets_s
Definition: hba.h:133
List * radiusports
Definition: hba.h:136
List * radiusidentifiers
Definition: hba.h:134
char * hostname
Definition: hba.h:107
char * pamservice
Definition: hba.h:110
List * databases
Definition: hba.h:100
ConnType conntype
Definition: hba.h:99
char * usermap
Definition: hba.h:109
char * ldapsuffix
Definition: hba.h:123
int ldapport
Definition: hba.h:115
struct sockaddr_storage addr
Definition: hba.h:102
char * ldapbindpasswd
Definition: hba.h:117
List * roles
Definition: hba.h:101
char * radiusports_s
Definition: hba.h:137
char * ldapbinddn
Definition: hba.h:116
bool compat_realm
Definition: hba.h:128
int ldapscope
Definition: hba.h:121
IPCompareMethod ip_cmp_method
Definition: hba.h:106
bool ldaptls
Definition: hba.h:112
char * radiusservers_s
Definition: hba.h:131
char * radiusidentifiers_s
Definition: hba.h:135
Definition: hba.h:141
AuthToken * pg_user
Definition: hba.h:146
AuthToken * system_user
Definition: hba.h:145
char * usermap
Definition: hba.h:144
int linenumber
Definition: hba.h:142
Definition: pg_list.h:54
int length
Definition: pg_list.h:56
Definition: libpq-be.h:133
struct sockaddr_storage addr
Definition: pqcomm.h:32
char * raw_line
Definition: hba.h:163
int line_num
Definition: hba.h:162
char * file_name
Definition: hba.h:161
char * err_msg
Definition: hba.h:164
List * fields
Definition: hba.h:160
bool result
Definition: hba.c:59
SockAddr * raddr
Definition: hba.c:58
IPCompareMethod method
Definition: hba.c:57
const char * filename
Definition: hba.c:64
bool SplitGUCList(char *rawstring, char separator, List **namelist)
Definition: varlena.c:3680
const char * name
bool am_walsender
Definition: walsender.c:115
bool am_db_walsender
Definition: walsender.c:118