public inbox for [email protected]
help / color / mirror / Atom feedFrom: Antonin Houska <[email protected]>
Subject: [PATCH 15/17] Make pg_upgrade aware of encryption.
Date: Fri, 5 Jul 2019 16:24:02 +0200
This includes pg_resetwal utility becaue pg_upgrade calls it.
---
src/bin/pg_resetwal/Makefile | 10 +++++--
src/bin/pg_resetwal/pg_resetwal.c | 51 +++++++++++++++++++++++++++++++++--
src/bin/pg_upgrade/controldata.c | 39 +++++++++++++++++++++++++++
src/bin/pg_upgrade/dump.c | 2 +-
src/bin/pg_upgrade/exec.c | 30 +++++++++++++++++++--
src/bin/pg_upgrade/option.c | 10 ++++++-
src/bin/pg_upgrade/parallel.c | 7 ++---
src/bin/pg_upgrade/pg_upgrade.c | 57 +++++++++++++++++++++++++++++++++------
src/bin/pg_upgrade/pg_upgrade.h | 9 ++++++-
src/bin/pg_upgrade/server.c | 39 +++++++++++++++++++++++++--
src/fe_utils/encryption.c | 25 ++++++++++-------
src/include/fe_utils/encryption.h | 1 +
12 files changed, 249 insertions(+), 31 deletions(-)
diff --git a/src/bin/pg_resetwal/Makefile b/src/bin/pg_resetwal/Makefile
index 2a3835691f..faebfda27e 100644
--- a/src/bin/pg_resetwal/Makefile
+++ b/src/bin/pg_resetwal/Makefile
@@ -15,13 +15,19 @@ subdir = src/bin/pg_resetwal
top_builddir = ../../..
include $(top_builddir)/src/Makefile.global
-OBJS= pg_resetwal.o $(WIN32RES)
+override CPPFLAGS := -DFRONTEND $(CPPFLAGS)
+LDFLAGS_INTERNAL += -L$(top_builddir)/src/fe_utils -lpgfeutils $(libpq_pgport)
+
+OBJS= pg_resetwal.o encryption.o $(WIN32RES)
all: pg_resetwal
pg_resetwal: $(OBJS) | submake-libpgport
$(CC) $(CFLAGS) $^ $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
+encryption.c: % : $(top_srcdir)/src/backend/storage/file/%
+ rm -f $@ && $(LN_S) $< .
+
install: all installdirs
$(INSTALL_PROGRAM) pg_resetwal$(X) '$(DESTDIR)$(bindir)/pg_resetwal$(X)'
@@ -32,7 +38,7 @@ uninstall:
rm -f '$(DESTDIR)$(bindir)/pg_resetwal$(X)'
clean distclean maintainer-clean:
- rm -f pg_resetwal$(X) $(OBJS)
+ rm -f pg_resetwal$(X) $(OBJS) encryption.c
rm -rf tmp_check
check:
diff --git a/src/bin/pg_resetwal/pg_resetwal.c b/src/bin/pg_resetwal/pg_resetwal.c
index ff0f8ea5e7..43921132d4 100644
--- a/src/bin/pg_resetwal/pg_resetwal.c
+++ b/src/bin/pg_resetwal/pg_resetwal.c
@@ -54,11 +54,12 @@
#include "common/file_perm.h"
#include "common/logging.h"
#include "common/restricted_token.h"
+#include "fe_utils/encryption.h"
+#include "storage/encryption.h"
#include "storage/large_object.h"
#include "pg_getopt.h"
#include "getopt_long.h"
-
static ControlFileData ControlFile; /* pg_control values */
static XLogSegNo newXlogSegNo; /* new XLOG segment # */
static bool guessed = false; /* T if we had to guess at any values */
@@ -135,7 +136,7 @@ main(int argc, char *argv[])
}
- while ((c = getopt_long(argc, argv, "c:D:e:fl:m:no:O:x:", long_options, NULL)) != -1)
+ while ((c = getopt_long(argc, argv, "c:D:e:fK:l:m:no:O:x:", long_options, NULL)) != -1)
{
switch (c)
{
@@ -277,6 +278,12 @@ main(int argc, char *argv[])
}
break;
+#ifdef USE_ENCRYPTION
+ case 'K':
+ encryption_key_command = strdup(optarg);
+ break;
+#endif /* USE_ENCRYPTION */
+
case 'l':
if (strspn(optarg, "01234567890ABCDEFabcdef") != XLOG_FNAME_LEN)
{
@@ -408,6 +415,28 @@ main(int argc, char *argv[])
XLogFromFileName(log_fname, &minXlogTli, &minXlogSegNo, WalSegSz);
/*
+ * If the data is encrypted, we also might need to encrypt the XLOG record
+ * below.
+ */
+ if (ControlFile.data_cipher > PG_CIPHER_NONE && !noupdate)
+ {
+ if (encryption_key_command)
+ run_encryption_key_command(encryption_key, DataDir);
+ else
+ {
+ /*
+ * If executed by pg_upgrade, we don't want pg_resetwal to run the
+ * encryption key command (possibly interactive application) w/o
+ * access to terminal.
+ */
+ read_encryption_key_fe(stdin);
+ }
+
+ setup_encryption();
+ data_encrypted = true;
+ }
+
+ /*
* Also look at existing segment files to set up newXlogSegNo
*/
FindEndOfXLOG();
@@ -814,6 +843,12 @@ PrintControlValues(bool guessed)
(ControlFile.float8ByVal ? _("by value") : _("by reference")));
printf(_("Data page checksum version: %u\n"),
ControlFile.data_checksum_version);
+ if (ControlFile.data_cipher > PG_CIPHER_NONE)
+ printf(_("Data encryption fingerprint: %08X%08X%08X%08X\n"),
+ htonl(((uint32 *) ControlFile.encryption_verification)[0]),
+ htonl(((uint32 *) ControlFile.encryption_verification)[1]),
+ htonl(((uint32 *) ControlFile.encryption_verification)[2]),
+ htonl(((uint32 *) ControlFile.encryption_verification)[3]));
}
@@ -1164,6 +1199,14 @@ WriteEmptyXLOG(void)
FIN_CRC32C(crc);
record->xl_crc = crc;
+ if (data_encrypted)
+ {
+ char tweak[TWEAK_SIZE];
+
+ XLogEncryptionTweak(tweak, page->xlp_tli, newXlogSegNo, 0);
+ encrypt_block(buffer.data, buffer.data, XLOG_BLCKSZ, tweak, true);
+ }
+
/* Write the first page */
XLogFilePath(path, ControlFile.checkPointCopy.ThisTimeLineID,
newXlogSegNo, WalSegSz);
@@ -1224,6 +1267,10 @@ usage(void)
printf(_(" [-D, --pgdata=]DATADIR data directory\n"));
printf(_(" -e, --epoch=XIDEPOCH set next transaction ID epoch\n"));
printf(_(" -f, --force force update to be done\n"));
+#ifdef USE_ENCRYPTION
+ printf(_(" -K, --encryption-key-command\n"
+ " command that returns encryption key\n"));
+#endif /* USE_ENCRYPTION */
printf(_(" -l, --next-wal-file=WALFILE set minimum starting location for new WAL\n"));
printf(_(" -m, --multixact-ids=MXID,MXID set next and oldest multitransaction ID\n"));
printf(_(" -n, --dry-run no update, just show what would be done\n"));
diff --git a/src/bin/pg_upgrade/controldata.c b/src/bin/pg_upgrade/controldata.c
index 38236415be..dc15b979bc 100644
--- a/src/bin/pg_upgrade/controldata.c
+++ b/src/bin/pg_upgrade/controldata.c
@@ -485,6 +485,33 @@ get_control_data(ClusterInfo *cluster, bool live_check)
cluster->controldata.data_checksum_version = str2uint(p);
got_data_checksum_version = true;
}
+ else if ((p = strstr(bufin, "encryption fingerprint")) != NULL)
+ {
+ int i;
+
+ p = strchr(p, ':');
+
+ if (p == NULL || strlen(p) <= 1)
+ pg_fatal("%d: controldata retrieval problem\n", __LINE__);
+
+ cluster->controldata.data_encrypted = true;
+
+ /* Skip the colon and any whitespace after it */
+ p = strchr(p, ':');
+ if (p == NULL || strlen(p) <= 1)
+ pg_fatal("%d: controldata retrieval problem\n", __LINE__);
+ p = strpbrk(p, "01234567890ABCDEF");
+ if (p == NULL || strlen(p) <= 1)
+ pg_fatal("%d: controldata retrieval problem\n", __LINE__);
+
+ /* Make sure it looks like a valid finerprint */
+ if (strspn(p, "0123456789ABCDEF") != 32)
+ pg_fatal("%d: controldata retrieval problem\n", __LINE__);
+
+ for (i = 0; i < ENCRYPTION_SAMPLE_SIZE; i++)
+ sscanf(p + 2 * i, "%2hhx",
+ cluster->controldata.encryption_verification + i);
+ }
}
pclose(output);
@@ -669,6 +696,18 @@ check_control_data(ControlData *oldctrl,
pg_fatal("old cluster uses data checksums but the new one does not\n");
else if (oldctrl->data_checksum_version != newctrl->data_checksum_version)
pg_fatal("old and new cluster pg_controldata checksum versions do not match\n");
+
+ if (oldctrl->data_encrypted && !newctrl->data_encrypted)
+ pg_fatal("old cluster is encrypted, but the new one is not\n");
+ else if (!oldctrl->data_encrypted && newctrl->data_encrypted)
+ pg_fatal("old cluster is not encrypted, but the new one is\n");
+ else if (oldctrl->data_encrypted)
+ {
+ if (memcmp(oldctrl->encryption_verification,
+ newctrl->encryption_verification,
+ ENCRYPTION_SAMPLE_SIZE) != 0)
+ pg_fatal("encryption of the new cluster is not compatible with encryption of the old one\n");
+ }
}
diff --git a/src/bin/pg_upgrade/dump.c b/src/bin/pg_upgrade/dump.c
index c1429fe4bf..6fcf9126a4 100644
--- a/src/bin/pg_upgrade/dump.c
+++ b/src/bin/pg_upgrade/dump.c
@@ -22,7 +22,7 @@ generate_old_dump(void)
prep_status("Creating dump of global objects");
/* run new pg_dumpall binary for globals */
- exec_prog(UTILITY_LOG_FILE, NULL, true, true,
+ exec_prog(UTILITY_LOG_FILE, NULL, true, true, NULL,
"\"%s/pg_dumpall\" %s --globals-only --quote-all-identifiers "
"--binary-upgrade %s -f %s",
new_cluster.bindir, cluster_conn_opts(&old_cluster),
diff --git a/src/bin/pg_upgrade/exec.c b/src/bin/pg_upgrade/exec.c
index 0363309328..cd6c68bdd9 100644
--- a/src/bin/pg_upgrade/exec.c
+++ b/src/bin/pg_upgrade/exec.c
@@ -74,11 +74,17 @@ get_bin_version(ClusterInfo *cluster)
* If the command fails, an error message is optionally written to the specified
* log_file, and the program optionally exits.
*
+ * If encryption_key is passed, popen() is used and the key is sent to stdin
+ * of the command.
+ *
* The code requires it be called first from the primary thread on Windows.
+ *
+ * TODO Consolidate the use of popen() with Windows. Or use only popen()?
*/
bool
exec_prog(const char *log_file, const char *opt_log_file,
- bool report_error, bool exit_on_error, const char *fmt,...)
+ bool report_error, bool exit_on_error, unsigned char *encryption_key,
+ const char *fmt,...)
{
int result = 0;
int written;
@@ -170,7 +176,27 @@ exec_prog(const char *log_file, const char *opt_log_file,
/* see comment above */
if (mainThreadId == GetCurrentThreadId())
#endif
- result = system(cmd);
+ {
+ if (!encryption_key)
+ result = system(cmd);
+ else
+ {
+ FILE *fp;
+ int i;
+
+ fp = popen(cmd, "w");
+ if (fp == NULL)
+ pg_fatal("Failed to execute \"%s\"\n", cmd);
+
+ /* Send the key. */
+ for (i = 0; i < ENCRYPTION_KEY_LENGTH; i++)
+ fprintf(fp, "%.2x", encryption_key[i]);
+ fputc('\n', fp);
+
+ if (pclose(fp))
+ pg_fatal("\"%s\" returned non-zero code\n", cmd);
+ }
+ }
if (result != 0 && report_error)
{
diff --git a/src/bin/pg_upgrade/option.c b/src/bin/pg_upgrade/option.c
index 73f395f2a3..e2bb0e7c8e 100644
--- a/src/bin/pg_upgrade/option.c
+++ b/src/bin/pg_upgrade/option.c
@@ -56,6 +56,7 @@ parseCommandLine(int argc, char *argv[])
{"socketdir", required_argument, NULL, 's'},
{"verbose", no_argument, NULL, 'v'},
{"clone", no_argument, NULL, 1},
+ {"encryption-key-command", required_argument, NULL, 'K'},
{NULL, 0, NULL, 0}
};
@@ -101,7 +102,7 @@ parseCommandLine(int argc, char *argv[])
if (os_user_effective_id == 0)
pg_fatal("%s: cannot be run as root\n", os_info.progname);
- while ((option = getopt_long(argc, argv, "d:D:b:B:cj:ko:O:p:P:rs:U:v",
+ while ((option = getopt_long(argc, argv, "d:D:b:B:cj:K:ko:O:p:P:rs:U:v",
long_options, &optindex)) != -1)
{
switch (option)
@@ -209,6 +210,10 @@ parseCommandLine(int argc, char *argv[])
user_opts.transfer_mode = TRANSFER_MODE_CLONE;
break;
+ case 'K':
+ encryption_key_command = pg_strdup(optarg);
+ break;
+
default:
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
os_info.progname);
@@ -309,6 +314,9 @@ usage(void)
printf(_(" -v, --verbose enable verbose internal logging\n"));
printf(_(" -V, --version display version information, then exit\n"));
printf(_(" --clone clone instead of copying files to new cluster\n"));
+#ifdef USE_ENCRYPTION
+ printf(_(" -K, --encryption-key-command command that returns encryption key\n\n"));
+#endif /* USE_ENCRYPTION */
printf(_(" -?, --help show this help, then exit\n"));
printf(_("\n"
"Before running pg_upgrade you must:\n"
diff --git a/src/bin/pg_upgrade/parallel.c b/src/bin/pg_upgrade/parallel.c
index 80ab1b8609..be3fd51f15 100644
--- a/src/bin/pg_upgrade/parallel.c
+++ b/src/bin/pg_upgrade/parallel.c
@@ -79,7 +79,7 @@ parallel_exec_prog(const char *log_file, const char *opt_log_file,
if (user_opts.jobs <= 1)
/* exit_on_error must be true to allow jobs */
- exec_prog(log_file, opt_log_file, true, true, "%s", cmd);
+ exec_prog(log_file, opt_log_file, true, true, NULL, "%s", cmd);
else
{
/* parallel */
@@ -122,7 +122,8 @@ parallel_exec_prog(const char *log_file, const char *opt_log_file,
child = fork();
if (child == 0)
/* use _exit to skip atexit() functions */
- _exit(!exec_prog(log_file, opt_log_file, true, true, "%s", cmd));
+ _exit(!exec_prog(log_file, opt_log_file, true, true, NULL, "%s",
+ cmd));
else if (child < 0)
/* fork failed */
pg_fatal("could not create worker process: %s\n", strerror(errno));
@@ -160,7 +161,7 @@ win32_exec_prog(exec_thread_arg *args)
{
int ret;
- ret = !exec_prog(args->log_file, args->opt_log_file, true, true, "%s", args->cmd);
+ ret = !exec_prog(args->log_file, args->opt_log_file, true, true, NULL, "%s", args->cmd);
/* terminates thread */
return ret;
diff --git a/src/bin/pg_upgrade/pg_upgrade.c b/src/bin/pg_upgrade/pg_upgrade.c
index 336df7378f..c464f90cf9 100644
--- a/src/bin/pg_upgrade/pg_upgrade.c
+++ b/src/bin/pg_upgrade/pg_upgrade.c
@@ -73,6 +73,12 @@ char *output_files[] = {
NULL
};
+/*
+ * Declare these locally so we don't have to link storage/file/encryption.c
+ * here.
+ */
+bool encryption_setup_done = false;
+unsigned char encryption_key[ENCRYPTION_KEY_LENGTH];
int
main(int argc, char **argv)
@@ -94,6 +100,20 @@ main(int argc, char **argv)
adjust_data_dir(&old_cluster);
adjust_data_dir(&new_cluster);
+ /*
+ * The encryption key is needed to start the clusters.
+ */
+ if (encryption_key_command)
+ {
+ /*
+ * Both clusters should have the same KDF parameters, so we can pass
+ * pgdata of any one.
+ */
+ run_encryption_key_command(encryption_key, old_cluster.pgdata);
+
+ encryption_setup_done = true;
+ }
+
setup(argv[0], &live_check);
output_check_banner(live_check);
@@ -139,6 +159,16 @@ main(int argc, char **argv)
copy_xact_xlog_xid();
+ if (encryption_setup_done)
+ {
+ /*
+ * Copy KDF file so that the old cluster encryption password works for
+ * the new cluster.
+ */
+ read_kdf_file(old_cluster.pgdata);
+ write_kdf_file(new_cluster.pgdata);
+ }
+
/* New now using xids of the old system */
/* -- NEW -- */
@@ -170,13 +200,15 @@ main(int argc, char **argv)
*/
prep_status("Setting next OID for new cluster");
exec_prog(UTILITY_LOG_FILE, NULL, true, true,
+ encryption_setup_done ? encryption_key : NULL,
"\"%s/pg_resetwal\" -o %u \"%s\"",
- new_cluster.bindir, old_cluster.controldata.chkpnt_nxtoid,
+ new_cluster.bindir,
+ old_cluster.controldata.chkpnt_nxtoid,
new_cluster.pgdata);
check_ok();
prep_status("Sync data directory to disk");
- exec_prog(UTILITY_LOG_FILE, NULL, true, true,
+ exec_prog(UTILITY_LOG_FILE, NULL, true, true, NULL,
"\"%s/initdb\" --sync-only \"%s\"", new_cluster.bindir,
new_cluster.pgdata);
check_ok();
@@ -270,7 +302,7 @@ prepare_new_cluster(void)
* --analyze so autovacuum doesn't update statistics later
*/
prep_status("Analyzing all rows in the new cluster");
- exec_prog(UTILITY_LOG_FILE, NULL, true, true,
+ exec_prog(UTILITY_LOG_FILE, NULL, true, true, NULL,
"\"%s/vacuumdb\" %s --all --analyze %s",
new_cluster.bindir, cluster_conn_opts(&new_cluster),
log_opts.verbose ? "--verbose" : "");
@@ -283,7 +315,7 @@ prepare_new_cluster(void)
* counter later.
*/
prep_status("Freezing all rows in the new cluster");
- exec_prog(UTILITY_LOG_FILE, NULL, true, true,
+ exec_prog(UTILITY_LOG_FILE, NULL, true, true, NULL,
"\"%s/vacuumdb\" %s --all --freeze %s",
new_cluster.bindir, cluster_conn_opts(&new_cluster),
log_opts.verbose ? "--verbose" : "");
@@ -304,7 +336,7 @@ prepare_new_globals(void)
*/
prep_status("Restoring global objects in the new cluster");
- exec_prog(UTILITY_LOG_FILE, NULL, true, true,
+ exec_prog(UTILITY_LOG_FILE, NULL, true, true, NULL,
"\"%s/psql\" " EXEC_PSQL_ARGS " %s -f \"%s\"",
new_cluster.bindir, cluster_conn_opts(&new_cluster),
GLOBALS_DUMP_FILE);
@@ -351,6 +383,7 @@ create_new_objects(void)
NULL,
true,
true,
+ NULL,
"\"%s/pg_restore\" %s %s --exit-on-error --verbose "
"--dbname postgres \"%s\"",
new_cluster.bindir,
@@ -448,7 +481,7 @@ copy_subdir_files(const char *old_subdir, const char *new_subdir)
prep_status("Copying old %s to new server", old_subdir);
- exec_prog(UTILITY_LOG_FILE, NULL, true, true,
+ exec_prog(UTILITY_LOG_FILE, NULL, true, true, NULL,
#ifndef WIN32
"cp -Rf \"%s\" \"%s\"",
#else
@@ -475,15 +508,20 @@ copy_xact_xlog_xid(void)
/* set the next transaction id and epoch of the new cluster */
prep_status("Setting next transaction ID and epoch for new cluster");
exec_prog(UTILITY_LOG_FILE, NULL, true, true,
+ encryption_setup_done ? encryption_key : NULL,
"\"%s/pg_resetwal\" -f -x %u \"%s\"",
- new_cluster.bindir, old_cluster.controldata.chkpnt_nxtxid,
+ new_cluster.bindir,
+ old_cluster.controldata.chkpnt_nxtxid,
new_cluster.pgdata);
exec_prog(UTILITY_LOG_FILE, NULL, true, true,
+ encryption_setup_done ? encryption_key : NULL,
"\"%s/pg_resetwal\" -f -e %u \"%s\"",
- new_cluster.bindir, old_cluster.controldata.chkpnt_nxtepoch,
+ new_cluster.bindir,
+ old_cluster.controldata.chkpnt_nxtepoch,
new_cluster.pgdata);
/* must reset commit timestamp limits also */
exec_prog(UTILITY_LOG_FILE, NULL, true, true,
+ encryption_setup_done ? encryption_key : NULL,
"\"%s/pg_resetwal\" -f -c %u,%u \"%s\"",
new_cluster.bindir,
old_cluster.controldata.chkpnt_nxtxid,
@@ -510,6 +548,7 @@ copy_xact_xlog_xid(void)
* counters here and the oldest multi present on system.
*/
exec_prog(UTILITY_LOG_FILE, NULL, true, true,
+ encryption_setup_done ? encryption_key : NULL,
"\"%s/pg_resetwal\" -O %u -m %u,%u \"%s\"",
new_cluster.bindir,
old_cluster.controldata.chkpnt_nxtmxoff,
@@ -538,6 +577,7 @@ copy_xact_xlog_xid(void)
* next=MaxMultiXactId, but multixact.c can cope with that just fine.
*/
exec_prog(UTILITY_LOG_FILE, NULL, true, true,
+ encryption_setup_done ? encryption_key : NULL,
"\"%s/pg_resetwal\" -m %u,%u \"%s\"",
new_cluster.bindir,
old_cluster.controldata.chkpnt_nxtmulti + 1,
@@ -549,6 +589,7 @@ copy_xact_xlog_xid(void)
/* now reset the wal archives in the new cluster */
prep_status("Resetting WAL archives");
exec_prog(UTILITY_LOG_FILE, NULL, true, true,
+ encryption_setup_done ? encryption_key : NULL,
/* use timeline 1 to match controldata and no WAL history file */
"\"%s/pg_resetwal\" -l 00000001%s \"%s\"", new_cluster.bindir,
old_cluster.controldata.nextxlogfile + 8,
diff --git a/src/bin/pg_upgrade/pg_upgrade.h b/src/bin/pg_upgrade/pg_upgrade.h
index 5d31750d86..e89f6c08a0 100644
--- a/src/bin/pg_upgrade/pg_upgrade.h
+++ b/src/bin/pg_upgrade/pg_upgrade.h
@@ -10,7 +10,10 @@
#include <sys/stat.h>
#include <sys/time.h>
+#include "fe_utils/encryption.h"
#include "libpq-fe.h"
+#include "storage/relfilenode.h"
+#include "storage/encryption.h"
/* Use port in the private/dynamic port number range */
#define DEF_PGUPORT 50432
@@ -227,6 +230,8 @@ typedef struct
bool date_is_int;
bool float8_pass_by_value;
bool data_checksum_version;
+ bool data_encrypted;
+ uint8 encryption_verification[ENCRYPTION_SAMPLE_SIZE];
} ControlData;
/*
@@ -367,7 +372,9 @@ void generate_old_dump(void);
#define EXEC_PSQL_ARGS "--echo-queries --set ON_ERROR_STOP=on --no-psqlrc --dbname=template1"
bool exec_prog(const char *log_file, const char *opt_log_file,
- bool report_error, bool exit_on_error, const char *fmt,...) pg_attribute_printf(5, 6);
+ bool report_error, bool exit_on_error,
+ unsigned char *encryption_key, const char *fmt,...)
+ pg_attribute_printf(6, 7);
void verify_directories(void);
bool pid_lock_file_exists(const char *datadir);
diff --git a/src/bin/pg_upgrade/server.c b/src/bin/pg_upgrade/server.c
index 6ad4b14e16..93cb518cc5 100644
--- a/src/bin/pg_upgrade/server.c
+++ b/src/bin/pg_upgrade/server.c
@@ -252,6 +252,41 @@ start_postmaster(ClusterInfo *cluster, bool report_and_exit_on_error)
cluster->pgopts ? cluster->pgopts : "", socket_string);
/*
+ * If encryption key needs to be sent, run a separate process now and let
+ * it send the password to the postmaster. We cannot send the key later
+ * in the current process because the exec_prog call below blocks until
+ * the postmaster succeeds or fails to start (and it will definitely fail
+ * if it receives no key).
+ */
+ if (encryption_setup_done)
+ {
+#ifndef WIN32
+ pid_t sender;
+
+ sender = fork();
+ if (sender == 0)
+ {
+ char port_str[6];
+
+ snprintf(port_str, sizeof(port_str), "%d", cluster->port);
+
+ /* in child process */
+ send_key_to_postmaster(cluster->sockdir, port_str,
+ encryption_key);
+ exit(EXIT_SUCCESS);
+ }
+ else if (sender < 0)
+ {
+ pg_fatal("could not create key sender process");
+ exit(EXIT_FAILURE);
+ }
+#else
+ /* TODO */
+ #error "W32 not implemented yet"
+#endif
+ }
+
+ /*
* Don't throw an error right away, let connecting throw the error because
* it might supply a reason for the failure.
*/
@@ -260,7 +295,7 @@ start_postmaster(ClusterInfo *cluster, bool report_and_exit_on_error)
(strcmp(SERVER_LOG_FILE,
SERVER_START_LOG_FILE) != 0) ?
SERVER_LOG_FILE : NULL,
- report_and_exit_on_error, false,
+ report_and_exit_on_error, false, NULL,
"%s", cmd);
/* Did it fail and we are just testing if the server could be started? */
@@ -336,7 +371,7 @@ stop_postmaster(bool in_atexit)
else
return; /* no cluster running */
- exec_prog(SERVER_STOP_LOG_FILE, NULL, !in_atexit, !in_atexit,
+ exec_prog(SERVER_STOP_LOG_FILE, NULL, !in_atexit, !in_atexit, NULL,
"\"%s/pg_ctl\" -w -D \"%s\" -o \"%s\" %s stop",
cluster->bindir, cluster->pgconfig,
cluster->pgopts ? cluster->pgopts : "",
diff --git a/src/fe_utils/encryption.c b/src/fe_utils/encryption.c
index 134b3bde9b..2b4a6fadad 100644
--- a/src/fe_utils/encryption.c
+++ b/src/fe_utils/encryption.c
@@ -259,8 +259,6 @@ run_encryption_key_command(unsigned char *encryption_key, char *data_dir)
FILE *fp;
char cmd[MAXPGPATH];
char *sp, *dp, *endp;
- char *buf;
- int read_len, i, c;
Assert(encryption_key_command != NULL &&
strlen(encryption_key_command) > 0);
@@ -312,15 +310,25 @@ run_encryption_key_command(unsigned char *encryption_key, char *data_dir)
exit(EXIT_FAILURE);
}
+ /* Read the key. */
+ read_encryption_key_fe(fp);
+
+ pclose(fp);
+}
+
+/*
+ * Frontend counterpart of read_encryption_key().
+ */
+void
+read_encryption_key_fe(FILE *f)
+{
+ char *buf;
+ int read_len, i, c;
+
buf = (char *) palloc(ENCRYPTION_KEY_CHARS);
- /*
- * Read the key. This is very similar to backend's read_encryption_key()
- * but there seems to be no straightforward way to call the function from
- * here.
- */
read_len = 0;
- while ((c = fgetc(fp)) != EOF && c != '\n')
+ while ((c = fgetc(f)) != EOF && c != '\n')
{
if (read_len >= ENCRYPTION_KEY_CHARS)
{
@@ -349,7 +357,6 @@ run_encryption_key_command(unsigned char *encryption_key, char *data_dir)
}
pfree(buf);
- pclose(fp);
}
/*
diff --git a/src/include/fe_utils/encryption.h b/src/include/fe_utils/encryption.h
index da302fe494..2c6032df07 100644
--- a/src/include/fe_utils/encryption.h
+++ b/src/include/fe_utils/encryption.h
@@ -22,5 +22,6 @@ extern void derive_key_from_password(unsigned char *encryption_key,
const char *password, int len);
extern void run_encryption_key_command(unsigned char *encryption_key,
char *data_dir);
+extern void read_encryption_key_fe(FILE *f);
extern bool send_key_to_postmaster(const char *host, const char *port,
const unsigned char *encryption_Key);
--
2.13.7
--=-=-=
Content-Type: text/x-diff
Content-Disposition: attachment;
filename=v04-0016-Teach-the-remaining-frontend-application-about-encry.patch
view thread (3+ messages) latest in thread
reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: [email protected]
Cc: [email protected]
Subject: Re: [PATCH 15/17] Make pg_upgrade aware of encryption.
In-Reply-To: <no-message-id-1881971@localhost>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox