hba.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:28k
源码类别:

数据库系统

开发平台:

Unix_Linux

  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 possibly using ident).
  7.  *
  8.  * $Id: hba.c,v 1.43 1999/05/25 16:08:59 momjian Exp $
  9.  *
  10.  *-------------------------------------------------------------------------
  11.  */
  12. #include <stdio.h>
  13. #include <string.h>
  14. #include <errno.h>
  15. #include <pwd.h>
  16. #include <sys/types.h>
  17. #include <fcntl.h>
  18. #include <sys/socket.h>
  19. #include <netinet/in.h>
  20. #include <arpa/inet.h>
  21. #include <unistd.h>
  22. #include <postgres.h>
  23. #include <miscadmin.h>
  24. #include <libpq/libpq.h>
  25. #include <libpq/pqcomm.h>
  26. #include <libpq/hba.h>
  27. #include <port/inet_aton.h> /* For inet_aton() */
  28. #include <storage/fd.h>
  29. /* Some standard C libraries, including GNU, have an isblank() function.
  30.    Others, including Solaris, do not.  So we have our own.
  31. */
  32. static bool
  33. isblank(const char c)
  34. {
  35. return c == ' ' || c == 9 /* tab */ ;
  36. }
  37. static void
  38. next_token(FILE *fp, char *buf, const int bufsz)
  39. {
  40. /*--------------------------------------------------------------------------
  41.   Grab one token out of fp.  Tokens are strings of non-blank
  42.   characters bounded by blank characters, beginning of line, and end
  43.   of line. Blank means space or tab.  Return the token as *buf.
  44.   Leave file positioned to character immediately after the token or
  45.   EOF, whichever comes first.  If no more tokens on line, return null
  46.   string as *buf and position file to beginning of next line or EOF,
  47.   whichever comes first.
  48. --------------------------------------------------------------------------*/
  49. int c;
  50. char    *eb = buf + (bufsz - 1);
  51. /* Move over inital token-delimiting blanks */
  52. while (isblank(c = getc(fp)));
  53. if (c != 'n')
  54. {
  55. /*
  56.  * build a token in buf of next characters up to EOF, eol, or
  57.  * blank.
  58.  */
  59. while (c != EOF && c != 'n' && !isblank(c))
  60. {
  61. if (buf < eb)
  62. *buf++ = c;
  63. c = getc(fp);
  64. /*
  65.  * Put back the char right after the token (putting back EOF
  66.  * is ok)
  67.  */
  68. }
  69. ungetc(c, fp);
  70. }
  71. *buf = '';
  72. }
  73. static void
  74. read_through_eol(FILE *file)
  75. {
  76. int c;
  77. do
  78. c = getc(file);
  79. while (c != 'n' && c != EOF);
  80. }
  81. static void
  82. read_hba_entry2(FILE *file, UserAuth *userauth_p, char *auth_arg,
  83. bool *error_p)
  84. {
  85. /*--------------------------------------------------------------------------
  86.   Read from file FILE the rest of a host record, after the mask field,
  87.   and return the interpretation of it as *userauth_p, auth_arg, and
  88.   *error_p.
  89. ---------------------------------------------------------------------------*/
  90. char buf[MAX_TOKEN];
  91. /* Get authentication type token. */
  92. next_token(file, buf, sizeof(buf));
  93. if (strcmp(buf, "trust") == 0)
  94. *userauth_p = uaTrust;
  95. else if (strcmp(buf, "ident") == 0)
  96. *userauth_p = uaIdent;
  97. else if (strcmp(buf, "password") == 0)
  98. *userauth_p = uaPassword;
  99. else if (strcmp(buf, "krb4") == 0)
  100. *userauth_p = uaKrb4;
  101. else if (strcmp(buf, "krb5") == 0)
  102. *userauth_p = uaKrb5;
  103. else if (strcmp(buf, "reject") == 0)
  104. *userauth_p = uaReject;
  105. else if (strcmp(buf, "crypt") == 0)
  106. *userauth_p = uaCrypt;
  107. else
  108. {
  109. *error_p = true;
  110. if (buf[0] != '')
  111. read_through_eol(file);
  112. }
  113. if (!*error_p)
  114. {
  115. /* Get the authentication argument token, if any */
  116. next_token(file, buf, sizeof(buf));
  117. if (buf[0] == '')
  118. auth_arg[0] = '';
  119. else
  120. {
  121. StrNCpy(auth_arg, buf, MAX_AUTH_ARG - 1);
  122. next_token(file, buf, sizeof(buf));
  123. if (buf[0] != '')
  124. {
  125. *error_p = true;
  126. read_through_eol(file);
  127. }
  128. }
  129. }
  130. }
  131. static void
  132. process_hba_record(FILE *file, SockAddr *raddr, const char *user,
  133.    const char *database, bool *matches_p, bool *error_p,
  134.    UserAuth *userauth_p, char *auth_arg)
  135. {
  136. /*---------------------------------------------------------------------------
  137.   Process the non-comment record in the config file that is next on the file.
  138.   See if it applies to a connection to a host with IP address "*raddr"
  139.   to a database named "*database". If so, return *matches_p true
  140.   and *userauth_p and *auth_arg as the values from the entry.
  141.   If not, leave *matches_p as it was.  If the record has a syntax error,
  142.   return *error_p true, after issuing a message to stderr. If no error,
  143.   leave *error_p as it was.
  144. ---------------------------------------------------------------------------*/
  145. char db[MAX_TOKEN],
  146. buf[MAX_TOKEN];
  147. /* Read the record type field. */
  148. next_token(file, buf, sizeof(buf));
  149. if (buf[0] == '')
  150. return;
  151. /* Check the record type. */
  152. if (strcmp(buf, "local") == 0)
  153. {
  154. /* Get the database. */
  155. next_token(file, db, sizeof(db));
  156. if (db[0] == '')
  157. goto syntax;
  158. /* Read the rest of the line. */
  159. read_hba_entry2(file, userauth_p, auth_arg, error_p);
  160. /*
  161.  * For now, disallow methods that need AF_INET sockets to work.
  162.  */
  163. if (!*error_p &&
  164. (*userauth_p == uaIdent ||
  165.  *userauth_p == uaKrb4 ||
  166.  *userauth_p == uaKrb5))
  167. *error_p = true;
  168. if (*error_p)
  169. goto syntax;
  170. /*
  171.  * If this record isn't for our database, or this is the wrong
  172.  * sort of connection, ignore it.
  173.  */
  174. if ((strcmp(db, database) != 0 && strcmp(db, "all") != 0 &&
  175.  (strcmp(db, "sameuser") != 0 || strcmp(database, user) != 0)) ||
  176. raddr->sa.sa_family != AF_UNIX)
  177. return;
  178. }
  179. else if (strcmp(buf, "host") == 0)
  180. {
  181. struct in_addr file_ip_addr,
  182. mask;
  183. /* Get the database. */
  184. next_token(file, db, sizeof(db));
  185. if (db[0] == '')
  186. goto syntax;
  187. /* Read the IP address field. */
  188. next_token(file, buf, sizeof(buf));
  189. if (buf[0] == '')
  190. goto syntax;
  191. /* Remember the IP address field and go get mask field. */
  192. if (!inet_aton(buf, &file_ip_addr))
  193. {
  194. read_through_eol(file);
  195. goto syntax;
  196. }
  197. /* Read the mask field. */
  198. next_token(file, buf, sizeof(buf));
  199. if (buf[0] == '')
  200. goto syntax;
  201. if (!inet_aton(buf, &mask))
  202. {
  203. read_through_eol(file);
  204. goto syntax;
  205. }
  206. /*
  207.  * This is the record we're looking for.  Read the rest of the
  208.  * info from it.
  209.  */
  210. read_hba_entry2(file, userauth_p, auth_arg, error_p);
  211. if (*error_p)
  212. goto syntax;
  213. /*
  214.  * If this record isn't for our database, or this is the wrong
  215.  * sort of connection, ignore it.
  216.  */
  217. if ((strcmp(db, database) != 0 && strcmp(db, "all") != 0 &&
  218.  (strcmp(db, "sameuser") != 0 || strcmp(database, user) != 0)) ||
  219. raddr->sa.sa_family != AF_INET ||
  220. ((file_ip_addr.s_addr ^ raddr->in.sin_addr.s_addr) & mask.s_addr) != 0x0000)
  221. return;
  222. }
  223. else
  224. {
  225. read_through_eol(file);
  226. goto syntax;
  227. }
  228. *matches_p = true;
  229. return;
  230. syntax:
  231. snprintf(PQerrormsg, ERROR_MSG_LENGTH,
  232.  "process_hba_record: invalid syntax in pg_hba.conf filen");
  233. fputs(PQerrormsg, stderr);
  234. pqdebug("%s", PQerrormsg);
  235. *error_p = true;
  236. }
  237. static void
  238. process_open_config_file(FILE *file, SockAddr *raddr, const char *user,
  239.  const char *database, bool *hba_ok_p,
  240.  UserAuth *userauth_p, char *auth_arg)
  241. {
  242. /*---------------------------------------------------------------------------
  243.   This function does the same thing as find_hba_entry, only with
  244.   the config file already open on stream descriptor "file".
  245. ----------------------------------------------------------------------------*/
  246. bool found_entry = false; /* found an applicable entry? */
  247. bool error = false; /* found an erroneous entry? */
  248. bool eof = false; /* end of hba file */
  249. while (!eof && !found_entry && !error)
  250. {
  251. /* Process a line from the config file */
  252. int c = getc(file);
  253. if (c == EOF)
  254. eof = true;
  255. else
  256. {
  257. ungetc(c, file);
  258. if (c == '#')
  259. read_through_eol(file);
  260. else
  261. process_hba_record(file, raddr, user, database,
  262.  &found_entry, &error, userauth_p, auth_arg);
  263. }
  264. }
  265. if (!error)
  266. {
  267. /* If no matching entry was found, synthesize 'reject' entry. */
  268. if (!found_entry)
  269. *userauth_p = uaReject;
  270. *hba_ok_p = true;
  271. }
  272. }
  273. static void
  274. find_hba_entry(SockAddr *raddr, const char *user, const char *database,
  275.    bool *hba_ok_p, UserAuth *userauth_p, char *auth_arg)
  276. {
  277. /*
  278.  * Read the config file and find an entry that allows connection from
  279.  * host "raddr", user "user", to database "database".  If found,
  280.  * return *hba_ok_p = true and *userauth_p and *auth_arg representing
  281.  * the contents of that entry. If there is no matching entry, we
  282.  * set *hba_ok_p = true, *userauth_p = uaReject.
  283.  *
  284.  * If the config file is unreadable or contains invalid syntax, we
  285.  * issue a diagnostic message to stderr (ie, the postmaster log file)
  286.  * and return without changing *hba_ok_p.
  287.  *
  288.  * If we find a file by the old name of the config file (pg_hba), we issue
  289.  * an error message because it probably needs to be converted. He didn't
  290.  * follow directions and just installed his old hba file in the new database
  291.  * system.
  292.  */
  293. int fd,
  294. bufsize;
  295. FILE    *file; /* The config file we have to read */
  296. char    *old_conf_file;
  297. /* The name of old config file that better not exist. */
  298. /* Fail if config file by old name exists. */
  299. /* put together the full pathname to the old config file */
  300. bufsize = (strlen(DataDir) + strlen(OLD_CONF_FILE) + 2) * sizeof(char);
  301. old_conf_file = (char *) palloc(bufsize);
  302. snprintf(old_conf_file, bufsize, "%s/%s", DataDir, OLD_CONF_FILE);
  303. #ifndef __CYGWIN32__
  304. if ((fd = open(old_conf_file, O_RDONLY, 0)) != -1)
  305. #else
  306. if ((fd = open(old_conf_file, O_RDONLY | O_BINARY, 0)) != -1)
  307. #endif
  308. {
  309. /* Old config file exists. Tell this guy he needs to upgrade. */
  310. close(fd);
  311. snprintf(PQerrormsg, ERROR_MSG_LENGTH,
  312.   "A file exists by the name used for host-based authentication "
  313.    "in prior releases of Postgres (%s).  The name and format of "
  314.    "the configuration file have changed, so this file should be "
  315.  "converted.n",
  316.  old_conf_file);
  317. fputs(PQerrormsg, stderr);
  318. pqdebug("%s", PQerrormsg);
  319. }
  320. else
  321. {
  322. char    *conf_file; /* The name of the config file we have to
  323.  * read */
  324. /* put together the full pathname to the config file */
  325. bufsize = (strlen(DataDir) + strlen(CONF_FILE) + 2) * sizeof(char);
  326. conf_file = (char *) palloc(bufsize);
  327. snprintf(conf_file, bufsize, "%s/%s", DataDir, CONF_FILE);
  328. file = AllocateFile(conf_file, "r");
  329. if (file == NULL)
  330. {
  331. /* The open of the config file failed. */
  332. snprintf(PQerrormsg, ERROR_MSG_LENGTH,
  333.  "find_hba_entry: Host-based authentication config file "
  334. "does not exist or permissions are not setup correctly! "
  335.  "Unable to open file "%s".n",
  336.  conf_file);
  337. fputs(PQerrormsg, stderr);
  338. pqdebug("%s", PQerrormsg);
  339. }
  340. else
  341. {
  342. process_open_config_file(file, raddr, user, database, hba_ok_p,
  343.  userauth_p, auth_arg);
  344. FreeFile(file);
  345. }
  346. pfree(conf_file);
  347. }
  348. pfree(old_conf_file);
  349. }
  350. static void
  351. interpret_ident_response(char *ident_response,
  352.  bool *error_p, char *ident_username)
  353. {
  354. /*----------------------------------------------------------------------------
  355.   Parse the string "*ident_response" as a response from a query to an Ident
  356.   server.  If it's a normal response indicating a username, return
  357.   *error_p == false and the username as *ident_username.  If it's anything
  358.   else, return *error_p == true and *ident_username undefined.
  359. ----------------------------------------------------------------------------*/
  360. char    *cursor; /* Cursor into *ident_response */
  361. cursor = &ident_response[0];
  362. /*
  363.  * Ident's response, in the telnet tradition, should end in crlf
  364.  * (rn).
  365.  */
  366. if (strlen(ident_response) < 2)
  367. *error_p = true;
  368. else if (ident_response[strlen(ident_response) - 2] != 'r')
  369. *error_p = true;
  370. else
  371. {
  372. while (*cursor != ':' && *cursor != 'r')
  373. cursor++; /* skip port field */
  374. if (*cursor != ':')
  375. *error_p = true;
  376. else
  377. {
  378. /* We're positioned to colon before response type field */
  379. char response_type[80];
  380. int i; /* Index into *response_type */
  381. cursor++; /* Go over colon */
  382. while (isblank(*cursor))
  383. cursor++; /* skip blanks */
  384. i = 0;
  385. while (*cursor != ':' && *cursor != 'r' && !isblank(*cursor)
  386.    && i < sizeof(response_type) - 1)
  387. response_type[i++] = *cursor++;
  388. response_type[i] = '';
  389. while (isblank(*cursor))
  390. cursor++; /* skip blanks */
  391. if (strcmp(response_type, "USERID") != 0)
  392. *error_p = true;
  393. else
  394. {
  395. /*
  396.  * It's a USERID response.  Good.  "cursor" should be
  397.  * pointing to the colon that precedes the operating
  398.  * system type.
  399.  */
  400. if (*cursor != ':')
  401. *error_p = true;
  402. else
  403. {
  404. cursor++; /* Go over colon */
  405. /* Skip over operating system field. */
  406. while (*cursor != ':' && *cursor != 'r')
  407. cursor++;
  408. if (*cursor != ':')
  409. *error_p = true;
  410. else
  411. {
  412. int i; /* Index into *ident_username */
  413. cursor++; /* Go over colon */
  414. while (isblank(*cursor))
  415. cursor++; /* skip blanks */
  416. /* Rest of line is username.  Copy it over. */
  417. i = 0;
  418. while (*cursor != 'r' && i < IDENT_USERNAME_MAX)
  419. ident_username[i++] = *cursor++;
  420. ident_username[i] = '';
  421. *error_p = false;
  422. }
  423. }
  424. }
  425. }
  426. }
  427. }
  428. static void
  429. ident(const struct in_addr remote_ip_addr, const struct in_addr local_ip_addr,
  430.   const ushort remote_port, const ushort local_port,
  431.   bool *ident_failed, char *ident_username)
  432. {
  433. /*--------------------------------------------------------------------------
  434.   Talk to the ident server on host "remote_ip_addr" and find out who
  435.   owns the tcp connection from his port "remote_port" to port
  436.   "local_port_addr" on host "local_ip_addr".  Return the username the
  437.   ident server gives as "*ident_username".
  438.   IP addresses and port numbers are in network byte order.
  439.   But iff we're unable to get the information from ident, return
  440.   *ident_failed == true (and *ident_username undefined).
  441. ----------------------------------------------------------------------------*/
  442. int sock_fd, /* File descriptor for socket on which we
  443.  * talk to Ident */
  444. rc; /* Return code from a locally called
  445.  * function */
  446. sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
  447. if (sock_fd == -1)
  448. {
  449. snprintf(PQerrormsg, ERROR_MSG_LENGTH,
  450.  "Failed to create socket on which to talk to Ident server. "
  451.  "socket() returned errno = %s (%d)n",
  452.  strerror(errno), errno);
  453. fputs(PQerrormsg, stderr);
  454. pqdebug("%s", PQerrormsg);
  455. }
  456. else
  457. {
  458. struct sockaddr_in ident_server;
  459. struct sockaddr_in la;
  460. /*
  461.  * Socket address of Ident server on the system from which client
  462.  * is attempting to connect to us.
  463.  */
  464. ident_server.sin_family = AF_INET;
  465. ident_server.sin_port = htons(IDENT_PORT);
  466. ident_server.sin_addr = remote_ip_addr;
  467. /*
  468.  * Bind to the address which the client originally contacted,
  469.  * otherwise the ident server won't be able to match up the right
  470.  * connection. This is necessary if the PostgreSQL server is
  471.  * running on an IP alias.
  472.  */
  473. memset(&la, 0, sizeof(la));
  474. la.sin_family = AF_INET;
  475. la.sin_addr = local_ip_addr;
  476. rc = bind(sock_fd, (struct sockaddr *) & la, sizeof(la));
  477. if (rc == 0)
  478. {
  479. rc = connect(sock_fd,
  480.    (struct sockaddr *) & ident_server, sizeof(ident_server));
  481. }
  482. if (rc != 0)
  483. {
  484. snprintf(PQerrormsg, ERROR_MSG_LENGTH,
  485. "Unable to connect to Ident server on the host which is "
  486.  "trying to connect to Postgres "
  487.  "(IP address %s, Port %d). "
  488.  "errno = %s (%d)n",
  489.  inet_ntoa(remote_ip_addr), IDENT_PORT, strerror(errno), errno);
  490. fputs(PQerrormsg, stderr);
  491. pqdebug("%s", PQerrormsg);
  492. *ident_failed = true;
  493. }
  494. else
  495. {
  496. char ident_query[80];
  497. /* The query we send to the Ident server */
  498. snprintf(ident_query, 80, "%d,%dn",
  499.  ntohs(remote_port), ntohs(local_port));
  500. rc = send(sock_fd, ident_query, strlen(ident_query), 0);
  501. if (rc < 0)
  502. {
  503. snprintf(PQerrormsg, ERROR_MSG_LENGTH,
  504.  "Unable to send query to Ident server on the host which is "
  505.   "trying to connect to Postgres (Host %s, Port %d),"
  506.  "even though we successfully connected to it.  "
  507.  "errno = %s (%d)n",
  508.  inet_ntoa(remote_ip_addr), IDENT_PORT, strerror(errno), errno);
  509. fputs(PQerrormsg, stderr);
  510. pqdebug("%s", PQerrormsg);
  511. *ident_failed = true;
  512. }
  513. else
  514. {
  515. char ident_response[80 + IDENT_USERNAME_MAX];
  516. rc = recv(sock_fd, ident_response, sizeof(ident_response) - 1, 0);
  517. if (rc < 0)
  518. {
  519. snprintf(PQerrormsg, ERROR_MSG_LENGTH,
  520.   "Unable to receive response from Ident server "
  521.  "on the host which is "
  522.   "trying to connect to Postgres (Host %s, Port %d),"
  523. "even though we successfully sent our query to it.  "
  524.  "errno = %s (%d)n",
  525.  inet_ntoa(remote_ip_addr), IDENT_PORT,
  526.  strerror(errno), errno);
  527. fputs(PQerrormsg, stderr);
  528. pqdebug("%s", PQerrormsg);
  529. *ident_failed = true;
  530. }
  531. else
  532. {
  533. bool error; /* response from Ident is garbage. */
  534. ident_response[rc] = '';
  535. interpret_ident_response(ident_response, &error, ident_username);
  536. *ident_failed = error;
  537. }
  538. }
  539. close(sock_fd);
  540. }
  541. }
  542. }
  543. static void
  544. parse_map_record(FILE *file,
  545.  char *file_map, char *file_pguser, char *file_iuser)
  546. {
  547. /*---------------------------------------------------------------------------
  548.   Take the noncomment line which is next on file "file" and interpret
  549.   it as a line in a usermap file.  Specifically, return the first
  550.   3 tokens as file_map, file_iuser, and file_pguser, respectively. If
  551.   there are fewer than 3 tokens, return null strings for the missing
  552.   ones.
  553. ---------------------------------------------------------------------------*/
  554. char buf[MAX_TOKEN];
  555. /* A token read from the file */
  556. /* Set defaults in case fields not in file */
  557. file_map[0] = '';
  558. file_pguser[0] = '';
  559. file_iuser[0] = '';
  560. next_token(file, buf, sizeof(buf));
  561. if (buf[0] != '')
  562. {
  563. strcpy(file_map, buf);
  564. next_token(file, buf, sizeof(buf));
  565. if (buf[0] != '')
  566. {
  567. strcpy(file_iuser, buf);
  568. next_token(file, buf, sizeof(buf));
  569. if (buf[0] != '')
  570. {
  571. strcpy(file_pguser, buf);
  572. read_through_eol(file);
  573. return;
  574. }
  575. }
  576. snprintf(PQerrormsg, ERROR_MSG_LENGTH,
  577.  "Incomplete line in pg_ident: %s", file_map);
  578. fputs(PQerrormsg, stderr);
  579. pqdebug("%s", PQerrormsg);
  580. }
  581. }
  582. static void
  583. verify_against_open_usermap(FILE *file,
  584. const char *pguser,
  585. const char *ident_username,
  586. const char *usermap_name,
  587. bool *checks_out_p)
  588. {
  589. /*--------------------------------------------------------------------------
  590.   This function does the same thing as verify_against_usermap,
  591.   only with the config file already open on stream descriptor "file".
  592. ---------------------------------------------------------------------------*/
  593. bool match; /* We found a matching entry in the map
  594.  * file */
  595. bool eof; /* We've reached the end of the file we're
  596.  * reading */
  597. match = false; /* initial value */
  598. eof = false; /* initial value */
  599. while (!eof && !match)
  600. {
  601. /* Process a line from the map file */
  602. int c; /* a character read from the file */
  603. c = getc(file);
  604. ungetc(c, file);
  605. if (c == EOF)
  606. eof = true;
  607. else
  608. {
  609. if (c == '#')
  610. read_through_eol(file);
  611. else
  612. {
  613. /* The following are fields read from a record of the file */
  614. char file_map[MAX_TOKEN + 1];
  615. char file_pguser[MAX_TOKEN + 1];
  616. char file_iuser[MAX_TOKEN + 1];
  617. parse_map_record(file, file_map, file_pguser, file_iuser);
  618. if (strcmp(file_map, usermap_name) == 0 &&
  619. strcmp(file_pguser, pguser) == 0 &&
  620. strcmp(file_iuser, ident_username) == 0)
  621. match = true;
  622. }
  623. }
  624. }
  625. *checks_out_p = match;
  626. }
  627. static void
  628. verify_against_usermap(const char *pguser,
  629.    const char *ident_username,
  630.    const char *usermap_name,
  631.    bool *checks_out_p)
  632. {
  633. /*--------------------------------------------------------------------------
  634.   See if the user with ident username "ident_username" is allowed to act
  635.   as Postgres user "pguser" according to usermap "usermap_name".   Look
  636.   it up in the usermap file.
  637.   Special case: For usermap "sameuser", don't look in the usermap
  638.   file.  That's an implied map where "pguser" must be identical to
  639.   "ident_username" in order to be authorized.
  640.   Iff authorized, return *checks_out_p == true.
  641. --------------------------------------------------------------------------*/
  642. if (usermap_name[0] == '')
  643. {
  644. *checks_out_p = false;
  645. snprintf(PQerrormsg, ERROR_MSG_LENGTH,
  646.    "verify_against_usermap: hba configuration file does not "
  647.    "have the usermap field filled in in the entry that pertains "
  648.   "to this connection.  That field is essential for Ident-based "
  649.  "authentication.n");
  650. fputs(PQerrormsg, stderr);
  651. pqdebug("%s", PQerrormsg);
  652. }
  653. else if (strcmp(usermap_name, "sameuser") == 0)
  654. {
  655. if (strcmp(ident_username, pguser) == 0)
  656. *checks_out_p = true;
  657. else
  658. *checks_out_p = false;
  659. }
  660. else
  661. {
  662. FILE    *file; /* The map file we have to read */
  663. char    *map_file; /* The name of the map file we have to
  664.  * read */
  665. int bufsize;
  666. /* put together the full pathname to the map file */
  667. bufsize = (strlen(DataDir) + strlen(USERMAP_FILE) + 2) * sizeof(char);
  668. map_file = (char *) palloc(bufsize);
  669. snprintf(map_file, bufsize, "%s/%s", DataDir, USERMAP_FILE);
  670. #ifndef __CYGWIN32__
  671. file = AllocateFile(map_file, "r");
  672. #else
  673. file = AllocateFile(map_file, "rb");
  674. #endif
  675. if (file == NULL)
  676. {
  677. /* The open of the map file failed.  */
  678. *checks_out_p = false;
  679. snprintf(PQerrormsg, ERROR_MSG_LENGTH,
  680.   "verify_against_usermap: usermap file for Ident-based "
  681.  "authentication "
  682. "does not exist or permissions are not setup correctly! "
  683.  "Unable to open file "%s".n",
  684.  map_file);
  685. fputs(PQerrormsg, stderr);
  686. pqdebug("%s", PQerrormsg);
  687. }
  688. else
  689. {
  690. verify_against_open_usermap(file,
  691. pguser, ident_username, usermap_name,
  692. checks_out_p);
  693. FreeFile(file);
  694. }
  695. pfree(map_file);
  696. }
  697. }
  698. int
  699. authident(struct sockaddr_in * raddr, struct sockaddr_in * laddr,
  700.   const char *postgres_username,
  701.   const char *auth_arg)
  702. {
  703. /*---------------------------------------------------------------------------
  704.   Talk to the ident server on the remote host and find out who owns the
  705.   connection described by "port".  Then look in the usermap file under
  706.   the usermap *auth_arg and see if that user is equivalent to
  707.   Postgres user *user.
  708.   Return STATUS_OK if yes.
  709. ---------------------------------------------------------------------------*/
  710. bool checks_out;
  711. bool ident_failed;
  712. /* We were unable to get ident to give us a username */
  713. char ident_username[IDENT_USERNAME_MAX + 1];
  714. /* The username returned by ident */
  715. ident(raddr->sin_addr, laddr->sin_addr,
  716.   raddr->sin_port, laddr->sin_port,
  717.   &ident_failed, ident_username);
  718. if (ident_failed)
  719. return STATUS_ERROR;
  720. verify_against_usermap(postgres_username, ident_username, auth_arg,
  721.    &checks_out);
  722. return checks_out ? STATUS_OK : STATUS_ERROR;
  723. }
  724. #ifdef CYR_RECODE
  725. #define CHARSET_FILE "charset.conf"
  726. #define MAX_CHARSETS   10
  727. #define KEY_HOST    1
  728. #define KEY_BASE    2
  729. #define KEY_TABLE    3
  730. struct CharsetItem
  731. {
  732. char Orig[MAX_TOKEN];
  733. char Dest[MAX_TOKEN];
  734. char Table[MAX_TOKEN];
  735. };
  736. int
  737. InRange(char *buf, int host)
  738. {
  739. int valid,
  740. i,
  741. FromAddr,
  742. ToAddr,
  743. tmp;
  744. struct in_addr file_ip_addr;
  745. char    *p;
  746. unsigned int one = 0x80000000,
  747. NetMask = 0;
  748. unsigned char mask;
  749. p = strchr(buf, '/');
  750. if (p)
  751. {
  752. *p++ = '';
  753. valid = inet_aton(buf, &file_ip_addr);
  754. if (valid)
  755. {
  756. mask = strtoul(p, 0, 0);
  757. FromAddr = ntohl(file_ip_addr.s_addr);
  758. ToAddr = ntohl(file_ip_addr.s_addr);
  759. for (i = 0; i < mask; i++)
  760. {
  761. NetMask |= one;
  762. one >>= 1;
  763. }
  764. FromAddr &= NetMask;
  765. ToAddr = ToAddr | ~NetMask;
  766. tmp = ntohl(host);
  767. return ((unsigned) tmp >= (unsigned) FromAddr &&
  768. (unsigned) tmp <= (unsigned) ToAddr);
  769. }
  770. }
  771. else
  772. {
  773. p = strchr(buf, '-');
  774. if (p)
  775. {
  776. *p++ = '';
  777. valid = inet_aton(buf, &file_ip_addr);
  778. if (valid)
  779. {
  780. FromAddr = ntohl(file_ip_addr.s_addr);
  781. valid = inet_aton(p, &file_ip_addr);
  782. if (valid)
  783. {
  784. ToAddr = ntohl(file_ip_addr.s_addr);
  785. tmp = ntohl(host);
  786. return ((unsigned) tmp >= (unsigned) FromAddr &&
  787. (unsigned) tmp <= (unsigned) ToAddr);
  788. }
  789. }
  790. }
  791. else
  792. {
  793. valid = inet_aton(buf, &file_ip_addr);
  794. if (valid)
  795. {
  796. FromAddr = file_ip_addr.s_addr;
  797. return (unsigned) FromAddr == (unsigned) host;
  798. }
  799. }
  800. }
  801. return false;
  802. }
  803. void
  804. GetCharSetByHost(char *TableName, int host, const char *DataDir)
  805. {
  806. FILE    *file;
  807. char buf[MAX_TOKEN],
  808. BaseCharset[MAX_TOKEN],
  809. OrigCharset[MAX_TOKEN],
  810. DestCharset[MAX_TOKEN],
  811. HostCharset[MAX_TOKEN],
  812. c,
  813. eof = false,
  814.    *map_file;
  815. int key = 0,
  816. ChIndex = 0,
  817. i,
  818. bufsize;
  819. struct CharsetItem *ChArray[MAX_CHARSETS];
  820. *TableName = '';
  821. bufsize = (strlen(DataDir) + strlen(CHARSET_FILE) + 2) * sizeof(char);
  822. map_file = (char *) palloc(bufsize);
  823. snprintf(map_file, bufsize, "%s/%s", DataDir, CHARSET_FILE);
  824. #ifndef __CYGWIN32__
  825. file = AllocateFile(map_file, "r");
  826. #else
  827. file = AllocateFile(map_file, "rb");
  828. #endif
  829. if (file == NULL)
  830. return;
  831. while (!eof)
  832. {
  833. c = getc(file);
  834. ungetc(c, file);
  835. if (c == EOF)
  836. eof = true;
  837. else
  838. {
  839. if (c == '#')
  840. read_through_eol(file);
  841. else
  842. {
  843. /* Read the key */
  844. next_token(file, buf, sizeof(buf));
  845. if (buf[0] != '')
  846. {
  847. if (strcasecmp(buf, "HostCharset") == 0)
  848. key = KEY_HOST;
  849. if (strcasecmp(buf, "BaseCharset") == 0)
  850. key = KEY_BASE;
  851. if (strcasecmp(buf, "RecodeTable") == 0)
  852. key = KEY_TABLE;
  853. switch (key)
  854. {
  855. case KEY_HOST:
  856. /* Read the host */
  857. next_token(file, buf, sizeof(buf));
  858. if (buf[0] != '')
  859. {
  860. if (InRange(buf, host))
  861. {
  862. /* Read the charset */
  863. next_token(file, buf, sizeof(buf));
  864. if (buf[0] != '')
  865. strcpy(HostCharset, buf);
  866. }
  867. }
  868. break;
  869. case KEY_BASE:
  870. /* Read the base charset */
  871. next_token(file, buf, sizeof(buf));
  872. if (buf[0] != '')
  873. strcpy(BaseCharset, buf);
  874. break;
  875. case KEY_TABLE:
  876. /* Read the original charset */
  877. next_token(file, buf, sizeof(buf));
  878. if (buf[0] != '')
  879. {
  880. strcpy(OrigCharset, buf);
  881. /* Read the destination charset */
  882. next_token(file, buf, sizeof(buf));
  883. if (buf[0] != '')
  884. {
  885. strcpy(DestCharset, buf);
  886. /* Read the table filename */
  887. next_token(file, buf, sizeof(buf));
  888. if (buf[0] != '')
  889. {
  890. ChArray[ChIndex] =
  891. (struct CharsetItem *) palloc(sizeof(struct CharsetItem));
  892. strcpy(ChArray[ChIndex]->Orig, OrigCharset);
  893. strcpy(ChArray[ChIndex]->Dest, DestCharset);
  894. strcpy(ChArray[ChIndex]->Table, buf);
  895. ChIndex++;
  896. }
  897. }
  898. }
  899. break;
  900. }
  901. read_through_eol(file);
  902. }
  903. }
  904. }
  905. }
  906. FreeFile(file);
  907. pfree(map_file);
  908. for (i = 0; i < ChIndex; i++)
  909. {
  910. if (!strcasecmp(BaseCharset, ChArray[i]->Orig) &&
  911. !strcasecmp(HostCharset, ChArray[i]->Dest))
  912. strncpy(TableName, ChArray[i]->Table, 79);
  913. pfree((struct CharsetItem *) ChArray[i]);
  914. }
  915. }
  916. #endif
  917. int
  918. hba_getauthmethod(SockAddr *raddr, char *user, char *database,
  919.   char *auth_arg, UserAuth *auth_method)
  920. {
  921. /*---------------------------------------------------------------------------
  922.   Determine what authentication method should be used when accessing database
  923.   "database" from frontend "raddr", user "user".  Return the method,
  924.   an optional argument, and STATUS_OK.
  925.   Note that STATUS_ERROR indicates a problem with the hba config file.
  926.   If the file is OK but does not contain any entry matching the request,
  927.   we return STATUS_OK and method = uaReject.
  928. ----------------------------------------------------------------------------*/
  929. bool hba_ok = false;
  930. find_hba_entry(raddr, user, database, &hba_ok, auth_method, auth_arg);
  931. return hba_ok ? STATUS_OK : STATUS_ERROR;
  932. }