PageRenderTime 35ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/src/backend/libpq/hba.c

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