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