From 85cbe762e5c7a74d0e3e02aa40ff9142e79b668e Mon Sep 17 00:00:00 2001
From: Bruce Momjian <bruce@momjian.us>
Date: Fri, 25 Jun 2021 16:56:53 -0400
Subject: [PATCH v2 06/12] cfe-06-backend_over_cfe-05-crypto squash commit

---
 doc/src/sgml/storage.sgml                     |  5 +++
 src/backend/Makefile                          |  2 +-
 src/backend/access/transam/xlog.c             | 33 +++++++++++++++++++
 src/backend/backup/basebackup.c               |  5 +++
 src/backend/bootstrap/bootstrap.c             | 29 +++++++++++++++-
 src/backend/crypto/kmgr.c                     |  3 ++
 src/backend/libpq/be-secure-common.c          | 14 ++++++++
 src/backend/main/main.c                       |  3 ++
 src/backend/postmaster/postmaster.c           | 13 +++++++-
 src/backend/storage/ipc/ipci.c                |  3 ++
 src/backend/storage/lmgr/lwlocknames.txt      |  1 +
 src/backend/tcop/postgres.c                   | 28 +++++++++++++++-
 src/backend/utils/activity/wait_event.c       |  9 +++++
 src/backend/utils/misc/guc_tables.c           | 25 ++++++++++++++
 src/backend/utils/misc/pg_controldata.c       | 11 +++++--
 src/backend/utils/misc/postgresql.conf.sample |  5 +++
 src/include/access/xlog.h                     |  5 +++
 src/include/catalog/pg_control.h              |  5 ++-
 src/include/catalog/pg_proc.dat               |  6 ++--
 src/include/postmaster/postmaster.h           |  2 ++
 src/include/utils/guc_tables.h                |  1 +
 21 files changed, 197 insertions(+), 11 deletions(-)

diff --git a/doc/src/sgml/storage.sgml b/doc/src/sgml/storage.sgml
index e5b9f3f1ff..f9dbf04735 100644
--- a/doc/src/sgml/storage.sgml
+++ b/doc/src/sgml/storage.sgml
@@ -77,6 +77,11 @@ Item
  <entry>Subdirectory containing transaction commit timestamp data</entry>
 </row>
 
+<row>
+ <entry><filename>pg_cryptokeys</filename></entry>
+ <entry>Subdirectory containing file encryption keys</entry>
+</row>
+
 <row>
  <entry><filename>pg_dynshmem</filename></entry>
  <entry>Subdirectory containing files used by the dynamic shared memory
diff --git a/src/backend/Makefile b/src/backend/Makefile
index 1a5239b822..4b8cdd1b44 100644
--- a/src/backend/Makefile
+++ b/src/backend/Makefile
@@ -22,7 +22,7 @@ SUBDIRS = access backup bootstrap catalog parser commands executor \
 	main nodes optimizer partitioning port postmaster \
 	regex replication rewrite \
 	statistics storage tcop tsearch utils $(top_builddir)/src/timezone \
-	jit
+	jit crypto
 
 include $(srcdir)/common.mk
 
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index be54c23187..e247376ead 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -69,6 +69,7 @@
 #include "catalog/pg_database.h"
 #include "common/controldata_utils.h"
 #include "common/file_utils.h"
+#include "crypto/kmgr.h"
 #include "executor/instrument.h"
 #include "miscadmin.h"
 #include "pg_trace.h"
@@ -76,6 +77,7 @@
 #include "port/atomics.h"
 #include "port/pg_iovec.h"
 #include "postmaster/bgwriter.h"
+#include "postmaster/postmaster.h"
 #include "postmaster/startup.h"
 #include "postmaster/walwriter.h"
 #include "replication/logical.h"
@@ -109,6 +111,7 @@
 #include "utils/varlena.h"
 
 extern uint32 bootstrap_data_checksum_version;
+extern int bootstrap_file_encryption_method;
 
 /* timeline ID to be used when bootstrapping */
 #define BootstrapTimeLineID		1
@@ -3898,6 +3901,7 @@ InitControlFile(uint64 sysidentifier)
 	ControlFile->wal_log_hints = wal_log_hints;
 	ControlFile->track_commit_timestamp = track_commit_timestamp;
 	ControlFile->data_checksum_version = bootstrap_data_checksum_version;
+	ControlFile->file_encryption_method = bootstrap_file_encryption_method;
 }
 
 static void
@@ -4185,6 +4189,12 @@ ReadControlFile(void)
 	/* Make the initdb settings visible as GUC variables, too */
 	SetConfigOption("data_checksums", DataChecksumsEnabled() ? "yes" : "no",
 					PGC_INTERNAL, PGC_S_DYNAMIC_DEFAULT);
+ 
+ 	StaticAssertStmt(lengthof(encryption_methods) == NUM_ENCRYPTION_METHODS,
+ 							 "encryption_methods[] must match NUM_ENCRYPTION_METHODS");
+ 	SetConfigOption("file_encryption_method",
+ 					encryption_methods[ControlFile->file_encryption_method].name,
+ 					PGC_INTERNAL, PGC_S_OVERRIDE);
 }
 
 /*
@@ -4227,6 +4237,21 @@ DataChecksumsEnabled(void)
 	return (ControlFile->data_checksum_version > 0);
 }
 
+/*
+ * Is cluster file encryption enabled?
+ */
+int
+GetFileEncryptionMethod(void)
+{
+	if (IsBootstrapProcessingMode())
+		return bootstrap_file_encryption_method;
+	else
+	{
+		Assert(ControlFile != NULL);
+		return ControlFile->file_encryption_method;
+	}
+}
+
 /*
  * Returns a fake LSN for unlogged relations.
  *
@@ -4806,6 +4831,14 @@ BootStrapXLOG(void)
 	/* some additional ControlFile fields are set in WriteControlFile() */
 	WriteControlFile();
 
+	BootStrapKmgr();
+
+	if (terminal_fd != -1)
+	{
+		close(terminal_fd);
+		terminal_fd = -1;
+	}
+
 	/* Bootstrap the commit log, too */
 	BootStrapCLOG();
 	BootStrapCommitTs();
diff --git a/src/backend/backup/basebackup.c b/src/backend/backup/basebackup.c
index 74fb529380..35e955e036 100644
--- a/src/backend/backup/basebackup.c
+++ b/src/backend/backup/basebackup.c
@@ -24,6 +24,7 @@
 #include "backup/basebackup_target.h"
 #include "commands/defrem.h"
 #include "common/compression.h"
+#include "common/kmgr_utils.h"
 #include "common/file_perm.h"
 #include "lib/stringinfo.h"
 #include "miscadmin.h"
@@ -129,6 +130,10 @@ struct exclude_list_item
  */
 static const char *const excludeDirContents[] =
 {
+	/* Skip temporary crypto key directories */
+	NEW_KMGR_DIR,
+	OLD_KMGR_DIR,
+
 	/*
 	 * Skip temporary statistics files. PG_STAT_TMP_DIR must be skipped
 	 * because extensions like pg_stat_statements store data there.
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index 661ebacb0c..87918a4d28 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -33,6 +33,7 @@
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "pg_getopt.h"
+#include "postmaster/postmaster.h" /* TODO: verify we need this still */
 #include "storage/bufmgr.h"
 #include "storage/bufpage.h"
 #include "storage/condition_variable.h"
@@ -46,6 +47,8 @@
 #include "utils/relmapper.h"
 
 uint32		bootstrap_data_checksum_version = 0;	/* No checksum */
+int			bootstrap_file_encryption_method = DISABLED_ENCRYPTION_METHOD;
+char		*bootstrap_old_key_datadir = NULL;	/* disabled */
 
 
 static void CheckerModeMain(void);
@@ -221,7 +224,7 @@ BootstrapModeMain(int argc, char *argv[], bool check_only)
 	argv++;
 	argc--;
 
-	while ((flag = getopt(argc, argv, "B:c:d:D:Fkr:X:-:")) != -1)
+ 	while ((flag = getopt(argc, argv, "B:c:d:D:FkK:r:R:u:X:-:")) != -1)
 	{
 		switch (flag)
 		{
@@ -250,9 +253,33 @@ BootstrapModeMain(int argc, char *argv[], bool check_only)
 			case 'k':
 				bootstrap_data_checksum_version = PG_DATA_CHECKSUM_VERSION;
 				break;
+ 			case 'K':
+ 				{
+ 					int i;
+ 
+ 					/* method 0/disabled cannot be specified */
+ 					for (i = DISABLED_ENCRYPTION_METHOD + 1;
+ 						 i < NUM_ENCRYPTION_METHODS; i++)
+ 						if (pg_strcasecmp(optarg, encryption_methods[i].name) == 0)
+ 						{
+ 							bootstrap_file_encryption_method = i;
+ 							break;
+ 						}
+ 					if (i == NUM_ENCRYPTION_METHODS)
+ 						ereport(ERROR,
+ 								(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ 								 errmsg("invalid encryption method specified")));
+ 				}
+ 				break;
 			case 'r':
 				strlcpy(OutputFileName, optarg, MAXPGPATH);
 				break;
+ 			case 'R':
+ 				terminal_fd = atoi(optarg);
+ 				break;
+ 			case 'u':
+ 				bootstrap_old_key_datadir = pstrdup(optarg);
+ 				break;
 			case 'X':
 				{
 					int			WalSegSz = strtoul(optarg, NULL, 0);
diff --git a/src/backend/crypto/kmgr.c b/src/backend/crypto/kmgr.c
index 4b74961323..a83effbca8 100644
--- a/src/backend/crypto/kmgr.c
+++ b/src/backend/crypto/kmgr.c
@@ -253,6 +253,9 @@ InitializeKmgr(void)
 	char		live_path[MAXPGPATH];
 	unsigned char cluster_key[KMGR_CLUSTER_KEY_LEN];
 
+	if (!FileEncryptionEnabled)
+		return;
+
 #ifndef USE_OPENSSL
 	ereport(ERROR,
 			(errcode(ERRCODE_CONFIG_FILE_ERROR),
diff --git a/src/backend/libpq/be-secure-common.c b/src/backend/libpq/be-secure-common.c
index 2719ce1403..9357c80ea6 100644
--- a/src/backend/libpq/be-secure-common.c
+++ b/src/backend/libpq/be-secure-common.c
@@ -22,6 +22,7 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
+#include "postmaster/postmaster.h"
 #include "common/string.h"
 #include "libpq/libpq.h"
 #include "storage/fd.h"
@@ -61,6 +62,19 @@ run_ssl_passphrase_command(const char *prompt, bool is_server_start, char *buf,
 					appendStringInfoString(&command, prompt);
 					p++;
 					break;
+				case 'R':
+					{
+						char fd_str[20];
+
+						if (terminal_fd == -1)
+							ereport(ERROR,
+									(errcode(ERRCODE_INTERNAL_ERROR),
+									 errmsg("ssl_passphrase_command referenced %%R, but -R not specified")));
+						p++;
+						snprintf(fd_str, sizeof(fd_str), "%d", terminal_fd);
+						appendStringInfoString(&command, fd_str);
+						break;
+					}
 				case '%':
 					appendStringInfoChar(&command, '%');
 					p++;
diff --git a/src/backend/main/main.c b/src/backend/main/main.c
index f5da4260a1..ddf3fcb6fb 100644
--- a/src/backend/main/main.c
+++ b/src/backend/main/main.c
@@ -343,6 +343,7 @@ help(const char *progname)
 #endif
 	printf(_("  -N MAX-CONNECT     maximum number of allowed connections\n"));
 	printf(_("  -p PORT            port number to listen on\n"));
+	printf(_("  -R fd              prompt for the cluster key\n"));
 	printf(_("  -s                 show statistics after each query\n"));
 	printf(_("  -S WORK-MEM        set amount of memory for sorts (in kB)\n"));
 	printf(_("  -V, --version      output version information, then exit\n"));
@@ -371,7 +372,9 @@ help(const char *progname)
 	printf(_("  --boot             selects bootstrapping mode (must be first argument)\n"));
 	printf(_("  --check            selects check mode (must be first argument)\n"));
 	printf(_("  DBNAME             database name (mandatory argument in bootstrapping mode)\n"));
+ 	printf(_("  -K LEN             enable cluster file encryption with specified key bit length\n"));
 	printf(_("  -r FILENAME        send stdout and stderr to given file\n"));
+ 	printf(_("  -u DATADIR         copy encryption keys from datadir\n"));
 
 	printf(_("\nPlease read the documentation for the complete list of run-time\n"
 			 "configuration settings and how to set them on the command line or in\n"
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 0b637ba6a2..1673717da9 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -98,6 +98,7 @@
 #include "common/ip.h"
 #include "common/pg_prng.h"
 #include "common/string.h"
+#include "crypto/kmgr.h"
 #include "lib/ilist.h"
 #include "libpq/auth.h"
 #include "libpq/libpq.h"
@@ -231,6 +232,7 @@ static int	SendStop = false;
 
 /* still more option variables */
 bool		EnableSSL = false;
+int			terminal_fd = -1;
 
 int			PreAuthDelay = 0;
 int			AuthenticationTimeout = 60;
@@ -697,7 +699,7 @@ PostmasterMain(int argc, char *argv[])
 	 * tcop/postgres.c (the option sets should not conflict) and with the
 	 * common help() function in main/main.c.
 	 */
-	while ((opt = getopt(argc, argv, "B:bc:C:D:d:EeFf:h:ijk:lN:nOPp:r:S:sTt:W:-:")) != -1)
+	while ((opt = getopt(argc, argv, "B:bc:C:D:d:EeFf:h:ijk:lN:nOPp:r:R:S:sTt:W:-:")) != -1)
 	{
 		switch (opt)
 		{
@@ -788,6 +790,10 @@ PostmasterMain(int argc, char *argv[])
 				/* only used by single-user backend */
 				break;
 
+			case 'R':
+				terminal_fd = atoi(optarg);
+				break;
+
 			case 'S':
 				SetConfigOption("work_mem", optarg, PGC_POSTMASTER, PGC_S_ARGV);
 				break;
@@ -1347,6 +1353,11 @@ PostmasterMain(int argc, char *argv[])
 		pfree(rawstring);
 	}
 
+	InitializeKmgr();
+
+	if (terminal_fd != -1)
+		close(terminal_fd);
+
 	/*
 	 * check that we have some socket to listen on
 	 */
diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c
index b204ecdbc3..061da11a58 100644
--- a/src/backend/storage/ipc/ipci.c
+++ b/src/backend/storage/ipc/ipci.c
@@ -25,6 +25,7 @@
 #include "access/xlogprefetcher.h"
 #include "access/xlogrecovery.h"
 #include "commands/async.h"
+#include "crypto/kmgr.h"
 #include "miscadmin.h"
 #include "pgstat.h"
 #include "postmaster/autovacuum.h"
@@ -142,6 +143,7 @@ CalculateShmemSize(int *num_semaphores)
 	size = add_size(size, SyncScanShmemSize());
 	size = add_size(size, AsyncShmemSize());
 	size = add_size(size, StatsShmemSize());
+	size = add_size(size, KmgrShmemSize());
 #ifdef EXEC_BACKEND
 	size = add_size(size, ShmemBackendArraySize());
 #endif
@@ -294,6 +296,7 @@ CreateSharedMemoryAndSemaphores(void)
 	SyncScanShmemInit();
 	AsyncShmemInit();
 	StatsShmemInit();
+ 	KmgrShmemInit();
 
 #ifdef EXEC_BACKEND
 
diff --git a/src/backend/storage/lmgr/lwlocknames.txt b/src/backend/storage/lmgr/lwlocknames.txt
index 6c7cf6c295..56ac32407f 100644
--- a/src/backend/storage/lmgr/lwlocknames.txt
+++ b/src/backend/storage/lmgr/lwlocknames.txt
@@ -53,3 +53,4 @@ XactTruncationLock					44
 # 45 was XactTruncationLock until removal of BackendRandomLock
 WrapLimitsVacuumLock				46
 NotifyQueueTailLock					47
+KmgrFileLock					48
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 3082093d1e..5ee6c43394 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -35,6 +35,7 @@
 #include "commands/async.h"
 #include "commands/prepare.h"
 #include "common/pg_prng.h"
+#include "crypto/kmgr.h"
 #include "jit/jit.h"
 #include "libpq/libpq.h"
 #include "libpq/pqformat.h"
@@ -3718,7 +3719,7 @@ process_postgres_switches(int argc, char *argv[], GucContext ctx,
 	 * postmaster/postmaster.c (the option sets should not conflict) and with
 	 * the common help() function in main/main.c.
 	 */
-	while ((flag = getopt(argc, argv, "B:bc:C:D:d:EeFf:h:ijk:lN:nOPp:r:S:sTt:v:W:-:")) != -1)
+	while ((flag = getopt(argc, argv, "B:bc:C:D:d:EeFf:h:ijk:lN:nOPp:r:R:S:sTt:v:W:-:")) != -1)
 	{
 		switch (flag)
 		{
@@ -3810,6 +3811,19 @@ process_postgres_switches(int argc, char *argv[], GucContext ctx,
 					strlcpy(OutputFileName, optarg, MAXPGPATH);
 				break;
 
+			case 'R':
+				terminal_fd = atoi(optarg);
+				if (terminal_fd == -1)
+				{
+					/*
+					 * Allow file descriptor closing to be bypassed via -1.
+					 * We just duplicate sterr.  This is useful for
+					 * single-user mode.
+					 */
+					terminal_fd = dup(2);
+				}
+				break;
+
 			case 'S':
 				SetConfigOption("work_mem", optarg, ctx, gucsource);
 				break;
@@ -4055,6 +4069,18 @@ PostgresMain(const char *dbname, const char *username)
 
 	SetProcessingMode(InitProcessing);
 
+	/*
+	 * Initialize kmgr for cluster encryption. Since kmgr needs to attach to
+	 * shared memory the initialization must be called after BaseInit().
+	 */
+	if (!IsUnderPostmaster)
+	{
+		InitializeKmgr();
+
+		if (terminal_fd != -1)
+			close(terminal_fd);
+	}
+
 	/*
 	 * Set up signal handlers.  (InitPostmasterChild or InitStandaloneProcess
 	 * has already set up BlockSig and made that the active signal mask.)
diff --git a/src/backend/utils/activity/wait_event.c b/src/backend/utils/activity/wait_event.c
index 92f24a6c9b..6f7953accb 100644
--- a/src/backend/utils/activity/wait_event.c
+++ b/src/backend/utils/activity/wait_event.c
@@ -591,6 +591,15 @@ pgstat_get_wait_io(WaitEventIO w)
 		case WAIT_EVENT_DSM_FILL_ZERO_WRITE:
 			event_name = "DSMFillZeroWrite";
 			break;
+		case WAIT_EVENT_KEY_FILE_READ:
+			event_name = "KeyFileRead";
+			break;
+		case WAIT_EVENT_KEY_FILE_WRITE:
+			event_name = "KeyFileWrite";
+			break;
+		case WAIT_EVENT_KEY_FILE_SYNC:
+			event_name = "KeyFileSync";
+			break;
 		case WAIT_EVENT_LOCK_FILE_ADDTODATADIR_READ:
 			event_name = "LockFileAddToDataDirRead";
 			break;
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index 836b49484a..e7d7cad2b2 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -40,6 +40,7 @@
 #include "commands/trigger.h"
 #include "commands/user.h"
 #include "commands/vacuum.h"
+#include "crypto/kmgr.h"
 #include "jit/jit.h"
 #include "libpq/auth.h"
 #include "libpq/libpq.h"
@@ -579,6 +580,7 @@ static char *recovery_target_string;
 static char *recovery_target_xid_string;
 static char *recovery_target_name_string;
 static char *recovery_target_lsn_string;
+static char *file_encryption_method_str;
 
 /* should be static, but commands/variable.c needs to get at this */
 char	   *role_string;
@@ -701,6 +703,8 @@ const char *const config_group_names[] =
 	gettext_noop("Statistics / Monitoring"),
 	/* STATS_CUMULATIVE */
 	gettext_noop("Statistics / Cumulative Query and Index Statistics"),
+	/* ENCRYPTION */
+	gettext_noop("Encryption"),
 	/* AUTOVACUUM */
 	gettext_noop("Autovacuum"),
 	/* CLIENT_CONN_STATEMENT */
@@ -4403,6 +4407,27 @@ struct config_string ConfigureNamesString[] =
 		NULL, NULL, NULL
 	},
 
+	{
+		{"cluster_key_command", PGC_SIGHUP, ENCRYPTION,
+			gettext_noop("Command to obtain cluster key for cluster file encryption."),
+			NULL
+		},
+		&cluster_key_command,
+		"",
+		NULL, NULL, NULL
+	},
+
+	{
+		{"file_encryption_method", PGC_INTERNAL, PRESET_OPTIONS,
+		 gettext_noop("Shows the cluster file encryption method."),
+		 NULL,
+		 GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
+ 		},
+		&file_encryption_method_str,
+		"",
+		NULL, NULL, NULL
+	},
+
 	{
 		{"application_name", PGC_USERSET, LOGGING_WHAT,
 			gettext_noop("Sets the application name to be reported in statistics and logs."),
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 781f8b8758..d5fbf8f7df 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -263,8 +263,8 @@ pg_control_recovery(PG_FUNCTION_ARGS)
 Datum
 pg_control_init(PG_FUNCTION_ARGS)
 {
-	Datum		values[11];
-	bool		nulls[11];
+	Datum		values[12];
+	bool		nulls[12];
 	TupleDesc	tupdesc;
 	HeapTuple	htup;
 	ControlFileData *ControlFile;
@@ -274,7 +274,7 @@ pg_control_init(PG_FUNCTION_ARGS)
 	 * Construct a tuple descriptor for the result row.  This must match this
 	 * function's pg_proc entry!
 	 */
-	tupdesc = CreateTemplateTupleDesc(11);
+	tupdesc = CreateTemplateTupleDesc(12);
 	TupleDescInitEntry(tupdesc, (AttrNumber) 1, "max_data_alignment",
 					   INT4OID, -1, 0);
 	TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database_block_size",
@@ -297,6 +297,8 @@ pg_control_init(PG_FUNCTION_ARGS)
 					   BOOLOID, -1, 0);
 	TupleDescInitEntry(tupdesc, (AttrNumber) 11, "data_page_checksum_version",
 					   INT4OID, -1, 0);
+	TupleDescInitEntry(tupdesc, (AttrNumber) 12, "file_encryption_method",
+					   INT4OID, -1, 0);
 	tupdesc = BlessTupleDesc(tupdesc);
 
 	/* read the control file */
@@ -338,6 +340,9 @@ pg_control_init(PG_FUNCTION_ARGS)
 	values[10] = Int32GetDatum(ControlFile->data_checksum_version);
 	nulls[10] = false;
 
+	values[11] = Int32GetDatum(ControlFile->file_encryption_method);
+	nulls[11] = false;
+
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
 	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 868d21c351..96b5c869e1 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -659,6 +659,11 @@
 					# autovacuum, -1 means use
 					# vacuum_cost_limit
 
+#------------------------------------------------------------------------------
+# ENCRYPTION
+#------------------------------------------------------------------------------
+
+#cluster_key_command = ''
 
 #------------------------------------------------------------------------------
 # CLIENT CONNECTION DEFAULTS
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 1fbd48fbda..8f219fbacc 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -13,6 +13,7 @@
 
 #include "access/xlogbackup.h"
 #include "access/xlogdefs.h"
+#include "common/kmgr_utils.h"
 #include "datatype/timestamp.h"
 #include "lib/stringinfo.h"
 #include "nodes/pg_list.h"
@@ -224,6 +225,10 @@ extern XLogRecPtr GetXLogWriteRecPtr(void);
 extern uint64 GetSystemIdentifier(void);
 extern char *GetMockAuthenticationNonce(void);
 extern bool DataChecksumsEnabled(void);
+
+#define FileEncryptionEnabled (GetFileEncryptionMethod() != DISABLED_ENCRYPTION_METHOD)
+extern int GetFileEncryptionMethod(void);
+
 extern XLogRecPtr GetFakeLSNForUnloggedRel(void);
 extern Size XLOGShmemSize(void);
 extern void XLOGShmemInit(void);
diff --git a/src/include/catalog/pg_control.h b/src/include/catalog/pg_control.h
index 06368e2366..db7de77287 100644
--- a/src/include/catalog/pg_control.h
+++ b/src/include/catalog/pg_control.h
@@ -22,7 +22,7 @@
 
 
 /* Version identifier for this pg_control format */
-#define PG_CONTROL_VERSION	1300
+#define PG_CONTROL_VERSION	1400
 
 /* Nonce key length, see below */
 #define MOCK_AUTH_NONCE_LEN		32
@@ -226,6 +226,9 @@ typedef struct ControlFileData
 	 */
 	char		mock_authentication_nonce[MOCK_AUTH_NONCE_LEN];
 
+	/* File encryption method;  index into encryption_methods[]. */
+	int		file_encryption_method;
+
 	/* CRC of all above ... MUST BE LAST! */
 	pg_crc32c	crc;
 } ControlFileData;
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 20f5aa56ea..f5e7a85519 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -11674,9 +11674,9 @@
   descr => 'pg_controldata init state information as a function',
   proname => 'pg_control_init', provolatile => 'v', prorettype => 'record',
   proargtypes => '',
-  proallargtypes => '{int4,int4,int4,int4,int4,int4,int4,int4,int4,bool,int4}',
-  proargmodes => '{o,o,o,o,o,o,o,o,o,o,o}',
-  proargnames => '{max_data_alignment,database_block_size,blocks_per_segment,wal_block_size,bytes_per_wal_segment,max_identifier_length,max_index_columns,max_toast_chunk_size,large_object_chunk_size,float8_pass_by_value,data_page_checksum_version}',
+  proallargtypes => '{int4,int4,int4,int4,int4,int4,int4,int4,int4,bool,int4,int4}',
+  proargmodes => '{o,o,o,o,o,o,o,o,o,o,o,o}',
+  proargnames => '{max_data_alignment,database_block_size,blocks_per_segment,wal_block_size,bytes_per_wal_segment,max_identifier_length,max_index_columns,max_toast_chunk_size,large_object_chunk_size,float8_pass_by_value,data_page_checksum_version,file_encryption_method}',
   prosrc => 'pg_control_init' },
 
 # subscripting support for built-in types
diff --git a/src/include/postmaster/postmaster.h b/src/include/postmaster/postmaster.h
index 90e333ccd2..deac25e115 100644
--- a/src/include/postmaster/postmaster.h
+++ b/src/include/postmaster/postmaster.h
@@ -31,6 +31,8 @@ extern PGDLLIMPORT char *bonjour_name;
 extern PGDLLIMPORT bool restart_after_crash;
 extern PGDLLIMPORT bool remove_temp_files_after_crash;
 
+extern int	terminal_fd;
+
 #ifdef WIN32
 extern PGDLLIMPORT HANDLE PostmasterHandle;
 #else
diff --git a/src/include/utils/guc_tables.h b/src/include/utils/guc_tables.h
index 51f7f09fde..1446b334b1 100644
--- a/src/include/utils/guc_tables.h
+++ b/src/include/utils/guc_tables.h
@@ -86,6 +86,7 @@ enum config_group
 	PROCESS_TITLE,
 	STATS_MONITORING,
 	STATS_CUMULATIVE,
+	ENCRYPTION,
 	AUTOVACUUM,
 	CLIENT_CONN_STATEMENT,
 	CLIENT_CONN_LOCALE,
-- 
2.31.1

