PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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-2017, 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",
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, char *optionname,
148  List *masters, 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  /* physical replication walsender connections can only match replication keyword */
621  if (token_is_keyword(tok, "replication"))
622  return true;
623  }
624  else if (token_is_keyword(tok, "all"))
625  return true;
626  else if (token_is_keyword(tok, "sameuser"))
627  {
628  if (strcmp(dbname, role) == 0)
629  return true;
630  }
631  else if (token_is_keyword(tok, "samegroup") ||
632  token_is_keyword(tok, "samerole"))
633  {
634  if (is_member(roleid, dbname))
635  return true;
636  }
637  else if (token_is_keyword(tok, "replication"))
638  continue; /* never match this if not walsender */
639  else if (token_matches(tok, dbname))
640  return true;
641  }
642  return false;
643 }
644 
645 static bool
646 ipv4eq(struct sockaddr_in * a, struct sockaddr_in * b)
647 {
648  return (a->sin_addr.s_addr == b->sin_addr.s_addr);
649 }
650 
651 #ifdef HAVE_IPV6
652 
653 static bool
654 ipv6eq(struct sockaddr_in6 * a, struct sockaddr_in6 * b)
655 {
656  int i;
657 
658  for (i = 0; i < 16; i++)
659  if (a->sin6_addr.s6_addr[i] != b->sin6_addr.s6_addr[i])
660  return false;
661 
662  return true;
663 }
664 #endif /* HAVE_IPV6 */
665 
666 /*
667  * Check whether host name matches pattern.
668  */
669 static bool
670 hostname_match(const char *pattern, const char *actual_hostname)
671 {
672  if (pattern[0] == '.') /* suffix match */
673  {
674  size_t plen = strlen(pattern);
675  size_t hlen = strlen(actual_hostname);
676 
677  if (hlen < plen)
678  return false;
679 
680  return (pg_strcasecmp(pattern, actual_hostname + (hlen - plen)) == 0);
681  }
682  else
683  return (pg_strcasecmp(pattern, actual_hostname) == 0);
684 }
685 
686 /*
687  * Check to see if a connecting IP matches a given host name.
688  */
689 static bool
691 {
692  struct addrinfo *gai_result,
693  *gai;
694  int ret;
695  bool found;
696 
697  /* Quick out if remote host name already known bad */
698  if (port->remote_hostname_resolv < 0)
699  return false;
700 
701  /* Lookup remote host name if not already done */
702  if (!port->remote_hostname)
703  {
704  char remote_hostname[NI_MAXHOST];
705 
706  ret = pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
707  remote_hostname, sizeof(remote_hostname),
708  NULL, 0,
709  NI_NAMEREQD);
710  if (ret != 0)
711  {
712  /* remember failure; don't complain in the postmaster log yet */
713  port->remote_hostname_resolv = -2;
714  port->remote_hostname_errcode = ret;
715  return false;
716  }
717 
718  port->remote_hostname = pstrdup(remote_hostname);
719  }
720 
721  /* Now see if remote host name matches this pg_hba line */
722  if (!hostname_match(hostname, port->remote_hostname))
723  return false;
724 
725  /* If we already verified the forward lookup, we're done */
726  if (port->remote_hostname_resolv == +1)
727  return true;
728 
729  /* Lookup IP from host name and check against original IP */
730  ret = getaddrinfo(port->remote_hostname, NULL, NULL, &gai_result);
731  if (ret != 0)
732  {
733  /* remember failure; don't complain in the postmaster log yet */
734  port->remote_hostname_resolv = -2;
735  port->remote_hostname_errcode = ret;
736  return false;
737  }
738 
739  found = false;
740  for (gai = gai_result; gai; gai = gai->ai_next)
741  {
742  if (gai->ai_addr->sa_family == port->raddr.addr.ss_family)
743  {
744  if (gai->ai_addr->sa_family == AF_INET)
745  {
746  if (ipv4eq((struct sockaddr_in *) gai->ai_addr,
747  (struct sockaddr_in *) & port->raddr.addr))
748  {
749  found = true;
750  break;
751  }
752  }
753 #ifdef HAVE_IPV6
754  else if (gai->ai_addr->sa_family == AF_INET6)
755  {
756  if (ipv6eq((struct sockaddr_in6 *) gai->ai_addr,
757  (struct sockaddr_in6 *) & port->raddr.addr))
758  {
759  found = true;
760  break;
761  }
762  }
763 #endif
764  }
765  }
766 
767  if (gai_result)
768  freeaddrinfo(gai_result);
769 
770  if (!found)
771  elog(DEBUG2, "pg_hba.conf host name \"%s\" rejected because address resolution did not return a match with IP address of client",
772  hostname);
773 
774  port->remote_hostname_resolv = found ? +1 : -1;
775 
776  return found;
777 }
778 
779 /*
780  * Check to see if a connecting IP matches the given address and netmask.
781  */
782 static bool
783 check_ip(SockAddr *raddr, struct sockaddr * addr, struct sockaddr * mask)
784 {
785  if (raddr->addr.ss_family == addr->sa_family &&
786  pg_range_sockaddr(&raddr->addr,
787  (struct sockaddr_storage *) addr,
788  (struct sockaddr_storage *) mask))
789  return true;
790  return false;
791 }
792 
793 /*
794  * pg_foreach_ifaddr callback: does client addr match this machine interface?
795  */
796 static void
797 check_network_callback(struct sockaddr * addr, struct sockaddr * netmask,
798  void *cb_data)
799 {
800  check_network_data *cn = (check_network_data *) cb_data;
801  struct sockaddr_storage mask;
802 
803  /* Already found a match? */
804  if (cn->result)
805  return;
806 
807  if (cn->method == ipCmpSameHost)
808  {
809  /* Make an all-ones netmask of appropriate length for family */
810  pg_sockaddr_cidr_mask(&mask, NULL, addr->sa_family);
811  cn->result = check_ip(cn->raddr, addr, (struct sockaddr *) & mask);
812  }
813  else
814  {
815  /* Use the netmask of the interface itself */
816  cn->result = check_ip(cn->raddr, addr, netmask);
817  }
818 }
819 
820 /*
821  * Use pg_foreach_ifaddr to check a samehost or samenet match
822  */
823 static bool
825 {
827 
828  cn.method = method;
829  cn.raddr = raddr;
830  cn.result = false;
831 
832  errno = 0;
834  {
835  elog(LOG, "error enumerating network interfaces: %m");
836  return false;
837  }
838 
839  return cn.result;
840 }
841 
842 
843 /*
844  * Macros used to check and report on invalid configuration options.
845  * On error: log a message at level elevel, set *err_msg, and exit the function.
846  * These macros are not as general-purpose as they look, because they know
847  * what the calling function's error-exit value is.
848  *
849  * INVALID_AUTH_OPTION = reports when an option is specified for a method where it's
850  * not supported.
851  * REQUIRE_AUTH_OPTION = same as INVALID_AUTH_OPTION, except it also checks if the
852  * method is actually the one specified. Used as a shortcut when
853  * the option is only valid for one authentication method.
854  * MANDATORY_AUTH_ARG = check if a required option is set for an authentication method,
855  * reporting error if it's not.
856  */
857 #define INVALID_AUTH_OPTION(optname, validmethods) \
858 do { \
859  ereport(elevel, \
860  (errcode(ERRCODE_CONFIG_FILE_ERROR), \
861  /* translator: the second %s is a list of auth methods */ \
862  errmsg("authentication option \"%s\" is only valid for authentication methods %s", \
863  optname, _(validmethods)), \
864  errcontext("line %d of configuration file \"%s\"", \
865  line_num, HbaFileName))); \
866  *err_msg = psprintf("authentication option \"%s\" is only valid for authentication methods %s", \
867  optname, validmethods); \
868  return false; \
869 } while (0)
870 
871 #define REQUIRE_AUTH_OPTION(methodval, optname, validmethods) \
872 do { \
873  if (hbaline->auth_method != methodval) \
874  INVALID_AUTH_OPTION(optname, validmethods); \
875 } while (0)
876 
877 #define MANDATORY_AUTH_ARG(argvar, argname, authname) \
878 do { \
879  if (argvar == NULL) { \
880  ereport(elevel, \
881  (errcode(ERRCODE_CONFIG_FILE_ERROR), \
882  errmsg("authentication method \"%s\" requires argument \"%s\" to be set", \
883  authname, argname), \
884  errcontext("line %d of configuration file \"%s\"", \
885  line_num, HbaFileName))); \
886  *err_msg = psprintf("authentication method \"%s\" requires argument \"%s\" to be set", \
887  authname, argname); \
888  return NULL; \
889  } \
890 } while (0)
891 
892 /*
893  * Macros for handling pg_ident problems.
894  * Much as above, but currently the message level is hardwired as LOG
895  * and there is no provision for an err_msg string.
896  *
897  * IDENT_FIELD_ABSENT:
898  * Log a message and exit the function if the given ident field ListCell is
899  * not populated.
900  *
901  * IDENT_MULTI_VALUE:
902  * Log a message and exit the function if the given ident token List has more
903  * than one element.
904  */
905 #define IDENT_FIELD_ABSENT(field) \
906 do { \
907  if (!field) { \
908  ereport(LOG, \
909  (errcode(ERRCODE_CONFIG_FILE_ERROR), \
910  errmsg("missing entry in file \"%s\" at end of line %d", \
911  IdentFileName, line_num))); \
912  return NULL; \
913  } \
914 } while (0)
915 
916 #define IDENT_MULTI_VALUE(tokens) \
917 do { \
918  if (tokens->length > 1) { \
919  ereport(LOG, \
920  (errcode(ERRCODE_CONFIG_FILE_ERROR), \
921  errmsg("multiple values in ident field"), \
922  errcontext("line %d of configuration file \"%s\"", \
923  line_num, IdentFileName))); \
924  return NULL; \
925  } \
926 } while (0)
927 
928 
929 /*
930  * Parse one tokenised line from the hba config file and store the result in a
931  * HbaLine structure.
932  *
933  * If parsing fails, log a message at ereport level elevel, store an error
934  * string in tok_line->err_msg, and return NULL. (Some non-error conditions
935  * can also result in such messages.)
936  *
937  * Note: this function leaks memory when an error occurs. Caller is expected
938  * to have set a memory context that will be reset if this function returns
939  * NULL.
940  */
941 static HbaLine *
943 {
944  int line_num = tok_line->line_num;
945  char **err_msg = &tok_line->err_msg;
946  char *str;
947  struct addrinfo *gai_result;
948  struct addrinfo hints;
949  int ret;
950  char *cidr_slash;
951  char *unsupauth;
952  ListCell *field;
953  List *tokens;
954  ListCell *tokencell;
955  HbaToken *token;
956  HbaLine *parsedline;
957 
958  parsedline = palloc0(sizeof(HbaLine));
959  parsedline->linenumber = line_num;
960  parsedline->rawline = pstrdup(tok_line->raw_line);
961 
962  /* Check the record type. */
963  Assert(tok_line->fields != NIL);
964  field = list_head(tok_line->fields);
965  tokens = lfirst(field);
966  if (tokens->length > 1)
967  {
968  ereport(elevel,
969  (errcode(ERRCODE_CONFIG_FILE_ERROR),
970  errmsg("multiple values specified for connection type"),
971  errhint("Specify exactly one connection type per line."),
972  errcontext("line %d of configuration file \"%s\"",
973  line_num, HbaFileName)));
974  *err_msg = "multiple values specified for connection type";
975  return NULL;
976  }
977  token = linitial(tokens);
978  if (strcmp(token->string, "local") == 0)
979  {
980 #ifdef HAVE_UNIX_SOCKETS
981  parsedline->conntype = ctLocal;
982 #else
983  ereport(elevel,
984  (errcode(ERRCODE_CONFIG_FILE_ERROR),
985  errmsg("local connections are not supported by this build"),
986  errcontext("line %d of configuration file \"%s\"",
987  line_num, HbaFileName)));
988  *err_msg = "local connections are not supported by this build";
989  return NULL;
990 #endif
991  }
992  else if (strcmp(token->string, "host") == 0 ||
993  strcmp(token->string, "hostssl") == 0 ||
994  strcmp(token->string, "hostnossl") == 0)
995  {
996 
997  if (token->string[4] == 's') /* "hostssl" */
998  {
999  parsedline->conntype = ctHostSSL;
1000  /* Log a warning if SSL support is not active */
1001 #ifdef USE_SSL
1002  if (!EnableSSL)
1003  {
1004  ereport(elevel,
1005  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1006  errmsg("hostssl record cannot match because SSL is disabled"),
1007  errhint("Set ssl = on in postgresql.conf."),
1008  errcontext("line %d of configuration file \"%s\"",
1009  line_num, HbaFileName)));
1010  *err_msg = "hostssl record cannot match because SSL is disabled";
1011  }
1012 #else
1013  ereport(elevel,
1014  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1015  errmsg("hostssl record cannot match because SSL is not supported by this build"),
1016  errhint("Compile with --with-openssl to use SSL connections."),
1017  errcontext("line %d of configuration file \"%s\"",
1018  line_num, HbaFileName)));
1019  *err_msg = "hostssl record cannot match because SSL is not supported by this build";
1020 #endif
1021  }
1022  else if (token->string[4] == 'n') /* "hostnossl" */
1023  {
1024  parsedline->conntype = ctHostNoSSL;
1025  }
1026  else
1027  {
1028  /* "host" */
1029  parsedline->conntype = ctHost;
1030  }
1031  } /* record type */
1032  else
1033  {
1034  ereport(elevel,
1035  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1036  errmsg("invalid connection type \"%s\"",
1037  token->string),
1038  errcontext("line %d of configuration file \"%s\"",
1039  line_num, HbaFileName)));
1040  *err_msg = psprintf("invalid connection type \"%s\"", token->string);
1041  return NULL;
1042  }
1043 
1044  /* Get the databases. */
1045  field = lnext(field);
1046  if (!field)
1047  {
1048  ereport(elevel,
1049  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1050  errmsg("end-of-line before database specification"),
1051  errcontext("line %d of configuration file \"%s\"",
1052  line_num, HbaFileName)));
1053  *err_msg = "end-of-line before database specification";
1054  return NULL;
1055  }
1056  parsedline->databases = NIL;
1057  tokens = lfirst(field);
1058  foreach(tokencell, tokens)
1059  {
1060  parsedline->databases = lappend(parsedline->databases,
1061  copy_hba_token(lfirst(tokencell)));
1062  }
1063 
1064  /* Get the roles. */
1065  field = lnext(field);
1066  if (!field)
1067  {
1068  ereport(elevel,
1069  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1070  errmsg("end-of-line before role specification"),
1071  errcontext("line %d of configuration file \"%s\"",
1072  line_num, HbaFileName)));
1073  *err_msg = "end-of-line before role specification";
1074  return NULL;
1075  }
1076  parsedline->roles = NIL;
1077  tokens = lfirst(field);
1078  foreach(tokencell, tokens)
1079  {
1080  parsedline->roles = lappend(parsedline->roles,
1081  copy_hba_token(lfirst(tokencell)));
1082  }
1083 
1084  if (parsedline->conntype != ctLocal)
1085  {
1086  /* Read the IP address field. (with or without CIDR netmask) */
1087  field = lnext(field);
1088  if (!field)
1089  {
1090  ereport(elevel,
1091  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1092  errmsg("end-of-line before IP address specification"),
1093  errcontext("line %d of configuration file \"%s\"",
1094  line_num, HbaFileName)));
1095  *err_msg = "end-of-line before IP address specification";
1096  return NULL;
1097  }
1098  tokens = lfirst(field);
1099  if (tokens->length > 1)
1100  {
1101  ereport(elevel,
1102  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1103  errmsg("multiple values specified for host address"),
1104  errhint("Specify one address range per line."),
1105  errcontext("line %d of configuration file \"%s\"",
1106  line_num, HbaFileName)));
1107  *err_msg = "multiple values specified for host address";
1108  return NULL;
1109  }
1110  token = linitial(tokens);
1111 
1112  if (token_is_keyword(token, "all"))
1113  {
1114  parsedline->ip_cmp_method = ipCmpAll;
1115  }
1116  else if (token_is_keyword(token, "samehost"))
1117  {
1118  /* Any IP on this host is allowed to connect */
1119  parsedline->ip_cmp_method = ipCmpSameHost;
1120  }
1121  else if (token_is_keyword(token, "samenet"))
1122  {
1123  /* Any IP on the host's subnets is allowed to connect */
1124  parsedline->ip_cmp_method = ipCmpSameNet;
1125  }
1126  else
1127  {
1128  /* IP and netmask are specified */
1129  parsedline->ip_cmp_method = ipCmpMask;
1130 
1131  /* need a modifiable copy of token */
1132  str = pstrdup(token->string);
1133 
1134  /* Check if it has a CIDR suffix and if so isolate it */
1135  cidr_slash = strchr(str, '/');
1136  if (cidr_slash)
1137  *cidr_slash = '\0';
1138 
1139  /* Get the IP address either way */
1140  hints.ai_flags = AI_NUMERICHOST;
1141  hints.ai_family = AF_UNSPEC;
1142  hints.ai_socktype = 0;
1143  hints.ai_protocol = 0;
1144  hints.ai_addrlen = 0;
1145  hints.ai_canonname = NULL;
1146  hints.ai_addr = NULL;
1147  hints.ai_next = NULL;
1148 
1149  ret = pg_getaddrinfo_all(str, NULL, &hints, &gai_result);
1150  if (ret == 0 && gai_result)
1151  memcpy(&parsedline->addr, gai_result->ai_addr,
1152  gai_result->ai_addrlen);
1153  else if (ret == EAI_NONAME)
1154  parsedline->hostname = str;
1155  else
1156  {
1157  ereport(elevel,
1158  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1159  errmsg("invalid IP address \"%s\": %s",
1160  str, gai_strerror(ret)),
1161  errcontext("line %d of configuration file \"%s\"",
1162  line_num, HbaFileName)));
1163  *err_msg = psprintf("invalid IP address \"%s\": %s",
1164  str, gai_strerror(ret));
1165  if (gai_result)
1166  pg_freeaddrinfo_all(hints.ai_family, gai_result);
1167  return NULL;
1168  }
1169 
1170  pg_freeaddrinfo_all(hints.ai_family, gai_result);
1171 
1172  /* Get the netmask */
1173  if (cidr_slash)
1174  {
1175  if (parsedline->hostname)
1176  {
1177  ereport(elevel,
1178  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1179  errmsg("specifying both host name and CIDR mask is invalid: \"%s\"",
1180  token->string),
1181  errcontext("line %d of configuration file \"%s\"",
1182  line_num, HbaFileName)));
1183  *err_msg = psprintf("specifying both host name and CIDR mask is invalid: \"%s\"",
1184  token->string);
1185  return NULL;
1186  }
1187 
1188  if (pg_sockaddr_cidr_mask(&parsedline->mask, cidr_slash + 1,
1189  parsedline->addr.ss_family) < 0)
1190  {
1191  ereport(elevel,
1192  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1193  errmsg("invalid CIDR mask in address \"%s\"",
1194  token->string),
1195  errcontext("line %d of configuration file \"%s\"",
1196  line_num, HbaFileName)));
1197  *err_msg = psprintf("invalid CIDR mask in address \"%s\"",
1198  token->string);
1199  return NULL;
1200  }
1201  pfree(str);
1202  }
1203  else if (!parsedline->hostname)
1204  {
1205  /* Read the mask field. */
1206  pfree(str);
1207  field = lnext(field);
1208  if (!field)
1209  {
1210  ereport(elevel,
1211  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1212  errmsg("end-of-line before netmask specification"),
1213  errhint("Specify an address range in CIDR notation, or provide a separate netmask."),
1214  errcontext("line %d of configuration file \"%s\"",
1215  line_num, HbaFileName)));
1216  *err_msg = "end-of-line before netmask specification";
1217  return NULL;
1218  }
1219  tokens = lfirst(field);
1220  if (tokens->length > 1)
1221  {
1222  ereport(elevel,
1223  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1224  errmsg("multiple values specified for netmask"),
1225  errcontext("line %d of configuration file \"%s\"",
1226  line_num, HbaFileName)));
1227  *err_msg = "multiple values specified for netmask";
1228  return NULL;
1229  }
1230  token = linitial(tokens);
1231 
1232  ret = pg_getaddrinfo_all(token->string, NULL,
1233  &hints, &gai_result);
1234  if (ret || !gai_result)
1235  {
1236  ereport(elevel,
1237  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1238  errmsg("invalid IP mask \"%s\": %s",
1239  token->string, gai_strerror(ret)),
1240  errcontext("line %d of configuration file \"%s\"",
1241  line_num, HbaFileName)));
1242  *err_msg = psprintf("invalid IP mask \"%s\": %s",
1243  token->string, gai_strerror(ret));
1244  if (gai_result)
1245  pg_freeaddrinfo_all(hints.ai_family, gai_result);
1246  return NULL;
1247  }
1248 
1249  memcpy(&parsedline->mask, gai_result->ai_addr,
1250  gai_result->ai_addrlen);
1251  pg_freeaddrinfo_all(hints.ai_family, gai_result);
1252 
1253  if (parsedline->addr.ss_family != parsedline->mask.ss_family)
1254  {
1255  ereport(elevel,
1256  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1257  errmsg("IP address and mask do not match"),
1258  errcontext("line %d of configuration file \"%s\"",
1259  line_num, HbaFileName)));
1260  *err_msg = "IP address and mask do not match";
1261  return NULL;
1262  }
1263  }
1264  }
1265  } /* != ctLocal */
1266 
1267  /* Get the authentication method */
1268  field = lnext(field);
1269  if (!field)
1270  {
1271  ereport(elevel,
1272  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1273  errmsg("end-of-line before authentication method"),
1274  errcontext("line %d of configuration file \"%s\"",
1275  line_num, HbaFileName)));
1276  *err_msg = "end-of-line before authentication method";
1277  return NULL;
1278  }
1279  tokens = lfirst(field);
1280  if (tokens->length > 1)
1281  {
1282  ereport(elevel,
1283  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1284  errmsg("multiple values specified for authentication type"),
1285  errhint("Specify exactly one authentication type per line."),
1286  errcontext("line %d of configuration file \"%s\"",
1287  line_num, HbaFileName)));
1288  *err_msg = "multiple values specified for authentication type";
1289  return NULL;
1290  }
1291  token = linitial(tokens);
1292 
1293  unsupauth = NULL;
1294  if (strcmp(token->string, "trust") == 0)
1295  parsedline->auth_method = uaTrust;
1296  else if (strcmp(token->string, "ident") == 0)
1297  parsedline->auth_method = uaIdent;
1298  else if (strcmp(token->string, "peer") == 0)
1299  parsedline->auth_method = uaPeer;
1300  else if (strcmp(token->string, "password") == 0)
1301  parsedline->auth_method = uaPassword;
1302  else if (strcmp(token->string, "gss") == 0)
1303 #ifdef ENABLE_GSS
1304  parsedline->auth_method = uaGSS;
1305 #else
1306  unsupauth = "gss";
1307 #endif
1308  else if (strcmp(token->string, "sspi") == 0)
1309 #ifdef ENABLE_SSPI
1310  parsedline->auth_method = uaSSPI;
1311 #else
1312  unsupauth = "sspi";
1313 #endif
1314  else if (strcmp(token->string, "reject") == 0)
1315  parsedline->auth_method = uaReject;
1316  else if (strcmp(token->string, "md5") == 0)
1317  {
1318  if (Db_user_namespace)
1319  {
1320  ereport(elevel,
1321  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1322  errmsg("MD5 authentication is not supported when \"db_user_namespace\" is enabled"),
1323  errcontext("line %d of configuration file \"%s\"",
1324  line_num, HbaFileName)));
1325  *err_msg = "MD5 authentication is not supported when \"db_user_namespace\" is enabled";
1326  return NULL;
1327  }
1328  parsedline->auth_method = uaMD5;
1329  }
1330  else if (strcmp(token->string, "scram") == 0)
1331  parsedline->auth_method = uaSCRAM;
1332  else if (strcmp(token->string, "pam") == 0)
1333 #ifdef USE_PAM
1334  parsedline->auth_method = uaPAM;
1335 #else
1336  unsupauth = "pam";
1337 #endif
1338  else if (strcmp(token->string, "bsd") == 0)
1339 #ifdef USE_BSD_AUTH
1340  parsedline->auth_method = uaBSD;
1341 #else
1342  unsupauth = "bsd";
1343 #endif
1344  else if (strcmp(token->string, "ldap") == 0)
1345 #ifdef USE_LDAP
1346  parsedline->auth_method = uaLDAP;
1347 #else
1348  unsupauth = "ldap";
1349 #endif
1350  else if (strcmp(token->string, "cert") == 0)
1351 #ifdef USE_SSL
1352  parsedline->auth_method = uaCert;
1353 #else
1354  unsupauth = "cert";
1355 #endif
1356  else if (strcmp(token->string, "radius") == 0)
1357  parsedline->auth_method = uaRADIUS;
1358  else
1359  {
1360  ereport(elevel,
1361  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1362  errmsg("invalid authentication method \"%s\"",
1363  token->string),
1364  errcontext("line %d of configuration file \"%s\"",
1365  line_num, HbaFileName)));
1366  *err_msg = psprintf("invalid authentication method \"%s\"",
1367  token->string);
1368  return NULL;
1369  }
1370 
1371  if (unsupauth)
1372  {
1373  ereport(elevel,
1374  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1375  errmsg("invalid authentication method \"%s\": not supported by this build",
1376  token->string),
1377  errcontext("line %d of configuration file \"%s\"",
1378  line_num, HbaFileName)));
1379  *err_msg = psprintf("invalid authentication method \"%s\": not supported by this build",
1380  token->string);
1381  return NULL;
1382  }
1383 
1384  /*
1385  * XXX: When using ident on local connections, change it to peer, for
1386  * backwards compatibility.
1387  */
1388  if (parsedline->conntype == ctLocal &&
1389  parsedline->auth_method == uaIdent)
1390  parsedline->auth_method = uaPeer;
1391 
1392  /* Invalid authentication combinations */
1393  if (parsedline->conntype == ctLocal &&
1394  parsedline->auth_method == uaGSS)
1395  {
1396  ereport(elevel,
1397  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1398  errmsg("gssapi authentication is not supported on local sockets"),
1399  errcontext("line %d of configuration file \"%s\"",
1400  line_num, HbaFileName)));
1401  *err_msg = "gssapi authentication is not supported on local sockets";
1402  return NULL;
1403  }
1404 
1405  if (parsedline->conntype != ctLocal &&
1406  parsedline->auth_method == uaPeer)
1407  {
1408  ereport(elevel,
1409  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1410  errmsg("peer authentication is only supported on local sockets"),
1411  errcontext("line %d of configuration file \"%s\"",
1412  line_num, HbaFileName)));
1413  *err_msg = "peer authentication is only supported on local sockets";
1414  return NULL;
1415  }
1416 
1417  /*
1418  * SSPI authentication can never be enabled on ctLocal connections,
1419  * because it's only supported on Windows, where ctLocal isn't supported.
1420  */
1421 
1422 
1423  if (parsedline->conntype != ctHostSSL &&
1424  parsedline->auth_method == uaCert)
1425  {
1426  ereport(elevel,
1427  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1428  errmsg("cert authentication is only supported on hostssl connections"),
1429  errcontext("line %d of configuration file \"%s\"",
1430  line_num, HbaFileName)));
1431  *err_msg = "cert authentication is only supported on hostssl connections";
1432  return NULL;
1433  }
1434 
1435  /*
1436  * For GSS and SSPI, set the default value of include_realm to true.
1437  * Having include_realm set to false is dangerous in multi-realm
1438  * situations and is generally considered bad practice. We keep the
1439  * capability around for backwards compatibility, but we might want to
1440  * remove it at some point in the future. Users who still need to strip
1441  * the realm off would be better served by using an appropriate regex in a
1442  * pg_ident.conf mapping.
1443  */
1444  if (parsedline->auth_method == uaGSS ||
1445  parsedline->auth_method == uaSSPI)
1446  parsedline->include_realm = true;
1447 
1448  /*
1449  * For SSPI, include_realm defaults to the SAM-compatible domain (aka
1450  * NetBIOS name) and user names instead of the Kerberos principal name for
1451  * compatibility.
1452  */
1453  if (parsedline->auth_method == uaSSPI)
1454  {
1455  parsedline->compat_realm = true;
1456  parsedline->upn_username = false;
1457  }
1458 
1459  /* Parse remaining arguments */
1460  while ((field = lnext(field)) != NULL)
1461  {
1462  tokens = lfirst(field);
1463  foreach(tokencell, tokens)
1464  {
1465  char *val;
1466 
1467  token = lfirst(tokencell);
1468 
1469  str = pstrdup(token->string);
1470  val = strchr(str, '=');
1471  if (val == NULL)
1472  {
1473  /*
1474  * Got something that's not a name=value pair.
1475  */
1476  ereport(elevel,
1477  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1478  errmsg("authentication option not in name=value format: %s", token->string),
1479  errcontext("line %d of configuration file \"%s\"",
1480  line_num, HbaFileName)));
1481  *err_msg = psprintf("authentication option not in name=value format: %s",
1482  token->string);
1483  return NULL;
1484  }
1485 
1486  *val++ = '\0'; /* str now holds "name", val holds "value" */
1487  if (!parse_hba_auth_opt(str, val, parsedline, elevel, err_msg))
1488  /* parse_hba_auth_opt already logged the error message */
1489  return NULL;
1490  pfree(str);
1491  }
1492  }
1493 
1494  /*
1495  * Check if the selected authentication method has any mandatory arguments
1496  * that are not set.
1497  */
1498  if (parsedline->auth_method == uaLDAP)
1499  {
1500  MANDATORY_AUTH_ARG(parsedline->ldapserver, "ldapserver", "ldap");
1501 
1502  /*
1503  * LDAP can operate in two modes: either with a direct bind, using
1504  * ldapprefix and ldapsuffix, or using a search+bind, using
1505  * ldapbasedn, ldapbinddn, ldapbindpasswd and ldapsearchattribute.
1506  * Disallow mixing these parameters.
1507  */
1508  if (parsedline->ldapprefix || parsedline->ldapsuffix)
1509  {
1510  if (parsedline->ldapbasedn ||
1511  parsedline->ldapbinddn ||
1512  parsedline->ldapbindpasswd ||
1513  parsedline->ldapsearchattribute)
1514  {
1515  ereport(elevel,
1516  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1517  errmsg("cannot use ldapbasedn, ldapbinddn, ldapbindpasswd, ldapsearchattribute, or ldapurl together with ldapprefix"),
1518  errcontext("line %d of configuration file \"%s\"",
1519  line_num, HbaFileName)));
1520  *err_msg = "cannot use ldapbasedn, ldapbinddn, ldapbindpasswd, ldapsearchattribute, or ldapurl together with ldapprefix";
1521  return NULL;
1522  }
1523  }
1524  else if (!parsedline->ldapbasedn)
1525  {
1526  ereport(elevel,
1527  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1528  errmsg("authentication method \"ldap\" requires argument \"ldapbasedn\", \"ldapprefix\", or \"ldapsuffix\" to be set"),
1529  errcontext("line %d of configuration file \"%s\"",
1530  line_num, HbaFileName)));
1531  *err_msg = "authentication method \"ldap\" requires argument \"ldapbasedn\", \"ldapprefix\", or \"ldapsuffix\" to be set";
1532  return NULL;
1533  }
1534  }
1535 
1536  if (parsedline->auth_method == uaRADIUS)
1537  {
1538  MANDATORY_AUTH_ARG(parsedline->radiusservers, "radiusservers", "radius");
1539  MANDATORY_AUTH_ARG(parsedline->radiussecrets, "radiussecrets", "radius");
1540 
1541  if (list_length(parsedline->radiusservers) < 1)
1542  {
1543  ereport(LOG,
1544  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1545  errmsg("list of RADIUS servers cannot be empty"),
1546  errcontext("line %d of configuration file \"%s\"",
1547  line_num, HbaFileName)));
1548  return NULL;
1549  }
1550 
1551  if (list_length(parsedline->radiussecrets) < 1)
1552  {
1553  ereport(LOG,
1554  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1555  errmsg("list of RADIUS secrets cannot be empty"),
1556  errcontext("line %d of configuration file \"%s\"",
1557  line_num, HbaFileName)));
1558  return NULL;
1559  }
1560 
1561  /*
1562  * Verify length of option lists - each can be 0 (except for secrets,
1563  * but that's already checked above), 1 (use the same value
1564  * everywhere) or the same as the number of servers.
1565  */
1566  if (!verify_option_list_length(parsedline->radiussecrets,
1567  "RADIUS secrets",
1568  parsedline->radiusservers,
1569  "RADIUS servers",
1570  line_num))
1571  return NULL;
1572  if (!verify_option_list_length(parsedline->radiusports,
1573  "RADIUS ports",
1574  parsedline->radiusservers,
1575  "RADIUS servers",
1576  line_num))
1577  return NULL;
1579  "RADIUS identifiers",
1580  parsedline->radiusservers,
1581  "RADIUS servers",
1582  line_num))
1583  return NULL;
1584  }
1585 
1586  /*
1587  * Enforce any parameters implied by other settings.
1588  */
1589  if (parsedline->auth_method == uaCert)
1590  {
1591  parsedline->clientcert = true;
1592  }
1593 
1594  return parsedline;
1595 }
1596 
1597 
1598 static bool
1599 verify_option_list_length(List *options, char *optionname, List *masters, char *mastername, int line_num)
1600 {
1601  if (list_length(options) == 0 ||
1602  list_length(options) == 1 ||
1603  list_length(options) == list_length(masters))
1604  return true;
1605 
1606  ereport(LOG,
1607  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1608  errmsg("the number of %s (%i) must be 1 or the same as the number of %s (%i)",
1609  optionname,
1610  list_length(options),
1611  mastername,
1612  list_length(masters)
1613  ),
1614  errcontext("line %d of configuration file \"%s\"",
1615  line_num, HbaFileName)));
1616  return false;
1617 }
1618 
1619 /*
1620  * Parse one name-value pair as an authentication option into the given
1621  * HbaLine. Return true if we successfully parse the option, false if we
1622  * encounter an error. In the event of an error, also log a message at
1623  * ereport level elevel, and store a message string into *err_msg.
1624  */
1625 static bool
1626 parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline,
1627  int elevel, char **err_msg)
1628 {
1629  int line_num = hbaline->linenumber;
1630 
1631 #ifdef USE_LDAP
1632  hbaline->ldapscope = LDAP_SCOPE_SUBTREE;
1633 #endif
1634 
1635  if (strcmp(name, "map") == 0)
1636  {
1637  if (hbaline->auth_method != uaIdent &&
1638  hbaline->auth_method != uaPeer &&
1639  hbaline->auth_method != uaGSS &&
1640  hbaline->auth_method != uaSSPI &&
1641  hbaline->auth_method != uaCert)
1642  INVALID_AUTH_OPTION("map", gettext_noop("ident, peer, gssapi, sspi, and cert"));
1643  hbaline->usermap = pstrdup(val);
1644  }
1645  else if (strcmp(name, "clientcert") == 0)
1646  {
1647  if (hbaline->conntype != ctHostSSL)
1648  {
1649  ereport(elevel,
1650  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1651  errmsg("clientcert can only be configured for \"hostssl\" rows"),
1652  errcontext("line %d of configuration file \"%s\"",
1653  line_num, HbaFileName)));
1654  *err_msg = "clientcert can only be configured for \"hostssl\" rows";
1655  return false;
1656  }
1657  if (strcmp(val, "1") == 0)
1658  {
1659  hbaline->clientcert = true;
1660  }
1661  else
1662  {
1663  if (hbaline->auth_method == uaCert)
1664  {
1665  ereport(elevel,
1666  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1667  errmsg("clientcert can not be set to 0 when using \"cert\" authentication"),
1668  errcontext("line %d of configuration file \"%s\"",
1669  line_num, HbaFileName)));
1670  *err_msg = "clientcert can not be set to 0 when using \"cert\" authentication";
1671  return false;
1672  }
1673  hbaline->clientcert = false;
1674  }
1675  }
1676  else if (strcmp(name, "pamservice") == 0)
1677  {
1678  REQUIRE_AUTH_OPTION(uaPAM, "pamservice", "pam");
1679  hbaline->pamservice = pstrdup(val);
1680  }
1681  else if (strcmp(name, "pam_use_hostname") == 0)
1682  {
1683  REQUIRE_AUTH_OPTION(uaPAM, "pam_use_hostname", "pam");
1684  if (strcmp(val, "1") == 0)
1685  hbaline->pam_use_hostname = true;
1686  else
1687  hbaline->pam_use_hostname = false;
1688 
1689  }
1690  else if (strcmp(name, "ldapurl") == 0)
1691  {
1692 #ifdef LDAP_API_FEATURE_X_OPENLDAP
1693  LDAPURLDesc *urldata;
1694  int rc;
1695 #endif
1696 
1697  REQUIRE_AUTH_OPTION(uaLDAP, "ldapurl", "ldap");
1698 #ifdef LDAP_API_FEATURE_X_OPENLDAP
1699  rc = ldap_url_parse(val, &urldata);
1700  if (rc != LDAP_SUCCESS)
1701  {
1702  ereport(elevel,
1703  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1704  errmsg("could not parse LDAP URL \"%s\": %s", val, ldap_err2string(rc))));
1705  *err_msg = psprintf("could not parse LDAP URL \"%s\": %s",
1706  val, ldap_err2string(rc));
1707  return false;
1708  }
1709 
1710  if (strcmp(urldata->lud_scheme, "ldap") != 0)
1711  {
1712  ereport(elevel,
1713  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1714  errmsg("unsupported LDAP URL scheme: %s", urldata->lud_scheme)));
1715  *err_msg = psprintf("unsupported LDAP URL scheme: %s",
1716  urldata->lud_scheme);
1717  ldap_free_urldesc(urldata);
1718  return false;
1719  }
1720 
1721  hbaline->ldapserver = pstrdup(urldata->lud_host);
1722  hbaline->ldapport = urldata->lud_port;
1723  hbaline->ldapbasedn = pstrdup(urldata->lud_dn);
1724 
1725  if (urldata->lud_attrs)
1726  hbaline->ldapsearchattribute = pstrdup(urldata->lud_attrs[0]); /* only use first one */
1727  hbaline->ldapscope = urldata->lud_scope;
1728  if (urldata->lud_filter)
1729  {
1730  ereport(elevel,
1731  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1732  errmsg("filters not supported in LDAP URLs")));
1733  *err_msg = "filters not supported in LDAP URLs";
1734  ldap_free_urldesc(urldata);
1735  return false;
1736  }
1737  ldap_free_urldesc(urldata);
1738 #else /* not OpenLDAP */
1739  ereport(elevel,
1740  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1741  errmsg("LDAP URLs not supported on this platform")));
1742  *err_msg = "LDAP URLs not supported on this platform";
1743 #endif /* not OpenLDAP */
1744  }
1745  else if (strcmp(name, "ldaptls") == 0)
1746  {
1747  REQUIRE_AUTH_OPTION(uaLDAP, "ldaptls", "ldap");
1748  if (strcmp(val, "1") == 0)
1749  hbaline->ldaptls = true;
1750  else
1751  hbaline->ldaptls = false;
1752  }
1753  else if (strcmp(name, "ldapserver") == 0)
1754  {
1755  REQUIRE_AUTH_OPTION(uaLDAP, "ldapserver", "ldap");
1756  hbaline->ldapserver = pstrdup(val);
1757  }
1758  else if (strcmp(name, "ldapport") == 0)
1759  {
1760  REQUIRE_AUTH_OPTION(uaLDAP, "ldapport", "ldap");
1761  hbaline->ldapport = atoi(val);
1762  if (hbaline->ldapport == 0)
1763  {
1764  ereport(elevel,
1765  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1766  errmsg("invalid LDAP port number: \"%s\"", val),
1767  errcontext("line %d of configuration file \"%s\"",
1768  line_num, HbaFileName)));
1769  *err_msg = psprintf("invalid LDAP port number: \"%s\"", val);
1770  return false;
1771  }
1772  }
1773  else if (strcmp(name, "ldapbinddn") == 0)
1774  {
1775  REQUIRE_AUTH_OPTION(uaLDAP, "ldapbinddn", "ldap");
1776  hbaline->ldapbinddn = pstrdup(val);
1777  }
1778  else if (strcmp(name, "ldapbindpasswd") == 0)
1779  {
1780  REQUIRE_AUTH_OPTION(uaLDAP, "ldapbindpasswd", "ldap");
1781  hbaline->ldapbindpasswd = pstrdup(val);
1782  }
1783  else if (strcmp(name, "ldapsearchattribute") == 0)
1784  {
1785  REQUIRE_AUTH_OPTION(uaLDAP, "ldapsearchattribute", "ldap");
1786  hbaline->ldapsearchattribute = pstrdup(val);
1787  }
1788  else if (strcmp(name, "ldapbasedn") == 0)
1789  {
1790  REQUIRE_AUTH_OPTION(uaLDAP, "ldapbasedn", "ldap");
1791  hbaline->ldapbasedn = pstrdup(val);
1792  }
1793  else if (strcmp(name, "ldapprefix") == 0)
1794  {
1795  REQUIRE_AUTH_OPTION(uaLDAP, "ldapprefix", "ldap");
1796  hbaline->ldapprefix = pstrdup(val);
1797  }
1798  else if (strcmp(name, "ldapsuffix") == 0)
1799  {
1800  REQUIRE_AUTH_OPTION(uaLDAP, "ldapsuffix", "ldap");
1801  hbaline->ldapsuffix = pstrdup(val);
1802  }
1803  else if (strcmp(name, "krb_realm") == 0)
1804  {
1805  if (hbaline->auth_method != uaGSS &&
1806  hbaline->auth_method != uaSSPI)
1807  INVALID_AUTH_OPTION("krb_realm", gettext_noop("gssapi and sspi"));
1808  hbaline->krb_realm = pstrdup(val);
1809  }
1810  else if (strcmp(name, "include_realm") == 0)
1811  {
1812  if (hbaline->auth_method != uaGSS &&
1813  hbaline->auth_method != uaSSPI)
1814  INVALID_AUTH_OPTION("include_realm", gettext_noop("gssapi and sspi"));
1815  if (strcmp(val, "1") == 0)
1816  hbaline->include_realm = true;
1817  else
1818  hbaline->include_realm = false;
1819  }
1820  else if (strcmp(name, "compat_realm") == 0)
1821  {
1822  if (hbaline->auth_method != uaSSPI)
1823  INVALID_AUTH_OPTION("compat_realm", gettext_noop("sspi"));
1824  if (strcmp(val, "1") == 0)
1825  hbaline->compat_realm = true;
1826  else
1827  hbaline->compat_realm = false;
1828  }
1829  else if (strcmp(name, "upn_username") == 0)
1830  {
1831  if (hbaline->auth_method != uaSSPI)
1832  INVALID_AUTH_OPTION("upn_username", gettext_noop("sspi"));
1833  if (strcmp(val, "1") == 0)
1834  hbaline->upn_username = true;
1835  else
1836  hbaline->upn_username = false;
1837  }
1838  else if (strcmp(name, "radiusservers") == 0)
1839  {
1840  struct addrinfo *gai_result;
1841  struct addrinfo hints;
1842  int ret;
1843  List *parsed_servers;
1844  ListCell *l;
1845  char *dupval = pstrdup(val);
1846 
1847  REQUIRE_AUTH_OPTION(uaRADIUS, "radiusservers", "radius");
1848 
1849  if (!SplitIdentifierString(dupval, ',', &parsed_servers))
1850  {
1851  /* syntax error in list */
1852  ereport(elevel,
1853  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1854  errmsg("could not parse RADIUS server list \"%s\"",
1855  val),
1856  errcontext("line %d of configuration file \"%s\"",
1857  line_num, HbaFileName)));
1858  return false;
1859  }
1860 
1861  /* For each entry in the list, translate it */
1862  foreach(l, parsed_servers)
1863  {
1864  MemSet(&hints, 0, sizeof(hints));
1865  hints.ai_socktype = SOCK_DGRAM;
1866  hints.ai_family = AF_UNSPEC;
1867 
1868  ret = pg_getaddrinfo_all((char *) lfirst(l), NULL, &hints, &gai_result);
1869  if (ret || !gai_result)
1870  {
1871  ereport(elevel,
1872  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1873  errmsg("could not translate RADIUS server name \"%s\" to address: %s",
1874  (char *) lfirst(l), gai_strerror(ret)),
1875  errcontext("line %d of configuration file \"%s\"",
1876  line_num, HbaFileName)));
1877  if (gai_result)
1878  pg_freeaddrinfo_all(hints.ai_family, gai_result);
1879 
1880  list_free(parsed_servers);
1881  return false;
1882  }
1883  pg_freeaddrinfo_all(hints.ai_family, gai_result);
1884  }
1885 
1886  /* All entries are OK, so store them */
1887  hbaline->radiusservers = parsed_servers;
1888  hbaline->radiusservers_s = pstrdup(val);
1889  }
1890  else if (strcmp(name, "radiusports") == 0)
1891  {
1892  List *parsed_ports;
1893  ListCell *l;
1894  char *dupval = pstrdup(val);
1895 
1896  REQUIRE_AUTH_OPTION(uaRADIUS, "radiusports", "radius");
1897 
1898  if (!SplitIdentifierString(dupval, ',', &parsed_ports))
1899  {
1900  ereport(elevel,
1901  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1902  errmsg("could not parse RADIUS port list \"%s\"",
1903  val),
1904  errcontext("line %d of configuration file \"%s\"",
1905  line_num, HbaFileName)));
1906  *err_msg = psprintf("invalid RADIUS port number: \"%s\"", val);
1907  return false;
1908  }
1909 
1910  foreach(l, parsed_ports)
1911  {
1912  if (atoi(lfirst(l)) == 0)
1913  {
1914  ereport(elevel,
1915  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1916  errmsg("invalid RADIUS port number: \"%s\"", val),
1917  errcontext("line %d of configuration file \"%s\"",
1918  line_num, HbaFileName)));
1919 
1920  return false;
1921  }
1922  }
1923  hbaline->radiusports = parsed_ports;
1924  hbaline->radiusports_s = pstrdup(val);
1925  }
1926  else if (strcmp(name, "radiussecrets") == 0)
1927  {
1928  List *parsed_secrets;
1929  char *dupval = pstrdup(val);
1930 
1931  REQUIRE_AUTH_OPTION(uaRADIUS, "radiussecrets", "radius");
1932 
1933  if (!SplitIdentifierString(dupval, ',', &parsed_secrets))
1934  {
1935  /* syntax error in list */
1936  ereport(elevel,
1937  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1938  errmsg("could not parse RADIUS secret list \"%s\"",
1939  val),
1940  errcontext("line %d of configuration file \"%s\"",
1941  line_num, HbaFileName)));
1942  return false;
1943  }
1944 
1945  hbaline->radiussecrets = parsed_secrets;
1946  hbaline->radiussecrets_s = pstrdup(val);
1947  }
1948  else if (strcmp(name, "radiusidentifiers") == 0)
1949  {
1950  List *parsed_identifiers;
1951  char *dupval = pstrdup(val);
1952 
1953  REQUIRE_AUTH_OPTION(uaRADIUS, "radiusidentifiers", "radius");
1954 
1955  if (!SplitIdentifierString(dupval, ',', &parsed_identifiers))
1956  {
1957  /* syntax error in list */
1958  ereport(elevel,
1959  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1960  errmsg("could not parse RADIUS identifiers list \"%s\"",
1961  val),
1962  errcontext("line %d of configuration file \"%s\"",
1963  line_num, HbaFileName)));
1964  return false;
1965  }
1966 
1967  hbaline->radiusidentifiers = parsed_identifiers;
1968  hbaline->radiusidentifiers_s = pstrdup(val);
1969  }
1970  else
1971  {
1972  ereport(elevel,
1973  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1974  errmsg("unrecognized authentication option name: \"%s\"",
1975  name),
1976  errcontext("line %d of configuration file \"%s\"",
1977  line_num, HbaFileName)));
1978  *err_msg = psprintf("unrecognized authentication option name: \"%s\"",
1979  name);
1980  return false;
1981  }
1982  return true;
1983 }
1984 
1985 /*
1986  * Scan the pre-parsed hba file, looking for a match to the port's connection
1987  * request.
1988  */
1989 static void
1991 {
1992  Oid roleid;
1993  ListCell *line;
1994  HbaLine *hba;
1995 
1996  /* Get the target role's OID. Note we do not error out for bad role. */
1997  roleid = get_role_oid(port->user_name, true);
1998 
1999  foreach(line, parsed_hba_lines)
2000  {
2001  hba = (HbaLine *) lfirst(line);
2002 
2003  /* Check connection type */
2004  if (hba->conntype == ctLocal)
2005  {
2006  if (!IS_AF_UNIX(port->raddr.addr.ss_family))
2007  continue;
2008  }
2009  else
2010  {
2011  if (IS_AF_UNIX(port->raddr.addr.ss_family))
2012  continue;
2013 
2014  /* Check SSL state */
2015  if (port->ssl_in_use)
2016  {
2017  /* Connection is SSL, match both "host" and "hostssl" */
2018  if (hba->conntype == ctHostNoSSL)
2019  continue;
2020  }
2021  else
2022  {
2023  /* Connection is not SSL, match both "host" and "hostnossl" */
2024  if (hba->conntype == ctHostSSL)
2025  continue;
2026  }
2027 
2028  /* Check IP address */
2029  switch (hba->ip_cmp_method)
2030  {
2031  case ipCmpMask:
2032  if (hba->hostname)
2033  {
2034  if (!check_hostname(port,
2035  hba->hostname))
2036  continue;
2037  }
2038  else
2039  {
2040  if (!check_ip(&port->raddr,
2041  (struct sockaddr *) & hba->addr,
2042  (struct sockaddr *) & hba->mask))
2043  continue;
2044  }
2045  break;
2046  case ipCmpAll:
2047  break;
2048  case ipCmpSameHost:
2049  case ipCmpSameNet:
2050  if (!check_same_host_or_net(&port->raddr,
2051  hba->ip_cmp_method))
2052  continue;
2053  break;
2054  default:
2055  /* shouldn't get here, but deem it no-match if so */
2056  continue;
2057  }
2058  } /* != ctLocal */
2059 
2060  /* Check database and role */
2061  if (!check_db(port->database_name, port->user_name, roleid,
2062  hba->databases))
2063  continue;
2064 
2065  if (!check_role(port->user_name, roleid, hba->roles))
2066  continue;
2067 
2068  /* Found a record that matched! */
2069  port->hba = hba;
2070  return;
2071  }
2072 
2073  /* If no matching entry was found, then implicitly reject. */
2074  hba = palloc0(sizeof(HbaLine));
2076  port->hba = hba;
2077 }
2078 
2079 /*
2080  * Read the config file and create a List of HbaLine records for the contents.
2081  *
2082  * The configuration is read into a temporary list, and if any parse error
2083  * occurs the old list is kept in place and false is returned. Only if the
2084  * whole file parses OK is the list replaced, and the function returns true.
2085  *
2086  * On a false result, caller will take care of reporting a FATAL error in case
2087  * this is the initial startup. If it happens on reload, we just keep running
2088  * with the old data.
2089  */
2090 bool
2092 {
2093  FILE *file;
2094  List *hba_lines = NIL;
2095  ListCell *line;
2096  List *new_parsed_lines = NIL;
2097  bool ok = true;
2098  MemoryContext linecxt;
2099  MemoryContext oldcxt;
2100  MemoryContext hbacxt;
2101 
2102  file = AllocateFile(HbaFileName, "r");
2103  if (file == NULL)
2104  {
2105  ereport(LOG,
2107  errmsg("could not open configuration file \"%s\": %m",
2108  HbaFileName)));
2109  return false;
2110  }
2111 
2112  linecxt = tokenize_file(HbaFileName, file, &hba_lines, LOG);
2113  FreeFile(file);
2114 
2115  /* Now parse all the lines */
2118  "hba parser context",
2120  oldcxt = MemoryContextSwitchTo(hbacxt);
2121  foreach(line, hba_lines)
2122  {
2123  TokenizedLine *tok_line = (TokenizedLine *) lfirst(line);
2124  HbaLine *newline;
2125 
2126  /* don't parse lines that already have errors */
2127  if (tok_line->err_msg != NULL)
2128  {
2129  ok = false;
2130  continue;
2131  }
2132 
2133  if ((newline = parse_hba_line(tok_line, LOG)) == NULL)
2134  {
2135  /* Parse error; remember there's trouble */
2136  ok = false;
2137 
2138  /*
2139  * Keep parsing the rest of the file so we can report errors on
2140  * more than the first line. Error has already been logged, no
2141  * need for more chatter here.
2142  */
2143  continue;
2144  }
2145 
2146  new_parsed_lines = lappend(new_parsed_lines, newline);
2147  }
2148 
2149  /*
2150  * A valid HBA file must have at least one entry; else there's no way to
2151  * connect to the postmaster. But only complain about this if we didn't
2152  * already have parsing errors.
2153  */
2154  if (ok && new_parsed_lines == NIL)
2155  {
2156  ereport(LOG,
2157  (errcode(ERRCODE_CONFIG_FILE_ERROR),
2158  errmsg("configuration file \"%s\" contains no entries",
2159  HbaFileName)));
2160  ok = false;
2161  }
2162 
2163  /* Free tokenizer memory */
2164  MemoryContextDelete(linecxt);
2165  MemoryContextSwitchTo(oldcxt);
2166 
2167  if (!ok)
2168  {
2169  /* File contained one or more errors, so bail out */
2170  MemoryContextDelete(hbacxt);
2171  return false;
2172  }
2173 
2174  /* Loaded new file successfully, replace the one we use */
2175  if (parsed_hba_context != NULL)
2176  MemoryContextDelete(parsed_hba_context);
2177  parsed_hba_context = hbacxt;
2178  parsed_hba_lines = new_parsed_lines;
2179 
2180  return true;
2181 }
2182 
2183 /*
2184  * This macro specifies the maximum number of authentication options
2185  * that are possible with any given authentication method that is supported.
2186  * Currently LDAP supports 10, so the macro value is well above the most any
2187  * method needs.
2188  */
2189 #define MAX_HBA_OPTIONS 12
2190 
2191 /*
2192  * Create a text array listing the options specified in the HBA line.
2193  * Return NULL if no options are specified.
2194  */
2195 static ArrayType *
2197 {
2198  int noptions;
2200 
2201  noptions = 0;
2202 
2203  if (hba->auth_method == uaGSS || hba->auth_method == uaSSPI)
2204  {
2205  if (hba->include_realm)
2206  options[noptions++] =
2207  CStringGetTextDatum("include_realm=true");
2208 
2209  if (hba->krb_realm)
2210  options[noptions++] =
2211  CStringGetTextDatum(psprintf("krb_realm=%s", hba->krb_realm));
2212  }
2213 
2214  if (hba->usermap)
2215  options[noptions++] =
2216  CStringGetTextDatum(psprintf("map=%s", hba->usermap));
2217 
2218  if (hba->clientcert)
2219  options[noptions++] =
2220  CStringGetTextDatum("clientcert=true");
2221 
2222  if (hba->pamservice)
2223  options[noptions++] =
2224  CStringGetTextDatum(psprintf("pamservice=%s", hba->pamservice));
2225 
2226  if (hba->auth_method == uaLDAP)
2227  {
2228  if (hba->ldapserver)
2229  options[noptions++] =
2230  CStringGetTextDatum(psprintf("ldapserver=%s", hba->ldapserver));
2231 
2232  if (hba->ldapport)
2233  options[noptions++] =
2234  CStringGetTextDatum(psprintf("ldapport=%d", hba->ldapport));
2235 
2236  if (hba->ldaptls)
2237  options[noptions++] =
2238  CStringGetTextDatum("ldaptls=true");
2239 
2240  if (hba->ldapprefix)
2241  options[noptions++] =
2242  CStringGetTextDatum(psprintf("ldapprefix=%s", hba->ldapprefix));
2243 
2244  if (hba->ldapsuffix)
2245  options[noptions++] =
2246  CStringGetTextDatum(psprintf("ldapsuffix=%s", hba->ldapsuffix));
2247 
2248  if (hba->ldapbasedn)
2249  options[noptions++] =
2250  CStringGetTextDatum(psprintf("ldapbasedn=%s", hba->ldapbasedn));
2251 
2252  if (hba->ldapbinddn)
2253  options[noptions++] =
2254  CStringGetTextDatum(psprintf("ldapbinddn=%s", hba->ldapbinddn));
2255 
2256  if (hba->ldapbindpasswd)
2257  options[noptions++] =
2258  CStringGetTextDatum(psprintf("ldapbindpasswd=%s",
2259  hba->ldapbindpasswd));
2260 
2261  if (hba->ldapsearchattribute)
2262  options[noptions++] =
2263  CStringGetTextDatum(psprintf("ldapsearchattribute=%s",
2264  hba->ldapsearchattribute));
2265 
2266  if (hba->ldapscope)
2267  options[noptions++] =
2268  CStringGetTextDatum(psprintf("ldapscope=%d", hba->ldapscope));
2269  }
2270 
2271  if (hba->auth_method == uaRADIUS)
2272  {
2273  if (hba->radiusservers_s)
2274  options[noptions++] =
2275  CStringGetTextDatum(psprintf("radiusservers=%s", hba->radiusservers_s));
2276 
2277  if (hba->radiussecrets_s)
2278  options[noptions++] =
2279  CStringGetTextDatum(psprintf("radiussecrets=%s", hba->radiussecrets_s));
2280 
2281  if (hba->radiusidentifiers_s)
2282  options[noptions++] =
2283  CStringGetTextDatum(psprintf("radiusidentifiers=%s", hba->radiusidentifiers_s));
2284 
2285  if (hba->radiusports_s)
2286  options[noptions++] =
2287  CStringGetTextDatum(psprintf("radiusports=%s", hba->radiusports_s));
2288  }
2289 
2290  Assert(noptions <= MAX_HBA_OPTIONS);
2291 
2292  if (noptions > 0)
2293  return construct_array(options, noptions, TEXTOID, -1, false, 'i');
2294  else
2295  return NULL;
2296 }
2297 
2298 /* Number of columns in pg_hba_file_rules view */
2299 #define NUM_PG_HBA_FILE_RULES_ATTS 9
2300 
2301 /*
2302  * fill_hba_line: build one row of pg_hba_file_rules view, add it to tuplestore
2303  *
2304  * tuple_store: where to store data
2305  * tupdesc: tuple descriptor for the view
2306  * lineno: pg_hba.conf line number (must always be valid)
2307  * hba: parsed line data (can be NULL, in which case err_msg should be set)
2308  * err_msg: error message (NULL if none)
2309  *
2310  * Note: leaks memory, but we don't care since this is run in a short-lived
2311  * memory context.
2312  */
2313 static void
2315  int lineno, HbaLine *hba, const char *err_msg)
2316 {
2318  bool nulls[NUM_PG_HBA_FILE_RULES_ATTS];
2319  char buffer[NI_MAXHOST];
2320  HeapTuple tuple;
2321  int index;
2322  ListCell *lc;
2323  const char *typestr;
2324  const char *addrstr;
2325  const char *maskstr;
2326  ArrayType *options;
2327 
2329 
2330  memset(values, 0, sizeof(values));
2331  memset(nulls, 0, sizeof(nulls));
2332  index = 0;
2333 
2334  /* line_number */
2335  values[index++] = Int32GetDatum(lineno);
2336 
2337  if (hba != NULL)
2338  {
2339  /* type */
2340  /* Avoid a default: case so compiler will warn about missing cases */
2341  typestr = NULL;
2342  switch (hba->conntype)
2343  {
2344  case ctLocal:
2345  typestr = "local";
2346  break;
2347  case ctHost:
2348  typestr = "host";
2349  break;
2350  case ctHostSSL:
2351  typestr = "hostssl";
2352  break;
2353  case ctHostNoSSL:
2354  typestr = "hostnossl";
2355  break;
2356  }
2357  if (typestr)
2358  values[index++] = CStringGetTextDatum(typestr);
2359  else
2360  nulls[index++] = true;
2361 
2362  /* database */
2363  if (hba->databases)
2364  {
2365  /*
2366  * Flatten HbaToken list to string list. It might seem that we
2367  * should re-quote any quoted tokens, but that has been rejected
2368  * on the grounds that it makes it harder to compare the array
2369  * elements to other system catalogs. That makes entries like
2370  * "all" or "samerole" formally ambiguous ... but users who name
2371  * databases/roles that way are inflicting their own pain.
2372  */
2373  List *names = NIL;
2374 
2375  foreach(lc, hba->databases)
2376  {
2377  HbaToken *tok = lfirst(lc);
2378 
2379  names = lappend(names, tok->string);
2380  }
2381  values[index++] = PointerGetDatum(strlist_to_textarray(names));
2382  }
2383  else
2384  nulls[index++] = true;
2385 
2386  /* user */
2387  if (hba->roles)
2388  {
2389  /* Flatten HbaToken list to string list; see comment above */
2390  List *roles = NIL;
2391 
2392  foreach(lc, hba->roles)
2393  {
2394  HbaToken *tok = lfirst(lc);
2395 
2396  roles = lappend(roles, tok->string);
2397  }
2398  values[index++] = PointerGetDatum(strlist_to_textarray(roles));
2399  }
2400  else
2401  nulls[index++] = true;
2402 
2403  /* address and netmask */
2404  /* Avoid a default: case so compiler will warn about missing cases */
2405  addrstr = maskstr = NULL;
2406  switch (hba->ip_cmp_method)
2407  {
2408  case ipCmpMask:
2409  if (hba->hostname)
2410  {
2411  addrstr = hba->hostname;
2412  }
2413  else
2414  {
2415  if (pg_getnameinfo_all(&hba->addr, sizeof(hba->addr),
2416  buffer, sizeof(buffer),
2417  NULL, 0,
2418  NI_NUMERICHOST) == 0)
2419  {
2420  clean_ipv6_addr(hba->addr.ss_family, buffer);
2421  addrstr = pstrdup(buffer);
2422  }
2423  if (pg_getnameinfo_all(&hba->mask, sizeof(hba->mask),
2424  buffer, sizeof(buffer),
2425  NULL, 0,
2426  NI_NUMERICHOST) == 0)
2427  {
2428  clean_ipv6_addr(hba->mask.ss_family, buffer);
2429  maskstr = pstrdup(buffer);
2430  }
2431  }
2432  break;
2433  case ipCmpAll:
2434  addrstr = "all";
2435  break;
2436  case ipCmpSameHost:
2437  addrstr = "samehost";
2438  break;
2439  case ipCmpSameNet:
2440  addrstr = "samenet";
2441  break;
2442  }
2443  if (addrstr)
2444  values[index++] = CStringGetTextDatum(addrstr);
2445  else
2446  nulls[index++] = true;
2447  if (maskstr)
2448  values[index++] = CStringGetTextDatum(maskstr);
2449  else
2450  nulls[index++] = true;
2451 
2452  /*
2453  * Make sure UserAuthName[] tracks additions to the UserAuth enum
2454  */
2456  "UserAuthName[] must match the UserAuth enum");
2457 
2458  /* auth_method */
2459  values[index++] = CStringGetTextDatum(UserAuthName[hba->auth_method]);
2460 
2461  /* options */
2462  options = gethba_options(hba);
2463  if (options)
2464  values[index++] = PointerGetDatum(options);
2465  else
2466  nulls[index++] = true;
2467  }
2468  else
2469  {
2470  /* no parsing result, so set relevant fields to nulls */
2471  memset(&nulls[1], true, (NUM_PG_HBA_FILE_RULES_ATTS - 2) * sizeof(bool));
2472  }
2473 
2474  /* error */
2475  if (err_msg)
2476  values[NUM_PG_HBA_FILE_RULES_ATTS - 1] = CStringGetTextDatum(err_msg);
2477  else
2478  nulls[NUM_PG_HBA_FILE_RULES_ATTS - 1] = true;
2479 
2480  tuple = heap_form_tuple(tupdesc, values, nulls);
2481  tuplestore_puttuple(tuple_store, tuple);
2482 }
2483 
2484 /*
2485  * Read the pg_hba.conf file and fill the tuplestore with view records.
2486  */
2487 static void
2489 {
2490  FILE *file;
2491  List *hba_lines = NIL;
2492  ListCell *line;
2493  MemoryContext linecxt;
2494  MemoryContext hbacxt;
2495  MemoryContext oldcxt;
2496 
2497  /*
2498  * In the unlikely event that we can't open pg_hba.conf, we throw an
2499  * error, rather than trying to report it via some sort of view entry.
2500  * (Most other error conditions should result in a message in a view
2501  * entry.)
2502  */
2503  file = AllocateFile(HbaFileName, "r");
2504  if (file == NULL)
2505  ereport(ERROR,
2507  errmsg("could not open configuration file \"%s\": %m",
2508  HbaFileName)));
2509 
2510  linecxt = tokenize_file(HbaFileName, file, &hba_lines, DEBUG3);
2511  FreeFile(file);
2512 
2513  /* Now parse all the lines */
2515  "hba parser context",
2517  oldcxt = MemoryContextSwitchTo(hbacxt);
2518  foreach(line, hba_lines)
2519  {
2520  TokenizedLine *tok_line = (TokenizedLine *) lfirst(line);
2521  HbaLine *hbaline = NULL;
2522 
2523  /* don't parse lines that already have errors */
2524  if (tok_line->err_msg == NULL)
2525  hbaline = parse_hba_line(tok_line, DEBUG3);
2526 
2527  fill_hba_line(tuple_store, tupdesc, tok_line->line_num,
2528  hbaline, tok_line->err_msg);
2529  }
2530 
2531  /* Free tokenizer memory */
2532  MemoryContextDelete(linecxt);
2533  /* Free parse_hba_line memory */
2534  MemoryContextSwitchTo(oldcxt);
2535  MemoryContextDelete(hbacxt);
2536 }
2537 
2538 /*
2539  * SQL-accessible SRF to return all the entries in the pg_hba.conf file.
2540  */
2541 Datum
2543 {
2544  Tuplestorestate *tuple_store;
2545  TupleDesc tupdesc;
2546  MemoryContext old_cxt;
2547  ReturnSetInfo *rsi;
2548 
2549  /*
2550  * We must use the Materialize mode to be safe against HBA file changes
2551  * while the cursor is open. It's also more efficient than having to look
2552  * up our current position in the parsed list every time.
2553  */
2554  rsi = (ReturnSetInfo *) fcinfo->resultinfo;
2555 
2556  /* Check to see if caller supports us returning a tuplestore */
2557  if (rsi == NULL || !IsA(rsi, ReturnSetInfo))
2558  ereport(ERROR,
2559  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2560  errmsg("set-valued function called in context that cannot accept a set")));
2561  if (!(rsi->allowedModes & SFRM_Materialize))
2562  ereport(ERROR,
2563  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2564  errmsg("materialize mode required, but it is not " \
2565  "allowed in this context")));
2566 
2568 
2569  /* Build a tuple descriptor for our result type */
2570  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
2571  elog(ERROR, "return type must be a row type");
2572 
2573  /* Build tuplestore to hold the result rows */
2575 
2576  tuple_store =
2578  false, work_mem);
2579  rsi->setDesc = tupdesc;
2580  rsi->setResult = tuple_store;
2581 
2582  MemoryContextSwitchTo(old_cxt);
2583 
2584  /* Fill the tuplestore */
2585  fill_hba_view(tuple_store, tupdesc);
2586 
2587  PG_RETURN_NULL();
2588 }
2589 
2590 
2591 /*
2592  * Parse one tokenised line from the ident config file and store the result in
2593  * an IdentLine structure.
2594  *
2595  * If parsing fails, log a message and return NULL.
2596  *
2597  * If ident_user is a regular expression (ie. begins with a slash), it is
2598  * compiled and stored in IdentLine structure.
2599  *
2600  * Note: this function leaks memory when an error occurs. Caller is expected
2601  * to have set a memory context that will be reset if this function returns
2602  * NULL.
2603  */
2604 static IdentLine *
2606 {
2607  int line_num = tok_line->line_num;
2608  ListCell *field;
2609  List *tokens;
2610  HbaToken *token;
2611  IdentLine *parsedline;
2612 
2613  Assert(tok_line->fields != NIL);
2614  field = list_head(tok_line->fields);
2615 
2616  parsedline = palloc0(sizeof(IdentLine));
2617  parsedline->linenumber = line_num;
2618 
2619  /* Get the map token (must exist) */
2620  tokens = lfirst(field);
2621  IDENT_MULTI_VALUE(tokens);
2622  token = linitial(tokens);
2623  parsedline->usermap = pstrdup(token->string);
2624 
2625  /* Get the ident user token */
2626  field = lnext(field);
2627  IDENT_FIELD_ABSENT(field);
2628  tokens = lfirst(field);
2629  IDENT_MULTI_VALUE(tokens);
2630  token = linitial(tokens);
2631  parsedline->ident_user = pstrdup(token->string);
2632 
2633  /* Get the PG rolename token */
2634  field = lnext(field);
2635  IDENT_FIELD_ABSENT(field);
2636  tokens = lfirst(field);
2637  IDENT_MULTI_VALUE(tokens);
2638  token = linitial(tokens);
2639  parsedline->pg_role = pstrdup(token->string);
2640 
2641  if (parsedline->ident_user[0] == '/')
2642  {
2643  /*
2644  * When system username starts with a slash, treat it as a regular
2645  * expression. Pre-compile it.
2646  */
2647  int r;
2648  pg_wchar *wstr;
2649  int wlen;
2650 
2651  wstr = palloc((strlen(parsedline->ident_user + 1) + 1) * sizeof(pg_wchar));
2652  wlen = pg_mb2wchar_with_len(parsedline->ident_user + 1,
2653  wstr, strlen(parsedline->ident_user + 1));
2654 
2655  r = pg_regcomp(&parsedline->re, wstr, wlen, REG_ADVANCED, C_COLLATION_OID);
2656  if (r)
2657  {
2658  char errstr[100];
2659 
2660  pg_regerror(r, &parsedline->re, errstr, sizeof(errstr));
2661  ereport(LOG,
2662  (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
2663  errmsg("invalid regular expression \"%s\": %s",
2664  parsedline->ident_user + 1, errstr)));
2665 
2666  pfree(wstr);
2667  return NULL;
2668  }
2669  pfree(wstr);
2670  }
2671 
2672  return parsedline;
2673 }
2674 
2675 /*
2676  * Process one line from the parsed ident config lines.
2677  *
2678  * Compare input parsed ident line to the needed map, pg_role and ident_user.
2679  * *found_p and *error_p are set according to our results.
2680  */
2681 static void
2682 check_ident_usermap(IdentLine *identLine, const char *usermap_name,
2683  const char *pg_role, const char *ident_user,
2684  bool case_insensitive, bool *found_p, bool *error_p)
2685 {
2686  *found_p = false;
2687  *error_p = false;
2688 
2689  if (strcmp(identLine->usermap, usermap_name) != 0)
2690  /* Line does not match the map name we're looking for, so just abort */
2691  return;
2692 
2693  /* Match? */
2694  if (identLine->ident_user[0] == '/')
2695  {
2696  /*
2697  * When system username starts with a slash, treat it as a regular
2698  * expression. In this case, we process the system username as a
2699  * regular expression that returns exactly one match. This is replaced
2700  * for \1 in the database username string, if present.
2701  */
2702  int r;
2703  regmatch_t matches[2];
2704  pg_wchar *wstr;
2705  int wlen;
2706  char *ofs;
2707  char *regexp_pgrole;
2708 
2709  wstr = palloc((strlen(ident_user) + 1) * sizeof(pg_wchar));
2710  wlen = pg_mb2wchar_with_len(ident_user, wstr, strlen(ident_user));
2711 
2712  r = pg_regexec(&identLine->re, wstr, wlen, 0, NULL, 2, matches, 0);
2713  if (r)
2714  {
2715  char errstr[100];
2716 
2717  if (r != REG_NOMATCH)
2718  {
2719  /* REG_NOMATCH is not an error, everything else is */
2720  pg_regerror(r, &identLine->re, errstr, sizeof(errstr));
2721  ereport(LOG,
2722  (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
2723  errmsg("regular expression match for \"%s\" failed: %s",
2724  identLine->ident_user + 1, errstr)));
2725  *error_p = true;
2726  }
2727 
2728  pfree(wstr);
2729  return;
2730  }
2731  pfree(wstr);
2732 
2733  if ((ofs = strstr(identLine->pg_role, "\\1")) != NULL)
2734  {
2735  int offset;
2736 
2737  /* substitution of the first argument requested */
2738  if (matches[1].rm_so < 0)
2739  {
2740  ereport(LOG,
2741  (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
2742  errmsg("regular expression \"%s\" has no subexpressions as requested by backreference in \"%s\"",
2743  identLine->ident_user + 1, identLine->pg_role)));
2744  *error_p = true;
2745  return;
2746  }
2747 
2748  /*
2749  * length: original length minus length of \1 plus length of match
2750  * plus null terminator
2751  */
2752  regexp_pgrole = palloc0(strlen(identLine->pg_role) - 2 + (matches[1].rm_eo - matches[1].rm_so) + 1);
2753  offset = ofs - identLine->pg_role;
2754  memcpy(regexp_pgrole, identLine->pg_role, offset);
2755  memcpy(regexp_pgrole + offset,
2756  ident_user + matches[1].rm_so,
2757  matches[1].rm_eo - matches[1].rm_so);
2758  strcat(regexp_pgrole, ofs + 2);
2759  }
2760  else
2761  {
2762  /* no substitution, so copy the match */
2763  regexp_pgrole = pstrdup(identLine->pg_role);
2764  }
2765 
2766  /*
2767  * now check if the username actually matched what the user is trying
2768  * to connect as
2769  */
2770  if (case_insensitive)
2771  {
2772  if (pg_strcasecmp(regexp_pgrole, pg_role) == 0)
2773  *found_p = true;
2774  }
2775  else
2776  {
2777  if (strcmp(regexp_pgrole, pg_role) == 0)
2778  *found_p = true;
2779  }
2780  pfree(regexp_pgrole);
2781 
2782  return;
2783  }
2784  else
2785  {
2786  /* Not regular expression, so make complete match */
2787  if (case_insensitive)
2788  {
2789  if (pg_strcasecmp(identLine->pg_role, pg_role) == 0 &&
2790  pg_strcasecmp(identLine->ident_user, ident_user) == 0)
2791  *found_p = true;
2792  }
2793  else
2794  {
2795  if (strcmp(identLine->pg_role, pg_role) == 0 &&
2796  strcmp(identLine->ident_user, ident_user) == 0)
2797  *found_p = true;
2798  }
2799  }
2800  return;
2801 }
2802 
2803 
2804 /*
2805  * Scan the (pre-parsed) ident usermap file line by line, looking for a match
2806  *
2807  * See if the user with ident username "auth_user" is allowed to act
2808  * as Postgres user "pg_role" according to usermap "usermap_name".
2809  *
2810  * Special case: Usermap NULL, equivalent to what was previously called
2811  * "sameuser" or "samerole", means don't look in the usermap file.
2812  * That's an implied map wherein "pg_role" must be identical to
2813  * "auth_user" in order to be authorized.
2814  *
2815  * Iff authorized, return STATUS_OK, otherwise return STATUS_ERROR.
2816  */
2817 int
2818 check_usermap(const char *usermap_name,
2819  const char *pg_role,
2820  const char *auth_user,
2821  bool case_insensitive)
2822 {
2823  bool found_entry = false,
2824  error = false;
2825 
2826  if (usermap_name == NULL || usermap_name[0] == '\0')
2827  {
2828  if (case_insensitive)
2829  {
2830  if (pg_strcasecmp(pg_role, auth_user) == 0)
2831  return STATUS_OK;
2832  }
2833  else
2834  {
2835  if (strcmp(pg_role, auth_user) == 0)
2836  return STATUS_OK;
2837  }
2838  ereport(LOG,
2839  (errmsg("provided user name (%s) and authenticated user name (%s) do not match",
2840  pg_role, auth_user)));
2841  return STATUS_ERROR;
2842  }
2843  else
2844  {
2845  ListCell *line_cell;
2846 
2847  foreach(line_cell, parsed_ident_lines)
2848  {
2849  check_ident_usermap(lfirst(line_cell), usermap_name,
2850  pg_role, auth_user, case_insensitive,
2851  &found_entry, &error);
2852  if (found_entry || error)
2853  break;
2854  }
2855  }
2856  if (!found_entry && !error)
2857  {
2858  ereport(LOG,
2859  (errmsg("no match in usermap \"%s\" for user \"%s\" authenticated as \"%s\"",
2860  usermap_name, pg_role, auth_user)));
2861  }
2862  return found_entry ? STATUS_OK : STATUS_ERROR;
2863 }
2864 
2865 
2866 /*
2867  * Read the ident config file and create a List of IdentLine records for
2868  * the contents.
2869  *
2870  * This works the same as load_hba(), but for the user config file.
2871  */
2872 bool
2874 {
2875  FILE *file;
2876  List *ident_lines = NIL;
2877  ListCell *line_cell,
2878  *parsed_line_cell;
2879  List *new_parsed_lines = NIL;
2880  bool ok = true;
2881  MemoryContext linecxt;
2882  MemoryContext oldcxt;
2883  MemoryContext ident_context;
2884  IdentLine *newline;
2885 
2886  file = AllocateFile(IdentFileName, "r");
2887  if (file == NULL)
2888  {
2889  /* not fatal ... we just won't do any special ident maps */
2890  ereport(LOG,
2892  errmsg("could not open usermap file \"%s\": %m",
2893  IdentFileName)));
2894  return false;
2895  }
2896 
2897  linecxt = tokenize_file(IdentFileName, file, &ident_lines, LOG);
2898  FreeFile(file);
2899 
2900  /* Now parse all the lines */
2902  ident_context = AllocSetContextCreate(PostmasterContext,
2903  "ident parser context",
2905  oldcxt = MemoryContextSwitchTo(ident_context);
2906  foreach(line_cell, ident_lines)
2907  {
2908  TokenizedLine *tok_line = (TokenizedLine *) lfirst(line_cell);
2909 
2910  /* don't parse lines that already have errors */
2911  if (tok_line->err_msg != NULL)
2912  {
2913  ok = false;
2914  continue;
2915  }
2916 
2917  if ((newline = parse_ident_line(tok_line)) == NULL)
2918  {
2919  /* Parse error; remember there's trouble */
2920  ok = false;
2921 
2922  /*
2923  * Keep parsing the rest of the file so we can report errors on
2924  * more than the first line. Error has already been logged, no
2925  * need for more chatter here.
2926  */
2927  continue;
2928  }
2929 
2930  new_parsed_lines = lappend(new_parsed_lines, newline);
2931  }
2932 
2933  /* Free tokenizer memory */
2934  MemoryContextDelete(linecxt);
2935  MemoryContextSwitchTo(oldcxt);
2936 
2937  if (!ok)
2938  {
2939  /*
2940  * File contained one or more errors, so bail out, first being careful
2941  * to clean up whatever we allocated. Most stuff will go away via
2942  * MemoryContextDelete, but we have to clean up regexes explicitly.
2943  */
2944  foreach(parsed_line_cell, new_parsed_lines)
2945  {
2946  newline = (IdentLine *) lfirst(parsed_line_cell);
2947  if (newline->ident_user[0] == '/')
2948  pg_regfree(&newline->re);
2949  }
2950  MemoryContextDelete(ident_context);
2951  return false;
2952  }
2953 
2954  /* Loaded new file successfully, replace the one we use */
2955  if (parsed_ident_lines != NIL)
2956  {
2957  foreach(parsed_line_cell, parsed_ident_lines)
2958  {
2959  newline = (IdentLine *) lfirst(parsed_line_cell);
2960  if (newline->ident_user[0] == '/')
2961  pg_regfree(&newline->re);
2962  }
2963  }
2964  if (parsed_ident_context != NULL)
2965  MemoryContextDelete(parsed_ident_context);
2966 
2967  parsed_ident_context = ident_context;
2968  parsed_ident_lines = new_parsed_lines;
2969 
2970  return true;
2971 }
2972 
2973 
2974 
2975 /*
2976  * Determine what authentication method should be used when accessing database
2977  * "database" from frontend "raddr", user "user". Return the method and
2978  * an optional argument (stored in fields of *port), and STATUS_OK.
2979  *
2980  * If the file does not contain any entry matching the request, we return
2981  * method = uaImplicitReject.
2982  */
2983 void
2985 {
2986  check_hba(port);
2987 }
int ldapscope
Definition: hba.h:84
Datum pg_hba_file_rules(PG_FUNCTION_ARGS)
Definition: hba.c:2542
List * databases
Definition: hba.h:66
char * radiusports_s
Definition: hba.h:99
Definition: hba.h:61
#define getaddrinfo
Definition: getaddrinfo.h:138
#define NIL
Definition: pg_list.h:69
Definition: hba.h:30
bool EnableSSL
Definition: postmaster.c:233
char * ldapserver
Definition: hba.h:78
#define REQUIRE_AUTH_OPTION(methodval, optname, validmethods)
Definition: hba.c:871
#define NI_NAMEREQD
Definition: getaddrinfo.h:86
#define IsA(nodeptr, _type_)
Definition: nodes.h:557
struct HbaToken HbaToken
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
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:80
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:2682
bool pg_isblank(const char c)
Definition: hba.c:160
int ldapport
Definition: hba.h:79
char * ldapbasedn
Definition: hba.h:83
static void error(void)
Definition: sql-dyntest.c:147
Definition: hba.h:32
#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:1626
char * pamservice
Definition: hba.h:75
#define TEXTOID
Definition: pg_type.h:324
#define PointerGetDatum(X)
Definition: postgres.h:562
regex_t re
Definition: hba.h:109
Definition: hba.h:47
char * pstrdup(const char *in)
Definition: mcxt.c:1077
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:175
Definition: hba.h:35
regoff_t rm_so
Definition: regex.h:85
#define freeaddrinfo
Definition: getaddrinfo.h:143
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:3306
#define gettext_noop(x)
Definition: c.h:139
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:976
#define MemSet(start, val, len)
Definition: c.h:857
bool ssl_in_use
Definition: libpq-be.h:181
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:692
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:562
#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:690
#define AI_NUMERICHOST
Definition: getaddrinfo.h:75
static chr newline(void)
Definition: regc_lex.c:1137
List * radiussecrets
Definition: hba.h:94
#define OidIsValid(objectId)
Definition: c.h:538
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:73
bool load_ident(void)
Definition: hba.c:2873
regoff_t rm_eo
Definition: regex.h:86
#define gai_strerror
Definition: getaddrinfo.h:148
char * ldapsuffix
Definition: hba.h:86
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:646
#define IDENT_FIELD_ABSENT(field)
Definition: hba.c:905
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:5096
#define INVALID_AUTH_OPTION(optname, validmethods)
Definition: hba.c:857
Definition: type.h:90
int linenumber
Definition: hba.h:104
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:757
SockAddr raddr
Definition: libpq-be.h:122
bool am_walsender
Definition: walsender.c:108
ConnType conntype
Definition: hba.h:65
void pfree(void *pointer)
Definition: mcxt.c:950
char * radiusservers_s
Definition: hba.h:93
Definition: hba.h:57
#define NI_MAXHOST
Definition: getaddrinfo.h:90
#define linitial(l)
Definition: pg_list.h:110
static bool hostname_match(const char *pattern, const char *actual_hostname)
Definition: hba.c:670
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:1990
#define IS_AF_UNIX(fam)
Definition: ip.h:24
int line_num
Definition: hba.c:92
char * usermap
Definition: hba.h:106
char * usermap
Definition: hba.h:74
List * radiusports
Definition: hba.h:98
Definition: hba.h:27
List * radiusservers
Definition: hba.h:92
bool include_realm
Definition: hba.h:89
void tuplestore_puttuple(Tuplestorestate *state, HeapTuple tuple)
Definition: tuplestore.c:715
#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:108
static bool check_ip(SockAddr *raddr, struct sockaddr *addr, struct sockaddr *mask)
Definition: hba.c:783
char * c
static char * buf
Definition: pg_test_fsync.c:65
bool load_hba(void)
Definition: hba.c:2091
bool Db_user_namespace
Definition: postmaster.c:240
bool SplitIdentifierString(char *rawstring, char separator, List **namelist)
Definition: varlena.c:3240
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:80
int errcode_for_file_access(void)
Definition: elog.c:598
#define is_absolute_path(filename)
Definition: port.h:77
#define EAI_NONAME
Definition: getaddrinfo.h:34
void hba_getauthmethod(hbaPort *port)
Definition: hba.c:2984
void get_parent_directory(char *path)
Definition: path.c:854
char * krb_realm
Definition: hba.h:88
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2094
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:877
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
IPCompareMethod
Definition: hba.h:45
char * ldapbindpasswd
Definition: hba.h:81
#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:975
char * ldapprefix
Definition: hba.h:85
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:916
static void check_network_callback(struct sockaddr *addr, struct sockaddr *netmask, void *cb_data)
Definition: hba.c:797
static int port
Definition: pg_regress.c:89
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
static HbaLine * parse_hba_line(TokenizedLine *tok_line, int elevel)
Definition: hba.c:942
static int elevel
Definition: vacuumlazy.c:137
static bool verify_option_list_length(List *options, char *optionname, List *masters, char *mastername, int line_num)
Definition: hba.c:1599
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:316
static void fill_hba_line(Tuplestorestate *tuple_store, TupleDesc tupdesc, int lineno, HbaLine *hba, const char *err_msg)
Definition: hba.c:2314
Definition: hba.h:33
static void fill_hba_view(Tuplestorestate *tuple_store, TupleDesc tupdesc)
Definition: hba.c:2488
Definition: hba.h:50
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
void * palloc0(Size size)
Definition: mcxt.c:878
uintptr_t Datum
Definition: postgres.h:372
char * hostname
Definition: hba.h:71
char * string
Definition: hba.c:77
char * radiusidentifiers_s
Definition: hba.h:97
bool am_db_walsender
Definition: walsender.c:111
int work_mem
Definition: globals.c:112
List * radiusidentifiers
Definition: hba.h:96
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:2818
bool quoted
Definition: hba.c:78
char * radiussecrets_s
Definition: hba.h:95
int pg_mb2wchar_with_len(const char *from, pg_wchar *to, int len)
Definition: mbutils.c:734
bool result
Definition: hba.c:64
int allowedModes
Definition: execnodes.h:267
static List * parsed_ident_lines
Definition: hba.c:112
static MemoryContext parsed_ident_context
Definition: hba.c:113
int ai_protocol
Definition: getaddrinfo.h:105
List * roles
Definition: hba.h:67
SetFunctionReturnMode returnMode
Definition: execnodes.h:269
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#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:2299
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:207
int ai_socktype
Definition: getaddrinfo.h:104
static MemoryContext tokenize_file(const char *filename, FILE *file, List **tok_lines, int elevel)
Definition: hba.c:470
Definition: hba.h:102
char * dbname
Definition: streamutil.c:38
void clean_ipv6_addr(int addr_family, char *addr)
Definition: network.c:1504
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
#define C_COLLATION_OID
Definition: pg_collation.h:77
static bool is_member(Oid userid, const char *role)
Definition: hba.c:562
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:201
void join_path_components(char *ret_path, const char *head, const char *tail)
Definition: path.c:218
char * ldapsearchattribute
Definition: hba.h:82
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:272
static HbaToken * copy_hba_token(HbaToken *in)
Definition: hba.c:307
int FreeFile(FILE *file)
Definition: fd.c:2277
static Datum values[MAXATTR]
Definition: bootstrap.c:162
#define MAX_TOKEN
Definition: hba.c:56
ExprContext * econtext
Definition: execnodes.h:265
bool upn_username
Definition: hba.h:91
#define Int32GetDatum(X)
Definition: postgres.h:485
static char * filename
Definition: pg_dumpall.c:87
struct addrinfo * ai_next
Definition: getaddrinfo.h:109
bool is_member_of_role_nosuper(Oid member, Oid role)
Definition: acl.c:4875
TupleDesc setDesc
Definition: execnodes.h:273
char * ident_user
Definition: hba.h:107
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:849
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:824
#define errcontext
Definition: elog.h:164
#define CStringGetTextDatum(s)
Definition: builtins.h:91
static IdentLine * parse_ident_line(TokenizedLine *tok_line)
Definition: hba.c:2605
bool clientcert
Definition: hba.h:87
#define PG_FUNCTION_ARGS
Definition: fmgr.h:158
size_t ai_addrlen
Definition: getaddrinfo.h:106
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:102
char * database_name
Definition: libpq-be.h:136
static char * hostname
Definition: pg_regress.c:88
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:90
MemoryContext PostmasterContext
Definition: mcxt.c:45
long val
Definition: informix.c:689
Definition: hba.h:56
char * pg_role
Definition: hba.h:108
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:107
#define PG_RETURN_NULL()
Definition: fmgr.h:305
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:2196
int ai_family
Definition: getaddrinfo.h:103
#define MAX_HBA_OPTIONS
Definition: hba.c:2189