pg_hba.conf caching - Mailing list pgsql-patches

From Bruce Momjian
Subject pg_hba.conf caching
Date
Msg-id 200107210031.f6L0V2o20575@candle.pha.pa.us
Whole thread Raw
Responses Re: pg_hba.conf caching  (Karel Zak <zakkr@zf.jcu.cz>)
List pgsql-patches
Attached is a patch that caches the non-comment contents of pg_hba.conf
as a List of list of tokens.  It uses that to test each authentication
request.  SIGHUP reloads from the file, and a cache of pg_ident.conf.

I replaced the File reading code with token storage and list traveral.

The only tricky part was moving the Postmaster memory clearing later in
the code so I had the file contents in postgres.c.

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026
Index: src/backend/libpq/hba.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/libpq/hba.c,v
retrieving revision 1.55
diff -c -r1.55 hba.c
*** src/backend/libpq/hba.c    2001/02/10 02:31:26    1.55
--- src/backend/libpq/hba.c    2001/07/21 00:12:41
***************
*** 22,27 ****
--- 22,28 ----

  #include "libpq/libpq.h"
  #include "miscadmin.h"
+ #include "nodes/pg_list.h"
  #include "storage/fd.h"


***************
*** 31,36 ****
--- 32,44 ----
  #define IDENT_USERNAME_MAX 512
   /* Max size of username ident server can return */

+ static List *hba_lines = NULL;    /* A list of lists: entry for every line,
+                                  * list of tokens on each line.
+                                  */
+
+ static List *ident_lines = NULL;/* A list of lists: entry for every line,
+                                  * list of tokens on each line.
+                                  */

  /* Some standard C libraries, including GNU, have an isblank() function.
     Others, including Solaris, do not.  So we have our own.
***************
*** 38,68 ****
  static bool
  isblank(const char c)
  {
!     return c == ' ' || c == 9 /* tab */ ;
  }


  static void
  next_token(FILE *fp, char *buf, const int bufsz)
  {
- /*--------------------------------------------------------------------------
-   Grab one token out of fp.  Tokens are strings of non-blank
-   characters bounded by blank characters, beginning of line, and end
-   of line.    Blank means space or tab.  Return the token as *buf.
-   Leave file positioned to character immediately after the token or
-   EOF, whichever comes first.  If no more tokens on line, return null
-   string as *buf and position file to beginning of next line or EOF,
-   whichever comes first.
- --------------------------------------------------------------------------*/
      int            c;
      char       *eb = buf + (bufsz - 1);

      /* Move over inital token-delimiting blanks */
!     while (isblank(c = getc(fp)));

      if (c != '\n')
      {
-
          /*
           * build a token in buf of next characters up to EOF, eol, or
           * blank.
--- 46,76 ----
  static bool
  isblank(const char c)
  {
!     return c == ' ' || c == 0x09;/* tab */
  }


+ /*
+  *  Grab one token out of fp.  Tokens are strings of non-blank
+  *  characters bounded by blank characters, beginning of line, and end
+  *  of line.    Blank means space or tab.  Return the token as *buf.
+  *  Leave file positioned to character immediately after the token or
+  *  EOF, whichever comes first.  If no more tokens on line, return null
+  *  string as *buf and position file to beginning of next line or EOF,
+  *  whichever comes first.
+  */
  static void
  next_token(FILE *fp, char *buf, const int bufsz)
  {
      int            c;
      char       *eb = buf + (bufsz - 1);

      /* Move over inital token-delimiting blanks */
!     while (isblank(c = getc(fp)))
!         ;

      if (c != '\n')
      {
          /*
           * build a token in buf of next characters up to EOF, eol, or
           * blank.
***************
*** 72,231 ****
              if (buf < eb)
                  *buf++ = c;
              c = getc(fp);
-
-             /*
-              * Put back the char right after the token (putting back EOF
-              * is ok)
-              */
          }
          ungetc(c, fp);
      }
      *buf = '\0';
  }


-
  static void
! read_through_eol(FILE *file)
  {
      int            c;

!     do
!         c = getc(file);
!     while (c != '\n' && c != EOF);
  }

-

  static void
! read_hba_entry2(FILE *file, UserAuth *userauth_p, char *auth_arg,
!                 bool *error_p)
  {
- /*--------------------------------------------------------------------------
-   Read from file FILE the rest of a host record, after the mask field,
-   and return the interpretation of it as *userauth_p, auth_arg, and
-   *error_p.
- ---------------------------------------------------------------------------*/
      char        buf[MAX_TOKEN];
!
!     /* Get authentication type token. */
!     next_token(file, buf, sizeof(buf));

!     if (strcmp(buf, "trust") == 0)
!         *userauth_p = uaTrust;
!     else if (strcmp(buf, "ident") == 0)
!         *userauth_p = uaIdent;
!     else if (strcmp(buf, "password") == 0)
!         *userauth_p = uaPassword;
!     else if (strcmp(buf, "krb4") == 0)
!         *userauth_p = uaKrb4;
!     else if (strcmp(buf, "krb5") == 0)
!         *userauth_p = uaKrb5;
!     else if (strcmp(buf, "reject") == 0)
!         *userauth_p = uaReject;
!     else if (strcmp(buf, "crypt") == 0)
!         *userauth_p = uaCrypt;
!     else
      {
!         *error_p = true;

          if (buf[0] != '\0')
!             read_through_eol(file);
      }

      if (!*error_p)
      {
          /* Get the authentication argument token, if any */
!         next_token(file, buf, sizeof(buf));
!         if (buf[0] == '\0')
              auth_arg[0] = '\0';
          else
          {
!             StrNCpy(auth_arg, buf, MAX_AUTH_ARG - 1);
!             next_token(file, buf, sizeof(buf));
!             if (buf[0] != '\0')
!             {
                  *error_p = true;
-                 read_through_eol(file);
-             }
          }
      }
  }

-

  static void
! process_hba_record(FILE *file, hbaPort *port, bool *matches_p, bool *error_p)
  {
! /*---------------------------------------------------------------------------
!   Process the non-comment record in the config file that is next on the file.
!   See if it applies to a connection to a host with IP address "*raddr"
!   to a database named "*database".    If so, return *matches_p true
!   and *userauth_p and *auth_arg as the values from the entry.
!   If not, leave *matches_p as it was.  If the record has a syntax error,
!   return *error_p true, after issuing a message to stderr.    If no error,
!   leave *error_p as it was.
! ---------------------------------------------------------------------------*/
!     char        db[MAX_TOKEN],
!                 buf[MAX_TOKEN];

!     /* Read the record type field. */
!
!     next_token(file, buf, sizeof(buf));
!
!     if (buf[0] == '\0')
!         return;
!
      /* Check the record type. */
!
!     if (strcmp(buf, "local") == 0)
      {
          /* Get the database. */
!
!         next_token(file, db, sizeof(db));
!
!         if (db[0] == '\0')
!             goto syntax;
!
          /* Read the rest of the line. */
!
!         read_hba_entry2(file, &port->auth_method, port->auth_arg, error_p);

          /*
           * For now, disallow methods that need AF_INET sockets to work.
           */
-
          if (!*error_p &&
              (port->auth_method == uaIdent ||
               port->auth_method == uaKrb4 ||
               port->auth_method == uaKrb5))
!             *error_p = true;

-         if (*error_p)
-             goto syntax;
-
          /*
           * If this record isn't for our database, or this is the wrong
           * sort of connection, ignore it.
           */
-
          if ((strcmp(db, port->database) != 0 && strcmp(db, "all") != 0 &&
               (strcmp(db, "sameuser") != 0 || strcmp(port->database, port->user) != 0)) ||
              port->raddr.sa.sa_family != AF_UNIX)
              return;
      }
!     else if (strcmp(buf, "host") == 0 || strcmp(buf, "hostssl") == 0)
      {
!         struct in_addr file_ip_addr,
!                     mask;
!         bool        discard = 0;/* Discard this entry */

  #ifdef USE_SSL
          /* If SSL, then check that we are on SSL */
!         if (strcmp(buf, "hostssl") == 0)
          {
              if (!port->ssl)
!                 discard = 1;

              /* Placeholder to require specific SSL level, perhaps? */
              /* Or a client certificate */
--- 80,293 ----
              if (buf < eb)
                  *buf++ = c;
              c = getc(fp);
          }
+         /*
+          * Put back the char right after the token (putting back EOF
+          * is ok)
+          */
          ungetc(c, fp);
      }
      *buf = '\0';
  }


  static void
! read_to_eol(FILE *file)
  {
      int            c;

!     while ((c = getc(file)) != '\n' && c != EOF)
!         ;
  }


+ /*
+  *  Process the file line by line and create a list of list of tokens.
+  */
  static void
! tokenize_file(FILE *file, List **lines)
  {
      char        buf[MAX_TOKEN];
!     List        *next_line = NIL;
!     bool        comment_found = false;

!     while (1)
      {
!         next_token(file, buf, sizeof(buf));
!         if (feof(file))
!             break;

+         /* trim off comment, even if inside a token */
+         if (strstr(buf,"#") != NULL)
+         {
+             *strstr(buf,"#") = '\0';
+             comment_found = true;
+         }
+
+         /* add token to list */
          if (buf[0] != '\0')
!         {
!             if (next_line == NIL)
!             {
!                 /* make a new line List */
!                 next_line = lcons(pstrdup(buf), NIL);
!                 *lines = lappend(*lines, next_line);
!             }
!             else
!                 /* append token to line */
!                 next_line = lappend(next_line, pstrdup(buf));
!         }
!         else
!             /* force a new List line */
!             next_line = NIL;
!
!         if (comment_found)
!         {
!             /* Skip the rest of the line */
!             read_to_eol(file);
!             next_line = NIL;
!             comment_found = false;
!         }
!     }
! }
!
!
! /*
!  * Free memory used by lines/tokens
!  */
! static void free_lines(List **lines)
! {
!     if (*lines)
!     {
!         List *line, *token;
!
!         foreach(line, *lines)
!         {
!             foreach(token,lfirst(line))
!                 pfree(lfirst(token));
!             freeList(lfirst(line));
!         }
!         freeList(*lines);
!         *lines = NULL;
      }
+ }
+

+ /*
+  *  Read from file FILE the rest of a host record, after the mask field,
+  *  and return the interpretation of it as *userauth_p, auth_arg, and
+  *  *error_p.
+  */
+ static void
+ parse_hba_auth(List *line, UserAuth *userauth_p, char *auth_arg,
+                 bool *error_p)
+ {
+     char        *token = NULL;
+
+     if (!line)
+         *error_p = true;
+     else
+     {
+         /* Get authentication type token. */
+         token = lfirst(line);
+         if (strcmp(token, "trust") == 0)
+             *userauth_p = uaTrust;
+         else if (strcmp(token, "ident") == 0)
+             *userauth_p = uaIdent;
+         else if (strcmp(token, "password") == 0)
+             *userauth_p = uaPassword;
+         else if (strcmp(token, "krb4") == 0)
+             *userauth_p = uaKrb4;
+         else if (strcmp(token, "krb5") == 0)
+             *userauth_p = uaKrb5;
+         else if (strcmp(token, "reject") == 0)
+             *userauth_p = uaReject;
+         else if (strcmp(token, "crypt") == 0)
+             *userauth_p = uaCrypt;
+         else
+             *error_p = true;
+     }
+
      if (!*error_p)
      {
          /* Get the authentication argument token, if any */
!         line = lnext(line);
!         if (!line)
              auth_arg[0] = '\0';
          else
          {
!             StrNCpy(auth_arg, token, MAX_AUTH_ARG - 1);
!             /* If there is more on the line, it is an error */
!             if (lnext(line))
                  *error_p = true;
          }
      }
  }


+ /*
+  *  Process the non-comment lines in the config file.
+  *
+  *  See if it applies to a connection to a host with IP address "*raddr"
+  *  to a database named "*database".    If so, return *found_p true
+  *  and *userauth_p and *auth_arg as the values from the entry.
+  *  If not, leave *found_p as it was.  If the record has a syntax error,
+  *  return *error_p true, after issuing a message to stderr.    If no error,
+  *  leave *error_p as it was.
+  */
  static void
! parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p)
  {
!     char        *db;
!     char        *token;

!     Assert(line != NIL);
!     token = lfirst(line);
      /* Check the record type. */
!     if (strcmp(token, "local") == 0)
      {
          /* Get the database. */
!         line = lnext(line);
!         if (!line)
!             goto hba_syntax;
!         db = lfirst(line);
!
!         line = lnext(line);
!         if (!line)
!             goto hba_syntax;
          /* Read the rest of the line. */
!         parse_hba_auth(line, &port->auth_method, port->auth_arg, error_p);
!         if (*error_p)
!             goto hba_syntax;

          /*
           * For now, disallow methods that need AF_INET sockets to work.
           */
          if (!*error_p &&
              (port->auth_method == uaIdent ||
               port->auth_method == uaKrb4 ||
               port->auth_method == uaKrb5))
!             goto hba_syntax;

          /*
           * If this record isn't for our database, or this is the wrong
           * sort of connection, ignore it.
           */
          if ((strcmp(db, port->database) != 0 && strcmp(db, "all") != 0 &&
               (strcmp(db, "sameuser") != 0 || strcmp(port->database, port->user) != 0)) ||
              port->raddr.sa.sa_family != AF_UNIX)
              return;
      }
!     else if (strcmp(token, "host") == 0 || strcmp(token, "hostssl") == 0)
      {
!         struct in_addr file_ip_addr, mask;

  #ifdef USE_SSL
          /* If SSL, then check that we are on SSL */
!         if (strcmp(token, "hostssl") == 0)
          {
              if (!port->ssl)
!                 return;

              /* Placeholder to require specific SSL level, perhaps? */
              /* Or a client certificate */
***************
*** 234,300 ****
          }
  #else
          /* If not SSL, we don't support this */
!         if (strcmp(buf, "hostssl") == 0)
!             goto syntax;
  #endif

          /* Get the database. */
!
!         next_token(file, db, sizeof(db));
!
!         if (db[0] == '\0')
!             goto syntax;

          /* Read the IP address field. */

-         next_token(file, buf, sizeof(buf));
-
-         if (buf[0] == '\0')
-             goto syntax;
-
          /* Remember the IP address field and go get mask field. */

-         if (!inet_aton(buf, &file_ip_addr))
-         {
-             read_through_eol(file);
-             goto syntax;
-         }
-
          /* Read the mask field. */
!
!         next_token(file, buf, sizeof(buf));

!         if (buf[0] == '\0')
!             goto syntax;

-         if (!inet_aton(buf, &mask))
-         {
-             read_through_eol(file);
-             goto syntax;
-         }
-
          /*
           * This is the record we're looking for.  Read the rest of the
           * info from it.
           */
!
!         read_hba_entry2(file, &port->auth_method, port->auth_arg, error_p);
!
          if (*error_p)
!             goto syntax;
!
!         /*
!          * If told to discard earlier. Moved down here so we don't get
!          * "out of sync" with the file.
!          */
!         if (discard)
!             return;

          /*
           * If this record isn't for our database, or this is the wrong
           * sort of connection, ignore it.
           */
-
          if ((strcmp(db, port->database) != 0 && strcmp(db, "all") != 0 &&
               (strcmp(db, "sameuser") != 0 || strcmp(port->database, port->user) != 0)) ||
              port->raddr.sa.sa_family != AF_INET ||
--- 296,345 ----
          }
  #else
          /* If not SSL, we don't support this */
!         if (strcmp(token, "hostssl") == 0)
!             goto hba_syntax;
  #endif

          /* Get the database. */
!         line = lnext(line);
!         if (!line)
!             goto hba_syntax;
!         db = lfirst(line);

          /* Read the IP address field. */
+         line = lnext(line);
+         if (!line)
+             goto hba_syntax;
+         token = lfirst(line);

          /* Remember the IP address field and go get mask field. */
+         if (!inet_aton(token, &file_ip_addr))
+             goto hba_syntax;

          /* Read the mask field. */
!         line = lnext(line);
!         if (!line)
!             goto hba_syntax;
!         token = lfirst(line);

!         if (!inet_aton(token, &mask))
!             goto hba_syntax;

          /*
           * This is the record we're looking for.  Read the rest of the
           * info from it.
           */
!         line = lnext(line);
!         if (!line)
!             goto hba_syntax;
!         parse_hba_auth(line, &port->auth_method, port->auth_arg, error_p);
          if (*error_p)
!             goto hba_syntax;

          /*
           * If this record isn't for our database, or this is the wrong
           * sort of connection, ignore it.
           */
          if ((strcmp(db, port->database) != 0 && strcmp(db, "all") != 0 &&
               (strcmp(db, "sameuser") != 0 || strcmp(port->database, port->user) != 0)) ||
              port->raddr.sa.sa_family != AF_INET ||
***************
*** 302,399 ****
              return;
      }
      else
!     {
!         read_through_eol(file);
!         goto syntax;
!     }

!     *matches_p = true;
!
      return;

! syntax:
      snprintf(PQerrormsg, PQERRORMSG_LENGTH,
!              "process_hba_record: invalid syntax in pg_hba.conf file\n");
      fputs(PQerrormsg, stderr);
      pqdebug("%s", PQerrormsg);

      *error_p = true;
  }


!
! static void
! process_open_config_file(FILE *file, hbaPort *port, bool *hba_ok_p)
  {
! /*---------------------------------------------------------------------------
!   This function does the same thing as find_hba_entry, only with
!   the config file already open on stream descriptor "file".
! ----------------------------------------------------------------------------*/
!     bool        found_entry = false;    /* found an applicable entry? */
!     bool        error = false;    /* found an erroneous entry? */
!     bool        eof = false;    /* end of hba file */
!
!     while (!eof && !found_entry && !error)
!     {
!         /* Process a line from the config file */
!         int            c = getc(file);
!
!         if (c == EOF)
!             eof = true;
!         else
!         {
!             ungetc(c, file);
!             if (c == '#')
!                 read_through_eol(file);
!             else
!                 process_hba_record(file, port, &found_entry, &error);
!         }
      }

      if (!error)
      {
          /* If no matching entry was found, synthesize 'reject' entry. */
-
          if (!found_entry)
              port->auth_method = uaReject;
!
!         *hba_ok_p = true;
      }
  }


-
- static void
- find_hba_entry(hbaPort *port, bool *hba_ok_p)
- {
  /*
!  * Read the config file and find an entry that allows connection from
!  * host "raddr", user "user", to database "database".  If found,
!  * return *hba_ok_p = true and *userauth_p and *auth_arg representing
!  * the contents of that entry.    If there is no matching entry, we
!  * set *hba_ok_p = true, *userauth_p = uaReject.
!  *
!  * If the config file is unreadable or contains invalid syntax, we
!  * issue a diagnostic message to stderr (ie, the postmaster log file)
!  * and return without changing *hba_ok_p.
!  *
   * If we find a file by the old name of the config file (pg_hba), we issue
   * an error message because it probably needs to be converted.    He didn't
   * follow directions and just installed his old hba file in the new database
   * system.
   */

      int            fd,
                  bufsize;
      FILE       *file;            /* The config file we have to read */
      char       *old_conf_file;

!     /* The name of old config file that better not exist. */
!
!     /* Fail if config file by old name exists. */
!
!
!     /* put together the full pathname to the old config file */
      bufsize = (strlen(DataDir) + strlen(OLD_CONF_FILE) + 2) * sizeof(char);
      old_conf_file = (char *) palloc(bufsize);
      snprintf(old_conf_file, bufsize, "%s/%s", DataDir, OLD_CONF_FILE);
--- 347,421 ----
              return;
      }
      else
!         goto hba_syntax;

!     /* Success */
!     *found_p = true;
      return;

! hba_syntax:
      snprintf(PQerrormsg, PQERRORMSG_LENGTH,
!              "parse_hba: invalid syntax in pg_hba.conf file\n");
      fputs(PQerrormsg, stderr);
      pqdebug("%s", PQerrormsg);

      *error_p = true;
+     return;
  }


! /*
!  *  Process the hba file line by line.
!  */
! static bool
! check_hba(hbaPort *port)
  {
!     List     *line;
!     bool    found_entry = false;
!     bool    error = false;
!
!     foreach (line, hba_lines)
!     {
!         parse_hba(lfirst(line), port, &found_entry, &error);
!         if (found_entry || error)
!             break;
      }

      if (!error)
      {
          /* If no matching entry was found, synthesize 'reject' entry. */
          if (!found_entry)
              port->auth_method = uaReject;
!         return true;
      }
+     else
+         return false;
  }


  /*
!  * Read the config file and create a List of Lists of tokens in the file.
   * If we find a file by the old name of the config file (pg_hba), we issue
   * an error message because it probably needs to be converted.    He didn't
   * follow directions and just installed his old hba file in the new database
   * system.
   */
+ static void
+ load_hba()
+ {

      int            fd,
                  bufsize;
      FILE       *file;            /* The config file we have to read */
      char       *old_conf_file;

!     if (hba_lines)
!         free_lines(&hba_lines);
!     /*
!      *    The name of old config file that better not exist.
!      *    Fail if config file by old name exists.
!      *    Put together the full pathname to the old config file.
!      */
      bufsize = (strlen(DataDir) + strlen(OLD_CONF_FILE) + 2) * sizeof(char);
      old_conf_file = (char *) palloc(bufsize);
      snprintf(old_conf_file, bufsize, "%s/%s", DataDir, OLD_CONF_FILE);
***************
*** 403,413 ****
          /* Old config file exists.    Tell this guy he needs to upgrade. */
          close(fd);
          snprintf(PQerrormsg, PQERRORMSG_LENGTH,
!           "A file exists by the name used for host-based authentication "
!            "in prior releases of Postgres (%s).  The name and format of "
!            "the configuration file have changed, so this file should be "
!                  "converted.\n",
!                  old_conf_file);
          fputs(PQerrormsg, stderr);
          pqdebug("%s", PQerrormsg);
      }
--- 425,434 ----
          /* Old config file exists.    Tell this guy he needs to upgrade. */
          close(fd);
          snprintf(PQerrormsg, PQERRORMSG_LENGTH,
!             "A file exists by the name used for host-based authentication "
!             "in prior releases of Postgres (%s).  The name and format of "
!             "the configuration file have changed, so this file should be "
!             "converted.\n", old_conf_file);
          fputs(PQerrormsg, stderr);
          pqdebug("%s", PQerrormsg);
      }
***************
*** 425,440 ****
          if (file == NULL)
          {
              /* The open of the config file failed.    */
-
              snprintf(PQerrormsg, PQERRORMSG_LENGTH,
!                      "find_hba_entry: Unable to open authentication config file \"%s\": %s\n",
                       conf_file, strerror(errno));
              fputs(PQerrormsg, stderr);
              pqdebug("%s", PQerrormsg);
          }
          else
          {
!             process_open_config_file(file, port, hba_ok_p);
              FreeFile(file);
          }
          pfree(conf_file);
--- 446,460 ----
          if (file == NULL)
          {
              /* The open of the config file failed.    */
              snprintf(PQerrormsg, PQERRORMSG_LENGTH,
!                      "load_hba: Unable to open authentication config file \"%s\": %s\n",
                       conf_file, strerror(errno));
              fputs(PQerrormsg, stderr);
              pqdebug("%s", PQerrormsg);
          }
          else
          {
!             tokenize_file(file, &hba_lines);
              FreeFile(file);
          }
          pfree(conf_file);
***************
*** 443,477 ****
  }


  static void
! interpret_ident_response(char *ident_response,
!                          bool *error_p, char *ident_username)
  {
! /*----------------------------------------------------------------------------
!   Parse the string "*ident_response" as a response from a query to an Ident
!   server.  If it's a normal response indicating a username, return
!   *error_p == false and the username as *ident_username.  If it's anything
!   else, return *error_p == true and *ident_username undefined.
! ----------------------------------------------------------------------------*/
!     char       *cursor;            /* Cursor into *ident_response */

!     cursor = &ident_response[0];

      /*
       * Ident's response, in the telnet tradition, should end in crlf
       * (\r\n).
       */
      if (strlen(ident_response) < 2)
!         *error_p = true;
      else if (ident_response[strlen(ident_response) - 2] != '\r')
!         *error_p = true;
      else
      {
          while (*cursor != ':' && *cursor != '\r')
              cursor++;            /* skip port field */

          if (*cursor != ':')
!             *error_p = true;
          else
          {
              /* We're positioned to colon before response type field */
--- 463,637 ----
  }


+ /*
+  *  Take the line and compare it to the needed map, pg_user and ident_user.
+  */
  static void
! parse_ident_usermap(List *line, const char *usermap_name, const char *pg_user,
!                  const char *ident_user, bool *found_p, bool *error_p)
! {
!     char        *token;
!     char        *file_map;
!     char        *file_pguser;
!     char        *file_ident_user;
!
!     *error_p = false;
!     *found_p = false;
!
!     /* A token read from the file */
!     Assert(line != NIL);
!     token = lfirst(line);
!     file_map = token;
!
!     line = lnext(line);
!     if (!line)
!         goto ident_syntax;
!     token = lfirst(line);
!     if (token[0] != '\0')
!     {
!         file_ident_user = token;
!         line = lnext(line);
!         if (!line)
!             goto ident_syntax;
!         token = lfirst(line);
!         if (token[0] != '\0')
!         {
!             file_pguser = token;
!             if (strcmp(file_map, usermap_name) == 0 &&
!                 strcmp(file_pguser, pg_user) == 0 &&
!                 strcmp(file_ident_user, ident_user) == 0)
!                 *found_p = true;
!         }
!     }
!
!     return;
!
! ident_syntax:
!     snprintf(PQerrormsg, PQERRORMSG_LENGTH,
!              "parse_ident_usermap: invalid syntax in pg_ident.conf file\n");
!     fputs(PQerrormsg, stderr);
!     pqdebug("%s", PQerrormsg);
!     *error_p = true;
!     return;
! }
!
!
! /*
!  *  Process the ident usermap file line by line.
!  */
! static bool
! check_ident_usermap(const char *usermap_name,
!                     const char *pg_user,
!                     const char *ident_user)
! {
!     List     *line;
!     bool    found_entry = false, error = false;
!
!     if (usermap_name[0] == '\0')
!     {
!         snprintf(PQerrormsg, PQERRORMSG_LENGTH,
!             "load_ident_usermap: hba configuration file does not "
!             "have the usermap field filled in in the entry that pertains "
!             "to this connection.  That field is essential for Ident-based "
!             "authentication.\n");
!         fputs(PQerrormsg, stderr);
!         pqdebug("%s", PQerrormsg);
!         found_entry = false;
!     }
!     else if (strcmp(usermap_name, "sameuser") == 0)
!     {
!         if (strcmp(pg_user, ident_user) == 0)
!             found_entry = true;
!         else
!             found_entry = false;
!     }
!     else
!     {
!         foreach(line, ident_lines)
!         {
!             parse_ident_usermap(lfirst(line), usermap_name, pg_user,
!                                 ident_user, &found_entry, &error);
!             if (found_entry || error)
!                 break;
!         }
!     }
!     return found_entry;
! }
!
!
! /*
!  *  See if the user with ident username "ident_user" is allowed to act
!  *  as Postgres user "pguser" according to usermap "usermap_name".   Look
!  *  it up in the usermap file.
!  *
!  *  Special case: For usermap "sameuser", don't look in the usermap
!  *  file.  That's an implied map where "pguser" must be identical to
!  *  "ident_user" in order to be authorized.
!  *
!  *  Iff authorized, return *checks_out_p == true.
!  */
! static void
! load_ident()
  {
!     FILE       *file;        /* The map file we have to read */
!     char       *map_file;    /* The name of the map file we have to
!                              * read */
!     int            bufsize;

!     if (ident_lines)
!         free_lines(&ident_lines);

+     /* put together the full pathname to the map file */
+     bufsize = (strlen(DataDir) + strlen(USERMAP_FILE) + 2) * sizeof(char);
+     map_file = (char *) palloc(bufsize);
+     snprintf(map_file, bufsize, "%s/%s", DataDir, USERMAP_FILE);
+
+     file = AllocateFile(map_file, PG_BINARY_R);
+     if (file == NULL)
+     {
+         /* The open of the map file failed.  */
+         snprintf(PQerrormsg, PQERRORMSG_LENGTH,
+             "load_ident_usermap: Unable to open usermap file \"%s\": %s\n",
+             map_file, strerror(errno));
+         fputs(PQerrormsg, stderr);
+         pqdebug("%s", PQerrormsg);
+     }
+     else
+     {
+         tokenize_file(file, &ident_lines);
+         FreeFile(file);
+     }
+     pfree(map_file);
+ }
+
+
+ /*
+  *  Parse the string "*ident_response" as a response from a query to an Ident
+  *  server.  If it's a normal response indicating a username, return
+  *  *error_p == false and the username as *ident_user.  If it's anything
+  *  else, return *error_p == true and *ident_user undefined.
+  */
+ static bool
+ interpret_ident_response(char *ident_response,
+                          char *ident_user)
+ {
+     char       *cursor = ident_response;/* Cursor into *ident_response */
+
      /*
       * Ident's response, in the telnet tradition, should end in crlf
       * (\r\n).
       */
      if (strlen(ident_response) < 2)
!         return false;
      else if (ident_response[strlen(ident_response) - 2] != '\r')
!         return false;
      else
      {
          while (*cursor != ':' && *cursor != '\r')
              cursor++;            /* skip port field */

          if (*cursor != ':')
!             return false;
          else
          {
              /* We're positioned to colon before response type field */
***************
*** 482,505 ****
              while (isblank(*cursor))
                  cursor++;        /* skip blanks */
              i = 0;
!             while (*cursor != ':' && *cursor != '\r' && !isblank(*cursor)
!                    && i < (int) (sizeof(response_type) - 1))
                  response_type[i++] = *cursor++;
              response_type[i] = '\0';
              while (isblank(*cursor))
                  cursor++;        /* skip blanks */
              if (strcmp(response_type, "USERID") != 0)
!                 *error_p = true;
              else
              {
-
                  /*
                   * It's a USERID response.  Good.  "cursor" should be
                   * pointing to the colon that precedes the operating
                   * system type.
                   */
                  if (*cursor != ':')
!                     *error_p = true;
                  else
                  {
                      cursor++;    /* Go over colon */
--- 642,664 ----
              while (isblank(*cursor))
                  cursor++;        /* skip blanks */
              i = 0;
!             while (*cursor != ':' && *cursor != '\r' && !isblank(*cursor) &&
!                    i < (int) (sizeof(response_type) - 1))
                  response_type[i++] = *cursor++;
              response_type[i] = '\0';
              while (isblank(*cursor))
                  cursor++;        /* skip blanks */
              if (strcmp(response_type, "USERID") != 0)
!                 return false;
              else
              {
                  /*
                   * It's a USERID response.  Good.  "cursor" should be
                   * pointing to the colon that precedes the operating
                   * system type.
                   */
                  if (*cursor != ':')
!                     return false;
                  else
                  {
                      cursor++;    /* Go over colon */
***************
*** 507,516 ****
                      while (*cursor != ':' && *cursor != '\r')
                          cursor++;
                      if (*cursor != ':')
!                         *error_p = true;
                      else
                      {
!                         int            i;    /* Index into *ident_username */

                          cursor++;        /* Go over colon */
                          while (isblank(*cursor))
--- 666,675 ----
                      while (*cursor != ':' && *cursor != '\r')
                          cursor++;
                      if (*cursor != ':')
!                         return false;
                      else
                      {
!                         int            i;    /* Index into *ident_user */

                          cursor++;        /* Go over colon */
                          while (isblank(*cursor))
***************
*** 518,526 ****
                          /* Rest of line is username.  Copy it over. */
                          i = 0;
                          while (*cursor != '\r' && i < IDENT_USERNAME_MAX)
!                             ident_username[i++] = *cursor++;
!                         ident_username[i] = '\0';
!                         *error_p = false;
                      }
                  }
              }
--- 677,685 ----
                          /* Rest of line is username.  Copy it over. */
                          i = 0;
                          while (*cursor != '\r' && i < IDENT_USERNAME_MAX)
!                             ident_user[i++] = *cursor++;
!                         ident_user[i] = '\0';
!                         return true;
                      }
                  }
              }
***************
*** 528,567 ****
      }
  }

-

! static void
! ident(const struct in_addr remote_ip_addr, const struct in_addr local_ip_addr,
!       const ushort remote_port, const ushort local_port,
!       bool *ident_failed, char *ident_username)
! {
! /*--------------------------------------------------------------------------
!   Talk to the ident server on host "remote_ip_addr" and find out who
!   owns the tcp connection from his port "remote_port" to port
!   "local_port_addr" on host "local_ip_addr".  Return the username the
!   ident server gives as "*ident_username".
!
!   IP addresses and port numbers are in network byte order.
!
!   But iff we're unable to get the information from ident, return
!   *ident_failed == true (and *ident_username undefined).
! ----------------------------------------------------------------------------*/


      int            sock_fd,        /* File descriptor for socket on which we
                                   * talk to Ident */
                  rc;                /* Return code from a locally called
                                   * function */

      sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
      if (sock_fd == -1)
      {
          snprintf(PQerrormsg, PQERRORMSG_LENGTH,
!              "Failed to create socket on which to talk to Ident server. "
!                  "socket() returned errno = %s (%d)\n",
!                  strerror(errno), errno);
          fputs(PQerrormsg, stderr);
          pqdebug("%s", PQerrormsg);
      }
      else
      {
--- 687,726 ----
      }
  }


! /*
!  *  Talk to the ident server on host "remote_ip_addr" and find out who
!  *  owns the tcp connection from his port "remote_port" to port
!  *  "local_port_addr" on host "local_ip_addr".  Return the username the
!  *  ident server gives as "*ident_user".

+  *  IP addresses and port numbers are in network byte order.

+  *  But iff we're unable to get the information from ident, return
+  *  false.
+  */
+ static int
+ ident(const struct in_addr remote_ip_addr,
+       const struct in_addr local_ip_addr,
+       const ushort remote_port,
+       const ushort local_port,
+       char *ident_user)
+ {
      int            sock_fd,        /* File descriptor for socket on which we
                                   * talk to Ident */
                  rc;                /* Return code from a locally called
                                   * function */
+     bool ident_return;

      sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
      if (sock_fd == -1)
      {
          snprintf(PQerrormsg, PQERRORMSG_LENGTH,
!             "Failed to create socket on which to talk to Ident server. "
!             "socket() returned errno = %s (%d)\n", strerror(errno), errno);
          fputs(PQerrormsg, stderr);
          pqdebug("%s", PQerrormsg);
+         ident_return = false;
      }
      else
      {
***************
*** 595,607 ****
          {
              snprintf(PQerrormsg, PQERRORMSG_LENGTH,
                  "Unable to connect to Ident server on the host which is "
!                      "trying to connect to Postgres "
!                      "(IP address %s, Port %d). "
!                      "errno = %s (%d)\n",
!                      inet_ntoa(remote_ip_addr), IDENT_PORT, strerror(errno), errno);
              fputs(PQerrormsg, stderr);
              pqdebug("%s", PQerrormsg);
!             *ident_failed = true;
          }
          else
          {
--- 754,766 ----
          {
              snprintf(PQerrormsg, PQERRORMSG_LENGTH,
                  "Unable to connect to Ident server on the host which is "
!                 "trying to connect to Postgres "
!                 "(IP address %s, Port %d). "
!                 "errno = %s (%d)\n",
!                 inet_ntoa(remote_ip_addr), IDENT_PORT, strerror(errno), errno);
              fputs(PQerrormsg, stderr);
              pqdebug("%s", PQerrormsg);
!             ident_return = false;
          }
          else
          {
***************
*** 614,873 ****
              if (rc < 0)
              {
                  snprintf(PQerrormsg, PQERRORMSG_LENGTH,
!                          "Unable to send query to Ident server on the host which is "
!                       "trying to connect to Postgres (Host %s, Port %d),"
!                          "even though we successfully connected to it.  "
!                          "errno = %s (%d)\n",
!                          inet_ntoa(remote_ip_addr), IDENT_PORT, strerror(errno), errno);
                  fputs(PQerrormsg, stderr);
                  pqdebug("%s", PQerrormsg);
!                 *ident_failed = true;
              }
              else
              {
                  char        ident_response[80 + IDENT_USERNAME_MAX];

!                 rc = recv(sock_fd, ident_response, sizeof(ident_response) - 1, 0);
                  if (rc < 0)
                  {
                      snprintf(PQerrormsg, PQERRORMSG_LENGTH,
!                           "Unable to receive response from Ident server "
!                              "on the host which is "
!                       "trying to connect to Postgres (Host %s, Port %d),"
!                     "even though we successfully sent our query to it.  "
!                              "errno = %s (%d)\n",
!                              inet_ntoa(remote_ip_addr), IDENT_PORT,
!                              strerror(errno), errno);
                      fputs(PQerrormsg, stderr);
                      pqdebug("%s", PQerrormsg);
!                     *ident_failed = true;
                  }
                  else
                  {
-                     bool        error;    /* response from Ident is garbage. */
-
                      ident_response[rc] = '\0';
!                     interpret_ident_response(ident_response, &error, ident_username);
!                     *ident_failed = error;
                  }
              }
              close(sock_fd);
          }
-     }
- }
-
-
-
- static void
- parse_map_record(FILE *file,
-                  char *file_map, char *file_pguser, char *file_iuser)
- {
- /*---------------------------------------------------------------------------
-   Take the noncomment line which is next on file "file" and interpret
-   it as a line in a usermap file.  Specifically, return the first
-   3 tokens as file_map, file_iuser, and file_pguser, respectively.    If
-   there are fewer than 3 tokens, return null strings for the missing
-   ones.
-
- ---------------------------------------------------------------------------*/
-     char        buf[MAX_TOKEN];
-
-     /* A token read from the file */
-
-     /* Set defaults in case fields not in file */
-     file_map[0] = '\0';
-     file_pguser[0] = '\0';
-     file_iuser[0] = '\0';
-
-     next_token(file, buf, sizeof(buf));
-     if (buf[0] != '\0')
-     {
-         strcpy(file_map, buf);
-         next_token(file, buf, sizeof(buf));
-         if (buf[0] != '\0')
-         {
-             strcpy(file_iuser, buf);
-             next_token(file, buf, sizeof(buf));
-             if (buf[0] != '\0')
-             {
-                 strcpy(file_pguser, buf);
-                 read_through_eol(file);
-                 return;
-             }
-         }
-         snprintf(PQerrormsg, PQERRORMSG_LENGTH,
-                  "Incomplete line in pg_ident: %s", file_map);
-         fputs(PQerrormsg, stderr);
-         pqdebug("%s", PQerrormsg);
      }
  }

-

! static void
! verify_against_open_usermap(FILE *file,
!                             const char *pguser,
!                             const char *ident_username,
!                             const char *usermap_name,
!                             bool *checks_out_p)
! {
! /*--------------------------------------------------------------------------
!   This function does the same thing as verify_against_usermap,
!   only with the config file already open on stream descriptor "file".
! ---------------------------------------------------------------------------*/
!     bool        match;            /* We found a matching entry in the map
!                                  * file */
!     bool        eof;            /* We've reached the end of the file we're
!                                  * reading */
!
!     match = false;                /* initial value */
!     eof = false;                /* initial value */
!     while (!eof && !match)
!     {
!         /* Process a line from the map file */
!
!         int            c;            /* a character read from the file */
!
!         c = getc(file);
!         ungetc(c, file);
!         if (c == EOF)
!             eof = true;
!         else
!         {
!             if (c == '#')
!                 read_through_eol(file);
!             else
!             {
!                 /* The following are fields read from a record of the file */
!                 char        file_map[MAX_TOKEN + 1];
!                 char        file_pguser[MAX_TOKEN + 1];
!                 char        file_iuser[MAX_TOKEN + 1];
!
!                 parse_map_record(file, file_map, file_pguser, file_iuser);
!                 if (strcmp(file_map, usermap_name) == 0 &&
!                     strcmp(file_pguser, pguser) == 0 &&
!                     strcmp(file_iuser, ident_username) == 0)
!                     match = true;
!             }
!         }
!     }
!     *checks_out_p = match;
! }
!
!
!
! static void
! verify_against_usermap(const char *pguser,
!                        const char *ident_username,
!                        const char *usermap_name,
!                        bool *checks_out_p)
  {
! /*--------------------------------------------------------------------------
!   See if the user with ident username "ident_username" is allowed to act
!   as Postgres user "pguser" according to usermap "usermap_name".   Look
!   it up in the usermap file.
!
!   Special case: For usermap "sameuser", don't look in the usermap
!   file.  That's an implied map where "pguser" must be identical to
!   "ident_username" in order to be authorized.
!
!   Iff authorized, return *checks_out_p == true.

! --------------------------------------------------------------------------*/

!     if (usermap_name[0] == '\0')
!     {
!         *checks_out_p = false;
!         snprintf(PQerrormsg, PQERRORMSG_LENGTH,
!                "verify_against_usermap: hba configuration file does not "
!            "have the usermap field filled in in the entry that pertains "
!           "to this connection.  That field is essential for Ident-based "
!                  "authentication.\n");
!         fputs(PQerrormsg, stderr);
!         pqdebug("%s", PQerrormsg);
!     }
!     else if (strcmp(usermap_name, "sameuser") == 0)
!     {
!         if (strcmp(ident_username, pguser) == 0)
!             *checks_out_p = true;
!         else
!             *checks_out_p = false;
!     }
      else
!     {
!         FILE       *file;        /* The map file we have to read */
!         char       *map_file;    /* The name of the map file we have to
!                                  * read */
!         int            bufsize;
!
!         /* put together the full pathname to the map file */
!         bufsize = (strlen(DataDir) + strlen(USERMAP_FILE) + 2) * sizeof(char);
!         map_file = (char *) palloc(bufsize);
!         snprintf(map_file, bufsize, "%s/%s", DataDir, USERMAP_FILE);
!
!         file = AllocateFile(map_file, PG_BINARY_R);
!         if (file == NULL)
!         {
!             /* The open of the map file failed.  */
!
!             snprintf(PQerrormsg, PQERRORMSG_LENGTH,
!                      "verify_against_usermap: Unable to open usermap file \"%s\": %s\n",
!                      map_file, strerror(errno));
!             fputs(PQerrormsg, stderr);
!             pqdebug("%s", PQerrormsg);
!
!             *checks_out_p = false;
!         }
!         else
!         {
!             verify_against_open_usermap(file,
!                                     pguser, ident_username, usermap_name,
!                                         checks_out_p);
!             FreeFile(file);
!         }
!         pfree(map_file);
!
!
!     }
  }


!
  int
! authident(struct sockaddr_in * raddr, struct sockaddr_in * laddr,
!           const char *postgres_username,
!           const char *auth_arg)
  {
- /*---------------------------------------------------------------------------
-   Talk to the ident server on the remote host and find out who owns the
-   connection described by "port".  Then look in the usermap file under
-   the usermap *auth_arg and see if that user is equivalent to
-   Postgres user *user.
-
-   Return STATUS_OK if yes.
- ---------------------------------------------------------------------------*/
-     bool        checks_out;
-     bool        ident_failed;
-
-     /* We were unable to get ident to give us a username */
-     char        ident_username[IDENT_USERNAME_MAX + 1];
-
-     /* The username returned by ident */
-
-     ident(raddr->sin_addr, laddr->sin_addr,
-           raddr->sin_port, laddr->sin_port,
-           &ident_failed, ident_username);

!     if (ident_failed)
          return STATUS_ERROR;
!
!     verify_against_usermap(postgres_username, ident_username, auth_arg,
!                            &checks_out);

!     return checks_out ? STATUS_OK : STATUS_ERROR;
  }


  #ifdef CYR_RECODE
  #define CHARSET_FILE "charset.conf"
  #define MAX_CHARSETS   10
--- 773,878 ----
              if (rc < 0)
              {
                  snprintf(PQerrormsg, PQERRORMSG_LENGTH,
!                     "Unable to send query to Ident server on the host which is "
!                     "trying to connect to Postgres (Host %s, Port %d),"
!                     "even though we successfully connected to it.  "
!                     "errno = %s (%d)\n",
!                     inet_ntoa(remote_ip_addr), IDENT_PORT, strerror(errno), errno);
                  fputs(PQerrormsg, stderr);
                  pqdebug("%s", PQerrormsg);
!                 ident_return = false;
              }
              else
              {
                  char        ident_response[80 + IDENT_USERNAME_MAX];

!                 rc = recv(sock_fd, ident_response,
!                           sizeof(ident_response) - 1, 0);
                  if (rc < 0)
                  {
                      snprintf(PQerrormsg, PQERRORMSG_LENGTH,
!                         "Unable to receive response from Ident server "
!                         "on the host which is "
!                         "trying to connect to Postgres (Host %s, Port %d),"
!                         "even though we successfully sent our query to it.  "
!                         "errno = %s (%d)\n",
!                         inet_ntoa(remote_ip_addr), IDENT_PORT,
!                         strerror(errno), errno);
                      fputs(PQerrormsg, stderr);
                      pqdebug("%s", PQerrormsg);
!                     ident_return = false;
                  }
                  else
                  {
                      ident_response[rc] = '\0';
!                     ident_return = interpret_ident_response(ident_response,
!                                                             ident_user);
                  }
              }
              close(sock_fd);
          }
      }
+     return ident_return;
  }


! /*
!  *  Talk to the ident server on the remote host and find out who owns the
!  *  connection described by "port".  Then look in the usermap file under
!  *  the usermap *auth_arg and see if that user is equivalent to
!  *  Postgres user *user.
!  *
!  *  Return STATUS_OK if yes.
!  */
! int
! authident(struct sockaddr_in *raddr, struct sockaddr_in *laddr,
!           const char *pg_user, const char *auth_arg)
  {
!     /* We were unable to get ident to give us a username */
!     char        ident_user[IDENT_USERNAME_MAX + 1];

!     /* The username returned by ident */
!     if (!ident(raddr->sin_addr, laddr->sin_addr,
!           raddr->sin_port, laddr->sin_port, ident_user))
!         return STATUS_ERROR;

!     if (check_ident_usermap(auth_arg, pg_user, ident_user))
!         return STATUS_OK;
      else
!         return STATUS_ERROR;
  }


! /*
!  *  Determine what authentication method should be used when accessing database
!  *  "database" from frontend "raddr", user "user".  Return the method,
!  *  an optional argument, and STATUS_OK.
!  *  Note that STATUS_ERROR indicates a problem with the hba config file.
!  *  If the file is OK but does not contain any entry matching the request,
!  *  we return STATUS_OK and method = uaReject.
!  */
  int
! hba_getauthmethod(hbaPort *port)
  {

!     if (check_hba(port))
!         return STATUS_OK;
!     else
          return STATUS_ERROR;
! }

! /*
!  * Clear tokenized file contents and force reload on next use.
!  */
! void load_hba_and_ident(void)
! {
!     load_hba();
!     load_ident();
  }


+ /* Character set stuff.  Not sure it really belongs in this file. */
+
  #ifdef CYR_RECODE
  #define CHARSET_FILE "charset.conf"
  #define MAX_CHARSETS   10
***************
*** 882,889 ****
      char        Table[MAX_TOKEN];
  };

  static bool
! InRange(char *buf, int host)
  {
      int            valid,
                  i,
--- 887,895 ----
      char        Table[MAX_TOKEN];
  };

+
  static bool
! CharSetInRange(char *buf, int host)
  {
      int            valid,
                  i,
***************
*** 989,995 ****
          else
          {
              if (c == '#')
!                 read_through_eol(file);
              else
              {
                  /* Read the key */
--- 995,1001 ----
          else
          {
              if (c == '#')
!                 read_to_eol(file);
              else
              {
                  /* Read the key */
***************
*** 1009,1015 ****
                              next_token(file, buf, sizeof(buf));
                              if (buf[0] != '\0')
                              {
!                                 if (InRange(buf, host))
                                  {
                                      /* Read the charset */
                                      next_token(file, buf, sizeof(buf));
--- 1015,1021 ----
                              next_token(file, buf, sizeof(buf));
                              if (buf[0] != '\0')
                              {
!                                 if (CharSetInRange(buf, host))
                                  {
                                      /* Read the charset */
                                      next_token(file, buf, sizeof(buf));
***************
*** 1050,1056 ****
                              }
                              break;
                      }
!                     read_through_eol(file);
                  }
              }
          }
--- 1056,1062 ----
                              }
                              break;
                      }
!                     read_to_eol(file);
                  }
              }
          }
***************
*** 1066,1088 ****
          pfree((struct CharsetItem *) ChArray[i]);
      }
  }
-
  #endif

- int
- hba_getauthmethod(hbaPort *port)
- {
- /*---------------------------------------------------------------------------
-   Determine what authentication method should be used when accessing database
-   "database" from frontend "raddr", user "user".  Return the method,
-   an optional argument, and STATUS_OK.
-   Note that STATUS_ERROR indicates a problem with the hba config file.
-   If the file is OK but does not contain any entry matching the request,
-   we return STATUS_OK and method = uaReject.
- ----------------------------------------------------------------------------*/
-     bool        hba_ok = false;

-     find_hba_entry(port, &hba_ok);

-     return hba_ok ? STATUS_OK : STATUS_ERROR;
- }
--- 1072,1078 ----
Index: src/backend/postmaster/postmaster.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/postmaster/postmaster.c,v
retrieving revision 1.231
diff -c -r1.231 postmaster.c
*** src/backend/postmaster/postmaster.c    2001/07/03 16:52:12    1.231
--- src/backend/postmaster/postmaster.c    2001/07/21 00:12:43
***************
*** 809,814 ****
--- 809,816 ----

      nSockets = initMasks(&readmask, &writemask);

+     load_hba_and_ident();
+
      for (;;)
      {
          Port       *port;
***************
*** 874,879 ****
--- 876,882 ----
          if (got_SIGHUP)
          {
              got_SIGHUP = false;
+             load_hba_and_ident();
              ProcessConfigFile(PGC_SIGHUP);
          }

***************
*** 993,999 ****

      buf = palloc(len);
      pq_getbytes(buf, len);
!
      packet = buf;

      /*
--- 996,1002 ----

      buf = palloc(len);
      pq_getbytes(buf, len);
!
      packet = buf;

      /*
***************
*** 1479,1485 ****
  #endif
          /*
           * Check if this child was the statistics collector. If
!          * so, start a new one.
           */
          if (pgstat_ispgstat(pid))
          {
--- 1482,1488 ----
  #endif
          /*
           * Check if this child was the statistics collector. If
!          * so, start a new one.
           */
          if (pgstat_ispgstat(pid))
          {
***************
*** 1987,2004 ****
          av[ac++] = "-o";
          av[ac++] = ttybuf;
      }
-
      av[ac] = (char *) NULL;
-
-     /*
-      * Release postmaster's working memory context so that backend can
-      * recycle the space.  Note this does not trash *MyProcPort, because
-      * ConnCreate() allocated that space with malloc() ... else we'd need
-      * to copy the Port data here.
-      */
-     MemoryContextSwitchTo(TopMemoryContext);
-     MemoryContextDelete(PostmasterContext);
-     PostmasterContext = NULL;

      /*
       * Debug: print arguments being passed to backend
--- 1990,1996 ----
Index: src/backend/tcop/postgres.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/tcop/postgres.c,v
retrieving revision 1.227
diff -c -r1.227 postgres.c
*** src/backend/tcop/postgres.c    2001/06/29 16:05:56    1.227
--- src/backend/tcop/postgres.c    2001/07/21 00:12:44
***************
*** 1120,1126 ****
      unsigned short remote_port;

      char       *potential_DataDir = NULL;
!
      /*
       * Catch standard options before doing much else.  This even works on
       * systems without getopt_long.
--- 1120,1126 ----
      unsigned short remote_port;

      char       *potential_DataDir = NULL;
!
      /*
       * Catch standard options before doing much else.  This even works on
       * systems without getopt_long.
***************
*** 1144,1158 ****
       *
       * If we are running under the postmaster, this is done already.
       */
!     if (!IsUnderPostmaster)
      {
          SetProcessingMode(InitProcessing);
          EnableExceptionHandling(true);
          MemoryContextInit();
      }
-
-     if (IsUnderPostmaster)
-         ClientAuthentication(MyProcPort); /* might not return */

      /*
       * Set default values for command-line options.
--- 1144,1169 ----
       *
       * If we are running under the postmaster, this is done already.
       */
!     if (IsUnderPostmaster)
!     {
!         MemoryContextSwitchTo(TopMemoryContext);
!         ClientAuthentication(MyProcPort); /* might not return */
!         /*
!          * Release postmaster's working memory context so that backend can
!          * recycle the space.  Note this does not trash *MyProcPort, because
!          * ConnCreate() allocated that space with malloc() ... else we'd need
!          * to copy the Port data here.  We delete it here because the
!          * authorization file tokens are stored in this context.
!          */
!         MemoryContextDelete(PostmasterContext);
!         PostmasterContext = NULL;
!     }
!     else
      {
          SetProcessingMode(InitProcessing);
          EnableExceptionHandling(true);
          MemoryContextInit();
      }

      /*
       * Set default values for command-line options.
Index: src/include/libpq/hba.h
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/include/libpq/hba.h,v
retrieving revision 1.19
diff -c -r1.19 hba.h
*** src/include/libpq/hba.h    2001/03/22 04:00:47    1.19
--- src/include/libpq/hba.h    2001/07/21 00:12:45
***************
*** 40,47 ****

  typedef struct Port hbaPort;

! int            hba_getauthmethod(hbaPort *port);
  int authident(struct sockaddr_in * raddr, struct sockaddr_in * laddr,
            const char *postgres_username, const char *auth_arg);

  #endif
--- 40,48 ----

  typedef struct Port hbaPort;

! int    hba_getauthmethod(hbaPort *port);
  int authident(struct sockaddr_in * raddr, struct sockaddr_in * laddr,
            const char *postgres_username, const char *auth_arg);
+ void load_hba_and_ident(void);

  #endif

pgsql-patches by date:

Previous
From: Bruce Momjian
Date:
Subject: pg_hba.conf cache
Next
From: Rene Pijlman
Date:
Subject: Improvement Linux startup script