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