Thread: pg_hba.conf caching

pg_hba.conf caching

From
Bruce Momjian
Date:
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

Re: pg_hba.conf caching

From
Karel Zak
Date:
On Fri, Jul 20, 2001 at 08:31:02PM -0400, Bruce Momjian wrote:
> 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

  Means it cached are tokens only (and it save lexical analyze for
postmaster children), and final parsing (syntax analyze) running always?

 If I'm right: why not store to memory some final structs with config
file content? And for example things like 'strcmp(token, "password")'
run only once during postmaster startup.

            Karel

--
 Karel Zak  <zakkr@zf.jcu.cz>
 http://home.zf.jcu.cz/~zakkr/

 C, PostgreSQL, PHP, WWW, http://docs.linux.cz, http://mape.jcu.cz

Re: pg_hba.conf caching

From
Tom Lane
Date:
Karel Zak <zakkr@zf.jcu.cz> writes:
>  If I'm right: why not store to memory some final structs with config
> file content?

That was the original suggestion, but Bruce realized that it's way more
work than it's worth.  Eliminating I/O for the comment lines was the big
point for this change --- in a typical pg_hba.conf, there aren't going
to be enough non-comment lines for parsing them to cost anything
noticeable.

            regards, tom lane

Re: pg_hba.conf caching

From
Bruce Momjian
Date:
> On Fri, Jul 20, 2001 at 08:31:02PM -0400, Bruce Momjian wrote:
> > 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
>
>   Means it cached are tokens only (and it save lexical analyze for
> postmaster children), and final parsing (syntax analyze) running always?
>
>  If I'm right: why not store to memory some final structs with config
> file content? And for example things like 'strcmp(token, "password")'
> run only once during postmaster startup.

The patch will tokenize the file, discard comments, and store the tokens
as a List of Lists, one List per line.  We could go with data structures
and eliminate the strncmp of fixed strings and conversion of inet
addresses to  inet values but it doesn't seemw worth it.  Certainly, now
that the code is completed overhauled, doing something like that will be
easier.  The hba.c code clearly needed an overhaul anyway.

--
  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