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