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