From: Antonin Houska Date: Fri, 5 Jul 2019 16:24:02 +0200 Subject: [PATCH 15/17] Make pg_upgrade aware of encryption. 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 #include +#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