New files and modifications to support client authentication (pool_hba).
authorUser yamaguti <yamaguti at pgfoundry.org>
Thu, 1 Feb 2007 15:31:59 +0000 (15:31 +0000)
committerUser yamaguti <yamaguti at pgfoundry.org>
Thu, 1 Feb 2007 15:31:59 +0000 (15:31 +0000)
25 files changed:
Makefile.am
Makefile.in
README
README.euc_jp
ac_func_accept_argtypes.m4 [new file with mode: 0644]
aclocal.m4
child.c
config.h.in
configure
configure.in
main.c
pgpool.conf.sample
pool.h
pool_config.c
pool_config.l
pool_hba.c [new file with mode: 0644]
pool_hba.conf.sample [new file with mode: 0644]
pool_ip.c [new file with mode: 0644]
pool_ip.h [new file with mode: 0644]
pool_list.c [new file with mode: 0644]
pool_list.h [new file with mode: 0644]
pool_path.c [new file with mode: 0644]
pool_path.h [new file with mode: 0644]
pool_process_query.c
pool_type.h [new file with mode: 0644]

index 71eb178b5af92001cda6078edb608b2595b011d4..2e97714e352ecc34bd845aaa4b9a2a160e013283 100644 (file)
@@ -4,12 +4,14 @@ pgpool_SOURCES = pool.h version.h pgpool.conf.sample \
        README.euc_jp pgpool.spec \
        main.c child.c pool_auth.c pool_config.l pool_error.c \
        pool_process_query.c pool_stream.c pool_connection_pool.c pool_params.c \
-       pool_signal.h pool_signal.c ps_status.c strlcpy.c
+       pool_signal.h pool_signal.c ps_status.c strlcpy.c \
+       pool_hba.c pool_list.h pool_list.c pool_path.h pool_path.c \
+       pool_type.h pool_ip.h pool_ip.c pool_hba.conf.sample
 
 DEFS = @DEFS@ \
        -DDEFAULT_CONFIGDIR=\"$(sysconfdir)\"
 
-sysconf_DATA = pgpool.conf.sample
+sysconf_DATA = pgpool.conf.sample pool_hba.conf.sample
 
 AM_CPPFLAGS = -Wall -Wmissing-prototypes -Wmissing-declarations -D_GNU_SOURCE
 
index 6f77c6513db6cf0f9e43fe024a4177f4f5bafb0b..1d34735ba4e700f6f40dc1f460aaa468b7d1081a 100644 (file)
@@ -42,7 +42,8 @@ DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \
        $(top_srcdir)/configure AUTHORS COPYING ChangeLog INSTALL NEWS \
        TODO depcomp install-sh missing mkinstalldirs pool_config.c
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__aclocal_m4_deps = $(top_srcdir)/ac_func_accept_argtypes.m4 \
+       $(top_srcdir)/configure.in
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
 am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
@@ -58,7 +59,9 @@ am_pgpool_OBJECTS = main.$(OBJEXT) child.$(OBJEXT) pool_auth.$(OBJEXT) \
        pool_config.$(OBJEXT) pool_error.$(OBJEXT) \
        pool_process_query.$(OBJEXT) pool_stream.$(OBJEXT) \
        pool_connection_pool.$(OBJEXT) pool_params.$(OBJEXT) \
-       pool_signal.$(OBJEXT) ps_status.$(OBJEXT) strlcpy.$(OBJEXT)
+       pool_signal.$(OBJEXT) ps_status.$(OBJEXT) strlcpy.$(OBJEXT) \
+       pool_hba.$(OBJEXT) pool_list.$(OBJEXT) pool_path.$(OBJEXT) \
+       pool_ip.$(OBJEXT)
 pgpool_OBJECTS = $(am_pgpool_OBJECTS)
 pgpool_LDADD = $(LDADD)
 DEFAULT_INCLUDES = -I. -I$(srcdir) -I.
@@ -176,9 +179,11 @@ pgpool_SOURCES = pool.h version.h pgpool.conf.sample \
        README.euc_jp pgpool.spec \
        main.c child.c pool_auth.c pool_config.l pool_error.c \
        pool_process_query.c pool_stream.c pool_connection_pool.c pool_params.c \
-       pool_signal.h pool_signal.c ps_status.c strlcpy.c
+       pool_signal.h pool_signal.c ps_status.c strlcpy.c \
+       pool_hba.c pool_list.h pool_list.c pool_path.h pool_path.c \
+       pool_type.h pool_ip.h pool_ip.c pool_hba.conf.sample
 
-sysconf_DATA = pgpool.conf.sample
+sysconf_DATA = pgpool.conf.sample pool_hba.conf.sample
 AM_CPPFLAGS = -Wall -Wmissing-prototypes -Wmissing-declarations -D_GNU_SOURCE
 man_MANS = pgpool.8
 CLEANFILES = pgpool.8
@@ -277,7 +282,11 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pool_config.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pool_connection_pool.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pool_error.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pool_hba.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pool_ip.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pool_list.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pool_params.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pool_path.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pool_process_query.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pool_signal.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pool_stream.Po@am__quote@
diff --git a/README b/README
index f04d32f9b6cf72f3e2311bd1bc7ee89886c74ef8..353553dfc7b80e343b133596df2196dfcd6a3f80 100644 (file)
--- a/README
+++ b/README
@@ -17,7 +17,7 @@ pgpool version 3.1 README
    secondary server.
 
    Moreover, pgpool supports scheduled switch over. See
-   "9. Switchover" for more details.
+   "10. Switchover" for more details.
 
 1.1 About replication facility of pgpool
 
@@ -222,8 +222,9 @@ pgpool version 3.1 README
 
       Default installation directories are:
 
-      /usr/local/bin/pgpool            pgpool executable
-      /usr/local/etc/pgpool.conf.sample        example configuration file
+      /usr/local/bin/pgpool                    pgpool executable
+      /usr/local/etc/pgpool.conf.sample                example configuration file
+      /usr/local/etc/pool_hba.conf.sample      example HBA configuration file
 
       You could change the installation directory by giving --prefix
       option to configure:
@@ -234,7 +235,7 @@ pgpool version 3.1 README
 
    pgpool.conf is the configuration file for pgpool.
 
-   Copy pgpool.conf.sample as pgpool.conf and change it if neccessary.
+   Copy pgpool.conf.sample as pgpool.conf and change it if necessary.
 
    Here is a explanation of pgpool.conf's grammar.
 
@@ -479,7 +480,81 @@ pgpool version 3.1 README
    to PostgreSQL, this allows for observing queries without engaging in full
    debugging.
 
-7. Starting pgpool
+   log_connections
+
+   If true, all incoming connections will be printed to the log.
+
+   enable_pool_hba
+
+   If true, use pool_hba.conf for client authentication. In pgpool 3.2,
+   the default value is false. This parameter is planned to be deleted
+   in the next version of pgpool, and pool_hba.conf will always be used.
+   See "7. Setting up pool_hba.conf for client authentication".
+
+7. Setting up pool_hba.conf for client authentication (HBA)
+
+  Just like pg_hba.conf with PostgreSQL, pgpool supports a similar
+  client authentication function using a configuration file called 
+  "pool_hba.conf".
+
+  When you install pgpool, pool_hba.conf.sample will be installed in
+  "/usr/local/etc", which is the default directory for configuration
+  files.
+
+  Copy pool_hba.conf.sample as pool_hba.conf and edit it if necessary.
+  By default, pool_hba authentication is disabled for backward 
+  compatibility. To enable it, set enable_pool_hba to true in
+  pgpool.conf. See "6. Setting up pgpool.conf" for more detail.
+
+  The format of pool_hba.conf file follows very closely to pg_hba.conf.
+
+    local      DATABASE  USER  METHOD  [OPTION]
+    host       DATABASE  USER  CIDR-ADDRESS  METHOD  [OPTION]
+
+  See "pool_hba.conf.sample" for details of each field.
+
+  Here are the limitations of pool_hba.
+
+  * "hostssl" connection type is not supported
+
+    "hostssl" is invalid since pgpool currently does not support SSL
+    connections.
+
+  * "samegroup" for DATABASE field is not supported
+
+    Since pgpool does not know anything about users in the backend server,
+    database name is simply checked against the entries in the DATABASE
+    field of pool_hba.conf.
+
+  * group names following "+" for USER field is not supported
+
+    This is the same reason as in the "samegroup" described above. A
+    user name is simply checked against the entries in the USER field
+    of pool_hba.conf.
+
+  * IPv6 for IP address/mask is not supported
+
+    pgpool currently does not support IPv6.
+
+  * Only "trust", "reject" and "pam" for METHOD field are supported
+
+    Again, this is the same reason as in the "samegroup" described above.
+    pgpool does not hold user/password information.
+  
+  Note that everything described in this section is about a client authen-
+  tication between a client and pgpool; a client still have to go through
+  an authentication process with PostgreSQL. As far as pool_hba is concerned,
+  it does not matter if a user name and/or database name given by a client
+  (i.e. psql -U testuser testdb) really exist in the backend. pool_hba only
+  cares if a match in the pool_hba.conf is found or not.
+
+  PAM authenticaion is supported using user information on the host where
+  pgpool is executed. To enable PAM support in pgpool, specify "--with-pam"
+  option to configure:
+
+    configure --with-pam
+
+8. Starting pgpool
 
    The simplist way to start pgpool is:
 
@@ -493,6 +568,10 @@ pgpool version 3.1 README
 
    the path to the configuration file.
 
+   -a path
+
+   the path to the pool_hba configuration file.
+
    -n
 
    do not start as daemon. Error messages go to stdout or stderr. Thus
@@ -507,7 +586,7 @@ pgpool version 3.1 README
 
    print the help message and quit
 
-8. Stopping pgpool
+9. Stopping pgpool
 
    You can stop pgpool by using "stop" option:
 
@@ -524,7 +603,7 @@ pgpool version 3.1 README
 
    $ pgpool -m i[mmediate] stop
 
-9. switchover
+10. switchover
 
    For maintenance purpose, scheduled switching or degeneration is
    supported.
@@ -540,7 +619,7 @@ pgpool version 3.1 README
    If there's only one PostgreSQL server, pgpool switch will just
    restart pgpool child processes.
 
-10. how to get logging
+11. how to get logging
 
    You could save messages from pgpool to a file by starting it with
    -n option:
@@ -551,14 +630,14 @@ pgpool version 3.1 README
 
    pgpool -n 2>&1 |logger -t pgpool -p local0.info&
 
-11. getting internal status of pgpool
+12. getting internal status of pgpool
 
     You could use psql or whatever to obtain the internal status of
     pgpool by issuing a special SQL command:
 
     psql -p 9999 -c 'show pool_status' template1
 
-             item             |                        value                         |                              description                               
+             item             |                        value                         |                              description
 ------------------------------+------------------------------------------------------+------------------------------------------------------------------------
  listen_addresses             | *                                                    | host name(s) or IP address(es) to listen to
  port                         | 9998                                                 | pgpool accepting port number
@@ -570,6 +649,7 @@ pgpool version 3.1 README
  num_init_children            | 32                                                   | # of children initially pre-forked
  child_life_time              | 0                                                    | if idle for this seconds, child exits
  connection_life_time         | 0                                                    | if idle for this seconds, connection closes
+ child_max_connections        | 0                                                    | if max_connections received, chile exits
  max_pool                     | 2                                                    | max # of connection pool per child
  logdir                       | /tmp                                                 | logging directory
  backend_socket_dir           | /tmp                                                 | Unix domain socket directory for the PostgreSQL server
@@ -588,13 +668,17 @@ pgpool version 3.1 README
  health_check_period          | 0                                                    | health check period
  health_check_user            | t-ishii                                              | health check user
  insert_lock                  | 1                                                    | insert lock
+ ignore_leading_white_space   | 0                                                    | ignore leading white spaces
  current_backend_host_name    |                                                      | current master host name
  current_backend_port         | 5432                                                 | current master port #
  replication_enabled          | 1                                                    | non 0 if actually operating in replication mode
  master_slave_enabled         | 0                                                    | non 0 if actually operating in master/slave
  num_reset_queries            | 3                                                    | number of queries in reset_query_list
+ log_statement                | 0                                                    | if true, print all statements to the log
+ log_connections              | 1                                                    | if true, print incoming connections to the log
+ enable_pool_hba              | 1                                                    | if true, use pool_hba.conf for client authentication
  server_status                | master( on 5432) up secondary( on 5433) up           | server status
-(34 rows)
+(39 rows)
 
 By using contrib/dblink, you can see part of the result of
 show_pool_status someting like:
@@ -606,13 +690,13 @@ test=# SELECT * FROM dblink('port=9999 dbname=test', 'show pool_status')
  port  | 9999
 (1 row)
 
-12. Playing with regression test
+13. Playing with regression test
 
    $ cd /usr/local/src/postgresql-7.4.5/src/test/regress
    $ make all
    $ ./pg_regress --schedule=parallel_schedule --port=9999
 
-13. Playing with benchmarking
+14. Playing with benchmarking
 
    Here is a brief explanation how to play with benchmarking using pgbench/PHP/ab.
 
@@ -641,7 +725,7 @@ test=# SELECT * FROM dblink('port=9999 dbname=test', 'show pool_status')
 
   $ /usr/local/apache/bin/ab -c 100 -n 1000 "http://localhost/bench.php"
 
-14. master/slave mode
+15. master/slave mode
 
   master/slave mode is designed to cope with master/slave replication
   softwares, such as Slony-I. To enable this mode, you need to set
@@ -658,7 +742,7 @@ test=# SELECT * FROM dblink('port=9999 dbname=test', 'show pool_status')
 
   2) in all other case, quries are sent to only master
 
-15. Multiple simultaneous instances of pgpool
+16. Multiple simultaneous instances of pgpool
 
   In order to run multiple instances of pgpool on the same server  
   simultaneously (in order to have two separate, non-conflicting  
index 516284e25271822e44d0bde71a1cde6b4884d60c..b163aea06d18216ff29c31687d5621c5d3e41a23 100644 (file)
@@ -21,7 +21,7 @@ pgpool version 3.1(kalekale) README
 
    ¤Ê¤ª¡¤¥Õ¥§¥¤¥ë¥ª¡¼¥Ð¤ä½ÌÂ౿ž¤Ï²¿¤«¾ã³²¤¬µ¯¤­¤¿¤³¤È¤ò¥È¥ê¥¬¤Ë¤·¤Æ
    µ¯Æ°¤µ¤ì¤Þ¤¹¤¬¡¤¥á¥¤¥ó¥Æ¥Ê¥ó¥¹¤Ê¤É¤Î¤¿¤á¤Ë°Õ¿ÞŪ¤Ë¥Õ¥§¥¤¥ë¥ª¡¼¥Ð¤ä
-   ½ÌÂ౿ž¥â¡¼¥É¤Ë°Ü¹Ô¤¹¤ë¤³¤È¤â¤Ç¤­¤Þ¤¹¡¥¾ÜºÙ¤Ï¡Ö9. ¥¹¥¤¥Ã¥Á¥ª¡¼¥Ð¡×
+   ½ÌÂ౿ž¥â¡¼¥É¤Ë°Ü¹Ô¤¹¤ë¤³¤È¤â¤Ç¤­¤Þ¤¹¡¥¾ÜºÙ¤Ï¡Ö10. ¥¹¥¤¥Ã¥Á¥ª¡¼¥Ð¡×
    ¤ò¤´Í÷²¼¤µ¤¤¡¥
 
 1.1 ¥ì¥×¥ê¥±¡¼¥·¥ç¥ó¤Ë¤Ä¤¤¤Æ
@@ -342,8 +342,9 @@ pgpool version 3.1(kalekale) README
       make¤ògmake¤ËÆÉ¤ßÂØ¤¨¤Æ¤¯¤À¤µ¤¤)¡¥¥Ç¥Õ¥©¥ë¥È¤Î¥¤¥ó¥¹¥È¡¼¥ëÀè¤Ï¡¤
       /usr/local°Ê²¼¤Ç°Ê²¼¤Î¤è¤¦¤Ê¥Õ¥¡¥¤¥ë¤¬¥¤¥ó¥¹¥È¡¼¥ë¤µ¤ì¤Þ¤¹¡¥
 
-      /usr/local/bin/pgpool    ¥×¥í¥°¥é¥àËÜÂÎ
-      /usr/local/etc/pgpool.conf.sample        ÀßÄê¥Õ¥¡¥¤¥ë¥µ¥ó¥×¥ë
+      /usr/local/bin/pgpool                    ¥×¥í¥°¥é¥àËÜÂÎ
+      /usr/local/etc/pgpool.conf.sample                ÀßÄê¥Õ¥¡¥¤¥ë¥µ¥ó¥×¥ë
+      /usr/local/etc/pool_hba.conf.sample      HBAÀßÄê¥Õ¥¡¥¤¥ë¥µ¥ó¥×¥ë
 
       ¥¤¥ó¥¹¥È¡¼¥ëÀè¤òÊѹ¹¤¹¤ë¾ì¹ç¤Ï¡¤configure --prefix=path... ¤È¤·
       ¤Æ¤¯¤À¤µ¤¤¡¥
@@ -665,7 +666,86 @@ pgpool version 3.1(kalekale) README
    log_statement¥ª¥×¥·¥ç¥ó¤È»÷¤Æ¤¤¤Æ¡¤¥Ç¥Ð¥Ã¥°¥ª¥×¥·¥ç¥ó¤¬¤Ê¤¤¤È¤­¤Ç¤â
    Ì䤤¹ç¤ï¤»¤ò¥í¥°½ÐÎϤ·¤ÆÄ´¤Ù¤ë¤³¤È¤¬¤Ç¤­¤ë¤Î¤ÇÊØÍø¤Ç¤¹¡¥
 
-7. pgpool¤Îµ¯Æ°
+   log_connections
+
+   true¤Ê¤é¤Ð¡¢Á´¤Æ¤Î¥¯¥é¥¤¥¢¥ó¥ÈÀܳ¤ò¥í¥°¤Ø½ÐÎϤ·¤Þ¤¹¡£
+
+   enable_pool_conf
+
+   true¤Ê¤é¤Ð¡¢pool_hba.conf¤Ë½¾¤Ã¤Æ¥¯¥é¥¤¥¢¥ó¥Èǧ¾Ú¤ò¹Ô¤¤¤Þ¤¹¡£pgpool
+   3.2¤Î¥Ç¥Õ¥©¥ë¥ÈÃͤÏfalse¤È¤Ê¤Ã¤Æ¤¤¤Þ¤¹¤¬¡¢¼¡¤Î¥ê¥ê¡¼¥¹¥Ð¡¼¥¸¥ç¥ó¤Ç
+   ¤Ï¤³¤Î¥Ñ¥é¥á¡¼¥¿¤Ïºï½ü¤µ¤ì¡¢¾ï¤Ëpool_hba.conf¤Ë¤è¤ë¥¯¥é¥¤¥ó¥¢¥ó¥Èǧ
+   ¾Ú¤¬¹Ô¤ï¤ì¤ëͽÄê¤Ç¤¹¡£¾ÜºÙ¤Ï¡Ö7. ¥¯¥é¥¤¥¢¥ó¥Èǧ¾Ú(HBA)¤Î¤¿¤á¤Î
+   pool_hba.confÀßÄêÊýË¡¡×¤ò»²¾È¤·¤Æ¤¯¤À¤µ¤¤¡£
+
+7. ¥¯¥é¥¤¥¢¥ó¥Èǧ¾Ú(HBA)¤Î¤¿¤á¤Î pool_hba.conf ÀßÄêÊýË¡
+
+   PostgreSQL¤Îpg_hba.conf¤ÈƱ¤¸¤è¤¦¤Ëpgpool¤Ç¤âpool_config.conf¥Õ¥¡¥¤
+   ¥ë¤ò»È¤Ã¤¿¥¯¥é¥¤¥¢¥ó¥Èǧ¾Ú¤¬¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤Þ¤¹¡£
+
+   pgpool¤ò¥¤¥ó¥¹¥È¡¼¥ë¤¹¤ë¤È¥Ç¥Õ¥©¥ë¥È¥¤¥ó¥¹¥È¡¼¥ëÀè¤ÎÀßÄê¥Õ¥¡¥¤¥ë¥Ç¥£
+   ¥ì¥¯¥È¥ê"/usr/local/etc"¤Ëpool_hba.conf.sample¤¬°ì½ï¤Ë¥¤¥ó¥¹¥È¡¼¥ë
+   ¤µ¤ì¤Þ¤¹¡£
+
+   ¤³¤Îpool_hba.conf.sample¥Õ¥¡¥¤¥ë¤òpool_hba.conf¤È¤·¤Æ¥³¥Ô¡¼¤·¡¢É¬Í×
+   ¤Ç¤¢¤ì¤ÐÊÔ½¸¤·¤Æ¤¯¤À¤µ¤¤¡£¥Ç¥Õ¥©¥ë¥È¤Ç¤Ïpool_hba¤Ë¤è¤ëǧ¾Ú¤Ï̵¸ú¤Ë
+   ¤Ê¤Ã¤Æ¤¤¤Þ¤¹¡£¤³¤ì¤Ï°ÊÁ°¤Îpgpool¤È¤Î¸ß´¹À­¤òÊݤĤ¿¤á¤Ç¤¹¡£Í­¸ú¤Ë¤¹
+   ¤ë¤¿¤á¤Ë¤Ïpgpool.conf¤Îenable_pool_hba¤òtrue¤ËÀßÄꤹ¤ëɬÍפ¬¤¢¤ê¤Þ
+   ¤¹¡£
+
+   pool_hba.conf¤Î¥Õ¥©¡¼¥Þ¥Ã¥È¤Ïpg_hba.conf¤Î¤â¤Î¤È¤Û¤È¤ó¤ÉƱ¤¸¤Ç¤¹¡£
+
+     local      DATABASE  USER  METHOD  [OPTION]
+     host       DATABASE  USER  CIDR-ADDRESS  METHOD  [OPTION]
+
+   ³Æ¥Õ¥£¡¼¥ë¥É¤ÇÀßÄê¤Ç¤­¤ëÃͤξܺ٤Ï"pool_hba.conf.sample"¤ò»²¾È¤·¤Æ
+   ¤¯¤À¤µ¤¤¡£
+
+   °Ê²¼¤Ïpool_hba¤ÎÀ©¸Â»ö¹à¤Ç¤¹¡£
+
+   * "hostssl"Àܳ¥¿¥¤¥×¤Ï¥µ¥Ý¡¼¥È¤µ¤ì¤Þ¤»¤ó
+
+     ¸½ºßpgpool¤ÏSSLÀܳ¤ò¥µ¥Ý¡¼¥È¤·¤Æ¤¤¤Ê¤¤¤Î¤Ç"hostssl"¤Ï»ØÄꤹ¤ë¤³
+     ¤È¤¬¤Ç¤­¤Þ¤»¤ó¡£
+
+   * DATABASE¥Õ¥£¡¼¥ë¥ÉÃͤȤ·¤Æ"samegroup"¤Ï¥µ¥Ý¡¼¥È¤µ¤ì¤Þ¤»¤ó
+
+     pgpool¤Ï¥Ð¥Ã¥¯¥¨¥ó¥É¥µ¡¼¥Ð¤Ë¤¢¤ë¥æ¡¼¥¶¾ðÊó¤ò»öÁ°¤ËÃΤë»ö¤¬¤Ç¤­¤Ê
+     ¤¤¤¿¤á¡¢¥Ç¡¼¥¿¥Ù¡¼¥¹Ì¾¤Ïpool_hba.conf¤Ë¤¢¤ëÃͤΤߤÈÈæ³Ó¤µ¤ì¤Þ¤¹¡£
+     ¤Ê¤Î¤Ç¥°¥ë¡¼¥×¤Ë´Ø¤¹¤ëǧ¾Ú¤Ïpool_hba¤Ç¹Ô¤¦¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¡£
+
+   * USER¥Õ¥£¡¼¥ë¥ÉÃͤȤ·¤Æ"+"¤ò»È¤Ã¤¿¥°¥ë¡¼¥×»ØÄê¤Ï¥µ¥Ý¡¼¥È¤µ¤ì¤Þ¤»¤ó
+
+     ¾åµ­¤Î"samegroup"¤ÈƱ¤¸Íýͳ¤Ç¡¢¥æ¡¼¥¶Ì¾¤Ïpool_hba.conf¤Ë¤¢¤ëÃͤÎ
+     ¤ß¤ÈÈæ³Ó¤µ¤ì¤Þ¤¹¡£¥°¥ë¡¼¥×¤Ë´Ø¤¹¤ëǧ¾Ú¤Ïpool_hba¤Ç¹Ô¤¦¤³¤È¤Ï¤Ç¤­
+     ¤Þ¤»¤ó¡£
+
+   * IPv6¥¢¥É¥ì¥¹/¥Þ¥¹¥¯É½µ­Ë¡¤Ï¥µ¥Ý¡¼¥È¤µ¤ì¤Þ¤»¤ó
+
+     ¸½ºßpgpool¤ÏIPv6¤ò¥µ¥Ý¡¼¥È¤·¤Æ¤¤¤Þ¤»¤ó¡£
+
+   * "trust", "reject", "pam"°Ê³°¤Î¥á¥½¥Ã¥É¤Ï¥µ¥Ý¡¼¥È¤µ¤ì¤Þ¤»¤ó
+
+     ¤³¤ì¤â¾åµ­¤Î"samegroup"¤ÈƱ¤¸Íýͳ¤Ë¤è¤ë¤â¤Î¤Ç¤¹¡£pgpool¤Ï¥Ð¥Ã¥¯¥¨
+     ¥ó¥É¤Î¥æ¡¼¥¶/¥Ñ¥¹¥ï¡¼¥É¾ðÊó¤ò»ý¤Ã¤Æ¤¤¤Ê¤¤¤Î¤Ç¡¢¥Ð¥Ã¥¯¥¨¥ó¥É¤ËÊݸ
+     ¤µ¤ì¤Æ¤¤¤ë¥Ñ¥¹¥ï¡¼¥É¤ò»È¤Ã¤¿Ç§¾Ú¤ò¹Ô¤¦¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¡£
+
+   ¤³¤³¤ÇÀâÌÀ¤µ¤ì¤¿µ¡Ç½¡¢À©¸Â¤Ï¥¯¥é¥¤¥¢¥ó¥È¤Èpgpool´Ö¤Ç¹Ô¤ï¤ì¤ë¥¯¥é¥¤
+   ¥¢¥ó¥Èǧ¾Ú¤Ë¤Ä¤¤¤Æ¤À¤È¤¤¤¦¤³¤È¤ËÃí°Õ¤·¤Æ¤¯¤À¤µ¤¤¡£¥¯¥é¥¤¥ó¥¢¥ó¥È¤Ï
+   pgpool¤Î¥¯¥é¥¤¥¢¥ó¥Èǧ¾Ú¤ËÀ®¸ù¤·¤¿¤È¤·¤Æ¤â¡¢PostgreSQL¤Ë¤è¤ë¥¯¥é¥¤
+   ¥¢¥ó¥Èǧ¾Ú¤ËÀ®¸ù¤·¤Ê¤¤¤ÈÀܳ¾õÂ֤Ȥʤê¤Þ¤»¤ó¡£pool_hba¤Ë¤È¤Ã¤Æ¤Ï¥¯
+   ¥é¥¤¥¢¥ó¥È¤Ë»ØÄꤵ¤ì¤¿¥æ¡¼¥¶Ì¾¤ä¥Ç¡¼¥¿¥Ù¡¼¥¹Ì¾
+   (Îã. psql -U testuser testdb)¤¬¼ÂºÝ¤Ë¥Ð¥Ã¥¯¥¨¥ó¥É¾å¤Ë¸ºß¤¹¤ë¤«¤É¤¦
+   ¤«¤ÏÌäÂê¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó¡£¤½¤ì¤¬pool_hba.conf¤ÎÃͤȥޥåÁ¤¹¤ë¤«¤É¤¦¤«
+   ¤Ç¥Á¥§¥Ã¥¯¤¬¹Ô¤ï¤ì¤Þ¤¹¡£
+
+   pgpool¤¬²ÔƯ¤¹¤ë¥Û¥¹¥È¾å¤Î¥æ¡¼¥¶¾ðÊó¤ò»È¤Ã¤¿PAMǧ¾Ú¤òÍøÍѤ¹¤ë¤³¤È¤¬
+   ¤Ç¤­¤Þ¤¹¡£pgpool¤òPAM¥µ¥Ý¡¼¥ÈÉÕ¤­¤Ç¥Ó¥ë¥É¤¹¤ë¤Ë¤Ïconfigure¥ª¥×¥·¥ç
+   ¥ó¤Ë"--with-pam"¤ò»ØÄꤷ¤Æ¤¯¤À¤µ¤¤¡£
+
+     configure --with-pam
+
+8. pgpool¤Îµ¯Æ°
 
    pgpool¤òµ¯Æ°¤¹¤ë¤â¤Ã¤È¤â´Êñ¤ÊÊýË¡¤Ï¡¤
 
@@ -693,7 +773,7 @@ pgpool version 3.1(kalekale) README
 
    ¥Ø¥ë¥×¥á¥Ã¥»¡¼¥¸¤ò½ÐÎϤ·¤Æ½ªÎ»¤·¤Þ¤¹¡¥
 
-8. pgpool¤Î½ªÎ»
+9. pgpool¤Î½ªÎ»
 
    ¡Östop¡×¥ª¥×¥·¥ç¥ó¤ò»È¤¤¤Þ¤¹¡¥
 
@@ -725,7 +805,7 @@ pgpool version 3.1(kalekale) README
 
    ¤È¤¹¤ë¤È¡¤pgpool stop¤ÈƱ¤¸Æ°ºî¤ò¤·¤Þ¤¹¡¥
 
-9. ¥¹¥¤¥Ã¥Á¥ª¡¼¥Ð
+10. ¥¹¥¤¥Ã¥Á¥ª¡¼¥Ð
 
    ¥á¥¤¥ó¥Æ¥Ê¥ó¥¹¤Ê¤É¤Î¤¿¤á¤Ë°Õ¿ÞŪ¤Ë¥Õ¥§¥¤¥ë¥ª¡¼¥Ð¤ä½ÌÂ౿ž¥â¡¼¥É¤Ë
    °Ü¹Ô¤¹¤ë¤³¤È¤¬¤Ç¤­¤Þ¤¹¡¥
@@ -744,7 +824,7 @@ pgpool version 3.1(kalekale) README
    ¥ó¥È¤«¤épgpool¤Ø¤Î¥³¥Í¥¯¥·¥ç¥ó¤ò¶¯À©Åª¤Ë°ìÅÙÀÚÃǤ·¡¤pgpool¤Î»Ò¥×¥í
    ¥»¥¹¤¬ºÆµ¯Æ°¤µ¤ì¤Þ¤¹¡¥
 
-10. ¥í¥°¤Î¼è¤êÊý
+11. ¥í¥°¤Î¼è¤êÊý
 
    pgpool¤ò-n¥ª¥×¥·¥ç¥óÉդǵ¯Æ°¤¹¤ë¤È¡¤stderr(ɸ½à¥¨¥é¡¼½ÐÎÏ)¤Ë¥¨¥é¡¼
    ¤ä½ÅÂç¤Ê¾ðÊó(¤¿¤È¤¨¤Ð¥Õ¥§¥¤¥ë¥ª¡¼¥Ð¤·¤¿¤è¤¦¤Ê¾ì¹ç)¤Ë´Ø¤¹¤ë¥á¥Ã¥»¡¼
@@ -773,7 +853,7 @@ pgpool version 3.1(kalekale) README
    Apr 13 15:07:11 srapc1977  4·î 13 15:07:11 pgpool: log: pid 2038: failover from (5432) to (5433) done.
 
 
-11. pgpool¤ÎÆâÉô¾ðÊó¤Î¼èÆÀ
+12. pgpool¤ÎÆâÉô¾ðÊó¤Î¼èÆÀ
 
     pgpool¤¬Ç§¼±¤·¤Æ¤¤¤ëÀßÄê¥Õ¥¡¥¤¥ë(pgpool.conf)¤ÎÆâÍÆ¤ä¡¤¸½ºß¤Î¥ì¥×
     ¥ê¥±¡¼¥·¥ç¥ó¤Î¾õÂÖ¤òSQL¤òȯ¹Ô¤¹¤ë¤³¤È¤Ë¤è¤Ã¤Æ¼èÆÀ¤¹¤ë¤³¤È¤¬¤Ç¤­¤Þ
@@ -784,8 +864,7 @@ pgpool version 3.1(kalekale) README
 
     (¥Ç¡¼¥¿¥Ù¡¼¥¹Ì¾¤Ï²¿¤Ç¤â¤«¤Þ¤¤¤Þ¤»¤ó)¡¥
 
-             item             |                        value                         |                              description                               
-------------------------------+------------------------------------------------------+------------------------------------------------------------------------
+             item             |                        value                         |                              description                                                   --------------------------------+------------------------------------------------------+------------------------------------------------------------------------
  listen_addresses             | *                                                    | host name(s) or IP address(es) to listen to
  port                         | 9998                                                 | pgpool accepting port number
  socket_dir                   | /tmp                                                 | pgpool socket directory
@@ -796,6 +875,7 @@ pgpool version 3.1(kalekale) README
  num_init_children            | 32                                                   | # of children initially pre-forked
  child_life_time              | 0                                                    | if idle for this seconds, child exits
  connection_life_time         | 0                                                    | if idle for this seconds, connection closes
+ child_max_connections        | 0                                                    | if max_connections received, chile exits
  max_pool                     | 2                                                    | max # of connection pool per child
  logdir                       | /tmp                                                 | logging directory
  backend_socket_dir           | /tmp                                                 | Unix domain socket directory for the PostgreSQL server
@@ -814,13 +894,17 @@ pgpool version 3.1(kalekale) README
  health_check_period          | 0                                                    | health check period
  health_check_user            | t-ishii                                              | health check user
  insert_lock                  | 1                                                    | insert lock
+ ignore_leading_white_space   | 0                                                    | ignore leading white spaces
  current_backend_host_name    |                                                      | current master host name
  current_backend_port         | 5432                                                 | current master port #
  replication_enabled          | 1                                                    | non 0 if actually operating in replication mode
  master_slave_enabled         | 0                                                    | non 0 if actually operating in master/slave
  num_reset_queries            | 3                                                    | number of queries in reset_query_list
+ log_statement                | 0                                                    | if true, print all statements to the log
+ log_connections              | 1                                                    | if true, print incoming connections to the log
+ enable_pool_hba              | 1                                                    | if true, use pool_hba.conf for client authentication
  server_status                | master( on 5432) up secondary( on 5433) up           | server status
-(34 rows)
+(39 rows)
 
 contrib/dblink¤ò»È¤¨¤Ð¡¤°Ê²¼¤Î¤è¤¦¤Ë¤·¤Æ°ìÉô¤Î·ë²Ì¤À¤±¤ò¸«¤ë¤³¤È¤¬¤Ç¤­
 ¤Þ¤¹¡¥
@@ -832,7 +916,7 @@ test=# SELECT * FROM dblink('port=9999 dbname=test', 'show pool_status')
  port  | 9999
 (1 row)
 
-12. regression test¤Î¼Â»Ü
+13. regression test¤Î¼Â»Ü
 
    °Ê²¼¤Î¤è¤¦¤Ë¤·¤Æpgpool¤òÊ»ÍѤ·¤Æregression test¤ò¹Ô¤¦¤³¤È¤¬¤Ç¤­¤Þ¤¹¡¥
 
@@ -845,7 +929,7 @@ test=# SELECT * FROM dblink('port=9999 dbname=test', 'show pool_status')
    ¥ì¥×¥ê¥±¡¼¥·¥ç¥ó¥â¡¼¥É¤Çregression test¤ò¤¹¤ë¤Èɬ¤ºtablespace¤Î¥Æ¥¹
    ¥È¤¬fail¤·¤Þ¤¹¤¬¡¤¤³¤ì¤Ï°Û¾ï¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó¡¥
 
-13. ¥Ù¥ó¥Á¥Þ¡¼¥¯¤Î¼Â»Ü
+14. ¥Ù¥ó¥Á¥Þ¡¼¥¯¤Î¼Â»Ü
 
    ¥Ù¥ó¥Á¥Þ¡¼¥¯¤ò¼Â»Ü¤¹¤ë¤Ë¤Ï¤¤¤í¤¤¤í¤ÊÊýË¡¤¬¤¢¤ê¤Þ¤¹¤¬¡¤¤³¤³¤Ç¤Ï
    pgbench¤ÈPHP¤½¤ì¤Ëab¤ò»È¤Ã¤¿´Êñ¤ÊÊýË¡¤ò¤´¾Ò²ð¤·¤Þ¤¹¡¥
@@ -874,7 +958,7 @@ test=# SELECT * FROM dblink('port=9999 dbname=test', 'show pool_status')
 
   $ /usr/local/apache/bin/ab -c 100 -n 1000 "http://localhost/bench.php"
 
-14. master/slave¥â¡¼¥É
+15. master/slave¥â¡¼¥É
 
   master/slave¥â¡¼¥É¤Ï¡¤Slony-I¤Î¤è¤¦¤Ê¡¤master/slave¼°¤Î¥ì¥×¥ê¥±¡¼¥·¥ç
   ¥ó¥½¥Õ¥È¤Ë¥ì¥×¥ê¥±¡¼¥·¥ç¥ó¤ò¤Þ¤«¤»¤ë¥â¡¼¥É¤Ç¤¹¡¥¤³¤Î¥â¡¼¥É¤Ç»È¤¦¤¿¤á¤Ë
@@ -895,7 +979,7 @@ test=# SELECT * FROM dblink('port=9999 dbname=test', 'show pool_status')
 
   2) 1)°Ê³°¤Î¾ì¹ç¤Ï¡¤¥Þ¥¹¥¿¤À¤±¤ËÌ䤤¹ç¤ï¤»¤¬Á÷¤é¤ì¤Þ¤¹¡¥
 
-15. Ê£¿ô¤Îpgpool¤òƱ¤¸¥Û¥¹¥È¤ÇΩ¤Á¾å¤²¤ë¤Ë¤Ï
+16. Ê£¿ô¤Îpgpool¤òƱ¤¸¥Û¥¹¥È¤ÇΩ¤Á¾å¤²¤ë¤Ë¤Ï
 
   Ê£¿ô¤Îpgpool¤òƱ¤¸¥Û¥¹¥È¤ÇΩ¤Á¾å¤²¤ë¤Ë¤Ï(¤¿¤È¤¨¤Ð2¤Ä¤ÎDB¥¯¥é¥¹¥¿¤òÊÌ¡¹
   ¤Ëpgpool¤Ç°·¤¦¥±¡¼¥¹)¡¤2¤Ä¤ÎÀßÄê¥Õ¥¡¥¤¥ë¤òºî¤ê¤Þ¤¹¡¥
diff --git a/ac_func_accept_argtypes.m4 b/ac_func_accept_argtypes.m4
new file mode 100644 (file)
index 0000000..917d59a
--- /dev/null
@@ -0,0 +1,85 @@
+# $PostgreSQL: pgsql/config/ac_func_accept_argtypes.m4,v 1.6 2003/11/29 19:51:17 pgsql Exp $
+# This comes from the official Autoconf macro archive at
+# <http://research.cys.de/autoconf-archive/>
+# (I removed the $ before the Id CVS keyword below.)
+
+
+dnl @synopsis AC_FUNC_ACCEPT_ARGTYPES
+dnl
+dnl Checks the data types of the three arguments to accept(). Results are
+dnl placed into the symbols ACCEPT_TYPE_RETURN and ACCEPT_TYPE_ARG[123], 
+dnl consistent with the following example:
+dnl
+dnl       #define ACCEPT_TYPE_RETURN int
+dnl       #define ACCEPT_TYPE_ARG1 int
+dnl       #define ACCEPT_TYPE_ARG2 struct sockaddr *
+dnl       #define ACCEPT_TYPE_ARG3 socklen_t
+dnl
+dnl This macro requires AC_CHECK_HEADERS to have already verified the
+dnl presence or absence of sys/types.h and sys/socket.h.
+dnl
+dnl NOTE: This is just a modified version of the AC_FUNC_SELECT_ARGTYPES
+dnl macro. Credit for that one goes to David MacKenzie et. al.
+dnl
+dnl @version Id: ac_func_accept_argtypes.m4,v 1.1 1999/12/03 11:29:29 simons Exp $
+dnl @author Daniel Richard G. <skunk@mit.edu>
+dnl
+
+# PostgreSQL local changes: In the original version ACCEPT_TYPE_ARG3
+# is a pointer type. That's kind of useless because then you can't
+# use the macro to define a corresponding variable. We also make the
+# reasonable(?) assumption that you can use arg3 for getsocktype etc.
+# as well (i.e., anywhere POSIX.2 has socklen_t).
+#
+# arg2 can also be `const' (e.g., RH 4.2). Change the order of tests
+# for arg3 so that `int' is first, in case there is no prototype at all.
+#
+# Solaris 7 and 8 have arg3 as 'void *' (disguised as 'Psocklen_t'
+# which is *not* 'socklen_t *').  If we detect that, then we assume
+# 'int' as the result, because that ought to work best.
+#
+# On Win32, accept() returns 'unsigned int PASCAL' 
+
+AC_DEFUN([AC_FUNC_ACCEPT_ARGTYPES],
+[AC_MSG_CHECKING([types of arguments for accept()])
+ AC_CACHE_VAL(ac_cv_func_accept_return,dnl
+ [AC_CACHE_VAL(ac_cv_func_accept_arg1,dnl
+  [AC_CACHE_VAL(ac_cv_func_accept_arg2,dnl
+   [AC_CACHE_VAL(ac_cv_func_accept_arg3,dnl
+    [for ac_cv_func_accept_return in 'int' 'unsigned int PASCAL'; do
+      for ac_cv_func_accept_arg1 in 'int' 'unsigned int'; do
+       for ac_cv_func_accept_arg2 in 'struct sockaddr *' 'const struct sockaddr *' 'void *'; do
+        for ac_cv_func_accept_arg3 in 'int' 'size_t' 'socklen_t' 'unsigned int' 'void'; do
+         AC_TRY_COMPILE(
+[#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+extern $ac_cv_func_accept_return accept ($ac_cv_func_accept_arg1, $ac_cv_func_accept_arg2, $ac_cv_func_accept_arg3 *);],
+         [], [ac_not_found=no; break 4], [ac_not_found=yes])
+       done
+      done
+     done
+    done
+    if test "$ac_not_found" = yes; then
+      AC_MSG_ERROR([could not determine argument types])
+    fi
+    if test "$ac_cv_func_accept_arg3" = "void"; then
+      ac_cv_func_accept_arg3=int
+    fi
+    ])dnl AC_CACHE_VAL
+   ])dnl AC_CACHE_VAL
+  ])dnl AC_CACHE_VAL
+ ])dnl AC_CACHE_VAL
+ AC_MSG_RESULT([$ac_cv_func_accept_return, $ac_cv_func_accept_arg1, $ac_cv_func_accept_arg2, $ac_cv_func_accept_arg3 *])
+ AC_DEFINE_UNQUOTED(ACCEPT_TYPE_RETURN, $ac_cv_func_accept_return,
+                    [Define to the return type of 'accept'])
+ AC_DEFINE_UNQUOTED(ACCEPT_TYPE_ARG1, $ac_cv_func_accept_arg1,
+                    [Define to the type of arg 1 of 'accept'])
+ AC_DEFINE_UNQUOTED(ACCEPT_TYPE_ARG2, $ac_cv_func_accept_arg2,
+                    [Define to the type of arg 2 of 'accept'])
+ AC_DEFINE_UNQUOTED(ACCEPT_TYPE_ARG3, $ac_cv_func_accept_arg3,
+                    [Define to the type of arg 3 of 'accept'])
+])
index 20ce300290d9fbd6f2aa7c1970dc6f7e81fa54ad..7258915b5e47964cf1b3ef2a928a35c762436c18 100644 (file)
@@ -881,3 +881,4 @@ AC_SUBST([am__tar])
 AC_SUBST([am__untar])
 ]) # _AM_PROG_TAR
 
+m4_include([ac_func_accept_argtypes.m4])
diff --git a/child.c b/child.c
index 40b466dcc5412752349e60949d6b2acbf6908a48..33684f322bca867f2782b4dfbef57032efd095ec 100644 (file)
--- a/child.c
+++ b/child.c
@@ -27,6 +27,8 @@
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <sys/un.h>
+#include <arpa/inet.h>
+#include <netdb.h>
 #ifdef HAVE_NETINET_TCP_H
 #include <netinet/tcp.h>
 #endif
@@ -45,6 +47,7 @@
 #endif
 
 #include "pool.h"
+#include "pool_ip.h"
 
 #ifdef NONE_BLOCK
 static void set_nonblock(int fd);
@@ -218,6 +221,29 @@ void do_child(int unix_fd, int inet_fd)
                        goto retry_startup;
                }
 
+               if (pool_config.enable_pool_hba)
+               {
+                       /*
+                        * do client authentication.
+                        * Note that ClientAuthentication does not return if frontend
+                        * was rejected; it simply terminates this process.
+                        */
+                       frontend->protoVersion = sp->major;
+                       frontend->database = strdup(sp->database);
+                       if (frontend->database == NULL)
+                       {
+                               pool_error("do_child: strdup failed: %s\n", strerror(errno));
+                               exit(1);
+                       }
+                       frontend->username = strdup(sp->user);
+                       if (frontend->username == NULL)
+                       {
+                               pool_error("do_child: strdup failed: %s\n", strerror(errno));
+                               exit(1);
+                       }
+                       ClientAuthentication(frontend);
+               }
+
                /*
                 * Ok, negotiaton with frontend has been done. Let's go to the next step.
                 */
@@ -490,8 +516,7 @@ static POOL_CONNECTION *do_accept(int unix_fd, int inet_fd, struct timeval *time
     fd_set     readmask;
     int fds;
 
-       struct sockaddr addr;
-       socklen_t addrlen;
+       SockAddr saddr;
        int fd = 0;
        int afd;
        int inet = 0;
@@ -590,12 +615,13 @@ static POOL_CONNECTION *do_accept(int unix_fd, int inet_fd, struct timeval *time
         * Note that some SysV systems do not work here. For those
         * systems, we need some locking mechanism for the fd.
         */
-       addrlen = sizeof(addr);
+       memset(&saddr, 0, sizeof(saddr));
+       saddr.salen = sizeof(saddr.addr);
 
 #ifdef ACCEPT_PERFORMANCE
        gettimeofday(&now1,0);
 #endif
-       afd = accept(fd, &addr, &addrlen);
+       afd = accept(fd, (struct sockaddr *)&saddr.addr, &saddr.salen);
        if (afd < 0)
        {
                /*
@@ -618,6 +644,30 @@ static POOL_CONNECTION *do_accept(int unix_fd, int inet_fd, struct timeval *time
        set_ps_display("accept connection", false);
        pool_debug("I am %d accept fd %d", getpid(), afd);
 
+       /* log who is connecting */
+       if (pool_config.log_connections)
+       {
+               char remote_host[NI_MAXHOST];
+               char remote_port[NI_MAXSERV];
+               
+               remote_host[0] = '\0';
+               remote_port[0] = '\0';
+               if (getnameinfo_all(&saddr.addr, saddr.salen,
+                                                       remote_host, sizeof(remote_host),
+                                                       remote_port, sizeof(remote_port),
+                                                       NI_NUMERICHOST | NI_NUMERICSERV))
+               {
+                       int ret = getnameinfo_all(&saddr.addr, saddr.salen,
+                                                                         remote_host, sizeof(remote_host),
+                                                                         remote_port, sizeof(remote_port),
+                                                                         NI_NUMERICHOST | NI_NUMERICSERV);
+                       if (ret)
+                               pool_error("getnameinfo_all() failed: %s", gai_strerror(ret));
+               }
+               pool_log("connection received: host=%s%s%s",
+                                remote_host, remote_port[0] ? " port=" : "", remote_port);
+       }
+
        /* set NODELAY and KEEPALIVE options if INET connection */
        if (inet)
        {
@@ -646,6 +696,12 @@ static POOL_CONNECTION *do_accept(int unix_fd, int inet_fd, struct timeval *time
                close(afd);
                return NULL;
        }
+
+       /* save ip addres for hba */
+       memcpy(&cp->raddr, &saddr, sizeof(SockAddr));
+       if (cp->raddr.addr.ss_family == 0)
+               cp->raddr.addr.ss_family = AF_UNIX;
+       
        return cp;
 }
 
index 44d2ad3963f43d71d9154e55fc1d50507cdfa0a7..91589de329bba7b1cdd5365bd9f67b774c3b8a3d 100644 (file)
@@ -1,5 +1,17 @@
 /* config.h.in.  Generated from configure.in by autoheader.  */
 
+/* Define to the type of arg 1 of 'accept' */
+#undef ACCEPT_TYPE_ARG1
+
+/* Define to the type of arg 2 of 'accept' */
+#undef ACCEPT_TYPE_ARG2
+
+/* Define to the type of arg 3 of 'accept' */
+#undef ACCEPT_TYPE_ARG3
+
+/* Define to the return type of 'accept' */
+#undef ACCEPT_TYPE_RETURN
+
 /* Define to 1 if you have the `asprintf' function. */
 #undef HAVE_ASPRINTF
 
@@ -36,6 +48,9 @@
 /* Define to 1 if you have the `nsl' library (-lnsl). */
 #undef HAVE_LIBNSL
 
+/* Define to 1 if you have the `pam' library (-lpam). */
+#undef HAVE_LIBPAM
+
 /* Define to 1 if you have the `PW' library (-lPW). */
 #undef HAVE_LIBPW
 
 /* Define to 1 if you have the <memory.h> header file. */
 #undef HAVE_MEMORY_H
 
+/* Define to 1 if you have the <netdb.h> header file. */
+#undef HAVE_NETDB_H
+
 /* Define to 1 if you have the <netinet/in.h> header file. */
 #undef HAVE_NETINET_IN_H
 
 /* Define to 1 if you have the <netinet/tcp.h> header file. */
 #undef HAVE_NETINET_TCP_H
 
+/* Define to 1 if you have the <pam/pam_appl.h> header file. */
+#undef HAVE_PAM_PAM_APPL_H
+
+/* Define to 1 if you have the <security/pam_appl.h> header file. */
+#undef HAVE_SECURITY_PAM_APPL_H
+
 /* Define to 1 if you have the `select' function. */
 #undef HAVE_SELECT
 
 /* Define to 1 if you have the `strtok' function. */
 #undef HAVE_STRTOK
 
+/* Define to 1 if `sa_len' is member of `struct sockaddr'. */
+#undef HAVE_STRUCT_SOCKADDR_SA_LEN
+
+/* Define to 1 if the system has the type `struct sockaddr_storage'. */
+#undef HAVE_STRUCT_SOCKADDR_STORAGE
+
+/* Define to 1 if `ss_family' is member of `struct sockaddr_storage'. */
+#undef HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY
+
+/* Define to 1 if `ss_len' is member of `struct sockaddr_storage'. */
+#undef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
+
+/* Define to 1 if `__ss_family' is member of `struct sockaddr_storage'. */
+#undef HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY
+
+/* Define to 1 if `__ss_len' is member of `struct sockaddr_storage'. */
+#undef HAVE_STRUCT_SOCKADDR_STORAGE___SS_LEN
+
 /* Define to 1 if you have the <sys/param.h> header file. */
 #undef HAVE_SYS_PARAM_H
 
 /* Define to 1 if you have the <sys/pstat.h> header file. */
 #undef HAVE_SYS_PSTAT_H
 
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#undef HAVE_SYS_SOCKET_H
+
 /* Define to 1 if you have the <sys/stat.h> header file. */
 #undef HAVE_SYS_STAT_H
 
 /* Define to 1 if you have the <sys/types.h> header file. */
 #undef HAVE_SYS_TYPES_H
 
+/* Define to 1 if you have the <sys/un.h> header file. */
+#undef HAVE_SYS_UN_H
+
 /* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
 #undef HAVE_SYS_WAIT_H
 
 /* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
 #undef TIME_WITH_SYS_TIME
 
+/* Define to 1 to build with PAM support. (--with-pam) */
+#undef USE_PAM
+
 /* Version number of package */
 #undef VERSION
 
index e4de826e947d00cef5389634e541a385a2bab8d6..6cde5b6d23e97d34f48fcdefd7663b63db4a0279 100755 (executable)
--- a/configure
+++ b/configure
@@ -718,13 +718,13 @@ echo X"$0" |
          /^X\(\/\).*/{ s//\1/; q; }
          s/.*/./; q'`
   srcdir=$ac_confdir
-  if test ! -r $srcdir/$ac_unique_file; then
+  if test ! -r "$srcdir/$ac_unique_file"; then
     srcdir=..
   fi
 else
   ac_srcdir_defaulted=no
 fi
-if test ! -r $srcdir/$ac_unique_file; then
+if test ! -r "$srcdir/$ac_unique_file"; then
   if test "$ac_srcdir_defaulted" = yes; then
     { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2
    { (exit 1); exit 1; }; }
@@ -733,7 +733,7 @@ if test ! -r $srcdir/$ac_unique_file; then
    { (exit 1); exit 1; }; }
   fi
 fi
-(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null ||
+(cd $srcdir && test -r "./$ac_unique_file") 2>/dev/null ||
   { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2
    { (exit 1); exit 1; }; }
 srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'`
@@ -851,6 +851,7 @@ Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
   --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
   --with-pgsql=DIR     site header files for PostgreSQL in DIR
+  --with-pam       build with PAM support
 
 Some influential environment variables:
   CC          C compiler command
@@ -4439,7 +4440,10 @@ done
 
 
 
-for ac_header in fcntl.h unistd.h getopt.h netinet/tcp.h netinet/in.h sys/param.h sys/types.h sys/time.h sys/pstat.h
+
+
+
+for ac_header in fcntl.h unistd.h getopt.h netinet/tcp.h netinet/in.h netdb.h sys/param.h sys/types.h sys/socket.h sys/un.h sys/time.h sys/pstat.h
 do
 as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
 if eval "test \"\${$as_ac_Header+set}\" = set"; then
@@ -4828,9 +4832,9 @@ _ACEOF
 fi
 
 
-echo "$as_me:$LINENO: checking return type of signal handlers" >&5
-echo $ECHO_N "checking return type of signal handlers... $ECHO_C" >&6
-if test "${ac_cv_type_signal+set}" = set; then
+echo "$as_me:$LINENO: checking for struct sockaddr_storage" >&5
+echo $ECHO_N "checking for struct sockaddr_storage... $ECHO_C" >&6
+if test "${ac_cv_type_struct_sockaddr_storage+set}" = set; then
   echo $ECHO_N "(cached) $ECHO_C" >&6
 else
   cat >conftest.$ac_ext <<_ACEOF
@@ -4840,20 +4844,18 @@ cat confdefs.h >>conftest.$ac_ext
 cat >>conftest.$ac_ext <<_ACEOF
 /* end confdefs.h.  */
 #include <sys/types.h>
-#include <signal.h>
-#ifdef signal
-# undef signal
-#endif
-#ifdef __cplusplus
-extern "C" void (*signal (int, void (*)(int)))(int);
-#else
-void (*signal ()) ();
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
 #endif
 
+
 int
 main ()
 {
-int i;
+if ((struct sockaddr_storage *) 0)
+  return 0;
+if (sizeof (struct sockaddr_storage))
+  return 0;
   ;
   return 0;
 }
@@ -4880,30 +4882,29 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   ac_status=$?
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); }; }; then
-  ac_cv_type_signal=void
+  ac_cv_type_struct_sockaddr_storage=yes
 else
   echo "$as_me: failed program was:" >&5
 sed 's/^/| /' conftest.$ac_ext >&5
 
-ac_cv_type_signal=int
+ac_cv_type_struct_sockaddr_storage=no
 fi
 rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
 fi
-echo "$as_me:$LINENO: result: $ac_cv_type_signal" >&5
-echo "${ECHO_T}$ac_cv_type_signal" >&6
+echo "$as_me:$LINENO: result: $ac_cv_type_struct_sockaddr_storage" >&5
+echo "${ECHO_T}$ac_cv_type_struct_sockaddr_storage" >&6
+if test $ac_cv_type_struct_sockaddr_storage = yes; then
 
 cat >>confdefs.h <<_ACEOF
-#define RETSIGTYPE $ac_cv_type_signal
+#define HAVE_STRUCT_SOCKADDR_STORAGE 1
 _ACEOF
 
 
+fi
 
-for ac_func in vprintf
-do
-as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
-echo "$as_me:$LINENO: checking for $ac_func" >&5
-echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
-if eval "test \"\${$as_ac_var+set}\" = set"; then
+echo "$as_me:$LINENO: checking for struct sockaddr_storage.ss_family" >&5
+echo $ECHO_N "checking for struct sockaddr_storage.ss_family... $ECHO_C" >&6
+if test "${ac_cv_member_struct_sockaddr_storage_ss_family+set}" = set; then
   echo $ECHO_N "(cached) $ECHO_C" >&6
 else
   cat >conftest.$ac_ext <<_ACEOF
@@ -4912,54 +4913,25 @@ _ACEOF
 cat confdefs.h >>conftest.$ac_ext
 cat >>conftest.$ac_ext <<_ACEOF
 /* end confdefs.h.  */
-/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
-   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
-#define $ac_func innocuous_$ac_func
-
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char $ac_func (); below.
-    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
-    <limits.h> exists even on freestanding compilers.  */
-
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
+#include <sys/types.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
 #endif
 
-#undef $ac_func
-
-/* Override any gcc2 internal prototype to avoid an error.  */
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-/* We use char because int might match the return type of a gcc2
-   builtin and then its argument prototype would still apply.  */
-char $ac_func ();
-/* The GNU C library defines this for functions which it implements
-    to always fail with ENOSYS.  Some functions are actually named
-    something starting with __ and the normal name is an alias.  */
-#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
-choke me
-#else
-char (*f) () = $ac_func;
-#endif
-#ifdef __cplusplus
-}
-#endif
 
 int
 main ()
 {
-return f != $ac_func;
+static struct sockaddr_storage ac_aggr;
+if (ac_aggr.ss_family)
+return 0;
   ;
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
-  (eval $ac_link) 2>conftest.er1
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
   ac_status=$?
   grep -v '^ *+' conftest.er1 >conftest.err
   rm -f conftest.er1
@@ -4973,88 +4945,42 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
   ac_status=$?
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); }; } &&
-        { ac_try='test -s conftest$ac_exeext'
+        { ac_try='test -s conftest.$ac_objext'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); }; }; then
-  eval "$as_ac_var=yes"
+  ac_cv_member_struct_sockaddr_storage_ss_family=yes
 else
   echo "$as_me: failed program was:" >&5
 sed 's/^/| /' conftest.$ac_ext >&5
 
-eval "$as_ac_var=no"
-fi
-rm -f conftest.err conftest.$ac_objext \
-      conftest$ac_exeext conftest.$ac_ext
-fi
-echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
-echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
-if test `eval echo '${'$as_ac_var'}'` = yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
-
-echo "$as_me:$LINENO: checking for _doprnt" >&5
-echo $ECHO_N "checking for _doprnt... $ECHO_C" >&6
-if test "${ac_cv_func__doprnt+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
-else
-  cat >conftest.$ac_ext <<_ACEOF
+cat >conftest.$ac_ext <<_ACEOF
 /* confdefs.h.  */
 _ACEOF
 cat confdefs.h >>conftest.$ac_ext
 cat >>conftest.$ac_ext <<_ACEOF
 /* end confdefs.h.  */
-/* Define _doprnt to an innocuous variant, in case <limits.h> declares _doprnt.
-   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
-#define _doprnt innocuous__doprnt
-
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char _doprnt (); below.
-    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
-    <limits.h> exists even on freestanding compilers.  */
-
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
+#include <sys/types.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
 #endif
 
-#undef _doprnt
-
-/* Override any gcc2 internal prototype to avoid an error.  */
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-/* We use char because int might match the return type of a gcc2
-   builtin and then its argument prototype would still apply.  */
-char _doprnt ();
-/* The GNU C library defines this for functions which it implements
-    to always fail with ENOSYS.  Some functions are actually named
-    something starting with __ and the normal name is an alias.  */
-#if defined (__stub__doprnt) || defined (__stub____doprnt)
-choke me
-#else
-char (*f) () = _doprnt;
-#endif
-#ifdef __cplusplus
-}
-#endif
 
 int
 main ()
 {
-return f != _doprnt;
+static struct sockaddr_storage ac_aggr;
+if (sizeof ac_aggr.ss_family)
+return 0;
   ;
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
-  (eval $ac_link) 2>conftest.er1
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
   ac_status=$?
   grep -v '^ *+' conftest.er1 >conftest.err
   rm -f conftest.er1
@@ -5068,43 +4994,37 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
   ac_status=$?
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); }; } &&
-        { ac_try='test -s conftest$ac_exeext'
+        { ac_try='test -s conftest.$ac_objext'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); }; }; then
-  ac_cv_func__doprnt=yes
+  ac_cv_member_struct_sockaddr_storage_ss_family=yes
 else
   echo "$as_me: failed program was:" >&5
 sed 's/^/| /' conftest.$ac_ext >&5
 
-ac_cv_func__doprnt=no
+ac_cv_member_struct_sockaddr_storage_ss_family=no
 fi
-rm -f conftest.err conftest.$ac_objext \
-      conftest$ac_exeext conftest.$ac_ext
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
 fi
-echo "$as_me:$LINENO: result: $ac_cv_func__doprnt" >&5
-echo "${ECHO_T}$ac_cv_func__doprnt" >&6
-if test $ac_cv_func__doprnt = yes; then
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_member_struct_sockaddr_storage_ss_family" >&5
+echo "${ECHO_T}$ac_cv_member_struct_sockaddr_storage_ss_family" >&6
+if test $ac_cv_member_struct_sockaddr_storage_ss_family = yes; then
 
-cat >>confdefs.h <<\_ACEOF
-#define HAVE_DOPRNT 1
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY 1
 _ACEOF
 
-fi
 
 fi
-done
-
-
-echo "$as_me:$LINENO: checking for wait3 that fills in rusage" >&5
-echo $ECHO_N "checking for wait3 that fills in rusage... $ECHO_C" >&6
-if test "${ac_cv_func_wait3_rusage+set}" = set; then
+echo "$as_me:$LINENO: checking for struct sockaddr_storage.__ss_family" >&5
+echo $ECHO_N "checking for struct sockaddr_storage.__ss_family... $ECHO_C" >&6
+if test "${ac_cv_member_struct_sockaddr_storage___ss_family+set}" = set; then
   echo $ECHO_N "(cached) $ECHO_C" >&6
-else
-  if test "$cross_compiling" = yes; then
-  ac_cv_func_wait3_rusage=no
 else
   cat >conftest.$ac_ext <<_ACEOF
 /* confdefs.h.  */
@@ -5113,90 +5033,116 @@ cat confdefs.h >>conftest.$ac_ext
 cat >>conftest.$ac_ext <<_ACEOF
 /* end confdefs.h.  */
 #include <sys/types.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <stdio.h>
-/* HP-UX has wait3 but does not fill in rusage at all.  */
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+
 int
 main ()
 {
-  struct rusage r;
-  int i;
-  /* Use a field that we can force nonzero --
-     voluntary context switches.
-     For systems like NeXT and OSF/1 that don't set it,
-     also use the system CPU time.  And page faults (I/O) for Linux.  */
-  r.ru_nvcsw = 0;
-  r.ru_stime.tv_sec = 0;
-  r.ru_stime.tv_usec = 0;
-  r.ru_majflt = r.ru_minflt = 0;
-  switch (fork ())
-    {
-    case 0: /* Child.  */
-      sleep(1); /* Give up the CPU.  */
-      _exit(0);
-      break;
-    case -1: /* What can we do?  */
-      _exit(0);
-      break;
-    default: /* Parent.  */
-      wait3(&i, 0, &r);
-      /* Avoid "text file busy" from rm on fast HP-UX machines.  */
-      sleep(2);
-      exit (r.ru_nvcsw == 0 && r.ru_majflt == 0 && r.ru_minflt == 0
-           && r.ru_stime.tv_sec == 0 && r.ru_stime.tv_usec == 0);
-    }
+static struct sockaddr_storage ac_aggr;
+if (ac_aggr.__ss_family)
+return 0;
+  ;
+  return 0;
 }
 _ACEOF
-rm -f conftest$ac_exeext
-if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
-  (eval $ac_link) 2>&5
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
   ac_status=$?
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); }; }; then
-  ac_cv_func_wait3_rusage=yes
+  ac_cv_member_struct_sockaddr_storage___ss_family=yes
 else
-  echo "$as_me: program exited with status $ac_status" >&5
-echo "$as_me: failed program was:" >&5
+  echo "$as_me: failed program was:" >&5
 sed 's/^/| /' conftest.$ac_ext >&5
 
-( exit $ac_status )
-ac_cv_func_wait3_rusage=no
-fi
-rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
-fi
-fi
-echo "$as_me:$LINENO: result: $ac_cv_func_wait3_rusage" >&5
-echo "${ECHO_T}$ac_cv_func_wait3_rusage" >&6
-if test $ac_cv_func_wait3_rusage = yes; then
-
-cat >>confdefs.h <<\_ACEOF
-#define HAVE_WAIT3 1
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
 _ACEOF
-
-fi
-
-
-
-
-
-
-
-
-
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
 
 
-for ac_func in setsid select socket sigprocmask strdup strerror strftime strtok asprintf setproctitle
-do
-as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
-echo "$as_me:$LINENO: checking for $ac_func" >&5
-echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
-if eval "test \"\${$as_ac_var+set}\" = set"; then
+int
+main ()
+{
+static struct sockaddr_storage ac_aggr;
+if (sizeof ac_aggr.__ss_family)
+return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_member_struct_sockaddr_storage___ss_family=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_member_struct_sockaddr_storage___ss_family=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_member_struct_sockaddr_storage___ss_family" >&5
+echo "${ECHO_T}$ac_cv_member_struct_sockaddr_storage___ss_family" >&6
+if test $ac_cv_member_struct_sockaddr_storage___ss_family = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY 1
+_ACEOF
+
+
+fi
+echo "$as_me:$LINENO: checking for struct sockaddr_storage.ss_len" >&5
+echo $ECHO_N "checking for struct sockaddr_storage.ss_len... $ECHO_C" >&6
+if test "${ac_cv_member_struct_sockaddr_storage_ss_len+set}" = set; then
   echo $ECHO_N "(cached) $ECHO_C" >&6
 else
   cat >conftest.$ac_ext <<_ACEOF
@@ -5205,54 +5151,74 @@ _ACEOF
 cat confdefs.h >>conftest.$ac_ext
 cat >>conftest.$ac_ext <<_ACEOF
 /* end confdefs.h.  */
-/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
-   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
-#define $ac_func innocuous_$ac_func
-
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char $ac_func (); below.
-    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
-    <limits.h> exists even on freestanding compilers.  */
-
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
+#include <sys/types.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
 #endif
 
-#undef $ac_func
 
-/* Override any gcc2 internal prototype to avoid an error.  */
-#ifdef __cplusplus
-extern "C"
+int
+main ()
 {
-#endif
-/* We use char because int might match the return type of a gcc2
-   builtin and then its argument prototype would still apply.  */
-char $ac_func ();
-/* The GNU C library defines this for functions which it implements
-    to always fail with ENOSYS.  Some functions are actually named
-    something starting with __ and the normal name is an alias.  */
-#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
-choke me
-#else
-char (*f) () = $ac_func;
-#endif
-#ifdef __cplusplus
+static struct sockaddr_storage ac_aggr;
+if (ac_aggr.ss_len)
+return 0;
+  ;
+  return 0;
 }
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_member_struct_sockaddr_storage_ss_len=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
 #endif
 
+
 int
 main ()
 {
-return f != $ac_func;
+static struct sockaddr_storage ac_aggr;
+if (sizeof ac_aggr.ss_len)
+return 0;
   ;
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
-  (eval $ac_link) 2>conftest.er1
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
   ac_status=$?
   grep -v '^ *+' conftest.er1 >conftest.err
   rm -f conftest.er1
@@ -5266,51 +5232,1264 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
   ac_status=$?
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); }; } &&
-        { ac_try='test -s conftest$ac_exeext'
+        { ac_try='test -s conftest.$ac_objext'
   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
   (eval $ac_try) 2>&5
   ac_status=$?
   echo "$as_me:$LINENO: \$? = $ac_status" >&5
   (exit $ac_status); }; }; then
-  eval "$as_ac_var=yes"
+  ac_cv_member_struct_sockaddr_storage_ss_len=yes
 else
   echo "$as_me: failed program was:" >&5
 sed 's/^/| /' conftest.$ac_ext >&5
 
-eval "$as_ac_var=no"
+ac_cv_member_struct_sockaddr_storage_ss_len=no
 fi
-rm -f conftest.err conftest.$ac_objext \
-      conftest$ac_exeext conftest.$ac_ext
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
 fi
-echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
-echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
-if test `eval echo '${'$as_ac_var'}'` = yes; then
-  cat >>confdefs.h <<_ACEOF
-#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_member_struct_sockaddr_storage_ss_len" >&5
+echo "${ECHO_T}$ac_cv_member_struct_sockaddr_storage_ss_len" >&6
+if test $ac_cv_member_struct_sockaddr_storage_ss_len = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN 1
 _ACEOF
 
+
 fi
-done
+echo "$as_me:$LINENO: checking for struct sockaddr_storage.__ss_len" >&5
+echo $ECHO_N "checking for struct sockaddr_storage.__ss_len... $ECHO_C" >&6
+if test "${ac_cv_member_struct_sockaddr_storage___ss_len+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
 
 
-PGSQL_INCLUDE_DIR=/usr/local/pgsql/include
+int
+main ()
+{
+static struct sockaddr_storage ac_aggr;
+if (ac_aggr.__ss_len)
+return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_member_struct_sockaddr_storage___ss_len=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
 
-# Check whether --with-pgsql or --without-pgsql was given.
-if test "${with_pgsql+set}" = set; then
-  withval="$with_pgsql"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
 
-       case "$withval" in
-       "" | y | ye | yes | n | no)
-           { { echo "$as_me:$LINENO: error: *** You must supply an argument to the --with-pgsql option." >&5
-echo "$as_me: error: *** You must supply an argument to the --with-pgsql option." >&2;}
-   { (exit 1); exit 1; }; }
-         ;;
-       esac
-       PGSQL_INCLUDE_DIR="$withval"
 
-fi;
+int
+main ()
+{
+static struct sockaddr_storage ac_aggr;
+if (sizeof ac_aggr.__ss_len)
+return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_member_struct_sockaddr_storage___ss_len=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_member_struct_sockaddr_storage___ss_len=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_member_struct_sockaddr_storage___ss_len" >&5
+echo "${ECHO_T}$ac_cv_member_struct_sockaddr_storage___ss_len" >&6
+if test $ac_cv_member_struct_sockaddr_storage___ss_len = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_SOCKADDR_STORAGE___SS_LEN 1
+_ACEOF
 
 
+fi
+echo "$as_me:$LINENO: checking for struct sockaddr.sa_len" >&5
+echo $ECHO_N "checking for struct sockaddr.sa_len... $ECHO_C" >&6
+if test "${ac_cv_member_struct_sockaddr_sa_len+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+
+int
+main ()
+{
+static struct sockaddr ac_aggr;
+if (ac_aggr.sa_len)
+return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_member_struct_sockaddr_sa_len=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+
+int
+main ()
+{
+static struct sockaddr ac_aggr;
+if (sizeof ac_aggr.sa_len)
+return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_member_struct_sockaddr_sa_len=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_member_struct_sockaddr_sa_len=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_member_struct_sockaddr_sa_len" >&5
+echo "${ECHO_T}$ac_cv_member_struct_sockaddr_sa_len" >&6
+if test $ac_cv_member_struct_sockaddr_sa_len = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_SOCKADDR_SA_LEN 1
+_ACEOF
+
+
+fi
+
+
+echo "$as_me:$LINENO: checking return type of signal handlers" >&5
+echo $ECHO_N "checking return type of signal handlers... $ECHO_C" >&6
+if test "${ac_cv_type_signal+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+# undef signal
+#endif
+#ifdef __cplusplus
+extern "C" void (*signal (int, void (*)(int)))(int);
+#else
+void (*signal ()) ();
+#endif
+
+int
+main ()
+{
+int i;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_type_signal=void
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_signal=int
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_signal" >&5
+echo "${ECHO_T}$ac_cv_type_signal" >&6
+
+cat >>confdefs.h <<_ACEOF
+#define RETSIGTYPE $ac_cv_type_signal
+_ACEOF
+
+
+
+for ac_func in vprintf
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+echo "$as_me:$LINENO: checking for _doprnt" >&5
+echo $ECHO_N "checking for _doprnt... $ECHO_C" >&6
+if test "${ac_cv_func__doprnt+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define _doprnt to an innocuous variant, in case <limits.h> declares _doprnt.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define _doprnt innocuous__doprnt
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char _doprnt (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef _doprnt
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char _doprnt ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub__doprnt) || defined (__stub____doprnt)
+choke me
+#else
+char (*f) () = _doprnt;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != _doprnt;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_func__doprnt=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func__doprnt=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func__doprnt" >&5
+echo "${ECHO_T}$ac_cv_func__doprnt" >&6
+if test $ac_cv_func__doprnt = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_DOPRNT 1
+_ACEOF
+
+fi
+
+fi
+done
+
+
+echo "$as_me:$LINENO: checking for wait3 that fills in rusage" >&5
+echo $ECHO_N "checking for wait3 that fills in rusage... $ECHO_C" >&6
+if test "${ac_cv_func_wait3_rusage+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$cross_compiling" = yes; then
+  ac_cv_func_wait3_rusage=no
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <stdio.h>
+/* HP-UX has wait3 but does not fill in rusage at all.  */
+int
+main ()
+{
+  struct rusage r;
+  int i;
+  /* Use a field that we can force nonzero --
+     voluntary context switches.
+     For systems like NeXT and OSF/1 that don't set it,
+     also use the system CPU time.  And page faults (I/O) for Linux.  */
+  r.ru_nvcsw = 0;
+  r.ru_stime.tv_sec = 0;
+  r.ru_stime.tv_usec = 0;
+  r.ru_majflt = r.ru_minflt = 0;
+  switch (fork ())
+    {
+    case 0: /* Child.  */
+      sleep(1); /* Give up the CPU.  */
+      _exit(0);
+      break;
+    case -1: /* What can we do?  */
+      _exit(0);
+      break;
+    default: /* Parent.  */
+      wait3(&i, 0, &r);
+      /* Avoid "text file busy" from rm on fast HP-UX machines.  */
+      sleep(2);
+      exit (r.ru_nvcsw == 0 && r.ru_majflt == 0 && r.ru_minflt == 0
+           && r.ru_stime.tv_sec == 0 && r.ru_stime.tv_usec == 0);
+    }
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_func_wait3_rusage=yes
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_func_wait3_rusage=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_wait3_rusage" >&5
+echo "${ECHO_T}$ac_cv_func_wait3_rusage" >&6
+if test $ac_cv_func_wait3_rusage = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_WAIT3 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking types of arguments for accept()" >&5
+echo $ECHO_N "checking types of arguments for accept()... $ECHO_C" >&6
+ if test "${ac_cv_func_accept_return+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+   if test "${ac_cv_func_accept_arg1+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+    if test "${ac_cv_func_accept_arg2+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+     if test "${ac_cv_func_accept_arg3+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+      for ac_cv_func_accept_return in 'int' 'unsigned int PASCAL'; do
+      for ac_cv_func_accept_arg1 in 'int' 'unsigned int'; do
+       for ac_cv_func_accept_arg2 in 'struct sockaddr *' 'const struct sockaddr *' 'void *'; do
+        for ac_cv_func_accept_arg3 in 'int' 'size_t' 'socklen_t' 'unsigned int' 'void'; do
+         cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+extern $ac_cv_func_accept_return accept ($ac_cv_func_accept_arg1, $ac_cv_func_accept_arg2, $ac_cv_func_accept_arg3 *);
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_not_found=no; break 4
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_not_found=yes
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+       done
+      done
+     done
+    done
+    if test "$ac_not_found" = yes; then
+      { { echo "$as_me:$LINENO: error: could not determine argument types" >&5
+echo "$as_me: error: could not determine argument types" >&2;}
+   { (exit 1); exit 1; }; }
+    fi
+    if test "$ac_cv_func_accept_arg3" = "void"; then
+      ac_cv_func_accept_arg3=int
+    fi
+
+fi
+
+fi
+
+fi
+
+fi
+ echo "$as_me:$LINENO: result: $ac_cv_func_accept_return, $ac_cv_func_accept_arg1, $ac_cv_func_accept_arg2, $ac_cv_func_accept_arg3 *" >&5
+echo "${ECHO_T}$ac_cv_func_accept_return, $ac_cv_func_accept_arg1, $ac_cv_func_accept_arg2, $ac_cv_func_accept_arg3 *" >&6
+
+cat >>confdefs.h <<_ACEOF
+#define ACCEPT_TYPE_RETURN $ac_cv_func_accept_return
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define ACCEPT_TYPE_ARG1 $ac_cv_func_accept_arg1
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define ACCEPT_TYPE_ARG2 $ac_cv_func_accept_arg2
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define ACCEPT_TYPE_ARG3 $ac_cv_func_accept_arg3
+_ACEOF
+
+
+
+
+
+
+
+
+
+
+
+
+for ac_func in setsid select socket sigprocmask strdup strerror strftime strtok asprintf setproctitle
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+PGSQL_INCLUDE_DIR=/usr/local/pgsql/include
+
+# Check whether --with-pgsql or --without-pgsql was given.
+if test "${with_pgsql+set}" = set; then
+  withval="$with_pgsql"
+
+       case "$withval" in
+       "" | y | ye | yes | n | no)
+           { { echo "$as_me:$LINENO: error: *** You must supply an argument to the --with-pgsql option." >&5
+echo "$as_me: error: *** You must supply an argument to the --with-pgsql option." >&2;}
+   { (exit 1); exit 1; }; }
+         ;;
+       esac
+       PGSQL_INCLUDE_DIR="$withval"
+
+fi;
+
+
+
+
+# Check whether --with-pam or --without-pam was given.
+if test "${with_pam+set}" = set; then
+  withval="$with_pam"
+
+cat >>confdefs.h <<\_ACEOF
+#define USE_PAM 1
+_ACEOF
+
+fi;
+if test "$with_pam" = yes ; then
+
+echo "$as_me:$LINENO: checking for pam_start in -lpam" >&5
+echo $ECHO_N "checking for pam_start in -lpam... $ECHO_C" >&6
+if test "${ac_cv_lib_pam_pam_start+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpam  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char pam_start ();
+int
+main ()
+{
+pam_start ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_pam_pam_start=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_pam_pam_start=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_pam_pam_start" >&5
+echo "${ECHO_T}$ac_cv_lib_pam_pam_start" >&6
+if test $ac_cv_lib_pam_pam_start = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBPAM 1
+_ACEOF
+
+  LIBS="-lpam $LIBS"
+
+else
+  { { echo "$as_me:$LINENO: error: library 'pam' is required for PAM" >&5
+echo "$as_me: error: library 'pam' is required for PAM" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+
+for ac_header in security/pam_appl.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+  # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    (
+      cat <<\_ASBOX
+## ------------------------------------------ ##
+## Report this to the AC_PACKAGE_NAME lists.  ##
+## ------------------------------------------ ##
+_ASBOX
+    ) |
+      sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+else
+
+for ac_header in pam/pam_appl.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+  # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    (
+      cat <<\_ASBOX
+## ------------------------------------------ ##
+## Report this to the AC_PACKAGE_NAME lists.  ##
+## ------------------------------------------ ##
+_ASBOX
+    ) |
+      sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+else
+  { { echo "$as_me:$LINENO: error: header file <security/pam_appl.h> or <pam/pam_appl.h> is required for PAM." >&5
+echo "$as_me: error: header file <security/pam_appl.h> or <pam/pam_appl.h> is required for PAM." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+done
+
+fi
+
+done
+
+fi
 
           ac_config_headers="$ac_config_headers config.h"
 
index 7a2fea2e4e5b7041f5a42687f5ebd9f163a83cc1..588450a9aea7a70962a9deb26c469255757a801b 100644 (file)
@@ -24,17 +24,36 @@ AC_CHECK_LIB(resolv,   main)
 dnl Checks for header files.
 AC_HEADER_STDC
 AC_HEADER_SYS_WAIT
-AC_CHECK_HEADERS(fcntl.h unistd.h getopt.h netinet/tcp.h netinet/in.h sys/param.h sys/types.h sys/time.h sys/pstat.h)
+AC_CHECK_HEADERS(fcntl.h unistd.h getopt.h netinet/tcp.h netinet/in.h netdb.h sys/param.h sys/types.h sys/socket.h sys/un.h sys/time.h sys/pstat.h)
 
 dnl Checks for typedefs, structures, and compiler characteristics.
 AC_C_CONST
 AC_TYPE_PID_T
 AC_HEADER_TIME
 
+dnl Checks for sockadr_storage structure, members and necessary types
+AC_CHECK_TYPES([struct sockaddr_storage], [], [],
+[#include <sys/types.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+])
+AC_CHECK_MEMBERS([struct sockaddr_storage.ss_family,
+                 struct sockaddr_storage.__ss_family,
+                 struct sockaddr_storage.ss_len,
+                 struct sockaddr_storage.__ss_len,
+                 struct sockaddr.sa_len], [], [],
+[#include <sys/types.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+])
+
 dnl Checks for library functions.
 AC_TYPE_SIGNAL
 AC_FUNC_VPRINTF
 AC_FUNC_WAIT3
+AC_FUNC_ACCEPT_ARGTYPES        
 AC_CHECK_FUNCS(setsid select socket sigprocmask strdup strerror strftime strtok asprintf setproctitle)
 
 PGSQL_INCLUDE_DIR=/usr/local/pgsql/include
@@ -51,6 +70,16 @@ AC_ARG_WITH(pgsql,
 
 AC_SUBST(PGSQL_INCLUDE_DIR)
 
+AC_ARG_WITH(pam,
+    [  --with-pam          build with PAM support],
+    [AC_DEFINE([USE_PAM], 1, [Define to 1 to build with PAM support. (--with-pam)])])
+if test "$with_pam" = yes ; then
+   AC_CHECK_LIB(pam,  pam_start, [], [AC_MSG_ERROR([library 'pam' is required for PAM])])
+   AC_CHECK_HEADERS(security/pam_appl.h, [],
+                    [AC_CHECK_HEADERS(pam/pam_appl.h, [],
+                                     [AC_MSG_ERROR([header file <security/pam_appl.h> or <pam/pam_appl.h> is required for PAM.])])])
+fi
+
 AM_CONFIG_HEADER(config.h)
 
 AC_OUTPUT(Makefile)
diff --git a/main.c b/main.c
index b926bf2d7ecb3ebc79a4b3d236040a2e4a843f5a..81992b45457b097d5ec4131cafad78d2c2953ac7 100644 (file)
--- a/main.c
+++ b/main.c
@@ -97,6 +97,7 @@ int main(int argc, char **argv)
 {
        int opt;
        char conf_file[POOLMAXPATHLEN+1];
+       char hba_file[POOLMAXPATHLEN+1];
        int i;
        int pid;
 
@@ -104,11 +105,21 @@ int main(int argc, char **argv)
        myargv = argv;
 
        snprintf(conf_file, sizeof(conf_file), "%s/%s", DEFAULT_CONFIGDIR, POOL_CONF_FILE_NAME);
+       snprintf(hba_file, sizeof(hba_file), "%s/%s", DEFAULT_CONFIGDIR, HBA_CONF_FILE_NAME);
 
-       while ((opt = getopt(argc, argv, "df:hm:ns:")) != -1)
+       while ((opt = getopt(argc, argv, "a:df:hm:ns:")) != -1)
        {
                switch (opt)
                {
+                       case 'a':    /* specify hba configuration file */
+                               if (!optarg)
+                               {
+                                       usage();
+                                       exit(1);
+                               }
+                               strncpy(hba_file, optarg, sizeof(hba_file));
+                               break;
+
                        case 'd':       /* debug option */
                                debug = 1;
                                break;
@@ -192,6 +203,10 @@ int main(int argc, char **argv)
 
        pool_debug("weight: %ld", weight_master);
 
+       /* read pool_hba.conf */
+       if (pool_config.enable_pool_hba)
+               load_hba(hba_file);
+
        /*
         * if a non-switch argument remains, then it should be either "stop" or "switch"
         */
@@ -358,11 +373,12 @@ static void usage(void)
 {
        fprintf(stderr, "pgpool version %s(%s),\n",     VERSION, PGPOOLVERSION);
        fprintf(stderr, "  a generic connection pool/replication/load balance server for PostgreSQL\n\n");
-       fprintf(stderr, "usage: pgpool [-f config_file][-n][-d]\n");
-       fprintf(stderr, "usage: pgpool [-f config_file] [-m {s[mart]|f[ast]|i[mmediate]}] stop\n");
-       fprintf(stderr, "usage: pgpool [-f config_file] [-s {m[aster]|s[econdary]] switch\n");
+       fprintf(stderr, "usage: pgpool [-f config_file][-a hba_file][-n][-d]\n");
+       fprintf(stderr, "usage: pgpool [-f config_file][-a hba_file] [-m {s[mart]|f[ast]|i[mmediate]}] stop\n");
+       fprintf(stderr, "usage: pgpool [-f config_file][-a hba_file] [-s {m[aster]|s[econdary]] switch\n");
        fprintf(stderr, "usage: pgpool -h\n");
        fprintf(stderr, "  config_file default path: %s/%s\n",DEFAULT_CONFIGDIR, POOL_CONF_FILE_NAME);
+       fprintf(stderr, "  hba_file default path:    %s/%s\n",DEFAULT_CONFIGDIR, HBA_CONF_FILE_NAME);
        fprintf(stderr, "  -n: don't run in daemon mode. does not detatch control tty\n");
        fprintf(stderr, "  -d: debug mode. lots of debug information will be printed\n");
        fprintf(stderr, "  stop: stop pgpool\n");
index 18c39ba7a425d1a7b1676bd8c1e526e2502f0f85..5fe90afcacfb9eca4052b23ddd534c7fe9faa7ca 100644 (file)
@@ -118,7 +118,19 @@ insert_lock = false
 # extra leading white space.
 ignore_leading_white_space = false
 
+# - What to Log -
+
 # If true, print all statements to the log.  Like the log_statement option
 # to PostgreSQL, this allows for observing queries without engaging in full
 # debugging.
 log_statement = false
+
+# If true, incoming connections will be printed to the log.
+log_connections = false
+
+# - HBA -
+
+# If true, use pool_hba.conf for client authentication. In pgpool 3.2,
+# the default value is false. This parameter is planned to be deleted
+# in pgpool 3.3, and pool_hba.conf will always be used.
+enable_pool_hba = false
diff --git a/pool.h b/pool.h
index 5d23eab8bdf98b7e91eab8d6581d4dc8dbc7e51e..b931e2616713118cc65195b605fa771d8868b1f3 100644 (file)
--- a/pool.h
+++ b/pool.h
 
 #include "config.h"
 #include "pool_signal.h"
+#include "pool_type.h"
+#include "pool_list.h"
 #include <stdio.h>
 #include <time.h>
-
-/* typdefs */
-#ifndef __cplusplus
-#ifndef bool
-typedef char bool;
-#endif
-
-#ifndef true
-#define true   ((bool) 1)
-#endif
-
-#ifndef false
-#define false  ((bool) 0)
-#endif
-
-#endif
+#include <netinet/in.h>
 
 /* undef this if you have problems with non blocking accept() */
 #define NONE_BLOCK
@@ -54,6 +41,7 @@ typedef char bool;
 
 /* configuration file name */
 #define POOL_CONF_FILE_NAME "pgpool.conf"
+#define HBA_CONF_FILE_NAME "pool_hba.conf"
 
 /* pid file directory */
 #define DEFAULT_LOGDIR "/tmp"
@@ -175,6 +163,8 @@ typedef struct {
        int num_servers;                        /* number of PostgreSQL servers */
        int server_status[MAX_CONNECTION_SLOTS];        /* server status 0:unused, 1:up, 2:down */
        int log_statement; /* 0:false, 1: true - logs all SQL statements */
+       int log_connections;            /* 0:false, 1:true - logs incoming connections */
+       int enable_pool_hba;            /* 0:false, 1:true - enables pool_hba.conf file authentication */
 } POOL_CONFIG;
 
 #define MAX_PASSWORD_SIZE              1024
@@ -227,6 +217,19 @@ typedef struct {
 
        int no_forward;         /* if non 0, do not write to frontend */
 
+       /*
+        * frontend info needed for hba
+        */
+       int protoVersion;
+       SockAddr raddr;
+       UserAuth auth_method;
+       char *auth_arg;
+       char *database;
+       char *username;
+#ifdef USE_SSL
+       bool ssl;
+#endif
+
 } POOL_CONNECTION;
 
 /*
@@ -362,10 +365,14 @@ extern bool update_process_title;
 extern char **save_ps_display_args(int argc, char **argv);
 
 extern void init_ps_display(const char *username, const char *dbname,
-                               const char *host_info, const char *initial_str);
+                                                       const char *host_info, const char *initial_str);
 
 extern void set_ps_display(const char *activity, bool force);
 
 extern const char *get_ps_display(int *displen);
 
+/* pool_hba.c */
+extern void load_hba(char *hbapath);
+extern void ClientAuthentication(POOL_CONNECTION *frontend);
+
 #endif /* POOL_H */
index 2fbe38b7db1ed14b143101c5d87c9972feb03e0b..22003910bcfe54c63a7c6c26665277a13808cfb3 100644 (file)
@@ -1,32 +1,93 @@
-/* A lexical scanner generated by flex */
 
-/* Scanner skeleton version:
- * $Header$
- */
+#line 3 "pool_config.c"
+
+#define  YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
 
 #define FLEX_SCANNER
 #define YY_FLEX_MAJOR_VERSION 2
 #define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 33
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
 
+/* First, we deal with  platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
 #include <stdio.h>
-#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
 
+#ifndef FLEXINT_H
+#define FLEXINT_H
 
-/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
-#ifdef c_plusplus
-#ifndef __cplusplus
-#define __cplusplus
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types. 
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t; 
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
 #endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
 #endif
 
+#endif /* ! FLEXINT_H */
 
 #ifdef __cplusplus
 
-#include <stdlib.h>
-
-/* Use prototypes in function declarations. */
-#define YY_USE_PROTOS
-
 /* The "const" storage-class-modifier is valid. */
 #define YY_USE_CONST
 
 
 #if __STDC__
 
-#define YY_USE_PROTOS
 #define YY_USE_CONST
 
 #endif /* __STDC__ */
 #endif /* ! __cplusplus */
 
-#ifdef __TURBOC__
- #pragma warn -rch
- #pragma warn -use
-#include <io.h>
-#include <stdlib.h>
-#define YY_USE_CONST
-#define YY_USE_PROTOS
-#endif
-
 #ifdef YY_USE_CONST
 #define yyconst const
 #else
 #define yyconst
 #endif
 
-
-#ifdef YY_USE_PROTOS
-#define YY_PROTO(proto) proto
-#else
-#define YY_PROTO(proto) ()
-#endif
-
 /* Returned upon end-of-file. */
 #define YY_NULL 0
 
  * but we do it the disgusting crufty way forced on us by the ()-less
  * definition of BEGIN.
  */
-#define BEGIN yy_start = 1 + 2 *
+#define BEGIN (yy_start) = 1 + 2 *
 
 /* Translate the current start state into a value that can be later handed
  * to BEGIN to return to the state.  The YYSTATE alias is for lex
  * compatibility.
  */
-#define YY_START ((yy_start - 1) / 2)
+#define YY_START (((yy_start) - 1) / 2)
 #define YYSTATE YY_START
 
 /* Action number for EOF rule of a given start state. */
 #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
 
 /* Special action meaning "start processing a new file". */
-#define YY_NEW_FILE yyrestart( yyin )
+#define YY_NEW_FILE yyrestart(yyin  )
 
 #define YY_END_OF_BUFFER_CHAR 0
 
 /* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
 #define YY_BUF_SIZE 16384
+#endif
 
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
 typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
 
 extern int yyleng;
+
 extern FILE *yyin, *yyout;
 
 #define EOB_ACT_CONTINUE_SCAN 0
 #define EOB_ACT_END_OF_FILE 1
 #define EOB_ACT_LAST_MATCH 2
 
-/* The funky do-while in the following #define is used to turn the definition
- * int a single C statement (which needs a semi-colon terminator).  This
- * avoids problems with code like:
- *
- *     if ( condition_holds )
- *             yyless( 5 );
- *     else
- *             do_something_else();
- *
- * Prior to using the do-while the compiler would get upset at the
- * "else" because it interpreted the "if" statement as being all
- * done when it reached the ';' after the yyless() call.
- */
-
-/* Return all but the first 'n' matched characters back to the input stream. */
-
+    #define YY_LESS_LINENO(n)
+    
+/* Return all but the first "n" matched characters back to the input stream. */
 #define yyless(n) \
        do \
                { \
                /* Undo effects of setting up yytext. */ \
-               *yy_cp = yy_hold_char; \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+               *yy_cp = (yy_hold_char); \
                YY_RESTORE_YY_MORE_OFFSET \
-               yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
+               (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
                YY_DO_BEFORE_ACTION; /* set up yytext again */ \
                } \
        while ( 0 )
 
-#define unput(c) yyunput( c, yytext_ptr )
+#define unput(c) yyunput( c, (yytext_ptr)  )
 
 /* The following is because we cannot portably get our hands on size_t
  * (without autoconf's help, which isn't available because we want
  * flex-generated scanners to compile on their own).
  */
-typedef unsigned int yy_size_t;
 
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef unsigned int yy_size_t;
+#endif
 
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
 struct yy_buffer_state
        {
        FILE *yy_input_file;
@@ -177,12 +225,16 @@ struct yy_buffer_state
         */
        int yy_at_bol;
 
+    int yy_bs_lineno; /**< The line count. */
+    int yy_bs_column; /**< The column count. */
+    
        /* Whether to try to fill the input buffer when we reach the
         * end of it.
         */
        int yy_fill_buffer;
 
        int yy_buffer_status;
+
 #define YY_BUFFER_NEW 0
 #define YY_BUFFER_NORMAL 1
        /* When an EOF's been seen but there's still some text to process
@@ -196,28 +248,38 @@ struct yy_buffer_state
         * just pointing yyin at a new input file.
         */
 #define YY_BUFFER_EOF_PENDING 2
+
        };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
 
-static YY_BUFFER_STATE yy_current_buffer = 0;
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
 
 /* We provide macros for accessing buffer states in case in the
  * future we want to put the buffer states in a more general
  * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
  */
-#define YY_CURRENT_BUFFER yy_current_buffer
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+                          ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+                          : NULL)
 
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
 
 /* yy_hold_char holds the character lost when yytext is formed. */
 static char yy_hold_char;
-
 static int yy_n_chars;         /* number of characters read into yy_ch_buf */
-
-
 int yyleng;
 
 /* Points to current character in buffer. */
 static char *yy_c_buf_p = (char *) 0;
-static int yy_init = 1;                /* whether we need to initialize */
+static int yy_init = 0;                /* whether we need to initialize */
 static int yy_start = 0;       /* start state number */
 
 /* Flag which is used to allow yywrap()'s to do buffer switches
@@ -225,69 +287,95 @@ static int yy_start = 0;  /* start state number */
  */
 static int yy_did_buffer_switch_on_eof;
 
-void yyrestart YY_PROTO(( FILE *input_file ));
+void yyrestart (FILE *input_file  );
+void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer  );
+YY_BUFFER_STATE yy_create_buffer (FILE *file,int size  );
+void yy_delete_buffer (YY_BUFFER_STATE b  );
+void yy_flush_buffer (YY_BUFFER_STATE b  );
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer  );
+void yypop_buffer_state (void );
+
+static void yyensure_buffer_stack (void );
+static void yy_load_buffer_state (void );
+static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file  );
 
-void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer ));
-void yy_load_buffer_state YY_PROTO(( void ));
-YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size ));
-void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b ));
-void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file ));
-void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b ));
-#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer )
+#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER )
 
-YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size ));
-YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str ));
-YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len ));
+YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size  );
+YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str  );
+YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len  );
 
-static void *yy_flex_alloc YY_PROTO(( yy_size_t ));
-static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t ));
-static void yy_flex_free YY_PROTO(( void * ));
+void *yyalloc (yy_size_t  );
+void *yyrealloc (void *,yy_size_t  );
+void yyfree (void *  );
 
 #define yy_new_buffer yy_create_buffer
 
 #define yy_set_interactive(is_interactive) \
        { \
-       if ( ! yy_current_buffer ) \
-               yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
-       yy_current_buffer->yy_is_interactive = is_interactive; \
+       if ( ! YY_CURRENT_BUFFER ){ \
+        yyensure_buffer_stack (); \
+               YY_CURRENT_BUFFER_LVALUE =    \
+            yy_create_buffer(yyin,YY_BUF_SIZE ); \
+       } \
+       YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
        }
 
 #define yy_set_bol(at_bol) \
        { \
-       if ( ! yy_current_buffer ) \
-               yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
-       yy_current_buffer->yy_at_bol = at_bol; \
+       if ( ! YY_CURRENT_BUFFER ){\
+        yyensure_buffer_stack (); \
+               YY_CURRENT_BUFFER_LVALUE =    \
+            yy_create_buffer(yyin,YY_BUF_SIZE ); \
+       } \
+       YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
        }
 
-#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
 
+/* Begin user sect3 */
 
-#define yywrap() 1
+#define yywrap(n) 1
 #define YY_SKIP_YYWRAP
+
 typedef unsigned char YY_CHAR;
+
 FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+
 typedef int yy_state_type;
+
+extern int yylineno;
+
+int yylineno = 1;
+
 extern char *yytext;
 #define yytext_ptr yytext
 
-static yy_state_type yy_get_previous_state YY_PROTO(( void ));
-static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state ));
-static int yy_get_next_buffer YY_PROTO(( void ));
-static void yy_fatal_error YY_PROTO(( yyconst char msg[] ));
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state  );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[]  );
 
 /* Done after the current pattern has been matched and before the
  * corresponding action - sets up yytext.
  */
 #define YY_DO_BEFORE_ACTION \
-       yytext_ptr = yy_bp; \
-       yyleng = (int) (yy_cp - yy_bp); \
-       yy_hold_char = *yy_cp; \
+       (yytext_ptr) = yy_bp; \
+       yyleng = (size_t) (yy_cp - yy_bp); \
+       (yy_hold_char) = *yy_cp; \
        *yy_cp = '\0'; \
-       yy_c_buf_p = yy_cp;
+       (yy_c_buf_p) = yy_cp;
 
 #define YY_NUM_RULES 11
 #define YY_END_OF_BUFFER 12
-static yyconst short int yy_accept[38] =
+/* This struct is not used in this scanner,
+   but its presence is necessary. */
+struct yy_trans_info
+       {
+       flex_int32_t yy_verify;
+       flex_int32_t yy_nxt;
+       };
+static yyconst flex_int16_t yy_accept[38] =
     {   0,
         0,    0,   12,   10,    2,    1,   10,   10,   10,    8,
         7,    7,    9,    4,    2,    0,    3,    0,    5,    0,
@@ -295,7 +383,7 @@ static yyconst short int yy_accept[38] =
         5,    0,    0,    8,    7,    6,    0
     } ;
 
-static yyconst int yy_ec[256] =
+static yyconst flex_int32_t yy_ec[256] =
     {   0,
         1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
         1,    1,    2,    1,    1,    1,    1,    1,    1,    1,
@@ -327,13 +415,13 @@ static yyconst int yy_ec[256] =
        15,   15,   15,   15,   15
     } ;
 
-static yyconst int yy_meta[19] =
+static yyconst flex_int32_t yy_meta[19] =
     {   0,
         1,    1,    2,    1,    1,    1,    3,    3,    3,    4,
         4,    1,    5,    4,    3,    1,    3,    3
     } ;
 
-static yyconst short int yy_base[45] =
+static yyconst flex_int16_t yy_base[45] =
     {   0,
         0,    0,   61,   86,   58,   86,   55,   14,   23,   43,
        10,   46,   86,   28,   47,   40,   86,   16,   86,   22,
@@ -342,7 +430,7 @@ static yyconst short int yy_base[45] =
        70,   75,   77,   80
     } ;
 
-static yyconst short int yy_def[45] =
+static yyconst flex_int16_t yy_def[45] =
     {   0,
        37,    1,   37,   37,   37,   37,   38,   39,   37,   40,
         9,    9,   37,   41,   37,   38,   37,   39,   37,   42,
@@ -351,7 +439,7 @@ static yyconst short int yy_def[45] =
        37,   37,   37,   37
     } ;
 
-static yyconst short int yy_nxt[105] =
+static yyconst flex_int16_t yy_nxt[105] =
     {   0,
         4,    5,    6,    7,    8,    9,    9,   10,    4,   11,
        12,   13,   14,   14,   14,    4,   14,   14,   19,   23,
@@ -367,7 +455,7 @@ static yyconst short int yy_nxt[105] =
        37,   37,   37,   37
     } ;
 
-static yyconst short int yy_chk[105] =
+static yyconst flex_int16_t yy_chk[105] =
     {   0,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    8,   11,
@@ -386,6 +474,9 @@ static yyconst short int yy_chk[105] =
 static yy_state_type yy_last_accepting_state;
 static char *yy_last_accepting_cpos;
 
+extern int yy_flex_debug;
+int yy_flex_debug = 0;
+
 /* The intent behind this definition is that it'll catch
  * any uses of REJECT which flex missed.
  */
@@ -395,7 +486,6 @@ static char *yy_last_accepting_cpos;
 #define YY_RESTORE_YY_MORE_OFFSET
 char *yytext;
 #line 1 "pool_config.l"
-#define INITIAL 0
 /* -*-pgsql-c-*- */
 /*
  *
@@ -447,9 +537,23 @@ typedef enum {
 static char *extract_string(char *value, POOL_TOKEN token);
 static char **extract_string_tokens(char *str, char *delim, int *n);
 
-#define YY_NEVER_INTERACTIVE 1
-#define YY_NO_UNPUT 1
-#line 453 "pool_config.c"
+#line 541 "pool_config.c"
+
+#define INITIAL 0
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+static int yy_init_globals (void );
 
 /* Macros after this point can all be overridden by user definitions in
  * section 1.
@@ -457,65 +561,28 @@ static char **extract_string_tokens(char *str, char *delim, int *n);
 
 #ifndef YY_SKIP_YYWRAP
 #ifdef __cplusplus
-extern "C" int yywrap YY_PROTO(( void ));
+extern "C" int yywrap (void );
 #else
-extern int yywrap YY_PROTO(( void ));
-#endif
+extern int yywrap (void );
 #endif
-
-#ifndef YY_NO_UNPUT
-static void yyunput YY_PROTO(( int c, char *buf_ptr ));
 #endif
 
 #ifndef yytext_ptr
-static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int ));
+static void yy_flex_strncpy (char *,yyconst char *,int );
 #endif
 
 #ifdef YY_NEED_STRLEN
-static int yy_flex_strlen YY_PROTO(( yyconst char * ));
+static int yy_flex_strlen (yyconst char * );
 #endif
 
 #ifndef YY_NO_INPUT
+
 #ifdef __cplusplus
-static int yyinput YY_PROTO(( void ));
+static int yyinput (void );
 #else
-static int input YY_PROTO(( void ));
-#endif
+static int input (void );
 #endif
 
-#if YY_STACK_USED
-static int yy_start_stack_ptr = 0;
-static int yy_start_stack_depth = 0;
-static int *yy_start_stack = 0;
-#ifndef YY_NO_PUSH_STATE
-static void yy_push_state YY_PROTO(( int new_state ));
-#endif
-#ifndef YY_NO_POP_STATE
-static void yy_pop_state YY_PROTO(( void ));
-#endif
-#ifndef YY_NO_TOP_STATE
-static int yy_top_state YY_PROTO(( void ));
-#endif
-
-#else
-#define YY_NO_PUSH_STATE 1
-#define YY_NO_POP_STATE 1
-#define YY_NO_TOP_STATE 1
-#endif
-
-#ifdef YY_MALLOC_DECL
-YY_MALLOC_DECL
-#else
-#if __STDC__
-#ifndef __cplusplus
-#include <stdlib.h>
-#endif
-#else
-/* Just try to get by without declaring the routines.  This will fail
- * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
- * or sizeof(void*) != sizeof(int).
- */
-#endif
 #endif
 
 /* Amount of stuff to slurp up with each read. */
@@ -524,7 +591,6 @@ YY_MALLOC_DECL
 #endif
 
 /* Copy whatever the last rule matched to the standard output. */
-
 #ifndef ECHO
 /* This used to be an fputs(), but since the string might contain NUL's,
  * we now use fwrite().
@@ -537,9 +603,10 @@ YY_MALLOC_DECL
  */
 #ifndef YY_INPUT
 #define YY_INPUT(buf,result,max_size) \
-       if ( yy_current_buffer->yy_is_interactive ) \
+       if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
                { \
-               int c = '*', n; \
+               int c = '*'; \
+               size_t n; \
                for ( n = 0; n < max_size && \
                             (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
                        buf[n] = (char) c; \
@@ -549,9 +616,22 @@ YY_MALLOC_DECL
                        YY_FATAL_ERROR( "input in flex scanner failed" ); \
                result = n; \
                } \
-       else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \
-                 && ferror( yyin ) ) \
-               YY_FATAL_ERROR( "input in flex scanner failed" );
+       else \
+               { \
+               errno=0; \
+               while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+                       { \
+                       if( errno != EINTR) \
+                               { \
+                               YY_FATAL_ERROR( "input in flex scanner failed" ); \
+                               break; \
+                               } \
+                       errno=0; \
+                       clearerr(yyin); \
+                       } \
+               }\
+\
+
 #endif
 
 /* No semi-colon after return; correct usage is to write "yyterminate();" -
@@ -572,12 +652,18 @@ YY_MALLOC_DECL
 #define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
 #endif
 
+/* end tables serialization structures and prototypes */
+
 /* Default declaration of generated scanner - a define so the user can
  * easily add parameters.
  */
 #ifndef YY_DECL
-#define YY_DECL int yylex YY_PROTO(( void ))
-#endif
+#define YY_DECL_IS_OURS 1
+
+extern int yylex (void);
+
+#define YY_DECL int yylex (void)
+#endif /* !YY_DECL */
 
 /* Code executed at the beginning of each rule, after yytext and yyleng
  * have been set up.
@@ -594,27 +680,29 @@ YY_MALLOC_DECL
 #define YY_RULE_SETUP \
        YY_USER_ACTION
 
+/** The main scanner function which does all the work.
+ */
 YY_DECL
-       {
+{
        register yy_state_type yy_current_state;
-       register char *yy_cp = NULL, *yy_bp = NULL;
+       register char *yy_cp, *yy_bp;
        register int yy_act;
-
+    
 #line 77 "pool_config.l"
 
 
-#line 607 "pool_config.c"
+#line 695 "pool_config.c"
 
-       if ( yy_init )
+       if ( !(yy_init) )
                {
-               yy_init = 0;
+               (yy_init) = 1;
 
 #ifdef YY_USER_INIT
                YY_USER_INIT;
 #endif
 
-               if ( ! yy_start )
-                       yy_start = 1;   /* first start state */
+               if ( ! (yy_start) )
+                       (yy_start) = 1; /* first start state */
 
                if ( ! yyin )
                        yyin = stdin;
@@ -622,34 +710,36 @@ YY_DECL
                if ( ! yyout )
                        yyout = stdout;
 
-               if ( ! yy_current_buffer )
-                       yy_current_buffer =
-                               yy_create_buffer( yyin, YY_BUF_SIZE );
+               if ( ! YY_CURRENT_BUFFER ) {
+                       yyensure_buffer_stack ();
+                       YY_CURRENT_BUFFER_LVALUE =
+                               yy_create_buffer(yyin,YY_BUF_SIZE );
+               }
 
-               yy_load_buffer_state();
+               yy_load_buffer_state( );
                }
 
        while ( 1 )             /* loops until end-of-file is reached */
                {
-               yy_cp = yy_c_buf_p;
+               yy_cp = (yy_c_buf_p);
 
                /* Support of yytext. */
-               *yy_cp = yy_hold_char;
+               *yy_cp = (yy_hold_char);
 
                /* yy_bp points to the position in yy_ch_buf of the start of
                 * the current run.
                 */
                yy_bp = yy_cp;
 
-               yy_current_state = yy_start;
+               yy_current_state = (yy_start);
 yy_match:
                do
                        {
                        register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
                        if ( yy_accept[yy_current_state] )
                                {
-                               yy_last_accepting_state = yy_current_state;
-                               yy_last_accepting_cpos = yy_cp;
+                               (yy_last_accepting_state) = yy_current_state;
+                               (yy_last_accepting_cpos) = yy_cp;
                                }
                        while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
                                {
@@ -660,33 +750,28 @@ yy_match:
                        yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
                        ++yy_cp;
                        }
-               while ( yy_base[yy_current_state] != 86 );
+               while ( yy_current_state != 37 );
+               yy_cp = (yy_last_accepting_cpos);
+               yy_current_state = (yy_last_accepting_state);
 
 yy_find_action:
                yy_act = yy_accept[yy_current_state];
-               if ( yy_act == 0 )
-                       { /* have to back up */
-                       yy_cp = yy_last_accepting_cpos;
-                       yy_current_state = yy_last_accepting_state;
-                       yy_act = yy_accept[yy_current_state];
-                       }
 
                YY_DO_BEFORE_ACTION;
 
-
 do_action:     /* This label is used only to access EOF actions. */
 
-
                switch ( yy_act )
        { /* beginning of action switch */
                        case 0: /* must back up */
                        /* undo the effects of YY_DO_BEFORE_ACTION */
-                       *yy_cp = yy_hold_char;
-                       yy_cp = yy_last_accepting_cpos;
-                       yy_current_state = yy_last_accepting_state;
+                       *yy_cp = (yy_hold_char);
+                       yy_cp = (yy_last_accepting_cpos);
+                       yy_current_state = (yy_last_accepting_state);
                        goto yy_find_action;
 
 case 1:
+/* rule 1 can match eol */
 YY_RULE_SETUP
 #line 79 "pool_config.l"
 Lineno++; return POOL_EOL;
@@ -697,8 +782,8 @@ YY_RULE_SETUP
 /* eat whitespace */
        YY_BREAK
 case 3:
-*yy_cp = yy_hold_char; /* undo effects of setting up yytext */
-yy_c_buf_p = yy_cp -= 1;
+*yy_cp = (yy_hold_char); /* undo effects of setting up yytext */
+(yy_c_buf_p) = yy_cp -= 1;
 YY_DO_BEFORE_ACTION; /* set up yytext again */
 YY_RULE_SETUP
 #line 81 "pool_config.l"
@@ -744,33 +829,33 @@ YY_RULE_SETUP
 #line 92 "pool_config.l"
 ECHO;
        YY_BREAK
-#line 748 "pool_config.c"
+#line 833 "pool_config.c"
 case YY_STATE_EOF(INITIAL):
        yyterminate();
 
        case YY_END_OF_BUFFER:
                {
                /* Amount of text matched not including the EOB char. */
-               int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1;
+               int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
 
                /* Undo the effects of YY_DO_BEFORE_ACTION. */
-               *yy_cp = yy_hold_char;
+               *yy_cp = (yy_hold_char);
                YY_RESTORE_YY_MORE_OFFSET
 
-               if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )
+               if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
                        {
                        /* We're scanning a new file or input source.  It's
                         * possible that this happened because the user
                         * just pointed yyin at a new source and called
                         * yylex().  If so, then we have to assure
-                        * consistency between yy_current_buffer and our
+                        * consistency between YY_CURRENT_BUFFER and our
                         * globals.  Here is the right place to do so, because
                         * this is the first action (other than possibly a
                         * back-up) that will match for the new input source.
                         */
-                       yy_n_chars = yy_current_buffer->yy_n_chars;
-                       yy_current_buffer->yy_input_file = yyin;
-                       yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
+                       (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+                       YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+                       YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
                        }
 
                /* Note that here we test for yy_c_buf_p "<=" to the position
@@ -780,13 +865,13 @@ case YY_STATE_EOF(INITIAL):
                 * end-of-buffer state).  Contrast this with the test
                 * in input().
                 */
-               if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+               if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
                        { /* This was really a NUL. */
                        yy_state_type yy_next_state;
 
-                       yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
+                       (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
 
-                       yy_current_state = yy_get_previous_state();
+                       yy_current_state = yy_get_previous_state(  );
 
                        /* Okay, we're now positioned to make the NUL
                         * transition.  We couldn't have
@@ -799,30 +884,31 @@ case YY_STATE_EOF(INITIAL):
 
                        yy_next_state = yy_try_NUL_trans( yy_current_state );
 
-                       yy_bp = yytext_ptr + YY_MORE_ADJ;
+                       yy_bp = (yytext_ptr) + YY_MORE_ADJ;
 
                        if ( yy_next_state )
                                {
                                /* Consume the NUL. */
-                               yy_cp = ++yy_c_buf_p;
+                               yy_cp = ++(yy_c_buf_p);
                                yy_current_state = yy_next_state;
                                goto yy_match;
                                }
 
                        else
                                {
-                               yy_cp = yy_c_buf_p;
+                               yy_cp = (yy_last_accepting_cpos);
+                               yy_current_state = (yy_last_accepting_state);
                                goto yy_find_action;
                                }
                        }
 
-               else switch ( yy_get_next_buffer() )
+               else switch ( yy_get_next_buffer(  ) )
                        {
                        case EOB_ACT_END_OF_FILE:
                                {
-                               yy_did_buffer_switch_on_eof = 0;
+                               (yy_did_buffer_switch_on_eof) = 0;
 
-                               if ( yywrap() )
+                               if ( yywrap( ) )
                                        {
                                        /* Note: because we've taken care in
                                         * yy_get_next_buffer() to have set up
@@ -833,7 +919,7 @@ case YY_STATE_EOF(INITIAL):
                                         * YY_NULL, it'll still work - another
                                         * YY_NULL will get returned.
                                         */
-                                       yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
+                                       (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
 
                                        yy_act = YY_STATE_EOF(YY_START);
                                        goto do_action;
@@ -841,30 +927,30 @@ case YY_STATE_EOF(INITIAL):
 
                                else
                                        {
-                                       if ( ! yy_did_buffer_switch_on_eof )
+                                       if ( ! (yy_did_buffer_switch_on_eof) )
                                                YY_NEW_FILE;
                                        }
                                break;
                                }
 
                        case EOB_ACT_CONTINUE_SCAN:
-                               yy_c_buf_p =
-                                       yytext_ptr + yy_amount_of_matched_text;
+                               (yy_c_buf_p) =
+                                       (yytext_ptr) + yy_amount_of_matched_text;
 
-                               yy_current_state = yy_get_previous_state();
+                               yy_current_state = yy_get_previous_state(  );
 
-                               yy_cp = yy_c_buf_p;
-                               yy_bp = yytext_ptr + YY_MORE_ADJ;
+                               yy_cp = (yy_c_buf_p);
+                               yy_bp = (yytext_ptr) + YY_MORE_ADJ;
                                goto yy_match;
 
                        case EOB_ACT_LAST_MATCH:
-                               yy_c_buf_p =
-                               &yy_current_buffer->yy_ch_buf[yy_n_chars];
+                               (yy_c_buf_p) =
+                               &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
 
-                               yy_current_state = yy_get_previous_state();
+                               yy_current_state = yy_get_previous_state(  );
 
-                               yy_cp = yy_c_buf_p;
-                               yy_bp = yytext_ptr + YY_MORE_ADJ;
+                               yy_cp = (yy_c_buf_p);
+                               yy_bp = (yytext_ptr) + YY_MORE_ADJ;
                                goto yy_find_action;
                        }
                break;
@@ -875,8 +961,7 @@ case YY_STATE_EOF(INITIAL):
                        "fatal flex scanner internal error--no action found" );
        } /* end of action switch */
                } /* end of scanning one token */
-       } /* end of yylex */
-
+} /* end of yylex */
 
 /* yy_get_next_buffer - try to read in a new buffer
  *
@@ -885,21 +970,20 @@ case YY_STATE_EOF(INITIAL):
  *     EOB_ACT_CONTINUE_SCAN - continue scanning from current position
  *     EOB_ACT_END_OF_FILE - end of file
  */
-
-static int yy_get_next_buffer()
-       {
-       register char *dest = yy_current_buffer->yy_ch_buf;
-       register char *source = yytext_ptr;
+static int yy_get_next_buffer (void)
+{
+       register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+       register char *source = (yytext_ptr);
        register int number_to_move, i;
        int ret_val;
 
-       if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )
+       if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
                YY_FATAL_ERROR(
                "fatal flex scanner internal error--end of buffer missed" );
 
-       if ( yy_current_buffer->yy_fill_buffer == 0 )
+       if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
                { /* Don't try to fill the buffer, so this is an EOF. */
-               if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )
+               if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
                        {
                        /* We matched a single character, the EOB, so
                         * treat this as a final EOF.
@@ -919,34 +1003,30 @@ static int yy_get_next_buffer()
        /* Try to read more data. */
 
        /* First move last chars to start of buffer. */
-       number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;
+       number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
 
        for ( i = 0; i < number_to_move; ++i )
                *(dest++) = *(source++);
 
-       if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+       if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
                /* don't do the read, it's not guaranteed to return an EOF,
                 * just force an EOF
                 */
-               yy_current_buffer->yy_n_chars = yy_n_chars = 0;
+               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
 
        else
                {
-               int num_to_read =
-                       yy_current_buffer->yy_buf_size - number_to_move - 1;
+                       int num_to_read =
+                       YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
 
                while ( num_to_read <= 0 )
                        { /* Not enough room in the buffer - grow it. */
-#ifdef YY_USES_REJECT
-                       YY_FATAL_ERROR(
-"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
-#else
 
                        /* just a shorter name for the current buffer */
-                       YY_BUFFER_STATE b = yy_current_buffer;
+                       YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
 
                        int yy_c_buf_p_offset =
-                               (int) (yy_c_buf_p - b->yy_ch_buf);
+                               (int) ((yy_c_buf_p) - b->yy_ch_buf);
 
                        if ( b->yy_is_our_buffer )
                                {
@@ -959,8 +1039,7 @@ static int yy_get_next_buffer()
 
                                b->yy_ch_buf = (char *)
                                        /* Include room in for 2 EOB chars. */
-                                       yy_flex_realloc( (void *) b->yy_ch_buf,
-                                                        b->yy_buf_size + 2 );
+                                       yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2  );
                                }
                        else
                                /* Can't grow it, we don't own it. */
@@ -970,35 +1049,35 @@ static int yy_get_next_buffer()
                                YY_FATAL_ERROR(
                                "fatal error - scanner input buffer overflow" );
 
-                       yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+                       (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
 
-                       num_to_read = yy_current_buffer->yy_buf_size -
+                       num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
                                                number_to_move - 1;
-#endif
+
                        }
 
                if ( num_to_read > YY_READ_BUF_SIZE )
                        num_to_read = YY_READ_BUF_SIZE;
 
                /* Read in more data. */
-               YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),
-                       yy_n_chars, num_to_read );
+               YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+                       (yy_n_chars), num_to_read );
 
-               yy_current_buffer->yy_n_chars = yy_n_chars;
+               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
                }
 
-       if ( yy_n_chars == 0 )
+       if ( (yy_n_chars) == 0 )
                {
                if ( number_to_move == YY_MORE_ADJ )
                        {
                        ret_val = EOB_ACT_END_OF_FILE;
-                       yyrestart( yyin );
+                       yyrestart(yyin  );
                        }
 
                else
                        {
                        ret_val = EOB_ACT_LAST_MATCH;
-                       yy_current_buffer->yy_buffer_status =
+                       YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
                                YY_BUFFER_EOF_PENDING;
                        }
                }
@@ -1006,32 +1085,31 @@ static int yy_get_next_buffer()
        else
                ret_val = EOB_ACT_CONTINUE_SCAN;
 
-       yy_n_chars += number_to_move;
-       yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
-       yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+       (yy_n_chars) += number_to_move;
+       YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+       YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
 
-       yytext_ptr = &yy_current_buffer->yy_ch_buf[0];
+       (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
 
        return ret_val;
-       }
-
+}
 
 /* yy_get_previous_state - get the state just before the EOB char was reached */
 
-static yy_state_type yy_get_previous_state()
-       {
+    static yy_state_type yy_get_previous_state (void)
+{
        register yy_state_type yy_current_state;
        register char *yy_cp;
+    
+       yy_current_state = (yy_start);
 
-       yy_current_state = yy_start;
-
-       for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )
+       for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
                {
                register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
                if ( yy_accept[yy_current_state] )
                        {
-                       yy_last_accepting_state = yy_current_state;
-                       yy_last_accepting_cpos = yy_cp;
+                       (yy_last_accepting_state) = yy_current_state;
+                       (yy_last_accepting_cpos) = yy_cp;
                        }
                while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
                        {
@@ -1043,30 +1121,23 @@ static yy_state_type yy_get_previous_state()
                }
 
        return yy_current_state;
-       }
-
+}
 
 /* yy_try_NUL_trans - try to make a transition on the NUL character
  *
  * synopsis
  *     next_state = yy_try_NUL_trans( current_state );
  */
-
-#ifdef YY_USE_PROTOS
-static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state )
-#else
-static yy_state_type yy_try_NUL_trans( yy_current_state )
-yy_state_type yy_current_state;
-#endif
-       {
+    static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state )
+{
        register int yy_is_jam;
-       register char *yy_cp = yy_c_buf_p;
+       register char *yy_cp = (yy_c_buf_p);
 
        register YY_CHAR yy_c = 1;
        if ( yy_accept[yy_current_state] )
                {
-               yy_last_accepting_state = yy_current_state;
-               yy_last_accepting_cpos = yy_cp;
+               (yy_last_accepting_state) = yy_current_state;
+               (yy_last_accepting_cpos) = yy_cp;
                }
        while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
                {
@@ -1078,81 +1149,36 @@ yy_state_type yy_current_state;
        yy_is_jam = (yy_current_state == 37);
 
        return yy_is_jam ? 0 : yy_current_state;
-       }
-
-
-#ifndef YY_NO_UNPUT
-#ifdef YY_USE_PROTOS
-static void yyunput( int c, register char *yy_bp )
-#else
-static void yyunput( c, yy_bp )
-int c;
-register char *yy_bp;
-#endif
-       {
-       register char *yy_cp = yy_c_buf_p;
-
-       /* undo effects of setting up yytext */
-       *yy_cp = yy_hold_char;
-
-       if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
-               { /* need to shift things up to make room */
-               /* +2 for EOB chars. */
-               register int number_to_move = yy_n_chars + 2;
-               register char *dest = &yy_current_buffer->yy_ch_buf[
-                                       yy_current_buffer->yy_buf_size + 2];
-               register char *source =
-                               &yy_current_buffer->yy_ch_buf[number_to_move];
-
-               while ( source > yy_current_buffer->yy_ch_buf )
-                       *--dest = *--source;
-
-               yy_cp += (int) (dest - source);
-               yy_bp += (int) (dest - source);
-               yy_current_buffer->yy_n_chars =
-                       yy_n_chars = yy_current_buffer->yy_buf_size;
-
-               if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
-                       YY_FATAL_ERROR( "flex scanner push-back overflow" );
-               }
-
-       *--yy_cp = (char) c;
-
-
-       yytext_ptr = yy_bp;
-       yy_hold_char = *yy_cp;
-       yy_c_buf_p = yy_cp;
-       }
-#endif /* ifndef YY_NO_UNPUT */
-
+}
 
 #ifndef YY_NO_INPUT
 #ifdef __cplusplus
-static int yyinput()
+    static int yyinput (void)
 #else
-static int input()
+    static int input  (void)
 #endif
-       {
-       int c;
 
-       *yy_c_buf_p = yy_hold_char;
+{
+       int c;
+    
+       *(yy_c_buf_p) = (yy_hold_char);
 
-       if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+       if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
                {
                /* yy_c_buf_p now points to the character we want to return.
                 * If this occurs *before* the EOB characters, then it's a
                 * valid NUL; if not, then we've hit the end of the buffer.
                 */
-               if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+               if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
                        /* This was really a NUL. */
-                       *yy_c_buf_p = '\0';
+                       *(yy_c_buf_p) = '\0';
 
                else
                        { /* need more input */
-                       int offset = yy_c_buf_p - yytext_ptr;
-                       ++yy_c_buf_p;
+                       int offset = (yy_c_buf_p) - (yytext_ptr);
+                       ++(yy_c_buf_p);
 
-                       switch ( yy_get_next_buffer() )
+                       switch ( yy_get_next_buffer(  ) )
                                {
                                case EOB_ACT_LAST_MATCH:
                                        /* This happens because yy_g_n_b()
@@ -1166,16 +1192,16 @@ static int input()
                                         */
 
                                        /* Reset buffer status. */
-                                       yyrestart( yyin );
+                                       yyrestart(yyin );
 
-                                       /* fall through */
+                                       /*FALLTHROUGH*/
 
                                case EOB_ACT_END_OF_FILE:
                                        {
-                                       if ( yywrap() )
+                                       if ( yywrap( ) )
                                                return EOF;
 
-                                       if ( ! yy_did_buffer_switch_on_eof )
+                                       if ( ! (yy_did_buffer_switch_on_eof) )
                                                YY_NEW_FILE;
 #ifdef __cplusplus
                                        return yyinput();
@@ -1185,90 +1211,92 @@ static int input()
                                        }
 
                                case EOB_ACT_CONTINUE_SCAN:
-                                       yy_c_buf_p = yytext_ptr + offset;
+                                       (yy_c_buf_p) = (yytext_ptr) + offset;
                                        break;
                                }
                        }
                }
 
-       c = *(unsigned char *) yy_c_buf_p;      /* cast for 8-bit char's */
-       *yy_c_buf_p = '\0';     /* preserve yytext */
-       yy_hold_char = *++yy_c_buf_p;
-
+       c = *(unsigned char *) (yy_c_buf_p);    /* cast for 8-bit char's */
+       *(yy_c_buf_p) = '\0';   /* preserve yytext */
+       (yy_hold_char) = *++(yy_c_buf_p);
 
        return c;
-       }
-#endif /* YY_NO_INPUT */
-
-#ifdef YY_USE_PROTOS
-void yyrestart( FILE *input_file )
-#else
-void yyrestart( input_file )
-FILE *input_file;
-#endif
-       {
-       if ( ! yy_current_buffer )
-               yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );
+}
+#endif /* ifndef YY_NO_INPUT */
 
-       yy_init_buffer( yy_current_buffer, input_file );
-       yy_load_buffer_state();
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * 
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+    void yyrestart  (FILE * input_file )
+{
+    
+       if ( ! YY_CURRENT_BUFFER ){
+        yyensure_buffer_stack ();
+               YY_CURRENT_BUFFER_LVALUE =
+            yy_create_buffer(yyin,YY_BUF_SIZE );
        }
 
+       yy_init_buffer(YY_CURRENT_BUFFER,input_file );
+       yy_load_buffer_state( );
+}
 
-#ifdef YY_USE_PROTOS
-void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
-#else
-void yy_switch_to_buffer( new_buffer )
-YY_BUFFER_STATE new_buffer;
-#endif
-       {
-       if ( yy_current_buffer == new_buffer )
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * 
+ */
+    void yy_switch_to_buffer  (YY_BUFFER_STATE  new_buffer )
+{
+    
+       /* TODO. We should be able to replace this entire function body
+        * with
+        *              yypop_buffer_state();
+        *              yypush_buffer_state(new_buffer);
+     */
+       yyensure_buffer_stack ();
+       if ( YY_CURRENT_BUFFER == new_buffer )
                return;
 
-       if ( yy_current_buffer )
+       if ( YY_CURRENT_BUFFER )
                {
                /* Flush out information for old buffer. */
-               *yy_c_buf_p = yy_hold_char;
-               yy_current_buffer->yy_buf_pos = yy_c_buf_p;
-               yy_current_buffer->yy_n_chars = yy_n_chars;
+               *(yy_c_buf_p) = (yy_hold_char);
+               YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
                }
 
-       yy_current_buffer = new_buffer;
-       yy_load_buffer_state();
+       YY_CURRENT_BUFFER_LVALUE = new_buffer;
+       yy_load_buffer_state( );
 
        /* We don't actually know whether we did this switch during
         * EOF (yywrap()) processing, but the only time this flag
         * is looked at is after yywrap() is called, so it's safe
         * to go ahead and always set it.
         */
-       yy_did_buffer_switch_on_eof = 1;
-       }
-
-
-#ifdef YY_USE_PROTOS
-void yy_load_buffer_state( void )
-#else
-void yy_load_buffer_state()
-#endif
-       {
-       yy_n_chars = yy_current_buffer->yy_n_chars;
-       yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
-       yyin = yy_current_buffer->yy_input_file;
-       yy_hold_char = *yy_c_buf_p;
-       }
+       (yy_did_buffer_switch_on_eof) = 1;
+}
 
+static void yy_load_buffer_state  (void)
+{
+       (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+       (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+       yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+       (yy_hold_char) = *(yy_c_buf_p);
+}
 
-#ifdef YY_USE_PROTOS
-YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
-#else
-YY_BUFFER_STATE yy_create_buffer( file, size )
-FILE *file;
-int size;
-#endif
-       {
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * 
+ * @return the allocated buffer state.
+ */
+    YY_BUFFER_STATE yy_create_buffer  (FILE * file, int  size )
+{
        YY_BUFFER_STATE b;
-
-       b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+    
+       b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state )  );
        if ( ! b )
                YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
 
@@ -1277,75 +1305,71 @@ int size;
        /* yy_ch_buf has to be 2 characters longer than the size given because
         * we need to put in 2 end-of-buffer characters.
         */
-       b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );
+       b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2  );
        if ( ! b->yy_ch_buf )
                YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
 
        b->yy_is_our_buffer = 1;
 
-       yy_init_buffer( b, file );
+       yy_init_buffer(b,file );
 
        return b;
-       }
-
+}
 
-#ifdef YY_USE_PROTOS
-void yy_delete_buffer( YY_BUFFER_STATE b )
-#else
-void yy_delete_buffer( b )
-YY_BUFFER_STATE b;
-#endif
-       {
+/** Destroy the buffer.
+ * @param b a buffer created with yy_create_buffer()
+ * 
+ */
+    void yy_delete_buffer (YY_BUFFER_STATE  b )
+{
+    
        if ( ! b )
                return;
 
-       if ( b == yy_current_buffer )
-               yy_current_buffer = (YY_BUFFER_STATE) 0;
+       if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+               YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
 
        if ( b->yy_is_our_buffer )
-               yy_flex_free( (void *) b->yy_ch_buf );
-
-       yy_flex_free( (void *) b );
-       }
-
+               yyfree((void *) b->yy_ch_buf  );
 
+       yyfree((void *) b  );
+}
 
-#ifdef YY_USE_PROTOS
-void yy_init_buffer( YY_BUFFER_STATE b, FILE *file )
-#else
-void yy_init_buffer( b, file )
-YY_BUFFER_STATE b;
-FILE *file;
-#endif
-
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a yyrestart() or at EOF.
+ */
+    static void yy_init_buffer  (YY_BUFFER_STATE  b, FILE * file )
 
-       {
-       yy_flush_buffer( b );
+{
+       int oerrno = errno;
+    
+       yy_flush_buffer(b );
 
        b->yy_input_file = file;
        b->yy_fill_buffer = 1;
 
-#if YY_ALWAYS_INTERACTIVE
-       b->yy_is_interactive = 1;
-#else
-#if YY_NEVER_INTERACTIVE
-       b->yy_is_interactive = 0;
-#else
-       b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
-#endif
-#endif
-       }
-
-
-#ifdef YY_USE_PROTOS
-void yy_flush_buffer( YY_BUFFER_STATE b )
-#else
-void yy_flush_buffer( b )
-YY_BUFFER_STATE b;
-#endif
+    /* If b is the current buffer, then yy_init_buffer was _probably_
+     * called from yyrestart() or through yy_get_next_buffer.
+     * In that case, we don't want to reset the lineno or column.
+     */
+    if (b != YY_CURRENT_BUFFER){
+        b->yy_bs_lineno = 1;
+        b->yy_bs_column = 0;
+    }
+
+        b->yy_is_interactive = 0;
+    
+       errno = oerrno;
+}
 
-       {
-       if ( ! b )
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * 
+ */
+    void yy_flush_buffer (YY_BUFFER_STATE  b )
+{
+       if ( ! b )
                return;
 
        b->yy_n_chars = 0;
@@ -1362,29 +1386,121 @@ YY_BUFFER_STATE b;
        b->yy_at_bol = 1;
        b->yy_buffer_status = YY_BUFFER_NEW;
 
-       if ( b == yy_current_buffer )
-               yy_load_buffer_state();
+       if ( b == YY_CURRENT_BUFFER )
+               yy_load_buffer_state( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ *  the current state. This function will allocate the stack
+ *  if necessary.
+ *  @param new_buffer The new state.
+ *  
+ */
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+       if (new_buffer == NULL)
+               return;
+
+       yyensure_buffer_stack();
+
+       /* This block is copied from yy_switch_to_buffer. */
+       if ( YY_CURRENT_BUFFER )
+               {
+               /* Flush out information for old buffer. */
+               *(yy_c_buf_p) = (yy_hold_char);
+               YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+               }
+
+       /* Only push if top exists. Otherwise, replace top. */
+       if (YY_CURRENT_BUFFER)
+               (yy_buffer_stack_top)++;
+       YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+       /* copied from yy_switch_to_buffer. */
+       yy_load_buffer_state( );
+       (yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ *  The next element becomes the new top.
+ *  
+ */
+void yypop_buffer_state (void)
+{
+       if (!YY_CURRENT_BUFFER)
+               return;
+
+       yy_delete_buffer(YY_CURRENT_BUFFER );
+       YY_CURRENT_BUFFER_LVALUE = NULL;
+       if ((yy_buffer_stack_top) > 0)
+               --(yy_buffer_stack_top);
+
+       if (YY_CURRENT_BUFFER) {
+               yy_load_buffer_state( );
+               (yy_did_buffer_switch_on_eof) = 1;
        }
+}
 
+/* Allocates the stack if it does not exist.
+ *  Guarantees space for at least one push.
+ */
+static void yyensure_buffer_stack (void)
+{
+       int num_to_alloc;
+    
+       if (!(yy_buffer_stack)) {
+
+               /* First allocation is just for 2 elements, since we don't know if this
+                * scanner will even need a stack. We use 2 instead of 1 to avoid an
+                * immediate realloc on the next call.
+         */
+               num_to_alloc = 1;
+               (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
+                                                               (num_to_alloc * sizeof(struct yy_buffer_state*)
+                                                               );
+               
+               memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+                               
+               (yy_buffer_stack_max) = num_to_alloc;
+               (yy_buffer_stack_top) = 0;
+               return;
+       }
 
-#ifndef YY_NO_SCAN_BUFFER
-#ifdef YY_USE_PROTOS
-YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size )
-#else
-YY_BUFFER_STATE yy_scan_buffer( base, size )
-char *base;
-yy_size_t size;
-#endif
-       {
-       YY_BUFFER_STATE b;
+       if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+               /* Increase the buffer to prepare for a possible push. */
+               int grow_size = 8 /* arbitrary grow size */;
 
+               num_to_alloc = (yy_buffer_stack_max) + grow_size;
+               (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
+                                                               ((yy_buffer_stack),
+                                                               num_to_alloc * sizeof(struct yy_buffer_state*)
+                                                               );
+
+               /* zero only the new slots.*/
+               memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+               (yy_buffer_stack_max) = num_to_alloc;
+       }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * 
+ * @return the newly allocated buffer state object. 
+ */
+YY_BUFFER_STATE yy_scan_buffer  (char * base, yy_size_t  size )
+{
+       YY_BUFFER_STATE b;
+    
        if ( size < 2 ||
             base[size-2] != YY_END_OF_BUFFER_CHAR ||
             base[size-1] != YY_END_OF_BUFFER_CHAR )
                /* They forgot to leave room for the EOB's. */
                return 0;
 
-       b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+       b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state )  );
        if ( ! b )
                YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
 
@@ -1398,56 +1514,51 @@ yy_size_t size;
        b->yy_fill_buffer = 0;
        b->yy_buffer_status = YY_BUFFER_NEW;
 
-       yy_switch_to_buffer( b );
+       yy_switch_to_buffer( );
 
        return b;
-       }
-#endif
-
-
-#ifndef YY_NO_SCAN_STRING
-#ifdef YY_USE_PROTOS
-YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str )
-#else
-YY_BUFFER_STATE yy_scan_string( yy_str )
-yyconst char *yy_str;
-#endif
-       {
-       int len;
-       for ( len = 0; yy_str[len]; ++len )
-               ;
-
-       return yy_scan_bytes( yy_str, len );
-       }
-#endif
+}
 
+/** Setup the input buffer state to scan a string. The next call to yylex() will
+ * scan from a @e copy of @a str.
+ * @param str a NUL-terminated string to scan
+ * 
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ *       yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE yy_scan_string (yyconst char * yystr )
+{
+    
+       return yy_scan_bytes(yystr,strlen(yystr) );
+}
 
-#ifndef YY_NO_SCAN_BYTES
-#ifdef YY_USE_PROTOS
-YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len )
-#else
-YY_BUFFER_STATE yy_scan_bytes( bytes, len )
-yyconst char *bytes;
-int len;
-#endif
-       {
+/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param bytes the byte buffer to scan
+ * @param len the number of bytes in the buffer pointed to by @a bytes.
+ * 
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_bytes  (yyconst char * yybytes, int  _yybytes_len )
+{
        YY_BUFFER_STATE b;
        char *buf;
        yy_size_t n;
        int i;
-
+    
        /* Get memory for full buffer, including space for trailing EOB's. */
-       n = len + 2;
-       buf = (char *) yy_flex_alloc( n );
+       n = _yybytes_len + 2;
+       buf = (char *) yyalloc(n  );
        if ( ! buf )
                YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
 
-       for ( i = 0; i < len; ++i )
-               buf[i] = bytes[i];
+       for ( i = 0; i < _yybytes_len; ++i )
+               buf[i] = yybytes[i];
 
-       buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;
+       buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
 
-       b = yy_scan_buffer( buf, n );
+       b = yy_scan_buffer(buf,n );
        if ( ! b )
                YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
 
@@ -1457,148 +1568,196 @@ int len;
        b->yy_is_our_buffer = 1;
 
        return b;
-       }
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
 #endif
 
+static void yy_fatal_error (yyconst char* msg )
+{
+       (void) fprintf( stderr, "%s\n", msg );
+       exit( YY_EXIT_FAILURE );
+}
 
-#ifndef YY_NO_PUSH_STATE
-#ifdef YY_USE_PROTOS
-static void yy_push_state( int new_state )
-#else
-static void yy_push_state( new_state )
-int new_state;
-#endif
-       {
-       if ( yy_start_stack_ptr >= yy_start_stack_depth )
-               {
-               yy_size_t new_size;
+/* Redefine yyless() so it works in section 3 code. */
 
-               yy_start_stack_depth += YY_START_STACK_INCR;
-               new_size = yy_start_stack_depth * sizeof( int );
+#undef yyless
+#define yyless(n) \
+       do \
+               { \
+               /* Undo effects of setting up yytext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+               yytext[yyleng] = (yy_hold_char); \
+               (yy_c_buf_p) = yytext + yyless_macro_arg; \
+               (yy_hold_char) = *(yy_c_buf_p); \
+               *(yy_c_buf_p) = '\0'; \
+               yyleng = yyless_macro_arg; \
+               } \
+       while ( 0 )
 
-               if ( ! yy_start_stack )
-                       yy_start_stack = (int *) yy_flex_alloc( new_size );
+/* Accessor  methods (get/set functions) to struct members. */
 
-               else
-                       yy_start_stack = (int *) yy_flex_realloc(
-                                       (void *) yy_start_stack, new_size );
+/** Get the current line number.
+ * 
+ */
+int yyget_lineno  (void)
+{
+        
+    return yylineno;
+}
 
-               if ( ! yy_start_stack )
-                       YY_FATAL_ERROR(
-                       "out of memory expanding start-condition stack" );
-               }
+/** Get the input stream.
+ * 
+ */
+FILE *yyget_in  (void)
+{
+        return yyin;
+}
 
-       yy_start_stack[yy_start_stack_ptr++] = YY_START;
+/** Get the output stream.
+ * 
+ */
+FILE *yyget_out  (void)
+{
+        return yyout;
+}
 
-       BEGIN(new_state);
-       }
-#endif
+/** Get the length of the current token.
+ * 
+ */
+int yyget_leng  (void)
+{
+        return yyleng;
+}
 
+/** Get the current token.
+ * 
+ */
 
-#ifndef YY_NO_POP_STATE
-static void yy_pop_state()
-       {
-       if ( --yy_start_stack_ptr < 0 )
-               YY_FATAL_ERROR( "start-condition stack underflow" );
+char *yyget_text  (void)
+{
+        return yytext;
+}
 
-       BEGIN(yy_start_stack[yy_start_stack_ptr]);
-       }
-#endif
+/** Set the current line number.
+ * @param line_number
+ * 
+ */
+void yyset_lineno (int  line_number )
+{
+    
+    yylineno = line_number;
+}
 
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ * 
+ * @see yy_switch_to_buffer
+ */
+void yyset_in (FILE *  in_str )
+{
+        yyin = in_str ;
+}
 
-#ifndef YY_NO_TOP_STATE
-static int yy_top_state()
-       {
-       return yy_start_stack[yy_start_stack_ptr - 1];
-       }
-#endif
+void yyset_out (FILE *  out_str )
+{
+        yyout = out_str ;
+}
 
-#ifndef YY_EXIT_FAILURE
-#define YY_EXIT_FAILURE 2
-#endif
+int yyget_debug  (void)
+{
+        return yy_flex_debug;
+}
 
-#ifdef YY_USE_PROTOS
-static void yy_fatal_error( yyconst char msg[] )
+void yyset_debug (int  bdebug )
+{
+        yy_flex_debug = bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+        /* Initialization is the same as for the non-reentrant scanner.
+     * This function is called from yylex_destroy(), so don't allocate here.
+     */
+
+    (yy_buffer_stack) = 0;
+    (yy_buffer_stack_top) = 0;
+    (yy_buffer_stack_max) = 0;
+    (yy_c_buf_p) = (char *) 0;
+    (yy_init) = 0;
+    (yy_start) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+    yyin = stdin;
+    yyout = stdout;
 #else
-static void yy_fatal_error( msg )
-char msg[];
+    yyin = (FILE *) 0;
+    yyout = (FILE *) 0;
 #endif
-       {
-       (void) fprintf( stderr, "%s\n", msg );
-       exit( YY_EXIT_FAILURE );
-       }
 
+    /* For future reference: Set errno on error, since we are called by
+     * yylex_init()
+     */
+    return 0;
+}
 
+/* yylex_destroy is for both reentrant and non-reentrant scanners. */
+int yylex_destroy  (void)
+{
+    
+    /* Pop the buffer stack, destroying each element. */
+       while(YY_CURRENT_BUFFER){
+               yy_delete_buffer(YY_CURRENT_BUFFER  );
+               YY_CURRENT_BUFFER_LVALUE = NULL;
+               yypop_buffer_state();
+       }
 
-/* Redefine yyless() so it works in section 3 code. */
+       /* Destroy the stack itself. */
+       yyfree((yy_buffer_stack) );
+       (yy_buffer_stack) = NULL;
 
-#undef yyless
-#define yyless(n) \
-       do \
-               { \
-               /* Undo effects of setting up yytext. */ \
-               yytext[yyleng] = yy_hold_char; \
-               yy_c_buf_p = yytext + n; \
-               yy_hold_char = *yy_c_buf_p; \
-               *yy_c_buf_p = '\0'; \
-               yyleng = n; \
-               } \
-       while ( 0 )
+    /* Reset the globals. This is important in a non-reentrant scanner so the next time
+     * yylex() is called, initialization will occur. */
+    yy_init_globals( );
 
+    return 0;
+}
 
-/* Internal utility routines. */
+/*
+ * Internal utility routines.
+ */
 
 #ifndef yytext_ptr
-#ifdef YY_USE_PROTOS
-static void yy_flex_strncpy( char *s1, yyconst char *s2, int n )
-#else
-static void yy_flex_strncpy( s1, s2, n )
-char *s1;
-yyconst char *s2;
-int n;
-#endif
-       {
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
        register int i;
        for ( i = 0; i < n; ++i )
                s1[i] = s2[i];
-       }
+}
 #endif
 
 #ifdef YY_NEED_STRLEN
-#ifdef YY_USE_PROTOS
-static int yy_flex_strlen( yyconst char *s )
-#else
-static int yy_flex_strlen( s )
-yyconst char *s;
-#endif
-       {
+static int yy_flex_strlen (yyconst char * s )
+{
        register int n;
        for ( n = 0; s[n]; ++n )
                ;
 
        return n;
-       }
+}
 #endif
 
-
-#ifdef YY_USE_PROTOS
-static void *yy_flex_alloc( yy_size_t size )
-#else
-static void *yy_flex_alloc( size )
-yy_size_t size;
-#endif
-       {
+void *yyalloc (yy_size_t  size )
+{
        return (void *) malloc( size );
-       }
+}
 
-#ifdef YY_USE_PROTOS
-static void *yy_flex_realloc( void *ptr, yy_size_t size )
-#else
-static void *yy_flex_realloc( ptr, size )
-void *ptr;
-yy_size_t size;
-#endif
-       {
+void *yyrealloc  (void * ptr, yy_size_t  size )
+{
        /* The cast to (char *) in the following accommodates both
         * implementations that use char* generic pointers, and those
         * that use void* generic pointers.  It works with the latter
@@ -1607,28 +1766,19 @@ yy_size_t size;
         * as though doing an assignment.
         */
        return (void *) realloc( (char *) ptr, size );
-       }
+}
 
-#ifdef YY_USE_PROTOS
-static void yy_flex_free( void *ptr )
-#else
-static void yy_flex_free( ptr )
-void *ptr;
-#endif
-       {
-       free( ptr );
-       }
+void yyfree (void * ptr )
+{
+       free( (char *) ptr );   /* see yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
 
-#if YY_MAIN
-int main()
-       {
-       yylex();
-       return 0;
-       }
-#endif
 #line 92 "pool_config.l"
 
 
+
 static int eval_logical(char *str);
 
 int pool_get_config(char *confpath)
@@ -1676,6 +1826,8 @@ int pool_get_config(char *confpath)
        pool_config.insert_lock = 0;
        pool_config.num_servers = 0;
        pool_config.log_statement = 0;
+       pool_config.log_connections = 0;
+       pool_config.enable_pool_hba = 0;
 #define PARSE_ERROR()          pool_error("pool_config: parse error at line %d '%s'", Lineno, yytext)
 
        /* open config file */
@@ -2154,6 +2306,28 @@ int pool_get_config(char *confpath)
                        }
                        pool_config.log_statement = v;
                }
+               else if (!strcmp(key, "log_connections"))
+               {
+                       int v = eval_logical(yytext);
+
+                       if (v < 0)
+                       {
+                               pool_error("pool_config: invalid value %s for %s", yytext, key);
+                               return(-1);
+                       }
+                       pool_config.log_connections = v;
+               }
+               else if (!strcmp(key, "enable_pool_hba"))
+               {
+                       int v = eval_logical(yytext);
+
+                       if (v < 0)
+                       {
+                               pool_error("pool_config: invalid value %s for %s", yytext, key);
+                               return(-1);
+                       }
+                       pool_config.enable_pool_hba = v;
+               }
        }
 
        if (pool_config.backend_port)
@@ -2230,3 +2404,4 @@ static char **extract_string_tokens(char *str, char *delimi, int *n)
        }
        return tokens;
 }
+
index 0c8ea536eca97519724120dc04465f0adf403742..f40062d10198e4d88b5486ce43789895f2721ca0 100644 (file)
@@ -138,6 +138,8 @@ int pool_get_config(char *confpath)
        pool_config.insert_lock = 0;
        pool_config.num_servers = 0;
        pool_config.log_statement = 0;
+       pool_config.log_connections = 0;
+       pool_config.enable_pool_hba = 0;
 #define PARSE_ERROR()          pool_error("pool_config: parse error at line %d '%s'", Lineno, yytext)
 
        /* open config file */
@@ -616,6 +618,28 @@ int pool_get_config(char *confpath)
                        }
                        pool_config.log_statement = v;
                }
+               else if (!strcmp(key, "log_connections"))
+               {
+                       int v = eval_logical(yytext);
+
+                       if (v < 0)
+                       {
+                               pool_error("pool_config: invalid value %s for %s", yytext, key);
+                               return(-1);
+                       }
+                       pool_config.log_connections = v;
+               }
+               else if (!strcmp(key, "enable_pool_hba"))
+               {
+                       int v = eval_logical(yytext);
+
+                       if (v < 0)
+                       {
+                               pool_error("pool_config: invalid value %s for %s", yytext, key);
+                               return(-1);
+                       }
+                       pool_config.enable_pool_hba = v;
+               }
        }
 
        if (pool_config.backend_port)
diff --git a/pool_hba.c b/pool_hba.c
new file mode 100644 (file)
index 0000000..976b78f
--- /dev/null
@@ -0,0 +1,1420 @@
+/* -*-pgsql-c-*- */
+/*
+ *
+ * $Header$
+ *
+ * pgpool: a language independent connection pool server for PostgreSQL 
+ * written by Tatsuo Ishii
+ *
+ * Portions Copyright (c) 2003-2007    PgPool Global Development Group
+ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California                                          *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of the
+ * author not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. The author makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * pool_hba.c.: Routines to handle host based authentication.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <netdb.h>
+
+#include "pool.h"
+#include "pool_path.h"
+#include "pool_ip.h"
+
+#define MULTI_VALUE_SEP "\001" /* delimiter for multi-valued column strings */
+#define MAX_TOKEN      256
+
+static List *hba_lines = NIL;
+static List *hba_line_nums = NIL;
+static char *hbaFileName;
+
+static void sendAuthRequest(POOL_CONNECTION *frontend, AuthRequest areq);
+static void auth_failed(POOL_CONNECTION *frontend);
+static void close_all_backend_connections(void);
+static bool hba_getauthmethod(POOL_CONNECTION *frontend);
+static bool check_hba(POOL_CONNECTION *frontend);
+static void parse_hba(List *line, int line_num, POOL_CONNECTION *frontend, bool *found_p, bool *error_p);
+static void parse_hba_auth(ListCell **line_item, UserAuth *userauth_p, char **auth_arg_p, bool *error_p);
+static bool check_user(char *user, char *param_str);
+static bool check_db(char *dbname, char *user, char *param_str);
+static void free_lines(List **lines, List **line_nums);
+static void tokenize_file(const char *filename, FILE *file, List **lines, List **line_nums);
+static char *tokenize_inc_file(const char *outer_filename, const char *inc_filename);
+static bool pg_isblank(const char c);
+static void next_token(FILE *fp, char *buf, int bufsz);
+static char * next_token_expand(const char *filename, FILE *file);
+
+#ifdef USE_PAM
+#ifdef HAVE_PAM_PAM_APPL_H
+#include <pam/pam_appl.h>
+#endif
+#ifdef HAVE_SECURITY_PAM_APPL_H
+#include <security/pam_appl.h>
+#endif
+
+#define PGPOOL_PAM_SERVICE "pgpool" /* Service name passed to PAM */
+
+static POOL_STATUS CheckPAMAuth(POOL_CONNECTION *frontend, char *user, char *password);
+static int pam_passwd_conv_proc(int num_msg, const struct pam_message ** msg, struct pam_response ** resp, void *appdata_ptr);
+/*
+ * recv_password_packet is usually used with authentications that require a client
+ * password. However, pgpool's hba function only uses it for PAM authentication,
+ * so declare a prototype here in "#ifdef USE_PAM" to avoid compilation warning.
+ */
+static char *recv_password_packet(POOL_CONNECTION *frontend);
+
+static struct pam_conv pam_passw_conv = {
+       &pam_passwd_conv_proc,
+       NULL
+};
+
+static char *pam_passwd = NULL;        /* Workaround for Solaris 2.6 brokenness */
+static POOL_CONNECTION *pam_frontend_kludge; /* Workaround for passing
+                                                                                         * POOL_CONNECTION *frontend
+                                                                                         * into pam_passwd_conv_proc */
+#endif /* USE_PAM */
+
+
+/*
+ * read in hba config file
+ */
+void load_hba(char *hbapath)
+{
+       FILE *file;
+       
+       if (hba_lines || hba_line_nums)
+               free_lines(&hba_lines, &hba_line_nums);
+
+       file = fopen(hbapath, "r");
+       if (!file)
+       {
+               pool_error("could not open \"%s\". reason: %s",
+                                  hbapath, strerror(errno));
+               exit(1);
+       }
+
+       pool_debug("loading \"%s\" for client authentication configuration file",
+                          hbapath);
+
+       tokenize_file(hbapath, file, &hba_lines, &hba_line_nums);
+       fclose(file);
+
+       hbaFileName = strdup(hbapath);
+       if (hbaFileName == NULL)
+       {
+               pool_error("load_hba: strdup failed: %s", strerror(errno));
+               exit(1);
+       }
+}
+
+
+/*
+ * do frontend <-> pgpool authentication based on pool_hba.conf
+ */
+void ClientAuthentication(POOL_CONNECTION *frontend)
+{
+       POOL_STATUS status = POOL_ERROR;
+
+       if (! hba_getauthmethod(frontend))
+       {
+               pool_error("missing or erroneous pool_hba.conf file");
+               pool_send_error_message(frontend, frontend->protoVersion, "XX000",
+                                                               "missing or erroneous pool_hba.conf file", "",
+                                                               "See pgpool log for details.", __FILE__, __LINE__);
+               close_all_backend_connections();
+               /*
+                * use exit(2) since this is not so fatal. other entries in
+                * pool_hba.conf may be valid, so treat it as reject.
+                */
+               exit(2);
+       }
+
+       switch (frontend->auth_method)
+       {
+               case uaReject:
+               {
+            /*
+                        * This could have come from an explicit "reject" entry in
+                        * pool_hba.conf, but more likely it means there was no matching
+                        * entry.  Take pity on the poor user and issue a helpful
+                        * error message.  NOTE: this is not a security breach,
+                        * because all the info reported here is known at the frontend
+                        * and must be assumed known to bad guys. We're merely helping
+                        * out the less clueful good guys.
+                        */
+                       char hostinfo[NI_MAXHOST];
+                       char *errmessage;
+                       int messagelen;
+
+                       getnameinfo_all(&frontend->raddr.addr, frontend->raddr.salen,
+                                                       hostinfo, sizeof(hostinfo),
+                                                       NULL, 0,
+                                                       NI_NUMERICHOST);
+
+                       messagelen = sizeof(hostinfo) +
+                               strlen(frontend->username) + strlen(frontend->database) + 80;
+                       if ((errmessage = (char *)malloc(messagelen+1)) == NULL)
+                       {
+                               pool_error("ClientAuthentication: malloc failed: %s", strerror(errno));
+                               exit(1);
+                       }
+                       
+#ifdef USE_SSL
+                       snprintf(errmessage, messagelen+7, /* +7 is for "SSL off" */
+                                        "no pool_hba.conf entry for host \"%s\", user \"%s\", database \"%s\", %s",
+                                        hostinfo, frontend->username, frontend->database,
+                                        frontend->ssl ? "SSL on" : "SSL off");
+#else
+                       snprintf(errmessage, messagelen,
+                                        "no pool_hba.conf entry for host \"%s\", user \"%s\", database \"%s\"",
+                                        hostinfo, frontend->username, frontend->database);
+#endif
+                       pool_error(errmessage);
+                       pool_send_error_message(frontend, frontend->protoVersion, "XX000", errmessage,
+                                                                       "", "", __FILE__, __LINE__);
+               
+                       free(errmessage);
+                       break;
+               }
+
+/*             case uaKrb4: */
+/*                     break; */
+
+/*             case uaKrb5: */
+/*                     break; */
+
+/*             case uaIdent: */
+/*                     break; */
+
+/*             case uaMD5: */
+/*                     break; */
+
+/*             case uaCrypt: */
+/*                     break; */
+
+/*             case uaPassword: */
+/*                     break; */
+
+#ifdef USE_PAM
+               case uaPAM:
+                       pam_frontend_kludge = frontend;
+                       status = CheckPAMAuth(frontend, frontend->username, "");
+                       break;
+#endif /* USE_PAM */
+
+               case uaTrust:
+                       status = POOL_CONTINUE;
+                       break;
+       }
+
+       if (status == POOL_CONTINUE)
+               sendAuthRequest(frontend, AUTH_REQ_OK);
+       else if (status != POOL_CONTINUE)
+               auth_failed(frontend);
+}
+
+
+static void sendAuthRequest(POOL_CONNECTION *frontend, AuthRequest areq)
+{
+       int wsize;                                      /* number of bytes to write */
+       int areq_nbo;                           /* areq in network byte order */
+
+       /*
+        * If AUTH_REQ_OK, then frontend is OK to connect __with_pgpool__.
+        * Do not send 'R' to the frontend, he still needs to authenticate
+        * himself with the backend.
+        */
+       if (areq == AUTH_REQ_OK)
+               return;
+
+       /* request a password */
+       pool_write(frontend, "R", 1);
+
+       if (frontend->protoVersion == PROTO_MAJOR_V3)
+       {
+/*             if (areq == AUTH_REQ_MD5) */
+/*                     wsize = htonl(sizeof(int)*2+4); */
+/*             else if (areq == AUTH_REQ_CRYPT) */
+/*                     wsize = htonl(sizeof(int)*2+2); */
+/*             else */
+                       wsize = htonl(sizeof(int)*2);
+               pool_write(frontend, &wsize, sizeof(int));
+       }
+
+       areq_nbo = htonl(areq);
+       pool_write(frontend, &areq_nbo, sizeof(int));
+
+       /* Add the salt for encrypted passwords. */
+/*     if (areq == AUTH_REQ_MD5) */
+/*             pq_sendbytes(&buf, port->md5Salt, 4); */
+/*     else if (areq == AUTH_REQ_CRYPT) */
+/*             pq_sendbytes(&buf, port->cryptSalt, 2); */
+
+       pool_flush(frontend);
+}
+
+
+#ifdef USE_PAM                                 /* see the prototype comment  */
+
+/*
+ * Collect password response packet from frontend.
+ *
+ * Returns NULL if couldn't get password, else malloc'd string.
+ */
+static char *recv_password_packet(POOL_CONNECTION *frontend)
+{
+       int rsize;
+       char *passwd;
+       char *returnVal;
+
+       if (frontend->protoVersion == PROTO_MAJOR_V3)
+       {
+               /* Expect 'p' message type */
+               char kind;
+
+               if (pool_read(frontend, &kind, 1) < 0)
+                       return NULL;
+               
+               if (kind != 'p')
+               {
+                       pool_error("expected password response, got message type %c",
+                                          kind);
+                       return NULL;            /* bad message type */
+               }
+       }
+       /* pre-3.0 protocol does not send a message type */
+       
+       if (pool_read(frontend, &rsize, sizeof(int)) < 0)
+               return NULL;
+
+       rsize = ntohl(rsize) - 4;
+       passwd = pool_read2(frontend, rsize); /* retrieve password */
+       if (passwd == NULL)
+               return NULL;
+
+       /* Do not echo password to logs, for security. */
+       pool_debug("received password packet from frontend for pgpool's HBA");
+
+       /*
+        * Return the received string.  Note we do not attempt to do any
+        * character-set conversion on it; since we don't yet know the
+        * client's encoding, there wouldn't be much point.
+        */
+       returnVal = strdup(passwd);
+       if (returnVal == NULL)
+       {
+               pool_error("recv_password_packet: strdup failed: %s", strerror(errno));
+               exit(1);
+       }
+       return returnVal;
+}
+
+#endif /* USE_PAM */
+
+/*
+ * Tell the user the authentication failed.
+ */
+static void auth_failed(POOL_CONNECTION *frontend)
+{
+       bool send_error_to_frontend = true;
+       int messagelen;
+       char *errmessage;
+
+       messagelen = strlen(frontend->username) + 100;
+       if ((errmessage = (char *)malloc(messagelen+1)) == NULL)
+       {
+               pool_error("auth_failed: malloc failed: %s", strerror(errno));
+               exit(1);
+       }
+
+       switch (frontend->auth_method)
+       {
+               case uaReject:
+                       snprintf(errmessage, messagelen,
+                                        "authentication with pgpool failed for user \"%s\": host rejected",
+                                        frontend->username);
+                       /*
+                        * if uaReject, frontend should have received 'E' and disconnected already.
+                        */
+                       send_error_to_frontend = false;
+                       break;
+/*             case uaKrb4: */
+/*                     snprintf(errmessage, messagelen, */
+/*                                      "Kerberos 4 authentication with pgpool failed for user \"%s\"", */
+/*                                      frontend->username); */
+/*                     break; */
+/*             case uaKrb5: */
+/*                     snprintf(errmessage, messagelen, */
+/*                                      "Kerberos 5 authentication with pgpool failed for user \"%s\"", */
+/*                                      frontend->username); */
+/*                     break; */
+               case uaTrust:
+                       snprintf(errmessage, messagelen,
+                                        "\"trust\" authentication with pgpool failed for user \"%s\"",
+                                        frontend->username);
+                       break;
+/*             case uaIdent: */
+/*                     snprintf(errmessage, messagelen, */
+/*                                      "Ident authentication with pgpool failed for user \"%s\"", */
+/*                                      frontend->username); */
+/*                     break; */
+/*             case uaMD5: */
+/*             case uaCrypt: */
+/*             case uaPassword: */
+/*                     snprintf(errmessage, messagelen, */
+/*                                      "password authentication with pgpool failed for user \"%s\"", */
+/*                                      frontend->username); */
+/*                     break; */
+#ifdef USE_PAM
+               case uaPAM:
+                       snprintf(errmessage, messagelen,
+                                        "PAM authentication with pgpool failed for user \"%s\"",
+                                        frontend->username);
+                       break;
+#endif /* USE_PAM */
+               default:
+                       snprintf(errmessage, messagelen,
+                                        "authentication with pgpool failed for user \"%s\": invalid authentication method",
+                                        frontend->username);
+                       break;
+       }
+
+       pool_error(errmessage);
+       if (send_error_to_frontend)
+               pool_send_error_message(frontend, frontend->protoVersion, "XX000", errmessage,
+                                                               "", "", __FILE__, __LINE__);
+
+       /*
+        * don't need to free(errmessage). I will just kill myself.
+        */
+       close_all_backend_connections();
+       exit(2);
+}
+
+
+/*
+ *  Close all of the cached backend connections.
+ *
+ *  This is exactly the same as send_frontend_exits() in child.c.
+ */
+static void close_all_backend_connections(void)
+{
+       int i;
+       POOL_CONNECTION_POOL *p = pool_connection_pool;
+
+#ifdef HAVE_SIGPROCMASK
+       sigset_t oldmask;
+#else
+       int     oldmask;
+#endif
+
+       POOL_SETMASK2(&BlockSig, &oldmask);
+
+       for (i=0;i<pool_config.max_pool;i++, p++)
+       {
+               if (!MASTER_CONNECTION(p))
+                       continue;
+               if (MASTER_CONNECTION(p)->sp->user == NULL)
+                       continue;
+               pool_send_frontend_exits(p);
+       }
+
+       POOL_SETMASK(&oldmask);
+}
+
+
+/*
+ *  Determine what authentication method should be used when accessing database
+ *  "database" from frontend "raddr", user "user".  Return the method and
+ *  an optional argument (stored in fields of *frontend), and true for success.
+ *
+ *  Note that false indicates a problem with the hba config file.
+ *  If the file is OK but does not contain any entry matching the request,
+ *  we return true and method = uaReject.
+ */
+static bool hba_getauthmethod(POOL_CONNECTION *frontend)
+{
+       if (check_hba(frontend))
+               return true;
+       else
+               return false;
+}
+
+
+/*
+ *  Scan the (pre-parsed) hba file line by line, looking for a match
+ *  to the port's connection request.
+ */
+static bool check_hba(POOL_CONNECTION *frontend)
+{
+       bool found_entry = false;
+       bool error = false;
+       ListCell *line;
+       ListCell *line_num;
+
+       forboth(line, hba_lines, line_num, hba_line_nums)
+       {
+               parse_hba(lfirst(line), lfirst_int(line_num),
+                                 frontend, &found_entry, &error);
+               if (found_entry || error)
+                       break;
+       }
+
+       if (!error)
+       {
+               /* If no matching entry was found, synthesize 'reject' entry. */
+               if (!found_entry)
+                       frontend->auth_method = uaReject;
+               return true;
+       }
+       else
+               return false;
+}
+
+
+/*
+ *  Process one line from the hba config file.
+ *
+ *  See if it applies to a connection from a frontend with IP address
+ *  frontend->raddr to a database named frontend->database.  If so, return
+ *  *found_p true and fill in the auth arguments into the appropriate
+ *  frontend fields. If not, leave *found_p as it was.  If the record has
+ *  a syntax error, return *error_p true, after issuing a message to the
+ *  log.  If no error, leave *error_p as it was.
+ */
+static void parse_hba(List *line, int line_num, POOL_CONNECTION *frontend,
+                                         bool *found_p, bool *error_p)
+{
+       char *token;
+       char *db, *db_tmp;
+       char *user, *user_tmp;
+       struct addrinfo *gai_result;
+       struct addrinfo hints;
+       int ret;
+       struct sockaddr_storage addr;
+       struct sockaddr_storage mask;
+       char *cidr_slash;
+       ListCell *line_item;
+
+       line_item = list_head(line);
+       /* Check the record type. */
+       token = lfirst(line_item);
+       if (strcmp(token, "local") == 0)
+       {
+               /* Get the database. */
+               line_item = lnext(line_item);
+               if (!line_item)
+                       goto hba_syntax;
+               db = lfirst(line_item);
+
+               /* Get the user. */
+               line_item = lnext(line_item);
+               if (!line_item)
+                       goto hba_syntax;
+               user = lfirst(line_item);
+
+               line_item = lnext(line_item);
+               if (!line_item)
+                       goto hba_syntax;
+
+               /* Read the rest of the line. */
+               parse_hba_auth(&line_item, &frontend->auth_method,
+                                          &frontend->auth_arg, error_p);
+               if (*error_p)
+                       goto hba_syntax;
+
+        /* Disallow auth methods that always need TCP/IP sockets to work */
+               /*
+               if (frontend->auth_method == uaKrb4 ||
+                       frontend->auth_method == uaKrb5)
+                       goto hba_syntax;
+               */
+
+               /* Does not match if connection isn't AF_UNIX */
+               if (!IS_AF_UNIX(frontend->raddr.addr.ss_family))
+                       return;
+       }
+       else if (strcmp(token, "host") == 0
+                        || strcmp(token, "hostssl") == 0
+                        || strcmp(token, "hostnossl") == 0)
+       {
+               if (token[4] == 's')    /* "hostssl" */
+               {
+#ifdef USE_SSL
+                       /* Record does not match if we are not on an SSL connection */
+                       if (!frontend->ssl)
+                               return;
+
+                       /* Placeholder to require specific SSL level, perhaps? */
+                       /* Or a client certificate */
+
+                       /* Since we were on SSL, proceed as with normal 'host' mode */
+#else
+                       /* We don't accept this keyword at all if no SSL support */
+                       goto hba_syntax;
+#endif
+               }
+#ifdef USE_SSL
+               else if (token[4] == 'n')       /* "hostnossl" */
+               {
+                       /* Record does not match if we are on an SSL connection */
+                       if (frontend->ssl)
+                               return;
+               }
+#endif
+
+        /* Get the database. */
+               line_item = lnext(line_item);
+               if (!line_item)
+                       goto hba_syntax;
+               db = lfirst(line_item);
+
+               /* Get the user. */
+               line_item = lnext(line_item);
+               if (!line_item)
+                       goto hba_syntax;
+               user = lfirst(line_item);
+
+               /* Read the IP address field. (with or without CIDR netmask) */
+               line_item = lnext(line_item);
+               if (!line_item)
+                       goto hba_syntax;
+               token = lfirst(line_item);
+
+               /* Check if it has a CIDR suffix and if so isolate it */
+               cidr_slash = strchr(token, '/');
+               if (cidr_slash)
+                       *cidr_slash = '\0';
+
+               /* Get the IP address either way */
+               hints.ai_flags = AI_NUMERICHOST;
+               hints.ai_family = PF_UNSPEC;
+               hints.ai_socktype = 0;
+               hints.ai_protocol = 0;
+               hints.ai_addrlen = 0;
+               hints.ai_canonname = NULL;
+               hints.ai_addr = NULL;
+               hints.ai_next = NULL;
+
+               ret = getaddrinfo_all(token, NULL, &hints, &gai_result);
+               if (ret || !gai_result)
+               {
+                       pool_log("invalid IP address \"%s\" in file \"%s\" line %d: %s",
+                                        token, hbaFileName, line_num, gai_strerror(ret));
+                       if (cidr_slash)
+                               *cidr_slash = '/';
+            if (gai_result)
+                               freeaddrinfo_all(hints.ai_family, gai_result);
+                       goto hba_other_error;
+               }
+
+               if (cidr_slash)
+                       *cidr_slash = '/';
+
+               memcpy(&addr, gai_result->ai_addr, gai_result->ai_addrlen);
+               freeaddrinfo_all(hints.ai_family, gai_result);
+
+               /* Get the netmask */
+               if (cidr_slash)
+               {
+                       if (SockAddr_cidr_mask(&mask, cidr_slash + 1, addr.ss_family) < 0)
+                               goto hba_syntax;
+               }
+               else
+               {
+                       /* Read the mask field. */
+                       line_item = lnext(line_item);
+                       if (!line_item)
+                               goto hba_syntax;
+                       token = lfirst(line_item);
+
+                       ret = getaddrinfo_all(token, NULL, &hints, &gai_result);
+                       if (ret || !gai_result)
+                       {
+                               pool_log("invalid IP mask \"%s\" in file \"%s\" line %d: %s",
+                                                token, hbaFileName, line_num, gai_strerror(ret));
+                               if (gai_result)
+                                       freeaddrinfo_all(hints.ai_family, gai_result);
+                               goto hba_other_error;
+                       }
+
+                       memcpy(&mask, gai_result->ai_addr, gai_result->ai_addrlen);
+                       freeaddrinfo_all(hints.ai_family, gai_result);
+
+                       if (addr.ss_family != mask.ss_family)
+                       {
+                               pool_log("IP address and mask do not match in file \"%s\" line %d",
+                                                hbaFileName, line_num);
+                               goto hba_other_error;
+                       }
+               }
+
+               if (addr.ss_family != frontend->raddr.addr.ss_family)
+               {
+                       /*
+                        * Wrong address family.  We allow only one case: if the file
+                        * has IPv4 and the port is IPv6, promote the file address to
+                        * IPv6 and try to match that way.
+                        */
+#ifdef HAVE_IPV6
+                       if (addr.ss_family == AF_INET && frontend->raddr.addr.ss_family == AF_INET6)
+                       {
+                               promote_v4_to_v6_addr(&addr);
+                               promote_v4_to_v6_mask(&mask);
+                       }
+                       else
+#endif   /* HAVE_IPV6 */
+                       {
+                               /* Line doesn't match client port, so ignore it. */
+                               return;
+                       }
+               }
+               
+               /* Ignore line if client port is not in the matching addr range. */
+               if (!rangeSockAddr(&frontend->raddr.addr, &addr, &mask))
+                       return;
+               
+               /* Read the rest of the line. */
+               line_item = lnext(line_item);
+               if (!line_item)
+                       goto hba_syntax;
+               parse_hba_auth(&line_item, &frontend->auth_method,
+                                          &frontend->auth_arg, error_p);
+               if (*error_p)
+                       goto hba_syntax;
+       }
+       else
+               goto hba_syntax;
+       
+       /* Does the entry match database and user? */
+       /*
+        * duplicate db and username since strtok() in check_db() and check_user()
+        * will override '\001' with '\0'.
+        */
+       db_tmp = strdup(db);
+       if (db_tmp == NULL)
+       {
+               pool_error("parse_hba: strdup failed: %s", strerror(errno));
+               exit(1);
+       }
+       user_tmp = strdup(user);
+       if (user_tmp == NULL)
+       {
+               pool_error("parse_hba: strdup failed: %s", strerror(errno));
+               exit(1);
+       }
+       if (!check_db(frontend->database, frontend->username, db_tmp))
+               return;
+       if (!check_user(frontend->username, user_tmp))
+        return;
+       free(db_tmp);
+       free(user_tmp);
+
+       /* Success */
+       *found_p = true;
+       return;
+
+ hba_syntax:
+       if (line_item)
+               pool_log("invalid entry in file \"%s\" at line %d, token \"%s\"",
+                                hbaFileName, line_num, (char *) lfirst(line_item));
+       else
+               pool_log("missing field in file \"%s\" at end of line %d",
+                                hbaFileName, line_num);
+
+       /* Come here if suitable message already logged */
+ hba_other_error:
+       *error_p = true;
+}
+
+
+/*
+ *  Scan the rest of a host record (after the mask field)
+ *  and return the interpretation of it as *userauth_p, *auth_arg_p, and
+ *  *error_p.  *line_item points to the next token of the line, and is
+ *  advanced over successfully-read tokens.
+ */
+static void parse_hba_auth(ListCell **line_item, UserAuth *userauth_p,
+                                                  char **auth_arg_p, bool *error_p)
+{
+       char *token;
+
+       *auth_arg_p = NULL;
+
+       if (!*line_item)
+       {
+               *error_p = true;
+               return;
+       }
+
+       token = lfirst(*line_item);
+       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, "md5") == 0)
+               *userauth_p = uaMD5;
+       else if (strcmp(token, "crypt") == 0)
+               *userauth_p = uaCrypt;
+       */
+#ifdef USE_PAM
+       else if (strcmp(token, "pam") == 0)
+               *userauth_p = uaPAM;
+#endif /* USE_PAM */
+       else
+       {
+               *error_p = true;
+               return;
+       }
+       *line_item = lnext(*line_item);
+
+       /* Get the authentication argument token, if any */
+       if (*line_item)
+       {
+               token = lfirst(*line_item);
+        *auth_arg_p = strdup(token);
+               if (*auth_arg_p == NULL)
+               {
+                       pool_error("parse_hba_auth: strdup failed: %s", strerror(errno));
+                       exit(1);
+               }
+               *line_item = lnext(*line_item);
+               /* If there is more on the line, it is an error */
+               if (*line_item)
+                       *error_p = true;
+       }
+}
+
+
+/*
+ * Check comma user list for a specific user, handle group names.
+ */
+static bool check_user(char *user, char *param_str)
+{
+       char *tok;
+
+       for (tok = strtok(param_str, MULTI_VALUE_SEP);
+                tok != NULL; tok = strtok(NULL, MULTI_VALUE_SEP))
+       {
+               if (tok[0] == '+')
+               {
+                       /*
+                        * pgpool cannot accept groups. commented lines below are the
+                        * original code.
+                        */
+                       pool_error("group token \"+\" is not supported in pgpool");
+                       return false;
+/*                     if (check_group(tok + 1, user)) */
+/*                             return true; */
+               }
+               else if (strcmp(tok, user) == 0 || strcmp(tok, "all\n") == 0)
+                       return true;
+       }
+
+       return false;
+}
+
+
+/*
+ * Check to see if db/user combination matches param string.
+ */
+static bool check_db(char *dbname, char *user, char *param_str)
+{
+       char *tok;
+
+       for (tok = strtok(param_str, MULTI_VALUE_SEP);
+                tok != NULL; tok = strtok(NULL, MULTI_VALUE_SEP))
+       {
+               if (strcmp(tok, "all\n") == 0)
+                       return true;
+               else if (strcmp(tok, "sameuser\n") == 0)
+               {
+                       if (strcmp(dbname, user) == 0)
+                               return true;
+               }
+               else if (strcmp(tok, "samegroup\n") == 0)
+               {
+                       /*
+                        * pgpool cannot accept groups. commented lines below are the
+                        * original code.
+                        */
+                       pool_error("group token \"samegroup\" is not supported in pgpool");
+                       return false;
+/*                     if (check_group(dbname, user)) */
+/*                             return true; */
+               }
+               else if (strcmp(tok, dbname) == 0)
+                       return true;
+       }
+
+       return false;
+}
+
+
+/*
+ * tokenize the given file, storing the resulting data into two lists:
+ * a list of sublists, each sublist containing the tokens in a line of
+ * the file, and a list of line numbers.
+ *
+ * filename must be the absolute path to the target file.
+ */
+static void tokenize_file(const char *filename, FILE *file,
+                                                 List **lines, List **line_nums)
+{
+       List *current_line = NIL;
+       int line_number = 1;
+       char *buf;
+
+       *lines = *line_nums = NIL;
+
+       while (!feof(file))
+       {
+               buf = next_token_expand(filename, file);
+
+               /* add token to list, unless we are at EOL or comment start */
+               if (buf[0])
+               {
+                       if (current_line == NIL)
+                       {
+                               /* make a new line List, record its line number */
+                               current_line = lappend(current_line, buf);
+                               *lines = lappend(*lines, current_line);
+                               *line_nums = lappend_int(*line_nums, line_number);
+                       }
+                       else
+                       {
+                               /* append token to current line's list */
+                               current_line = lappend(current_line, buf);
+                       }
+               }
+               else
+               {
+                       /* we are at real or logical EOL, so force a new line List */
+                       current_line = NIL;
+                       /* Advance line number whenever we reach EOL */
+                       line_number++;
+                       /* Don't forget to free the next_token_expand result */
+                       free(buf);
+               }
+       }
+}
+
+
+static char * tokenize_inc_file(const char *outer_filename,
+                                                               const char *inc_filename)
+{
+       char *inc_fullname;
+       FILE *inc_file;
+       List *inc_lines;
+       List *inc_line_nums;
+       ListCell *line;
+       char *comma_str;
+
+       if (is_absolute_path(inc_filename))
+       {
+               /* absolute path is taken as-is */
+               inc_fullname = strdup(inc_filename);
+               if (inc_fullname == NULL)
+               {
+                       pool_error("tokenize_inc_file: strdup failed: %s", strerror(errno));
+                       exit(1);
+               }
+       }
+       else
+       {
+               /* relative path is relative to dir of calling file */
+               inc_fullname = (char *)malloc(strlen(outer_filename) + 1 +
+                                                                         strlen(inc_filename) + 1);
+               if (inc_fullname == NULL)
+               {
+                       pool_error("tokenize_inc_file: malloc failed: %s", strerror(errno));
+                       exit(1);
+               }
+               strcpy(inc_fullname, outer_filename);
+               get_parent_directory(inc_fullname);
+               join_path_components(inc_fullname, inc_fullname, inc_filename);
+               canonicalize_path(inc_fullname);
+       }
+
+       inc_file = fopen(inc_fullname, "r");
+       if (inc_file == NULL)
+       {
+               char *returnVal;
+
+               pool_error("could not open secondary authentication file \"@%s\" as \"%s\": reason: %s",
+                                  inc_filename, inc_fullname, strerror(errno));
+               free(inc_fullname);
+
+               /* return single space, it matches nothing */
+               returnVal = strdup(" ");
+               if (returnVal == NULL)
+               {
+                       pool_error("tokenize_inc_file: malloc failed: %s", strerror(errno));
+                       exit(1);
+               }
+               return returnVal;
+       }
+
+    /* There is possible recursion here if the file contains @ */
+       tokenize_file(inc_fullname, inc_file, &inc_lines, &inc_line_nums);
+
+       /*FreeFile(inc_file);*/
+       fclose(inc_file);
+       free(inc_fullname);
+
+       /* Create comma-separated string from List */
+       comma_str = strdup("");
+       if (comma_str == NULL)
+       {
+               pool_error("tokenize_inc_file: strdup failed: %s", strerror(errno));
+               exit(1);
+       }
+       foreach(line, inc_lines)
+       {
+               List *token_list = (List *) lfirst(line);
+               ListCell *token;
+
+               foreach(token, token_list)
+               {
+                       int oldlen = strlen(comma_str);
+                       int needed;
+
+                       needed = oldlen + strlen(lfirst(token)) + 1;
+                       if (oldlen > 0)
+                               needed++;
+                       comma_str = realloc(comma_str, needed);
+                       if (comma_str == NULL)
+                       {
+                               pool_error("tokenize_inc_file: realloc failed: %s", strerror(errno));
+                               exit(1);
+                       }
+                       if (oldlen > 0)
+                               strcat(comma_str, MULTI_VALUE_SEP);
+                       strcat(comma_str, lfirst(token));
+               }
+       }
+
+       free_lines(&inc_lines, &inc_line_nums);
+
+       /* if file is empty, return single space rather than empty string */
+       if (strlen(comma_str) == 0)
+       {
+               char *returnVal;
+
+               free(comma_str);
+               returnVal = strdup(" ");
+               if (returnVal == NULL)
+               {
+                       pool_error("tokenize_inc_file: strdup failed: %s", strerror(errno));
+                       exit(1);
+               }
+               return returnVal;
+       }
+
+       return comma_str;
+}
+
+
+/*
+ * isblank() exists in the ISO C99 spec, but it's not very portable yet,
+ * so provide our own version.
+ */
+static bool pg_isblank(const char c)
+{
+       return c == ' ' || c == '\t' || c == '\r';
+}
+
+
+/*
+ *      Tokenize file and handle file inclusion and comma lists. We have
+ *      to  break      apart  the      commas  to      expand  any  file names then
+ *      reconstruct with commas.
+ *
+ * The result is always a malloc'd string.  If it's zero-length then
+ * we have reached EOL.
+ */
+static char * next_token_expand(const char *filename, FILE *file)
+{
+       char buf[MAX_TOKEN];
+       char *comma_str;
+       bool trailing_comma;
+       char *incbuf;
+       int needed;
+
+       comma_str = strdup("");
+       if (comma_str == NULL)
+       {
+               pool_error("next_token_expand: strdup failed: %s", strerror(errno));
+               exit(1);
+       }
+
+       do
+       {
+               next_token(file, buf, sizeof(buf));
+               if (!buf[0])
+                       break;
+
+               if (buf[strlen(buf) - 1] == ',')
+               {
+                       trailing_comma = true;
+                       buf[strlen(buf) - 1] = '\0';
+               }
+               else
+                       trailing_comma = false;
+
+               /* Is this referencing a file? */
+               if (buf[0] == '@')
+                       incbuf = tokenize_inc_file(filename, buf + 1);
+               else
+               {
+                       incbuf = strdup(buf);
+                       if (incbuf == NULL)
+                       {
+                               pool_error("next_token_expand: strdup failed: %s", strerror(errno));
+                               exit(1);
+                       }
+               }
+
+               needed = strlen(comma_str) + strlen(incbuf) + 1;
+               if (trailing_comma)
+                       needed++;
+               comma_str = realloc(comma_str, needed);
+               if (comma_str == NULL)
+               {
+                       pool_error("next_token_expand: realloc failed: %s", strerror(errno));
+                       exit(1);
+               }
+               strcat(comma_str, incbuf);
+               if (trailing_comma)
+                       strcat(comma_str, MULTI_VALUE_SEP);
+               free(incbuf);
+       } while (trailing_comma);
+
+       return comma_str;
+}
+
+
+/*
+ * 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 at the character immediately after the
+ * token or EOF, whichever comes first. If no more tokens on line,
+ * return empty string as *buf and position the file to the beginning
+ * of the next line or EOF, whichever comes first. Allow spaces in
+ * quoted strings. Terminate on unquoted commas. Handle
+ * comments. Treat unquoted keywords that might be user names or
+ * database names specially, by appending a newline to them.
+ */
+static void next_token(FILE *fp, char *buf, int bufsz)
+{
+       int c;
+       char *start_buf = buf;
+       char *end_buf = buf + (bufsz - 2);
+       bool in_quote = false;
+       bool was_quote = false;
+       bool saw_quote = false;
+
+       /*Assert(end_buf > start_buf);*/
+
+       /* Move over initial whitespace and commas */
+       while ((c = getc(fp)) != EOF && (pg_isblank(c) || c == ','))
+               ;
+
+       if (c == EOF || c == '\n')
+       {
+               *buf = '\0';
+               return;
+       }
+
+       /*
+        * Build a token in buf of next characters up to EOF, EOL, unquoted
+        * comma, or unquoted whitespace.
+        */
+       while (c != EOF && c != '\n' &&
+                  (!pg_isblank(c) || in_quote == true))
+       {
+               /* skip comments to EOL */
+               if (c == '#' && !in_quote)
+               {
+                       while ((c = getc(fp)) != EOF && c != '\n')
+                               ;
+                       /* If only comment, consume EOL too; return EOL */
+                       if (c != EOF && buf == start_buf)
+                               c = getc(fp);
+                       break;
+               }
+
+               if (buf >= end_buf)
+               {
+                       *buf = '\0';
+                       pool_log("authentication file token too long, skipping: \"%s\"", start_buf);
+                       /* Discard remainder of line */
+                       while ((c = getc(fp)) != EOF && c != '\n')
+                               ;
+                       break;
+               }
+
+               if (c != '"' || (c == '"' && was_quote))
+                       *buf++ = c;
+
+               /* We pass back the comma so the caller knows there is more */
+               if ((pg_isblank(c) || c == ',') && !in_quote)
+                       break;
+
+               /* Literal double-quote is two double-quotes */
+               if (in_quote && c == '"')
+                       was_quote = !was_quote;
+               else
+                       was_quote = false;
+
+               if (c == '"')
+               {
+                       in_quote = !in_quote;
+                       saw_quote = true;
+               }
+
+               c = getc(fp);
+       }
+
+       /*
+        * Put back the char right after the token (critical in case it is
+        * EOL, since we need to detect end-of-line at next call).
+        */
+       if (c != EOF)
+               ungetc(c, fp);
+
+       *buf = '\0';
+
+       if (!saw_quote &&
+               (strcmp(start_buf, "all") == 0 ||
+                strcmp(start_buf, "sameuser") == 0 ||
+                strcmp(start_buf, "samegroup") == 0))
+       {
+               /* append newline to a magical keyword */
+               *buf++ = '\n';
+               *buf = '\0';
+       }
+}
+
+
+/*
+ * free memory used by lines and tokens built by tokenize_file()
+ */
+static void free_lines(List **lines, List **line_nums)
+{
+       if (*lines)
+       {
+               ListCell *line;
+
+               foreach(line, *lines)
+               {
+                       List *ln = lfirst(line);
+                       ListCell *token;
+                       
+                       foreach(token, ln)
+                               free(lfirst(token));
+
+                       list_free(ln);
+               }
+               
+               list_free(*lines);
+               *lines = NIL;
+       }
+       
+       if (*line_nums)
+       {
+               list_free(*line_nums);
+               *line_nums = NIL;
+       }
+}
+
+
+#ifdef USE_PAM
+
+/*
+ * PAM conversation function
+ */
+static int pam_passwd_conv_proc(int num_msg, const struct pam_message ** msg,
+                                                               struct pam_response ** resp, void *appdata_ptr)
+{
+       if (num_msg != 1 || msg[0]->msg_style != PAM_PROMPT_ECHO_OFF)
+       {
+               switch (msg[0]->msg_style)
+               {
+                       case PAM_ERROR_MSG:
+                               pool_log("error from underlying PAM layer: %s",
+                                                msg[0]->msg);
+                               return PAM_CONV_ERR;
+                       default:
+                               pool_log("unsupported PAM conversation %d/%s",
+                                                msg[0]->msg_style, msg[0]->msg);
+                               return PAM_CONV_ERR;
+               }
+       }
+
+       if (!appdata_ptr)
+       {
+               /*
+                * Workaround for Solaris 2.6 where the PAM library is broken and
+                * does not pass appdata_ptr to the conversation routine
+                */
+               appdata_ptr = pam_passwd;
+       }
+
+       /*
+        * Password wasn't passed to PAM the first time around - let's go ask
+        * the client to send a password, which we then stuff into PAM.
+        */
+       if (strlen(appdata_ptr) == 0)
+       {
+               char *passwd;
+
+               sendAuthRequest(pam_frontend_kludge, AUTH_REQ_PASSWORD);
+               passwd = recv_password_packet(pam_frontend_kludge);
+
+               if (passwd == NULL)
+                       return PAM_CONV_ERR; /* client didn't want to send password */
+
+               if (strlen(passwd) == 0)
+               {
+                       pool_log("empty password returned by client");
+                       return PAM_CONV_ERR;
+               }
+               appdata_ptr = passwd;
+       }
+
+       /*
+        * PAM will free this memory in * pam_end()
+        */
+       *resp = calloc(num_msg, sizeof(struct pam_response));
+       if (!*resp)
+       {
+               /* originally, it was logged as LOG */
+               pool_error("pam_passwd_conv_proc: calloc failed: %s", strerror(errno));
+               return PAM_CONV_ERR;
+       }
+
+       (*resp)[0].resp = strdup((char *) appdata_ptr);
+       if ((*resp)[0].resp == NULL)
+       {
+               pool_error("pam_passwd_conv_proc: strdup failed: %s", strerror(errno));
+               exit(1);
+       }
+       (*resp)[0].resp_retcode = 0;
+
+       return ((*resp)[0].resp ? PAM_SUCCESS : PAM_CONV_ERR);
+}
+
+
+/*
+ * Check authentication against PAM.
+ */
+static POOL_STATUS CheckPAMAuth(POOL_CONNECTION *frontend, char *user, char *password)
+{
+       int retval;
+       pam_handle_t *pamh = NULL;
+
+       /*
+        * Apparently, Solaris 2.6 is broken, and needs ugly static variable
+        * workaround
+        */
+       pam_passwd = password;
+
+       /*
+        * Set the application data portion of the conversation struct This is
+        * later used inside the PAM conversation to pass the password to the
+        * authentication module.
+        */
+       pam_passw_conv.appdata_ptr = (char *) password; /* from password above,
+                                                                                                        * not allocated */
+
+       /* Optionally, one can set the service name in pool_hba.conf */
+       if (frontend->auth_arg && frontend->auth_arg[0] != '\0')
+               retval = pam_start(frontend->auth_arg, "pgpool@",
+                                                  &pam_passw_conv, &pamh);
+       else
+               retval = pam_start(PGPOOL_PAM_SERVICE, "pgpool@",
+                                                  &pam_passw_conv, &pamh);
+
+       if (retval != PAM_SUCCESS)
+       {
+               pool_log("could not create PAM authenticator: %s",
+                                pam_strerror(pamh, retval));
+               pam_passwd = NULL;              /* Unset pam_passwd */
+               return POOL_ERROR;
+       }
+
+       retval = pam_set_item(pamh, PAM_USER, user);
+       if (retval != PAM_SUCCESS)
+       {
+               pool_log("pam_set_item(PAM_USER) failed: %s",
+                                pam_strerror(pamh, retval));
+               pam_passwd = NULL;              /* Unset pam_passwd */
+               return POOL_ERROR;
+       }
+
+       retval = pam_set_item(pamh, PAM_CONV, &pam_passw_conv);
+       if (retval != PAM_SUCCESS)
+       {
+               pool_log("pam_set_item(PAM_CONV) failed: %s",
+                                pam_strerror(pamh, retval));
+               pam_passwd = NULL;              /* Unset pam_passwd */
+               return POOL_ERROR;
+       }
+
+       retval = pam_authenticate(pamh, 0);
+       if (retval != PAM_SUCCESS)      /* service name does not exist */
+       {
+               pool_log("pam_authenticate failed: %s",
+                                pam_strerror(pamh, retval));
+               pam_passwd = NULL;              /* Unset pam_passwd */
+               return POOL_ERROR;
+       }
+
+       retval = pam_acct_mgmt(pamh, 0);
+       if (retval != PAM_SUCCESS)
+       {
+               pool_log("pam_acct_mgmt failed: %s",
+                                pam_strerror(pamh, retval));
+               pam_passwd = NULL;              /* Unset pam_passwd */
+               return POOL_ERROR;
+       }
+
+       retval = pam_end(pamh, retval);
+       if (retval != PAM_SUCCESS)
+       {
+               pool_log("could not release PAM authenticator: %s",
+                                pam_strerror(pamh, retval));
+       }
+
+       pam_passwd = NULL;                      /* Unset pam_passwd */
+
+       return (retval == PAM_SUCCESS ? POOL_CONTINUE : POOL_ERROR);
+}
+
+#endif   /* USE_PAM */
diff --git a/pool_hba.conf.sample b/pool_hba.conf.sample
new file mode 100644 (file)
index 0000000..b2fe374
--- /dev/null
@@ -0,0 +1,69 @@
+# pgpool Client Authentication Configuration File
+# ===============================================
+#
+# The format rule in this file follows the rules in the PostgreSQL
+# Administrator's Guide. Refer to chapter "Client Authentication" for a
+# complete description.  A short synopsis follows.
+#
+# This file controls: which hosts are allowed to connect, how clients
+# are authenticated, which user names they can use, which databases they
+# can access.  Records take one of these forms:
+#
+# local      DATABASE  USER  METHOD  [OPTION]
+# host       DATABASE  USER  CIDR-ADDRESS  METHOD  [OPTION]
+# hostnossl  DATABASE  USER  CIDR-ADDRESS  METHOD  [OPTION]
+#
+# (The uppercase items must be replaced by actual values.)
+#
+# The first field is the connection type: "local" is a Unix-domain socket,
+# "host" is a plain TCP/IP socket since pgpool currently doest not support
+# SSL connection. "hostnossl" is also a plain TCP/IP socket.
+#
+# DATABASE can be "all", "sameuser", a database name, or a comma-separated
+# list thereof. Note that "samegroup" like in PostgreSQL's pg_hba.conf
+# file is not supported, since pgpool does not know which group a user
+# belongs to. Also note that the database specified here may not exist in
+# the backend PostgreSQL. pgpool will authenticate based on the database's
+# name, not based on whether it exists or not.
+#
+# USER can be "all", a user name, or a comma-separated list thereof.  In
+# both the DATABASE and USER fields you can also write a file name prefixed
+# with "@" to include names from a separate file. Note that a group name
+# prefixed with "+" like in PostgreSQL's pg_hba.conf file is not supported
+# because of the same reason as "samegroup" token. Also note that a user
+# name specified here may not exist in the backend PostgreSQL. pgpool will
+# authenticate based on the user's name, not based on whether he/she exists.
+#
+# CIDR-ADDRESS specifies the set of hosts the record matches.
+# It is made up of an IP address and a CIDR mask that is an integer
+# (between 0 and 32 (IPv4) that specifies the number of significant bits in
+# the mask.  Alternatively, you can write an IP address and netmask in
+# separate columns to specify the set of hosts.
+#
+# METHOD can be "trust", "reject", or "pam".  Note that "pam" sends passwords
+# in clear text.
+#
+# OPTION is the name of the PAM service. Default service name is "pgpool"
+#
+# Database and user names containing spaces, commas, quotes and other special
+# characters must be quoted. Quoting one of the keywords "all" or "sameuser"
+# makes the name lose its special character, and just match a database or
+# username with that name.
+#
+# This file is read on pgpool startup.  If you edit the file on a running
+# system, you have to restart the pgpool  for the changes to take effect.
+
+# Put your actual configuration here
+# ----------------------------------
+#
+# If you want to allow non-local connections, you need to add more
+# "host" records. In that case you will also need to make pgpool listen
+# on a non-local interface via the listen_addresses configuration parameter.
+#
+
+# TYPE  DATABASE    USER        CIDR-ADDRESS          METHOD
+
+# "local" is for Unix domain socket connections only
+local   all         all                               trust
+# IPv4 local connections:
+host    all         all         127.0.0.1/32          trust
diff --git a/pool_ip.c b/pool_ip.c
new file mode 100644 (file)
index 0000000..41571ab
--- /dev/null
+++ b/pool_ip.c
@@ -0,0 +1,498 @@
+/* -*-pgsql-c-*- */
+/*
+ *
+ * $Header$
+ *
+ * This file was imported from PostgreSQL 8.0.8 source code.
+ * See below for the copyright and description.
+ *
+ * pgpool: a language independent connection pool server for PostgreSQL 
+ * written by Tatsuo Ishii
+ *
+ * Portions Copyright (c) 2003-2007    PgPool Global Development Group
+ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of the
+ * author not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. The author makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * ------------------------------
+ *
+ *
+ * This file and the IPV6 implementation were initially provided by
+ * Nigel Kukard <nkukard@lbsd.net>, Linux Based Systems Design
+ * http://www.lbsd.net.
+ *
+ * pool_ip.c.: IPv6-aware network access.
+ *
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/un.h>
+#include "pool_ip.h"
+
+
+static int rangeSockAddrAF_INET(const struct sockaddr_in * addr,
+                                        const struct sockaddr_in * netaddr,
+                                        const struct sockaddr_in * netmask);
+
+#ifdef HAVE_IPV6
+static int rangeSockAddrAF_INET6(const struct sockaddr_in6 * addr,
+                                         const struct sockaddr_in6 * netaddr,
+                                         const struct sockaddr_in6 * netmask);
+#endif
+
+static int getaddrinfo_unix(const char *path,
+                                const struct addrinfo * hintsp,
+                                struct addrinfo ** result);
+
+static int getnameinfo_unix(const struct sockaddr_un * sa, int salen,
+                                char *node, int nodelen,
+                                char *service, int servicelen,
+                                int flags);
+
+
+/*
+ *     getaddrinfo_all - get address info for Unix, IPv4 and IPv6 sockets
+ */
+int
+getaddrinfo_all(const char *hostname, const char *servname,
+                               const struct addrinfo * hintp, struct addrinfo ** result)
+{
+       /* not all versions of getaddrinfo() zero *result on failure */
+       *result = NULL;
+
+       if (hintp->ai_family == AF_UNIX)
+               return getaddrinfo_unix(servname, hintp, result);
+
+       /* NULL has special meaning to getaddrinfo(). */
+       return getaddrinfo((!hostname || hostname[0] == '\0') ? NULL : hostname,
+                                          servname, hintp, result);
+}
+
+
+/*
+ *     freeaddrinfo_all - free addrinfo structures for IPv4, IPv6, or Unix
+ *
+ * Note: the ai_family field of the original hint structure must be passed
+ * so that we can tell whether the addrinfo struct was built by the system's
+ * getaddrinfo() routine or our own getaddrinfo_unix() routine.  Some versions
+ * of getaddrinfo() might be willing to return AF_UNIX addresses, so it's
+ * not safe to look at ai_family in the addrinfo itself.
+ */
+void
+freeaddrinfo_all(int hint_ai_family, struct addrinfo * ai)
+{
+       if (hint_ai_family == AF_UNIX)
+       {
+               /* struct was built by getaddrinfo_unix (see getaddrinfo_all) */
+               while (ai != NULL)
+               {
+                       struct addrinfo *p = ai;
+
+                       ai = ai->ai_next;
+                       free(p->ai_addr);
+                       free(p);
+               }
+       }
+       else
+       {
+               /* struct was built by getaddrinfo() */
+               if (ai != NULL)
+                       freeaddrinfo(ai);
+       }
+}
+
+
+/*
+ *     getnameinfo_all - get name info for Unix, IPv4 and IPv6 sockets
+ *
+ * The API of this routine differs from the standard getnameinfo() definition
+ * in two ways: first, the addr parameter is declared as sockaddr_storage
+ * rather than struct sockaddr, and second, the node and service fields are
+ * guaranteed to be filled with something even on failure return.
+ */
+int
+getnameinfo_all(const struct sockaddr_storage * addr, int salen,
+                               char *node, int nodelen,
+                               char *service, int servicelen,
+                               int flags)
+{
+       int                     rc;
+
+       if (addr && addr->ss_family == AF_UNIX)
+               rc = getnameinfo_unix((const struct sockaddr_un *) addr, salen,
+                                                         node, nodelen,
+                                                         service, servicelen,
+                                                         flags);
+       else
+               rc = getnameinfo((const struct sockaddr *) addr, salen,
+                                                node, nodelen,
+                                                service, servicelen,
+                                                flags);
+
+       if (rc != 0)
+       {
+               if (node)
+                       strncpy(node, "???", nodelen);
+               if (service)
+                       strncpy(service, "???", servicelen);
+       }
+
+       return rc;
+}
+
+
+const char *
+gai_strerror(int errcode)
+{
+       int         hcode;
+
+       switch (errcode)
+       {
+               case EAI_NONAME:
+                       hcode = HOST_NOT_FOUND;
+                       break;
+               case EAI_AGAIN:
+                       hcode = TRY_AGAIN;
+                       break;
+               case EAI_FAIL:
+               default:
+                       hcode = NO_RECOVERY;
+                       break;
+       }
+
+       return hstrerror(hcode);
+}
+
+
+/*
+ *     getaddrinfo_unix - get unix socket info using IPv6-compatible API
+ *
+ *     Bugs: only one addrinfo is set even though hintsp is NULL or
+ *               ai_socktype is 0
+ *               AI_CANONNAME is not supported.
+ *
+ */
+static int
+getaddrinfo_unix(const char *path, const struct addrinfo * hintsp,
+                                struct addrinfo ** result)
+{
+       struct addrinfo hints;
+       struct addrinfo *aip;
+       struct sockaddr_un *unp;
+
+       *result = NULL;
+
+       memset(&hints, 0, sizeof(hints));
+
+       if (strlen(path) >= sizeof(unp->sun_path))
+               return EAI_FAIL;
+
+       if (hintsp == NULL)
+       {
+               hints.ai_family = AF_UNIX;
+               hints.ai_socktype = SOCK_STREAM;
+       }
+       else
+               memcpy(&hints, hintsp, sizeof(hints));
+
+       if (hints.ai_socktype == 0)
+               hints.ai_socktype = SOCK_STREAM;
+
+       if (hints.ai_family != AF_UNIX)
+       {
+               /* shouldn't have been called */
+               return EAI_FAIL;
+       }
+
+       aip = calloc(1, sizeof(struct addrinfo));
+       if (aip == NULL)
+               return EAI_MEMORY;
+
+       unp = calloc(1, sizeof(struct sockaddr_un));
+       if (unp == NULL)
+       {
+               free(aip);
+               return EAI_MEMORY;
+       }
+
+       aip->ai_family = AF_UNIX;
+       aip->ai_socktype = hints.ai_socktype;
+       aip->ai_protocol = hints.ai_protocol;
+       aip->ai_next = NULL;
+       aip->ai_canonname = NULL;
+       *result = aip;
+
+       unp->sun_family = AF_UNIX;
+       aip->ai_addr = (struct sockaddr *) unp;
+       aip->ai_addrlen = sizeof(struct sockaddr_un);
+
+       strcpy(unp->sun_path, path);
+
+#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
+       unp->sun_len = sizeof(struct sockaddr_un);
+#endif
+
+       return 0;
+}
+
+/*
+ * Convert an address to a hostname.
+ */
+static int
+getnameinfo_unix(const struct sockaddr_un * sa, int salen,
+                                char *node, int nodelen,
+                                char *service, int servicelen,
+                                int flags)
+{
+       int                     ret = -1;
+
+       /* Invalid arguments. */
+       if (sa == NULL || sa->sun_family != AF_UNIX ||
+               (node == NULL && service == NULL))
+               return EAI_FAIL;
+
+       /* We don't support those. */
+       if ((node && !(flags & NI_NUMERICHOST))
+               || (service && !(flags & NI_NUMERICSERV)))
+               return EAI_FAIL;
+
+       if (node)
+       {
+               ret = snprintf(node, nodelen, "%s", "[local]");
+               if (ret == -1 || ret > nodelen)
+                       return EAI_MEMORY;
+       }
+
+       if (service)
+       {
+               ret = snprintf(service, servicelen, "%s", sa->sun_path);
+               if (ret == -1 || ret > servicelen)
+                       return EAI_MEMORY;
+       }
+
+       return 0;
+}
+
+
+/*
+ * rangeSockAddr - is addr within the subnet specified by netaddr/netmask ?
+ *
+ * Note: caller must already have verified that all three addresses are
+ * in the same address family; and AF_UNIX addresses are not supported.
+ */
+int
+rangeSockAddr(const struct sockaddr_storage * addr,
+                         const struct sockaddr_storage * netaddr,
+                         const struct sockaddr_storage * netmask)
+{
+       if (addr->ss_family == AF_INET)
+               return rangeSockAddrAF_INET((struct sockaddr_in *) addr,
+                                                                       (struct sockaddr_in *) netaddr,
+                                                                       (struct sockaddr_in *) netmask);
+#ifdef HAVE_IPV6
+       else if (addr->ss_family == AF_INET6)
+               return rangeSockAddrAF_INET6((struct sockaddr_in6 *) addr,
+                                                                        (struct sockaddr_in6 *) netaddr,
+                                                                        (struct sockaddr_in6 *) netmask);
+#endif
+       else
+               return 0;
+}
+
+static int
+rangeSockAddrAF_INET(const struct sockaddr_in * addr,
+                                        const struct sockaddr_in * netaddr,
+                                        const struct sockaddr_in * netmask)
+{
+       if (((addr->sin_addr.s_addr ^ netaddr->sin_addr.s_addr) &
+                netmask->sin_addr.s_addr) == 0)
+               return 1;
+       else
+               return 0;
+}
+
+
+#ifdef HAVE_IPV6
+static int
+rangeSockAddrAF_INET6(const struct sockaddr_in6 * addr,
+                                         const struct sockaddr_in6 * netaddr,
+                                         const struct sockaddr_in6 * netmask)
+{
+       int                     i;
+
+       for (i = 0; i < 16; i++)
+       {
+               if (((addr->sin6_addr.s6_addr[i] ^ netaddr->sin6_addr.s6_addr[i]) &
+                        netmask->sin6_addr.s6_addr[i]) != 0)
+                       return 0;
+       }
+
+       return 1;
+}
+#endif
+
+/*
+ *     SockAddr_cidr_mask - make a network mask of the appropriate family
+ *       and required number of significant bits
+ *
+ * The resulting mask is placed in *mask, which had better be big enough.
+ *
+ * Return value is 0 if okay, -1 if not.
+ */
+int
+SockAddr_cidr_mask(struct sockaddr_storage * mask, char *numbits, int family)
+{
+       long            bits;
+       char       *endptr;
+
+       bits = strtol(numbits, &endptr, 10);
+
+       if (*numbits == '\0' || *endptr != '\0')
+               return -1;
+
+       switch (family)
+       {
+               case AF_INET:
+                       {
+                               struct sockaddr_in mask4;
+                               long            maskl;
+
+                               if (bits < 0 || bits > 32)
+                                       return -1;
+                               /* avoid "x << 32", which is not portable */
+                               if (bits > 0)
+                                       maskl = (0xffffffffUL << (32 - (int) bits))
+                                               & 0xffffffffUL;
+                               else
+                                       maskl = 0;
+                               mask4.sin_addr.s_addr = htonl(maskl);
+                               memcpy(mask, &mask4, sizeof(mask4));
+                               break;
+                       }
+
+#ifdef HAVE_IPV6
+               case AF_INET6:
+                       {
+                               struct sockaddr_in6 mask6;
+                               int                     i;
+
+                               if (bits < 0 || bits > 128)
+                                       return -1;
+                               for (i = 0; i < 16; i++)
+                               {
+                                       if (bits <= 0)
+                                               mask6.sin6_addr.s6_addr[i] = 0;
+                                       else if (bits >= 8)
+                                               mask6.sin6_addr.s6_addr[i] = 0xff;
+                                       else
+                                       {
+                                               mask6.sin6_addr.s6_addr[i] =
+                                                       (0xff << (8 - (int) bits)) & 0xff;
+                                       }
+                                       bits -= 8;
+                               }
+                               memcpy(mask, &mask6, sizeof(mask6));
+                               break;
+                       }
+#endif
+               default:
+                       return -1;
+       }
+
+       mask->ss_family = family;
+       return 0;
+}
+
+
+#ifdef HAVE_IPV6
+
+/*
+ * promote_v4_to_v6_addr --- convert an AF_INET addr to AF_INET6, using
+ *             the standard convention for IPv4 addresses mapped into IPv6 world
+ *
+ * The passed addr is modified in place; be sure it is large enough to
+ * hold the result!  Note that we only worry about setting the fields
+ * that rangeSockAddr will look at.
+ */
+void
+promote_v4_to_v6_addr(struct sockaddr_storage * addr)
+{
+       struct sockaddr_in addr4;
+       struct sockaddr_in6 addr6;
+       uint32          ip4addr;
+
+       memcpy(&addr4, addr, sizeof(addr4));
+       ip4addr = ntohl(addr4.sin_addr.s_addr);
+
+       memset(&addr6, 0, sizeof(addr6));
+
+       addr6.sin6_family = AF_INET6;
+
+       addr6.sin6_addr.s6_addr[10] = 0xff;
+       addr6.sin6_addr.s6_addr[11] = 0xff;
+       addr6.sin6_addr.s6_addr[12] = (ip4addr >> 24) & 0xFF;
+       addr6.sin6_addr.s6_addr[13] = (ip4addr >> 16) & 0xFF;
+       addr6.sin6_addr.s6_addr[14] = (ip4addr >> 8) & 0xFF;
+       addr6.sin6_addr.s6_addr[15] = (ip4addr) & 0xFF;
+
+       memcpy(addr, &addr6, sizeof(addr6));
+}
+
+/*
+ * promote_v4_to_v6_mask --- convert an AF_INET netmask to AF_INET6, using
+ *             the standard convention for IPv4 addresses mapped into IPv6 world
+ *
+ * This must be different from promote_v4_to_v6_addr because we want to
+ * set the high-order bits to 1's not 0's.
+ *
+ * The passed addr is modified in place; be sure it is large enough to
+ * hold the result!  Note that we only worry about setting the fields
+ * that rangeSockAddr will look at.
+ */
+void
+promote_v4_to_v6_mask(struct sockaddr_storage * addr)
+{
+       struct sockaddr_in addr4;
+       struct sockaddr_in6 addr6;
+       uint32          ip4addr;
+       int                     i;
+
+       memcpy(&addr4, addr, sizeof(addr4));
+       ip4addr = ntohl(addr4.sin_addr.s_addr);
+
+       memset(&addr6, 0, sizeof(addr6));
+
+       addr6.sin6_family = AF_INET6;
+
+       for (i = 0; i < 12; i++)
+               addr6.sin6_addr.s6_addr[i] = 0xff;
+
+       addr6.sin6_addr.s6_addr[12] = (ip4addr >> 24) & 0xFF;
+       addr6.sin6_addr.s6_addr[13] = (ip4addr >> 16) & 0xFF;
+       addr6.sin6_addr.s6_addr[14] = (ip4addr >> 8) & 0xFF;
+       addr6.sin6_addr.s6_addr[15] = (ip4addr) & 0xFF;
+
+       memcpy(addr, &addr6, sizeof(addr6));
+}
+
+#endif   /* HAVE_IPV6 */
diff --git a/pool_ip.h b/pool_ip.h
new file mode 100644 (file)
index 0000000..12a8cb6
--- /dev/null
+++ b/pool_ip.h
@@ -0,0 +1,63 @@
+/* -*-pgsql-c-*- */
+/*
+ *
+ * $Header$
+ *
+ * This file was imported from PostgreSQL 8.0.8 source code.
+ * See below for the copyright and description.
+ *
+ * pgpool: a language independent connection pool server for PostgreSQL 
+ * written by Tatsuo Ishii
+ *
+ * Portions Copyright (c) 2003-2007    PgPool Global Development Group
+ * Portions Copyright (c) 2003-2005, PostgreSQL Global Development Group
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of the
+ * author not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. The author makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * pool_ip.h.: Definitions for IPv6-aware network access.
+ *
+ */
+
+#ifndef POOL_IP_H
+#define POOL_IP_H
+
+#include "pool_type.h"
+
+extern int getaddrinfo_all(const char *hostname, const char *servname,
+                               const struct addrinfo * hintp,
+                               struct addrinfo ** result);
+extern void freeaddrinfo_all(int hint_ai_family, struct addrinfo * ai);
+
+extern int getnameinfo_all(const struct sockaddr_storage * addr, int salen,
+                               char *node, int nodelen,
+                               char *service, int servicelen,
+                               int flags);
+
+extern int rangeSockAddr(const struct sockaddr_storage * addr,
+                         const struct sockaddr_storage * netaddr,
+                         const struct sockaddr_storage * netmask);
+
+extern int SockAddr_cidr_mask(struct sockaddr_storage * mask,
+                                  char *numbits, int family);
+
+/* imported from PostgreSQL getaddrinfo.c */
+extern const char * gai_strerror(int errcode);
+
+#ifdef HAVE_IPV6
+extern void promote_v4_to_v6_addr(struct sockaddr_storage * addr);
+extern void promote_v4_to_v6_mask(struct sockaddr_storage * addr);
+#endif
+
+#define IS_AF_INET(fam) ((fam) == AF_INET)
+#define IS_AF_UNIX(fam) ((fam) == AF_UNIX)
+
+#endif   /* IP_H */
diff --git a/pool_list.c b/pool_list.c
new file mode 100644 (file)
index 0000000..6e31be6
--- /dev/null
@@ -0,0 +1,171 @@
+/* -*-pgsql-c-*- */
+/*
+ *
+ * $Header$
+ *
+ * pgpool: a language independent connection pool server for PostgreSQL 
+ * written by Tatsuo Ishii
+ *
+ * Portions Copyright (c) 2003-2007,   PgPool Global Development Group
+ * Portions Copyright (c) 2004, PostgreSQL Global Development Group
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of the
+ * author not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. The author makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * pool_list.c.: Implementation of singly-linked homogeneous lists
+ *
+ */
+
+#include <string.h>
+#include <errno.h>
+
+#include "pool.h"
+#include "pool_type.h"
+#include "pool_list.h"
+
+static List * new_list(void);
+/* static void new_head_cell(List *list); */
+static void new_tail_cell(List *list);
+static void list_free_private(List *list, bool deep);
+
+#ifndef __GNUC__
+
+ListCell * list_head(List *l)
+{
+       return l ? l->head : NULL;
+}
+
+ListCell * list_tail(List *l)
+{
+       return l ? l->tail : NULL;
+}
+
+int list_length(List *l)
+{
+       return l ? l->length : 0;
+}
+
+#endif /* __GNUC__ */
+
+List * lappend(List *list, void *datum)
+{
+       if (list == NIL)
+               list = new_list();
+       else
+               new_tail_cell(list);
+
+       lfirst(list->tail) = datum;
+
+       return list;
+}
+
+List * lappend_int(List *list, int datum)
+{
+       if (list == NIL)
+               list = new_list();
+       else
+               new_tail_cell(list);
+
+       lfirst_int(list->tail) = datum;
+
+       return list;
+}
+
+static List * new_list(void)
+{
+       List *new_list;
+       ListCell *new_head;
+
+       new_head = (ListCell *)malloc(sizeof(*new_head));
+       if (new_head == NULL)
+       {
+               pool_error("new_list: malloc failed: %s", strerror(errno));
+               exit(1);
+       }
+       new_head->next = NULL;
+
+       new_list = (List *)malloc(sizeof(*new_list));
+       if (new_list == NULL)
+       {
+               pool_error("new_list: malloc failed: %s", strerror(errno));
+               exit(1);
+       }
+       new_list->length = 1;
+       new_list->head = new_head;
+       new_list->tail = new_head;
+
+       return new_list;
+}
+
+#ifdef NOT_USED
+static void new_head_cell(List *list)
+{
+       ListCell *new_head;
+
+       new_head = (ListCell *)malloc(sizeof(*new_head));
+       if (new_head == NULL)
+       {
+               pool_error("new_head_cell: malloc failed: %s", strerror(errno));
+               exit(1);
+       }
+       new_head->next = list->head;
+
+       list->head = new_head;
+       list->length++;
+}
+#endif
+
+static void new_tail_cell(List *list)
+{
+       ListCell *new_tail;
+
+       new_tail = (ListCell *)malloc(sizeof(*new_tail));
+       if (new_tail == NULL)
+       {
+               pool_error("new_tail_cell: malloc failed: %s", strerror(errno));
+               exit(1);
+       }
+       new_tail->next = NULL;
+
+       list->tail->next = new_tail;
+       list->tail = new_tail;
+       list->length++;
+}
+
+/*
+ * free all storage in a list, but not the pointed-to elements
+ */
+void list_free(List *list)
+{
+       list_free_private(list, false);
+}
+
+/*
+ * free all storage in a list, and the pointed-to elements iff deep is true
+ */
+static void list_free_private(List *list, bool deep)
+{
+       ListCell *cell;
+
+       cell = list_head(list);
+       while (cell != NULL)
+       {
+               ListCell *tmp = cell;
+
+               cell = lnext(cell);
+               if (deep)
+                       free(lfirst(tmp));
+               free(tmp);
+       }
+
+       if (list)
+               free(list);
+}
diff --git a/pool_list.h b/pool_list.h
new file mode 100644 (file)
index 0000000..e13e07c
--- /dev/null
@@ -0,0 +1,95 @@
+/* -*-pgsql-c-*- */
+/*
+ *
+ * $Header$
+ *
+ * pgpool: a language independent connection pool server for PostgreSQL 
+ * written by Tatsuo Ishii
+ *
+ * Portions Copyright (c) 2003-2007,   PgPool Global Development Group
+ * Portions Copyright (c) 2004, PostgreSQL Global Development Group
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of the
+ * author not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. The author makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * pool_list.h.: interface to pool_list.c
+ *
+ */
+
+#ifndef POOL_LIST_H
+#define POOL_LIST_H
+
+#include <stdlib.h>
+
+#define NIL ((List *) NULL)
+
+#define lnext(lc) ((lc)->next)
+#define lfirst(lc) ((lc)->data.ptr_value)
+#define lfirst_int(lc) ((lc)->data.int_value)
+#define foreach(cell, l) \
+       for ((cell) = list_head(l); (cell) != NULL; (cell) = lnext(cell))
+#define forboth(cell1, list1, cell2, list2) \
+       for ((cell1) = list_head(list1), (cell2) = list_head(list2); \
+                (cell1) != NULL && (cell2) != NULL; \
+                (cell1) = lnext(cell1), (cell2) = lnext(cell2))
+
+typedef struct ListCell ListCell;
+
+typedef struct List
+{
+       int length;
+       ListCell *head;
+       ListCell *tail;
+} List;
+
+struct ListCell
+{
+       union
+       {
+               void *ptr_value;
+               int int_value;
+       } data;
+       ListCell *next;
+};
+
+#ifdef __GNUC__
+
+static __inline__ ListCell *
+list_head(List *l)
+{
+       return l ? l->head : NULL;
+}
+
+static __inline__ ListCell *
+list_tail(List *l)
+{
+       return l ? l->tail : NULL;
+}
+
+static __inline__ int
+list_length(List *l)
+{
+       return l ? l->length : 0;
+}
+
+#else
+
+extern ListCell * list_head(List *l);
+extern ListCell * list_tail(List *l);
+extern int list_length(List *l);
+
+#endif /* __GNUC__ */
+
+extern List * lappend(List *list, void *datum);
+extern List * lappend_int(List *list, int datum);
+extern void list_free(List *list);
+
+#endif /* POOL_LIST_H */
diff --git a/pool_path.c b/pool_path.c
new file mode 100644 (file)
index 0000000..7129f17
--- /dev/null
@@ -0,0 +1,193 @@
+/* -*-pgsql-c-*- */
+/*
+ *
+ * $Header$
+ *
+ * pgpool: a language independent connection pool server for PostgreSQL 
+ * written by Tatsuo Ishii
+ *
+ * Portions Copyright (c) 2003-2007,   PgPool Global Development Group
+ * Portions Copyright (c) 2004, PostgreSQL Global Development Group
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of the
+ * author not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. The author makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * pool_path.c.: small functions to manipulate paths
+ *
+ */
+
+#include "pool_type.h"
+#include "pool_path.h"
+#include <stdio.h>
+#include <string.h>
+
+static void trim_directory(char *path);
+static void trim_trailing_separator(char *path);
+
+/*
+ * get_parent_directory
+ *
+ * Modify the given string in-place to name the parent directory of the
+ * named file.
+ */
+void get_parent_directory(char *path)
+{
+       trim_directory(path);
+}
+
+
+/*
+ *  trim_directory
+ *
+ *  Trim trailing directory from path, that is, remove any trailing slashes,
+ *  the last pathname component, and the slash just ahead of it --- but never
+ *  remove a leading slash.
+ */
+static void trim_directory(char *path)
+{
+       char *p;
+
+       if (path[0] == '\0')
+               return;
+
+       /* back up over trailing slash(es) */
+       for (p = path + strlen(path) - 1; IS_DIR_SEP(*p) && p > path; p--);
+
+       /* back up over directory name */
+       for (; !IS_DIR_SEP(*p) && p > path; p--);
+
+       /* if multiple slashes before directory name, remove 'em all */
+       for (; p > path && IS_DIR_SEP(*(p - 1)); p--);
+
+       /* don't erase a leading slash */
+       if (p == path && IS_DIR_SEP(*p))
+               p++;
+
+       *p = '\0';
+}
+
+
+/*
+ * join_path_components - join two path components, inserting a slash
+ *
+ * ret_path is the output area (must be of size MAXPGPATH)
+ *
+ * ret_path can be the same as head, but not the same as tail.
+ */
+void join_path_components(char *ret_path, const char *head, const char *tail)
+{
+       if (ret_path != head)
+               StrNCpy(ret_path, head, MAXPGPATH);
+
+       /*
+        * Remove any leading "." and ".." in the tail component,
+        * adjusting head as needed.
+        */
+       for (;;)
+       {
+               if (tail[0] == '.' && IS_DIR_SEP(tail[1]))
+               {
+                       tail += 2;
+               }
+               else if (tail[0] == '.' && tail[1] == '\0')
+               {
+                       tail += 1;
+                       break;
+               }
+               else if (tail[0] == '.' && tail[1] == '.' && IS_DIR_SEP(tail[2]))
+               {
+                       trim_directory(ret_path);
+                       tail += 3;
+               }
+               else if (tail[0] == '.' && tail[1] == '.' && tail[2] == '\0')
+               {
+                       trim_directory(ret_path);
+                       tail += 2;
+                       break;
+               }
+               else
+                       break;
+       }
+
+       if (*tail)
+               snprintf(ret_path + strlen(ret_path), MAXPGPATH - strlen(ret_path), "/%s", tail);
+}
+
+
+/*
+ *  Clean up path by:
+ *      o  remove trailing slash
+ *      o  remove duplicate adjacent separators
+ *      o  remove trailing '.'
+ *      o  process trailing '..' ourselves
+ */
+void canonicalize_path(char *path)
+{
+       char *p, *to_p;
+       bool was_sep = false;
+
+       /*
+        * Removing the trailing slash on a path means we never get ugly
+        * double trailing slashes.
+        */
+       trim_trailing_separator(path);
+
+       /*
+        *  Remove duplicate adjacent separators
+        */
+       p = path;
+       to_p = p;
+       for (; *p; p++, to_p++)
+       {
+               /* Handle many adjacent slashes, like "/a///b" */
+               while (*p == '/' && was_sep)
+                       p++;
+               if (to_p != p)
+                       *to_p = *p;
+               was_sep = (*p == '/');
+       }
+       *to_p = '\0';
+
+       /*
+        * Remove any trailing uses of "." and process ".." ourselves
+        */
+       for (;;)
+       {
+               int len = strlen(path);
+
+               if (len > 2 && strcmp(path + len - 2, "/.") == 0)
+                       trim_directory(path);
+               else if (len > 3 && strcmp(path + len - 3, "/..") == 0)
+               {
+                       trim_directory(path);
+                       trim_directory(path);
+                       /* remove directory above */
+               }
+               else
+                       break;
+       }
+}
+
+
+/*
+ *  trim_trailing_separator
+ *
+ * trim off trailing slashes, but not a leading slash
+ */
+static void trim_trailing_separator(char *path)
+{
+       char *p;
+
+       p = path + strlen(path);
+       if (p > path)
+               for (p--; p > path && IS_DIR_SEP(*p); p--)
+                       *p = '\0';
+}
diff --git a/pool_path.h b/pool_path.h
new file mode 100644 (file)
index 0000000..a1cc9a4
--- /dev/null
@@ -0,0 +1,81 @@
+/* -*-pgsql-c-*- */
+/*
+ *
+ * $Header$
+ *
+ * pgpool: a language independent connection pool server for PostgreSQL 
+ * written by Tatsuo Ishii
+ *
+ * Portions Copyright (c) 2003-2007,   PgPool Global Development Group
+ * Portions Copyright (c) 2004, PostgreSQL Global Development Group
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of the
+ * author not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. The author makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * pool_path.h.: interface to pool_path.c
+ *
+ */
+
+#ifndef POOL_PATH_H
+#define POOL_PATH_H
+
+/*
+ * MAXPGPATH: standard size of a pathname buffer in PostgreSQL (hence,
+ * maximum usable pathname length is one less).
+ *
+ * We'd use a standard system header symbol for this, if there weren't
+ * so many to choose from: MAXPATHLEN, MAX_PATH, PATH_MAX are all
+ * defined by different "standards", and often have different values
+ * on the same platform!  So we just punt and use a reasonably
+ * generous setting here.
+ */
+#define MAXPGPATH       1024
+
+#define IS_DIR_SEP(ch)  ((ch) == '/')
+#define is_absolute_path(filename) \
+( \
+    ((filename)[0] == '/') \
+)
+
+/*
+ * StrNCpy
+ *  Like standard library function strncpy(), except that result string
+ *  is guaranteed to be null-terminated --- that is, at most N-1 bytes
+ *  of the source string will be kept.
+ *  Also, the macro returns no result (too hard to do that without
+ *  evaluating the arguments multiple times, which seems worse).
+ *
+ *  BTW: when you need to copy a non-null-terminated string (like a text
+ *  datum) and add a null, do not do it with StrNCpy(..., len+1).  That
+ *  might seem to work, but it fetches one byte more than there is in the
+ *  text object.  One fine day you'll have a SIGSEGV because there isn't
+ *  another byte before the end of memory.  Don't laugh, we've had real
+ *  live bug reports from real live users over exactly this mistake.
+ *  Do it honestly with "memcpy(dst,src,len); dst[len] = '\0';", instead.
+ */
+#define StrNCpy(dst,src,len) \
+    do \
+    { \
+        char * _dst = (dst); \
+        size_t _len = (len); \
+\
+        if (_len > 0) \
+        { \
+            strncpy(_dst, (src), _len); \
+            _dst[_len-1] = '\0'; \
+        } \
+    } while (0)
+
+extern void get_parent_directory(char *path);
+extern void join_path_components(char *ret_path, const char *head, const char *tail);
+extern void canonicalize_path(char *path);
+       
+#endif /* POOL_PATH_H */
index c24ce3c5b257212019a279e93ca9226e26c86a59..a51d03465f3f62c0dd356f07e4a2f4dffcb2d319 100644 (file)
@@ -2243,6 +2243,21 @@ static void process_reporting(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *b
        status[i].desc = "number of queries in reset_query_list";
        i++;
 
+       status[i].name = "log_statement";
+       snprintf(status[i].value, MAXVALLEN, "%d", pool_config.log_statement);
+       status[i].desc = "if true, print all statements to the log";
+       i++;
+
+       status[i].name = "log_connections";
+       snprintf(status[i].value, MAXVALLEN, "%d", pool_config.log_connections);
+       status[i].desc = "if true, print incoming connections to the log";
+       i++;
+
+       status[i].name = "enable_pool_hba";
+       snprintf(status[i].value, MAXVALLEN, "%d", pool_config.enable_pool_hba);
+       status[i].desc = "if true, use pool_hba.conf for client authentication";
+       i++;
+
        status[i].name = "server_status";
 
        if (pool_config.server_status[0] == 0)
diff --git a/pool_type.h b/pool_type.h
new file mode 100644 (file)
index 0000000..2edf9b2
--- /dev/null
@@ -0,0 +1,139 @@
+/* -*-pgsql-c-*- */
+/*
+ *
+ * $Header$
+ *
+ * pgpool: a language independent connection pool server for PostgreSQL 
+ * written by Tatsuo Ishii
+ *
+ * Portions Copyright (c) 2003-2007,   PgPool Global Development Group
+ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of the
+ * author not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. The author makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * pool_type.h.: definition of new types
+ *
+ */
+
+#ifndef POOL_TYPE_H
+#define POOL_TYPE_H
+
+
+#include "config.h"
+#include <sys/socket.h>
+
+
+/* Define common boolean type. C++ and BEOS already has it so exclude them. */
+#ifdef c_plusplus
+#ifndef __cplusplus
+#define __cplusplus
+#endif /* __cplusplus */
+#endif /* c_plusplus */
+
+#ifndef __BEOS__
+#ifndef __cplusplus
+#ifndef bool
+typedef char bool;
+#endif
+#ifndef true
+#define true ((bool) 1)
+#endif
+#ifndef false
+#define false ((bool) 0)
+#endif
+#endif /* not C++ */
+#endif /* __BEOS__ */
+
+
+/*
+ *  It seems that sockaddr_storage is now commonly used in place of sockaddr.
+ *  So, define it if it is not define yet, and create new SockAddr structure
+ *  that uses sockaddr_storage.
+ */
+#ifdef HAVE_STRUCT_SOCKADDR_STORAGE
+
+#ifndef HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY
+#ifdef HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY
+#define ss_family __ss_family
+#else
+#error struct sockaddr_storage does not provide an ss_family member
+#endif /* HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY */
+#endif /* HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY */
+
+#ifdef HAVE_STRUCT_SOCKADDR_STORAGE___SS_LEN
+#define ss_len __ss_len
+#define HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN 1
+#endif /* HAVE_STRUCT_SOCKADDR_STORAGE___SS_LEN */
+
+#else /* !HAVE_STRUCT_SOCKADDR_STORAGE */
+
+/* Define a struct sockaddr_storage if we don't have one. */
+struct sockaddr_storage
+{
+       union
+       {
+               struct sockaddr sa;             /* get the system-dependent fields */
+               long int ss_align;              /* ensures struct is properly aligned. original uses int64 */
+               char ss_pad[128];               /* ensures struct has desired size */
+       }
+       ss_stuff;
+};
+
+#define ss_family   ss_stuff.sa.sa_family
+/* It should have an ss_len field if sockaddr has sa_len. */
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+#define ss_len      ss_stuff.sa.sa_len
+#define HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN 1
+#endif
+#endif /* HAVE_STRUCT_SOCKADDR_STORAGE */
+
+typedef struct
+{
+       struct sockaddr_storage addr;
+       /* ACCEPT_TYPE_ARG3 - Third argument type of accept().
+        * It is defined in ac_func_accept_argtypes.m4
+        * If a need to run aclocal arises, be sure to use "-I ./" option.
+        */
+       ACCEPT_TYPE_ARG3 salen;
+}
+SockAddr;
+
+
+/* UserAuth type used for HBA which indicates the authentication method */
+typedef enum UserAuth
+{
+       uaReject,
+/*     uaKrb4, */
+/*     uaKrb5, */
+       uaTrust
+/*     uaIdent, */
+/*     uaPassword, */
+/*     uaCrypt, */
+/*     uaMD5, */
+#ifdef USE_PAM
+       ,uaPAM
+#endif /* USE_PAM */
+}
+UserAuth;
+
+#define AUTH_REQ_OK         0   /* User is authenticated  */
+#define AUTH_REQ_KRB4       1   /* Kerberos V4 */
+#define AUTH_REQ_KRB5       2   /* Kerberos V5 */
+#define AUTH_REQ_PASSWORD   3   /* Password */
+#define AUTH_REQ_CRYPT      4   /* crypt password */
+#define AUTH_REQ_MD5        5   /* md5 password */
+#define AUTH_REQ_SCM_CREDS  6   /* transfer SCM credentials */
+
+typedef unsigned int AuthRequest;
+                                                          
+#endif /* POOL_TYPE_H */