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