PageRenderTime 52ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/src/backend/libpq/hba.c

https://bitbucket.org/gencer/postgres
C | 2257 lines | 2160 code | 26 blank | 71 comment | 54 complexity | b1b316a2996f789bbe453bc207ad24dc 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-2014, 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 "catalog/pg_collation.h"
  27. #include "libpq/ip.h"
  28. #include "libpq/libpq.h"
  29. #include "postmaster/postmaster.h"
  30. #include "regex/regex.h"
  31. #include "replication/walsender.h"
  32. #include "storage/fd.h"
  33. #include "utils/acl.h"
  34. #include "utils/guc.h"
  35. #include "utils/lsyscache.h"
  36. #include "utils/memutils.h"
  37. #ifdef USE_LDAP
  38. #ifdef WIN32
  39. #include <winldap.h>
  40. #else
  41. #include <ldap.h>
  42. #endif
  43. #endif
  44. #define atooid(x) ((Oid) strtoul((x), NULL, 10))
  45. #define atoxid(x) ((TransactionId) strtoul((x), NULL, 10))
  46. #define MAX_TOKEN 256
  47. #define MAX_LINE 8192
  48. /* callback data for check_network_callback */
  49. typedef struct check_network_data
  50. {
  51. IPCompareMethod method; /* test method */
  52. SockAddr *raddr; /* client's actual address */
  53. bool result; /* set to true if match */
  54. } check_network_data;
  55. #define token_is_keyword(t, k) (!t->quoted && strcmp(t->string, k) == 0)
  56. #define token_matches(t, k) (strcmp(t->string, k) == 0)
  57. /*
  58. * A single string token lexed from the HBA config file, together with whether
  59. * the token had been quoted.
  60. */
  61. typedef struct HbaToken
  62. {
  63. char *string;
  64. bool quoted;
  65. } HbaToken;
  66. /*
  67. * pre-parsed content of HBA config file: list of HbaLine structs.
  68. * parsed_hba_context is the memory context where it lives.
  69. */
  70. static List *parsed_hba_lines = NIL;
  71. static MemoryContext parsed_hba_context = NULL;
  72. /*
  73. * pre-parsed content of ident mapping file: list of IdentLine structs.
  74. * parsed_ident_context is the memory context where it lives.
  75. *
  76. * NOTE: the IdentLine structs can contain pre-compiled regular expressions
  77. * that live outside the memory context. Before destroying or resetting the
  78. * memory context, they need to be expliticly free'd.
  79. */
  80. static List *parsed_ident_lines = NIL;
  81. static MemoryContext parsed_ident_context = NULL;
  82. static MemoryContext tokenize_file(const char *filename, FILE *file,
  83. List **lines, List **line_nums, List **raw_lines);
  84. static List *tokenize_inc_file(List *tokens, const char *outer_filename,
  85. const char *inc_filename);
  86. static bool parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline,
  87. int line_num);
  88. /*
  89. * isblank() exists in the ISO C99 spec, but it's not very portable yet,
  90. * so provide our own version.
  91. */
  92. bool
  93. pg_isblank(const char c)
  94. {
  95. return c == ' ' || c == '\t' || c == '\r';
  96. }
  97. /*
  98. * Grab one token out of the string pointed to by lineptr.
  99. * Tokens are strings of non-blank
  100. * characters bounded by blank characters, commas, beginning of line, and
  101. * end of line. Blank means space or tab. Tokens can be delimited by
  102. * double quotes (this allows the inclusion of blanks, but not newlines).
  103. *
  104. * The token, if any, is returned at *buf (a buffer of size bufsz).
  105. * Also, we set *initial_quote to indicate whether there was quoting before
  106. * the first character. (We use that to prevent "@x" from being treated
  107. * as a file inclusion request. Note that @"x" should be so treated;
  108. * we want to allow that to support embedded spaces in file paths.)
  109. * We set *terminating_comma to indicate whether the token is terminated by a
  110. * comma (which is not returned.)
  111. *
  112. * If successful: store null-terminated token at *buf and return TRUE.
  113. * If no more tokens on line: set *buf = '\0' and return FALSE.
  114. *
  115. * Leave file positioned at the character immediately after the token or EOF,
  116. * whichever comes first. If no more tokens on line, position the file to the
  117. * beginning of the next line or EOF, whichever comes first.
  118. *
  119. * Handle comments.
  120. */
  121. static bool
  122. next_token(char **lineptr, char *buf, int bufsz, bool *initial_quote,
  123. bool *terminating_comma)
  124. {
  125. int c;
  126. char *start_buf = buf;
  127. char *end_buf = buf + (bufsz - 2);
  128. bool in_quote = false;
  129. bool was_quote = false;
  130. bool saw_quote = false;
  131. /* end_buf reserves two bytes to ensure we can append \n and \0 */
  132. Assert(end_buf > start_buf);
  133. *initial_quote = false;
  134. *terminating_comma = false;
  135. /* Move over initial whitespace and commas */
  136. while ((c = (*(*lineptr)++)) != '\0' && (pg_isblank(c) || c == ','))
  137. ;
  138. if (c == '\0' || c == '\n')
  139. {
  140. *buf = '\0';
  141. return false;
  142. }
  143. /*
  144. * Build a token in buf of next characters up to EOF, EOL, unquoted comma,
  145. * or unquoted whitespace.
  146. */
  147. while (c != '\0' && c != '\n' &&
  148. (!pg_isblank(c) || in_quote))
  149. {
  150. /* skip comments to EOL */
  151. if (c == '#' && !in_quote)
  152. {
  153. while ((c = (*(*lineptr)++)) != '\0' && c != '\n')
  154. ;
  155. /* If only comment, consume EOL too; return EOL */
  156. if (c != '\0' && buf == start_buf)
  157. (*lineptr)++;
  158. break;
  159. }
  160. if (buf >= end_buf)
  161. {
  162. *buf = '\0';
  163. ereport(LOG,
  164. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  165. errmsg("authentication file token too long, skipping: \"%s\"",
  166. start_buf)));
  167. /* Discard remainder of line */
  168. while ((c = (*(*lineptr)++)) != '\0' && c != '\n')
  169. ;
  170. break;
  171. }
  172. /* we do not pass back the comma in the token */
  173. if (c == ',' && !in_quote)
  174. {
  175. *terminating_comma = true;
  176. break;
  177. }
  178. if (c != '"' || was_quote)
  179. *buf++ = c;
  180. /* Literal double-quote is two double-quotes */
  181. if (in_quote && c == '"')
  182. was_quote = !was_quote;
  183. else
  184. was_quote = false;
  185. if (c == '"')
  186. {
  187. in_quote = !in_quote;
  188. saw_quote = true;
  189. if (buf == start_buf)
  190. *initial_quote = true;
  191. }
  192. c = *(*lineptr)++;
  193. }
  194. /*
  195. * Put back the char right after the token (critical in case it is EOL,
  196. * since we need to detect end-of-line at next call).
  197. */
  198. (*lineptr)--;
  199. *buf = '\0';
  200. return (saw_quote || buf > start_buf);
  201. }
  202. static HbaToken *
  203. make_hba_token(char *token, bool quoted)
  204. {
  205. HbaToken *hbatoken;
  206. int toklen;
  207. toklen = strlen(token);
  208. hbatoken = (HbaToken *) palloc(sizeof(HbaToken) + toklen + 1);
  209. hbatoken->string = (char *) hbatoken + sizeof(HbaToken);
  210. hbatoken->quoted = quoted;
  211. memcpy(hbatoken->string, token, toklen + 1);
  212. return hbatoken;
  213. }
  214. /*
  215. * Copy a HbaToken struct into freshly palloc'd memory.
  216. */
  217. static HbaToken *
  218. copy_hba_token(HbaToken *in)
  219. {
  220. HbaToken *out = make_hba_token(in->string, in->quoted);
  221. return out;
  222. }
  223. /*
  224. * Tokenize one HBA field from a line, handling file inclusion and comma lists.
  225. *
  226. * The result is a List of HbaToken structs for each individual token,
  227. * or NIL if we reached EOL.
  228. */
  229. static List *
  230. next_field_expand(const char *filename, char **lineptr)
  231. {
  232. char buf[MAX_TOKEN];
  233. bool trailing_comma;
  234. bool initial_quote;
  235. List *tokens = NIL;
  236. do
  237. {
  238. if (!next_token(lineptr, buf, sizeof(buf), &initial_quote, &trailing_comma))
  239. break;
  240. /* Is this referencing a file? */
  241. if (!initial_quote && buf[0] == '@' && buf[1] != '\0')
  242. tokens = tokenize_inc_file(tokens, filename, buf + 1);
  243. else
  244. tokens = lappend(tokens, make_hba_token(buf, initial_quote));
  245. } while (trailing_comma);
  246. return tokens;
  247. }
  248. /*
  249. * tokenize_inc_file
  250. * Expand a file included from another file into an hba "field"
  251. *
  252. * Opens and tokenises a file included from another HBA config file with @,
  253. * and returns all values found therein as a flat list of HbaTokens. If a
  254. * @-token is found, recursively expand it. The given token list is used as
  255. * initial contents of list (so foo,bar,@baz does what you expect).
  256. */
  257. static List *
  258. tokenize_inc_file(List *tokens,
  259. const char *outer_filename,
  260. const char *inc_filename)
  261. {
  262. char *inc_fullname;
  263. FILE *inc_file;
  264. List *inc_lines;
  265. List *inc_line_nums;
  266. ListCell *inc_line;
  267. MemoryContext linecxt;
  268. if (is_absolute_path(inc_filename))
  269. {
  270. /* absolute path is taken as-is */
  271. inc_fullname = pstrdup(inc_filename);
  272. }
  273. else
  274. {
  275. /* relative path is relative to dir of calling file */
  276. inc_fullname = (char *) palloc(strlen(outer_filename) + 1 +
  277. strlen(inc_filename) + 1);
  278. strcpy(inc_fullname, outer_filename);
  279. get_parent_directory(inc_fullname);
  280. join_path_components(inc_fullname, inc_fullname, inc_filename);
  281. canonicalize_path(inc_fullname);
  282. }
  283. inc_file = AllocateFile(inc_fullname, "r");
  284. if (inc_file == NULL)
  285. {
  286. ereport(LOG,
  287. (errcode_for_file_access(),
  288. errmsg("could not open secondary authentication file \"@%s\" as \"%s\": %m",
  289. inc_filename, inc_fullname)));
  290. pfree(inc_fullname);
  291. return tokens;
  292. }
  293. /* There is possible recursion here if the file contains @ */
  294. linecxt = tokenize_file(inc_fullname, inc_file, &inc_lines, &inc_line_nums, NULL);
  295. FreeFile(inc_file);
  296. pfree(inc_fullname);
  297. foreach(inc_line, inc_lines)
  298. {
  299. List *inc_fields = lfirst(inc_line);
  300. ListCell *inc_field;
  301. foreach(inc_field, inc_fields)
  302. {
  303. List *inc_tokens = lfirst(inc_field);
  304. ListCell *inc_token;
  305. foreach(inc_token, inc_tokens)
  306. {
  307. HbaToken *token = lfirst(inc_token);
  308. tokens = lappend(tokens, copy_hba_token(token));
  309. }
  310. }
  311. }
  312. MemoryContextDelete(linecxt);
  313. return tokens;
  314. }
  315. /*
  316. * Tokenize the given file, storing the resulting data into three Lists: a
  317. * List of lines, a List of line numbers, and a List of raw line contents.
  318. *
  319. * The list of lines is a triple-nested List structure. Each line is a List of
  320. * fields, and each field is a List of HbaTokens.
  321. *
  322. * filename must be the absolute path to the target file.
  323. *
  324. * Return value is a memory context which contains all memory allocated by
  325. * this function.
  326. */
  327. static MemoryContext
  328. tokenize_file(const char *filename, FILE *file,
  329. List **lines, List **line_nums, List **raw_lines)
  330. {
  331. List *current_line = NIL;
  332. List *current_field = NIL;
  333. int line_number = 1;
  334. MemoryContext linecxt;
  335. MemoryContext oldcxt;
  336. linecxt = AllocSetContextCreate(TopMemoryContext,
  337. "tokenize file cxt",
  338. ALLOCSET_DEFAULT_MINSIZE,
  339. ALLOCSET_DEFAULT_INITSIZE,
  340. ALLOCSET_DEFAULT_MAXSIZE);
  341. oldcxt = MemoryContextSwitchTo(linecxt);
  342. *lines = *line_nums = NIL;
  343. while (!feof(file) && !ferror(file))
  344. {
  345. char rawline[MAX_LINE];
  346. char *lineptr;
  347. if (!fgets(rawline, sizeof(rawline), file))
  348. break;
  349. if (strlen(rawline) == MAX_LINE - 1)
  350. /* Line too long! */
  351. ereport(ERROR,
  352. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  353. errmsg("authentication file line too long"),
  354. errcontext("line %d of configuration file \"%s\"",
  355. line_number, filename)));
  356. /* Strip trailing linebreak from rawline */
  357. lineptr = rawline + strlen(rawline) - 1;
  358. while (lineptr >= rawline && (*lineptr == '\n' || *lineptr == '\r'))
  359. *lineptr-- = '\0';
  360. lineptr = rawline;
  361. while (strlen(lineptr) > 0)
  362. {
  363. current_field = next_field_expand(filename, &lineptr);
  364. /* add tokens to list, unless we are at EOL or comment start */
  365. if (list_length(current_field) > 0)
  366. {
  367. if (current_line == NIL)
  368. {
  369. /* make a new line List, record its line number */
  370. current_line = lappend(current_line, current_field);
  371. *lines = lappend(*lines, current_line);
  372. *line_nums = lappend_int(*line_nums, line_number);
  373. if (raw_lines)
  374. *raw_lines = lappend(*raw_lines, pstrdup(rawline));
  375. }
  376. else
  377. {
  378. /* append tokens to current line's list */
  379. current_line = lappend(current_line, current_field);
  380. }
  381. }
  382. }
  383. /* we are at real or logical EOL, so force a new line List */
  384. current_line = NIL;
  385. line_number++;
  386. }
  387. MemoryContextSwitchTo(oldcxt);
  388. return linecxt;
  389. }
  390. /*
  391. * Does user belong to role?
  392. *
  393. * userid is the OID of the role given as the attempted login identifier.
  394. * We check to see if it is a member of the specified role name.
  395. */
  396. static bool
  397. is_member(Oid userid, const char *role)
  398. {
  399. Oid roleid;
  400. if (!OidIsValid(userid))
  401. return false; /* if user not exist, say "no" */
  402. roleid = get_role_oid(role, true);
  403. if (!OidIsValid(roleid))
  404. return false; /* if target role not exist, say "no" */
  405. /*
  406. * See if user is directly or indirectly a member of role. For this
  407. * purpose, a superuser is not considered to be automatically a member of
  408. * the role, so group auth only applies to explicit membership.
  409. */
  410. return is_member_of_role_nosuper(userid, roleid);
  411. }
  412. /*
  413. * Check HbaToken list for a match to role, allowing group names.
  414. */
  415. static bool
  416. check_role(const char *role, Oid roleid, List *tokens)
  417. {
  418. ListCell *cell;
  419. HbaToken *tok;
  420. foreach(cell, tokens)
  421. {
  422. tok = lfirst(cell);
  423. if (!tok->quoted && tok->string[0] == '+')
  424. {
  425. if (is_member(roleid, tok->string + 1))
  426. return true;
  427. }
  428. else if (token_matches(tok, role) ||
  429. token_is_keyword(tok, "all"))
  430. return true;
  431. }
  432. return false;
  433. }
  434. /*
  435. * Check to see if db/role combination matches HbaToken list.
  436. */
  437. static bool
  438. check_db(const char *dbname, const char *role, Oid roleid, List *tokens)
  439. {
  440. ListCell *cell;
  441. HbaToken *tok;
  442. foreach(cell, tokens)
  443. {
  444. tok = lfirst(cell);
  445. if (am_walsender)
  446. {
  447. /* walsender connections can only match replication keyword */
  448. if (token_is_keyword(tok, "replication"))
  449. return true;
  450. }
  451. else if (token_is_keyword(tok, "all"))
  452. return true;
  453. else if (token_is_keyword(tok, "sameuser"))
  454. {
  455. if (strcmp(dbname, role) == 0)
  456. return true;
  457. }
  458. else if (token_is_keyword(tok, "samegroup") ||
  459. token_is_keyword(tok, "samerole"))
  460. {
  461. if (is_member(roleid, dbname))
  462. return true;
  463. }
  464. else if (token_is_keyword(tok, "replication"))
  465. continue; /* never match this if not walsender */
  466. else if (token_matches(tok, dbname))
  467. return true;
  468. }
  469. return false;
  470. }
  471. static bool
  472. ipv4eq(struct sockaddr_in * a, struct sockaddr_in * b)
  473. {
  474. return (a->sin_addr.s_addr == b->sin_addr.s_addr);
  475. }
  476. #ifdef HAVE_IPV6
  477. static bool
  478. ipv6eq(struct sockaddr_in6 * a, struct sockaddr_in6 * b)
  479. {
  480. int i;
  481. for (i = 0; i < 16; i++)
  482. if (a->sin6_addr.s6_addr[i] != b->sin6_addr.s6_addr[i])
  483. return false;
  484. return true;
  485. }
  486. #endif /* HAVE_IPV6 */
  487. /*
  488. * Check whether host name matches pattern.
  489. */
  490. static bool
  491. hostname_match(const char *pattern, const char *actual_hostname)
  492. {
  493. if (pattern[0] == '.') /* suffix match */
  494. {
  495. size_t plen = strlen(pattern);
  496. size_t hlen = strlen(actual_hostname);
  497. if (hlen < plen)
  498. return false;
  499. return (pg_strcasecmp(pattern, actual_hostname + (hlen - plen)) == 0);
  500. }
  501. else
  502. return (pg_strcasecmp(pattern, actual_hostname) == 0);
  503. }
  504. /*
  505. * Check to see if a connecting IP matches a given host name.
  506. */
  507. static bool
  508. check_hostname(hbaPort *port, const char *hostname)
  509. {
  510. struct addrinfo *gai_result,
  511. *gai;
  512. int ret;
  513. bool found;
  514. /* Quick out if remote host name already known bad */
  515. if (port->remote_hostname_resolv < 0)
  516. return false;
  517. /* Lookup remote host name if not already done */
  518. if (!port->remote_hostname)
  519. {
  520. char remote_hostname[NI_MAXHOST];
  521. ret = pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
  522. remote_hostname, sizeof(remote_hostname),
  523. NULL, 0,
  524. NI_NAMEREQD);
  525. if (ret != 0)
  526. {
  527. /* remember failure; don't complain in the postmaster log yet */
  528. port->remote_hostname_resolv = -2;
  529. port->remote_hostname_errcode = ret;
  530. return false;
  531. }
  532. port->remote_hostname = pstrdup(remote_hostname);
  533. }
  534. /* Now see if remote host name matches this pg_hba line */
  535. if (!hostname_match(hostname, port->remote_hostname))
  536. return false;
  537. /* If we already verified the forward lookup, we're done */
  538. if (port->remote_hostname_resolv == +1)
  539. return true;
  540. /* Lookup IP from host name and check against original IP */
  541. ret = getaddrinfo(port->remote_hostname, NULL, NULL, &gai_result);
  542. if (ret != 0)
  543. {
  544. /* remember failure; don't complain in the postmaster log yet */
  545. port->remote_hostname_resolv = -2;
  546. port->remote_hostname_errcode = ret;
  547. return false;
  548. }
  549. found = false;
  550. for (gai = gai_result; gai; gai = gai->ai_next)
  551. {
  552. if (gai->ai_addr->sa_family == port->raddr.addr.ss_family)
  553. {
  554. if (gai->ai_addr->sa_family == AF_INET)
  555. {
  556. if (ipv4eq((struct sockaddr_in *) gai->ai_addr,
  557. (struct sockaddr_in *) & port->raddr.addr))
  558. {
  559. found = true;
  560. break;
  561. }
  562. }
  563. #ifdef HAVE_IPV6
  564. else if (gai->ai_addr->sa_family == AF_INET6)
  565. {
  566. if (ipv6eq((struct sockaddr_in6 *) gai->ai_addr,
  567. (struct sockaddr_in6 *) & port->raddr.addr))
  568. {
  569. found = true;
  570. break;
  571. }
  572. }
  573. #endif
  574. }
  575. }
  576. if (gai_result)
  577. freeaddrinfo(gai_result);
  578. if (!found)
  579. elog(DEBUG2, "pg_hba.conf host name \"%s\" rejected because address resolution did not return a match with IP address of client",
  580. hostname);
  581. port->remote_hostname_resolv = found ? +1 : -1;
  582. return found;
  583. }
  584. /*
  585. * Check to see if a connecting IP matches the given address and netmask.
  586. */
  587. static bool
  588. check_ip(SockAddr *raddr, struct sockaddr * addr, struct sockaddr * mask)
  589. {
  590. if (raddr->addr.ss_family == addr->sa_family)
  591. {
  592. /* Same address family */
  593. if (!pg_range_sockaddr(&raddr->addr,
  594. (struct sockaddr_storage *) addr,
  595. (struct sockaddr_storage *) mask))
  596. return false;
  597. }
  598. #ifdef HAVE_IPV6
  599. else if (addr->sa_family == AF_INET &&
  600. raddr->addr.ss_family == AF_INET6)
  601. {
  602. /*
  603. * If we're connected on IPv6 but the file specifies an IPv4 address
  604. * to match against, promote the latter to an IPv6 address before
  605. * trying to match the client's address.
  606. */
  607. struct sockaddr_storage addrcopy,
  608. maskcopy;
  609. memcpy(&addrcopy, &addr, sizeof(addrcopy));
  610. memcpy(&maskcopy, &mask, sizeof(maskcopy));
  611. pg_promote_v4_to_v6_addr(&addrcopy);
  612. pg_promote_v4_to_v6_mask(&maskcopy);
  613. if (!pg_range_sockaddr(&raddr->addr, &addrcopy, &maskcopy))
  614. return false;
  615. }
  616. #endif /* HAVE_IPV6 */
  617. else
  618. {
  619. /* Wrong address family, no IPV6 */
  620. return false;
  621. }
  622. return true;
  623. }
  624. /*
  625. * pg_foreach_ifaddr callback: does client addr match this machine interface?
  626. */
  627. static void
  628. check_network_callback(struct sockaddr * addr, struct sockaddr * netmask,
  629. void *cb_data)
  630. {
  631. check_network_data *cn = (check_network_data *) cb_data;
  632. struct sockaddr_storage mask;
  633. /* Already found a match? */
  634. if (cn->result)
  635. return;
  636. if (cn->method == ipCmpSameHost)
  637. {
  638. /* Make an all-ones netmask of appropriate length for family */
  639. pg_sockaddr_cidr_mask(&mask, NULL, addr->sa_family);
  640. cn->result = check_ip(cn->raddr, addr, (struct sockaddr *) & mask);
  641. }
  642. else
  643. {
  644. /* Use the netmask of the interface itself */
  645. cn->result = check_ip(cn->raddr, addr, netmask);
  646. }
  647. }
  648. /*
  649. * Use pg_foreach_ifaddr to check a samehost or samenet match
  650. */
  651. static bool
  652. check_same_host_or_net(SockAddr *raddr, IPCompareMethod method)
  653. {
  654. check_network_data cn;
  655. cn.method = method;
  656. cn.raddr = raddr;
  657. cn.result = false;
  658. errno = 0;
  659. if (pg_foreach_ifaddr(check_network_callback, &cn) < 0)
  660. {
  661. elog(LOG, "error enumerating network interfaces: %m");
  662. return false;
  663. }
  664. return cn.result;
  665. }
  666. /*
  667. * Macros used to check and report on invalid configuration options.
  668. * INVALID_AUTH_OPTION = reports when an option is specified for a method where it's
  669. * not supported.
  670. * REQUIRE_AUTH_OPTION = same as INVALID_AUTH_OPTION, except it also checks if the
  671. * method is actually the one specified. Used as a shortcut when
  672. * the option is only valid for one authentication method.
  673. * MANDATORY_AUTH_ARG = check if a required option is set for an authentication method,
  674. * reporting error if it's not.
  675. */
  676. #define INVALID_AUTH_OPTION(optname, validmethods) do {\
  677. ereport(LOG, \
  678. (errcode(ERRCODE_CONFIG_FILE_ERROR), \
  679. /* translator: the second %s is a list of auth methods */ \
  680. errmsg("authentication option \"%s\" is only valid for authentication methods %s", \
  681. optname, _(validmethods)), \
  682. errcontext("line %d of configuration file \"%s\"", \
  683. line_num, HbaFileName))); \
  684. return false; \
  685. } while (0);
  686. #define REQUIRE_AUTH_OPTION(methodval, optname, validmethods) do {\
  687. if (hbaline->auth_method != methodval) \
  688. INVALID_AUTH_OPTION(optname, validmethods); \
  689. } while (0);
  690. #define MANDATORY_AUTH_ARG(argvar, argname, authname) do {\
  691. if (argvar == NULL) {\
  692. ereport(LOG, \
  693. (errcode(ERRCODE_CONFIG_FILE_ERROR), \
  694. errmsg("authentication method \"%s\" requires argument \"%s\" to be set", \
  695. authname, argname), \
  696. errcontext("line %d of configuration file \"%s\"", \
  697. line_num, HbaFileName))); \
  698. return NULL; \
  699. } \
  700. } while (0);
  701. /*
  702. * IDENT_FIELD_ABSENT:
  703. * Throw an error and exit the function if the given ident field ListCell is
  704. * not populated.
  705. *
  706. * IDENT_MULTI_VALUE:
  707. * Throw an error and exit the function if the given ident token List has more
  708. * than one element.
  709. */
  710. #define IDENT_FIELD_ABSENT(field) do {\
  711. if (!field) { \
  712. ereport(LOG, \
  713. (errcode(ERRCODE_CONFIG_FILE_ERROR), \
  714. errmsg("missing entry in file \"%s\" at end of line %d", \
  715. IdentFileName, line_number))); \
  716. return NULL; \
  717. } \
  718. } while (0);
  719. #define IDENT_MULTI_VALUE(tokens) do {\
  720. if (tokens->length > 1) { \
  721. ereport(LOG, \
  722. (errcode(ERRCODE_CONFIG_FILE_ERROR), \
  723. errmsg("multiple values in ident field"), \
  724. errcontext("line %d of configuration file \"%s\"", \
  725. line_number, IdentFileName))); \
  726. return NULL; \
  727. } \
  728. } while (0);
  729. /*
  730. * Parse one tokenised line from the hba config file and store the result in a
  731. * HbaLine structure, or NULL if parsing fails.
  732. *
  733. * The tokenised line is a List of fields, each field being a List of
  734. * HbaTokens.
  735. *
  736. * Note: this function leaks memory when an error occurs. Caller is expected
  737. * to have set a memory context that will be reset if this function returns
  738. * NULL.
  739. */
  740. static HbaLine *
  741. parse_hba_line(List *line, int line_num, char *raw_line)
  742. {
  743. char *str;
  744. struct addrinfo *gai_result;
  745. struct addrinfo hints;
  746. int ret;
  747. char *cidr_slash;
  748. char *unsupauth;
  749. ListCell *field;
  750. List *tokens;
  751. ListCell *tokencell;
  752. HbaToken *token;
  753. HbaLine *parsedline;
  754. parsedline = palloc0(sizeof(HbaLine));
  755. parsedline->linenumber = line_num;
  756. parsedline->rawline = pstrdup(raw_line);
  757. /* Check the record type. */
  758. field = list_head(line);
  759. tokens = lfirst(field);
  760. if (tokens->length > 1)
  761. {
  762. ereport(LOG,
  763. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  764. errmsg("multiple values specified for connection type"),
  765. errhint("Specify exactly one connection type per line."),
  766. errcontext("line %d of configuration file \"%s\"",
  767. line_num, HbaFileName)));
  768. return NULL;
  769. }
  770. token = linitial(tokens);
  771. if (strcmp(token->string, "local") == 0)
  772. {
  773. #ifdef HAVE_UNIX_SOCKETS
  774. parsedline->conntype = ctLocal;
  775. #else
  776. ereport(LOG,
  777. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  778. errmsg("local connections are not supported by this build"),
  779. errcontext("line %d of configuration file \"%s\"",
  780. line_num, HbaFileName)));
  781. return NULL;
  782. #endif
  783. }
  784. else if (strcmp(token->string, "host") == 0 ||
  785. strcmp(token->string, "hostssl") == 0 ||
  786. strcmp(token->string, "hostnossl") == 0)
  787. {
  788. if (token->string[4] == 's') /* "hostssl" */
  789. {
  790. /* SSL support must be actually active, else complain */
  791. #ifdef USE_SSL
  792. if (EnableSSL)
  793. parsedline->conntype = ctHostSSL;
  794. else
  795. {
  796. ereport(LOG,
  797. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  798. errmsg("hostssl requires SSL to be turned on"),
  799. errhint("Set ssl = on in postgresql.conf."),
  800. errcontext("line %d of configuration file \"%s\"",
  801. line_num, HbaFileName)));
  802. return NULL;
  803. }
  804. #else
  805. ereport(LOG,
  806. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  807. errmsg("hostssl is not supported by this build"),
  808. errhint("Compile with --with-openssl to use SSL connections."),
  809. errcontext("line %d of configuration file \"%s\"",
  810. line_num, HbaFileName)));
  811. return NULL;
  812. #endif
  813. }
  814. #ifdef USE_SSL
  815. else if (token->string[4] == 'n') /* "hostnossl" */
  816. {
  817. parsedline->conntype = ctHostNoSSL;
  818. }
  819. #endif
  820. else
  821. {
  822. /* "host", or "hostnossl" and SSL support not built in */
  823. parsedline->conntype = ctHost;
  824. }
  825. } /* record type */
  826. else
  827. {
  828. ereport(LOG,
  829. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  830. errmsg("invalid connection type \"%s\"",
  831. token->string),
  832. errcontext("line %d of configuration file \"%s\"",
  833. line_num, HbaFileName)));
  834. return NULL;
  835. }
  836. /* Get the databases. */
  837. field = lnext(field);
  838. if (!field)
  839. {
  840. ereport(LOG,
  841. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  842. errmsg("end-of-line before database specification"),
  843. errcontext("line %d of configuration file \"%s\"",
  844. line_num, HbaFileName)));
  845. return NULL;
  846. }
  847. parsedline->databases = NIL;
  848. tokens = lfirst(field);
  849. foreach(tokencell, tokens)
  850. {
  851. parsedline->databases = lappend(parsedline->databases,
  852. copy_hba_token(lfirst(tokencell)));
  853. }
  854. /* Get the roles. */
  855. field = lnext(field);
  856. if (!field)
  857. {
  858. ereport(LOG,
  859. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  860. errmsg("end-of-line before role specification"),
  861. errcontext("line %d of configuration file \"%s\"",
  862. line_num, HbaFileName)));
  863. return NULL;
  864. }
  865. parsedline->roles = NIL;
  866. tokens = lfirst(field);
  867. foreach(tokencell, tokens)
  868. {
  869. parsedline->roles = lappend(parsedline->roles,
  870. copy_hba_token(lfirst(tokencell)));
  871. }
  872. if (parsedline->conntype != ctLocal)
  873. {
  874. /* Read the IP address field. (with or without CIDR netmask) */
  875. field = lnext(field);
  876. if (!field)
  877. {
  878. ereport(LOG,
  879. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  880. errmsg("end-of-line before IP address specification"),
  881. errcontext("line %d of configuration file \"%s\"",
  882. line_num, HbaFileName)));
  883. return NULL;
  884. }
  885. tokens = lfirst(field);
  886. if (tokens->length > 1)
  887. {
  888. ereport(LOG,
  889. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  890. errmsg("multiple values specified for host address"),
  891. errhint("Specify one address range per line."),
  892. errcontext("line %d of configuration file \"%s\"",
  893. line_num, HbaFileName)));
  894. return NULL;
  895. }
  896. token = linitial(tokens);
  897. if (token_is_keyword(token, "all"))
  898. {
  899. parsedline->ip_cmp_method = ipCmpAll;
  900. }
  901. else if (token_is_keyword(token, "samehost"))
  902. {
  903. /* Any IP on this host is allowed to connect */
  904. parsedline->ip_cmp_method = ipCmpSameHost;
  905. }
  906. else if (token_is_keyword(token, "samenet"))
  907. {
  908. /* Any IP on the host's subnets is allowed to connect */
  909. parsedline->ip_cmp_method = ipCmpSameNet;
  910. }
  911. else
  912. {
  913. /* IP and netmask are specified */
  914. parsedline->ip_cmp_method = ipCmpMask;
  915. /* need a modifiable copy of token */
  916. str = pstrdup(token->string);
  917. /* Check if it has a CIDR suffix and if so isolate it */
  918. cidr_slash = strchr(str, '/');
  919. if (cidr_slash)
  920. *cidr_slash = '\0';
  921. /* Get the IP address either way */
  922. hints.ai_flags = AI_NUMERICHOST;
  923. hints.ai_family = PF_UNSPEC;
  924. hints.ai_socktype = 0;
  925. hints.ai_protocol = 0;
  926. hints.ai_addrlen = 0;
  927. hints.ai_canonname = NULL;
  928. hints.ai_addr = NULL;
  929. hints.ai_next = NULL;
  930. ret = pg_getaddrinfo_all(str, NULL, &hints, &gai_result);
  931. if (ret == 0 && gai_result)
  932. memcpy(&parsedline->addr, gai_result->ai_addr,
  933. gai_result->ai_addrlen);
  934. else if (ret == EAI_NONAME)
  935. parsedline->hostname = str;
  936. else
  937. {
  938. ereport(LOG,
  939. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  940. errmsg("invalid IP address \"%s\": %s",
  941. str, gai_strerror(ret)),
  942. errcontext("line %d of configuration file \"%s\"",
  943. line_num, HbaFileName)));
  944. if (gai_result)
  945. pg_freeaddrinfo_all(hints.ai_family, gai_result);
  946. return NULL;
  947. }
  948. pg_freeaddrinfo_all(hints.ai_family, gai_result);
  949. /* Get the netmask */
  950. if (cidr_slash)
  951. {
  952. if (parsedline->hostname)
  953. {
  954. ereport(LOG,
  955. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  956. errmsg("specifying both host name and CIDR mask is invalid: \"%s\"",
  957. token->string),
  958. errcontext("line %d of configuration file \"%s\"",
  959. line_num, HbaFileName)));
  960. return NULL;
  961. }
  962. if (pg_sockaddr_cidr_mask(&parsedline->mask, cidr_slash + 1,
  963. parsedline->addr.ss_family) < 0)
  964. {
  965. ereport(LOG,
  966. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  967. errmsg("invalid CIDR mask in address \"%s\"",
  968. token->string),
  969. errcontext("line %d of configuration file \"%s\"",
  970. line_num, HbaFileName)));
  971. return NULL;
  972. }
  973. pfree(str);
  974. }
  975. else if (!parsedline->hostname)
  976. {
  977. /* Read the mask field. */
  978. pfree(str);
  979. field = lnext(field);
  980. if (!field)
  981. {
  982. ereport(LOG,
  983. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  984. errmsg("end-of-line before netmask specification"),
  985. errhint("Specify an address range in CIDR notation, or provide a separate netmask."),
  986. errcontext("line %d of configuration file \"%s\"",
  987. line_num, HbaFileName)));
  988. return NULL;
  989. }
  990. tokens = lfirst(field);
  991. if (tokens->length > 1)
  992. {
  993. ereport(LOG,
  994. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  995. errmsg("multiple values specified for netmask"),
  996. errcontext("line %d of configuration file \"%s\"",
  997. line_num, HbaFileName)));
  998. return NULL;
  999. }
  1000. token = linitial(tokens);
  1001. ret = pg_getaddrinfo_all(token->string, NULL,
  1002. &hints, &gai_result);
  1003. if (ret || !gai_result)
  1004. {
  1005. ereport(LOG,
  1006. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  1007. errmsg("invalid IP mask \"%s\": %s",
  1008. token->string, gai_strerror(ret)),
  1009. errcontext("line %d of configuration file \"%s\"",
  1010. line_num, HbaFileName)));
  1011. if (gai_result)
  1012. pg_freeaddrinfo_all(hints.ai_family, gai_result);
  1013. return NULL;
  1014. }
  1015. memcpy(&parsedline->mask, gai_result->ai_addr,
  1016. gai_result->ai_addrlen);
  1017. pg_freeaddrinfo_all(hints.ai_family, gai_result);
  1018. if (parsedline->addr.ss_family != parsedline->mask.ss_family)
  1019. {
  1020. ereport(LOG,
  1021. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  1022. errmsg("IP address and mask do not match"),
  1023. errcontext("line %d of configuration file \"%s\"",
  1024. line_num, HbaFileName)));
  1025. return NULL;
  1026. }
  1027. }
  1028. }
  1029. } /* != ctLocal */
  1030. /* Get the authentication method */
  1031. field = lnext(field);
  1032. if (!field)
  1033. {
  1034. ereport(LOG,
  1035. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  1036. errmsg("end-of-line before authentication method"),
  1037. errcontext("line %d of configuration file \"%s\"",
  1038. line_num, HbaFileName)));
  1039. return NULL;
  1040. }
  1041. tokens = lfirst(field);
  1042. if (tokens->length > 1)
  1043. {
  1044. ereport(LOG,
  1045. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  1046. errmsg("multiple values specified for authentication type"),
  1047. errhint("Specify exactly one authentication type per line."),
  1048. errcontext("line %d of configuration file \"%s\"",
  1049. line_num, HbaFileName)));
  1050. return NULL;
  1051. }
  1052. token = linitial(tokens);
  1053. unsupauth = NULL;
  1054. if (strcmp(token->string, "trust") == 0)
  1055. parsedline->auth_method = uaTrust;
  1056. else if (strcmp(token->string, "ident") == 0)
  1057. parsedline->auth_method = uaIdent;
  1058. else if (strcmp(token->string, "peer") == 0)
  1059. parsedline->auth_method = uaPeer;
  1060. else if (strcmp(token->string, "password") == 0)
  1061. parsedline->auth_method = uaPassword;
  1062. else if (strcmp(token->string, "gss") == 0)
  1063. #ifdef ENABLE_GSS
  1064. parsedline->auth_method = uaGSS;
  1065. #else
  1066. unsupauth = "gss";
  1067. #endif
  1068. else if (strcmp(token->string, "sspi") == 0)
  1069. #ifdef ENABLE_SSPI
  1070. parsedline->auth_method = uaSSPI;
  1071. #else
  1072. unsupauth = "sspi";
  1073. #endif
  1074. else if (strcmp(token->string, "reject") == 0)
  1075. parsedline->auth_method = uaReject;
  1076. else if (strcmp(token->string, "md5") == 0)
  1077. {
  1078. if (Db_user_namespace)
  1079. {
  1080. ereport(LOG,
  1081. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  1082. errmsg("MD5 authentication is not supported when \"db_user_namespace\" is enabled"),
  1083. errcontext("line %d of configuration file \"%s\"",
  1084. line_num, HbaFileName)));
  1085. return NULL;
  1086. }
  1087. parsedline->auth_method = uaMD5;
  1088. }
  1089. else if (strcmp(token->string, "pam") == 0)
  1090. #ifdef USE_PAM
  1091. parsedline->auth_method = uaPAM;
  1092. #else
  1093. unsupauth = "pam";
  1094. #endif
  1095. else if (strcmp(token->string, "ldap") == 0)
  1096. #ifdef USE_LDAP
  1097. parsedline->auth_method = uaLDAP;
  1098. #else
  1099. unsupauth = "ldap";
  1100. #endif
  1101. else if (strcmp(token->string, "cert") == 0)
  1102. #ifdef USE_SSL
  1103. parsedline->auth_method = uaCert;
  1104. #else
  1105. unsupauth = "cert";
  1106. #endif
  1107. else if (strcmp(token->string, "radius") == 0)
  1108. parsedline->auth_method = uaRADIUS;
  1109. else
  1110. {
  1111. ereport(LOG,
  1112. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  1113. errmsg("invalid authentication method \"%s\"",
  1114. token->string),
  1115. errcontext("line %d of configuration file \"%s\"",
  1116. line_num, HbaFileName)));
  1117. return NULL;
  1118. }
  1119. if (unsupauth)
  1120. {
  1121. ereport(LOG,
  1122. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  1123. errmsg("invalid authentication method \"%s\": not supported by this build",
  1124. token->string),
  1125. errcontext("line %d of configuration file \"%s\"",
  1126. line_num, HbaFileName)));
  1127. return NULL;
  1128. }
  1129. /*
  1130. * XXX: When using ident on local connections, change it to peer, for
  1131. * backwards compatibility.
  1132. */
  1133. if (parsedline->conntype == ctLocal &&
  1134. parsedline->auth_method == uaIdent)
  1135. parsedline->auth_method = uaPeer;
  1136. /* Invalid authentication combinations */
  1137. if (parsedline->conntype == ctLocal &&
  1138. parsedline->auth_method == uaGSS)
  1139. {
  1140. ereport(LOG,
  1141. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  1142. errmsg("gssapi authentication is not supported on local sockets"),
  1143. errcontext("line %d of configuration file \"%s\"",
  1144. line_num, HbaFileName)));
  1145. return NULL;
  1146. }
  1147. if (parsedline->conntype != ctLocal &&
  1148. parsedline->auth_method == uaPeer)
  1149. {
  1150. ereport(LOG,
  1151. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  1152. errmsg("peer authentication is only supported on local sockets"),
  1153. errcontext("line %d of configuration file \"%s\"",
  1154. line_num, HbaFileName)));
  1155. return NULL;
  1156. }
  1157. /*
  1158. * SSPI authentication can never be enabled on ctLocal connections,
  1159. * because it's only supported on Windows, where ctLocal isn't supported.
  1160. */
  1161. if (parsedline->conntype != ctHostSSL &&
  1162. parsedline->auth_method == uaCert)
  1163. {
  1164. ereport(LOG,
  1165. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  1166. errmsg("cert authentication is only supported on hostssl connections"),
  1167. errcontext("line %d of configuration file \"%s\"",
  1168. line_num, HbaFileName)));
  1169. return NULL;
  1170. }
  1171. /* Parse remaining arguments */
  1172. while ((field = lnext(field)) != NULL)
  1173. {
  1174. tokens = lfirst(field);
  1175. foreach(tokencell, tokens)
  1176. {
  1177. char *val;
  1178. token = lfirst(tokencell);
  1179. str = pstrdup(token->string);
  1180. val = strchr(str, '=');
  1181. if (val == NULL)
  1182. {
  1183. /*
  1184. * Got something that's not a name=value pair.
  1185. */
  1186. ereport(LOG,
  1187. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  1188. errmsg("authentication option not in name=value format: %s", token->string),
  1189. errcontext("line %d of configuration file \"%s\"",
  1190. line_num, HbaFileName)));
  1191. return NULL;
  1192. }
  1193. *val++ = '\0'; /* str now holds "name", val holds "value" */
  1194. if (!parse_hba_auth_opt(str, val, parsedline, line_num))
  1195. /* parse_hba_auth_opt already logged the error message */
  1196. return NULL;
  1197. pfree(str);
  1198. }
  1199. }
  1200. /*
  1201. * Check if the selected authentication method has any mandatory arguments
  1202. * that are not set.
  1203. */
  1204. if (parsedline->auth_method == uaLDAP)
  1205. {
  1206. MANDATORY_AUTH_ARG(parsedline->ldapserver, "ldapserver", "ldap");
  1207. /*
  1208. * LDAP can operate in two modes: either with a direct bind, using
  1209. * ldapprefix and ldapsuffix, or using a search+bind, using
  1210. * ldapbasedn, ldapbinddn, ldapbindpasswd and ldapsearchattribute.
  1211. * Disallow mixing these parameters.
  1212. */
  1213. if (parsedline->ldapprefix || parsedline->ldapsuffix)
  1214. {
  1215. if (parsedline->ldapbasedn ||
  1216. parsedline->ldapbinddn ||
  1217. parsedline->ldapbindpasswd ||
  1218. parsedline->ldapsearchattribute)
  1219. {
  1220. ereport(LOG,
  1221. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  1222. errmsg("cannot use ldapbasedn, ldapbinddn, ldapbindpasswd, ldapsearchattribute, or ldapurl together with ldapprefix"),
  1223. errcontext("line %d of configuration file \"%s\"",
  1224. line_num, HbaFileName)));
  1225. return NULL;
  1226. }
  1227. }
  1228. else if (!parsedline->ldapbasedn)
  1229. {
  1230. ereport(LOG,
  1231. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  1232. errmsg("authentication method \"ldap\" requires argument \"ldapbasedn\", \"ldapprefix\", or \"ldapsuffix\" to be set"),
  1233. errcontext("line %d of configuration file \"%s\"",
  1234. line_num, HbaFileName)));
  1235. return NULL;
  1236. }
  1237. }
  1238. if (parsedline->auth_method == uaRADIUS)
  1239. {
  1240. MANDATORY_AUTH_ARG(parsedline->radiusserver, "radiusserver", "radius");
  1241. MANDATORY_AUTH_ARG(parsedline->radiussecret, "radiussecret", "radius");
  1242. }
  1243. /*
  1244. * Enforce any parameters implied by other settings.
  1245. */
  1246. if (parsedline->auth_method == uaCert)
  1247. {
  1248. parsedline->clientcert = true;
  1249. }
  1250. return parsedline;
  1251. }
  1252. /*
  1253. * Parse one name-value pair as an authentication option into the given
  1254. * HbaLine. Return true if we successfully parse the option, false if we
  1255. * encounter an error.
  1256. */
  1257. static bool
  1258. parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline, int line_num)
  1259. {
  1260. #ifdef USE_LDAP
  1261. hbaline->ldapscope = LDAP_SCOPE_SUBTREE;
  1262. #endif
  1263. if (strcmp(name, "map") == 0)
  1264. {
  1265. if (hbaline->auth_method != uaIdent &&
  1266. hbaline->auth_method != uaPeer &&
  1267. hbaline->auth_method != uaGSS &&
  1268. hbaline->auth_method != uaSSPI &&
  1269. hbaline->auth_method != uaCert)
  1270. INVALID_AUTH_OPTION("map", gettext_noop("ident, peer, gssapi, sspi, and cert"));
  1271. hbaline->usermap = pstrdup(val);
  1272. }
  1273. else if (strcmp(name, "clientcert") == 0)
  1274. {
  1275. /*
  1276. * Since we require ctHostSSL, this really can never happen on
  1277. * non-SSL-enabled builds, so don't bother checking for USE_SSL.
  1278. */
  1279. if (hbaline->conntype != ctHostSSL)
  1280. {
  1281. ereport(LOG,
  1282. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  1283. errmsg("clientcert can only be configured for \"hostssl\" rows"),
  1284. errcontext("line %d of configuration file \"%s\"",
  1285. line_num, HbaFileName)));
  1286. return false;
  1287. }
  1288. if (strcmp(val, "1") == 0)
  1289. {
  1290. if (!secure_loaded_verify_locations())
  1291. {
  1292. ereport(LOG,
  1293. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  1294. errmsg("client certificates can only be checked if a root certificate store is available"),
  1295. errhint("Make sure the configuration parameter \"ssl_ca_file\" is set."),
  1296. errcontext("line %d of configuration file \"%s\"",
  1297. line_num, HbaFileName)));
  1298. return false;
  1299. }
  1300. hbaline->clientcert = true;
  1301. }
  1302. else
  1303. {
  1304. if (hbaline->auth_method == uaCert)
  1305. {
  1306. ereport(LOG,
  1307. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  1308. errmsg("clientcert can not be set to 0 when using \"cert\" authentication"),
  1309. errcontext("line %d of configuration file \"%s\"",
  1310. line_num, HbaFileName)));
  1311. return false;
  1312. }
  1313. hbaline->clientcert = false;
  1314. }
  1315. }
  1316. else if (strcmp(name, "pamservice") == 0)
  1317. {
  1318. REQUIRE_AUTH_OPTION(uaPAM, "pamservice", "pam");
  1319. hbaline->pamservice = pstrdup(val);
  1320. }
  1321. else if (strcmp(name, "ldapurl") == 0)
  1322. {
  1323. #ifdef LDAP_API_FEATURE_X_OPENLDAP
  1324. LDAPURLDesc *urldata;
  1325. int rc;
  1326. #endif
  1327. REQUIRE_AUTH_OPTION(uaLDAP, "ldapurl", "ldap");
  1328. #ifdef LDAP_API_FEATURE_X_OPENLDAP
  1329. rc = ldap_url_parse(val, &urldata);
  1330. if (rc != LDAP_SUCCESS)
  1331. {
  1332. ereport(LOG,
  1333. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  1334. errmsg("could not parse LDAP URL \"%s\": %s", val, ldap_err2string(rc))));
  1335. return false;
  1336. }
  1337. if (strcmp(urldata->lud_scheme, "ldap") != 0)
  1338. {
  1339. ereport(LOG,
  1340. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  1341. errmsg("unsupported LDAP URL scheme: %s", urldata->lud_scheme)));
  1342. ldap_free_urldesc(urldata);
  1343. return false;
  1344. }
  1345. hbaline->ldapserver = pstrdup(urldata->lud_host);
  1346. hbaline->ldapport = urldata->lud_port;
  1347. hbaline->ldapbasedn = pstrdup(urldata->lud_dn);
  1348. if (urldata->lud_attrs)
  1349. hbaline->ldapsearchattribute = pstrdup(urldata->lud_attrs[0]); /* only use first one */
  1350. hbaline->ldapscope = urldata->lud_scope;
  1351. if (urldata->lud_filter)
  1352. {
  1353. ereport(LOG,
  1354. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  1355. errmsg("filters not supported in LDAP URLs")));
  1356. ldap_free_urldesc(urldata);
  1357. return false;
  1358. }
  1359. ldap_free_urldesc(urldata);
  1360. #else /* not OpenLDAP */
  1361. ereport(LOG,
  1362. (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  1363. errmsg("LDAP URLs not supported on this platform")));
  1364. #endif /* not OpenLDAP */
  1365. }
  1366. else if (strcmp(name, "ldaptls") == 0)
  1367. {
  1368. REQUIRE_AUTH_OPTION(uaLDAP, "ldaptls", "ldap");
  1369. if (strcmp(val, "1") == 0)
  1370. hbaline->ldaptls = true;
  1371. else
  1372. hbaline->ldaptls = false;
  1373. }
  1374. else if (strcmp(name, "ldapserver") == 0)
  1375. {
  1376. REQUIRE_AUTH_OPTION(uaLDAP, "ldapserver", "ldap");
  1377. hbaline->ldapserver = pstrdup(val);
  1378. }
  1379. else if (strcmp(name, "ldapport") == 0)
  1380. {
  1381. REQUIRE_AUTH_OPTION(uaLDAP, "ldapport", "ldap");
  1382. hbaline->ldapport = atoi(val);
  1383. if (hbaline->ldapport == 0)
  1384. {
  1385. ereport(LOG,
  1386. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  1387. errmsg("invalid LDAP port number: \"%s\"", val),
  1388. errcontext("line %d of configuration file \"%s\"",
  1389. line_num, HbaFileName)));
  1390. return false;
  1391. }
  1392. }
  1393. else if (strcmp(name, "ldapbinddn") == 0)
  1394. {
  1395. REQUIRE_AUTH_OPTION(uaLDAP, "ldapbinddn", "ldap");
  1396. hbaline->ldapbinddn = pstrdup(val);
  1397. }
  1398. else if (strcmp(name, "ldapbindpasswd") == 0)
  1399. {
  1400. REQUIRE_AUTH_OPTION(uaLDAP, "ldapbindpasswd", "ldap");
  1401. hbaline->ldapbindpasswd = pstrdup(val);
  1402. }
  1403. else if (strcmp(name, "ldapsearchattribute") == 0)
  1404. {
  1405. REQUIRE_AUTH_OPTION(uaLDAP, "ldapsearchattribute", "ldap");
  1406. hbaline->ldapsearchattribute = pstrdup(val);
  1407. }
  1408. else if (strcmp(name, "ldapbasedn") == 0)
  1409. {
  1410. REQUIRE_AUTH_OPTION(uaLDAP, "ldapbasedn", "ldap");
  1411. hbaline->ldapbasedn = pstrdup(val);
  1412. }
  1413. else if (strcmp(name, "ldapprefix") == 0)
  1414. {
  1415. REQUIRE_AUTH_OPTION(uaLDAP, "ldapprefix", "ldap");
  1416. hbaline->ldapprefix = pstrdup(val);
  1417. }
  1418. else if (strcmp(name, "ldapsuffix") == 0)
  1419. {
  1420. REQUIRE_AUTH_OPTION(uaLDAP, "ldapsuffix", "ldap");
  1421. hbaline->ldapsuffix = pstrdup(val);
  1422. }
  1423. else if (strcmp(name, "krb_realm") == 0)
  1424. {
  1425. if (hbaline->auth_method != uaGSS &&
  1426. hbaline->auth_method != uaSSPI)
  1427. INVALID_AUTH_OPTION("krb_realm", gettext_noop("gssapi and sspi"));
  1428. hbaline->krb_realm = pstrdup(val);
  1429. }
  1430. else if (strcmp(name, "include_realm") == 0)
  1431. {
  1432. if (hbaline->auth_method != uaGSS &&
  1433. hbaline->auth_method != uaSSPI)
  1434. INVALID_AUTH_OPTION("include_realm", gettext_noop("gssapi and sspi"));
  1435. if (strcmp(val, "1") == 0)
  1436. hbaline->include_realm = true;
  1437. else
  1438. hbaline->include_realm = false;
  1439. }
  1440. else if (strcmp(name, "radiusserver") == 0)
  1441. {
  1442. struct addrinfo *gai_result;
  1443. struct addrinfo hints;
  1444. int ret;
  1445. REQUIRE_AUTH_OPTION(uaRADIUS, "radiusserver", "radius");
  1446. MemSet(&hints, 0, sizeof(hints));
  1447. hints.ai_socktype = SOCK_DGRAM;
  1448. hints.ai_family = AF_UNSPEC;
  1449. ret = pg_getaddrinfo_all(val, NULL, &hints, &gai_result);
  1450. if (ret || !gai_result)
  1451. {
  1452. ereport(LOG,
  1453. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  1454. errmsg("could not translate RADIUS server name \"%s\" to address: %s",
  1455. val, gai_strerror(ret)),
  1456. errcontext("line %d of configuration file \"%s\"",
  1457. line_num, HbaFileName)));
  1458. if (gai_result)
  1459. pg_freeaddrinfo_all(hints.ai_family, gai_result);
  1460. return false;
  1461. }
  1462. pg_freeaddrinfo_all(hints.ai_family, gai_result);
  1463. hbaline->radiusserver = pstrdup(val);
  1464. }
  1465. else if (strcmp(name, "radiusport") == 0)
  1466. {
  1467. REQUIRE_AUTH_OPTION(uaRADIUS, "radiusport", "radius");
  1468. hbaline->radiusport = atoi(val);
  1469. if (hbaline->radiusport == 0)
  1470. {
  1471. ereport(LOG,
  1472. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  1473. errmsg("invalid RADIUS port number: \"%s\"", val),
  1474. errcontext("line %d of configuration file \"%s\"",
  1475. line_num, HbaFileName)));
  1476. return false;
  1477. }
  1478. }
  1479. else if (strcmp(name, "radiussecret") == 0)
  1480. {
  1481. REQUIRE_AUTH_OPTION(uaRADIUS, "radiussecret", "radius");
  1482. hbaline->radiussecret = pstrdup(val);
  1483. }
  1484. else if (strcmp(name, "radiusidentifier") == 0)
  1485. {
  1486. REQUIRE_AUTH_OPTION(uaRADIUS, "radiusidentifier", "radius");
  1487. hbaline->radiusidentifier = pstrdup(val);
  1488. }
  1489. else
  1490. {
  1491. ereport(LOG,
  1492. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  1493. errmsg("unrecognized authentication option name: \"%s\"",
  1494. name),
  1495. errcontext("line %d of configuration file \"%s\"",
  1496. line_num, HbaFileName)));
  1497. return false;
  1498. }
  1499. return true;
  1500. }
  1501. /*
  1502. * Scan the pre-parsed hba file, looking for a match to the port's connection
  1503. * request.
  1504. */
  1505. static void
  1506. check_hba(hbaPort *port)
  1507. {
  1508. Oid roleid;
  1509. ListCell *line;
  1510. HbaLine *hba;
  1511. /* Get the target role's OID. Note we do not error out for bad role. */
  1512. roleid = get_role_oid(port->user_name, true);
  1513. foreach(line, parsed_hba_lines)
  1514. {
  1515. hba = (HbaLine *) lfirst(line);
  1516. /* Check connection type */
  1517. if (hba->conntype == ctLocal)
  1518. {
  1519. if (!IS_AF_UNIX(port->raddr.addr.ss_family))
  1520. continue;
  1521. }
  1522. else
  1523. {
  1524. if (IS_AF_UNIX(port->raddr.addr.ss_family))
  1525. continue;
  1526. /* Check SSL state */
  1527. #ifdef USE_SSL
  1528. if (port->ssl)
  1529. {
  1530. /* Connection is SSL, match both "host" and "hostssl" */
  1531. if (hba->conntype == ctHostNoSSL)
  1532. continue;
  1533. }
  1534. else
  1535. {
  1536. /* Connection is not SSL, match both "host" and "hostnossl" */
  1537. if (hba->conntype == ctHostSSL)
  1538. continue;
  1539. }
  1540. #else
  1541. /* No SSL support, so reject "hostssl" lines */
  1542. if (hba->conntype == ctHostSSL)
  1543. continue;
  1544. #endif
  1545. /* Check IP address */
  1546. switch (hba->ip_cmp_method)
  1547. {
  1548. case ipCmpMask:
  1549. if (hba->hostname)
  1550. {
  1551. if (!check_hostname(port,
  1552. hba->hostname))
  1553. continue;
  1554. }
  1555. else
  1556. {
  1557. if (!check_ip(&port->raddr,
  1558. (struct sockaddr *) & hba->addr,
  1559. (struct sockaddr *) & hba->mask))
  1560. continue;
  1561. }
  1562. break;
  1563. case ipCmpAll:
  1564. break;
  1565. case ipCmpSameHost:
  1566. case ipCmpSameNet:
  1567. if (!check_same_host_or_net(&port->raddr,
  1568. hba->ip_cmp_method))
  1569. continue;
  1570. break;
  1571. default:
  1572. /* shouldn't get here, but deem it no-match if so */
  1573. continue;
  1574. }
  1575. } /* != ctLocal */
  1576. /* Check database and role */
  1577. if (!check_db(port->database_name, port->user_name, roleid,
  1578. hba->databases))
  1579. continue;
  1580. if (!check_role(port->user_name, roleid, hba->roles))
  1581. continue;
  1582. /* Found a record that matched! */
  1583. port->hba = hba;
  1584. return;
  1585. }
  1586. /* If no matching entry was found, then implicitly reject. */
  1587. hba = palloc0(sizeof(HbaLine));
  1588. hba->auth_method = uaImplicitReject;
  1589. port->hba = hba;
  1590. }
  1591. /*
  1592. * Read the config file and create a List of HbaLine records for the contents.
  1593. *
  1594. * The configuration is read into a temporary list, and if any parse error
  1595. * occurs the old list is kept in place and false is returned. Only if the
  1596. * whole file parses OK is the list replaced, and the function returns true.
  1597. *
  1598. * On a false result, caller will take care of reporting a FATAL error in case
  1599. * this is the initial startup. If it happens on reload, we just keep running
  1600. * with the old data.
  1601. */
  1602. bool
  1603. load_hba(void)
  1604. {
  1605. FILE *file;
  1606. List *hba_lines = NIL;
  1607. List *hba_line_nums = NIL;
  1608. List *hba_raw_lines = NIL;
  1609. ListCell *line,
  1610. *line_num,
  1611. *raw_line;
  1612. List *new_parsed_lines = NIL;
  1613. bool ok = true;
  1614. MemoryContext linecxt;
  1615. MemoryContext oldcxt;
  1616. MemoryContext hbacxt;
  1617. file = AllocateFile(HbaFileName, "r");
  1618. if (file == NULL)
  1619. {
  1620. ereport(LOG,
  1621. (errcode_for_file_access(),
  1622. errmsg("could not open configuration file \"%s\": %m",
  1623. HbaFileName)));
  1624. return false;
  1625. }
  1626. linecxt = tokenize_file(HbaFileName, file, &hba_lines, &hba_line_nums, &hba_raw_lines);
  1627. FreeFile(file);
  1628. /* Now parse all the lines */
  1629. hbacxt = AllocSetContextCreate(TopMemoryContext,
  1630. "hba parser context",
  1631. ALLOCSET_DEFAULT_MINSIZE,
  1632. ALLOCSET_DEFAULT_MINSIZE,
  1633. ALLOCSET_DEFAULT_MAXSIZE);
  1634. oldcxt = MemoryContextSwitchTo(hbacxt);
  1635. forthree(line, hba_lines, line_num, hba_line_nums, raw_line, hba_raw_lines)
  1636. {
  1637. HbaLine *newline;
  1638. if ((newline = parse_hba_line(lfirst(line), lfirst_int(line_num), lfirst(raw_line))) == NULL)
  1639. {
  1640. /*
  1641. * Parse error in the file, so indicate there's a problem. NB: a
  1642. * problem in a line will free the memory for all previous lines
  1643. * as well!
  1644. */
  1645. MemoryContextReset(hbacxt);
  1646. new_parsed_lines = NIL;
  1647. ok = false;
  1648. /*
  1649. * Keep parsing the rest of the file so we can report errors on
  1650. * more than the first row. Error has already been reported in the
  1651. * parsing function, so no need to log it here.
  1652. */
  1653. continue;
  1654. }
  1655. new_parsed_lines = lappend(new_parsed_lines, newline);
  1656. }
  1657. /*
  1658. * A valid HBA file must have at least one entry; else there's no way to
  1659. * connect to the postmaster. But only complain about this if we didn't
  1660. * already have parsing errors.
  1661. */
  1662. if (ok && new_parsed_lines == NIL)
  1663. {
  1664. ereport(LOG,
  1665. (errcode(ERRCODE_CONFIG_FILE_ERROR),
  1666. errmsg("configuration file \"%s\" contains no entries",
  1667. HbaFileName)));
  1668. ok = false;
  1669. }
  1670. /* Free tokenizer memory */
  1671. MemoryContextDelete(linecxt);
  1672. MemoryContextSwitchTo(oldcxt);
  1673. if (!ok)
  1674. {
  1675. /* File contained one or more errors, so bail out */
  1676. MemoryContextDelete(hbacxt);
  1677. return false;
  1678. }
  1679. /* Loaded new file successfully, replace the one we use */
  1680. if (parsed_hba_context != NULL)
  1681. MemoryContextDelete(parsed_hba_context);
  1682. parsed_hba_context = hbacxt;
  1683. parsed_hba_lines = new_parsed_lines;
  1684. return true;
  1685. }
  1686. /*
  1687. * Parse one tokenised line from the ident config file and store the result in
  1688. * an IdentLine structure, or NULL if parsing fails.
  1689. *
  1690. * The tokenised line is a nested List of fields and tokens.
  1691. *
  1692. * If ident_user is a regular expression (ie. begins with a slash), it is
  1693. * compiled and stored in IdentLine structure.
  1694. *
  1695. * Note: this function leaks memory when an error occurs. Caller is expected
  1696. * to have set a memory context that will be reset if this function returns
  1697. * NULL.
  1698. */
  1699. static IdentLine *
  1700. pars

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