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