adding the support for using and storing the encrypted passwords in pool_passwd
authorMuhammad Usama <[email protected]>
Fri, 20 Jul 2018 22:36:53 +0000 (03:36 +0500)
committerMuhammad Usama <[email protected]>
Fri, 20 Jul 2018 22:36:53 +0000 (03:36 +0500)
file to be used for SCRAM and other auth methods.
new utility pg_enc is also added for creating the encrypted passwords.
openssl is used for encryption and decryption, so Pgpool-II must be built with
ssl (--with-openssl) support to use the encrypted password feature.

21 files changed:
configure
configure.ac
src/Makefile.am
src/Makefile.in
src/auth/pool_auth.c
src/auth/pool_hba.c
src/auth/pool_passwd.c
src/include/auth/md5.h
src/include/auth/pool_passwd.h
src/include/auth/scram.h
src/include/pool.h
src/include/utils/ssl_utils.h [new file with mode: 0644]
src/include/watchdog/wd_utils.h
src/main/main.c
src/tools/Makefile.am
src/tools/Makefile.in
src/tools/pgenc/Makefile.am [new file with mode: 0644]
src/tools/pgenc/Makefile.in [new file with mode: 0644]
src/tools/pgenc/pg_enc.c [new file with mode: 0644]
src/utils/ssl_utils.c [new file with mode: 0644]
src/watchdog/wd_utils.c

index 848fae1611dd94b91d8b40fb16226ccecbd9d4e1..c0a08978bbeccc6885d33c7e7cddfb192e8a3517 100755 (executable)
--- a/configure
+++ b/configure
@@ -14906,7 +14906,7 @@ ac_config_headers="$ac_config_headers src/include/config.h"
 ac_config_files="$ac_config_files src/sql/pgpool_adm/Makefile"
 
 
-ac_config_files="$ac_config_files Makefile doc/Makefile doc/src/Makefile doc/src/sgml/Makefile doc.ja/Makefile doc.ja/src/Makefile doc.ja/src/sgml/Makefile src/Makefile src/include/Makefile src/parser/Makefile src/libs/Makefile src/libs/pcp/Makefile src/tools/Makefile src/tools/pgmd5/Makefile src/tools/pcp/Makefile src/watchdog/Makefile"
+ac_config_files="$ac_config_files Makefile doc/Makefile doc/src/Makefile doc/src/sgml/Makefile doc.ja/Makefile doc.ja/src/Makefile doc.ja/src/sgml/Makefile src/Makefile src/include/Makefile src/parser/Makefile src/libs/Makefile src/libs/pcp/Makefile src/tools/Makefile src/tools/pgmd5/Makefile src/tools/pgenc/Makefile src/tools/pcp/Makefile src/watchdog/Makefile"
 
 cat >confcache <<\_ACEOF
 # This file is a shell script that caches the results of configure
@@ -15937,6 +15937,7 @@ do
     "src/libs/pcp/Makefile") CONFIG_FILES="$CONFIG_FILES src/libs/pcp/Makefile" ;;
     "src/tools/Makefile") CONFIG_FILES="$CONFIG_FILES src/tools/Makefile" ;;
     "src/tools/pgmd5/Makefile") CONFIG_FILES="$CONFIG_FILES src/tools/pgmd5/Makefile" ;;
+    "src/tools/pgenc/Makefile") CONFIG_FILES="$CONFIG_FILES src/tools/pgenc/Makefile" ;;
     "src/tools/pcp/Makefile") CONFIG_FILES="$CONFIG_FILES src/tools/pcp/Makefile" ;;
     "src/watchdog/Makefile") CONFIG_FILES="$CONFIG_FILES src/watchdog/Makefile" ;;
 
index 1bbe75616267fa1cb2665f6f28f2adced02eb0ef..bc9bc303c46dc0868436d5eefd3d0d97fbd73829 100644 (file)
@@ -429,4 +429,4 @@ AC_MSG_RESULT([enable cassert = $enable_cassert])
 AM_CONFIG_HEADER(src/include/config.h)
 AC_CONFIG_FILES([src/sql/pgpool_adm/Makefile])
 
-AC_OUTPUT([Makefile doc/Makefile  doc/src/Makefile doc/src/sgml/Makefile doc.ja/Makefile  doc.ja/src/Makefile doc.ja/src/sgml/Makefile src/Makefile src/include/Makefile src/parser/Makefile src/libs/Makefile src/libs/pcp/Makefile src/tools/Makefile src/tools/pgmd5/Makefile src/tools/pcp/Makefile src/watchdog/Makefile])
+AC_OUTPUT([Makefile doc/Makefile  doc/src/Makefile doc/src/sgml/Makefile doc.ja/Makefile  doc.ja/src/Makefile doc.ja/src/sgml/Makefile src/Makefile src/include/Makefile src/parser/Makefile src/libs/Makefile src/libs/pcp/Makefile src/tools/Makefile src/tools/pgmd5/Makefile src/tools/pgenc/Makefile src/tools/pcp/Makefile src/watchdog/Makefile])
index 0155c48bd748688df77ef84d6d335143b7a59d14..941c943f33e3b164ed1b0ae0efa5a1e150a417ca 100644 (file)
@@ -57,6 +57,7 @@ pgpool_SOURCES = main/main.c \
        utils/scram-common.c \
        utils/base64.c \
        utils/sha2.c \
+       utils/ssl_utils.c \
     utils/statistics.c
 
 DEFS = @DEFS@ \
index be803ddfc5be0febff231f22c2dc08f052ddff2a..235f91a78376f39cf2bedbe79537c5503072d785 100644 (file)
@@ -135,7 +135,7 @@ am_pgpool_OBJECTS = main/main.$(OBJEXT) main/pool_globals.$(OBJEXT) \
        utils/regex_array.$(OBJEXT) utils/json_writer.$(OBJEXT) \
        utils/json.$(OBJEXT) utils/scram-common.$(OBJEXT) \
        utils/base64.$(OBJEXT) utils/sha2.$(OBJEXT) \
-       utils/statistics.$(OBJEXT)
+       utils/ssl_utils.$(OBJEXT) utils/statistics.$(OBJEXT)
 pgpool_OBJECTS = $(am_pgpool_OBJECTS)
 pgpool_DEPENDENCIES = parser/libsql-parser.a parser/nodes.o \
        watchdog/lib-watchdog.a
@@ -481,6 +481,7 @@ pgpool_SOURCES = main/main.c \
        utils/scram-common.c \
        utils/base64.c \
        utils/sha2.c \
+       utils/ssl_utils.c \
     utils/statistics.c
 
 sysconf_DATA = sample/pgpool.conf.sample \
@@ -742,6 +743,7 @@ utils/json.$(OBJEXT): utils/$(am__dirstamp)
 utils/scram-common.$(OBJEXT): utils/$(am__dirstamp)
 utils/base64.$(OBJEXT): utils/$(am__dirstamp)
 utils/sha2.$(OBJEXT): utils/$(am__dirstamp)
+utils/ssl_utils.$(OBJEXT): utils/$(am__dirstamp)
 utils/statistics.$(OBJEXT): utils/$(am__dirstamp)
 
 pgpool$(EXEEXT): $(pgpool_OBJECTS) $(pgpool_DEPENDENCIES) $(EXTRA_pgpool_DEPENDENCIES) 
index 124e21bc8c32548d35d68b36031328aa76e7e5a9..defcb675e3a7963d9bccf287922ddda22007c7dd 100644 (file)
@@ -274,7 +274,8 @@ int pool_do_auth(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *cp)
                                }
                        }
                        /* we have a password to use, validate the password type */
-                       if (passwordType != PASSWORD_TYPE_PLAINTEXT && passwordType != PASSWORD_TYPE_MD5)
+                       if (passwordType != PASSWORD_TYPE_PLAINTEXT && passwordType != PASSWORD_TYPE_MD5
+                               && passwordType != PASSWORD_TYPE_AES)
                        {
                                ereport(ERROR,
                                        (errmsg("failed to authenticate with backend using md5"),
@@ -307,13 +308,13 @@ int pool_do_auth(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *cp)
        else if (authkind == AUTH_REQ_SASL)
        {
                char *password;
-               PasswordType passwordType;
+               PasswordType passwordType = PASSWORD_TYPE_UNKNOWN;
 
                if (get_auth_password(MASTER(cp), frontend, 0,
                                                          &password, &passwordType) == false)
                {
                        /*
-                        * We do not have any passeord,
+                        * We do not have any password,
                         * we can still get the password from client using plain text authentication
                         * if it is allowed by user
                         */
@@ -334,12 +335,28 @@ int pool_do_auth(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *cp)
                                }
                        }
                }
+               /*
+                * if we have encrypted password,
+                * Decrypt it before going any further
+                */
+               if (passwordType == PASSWORD_TYPE_AES)
+               {
+                       password = get_decrypted_password(password);
+                       if (password == NULL)
+                               ereport(ERROR,
+                                               (errmsg("SCRAM authentication failed"),
+                                                errdetail("unable to decrypt password from pool_passwd"),
+                                                errhint("verify the valid pool_key exists")));
+                       /* we have converted the password to plain text */
+                       passwordType = PASSWORD_TYPE_PLAINTEXT;
+               }
+
                /* we have a password to use, validate the password type */
                if (passwordType != PASSWORD_TYPE_PLAINTEXT)
                {
                        ereport(ERROR,
                                        (errmsg("failed to authenticate with backend using SCRAM"),
-                                        errdetail("valid password not ")));
+                                        errdetail("valid password not found")));
                }
 
                for (i=0;i<NUM_BACKENDS;i++)
@@ -651,8 +668,8 @@ static void authenticate_frontend_clear_text(POOL_CONNECTION *frontend)
        static int size;
        char password[MAX_PASSWORD_SIZE];
        char userPassword[MAX_PASSWORD_SIZE];
-       char *pwd;
-
+       char *storedPassword = NULL;
+       char *userPwd = NULL;
 
        sendAuthRequest(frontend, frontend->protoVersion, AUTH_REQ_PASSWORD, NULL, 0);
 
@@ -669,11 +686,15 @@ static void authenticate_frontend_clear_text(POOL_CONNECTION *frontend)
        if (!frontend->passwordMapping)
        {
                /*
-                * if the password is not saved in pool_passwd
+                * if the password is not present in pool_passwd
                 * just bail out from here
                 */
                return;
        }
+
+       storedPassword = frontend->passwordMapping->pgpoolUser.password;
+       userPwd = password;
+
        /*
         * If we have md5 password stored in pool_passwd, convert the user
         * supplied password to md5 for comparison
@@ -683,21 +704,30 @@ static void authenticate_frontend_clear_text(POOL_CONNECTION *frontend)
                pg_md5_encrypt(password,
                                           frontend->username,
                                           strlen(frontend->username), userPassword);
-               
-               pwd = userPassword;
+               userPwd = userPassword;
+               size = strlen (userPwd);
        }
-       else if (frontend->passwordMapping->pgpoolUser.passwordType == PASSWORD_TYPE_PLAINTEXT)
+       else if (frontend->passwordMapping->pgpoolUser.passwordType == PASSWORD_TYPE_AES)
        {
-               pwd = password;
+               /*
+                * decrypt the stored AES password
+                * for comparing it
+                */
+               storedPassword = get_decrypted_password(storedPassword);
+               if (storedPassword == NULL)
+                       ereport(ERROR,
+                               (errmsg("clear text authentication failed"),
+                                        errdetail("unable to decrypt password from pool_passwd"),
+                                        errhint("verify the valid pool_key exists")));
        }
-       else
+       else if (frontend->passwordMapping->pgpoolUser.passwordType != PASSWORD_TYPE_PLAINTEXT)
        {
-               ereport(LOG,
-                               (errmsg("password type stored in pool_passwd can't be used for clear text authentication")));
-               return;
+               ereport(ERROR,
+                       (errmsg("clear text authentication failed"),
+                                errdetail("password type stored in pool_passwd can't be used for clear text authentication")));
        }
 
-       if (memcmp(password, frontend->passwordMapping->pgpoolUser.password, size))
+       if (memcmp(userPwd, storedPassword, size))
        {
                /* Password does not match */
                ereport(ERROR,
@@ -705,7 +735,10 @@ static void authenticate_frontend_clear_text(POOL_CONNECTION *frontend)
                                 errdetail("password does not match")));
        }
        ereport(LOG,
-                       (errmsg("clear text authentication successfull with frontend")));
+                       (errmsg("clear text authentication successful with frontend")));
+
+       if (frontend->passwordMapping->pgpoolUser.passwordType == PASSWORD_TYPE_AES)
+               pfree(storedPassword);
 
        frontend->frontend_authenticated = true;
 }
@@ -731,12 +764,28 @@ static int do_clear_text_password(POOL_CONNECTION *backend, POOL_CONNECTION *fro
                pwd = frontend->password;
                size = frontend->pwd_size;
        }
-       else if (frontend->passwordMapping && frontend->passwordMapping->pgpoolUser.passwordType == PASSWORD_TYPE_PLAINTEXT)
+       else if (frontend->passwordMapping)
        {
-               pwd = frontend->passwordMapping->pgpoolUser.password;
-               size = pwd? strlen(pwd): 0;
+               if (frontend->passwordMapping->pgpoolUser.passwordType == PASSWORD_TYPE_PLAINTEXT)
+               {
+                       pwd = frontend->passwordMapping->pgpoolUser.password;
+                       size = pwd? strlen(pwd): 0;
+               }
+               else if (frontend->passwordMapping->pgpoolUser.passwordType == PASSWORD_TYPE_AES)
+               {
+                       /*
+                        * decrypt the stored AES password
+                        * for comparing it
+                        */
+                       pwd = get_decrypted_password(frontend->passwordMapping->pgpoolUser.password);
+                       if (pwd == NULL)
+                               ereport(ERROR,
+                                       (errmsg("clear text password authentication failed"),
+                                                errdetail("unable to decrypt password from pool_passwd"),
+                                                errhint("verify the valid pool_key exists")));
+                       size = strlen(pwd);
+               }
        }
-
        if (pwd == NULL)
        {
                /* If we still do not have a password. we can't proceed */
@@ -972,6 +1021,22 @@ authenticate_frontend_SCRAM(POOL_CONNECTION *backend, POOL_CONNECTION *frontend,
                storedPassword = frontend->passwordMapping->pgpoolUser.password;
        }
 
+       if (storedPasswordType == PASSWORD_TYPE_AES)
+       {
+               /*
+                * decrypt the stored AES password
+                * for comparing it
+                */
+               storedPassword = get_decrypted_password(storedPassword);
+               if (storedPassword == NULL)
+                       ereport(ERROR,
+                                       (errmsg("SCRAM authentication failed"),
+                                        errdetail("unable to decrypt password from pool_passwd"),
+                                        errhint("verify the valid pool_key exists")));
+               /* we have converted the password to plain text */
+               storedPasswordType = PASSWORD_TYPE_PLAINTEXT;
+       }
+
        if (storedPasswordType != PASSWORD_TYPE_PLAINTEXT)
        {
                ereport(ERROR,
@@ -1145,7 +1210,7 @@ static void authenticate_frontend_cert(POOL_CONNECTION *frontend)
                        frontend->frontend_authenticated = true;
                        ereport(LOG,
                                        (errmsg("SSL certificate authentication for user \"%s\" with Pgpool-II is successful",frontend->username)));
-                       return POOL_CONTINUE;
+                       return;
                }
                else
                {
@@ -1218,12 +1283,30 @@ static void authenticate_frontend_md5(POOL_CONNECTION *backend, POOL_CONNECTION
        read_password_packet(frontend, frontend->protoVersion, password, &size);
 
        /*If we have clear text password stored in pool_passwd, convert it to md5 */
-       if (storedPasswordType == PASSWORD_TYPE_PLAINTEXT)
+       if (storedPasswordType == PASSWORD_TYPE_PLAINTEXT || storedPasswordType == PASSWORD_TYPE_AES)
        {
-               pg_md5_encrypt(storedPassword,
+               char *pwd;
+               if (storedPasswordType == PASSWORD_TYPE_AES)
+               {
+                       pwd = get_decrypted_password(storedPassword);
+                       if (pwd == NULL)
+                               ereport(ERROR,
+                                               (errmsg("md5 authentication failed"),
+                                                errdetail("unable to decrypt password from pool_passwd"),
+                                                errhint("verify the valid pool_key exists")));
+
+               }
+               else
+               {
+                       pwd = storedPassword;
+               }
+               pg_md5_encrypt(pwd,
                                           frontend->username,
                                           strlen(frontend->username), userPassword);
 
+               if (storedPasswordType == PASSWORD_TYPE_AES)
+                       pfree(pwd);
+
                md5 = userPassword;
        }
        else if (storedPasswordType == PASSWORD_TYPE_MD5)
@@ -1248,7 +1331,7 @@ static void authenticate_frontend_md5(POOL_CONNECTION *backend, POOL_CONNECTION
                                 errdetail("password does not match")));
        }
        ereport(LOG,
-                       (errmsg("md5 authentication successfull with frontend")));
+                       (errmsg("md5 authentication successful with frontend")));
 
        frontend->frontend_authenticated = true;
 }
@@ -1371,12 +1454,29 @@ static int do_md5(POOL_CONNECTION *backend, POOL_CONNECTION *frontend, int reaut
        char salt[4];
        static char userPassword[MAX_PASSWORD_SIZE];
        int kind;
+       bool password_decrypted = false;
        char encbuf[POOL_PASSWD_LEN+1];
        char *pool_passwd = NULL;
        
        if (NUM_BACKENDS == 1)
                return do_md5_single_backend(backend, frontend, reauth, protoMajor);
 
+       if (passwordType == PASSWORD_TYPE_AES)
+       {
+               /*
+                * decrypt the stored AES password
+                * for comparing it
+                */
+               storedPassword = get_decrypted_password(storedPassword);
+               if (storedPassword == NULL)
+                       ereport(ERROR,
+                                       (errmsg("md5 authentication failed"),
+                                        errdetail("unable to decrypt password from pool_passwd"),
+                                        errhint("verify the valid pool_key exists")));
+               /* we have converted the password to plain text */
+               passwordType = PASSWORD_TYPE_PLAINTEXT;
+               password_decrypted = true;
+       }
        if (passwordType == PASSWORD_TYPE_PLAINTEXT)
        {
                pg_md5_encrypt(storedPassword,
@@ -1452,6 +1552,10 @@ static int do_md5(POOL_CONNECTION *backend, POOL_CONNECTION *frontend, int reaut
                /* Save the auth info */
                backend->auth_kind = AUTH_REQ_MD5;
        }
+
+       if (password_decrypted && storedPassword)
+               pfree(storedPassword);
+
        return 0;
 }
 
index 59df59053fc4f1154803490ede2ec5dbe6fdd205..4e95828e6516cfc01fed364623ea8285d317beab 100644 (file)
@@ -846,7 +846,8 @@ void ClientAuthentication(POOL_CONNECTION *frontend)
                                                        errmsg("md5 authentication failed"),
                                                                errdetail("pool_passwd file does not contain an entry for \"%s\"",frontend->username)));
                                if (frontend->passwordMapping->pgpoolUser.passwordType != PASSWORD_TYPE_PLAINTEXT &&
-                                       frontend->passwordMapping->pgpoolUser.passwordType != PASSWORD_TYPE_MD5)
+                                       frontend->passwordMapping->pgpoolUser.passwordType != PASSWORD_TYPE_MD5 &&
+                                       frontend->passwordMapping->pgpoolUser.passwordType != PASSWORD_TYPE_AES)
                                        ereport(FATAL,
                                                (return_code(2),
                                                        errmsg("md5 authentication failed"),
@@ -860,7 +861,8 @@ void ClientAuthentication(POOL_CONNECTION *frontend)
                                                        errmsg("SCRAM authentication failed"),
                                                         errdetail("pool_passwd file does not contain an entry for \"%s\"",frontend->username)));
                                if (frontend->passwordMapping->pgpoolUser.passwordType != PASSWORD_TYPE_PLAINTEXT &&
-                                       frontend->passwordMapping->pgpoolUser.passwordType != PASSWORD_TYPE_SCRAM_SHA_256)
+                                       frontend->passwordMapping->pgpoolUser.passwordType != PASSWORD_TYPE_SCRAM_SHA_256 &&
+                                       frontend->passwordMapping->pgpoolUser.passwordType != PASSWORD_TYPE_AES)
                                        ereport(FATAL,
                                                (return_code(2),
                                                        errmsg("SCRAM authentication failed"),
index dab815d1c1c6f96ba3d68787998bd96c752b4960..051f18534ac1756b1433e590ac900ebd89b3acfd 100644 (file)
@@ -6,7 +6,7 @@
  * pgpool: a language independent connection pool server for PostgreSQL 
  * written by Tatsuo Ishii
  *
- * Copyright (c) 2003-2015     PgPool Global Development Group
+ * Copyright (c) 2003-2018     PgPool Global Development Group
  *
  * Permission to use, copy, modify, and distribute this software and
  * its documentation for any purpose and without fee is hereby
 #include "pool.h"
 #include "auth/pool_passwd.h"
 #include "auth/md5.h"
+#include "utils/ssl_utils.h"
+#include "utils/base64.h"
 #ifndef POOL_PRIVATE
 #include "utils/elog.h"
 #else
 #include "utils/fe_ports.h"
 #endif
+#include <sys/stat.h>
+
 
 static FILE *passwd_fd = NULL; /* File descriptor for pool_passwd */
 static char saved_passwd_filename[POOLMAXPATHLEN+1];
@@ -101,7 +105,7 @@ int pool_create_passwdent(char *username, char *passwd)
                                (errmsg("pool_create_passwdent should be called with pool_passwd opened with read/write mode")));
 
        len = strlen(passwd);
-       if (len != POOL_PASSWD_LEN)
+       if (len <= 0)
                ereport(ERROR,
                                (errmsg("error updating password, invalid password length:%d",len)));
 
@@ -411,15 +415,130 @@ void pool_reopen_passwd_file(void)
        pool_init_pool_passwd(saved_passwd_filename, pool_passwd_mode);
 }
 
+#ifndef POOL_PRIVATE
+char *get_decrypted_password(const char *shadow_pass)
+{
+       if (get_password_type(shadow_pass) == PASSWORD_TYPE_AES)
+       {
+               unsigned char b64_dec[MAX_PGPASS_LEN *2];
+               unsigned char plaintext[MAX_PGPASS_LEN];
+               int len;
+               char *pwd;
+               const char *enc_key = (const char*)get_pool_key();
+
+               if (enc_key == NULL)
+                       return NULL;
+
+               pwd = (char*)shadow_pass + 3;
+
+               if ((len = strlen(pwd)) == 0)
+                       return NULL;
+
+               if ((len = pg_b64_decode((const char*)pwd, len, (char*)b64_dec)) == 0)
+               {
+                       ereport(WARNING,
+                                       (errmsg("base64 decoding failed")));
+                       return NULL;
+               }
+               if ((len = aes_decrypt_with_password(b64_dec, len,
+                                                                               enc_key, plaintext)) <= 0)
+               {
+                       ereport(WARNING,
+                                       (errmsg("decryption failed")));
+                       return NULL;
+               }
+               plaintext[len] = 0;
+               return pstrdup((const char*)plaintext);
+       }
+       return NULL;
+}
+#else
+char *get_decrypted_password(const char *shadow_pass)
+{
+       ereport(ERROR,
+                       (errmsg("unable to decrypt password")));
+}
+#endif
+
 /*
 * What kind of a password verifier is 'shadow_pass'?
 */
 PasswordType
 get_password_type(const char *shadow_pass)
 {
-       if (strncmp(shadow_pass, "md5", 3) == 0 && strlen(shadow_pass) == MD5_PASSWD_LEN)
+       if (strncmp(shadow_pass, PASSWORD_MD5_PREFIX, strlen(PASSWORD_MD5_PREFIX)) == 0 && strlen(shadow_pass) == MD5_PASSWD_LEN)
                return PASSWORD_TYPE_MD5;
-       if (strncmp(shadow_pass, "SCRAM-SHA-256$", strlen("SCRAM-SHA-256$")) == 0)
+       if (strncmp(shadow_pass, PASSWORD_AES_PREFIX, strlen(PASSWORD_AES_PREFIX)) == 0 )
+               return PASSWORD_TYPE_AES;
+       if (strncmp(shadow_pass, PASSWORD_SCRAM_PREFIX, strlen(PASSWORD_SCRAM_PREFIX)) == 0)
                return PASSWORD_TYPE_SCRAM_SHA_256;
        return PASSWORD_TYPE_PLAINTEXT;
 }
+
+/*
+ * Get a key from the pgpool key file. return the palloc'd.
+ * value
+ */
+char *read_pool_key(char *key_file_path)
+{
+       FILE        *fp;
+       struct stat stat_buf;
+       char *key = NULL;
+
+#define LINELEN MAX_POOL_KEY_LEN
+       char        buf[LINELEN];
+
+       if (strlen(key_file_path) == 0)
+               return NULL;
+
+       /* If password file cannot be opened, ignore it. */
+       if (stat(key_file_path, &stat_buf) != 0)
+               return NULL;
+
+       if (!S_ISREG(stat_buf.st_mode))
+       {
+               ereport(WARNING,
+                               (errmsg("pool key file \"%s\" is not a text file\n",key_file_path)));
+               return NULL;
+       }
+
+       /* If password file is insecure, alert the user. */
+       if (stat_buf.st_mode & (S_IRWXG | S_IRWXO))
+       {
+               ereport(WARNING,
+                               (errmsg("pool key file \"%s\" is not a text file\n",key_file_path)));
+
+               ereport(WARNING,
+                               (errmsg("pool key file \"%s\" has group or world access; permissions should be u=rw (0600) or less\n",
+                               key_file_path)));
+               /* do we want to allow unsecure pool key file ?*/
+               //return NULL;
+       }
+
+       fp = fopen(key_file_path, "r");
+       if (fp == NULL)
+               return NULL;
+
+       while (!feof(fp) && !ferror(fp))
+       {
+               int     len;
+
+               if (fgets(buf, sizeof(buf), fp) == NULL)
+                       break;
+
+               len = strlen(buf);
+               if (len == 0)
+                       continue;
+
+               /* Remove trailing newline */
+               if (buf[len - 1] == '\n')
+                       buf[len - 1] = 0;
+               key = pstrdup(buf);
+               break;
+       }
+
+       fclose(fp);
+       return key;
+
+#undef LINELEN
+}
index 209a9d0db89c18705b70348f9faa6716e2f0c8cc..87d23769f9229cc39ae6b7ac5ed814e81c6fb230 100644 (file)
@@ -19,7 +19,6 @@
 #ifndef MD5_H
 #define MD5_H
 
-#define MAX_USER_NAME_LEN 128
 #define MD5_PASSWD_LEN 32
 
 #define WD_AUTH_HASH_LEN 64
index 45f82dcac3440351d0ef3e14f270c68c870af3a1..9005f904ca7af1bbc1d024c5f806ebcf97cc5f11 100644 (file)
 #define POOL_PASSWD_FILENAME "pool_passwd"
 #define POOL_PASSWD_LEN 35
 
+#define MAX_USER_NAME_LEN      128
+#define MAX_PGPASS_LEN         128
+#define MAX_POOL_KEY_LEN       256
+
+
+#define PASSWORD_MD5_PREFIX    "md5"
+#define PASSWORD_AES_PREFIX    "AES"
+#define PASSWORD_SCRAM_PREFIX  "SCRAM-SHA-256$"
+
 typedef enum {
        POOL_PASSWD_R,          /* open pool_passwd in read only mode. used by pgpool-II child main process */
        POOL_PASSWD_RW,         /* open pool_passwd in read/write mode. used by pg_md5 command */
@@ -40,6 +49,7 @@ typedef enum PasswordType
        PASSWORD_TYPE_UNKNOWN = 0,
        PASSWORD_TYPE_PLAINTEXT,
        PASSWORD_TYPE_MD5,
+       PASSWORD_TYPE_AES,
        PASSWORD_TYPE_SCRAM_SHA_256
 } PasswordType;
 
@@ -65,5 +75,7 @@ extern char *pool_get_passwd(char *username);
 extern void pool_delete_passwdent(char *username);
 extern void pool_finish_pool_passwd(void);
 extern void pool_reopen_passwd_file(void);
+extern char *get_decrypted_password(const char *shadow_pass);
+extern char *read_pool_key(char *key_file_path);
 
 #endif /* POOL_PASSWD_H */
index c2768fbb2b1f4ea138a0ff9b1aee60945212083b..71222d47ccca5d7b10f551d18e6dde3496151a11 100644 (file)
@@ -59,5 +59,7 @@ extern void *pg_fe_scram_init(const char *username, const char *password);
 extern void pg_fe_scram_exchange(void *opaq, char *input, int inputlen,
                                         char **output, int *outputlen,
                                                  bool *done, bool *success);
+extern void pg_fe_scram_free(void *opaq);
+extern char *pg_fe_scram_build_verifier(const char *password);
 
 #endif                                                 /* PG_SCRAM_H */
index 96f60a9b8cfc7891ada89ea3ed6060478bb854b9..0881f0aaf14a380bab411e21c3b7ad03b00c621b 100644 (file)
@@ -51,6 +51,9 @@
 
 #define POOLMAXPATHLEN 8192
 
+#define POOLKEYFILE    ".pgpoolkey"
+#define POOLKEYFILEENV "PGPOOLKEYFILE"
+
 /*
  * Brought from PostgreSQL's pg_config_manual.h.
  *
@@ -712,6 +715,7 @@ extern void pool_random(void *buf, size_t len);
 
 /* main.c */
 extern void pool_sleep(unsigned int second);
+extern char *get_pool_key(void);
 
 /* pool_worker_child.c */
 extern void do_worker_child(void);
diff --git a/src/include/utils/ssl_utils.h b/src/include/utils/ssl_utils.h
new file mode 100644 (file)
index 0000000..36b053d
--- /dev/null
@@ -0,0 +1,34 @@
+/* -*-pgsql-c-*- */
+/*
+ *
+ * $Header$
+ *
+ * pgpool: a language independent connection pool server for PostgreSQL
+ * written by Tatsuo Ishii
+ *
+ * Copyright (c) 2003-2018     PgPool 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.
+ *
+ *
+ */
+
+#ifndef SSL_UTILS_H
+#define SSL_UTILS_H
+
+extern void calculate_hmac_sha256(const char *data, int len, char *buf);
+extern int aes_decrypt_with_password(unsigned char *ciphertext, int ciphertext_len,
+                                                         const char *password, unsigned char *plaintext);
+extern int aes_encrypt_with_password(unsigned char *plaintext, int plaintext_len,
+                                                         const char *password, unsigned char *ciphertext);
+
+#endif
index 69bdbd0d029e8cf5de8aea92808a8372f30f971c..cd6567a29f18a8fe9b2318088281c17d1f118d6c 100644 (file)
@@ -6,7 +6,7 @@
  * pgpool: a language independent connection pool server for PostgreSQL
  * written by Tatsuo Ishii
  *
- * Copyright (c) 2003-2016     PgPool Global Development Group
+ * Copyright (c) 2003-2018     PgPool Global Development Group
  *
  * Permission to use, copy, modify, and distribute this software and
  * its documentation for any purpose and without fee is hereby
@@ -38,7 +38,10 @@ extern void wd_check_network_command_configurations(void);
 extern int watchdog_thread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
 extern char *string_replace(const char *string, const char *pattern, const char *replacement);
 extern void wd_calc_hash(const char *str, int len, char *buf);
-
+extern int aes_decrypt_with_password(unsigned char *ciphertext, int ciphertext_len,
+                                                         const char *password, unsigned char *plaintext);
+extern int aes_encrypt_with_password(unsigned char *plaintext, int plaintext_len,
+                                                         const char *password, unsigned char *ciphertext);
 /* wd_escalation.c */
 extern pid_t fork_escalation_process(void);
 extern pid_t fork_plunging_process(void);
index 0d7bde87df36831c01a2a35a68d921d078ca5584..a8af732ba02b56df3cba80b80591e72eea84b0b7 100644 (file)
@@ -5,7 +5,7 @@
  * pgpool: a language independent connection pool server for PostgreSQL
  * written by Tatsuo Ishii
  *
- * Copyright (c) 2003-2017     PgPool Global Development Group
+ * Copyright (c) 2003-2018     PgPool Global Development Group
  *
  * Permission to use, copy, modify, and distribute this software and
  * its documentation for any purpose and without fee is hereby
@@ -47,6 +47,9 @@
 #include "watchdog/wd_utils.h"
 #include "pool_config_variables.h"
 
+
+static bool get_pool_key_filename(char *poolKeyFile);
+
 static void daemonize(void);
 static char    *get_pid_file_path(void);
 static int read_pid_file(void);
@@ -66,7 +69,7 @@ int stop_sig = SIGTERM;               /* stopping signal default value */
 int myargc;
 char **myargv;
 int assert_enabled = 0;
-
+char *pool_key = NULL;
 int main(int argc, char **argv)
 {
        int opt;
@@ -78,11 +81,13 @@ int main(int argc, char **argv)
        char pcp_conf_file_path[POOLMAXPATHLEN+1];
        char conf_file_path[POOLMAXPATHLEN+1];
        char hba_file_path[POOLMAXPATHLEN+1];
+       char pool_passwd_key_file_path[POOLMAXPATHLEN+1];
 
        static struct option long_options[] = {
                {"hba-file", required_argument, NULL, 'a'},
                {"debug", no_argument, NULL, 'd'},
                {"config-file", required_argument, NULL, 'f'},
+               {"key-file", required_argument, NULL, 'k'},
                {"pcp-file", required_argument, NULL, 'F'},
                {"help", no_argument, NULL, 'h'},
                {"mode", required_argument, NULL, 'm'},
@@ -100,7 +105,9 @@ int main(int argc, char **argv)
        snprintf(conf_file_path, sizeof(conf_file_path), "%s/%s", DEFAULT_CONFIGDIR, POOL_CONF_FILE_NAME);
        snprintf(pcp_conf_file_path, sizeof(pcp_conf_file_path), "%s/%s", DEFAULT_CONFIGDIR, PCP_PASSWD_FILE_NAME);
        snprintf(hba_file_path, sizeof(hba_file_path), "%s/%s", DEFAULT_CONFIGDIR, HBA_CONF_FILE_NAME);
-    while ((opt = getopt_long(argc, argv, "a:df:F:hm:nDCxv", long_options, &optindex)) != -1)
+       pool_passwd_key_file_path[0] = 0;
+
+       while ((opt = getopt_long(argc, argv, "a:df:k:F:hm:nDCxv", long_options, &optindex)) != -1)
        {
                switch (opt)
                {
@@ -139,6 +146,15 @@ int main(int argc, char **argv)
                                strlcpy(pcp_conf_file_path, optarg, sizeof(pcp_conf_file_path));
                                break;
 
+                       case 'k':       /* specify key file for decrypt pool_password entries */
+                               if (!optarg)
+                               {
+                                       usage();
+                                       exit(1);
+                               }
+                               strlcpy(pool_passwd_key_file_path, optarg, sizeof(pool_passwd_key_file_path));
+                               break;
+
                        case 'h':
                                usage();
                                exit(0);
@@ -299,6 +315,13 @@ int main(int argc, char **argv)
        /* set signal masks */
        poolinitmask();
 
+       /* read the pool password key */
+       if (strlen(pool_passwd_key_file_path) == 0)
+       {
+               get_pool_key_filename(pool_passwd_key_file_path);
+       }
+       pool_key = read_pool_key(pool_passwd_key_file_path);
+
        if (not_detach)
                write_pid_file();
        else
@@ -336,6 +359,10 @@ static void show_version(void)
 
 static void usage(void)
 {
+       char    homedir[POOLMAXPATHLEN];
+       if (!get_home_directory(homedir, sizeof(homedir)))
+               strncpy(homedir,"USER-HOME-DIR",POOLMAXPATHLEN);
+
        fprintf(stderr, "%s version %s (%s),\n",        PACKAGE, VERSION, PGPOOLVERSION);
        fprintf(stderr, "  A generic connection pool/replication/load balance server for PostgreSQL\n\n");
        fprintf(stderr, "Usage:\n");
@@ -351,6 +378,10 @@ static void usage(void)
        fprintf(stderr, "  -f, --config-file=CONFIG_FILE\n");
        fprintf(stderr, "                      Set the path to the pgpool.conf configuration file\n");
        fprintf(stderr, "                      (default: %s/%s)\n",DEFAULT_CONFIGDIR, POOL_CONF_FILE_NAME);
+       fprintf(stderr, "  -k, --key-file=KEY_FILE\n");
+       fprintf(stderr, "                      Set the path to the pgpool key file\n");
+       fprintf(stderr, "                      (default: %s/%s)\n",homedir, POOLKEYFILE);
+       fprintf(stderr, "                      can be over ridden by %s environment variable\n",POOLKEYFILEENV);
        fprintf(stderr, "  -F, --pcp-file=PCP_CONFIG_FILE\n");
        fprintf(stderr, "                      Set the path to the pcp.conf configuration file\n");
        fprintf(stderr, "                      (default: %s/%s)\n",DEFAULT_CONFIGDIR, PCP_PASSWD_FILE_NAME);
@@ -371,6 +402,31 @@ static void usage(void)
        fprintf(stderr, "  immediate   the same mode as fast\n");
 }
 
+static bool
+get_pool_key_filename(char *poolKeyFile)
+{
+       char    *passfile_env;
+
+       if ((passfile_env = getenv(POOLKEYFILEENV)) != NULL)
+       {
+               /* use the literal path from the environment, if set */
+               strlcpy(poolKeyFile, passfile_env, POOLMAXPATHLEN);
+       }
+       else
+       {
+               char    homedir[POOLMAXPATHLEN];
+               if (!get_home_directory(homedir, sizeof(homedir)))
+                       return false;
+               snprintf(poolKeyFile, POOLMAXPATHLEN, "%s/%s", homedir, POOLKEYFILE);
+       }
+       return true;
+}
+
+
+char *get_pool_key(void)
+{
+       return pool_key;
+}
 /*
 * detach control ttys
 */
index cb31c42f7b23e278a5e8c0872ae9dd9e568b5e11..7f446c87e502fc5f3e6b76c813c19c2d50c55cff 100644 (file)
@@ -1,4 +1,4 @@
-SUBDIRS = pcp pgmd5
+SUBDIRS = pcp pgmd5 pgenc
 
 dist_bin_SCRIPTS =  pgpool_setup watchdog_setup
 
index c86ecab2b2d175811a509845de5b6fd1bcb0b5fa..ea12591d607374e4674b65103c563788b2741445 100644 (file)
@@ -343,7 +343,7 @@ target_alias = @target_alias@
 top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
-SUBDIRS = pcp pgmd5
+SUBDIRS = pcp pgmd5 pgenc
 dist_bin_SCRIPTS = pgpool_setup watchdog_setup
 all: all-recursive
 
diff --git a/src/tools/pgenc/Makefile.am b/src/tools/pgenc/Makefile.am
new file mode 100644 (file)
index 0000000..b04fb4d
--- /dev/null
@@ -0,0 +1,54 @@
+AM_CPPFLAGS = -D_GNU_SOURCE -DPOOL_PRIVATE -I @PGSQL_INCLUDE_DIR@
+bin_PROGRAMS = pg_enc
+
+dist_pg_enc_SOURCES = pg_enc.c \
+               ../fe_port.c
+nodist_pg_enc_SOURCES = ssl_utils.c \
+               md5.c \
+               base64.c \
+               pool_passwd.c \
+               pool_signal.c \
+               strlcpy.c \
+               regex_array.c \
+               pool_config_variables.c \
+               pool_config.c \
+               fe_memutils.c \
+               pool_path.c \
+               pool_globals.c
+
+DEFS = @DEFS@ \
+    -DDEFAULT_CONFIGDIR=\"$(sysconfdir)\" -DPOOL_TOOLS
+
+pool_passwd.c: ../../../src/auth/pool_passwd.c
+       rm -f $@ && ln -s $< .
+pool_path.c: ../../../src/utils/pool_path.c
+       rm -f $@ && ln -s $< .
+md5.c: ../../../src/auth/md5.c
+       rm -f $@ && ln -s $< .
+md5.h: ../../../src/include/auth/md5.h
+       rm -f $@ && ln -s $< .
+base64.c: ../../../src/utils/base64.c
+       rm -f $@ && ln -s $< .
+ssl_utils.c: ../../../src/utils/ssl_utils.c
+       rm -f $@ && ln -s $< .
+base64.h: ../../../src/include/utils/base64.h
+       rm -f $@ && ln -s $< .
+ssl_utils.h: ../../../src/include/utils/ssl_utils.h
+       rm -f $@ && ln -s $< .
+pool_signal.c: ../../../src/utils/pool_signal.c
+       rm -f $@ && ln -s $< .
+strlcpy.c: ../../../src/utils/strlcpy.c
+       rm -f $@ && ln -s $< .
+regex_array.c: ../../../src/utils/regex_array.c
+       rm -f $@ && ln -s $< .
+pool_config_variables.c: ../../../src/config/pool_config_variables.c
+       rm -f $@ && ln -s $< .
+pool_config.c: ../../../src/config/pool_config.c
+       rm -f $@ && ln -s $< .
+fe_memutils.c: ../../../src/tools/fe_memutils.c
+       rm -f $@ && ln -s $< .
+pool_globals.c: ../../../src/main/pool_globals.c
+       rm -f $@ && ln -s $< .
+
+clean-local:
+       -rm -f $(nodist_pg_enc_SOURCES)
diff --git a/src/tools/pgenc/Makefile.in b/src/tools/pgenc/Makefile.in
new file mode 100644 (file)
index 0000000..e71fdbb
--- /dev/null
@@ -0,0 +1,687 @@
+# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \  ]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs  ]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+bin_PROGRAMS = pg_enc$(EXEEXT)
+subdir = src/tools/pgenc
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+       $(top_srcdir)/mkinstalldirs
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/docbook.m4 \
+       $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+       $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+       $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/c-compiler.m4 \
+       $(top_srcdir)/c-library.m4 $(top_srcdir)/general.m4 \
+       $(top_srcdir)/ac_func_accept_argtypes.m4 \
+       $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+       $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/src/include/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(bindir)"
+PROGRAMS = $(bin_PROGRAMS)
+am__dirstamp = $(am__leading_dot)dirstamp
+dist_pg_enc_OBJECTS = pg_enc.$(OBJEXT) ../fe_port.$(OBJEXT)
+nodist_pg_enc_OBJECTS = ssl_utils.$(OBJEXT) md5.$(OBJEXT) \
+       base64.$(OBJEXT) pool_passwd.$(OBJEXT) pool_signal.$(OBJEXT) \
+       strlcpy.$(OBJEXT) regex_array.$(OBJEXT) \
+       pool_config_variables.$(OBJEXT) pool_config.$(OBJEXT) \
+       fe_memutils.$(OBJEXT) pool_path.$(OBJEXT) \
+       pool_globals.$(OBJEXT)
+pg_enc_OBJECTS = $(dist_pg_enc_OBJECTS) $(nodist_pg_enc_OBJECTS)
+pg_enc_LDADD = $(LDADD)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/src/include
+depcomp =
+am__depfiles_maybe =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+       $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+       $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+       $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+       $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = $(dist_pg_enc_SOURCES) $(nodist_pg_enc_SOURCES)
+DIST_SOURCES = $(dist_pg_enc_SOURCES)
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CATALOG = @CATALOG@
+CC = @CC@
+CFLAGS = @CFLAGS@
+COLLATEINDEX = @COLLATEINDEX@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@ \
+    -DDEFAULT_CONFIGDIR=\"$(sysconfdir)\" -DPOOL_TOOLS
+
+DLLTOOL = @DLLTOOL@
+DOCBOOKSTYLE = @DOCBOOKSTYLE@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JADE = @JADE@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LYNX = @LYNX@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MEMCACHED_DIR = @MEMCACHED_DIR@
+MEMCACHED_INCLUDE_OPT = @MEMCACHED_INCLUDE_OPT@
+MEMCACHED_LINK_OPT = @MEMCACHED_LINK_OPT@
+MEMCACHED_RPATH_OPT = @MEMCACHED_RPATH_OPT@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NSGMLS = @NSGMLS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OSX = @OSX@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PGCONFIG = @PGCONFIG@
+PGSQL_INCLUDE_DIR = @PGSQL_INCLUDE_DIR@
+PGSQL_LIB_DIR = @PGSQL_LIB_DIR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+STYLE = @STYLE@
+VERSION = @VERSION@
+XMLLINT = @XMLLINT@
+XSLTPROC = @XSLTPROC@
+XSLTPROC_HTML_FLAGS = @XSLTPROC_HTML_FLAGS@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__leading_dot = @am__leading_dot@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+have_docbook = @have_docbook@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = -D_GNU_SOURCE -DPOOL_PRIVATE -I @PGSQL_INCLUDE_DIR@
+dist_pg_enc_SOURCES = pg_enc.c \
+               ../fe_port.c
+
+nodist_pg_enc_SOURCES = ssl_utils.c \
+               md5.c \
+               base64.c \
+               pool_passwd.c \
+               pool_signal.c \
+               strlcpy.c \
+               regex_array.c \
+               pool_config_variables.c \
+               pool_config.c \
+               fe_memutils.c \
+               pool_path.c \
+               pool_globals.c
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+       @for dep in $?; do \
+         case '$(am__configure_deps)' in \
+           *$$dep*) \
+             ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+               && { if test -f $@; then exit 0; else break; fi; }; \
+             exit 1;; \
+         esac; \
+       done; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps src/tools/pgenc/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --foreign --ignore-deps src/tools/pgenc/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       @case '$?' in \
+         *config.status*) \
+           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+         *) \
+           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+       esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-binPROGRAMS: $(bin_PROGRAMS)
+       @$(NORMAL_INSTALL)
+       @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+       if test -n "$$list"; then \
+         echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
+         $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
+       fi; \
+       for p in $$list; do echo "$$p $$p"; done | \
+       sed 's/$(EXEEXT)$$//' | \
+       while read p p1; do if test -f $$p \
+        || test -f $$p1 \
+         ; then echo "$$p"; echo "$$p"; else :; fi; \
+       done | \
+       sed -e 'p;s,.*/,,;n;h' \
+           -e 's|.*|.|' \
+           -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+       sed 'N;N;N;s,\n, ,g' | \
+       $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+         { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+           if ($$2 == $$4) files[d] = files[d] " " $$1; \
+           else { print "f", $$3 "/" $$4, $$1; } } \
+         END { for (d in files) print "f", d, files[d] }' | \
+       while read type dir files; do \
+           if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+           test -z "$$files" || { \
+           echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+           $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+           } \
+       ; done
+
+uninstall-binPROGRAMS:
+       @$(NORMAL_UNINSTALL)
+       @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+       files=`for p in $$list; do echo "$$p"; done | \
+         sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+             -e 's/$$/$(EXEEXT)/' \
+       `; \
+       test -n "$$list" || exit 0; \
+       echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+       cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+       @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
+       echo " rm -f" $$list; \
+       rm -f $$list || exit $$?; \
+       test -n "$(EXEEXT)" || exit 0; \
+       list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+       echo " rm -f" $$list; \
+       rm -f $$list
+../$(am__dirstamp):
+       @$(MKDIR_P) ..
+       @: > ../$(am__dirstamp)
+../fe_port.$(OBJEXT): ../$(am__dirstamp)
+
+pg_enc$(EXEEXT): $(pg_enc_OBJECTS) $(pg_enc_DEPENDENCIES) $(EXTRA_pg_enc_DEPENDENCIES) 
+       @rm -f pg_enc$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(pg_enc_OBJECTS) $(pg_enc_LDADD) $(LIBS)
+
+mostlyclean-compile:
+       -rm -f *.$(OBJEXT)
+       -rm -f ../*.$(OBJEXT)
+
+distclean-compile:
+       -rm -f *.tab.c
+
+.c.o:
+       $(AM_V_CC)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+       $(AM_V_CC)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+       $(AM_V_CC)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+       $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+       set x; \
+       here=`pwd`; \
+       $(am__define_uniq_tagged_files); \
+       shift; \
+       if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+         test -n "$$unique" || unique=$$empty_fix; \
+         if test $$# -gt 0; then \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             "$$@" $$unique; \
+         else \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             $$unique; \
+         fi; \
+       fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+       $(am__define_uniq_tagged_files); \
+       test -z "$(CTAGS_ARGS)$$unique" \
+         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+            $$unique
+
+GTAGS:
+       here=`$(am__cd) $(top_builddir) && pwd` \
+         && $(am__cd) $(top_srcdir) \
+         && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+       list='$(am__tagged_files)'; \
+       case "$(srcdir)" in \
+         [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+         *) sdir=$(subdir)/$(srcdir) ;; \
+       esac; \
+       for i in $$list; do \
+         if test -f "$$i"; then \
+           echo "$(subdir)/$$i"; \
+         else \
+           echo "$$sdir/$$i"; \
+         fi; \
+       done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+       -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       list='$(DISTFILES)'; \
+         dist_files=`for file in $$list; do echo $$file; done | \
+         sed -e "s|^$$srcdirstrip/||;t" \
+             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+       case $$dist_files in \
+         */*) $(MKDIR_P) `echo "$$dist_files" | \
+                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+                          sort -u` ;; \
+       esac; \
+       for file in $$dist_files; do \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         if test -d $$d/$$file; then \
+           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+           if test -d "$(distdir)/$$file"; then \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+         else \
+           test -f "$(distdir)/$$file" \
+           || cp -p $$d/$$file "$(distdir)/$$file" \
+           || exit 1; \
+         fi; \
+       done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS)
+installdirs:
+       for dir in "$(DESTDIR)$(bindir)"; do \
+         test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+       done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+       if test -z '$(STRIP)'; then \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+             install; \
+       else \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+           "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+       fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+       -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+       -rm -f ../$(am__dirstamp)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic clean-libtool clean-local \
+       mostlyclean-am
+
+distclean: distclean-am
+       -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+       distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+       mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \
+       clean-binPROGRAMS clean-generic clean-libtool clean-local \
+       cscopelist-am ctags ctags-am distclean distclean-compile \
+       distclean-generic distclean-libtool distclean-tags distdir dvi \
+       dvi-am html html-am info info-am install install-am \
+       install-binPROGRAMS install-data install-data-am install-dvi \
+       install-dvi-am install-exec install-exec-am install-html \
+       install-html-am install-info install-info-am install-man \
+       install-pdf install-pdf-am install-ps install-ps-am \
+       install-strip installcheck installcheck-am installdirs \
+       maintainer-clean maintainer-clean-generic mostlyclean \
+       mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+       pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
+       uninstall-binPROGRAMS
+
+
+pool_passwd.c: ../../../src/auth/pool_passwd.c
+       rm -f $@ && ln -s $< .
+pool_path.c: ../../../src/utils/pool_path.c
+       rm -f $@ && ln -s $< .
+md5.c: ../../../src/auth/md5.c
+       rm -f $@ && ln -s $< .
+md5.h: ../../../src/include/auth/md5.h
+       rm -f $@ && ln -s $< .
+base64.c: ../../../src/utils/base64.c
+       rm -f $@ && ln -s $< .
+ssl_utils.c: ../../../src/utils/ssl_utils.c
+       rm -f $@ && ln -s $< .
+base64.h: ../../../src/include/utils/base64.h
+       rm -f $@ && ln -s $< .
+ssl_utils.h: ../../../src/include/utils/ssl_utils.h
+       rm -f $@ && ln -s $< .
+pool_signal.c: ../../../src/utils/pool_signal.c
+       rm -f $@ && ln -s $< .
+strlcpy.c: ../../../src/utils/strlcpy.c
+       rm -f $@ && ln -s $< .
+regex_array.c: ../../../src/utils/regex_array.c
+       rm -f $@ && ln -s $< .
+pool_config_variables.c: ../../../src/config/pool_config_variables.c
+       rm -f $@ && ln -s $< .
+pool_config.c: ../../../src/config/pool_config.c
+       rm -f $@ && ln -s $< .
+fe_memutils.c: ../../../src/tools/fe_memutils.c
+       rm -f $@ && ln -s $< .
+pool_globals.c: ../../../src/main/pool_globals.c
+       rm -f $@ && ln -s $< .
+
+clean-local:
+       -rm -f $(nodist_pg_enc_SOURCES)
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/tools/pgenc/pg_enc.c b/src/tools/pgenc/pg_enc.c
new file mode 100644 (file)
index 0000000..8671b44
--- /dev/null
@@ -0,0 +1,450 @@
+/* -*-pgsql-c-*- */
+/*
+ * $Header$
+ *
+ * pgpool: a language independent connection pool server for PostgreSQL
+ * written by Tatsuo Ishii
+ *
+ * Copyright (c) 2003-2018     PgPool 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.
+ *
+ * pg_enc command main
+ *
+ */
+#include "pool.h"
+#include "pool_config.h"
+#include "auth/pool_passwd.h"
+#include "utils/ssl_utils.h"
+#include "utils/pool_path.h"
+#include "utils/base64.h"
+#include "version.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <termios.h>
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#else
+#include "utils/getopt_long.h"
+#endif
+#include <pwd.h>
+#include <libgen.h>
+
+#define MAX_ENCODED_PASSWD_LEN (MAX_POOL_KEY_LEN * 2)
+
+static void    print_usage(const char prog[], int exit_code);
+static void    set_tio_attr(int enable);
+static void update_pool_passwd(char *conf_file, char *username, char *password, char *key);
+static bool get_pool_key_filename(char *poolKeyFile);
+
+int
+main(int argc, char *argv[])
+{
+#define PRINT_USAGE(exit_code) print_usage(argv[0], exit_code)
+
+       char conf_file[POOLMAXPATHLEN+1];
+       char enc_key[MAX_POOL_KEY_LEN+1];
+       char pg_pass[MAX_PGPASS_LEN+1];
+       char username[MAX_USER_NAME_LEN+1];
+       char key_file_path[POOLMAXPATHLEN];
+       int opt;
+       int optindex;
+       bool updatepasswd = false;
+       bool prompt = false;
+       bool prompt_for_key = false;
+       char *pool_key = NULL;
+
+       static struct option long_options[] = {
+               {"help", no_argument, NULL, 'h'},
+               {"prompt", no_argument, NULL, 'p'},
+               {"prompt-for-key", no_argument, NULL, 'P'},
+               {"update-pass", no_argument, NULL, 'm'},
+               {"username", required_argument, NULL, 'u'},
+               {"enc-key", required_argument, NULL, 'K'},
+               {"key-file", required_argument, NULL, 'k'},
+               {"config-file", required_argument, NULL, 'f'},
+               {NULL, 0, NULL, 0}
+       };
+
+       snprintf(conf_file, sizeof(conf_file), "%s/%s", DEFAULT_CONFIGDIR, POOL_CONF_FILE_NAME);
+
+       /* initialize username buffer with zeros so that we can use strlen on it later
+          to check if a username was given on the command line
+        */
+       memset(username, 0, sizeof(username));
+       memset(enc_key, 0, sizeof(enc_key));
+       memset(key_file_path, 0, sizeof(key_file_path));
+
+       while ((opt = getopt_long(argc, argv, "hPpmf:u:k:K:", long_options, &optindex)) != -1)
+       {
+               switch (opt)
+               {
+                       case 'p':    /* prompt for postgres password */
+                               prompt = true;
+                               break;
+
+                       case 'P':    /* prompt for encryption key */
+                               prompt_for_key = true;
+                               break;
+
+                       case 'm':       /* update password file */
+                               updatepasswd = true;
+                               break;
+
+                       case 'f':       /* specify configuration file */
+                               if (!optarg)
+                               {
+                                       PRINT_USAGE(EXIT_SUCCESS);
+                               }
+                               strlcpy(conf_file, optarg, sizeof(conf_file));
+                               break;
+
+                       case 'k':       /* specify key file for encrypting pool_password entries */
+                               if (!optarg)
+                               {
+                                       PRINT_USAGE(EXIT_SUCCESS);
+                               }
+                               strlcpy(key_file_path, optarg, sizeof(key_file_path));
+                               break;
+
+                       case 'K':       /* specify configuration file */
+                               if (!optarg)
+                               {
+                                       PRINT_USAGE(EXIT_SUCCESS);
+                               }
+                               strlcpy(enc_key, optarg, sizeof(enc_key));
+                               break;
+
+                       case 'u':
+                               if (!optarg)
+                               {
+                                       PRINT_USAGE(EXIT_SUCCESS);
+                               }
+                               /* check the input limit early */
+                               if (strlen(optarg) > sizeof(username))
+                               {
+                                       fprintf(stderr, "Error: input exceeds maximum username length!\n\n");
+                                       exit(EXIT_FAILURE);
+                               }
+                               strlcpy(username, optarg, sizeof(username));
+                               break;
+
+                       default:
+                               PRINT_USAGE(EXIT_SUCCESS);
+                               break;
+               }
+       }
+
+       /* Prompt for password. */
+       if (prompt || optind >= argc)
+       {
+               char     buf[MAX_PGPASS_LEN];
+               int              len;
+
+               set_tio_attr(1);
+               printf("db password: ");
+               if (!fgets(buf, sizeof(buf), stdin))
+               {
+                       int eno = errno;
+
+                       fprintf(stderr, "Couldn't read input from stdin. (fgets(): %s)",
+                                       strerror(eno));
+
+                       exit(EXIT_FAILURE);
+               }
+               printf("\n");
+               set_tio_attr(0);
+
+               /* Remove LF at the end of line, if there is any. */
+               len = strlen(buf);
+               if (len > 0 && buf[len-1] == '\n')
+               {
+                       buf[len-1] = '\0';
+                       len--;
+               }
+               stpncpy(pg_pass,buf,sizeof(pg_pass));
+       }
+
+       /* Read password from argv. */
+       else
+       {
+               int             len;
+
+               len = strlen(argv[optind]);
+
+               if (len > MAX_PGPASS_LEN)
+               {
+                       fprintf(stderr, "Error: Input exceeds maximum password length given:%d max allowed:%d!\n\n",len,MAX_PGPASS_LEN);
+                       PRINT_USAGE(EXIT_FAILURE);
+               }
+
+               stpncpy(pg_pass,argv[optind],sizeof(pg_pass));
+       }
+       /* prompt for key, overrides all key related arguments */
+       if (prompt_for_key)
+       {
+               char    buf[MAX_POOL_KEY_LEN];
+               int     len;
+               /* we need to read the encryption key from stdin */
+               set_tio_attr(1);
+               printf("encryption key: ");
+               if (!fgets(buf, sizeof(buf), stdin))
+               {
+                       int eno = errno;
+
+                       fprintf(stderr, "Couldn't read input from stdin. (fgets(): %s)",
+                                       strerror(eno));
+
+                       exit(EXIT_FAILURE);
+               }
+               printf("\n");
+               set_tio_attr(0);
+               /* Remove LF at the end of line, if there is any. */
+               len = strlen(buf);
+               if (len > 0 && buf[len-1] == '\n')
+               {
+                       buf[len-1] = '\0';
+                       len--;
+               }
+               if (len == 0)
+               {
+                       fprintf(stderr, "encryption key not provided\n");
+                       exit(EXIT_FAILURE);
+               }
+               stpncpy(enc_key,buf,sizeof(enc_key));
+       }
+       else
+       {
+               /* check if we already have not got the key from command line argument */
+               if (strlen(enc_key) == 0)
+               {
+                       /* read from file */
+                       if (strlen(key_file_path) == 0)
+                       {
+                               get_pool_key_filename(key_file_path);
+                       }
+
+                       fprintf(stdout, "trying to read key from file %s\n",key_file_path);
+
+                       pool_key = read_pool_key(key_file_path);
+               }
+               else
+               {
+                       pool_key = enc_key;
+               }
+       }
+
+       if (pool_key == NULL)
+       {
+               fprintf(stderr, "encryption key not provided");
+               exit(EXIT_FAILURE);
+       }
+
+       if (updatepasswd)
+       {
+               update_pool_passwd(conf_file, username, pg_pass, pool_key);
+       }
+       else
+       {
+               unsigned char ciphertext[MAX_ENCODED_PASSWD_LEN];
+               unsigned char b64_enc[MAX_ENCODED_PASSWD_LEN];
+               int len;
+               int cypher_len;
+
+               cypher_len = aes_encrypt_with_password((unsigned char*)pg_pass,
+                                                                               strlen(pg_pass), pool_key, ciphertext);
+
+               /* generate the hash for the given username */
+               len = pg_b64_encode((const char*)ciphertext, cypher_len, (char*)b64_enc);
+               b64_enc[len] = 0;
+               fprintf(stdout,"\n%s\n",b64_enc);
+               fprintf(stdout,"pool_passwd string: AES%s\n",b64_enc);
+
+#ifdef DEBUG_ENCODING
+               unsigned char b64_dec[MAX_ENCODED_PASSWD_LEN];
+               unsigned char plaintext[MAX_PGPASS_LEN];
+               len = pg_b64_decode(b64_enc, len, b64_dec);
+               len = aes_decrypt_with_password(b64_dec, len,
+                                                                               pool_key, plaintext);
+               plaintext[len] = 0;
+#endif
+       }
+
+       if (pool_key != enc_key)
+               free(pool_key);
+
+       return EXIT_SUCCESS;
+}
+
+static void update_pool_passwd(char *conf_file, char *username, char *password, char *key)
+{
+       struct passwd *pw;
+       char pool_passwd[MAX_PGPASS_LEN+1];
+       char dirnamebuf[POOLMAXPATHLEN+1];
+       char *dirp;
+       char *user = username;
+
+       unsigned char ciphertext[MAX_ENCODED_PASSWD_LEN];
+       unsigned char b64_enc[MAX_ENCODED_PASSWD_LEN];
+       int len;
+
+       if (pool_init_config())
+       {
+               fprintf(stderr, "pool_init_config() failed\n\n");
+               exit(EXIT_FAILURE);
+       }
+       if (pool_get_config(conf_file, CFGCXT_RELOAD) == false)
+       {
+               fprintf(stderr, "Unable to get configuration. Exiting...");
+               exit(EXIT_FAILURE);
+       }
+
+       strlcpy(dirnamebuf, conf_file, sizeof(dirnamebuf));
+       dirp = dirname(dirnamebuf);
+       snprintf(pool_passwd, sizeof(pool_passwd), "%s/%s",
+                        dirp, pool_config->pool_passwd);
+       pool_init_pool_passwd(pool_passwd, POOL_PASSWD_RW);
+
+       if(username == NULL || strlen(username) == 0)
+       {
+               /* get the user information from the current uid */
+               pw = getpwuid(getuid());
+               if (!pw)
+               {
+                       fprintf(stderr, "getpwuid() failed\n\n");
+                       exit(EXIT_FAILURE);
+               }
+               user = pw->pw_name;
+       }
+
+       /* generate the hash for the given username */
+       int cypher_len = aes_encrypt_with_password((unsigned char*)password, strlen(password), key, ciphertext);
+       if (cypher_len <= 0 )
+       {
+               fprintf(stderr, "password encryption failed\n\n");
+               exit(EXIT_FAILURE);
+       }
+
+       /* copy the prefix at the start of string */
+       strcpy((char*)b64_enc, (char*)PASSWORD_AES_PREFIX);
+       len = pg_b64_encode((const char*)ciphertext, cypher_len, (char*)b64_enc + strlen(PASSWORD_AES_PREFIX));
+       if (cypher_len <= 0 )
+       {
+               fprintf(stderr, "base64 encoding failed\n\n");
+               exit(EXIT_FAILURE);
+       }
+       len+= strlen(PASSWORD_AES_PREFIX);
+       b64_enc[len] = 0;
+
+       pool_create_passwdent(user, (char*)b64_enc);
+       pool_finish_pool_passwd();
+}
+
+static void
+print_usage(const char prog[], int exit_code)
+{
+       char    homedir[POOLMAXPATHLEN];
+       FILE *stream = (exit_code == EXIT_SUCCESS) ? stdout : stderr;
+       if (!get_home_directory(homedir, sizeof(homedir)))
+               strncpy(homedir,"USER-HOME-DIR",POOLMAXPATHLEN);
+
+       fprintf(stream, "%s version %s (%s),\n",        PACKAGE, VERSION, PGPOOLVERSION);
+       fprintf(stream, "  password encryption utility for Pgpool\n\n");
+       fprintf(stream, "Usage:\n");
+       fprintf(stream, "  %s [OPTIONS] <PASSWORD>\n",prog);
+       fprintf(stream, "  -k, --key-file=KEY_FILE\n");
+       fprintf(stream, "                       Set the path to the encryption key file\n");
+       fprintf(stream, "                       (default: %s/%s)\n",homedir, POOLKEYFILE);
+       fprintf(stream, "                       can be over ridden by %s environment variable\n",POOLKEYFILEENV);
+       fprintf(stream, "  -K, --enc-key=ENCRYPTION_KEY\n");
+       fprintf(stream, "                       Encryption key to be used for encrypting database passwords\n");
+       fprintf(stream, "                       Specify pgpool.conf\n");
+       fprintf(stream, "  -f, --config-file=CONFIG_FILE\n");
+       fprintf(stream, "                       Encryption key to be used for encrypting database passwords\n");
+       fprintf(stream, "  -p, --prompt         Prompt for database password using standard input.\n");
+       fprintf(stream, "  -P, --prompt-for-key Prompt for encryption key using standard input.\n");
+       fprintf(stream, "  -m, --update-pass    create encrypted password entry in pool_passwd file.\n");
+       fprintf(stream, "  -u, --username       database USER for creating pool_password entry.\n");
+       fprintf(stream, "  -h, --help           Print this help\n\n");
+
+       exit(exit_code);
+}
+
+
+static void
+set_tio_attr(int set)
+{
+       struct termios tio;
+       static struct termios tio_save;
+
+
+       if (!isatty(0))
+       {
+               fprintf(stderr, "stdin is not tty\n");
+               exit(EXIT_FAILURE);
+       }
+
+       if (set)
+       {
+               if (tcgetattr(0, &tio) < 0)
+               {
+                       fprintf(stderr, "set_tio_attr(set): tcgetattr failed\n");
+                       exit(EXIT_FAILURE);
+               }
+
+               tio_save = tio;
+
+               tio.c_iflag &= ~(BRKINT|ISTRIP|IXON);
+               tio.c_lflag &= ~(ICANON|IEXTEN|ECHO|ECHOE|ECHOK|ECHONL);
+               tio.c_cc[VMIN] = 1;
+               tio.c_cc[VTIME] = 0;
+
+               if (tcsetattr(0, TCSANOW, &tio) < 0)
+               {
+                       fprintf(stderr, "(set_tio_attr(set): tcsetattr failed\n");
+                       exit(EXIT_FAILURE);
+               }
+       }
+       else
+       {
+               if (tcsetattr(0, TCSANOW, &tio_save) < 0)
+               {
+                       fprintf(stderr, "set_tio_attr(reset): tcsetattr failed\n");
+                       exit(EXIT_FAILURE);
+               }
+       }
+}
+
+static bool
+get_pool_key_filename(char *poolKeyFile)
+{
+       char    *passfile_env;
+       
+       if ((passfile_env = getenv(POOLKEYFILEENV)) != NULL)
+       {
+               /* use the literal path from the environment, if set */
+               strlcpy(poolKeyFile, passfile_env, POOLMAXPATHLEN);
+       }
+       else
+       {
+               char    homedir[POOLMAXPATHLEN];
+               if (!get_home_directory(homedir, sizeof(homedir)))
+                       return false;
+               snprintf(poolKeyFile, POOLMAXPATHLEN, "%s/%s", homedir, POOLKEYFILE);
+       }
+       return true;
+}
+
diff --git a/src/utils/ssl_utils.c b/src/utils/ssl_utils.c
new file mode 100644 (file)
index 0000000..df35655
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ * $Header$
+ *
+ * Handles watchdog connection, and protocol communication with pgpool-II
+ *
+ * pgpool: a language independent connection pool server for PostgreSQL
+ * written by Tatsuo Ishii
+ *
+ * Copyright (c) 2003-2018     PgPool 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.
+ *
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <sys/un.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <errno.h>
+
+#include "pool.h"
+#include "auth/md5.h"
+#include "utils/elog.h"
+#include "utils/palloc.h"
+#include "utils/memutils.h"
+#include "pool_config.h"
+#include "utils/ssl_utils.h"
+
+#ifdef USE_SSL
+static int aes_get_key(const char *password, unsigned char     *key, unsigned char     *iv);
+static int aes_encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key,
+                               unsigned char *iv, unsigned char *ciphertext);
+
+static int aes_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key,
+                               unsigned char *iv, unsigned char *plaintext);
+#endif
+
+#ifdef USE_SSL
+
+int aes_encrypt_with_password(unsigned char *plaintext, int plaintext_len,
+                                                 const char *password, unsigned char *ciphertext)
+{
+       unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH];
+
+       /* First get the key and iv using the password */
+       if (aes_get_key(password, key, iv) != 0)
+               return -1;
+       return aes_encrypt(plaintext, plaintext_len, key, iv, ciphertext);
+}
+
+int aes_decrypt_with_password(unsigned char *ciphertext, int ciphertext_len,
+                                                         const char *password, unsigned char *plaintext)
+{
+       unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH];
+
+       /* First get the key and iv using the password */
+       if (aes_get_key(password, key, iv) != 0)
+               return -1;
+       return aes_decrypt(ciphertext, ciphertext_len, key,
+                                          iv, plaintext);
+}
+
+/*
+ * key must be EVP_MAX_KEY_LENGTH length
+ * iv must be EVP_MAX_IV_LENGTH length
+ */
+static int aes_get_key(const char *password, unsigned char     *key, unsigned char     *iv)
+{
+       const unsigned char *salt = NULL;
+
+       OpenSSL_add_all_algorithms();
+
+       if(!EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), salt,
+                                          (unsigned char *) password,
+                                          strlen(password), 1, key, iv))
+       {
+               ereport(ERROR,
+                               (errmsg("unable to generate AES key from password"),
+                                errdetail("EVP_BytesToKey failed")));
+               return 1;
+       }
+
+#ifdef DEBUG_ENCRYPT
+       printf("Key: "); for(i=0; i<EVP_aes_256_cbc()->key_len; ++i) { printf("%02x", key[i]); } printf("\n");
+       printf("IV: "); for(i=0; i<EVP_aes_256_cbc()->iv_len; ++i) { printf("%02x", iv[i]); } printf("\n");
+#endif
+       return 0;
+}
+
+/*
+ * from: https://wiki.openssl.org/index.php/EVP_Symmetric_Encryption_and_Decryption
+ */
+static int aes_encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key,
+                       unsigned char *iv, unsigned char *ciphertext)
+{
+       EVP_CIPHER_CTX *ctx = NULL;
+       int len;
+       int ciphertext_len;
+
+       /* Create and initialise the context */
+       if(!(ctx = EVP_CIPHER_CTX_new()))
+               goto encrypt_error;
+       /* Initialise the encryption operation. IMPORTANT - ensure you use a key
+        * and IV size appropriate for your cipher
+        * In this example we are using 256 bit AES (i.e. a 256 bit key). The
+        * IV size for *most* modes is the same as the block size. For AES this
+        * is 128 bits */
+       if (EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv) != 1)
+               goto encrypt_error;
+
+       /* Provide the message to be encrypted, and obtain the encrypted output.
+        * EVP_EncryptUpdate can be called multiple times if necessary
+        */
+       if (EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len) != 1)
+               goto encrypt_error;
+       ciphertext_len = len;
+
+       /* Finalise the encryption. Further ciphertext bytes may be written at
+        * this stage.
+        */
+       if (EVP_EncryptFinal_ex(ctx, ciphertext + len, &len) != 1)
+               goto encrypt_error;
+       ciphertext_len += len;
+
+       /* Clean up */
+       EVP_CIPHER_CTX_free(ctx);
+
+       return ciphertext_len;
+
+encrypt_error:
+       if (ctx)
+               EVP_CIPHER_CTX_free(ctx);
+       return -1;
+}
+
+static int aes_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key,
+                       unsigned char *iv, unsigned char *plaintext)
+{
+       EVP_CIPHER_CTX *ctx = NULL;
+       int len;
+       int plaintext_len;
+
+       /* Create and initialise the context */
+       if(!(ctx = EVP_CIPHER_CTX_new()))
+               goto decrypt_error;
+
+       /* Initialise the decryption operation. IMPORTANT - ensure you use a key
+        * and IV size appropriate for your cipher
+        * In this example we are using 256 bit AES (i.e. a 256 bit key). The
+        * IV size for *most* modes is the same as the block size. For AES this
+        * is 128 bits */
+       if (EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv) != 1)
+               goto decrypt_error;
+
+       /* Provide the message to be decrypted, and obtain the plaintext output.
+        * EVP_DecryptUpdate can be called multiple times if necessary
+        */
+       if (EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len) != 1)
+               goto decrypt_error;
+       plaintext_len = len;
+
+       /* Finalise the decryption. Further plaintext bytes may be written at
+        * this stage.
+        */
+       if (EVP_DecryptFinal_ex(ctx, plaintext + len, &len) != 1)
+               goto decrypt_error;
+       plaintext_len += len;
+
+       /* Clean up */
+       EVP_CIPHER_CTX_free(ctx);
+
+       return plaintext_len;
+
+decrypt_error:
+       if (ctx)
+               EVP_CIPHER_CTX_free(ctx);
+       return -1;
+}
+
+/* HMAC SHA-256*/
+void calculate_hmac_sha256(const char *data, int len, char *buf)
+{
+       char* key = pool_config->wd_authkey;
+       char str[WD_AUTH_HASH_LEN/2];
+       unsigned int res_len = WD_AUTH_HASH_LEN;
+       HMAC_CTX *ctx = NULL;
+
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined (LIBRESSL_VERSION_NUMBER))
+       ctx = HMAC_CTX_new();
+       HMAC_CTX_reset(ctx);
+#else
+       HMAC_CTX ctx_obj;
+       ctx = &ctx_obj;
+       HMAC_CTX_init(ctx);
+#endif
+       HMAC_Init_ex(ctx, key, strlen(key), EVP_sha256(), NULL);
+       HMAC_Update(ctx, (unsigned char*)data, len);
+       HMAC_Final(ctx, (unsigned char*)str, &res_len);
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined (LIBRESSL_VERSION_NUMBER))
+       HMAC_CTX_reset(ctx);
+       HMAC_CTX_free(ctx);
+#else
+       HMAC_CTX_cleanup(ctx);
+#endif
+       bytesToHex(str,32,buf);
+       buf[WD_AUTH_HASH_LEN] = '\0';
+}
+
+#else
+
+int aes_decrypt_with_password(unsigned char *ciphertext, int ciphertext_len,
+                                                         const char *password, unsigned char *plaintext)
+{
+       ereport(ERROR,
+               (errmsg("AES decryption is not supported by this build"),
+                        errhint("Compile with --with-openssl to use AES.")));
+       return -1;
+}
+int aes_encrypt_with_password(unsigned char *plaintext, int plaintext_len,
+                                                         const char *password, unsigned char *ciphertext)
+{
+       ereport(ERROR,
+               (errmsg("AES encryption is not supported by this build"),
+                        errhint("Compile with --with-openssl to use AES.")));
+       return -1;
+}
+void calculate_hmac_sha256(const char *data, int len, char *buf)
+{
+       ereport(ERROR,
+                       (errmsg("HMAC SHA256 encryption is not supported by this build"),
+                        errhint("Compile with --with-openssl to use AES.")));
+}
+#endif
+
+
index b16b6974ff136bd2c8fa5d3636b162facbb6c436..24e27b6ea86f33f496de3dcf037b1eef019003b6 100644 (file)
@@ -6,7 +6,7 @@
  * pgpool: a language independent connection pool server for PostgreSQL
  * written by Tatsuo Ishii
  *
- * Copyright (c) 2003-2015     PgPool Global Development Group
+ * Copyright (c) 2003-2018     PgPool Global Development Group
  *
  * Permission to use, copy, modify, and distribute this software and
  * its documentation for any purpose and without fee is hereby
@@ -39,6 +39,7 @@
 #include "utils/memutils.h"
 #include "pool_config.h"
 #include "watchdog/wd_utils.h"
+#include "utils/ssl_utils.h"
 
 static int has_setuid_bit(char * path);
 static void *exec_func(void *arg);
@@ -146,34 +147,6 @@ has_setuid_bit(char * path)
 
 
 #ifdef USE_SSL
-/* HMAC SHA-256*/
-static void calculate_hmac_sha256(const char *data, int len, char *buf)
-{
-       char* key = pool_config->wd_authkey;
-       char str[WD_AUTH_HASH_LEN/2];
-       unsigned int res_len = WD_AUTH_HASH_LEN;
-       HMAC_CTX *ctx = NULL;
-
-#if (OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined (LIBRESSL_VERSION_NUMBER))
-       ctx = HMAC_CTX_new();
-       HMAC_CTX_reset(ctx);
-#else
-       HMAC_CTX ctx_obj;
-       ctx = &ctx_obj;
-       HMAC_CTX_init(ctx);
-#endif
-       HMAC_Init_ex(ctx, key, strlen(key), EVP_sha256(), NULL);
-       HMAC_Update(ctx, (unsigned char*)data, len);
-       HMAC_Final(ctx, (unsigned char*)str, &res_len);
-#if (OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined (LIBRESSL_VERSION_NUMBER))
-       HMAC_CTX_reset(ctx);
-       HMAC_CTX_free(ctx);
-#else
-       HMAC_CTX_cleanup(ctx);
-#endif
-       bytesToHex(str,32,buf);
-       buf[WD_AUTH_HASH_LEN] = '\0';
-}
 
 void
 wd_calc_hash(const char *str, int len, char *buf)
@@ -181,6 +154,7 @@ wd_calc_hash(const char *str, int len, char *buf)
        calculate_hmac_sha256(str, len, buf);
 }
 #else
+
 /* calculate hash for authentication using packet contents */
 void
 wd_calc_hash(const char *str, int len, char *buf)