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