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.
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
"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" ;;
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])
utils/scram-common.c \
utils/base64.c \
utils/sha2.c \
+ utils/ssl_utils.c \
utils/statistics.c
DEFS = @DEFS@ \
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
utils/scram-common.c \
utils/base64.c \
utils/sha2.c \
+ utils/ssl_utils.c \
utils/statistics.c
sysconf_DATA = sample/pgpool.conf.sample \
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)
}
}
/* 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"),
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
*/
}
}
}
+ /*
+ * 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++)
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);
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
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,
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;
}
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 */
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,
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
{
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)
errdetail("password does not match")));
}
ereport(LOG,
- (errmsg("md5 authentication successfull with frontend")));
+ (errmsg("md5 authentication successful with frontend")));
frontend->frontend_authenticated = true;
}
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,
/* Save the auth info */
backend->auth_kind = AUTH_REQ_MD5;
}
+
+ if (password_decrypted && storedPassword)
+ pfree(storedPassword);
+
return 0;
}
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"),
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"),
* 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];
(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)));
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
+}
#ifndef MD5_H
#define MD5_H
-#define MAX_USER_NAME_LEN 128
#define MD5_PASSWD_LEN 32
#define WD_AUTH_HASH_LEN 64
#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 */
PASSWORD_TYPE_UNKNOWN = 0,
PASSWORD_TYPE_PLAINTEXT,
PASSWORD_TYPE_MD5,
+ PASSWORD_TYPE_AES,
PASSWORD_TYPE_SCRAM_SHA_256
} PasswordType;
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 */
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 */
#define POOLMAXPATHLEN 8192
+#define POOLKEYFILE ".pgpoolkey"
+#define POOLKEYFILEENV "PGPOOLKEYFILE"
+
/*
* Brought from PostgreSQL's pg_config_manual.h.
*
/* 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);
--- /dev/null
+/* -*-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
* 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
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);
* 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
#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);
int myargc;
char **myargv;
int assert_enabled = 0;
-
+char *pool_key = NULL;
int main(int argc, char **argv)
{
int opt;
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'},
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)
{
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);
/* 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
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");
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);
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
*/
-SUBDIRS = pcp pgmd5
+SUBDIRS = pcp pgmd5 pgenc
dist_bin_SCRIPTS = pgpool_setup watchdog_setup
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
--- /dev/null
+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)
--- /dev/null
+# 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:
--- /dev/null
+/* -*-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;
+}
+
--- /dev/null
+/*
+ * $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
+
+
* 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 "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);
#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)
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)