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