PageRenderTime 69ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 1ms

/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

Large files files are truncated, but you can click here to view the full file

  1. /*-------------------------------------------------------------------------
  2. *
  3. * hba.c
  4. * Routines to handle host based authentication (that's the scheme
  5. * wherein you authenticate a user by seeing what IP address the system
  6. * says he comes from and choosing authentication method based on it).
  7. *
  8. * Portions Copyright (c) 1996-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\"",

Large files files are truncated, but you can click here to view the full file