PG-1095 Add format validation CI workflow and format sources (#308)

* PG-1095 Add code format validation to CI

* PG-1095 Manually fix some codestyle

* PG-1095 Add comment to pgindent_exclude file

* PG-1095 Format sources

* PG-1095 Fix makefile

* PG-1095 Remove accidentally commited file

* PG-1094 Update gitignore

* PG-1094 Update pgindent_exclude

* PG-1095 Update typedefs list

* PG-1095 Manual code formatting

* PG-1095 Update typedefs list

* PG-1095 More manual code formatting

* PG-1095 More manual code formatting

* PG-1095 More fixes

* PG-1095 Fix
pull/209/head
Artem Gavrilov 10 months ago committed by GitHub
parent 2f31c0ed45
commit d2237acde5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 57
      .github/workflows/check.yaml
  2. 4
      .gitignore
  3. 11
      Makefile.in
  4. 9
      pgindent_excludes
  5. 4
      src/access/pg_tde_ddl.c
  6. 10
      src/access/pg_tde_slot.c
  7. 76
      src/access/pg_tde_tdemap.c
  8. 1
      src/access/pg_tde_xlog.c
  9. 35
      src/access/pg_tde_xlog_encrypt.c
  10. 1
      src/catalog/tde_global_space.c
  11. 27
      src/catalog/tde_keyring.c
  12. 59
      src/catalog/tde_principal_key.c
  13. 24
      src/common/pg_tde_shmem.c
  14. 7
      src/common/pg_tde_utils.c
  15. 37
      src/encryption/enc_aes.c
  16. 64
      src/encryption/enc_tde.c
  17. 3
      src/include/catalog/tde_keyring.h
  18. 21
      src/include/common/pg_tde_shmem.h
  19. 5
      src/include/keyring/keyring_curl.h
  20. 2
      src/include/keyring/keyring_vault.h
  21. 8
      src/include/pg_tde_defines.h
  22. 12
      src/keyring/keyring_api.c
  23. 55
      src/keyring/keyring_curl.c
  24. 3
      src/keyring/keyring_file.c
  25. 26
      src/keyring/keyring_vault.c
  26. 19
      src/pg_tde.c
  27. 8
      src/pg_tde_event_capture.c
  28. 61
      src/smgr/pg_tde_smgr.c
  29. 4
      src/transam/pg_tde_xact_handler.c
  30. 113
      typedefs.list

@ -0,0 +1,57 @@
name: Checks
on:
pull_request:
jobs:
format:
name: Format
runs-on: ubuntu-22.04
timeout-minutes: 5
steps:
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y libcurl4-openssl-dev
- name: Clone postgres repository
uses: actions/checkout@v4
with:
repository: 'postgres/postgres'
ref: 'REL_17_STABLE'
- name: Checkout sources
uses: actions/checkout@v4
with:
path: 'contrib/pg_tde'
- name: Configure postgres
run: ./configure
- name: Configure pg_tde
run: ./configure
working-directory: contrib/pg_tde
- name: Install perltidy
run: sudo cpan -T SHANCOCK/Perl-Tidy-20230309.tar.gz
- name: Install pg_bsd_indent
working-directory: src/tools/pg_bsd_indent
run: sudo make install
- name: Add pg_bsd_indent and pgindent to path
run: |
echo "/usr/local/pgsql/bin" >> $GITHUB_PATH
echo "${{ github.workspace }}/src/tools/pgindent" >> $GITHUB_PATH
- name: Format sources
working-directory: contrib/pg_tde
run: |
make update-typedefs
make indent
- name: Check files are formatted and no source code changes
working-directory: contrib/pg_tde
run: |
git status
git diff --exit-code

4
.gitignore vendored

@ -9,3 +9,7 @@ __pycache__
/autom4te.cache /autom4te.cache
/configure~ /configure~
t/results t/results
src/include/config.h
# tools files
typedefs-full.list

@ -74,3 +74,14 @@ include $(top_srcdir)/contrib/contrib-global.mk
endif endif
override SHLIB_LINK += @tde_LDFLAGS@ -lcrypto -lssl override SHLIB_LINK += @tde_LDFLAGS@ -lcrypto -lssl
# Fetches typedefs list for PostgreSQL core and merges it with typedefs defined in this project.
# https://wiki.postgresql.org/wiki/Running_pgindent_on_non-core_code_or_development_code
update-typedefs:
wget -q -O - "https://buildfarm.postgresql.org/cgi-bin/typedefs.pl?branch=REL_17_STABLE" | cat - typedefs.list | sort | uniq > typedefs-full.list
# Indents projects sources.
indent:
pgindent --typedefs=typedefs-full.list --excludes=pgindent_excludes .
.PHONY: update-typedefs indent

@ -0,0 +1,9 @@
# List of filename patterns to exclude from pgindent runs
#
# This contains code copied from postgres tree as is and slightly modified.
# We don't want to run pgindent on these files to avoid unnecessary conflicts.
src\d\d/
# This file is generated by configure and should not be formatted
src/include/config.h

@ -22,7 +22,8 @@ static object_access_hook_type prev_object_access_hook = NULL;
static void tdeheap_object_access_hook(ObjectAccessType access, Oid classId, static void tdeheap_object_access_hook(ObjectAccessType access, Oid classId,
Oid objectId, int subId, void *arg); Oid objectId, int subId, void *arg);
void SetupTdeDDLHooks(void) void
SetupTdeDDLHooks(void)
{ {
prev_object_access_hook = object_access_hook; prev_object_access_hook = object_access_hook;
object_access_hook = tdeheap_object_access_hook; object_access_hook = tdeheap_object_access_hook;
@ -40,6 +41,7 @@ tdeheap_object_access_hook(ObjectAccessType access, Oid classId, Oid objectId,
if (access == OAT_DROP && classId == RelationRelationId) if (access == OAT_DROP && classId == RelationRelationId)
{ {
ObjectAccessDrop *drop_arg = (ObjectAccessDrop *) arg; ObjectAccessDrop *drop_arg = (ObjectAccessDrop *) arg;
rel = relation_open(objectId, AccessShareLock); rel = relation_open(objectId, AccessShareLock);
} }
if (rel != NULL) if (rel != NULL)

@ -49,6 +49,7 @@ static void
tdeheap_tts_buffer_heap_init(TupleTableSlot *slot) tdeheap_tts_buffer_heap_init(TupleTableSlot *slot)
{ {
TDEBufferHeapTupleTableSlot *bslot = (TDEBufferHeapTupleTableSlot *) slot; TDEBufferHeapTupleTableSlot *bslot = (TDEBufferHeapTupleTableSlot *) slot;
bslot->cached_relation_key = NULL; bslot->cached_relation_key = NULL;
} }
@ -254,6 +255,7 @@ static HeapTuple
tdeheap_tts_buffer_heap_get_heap_tuple(TupleTableSlot *slot) tdeheap_tts_buffer_heap_get_heap_tuple(TupleTableSlot *slot)
{ {
BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot; BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
Assert(!TTS_EMPTY(slot)); Assert(!TTS_EMPTY(slot));
if (!bslot->base.tuple) if (!bslot->base.tuple)
@ -367,6 +369,7 @@ tdeheap_slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *of
uint32 off; /* offset in tuple data */ uint32 off; /* offset in tuple data */
bits8 *bp = tup->t_bits; /* ptr to null bitmap in tuple */ bits8 *bp = tup->t_bits; /* ptr to null bitmap in tuple */
bool slow; /* can we use/set attcacheoff? */ bool slow; /* can we use/set attcacheoff? */
/* We can only fetch as many attributes as the tuple has. */ /* We can only fetch as many attributes as the tuple has. */
natts = Min(HeapTupleHeaderGetNatts(tuple->t_data), natts); natts = Min(HeapTupleHeaderGetNatts(tuple->t_data), natts);
@ -465,7 +468,7 @@ slot_copytuple(void* buffer, HeapTuple tuple)
newTuple->t_self = tuple->t_self; newTuple->t_self = tuple->t_self;
newTuple->t_tableOid = tuple->t_tableOid; newTuple->t_tableOid = tuple->t_tableOid;
newTuple->t_data = (HeapTupleHeader) ((char *) newTuple + HEAPTUPLESIZE); newTuple->t_data = (HeapTupleHeader) ((char *) newTuple + HEAPTUPLESIZE);
// We don't copy the data, it will be copied by the decryption code /* We don't copy the data, it will be copied by the decryption code */
memcpy((char *) newTuple->t_data, (char *) tuple->t_data, tuple->t_data->t_hoff); memcpy((char *) newTuple->t_data, (char *) tuple->t_data, tuple->t_data->t_hoff);
return newTuple; return newTuple;
} }
@ -487,7 +490,8 @@ const TupleTableSlotOps TTSOpsTDEBufferHeapTuple = {
/* A buffer heap tuple table slot can not "own" a minimal tuple. */ /* A buffer heap tuple table slot can not "own" a minimal tuple. */
.get_minimal_tuple = NULL, .get_minimal_tuple = NULL,
.copy_heap_tuple = tdeheap_tts_buffer_heap_copy_heap_tuple, .copy_heap_tuple = tdeheap_tts_buffer_heap_copy_heap_tuple,
.copy_minimal_tuple = tdeheap_tts_buffer_heap_copy_minimal_tuple}; .copy_minimal_tuple = tdeheap_tts_buffer_heap_copy_minimal_tuple
};
/* -------------------------------- /* --------------------------------
* ExecStoreBufferHeapTuple * ExecStoreBufferHeapTuple
@ -516,6 +520,7 @@ PGTdeExecStoreBufferHeapTuple(Relation rel,
{ {
TDEBufferHeapTupleTableSlot *bslot = (TDEBufferHeapTupleTableSlot *) slot; TDEBufferHeapTupleTableSlot *bslot = (TDEBufferHeapTupleTableSlot *) slot;
/* /*
* sanity checks * sanity checks
*/ */
@ -557,6 +562,7 @@ PGTdeExecStorePinnedBufferHeapTuple(Relation rel,
Buffer buffer) Buffer buffer)
{ {
TDEBufferHeapTupleTableSlot *bslot = (TDEBufferHeapTupleTableSlot *) slot; TDEBufferHeapTupleTableSlot *bslot = (TDEBufferHeapTupleTableSlot *) slot;
/* /*
* sanity checks * sanity checks
*/ */

@ -231,6 +231,7 @@ RelKeyData *
tde_create_rel_key(RelFileNumber rel_num, InternalKey *key, TDEPrincipalKeyInfo *principal_key_info) tde_create_rel_key(RelFileNumber rel_num, InternalKey *key, TDEPrincipalKeyInfo *principal_key_info)
{ {
RelKeyData rel_key_data; RelKeyData rel_key_data;
memcpy(&rel_key_data.principal_key_id, &principal_key_info->keyId, sizeof(TDEPrincipalKeyId)); memcpy(&rel_key_data.principal_key_id, &principal_key_info->keyId, sizeof(TDEPrincipalKeyId));
memcpy(&rel_key_data.internal_key, key, sizeof(InternalKey)); memcpy(&rel_key_data.internal_key, key, sizeof(InternalKey));
rel_key_data.internal_key.ctx = NULL; rel_key_data.internal_key.ctx = NULL;
@ -238,6 +239,7 @@ tde_create_rel_key(RelFileNumber rel_num, InternalKey *key, TDEPrincipalKeyInfo
/* Add to the decrypted key to cache */ /* Add to the decrypted key to cache */
return pg_tde_put_key_into_cache(rel_num, &rel_key_data); return pg_tde_put_key_into_cache(rel_num, &rel_key_data);
} }
/* /*
* Encrypts a given key and returns the encrypted one. * Encrypts a given key and returns the encrypted one.
*/ */
@ -373,15 +375,18 @@ pg_tde_write_map_entry(const RelFileLocator *rlocator, uint32 entry_type, char *
/* /*
* Read until we find an empty slot. Otherwise, read until end. This seems * Read until we find an empty slot. Otherwise, read until end. This seems
* to be less frequent than vacuum. So let's keep this function here rather * to be less frequent than vacuum. So let's keep this function here
* than overloading the vacuum process. * rather than overloading the vacuum process.
*/ */
while (1) while (1)
{ {
prev_pos = curr_pos; prev_pos = curr_pos;
found = pg_tde_read_one_map_entry(map_fd, NULL, MAP_ENTRY_EMPTY, &map_entry, &curr_pos); found = pg_tde_read_one_map_entry(map_fd, NULL, MAP_ENTRY_EMPTY, &map_entry, &curr_pos);
/* We either reach EOF or found an empty slot in the middle of the file */ /*
* We either reach EOF or found an empty slot in the middle of the
* file
*/
if (prev_pos == curr_pos || found) if (prev_pos == curr_pos || found)
break; break;
@ -389,7 +394,10 @@ pg_tde_write_map_entry(const RelFileLocator *rlocator, uint32 entry_type, char *
key_index++; key_index++;
} }
/* Write the given entry at the location pointed by prev_pos; i.e. the free entry */ /*
* Write the given entry at the location pointed by prev_pos; i.e. the
* free entry
*/
curr_pos = prev_pos; curr_pos = prev_pos;
pg_tde_write_one_map_entry(map_fd, rlocator, entry_type, key_index, &map_entry, &prev_pos); pg_tde_write_one_map_entry(map_fd, rlocator, entry_type, key_index, &map_entry, &prev_pos);
@ -425,6 +433,7 @@ pg_tde_write_one_map_entry(int fd, const RelFileLocator *rlocator, uint32 flags,
if (bytes_written != MAP_ENTRY_SIZE) if (bytes_written != MAP_ENTRY_SIZE)
{ {
char db_map_path[MAXPGPATH] = {0}; char db_map_path[MAXPGPATH] = {0};
pg_tde_set_db_file_paths(rlocator->dbOid, rlocator->spcOid, db_map_path, NULL); pg_tde_set_db_file_paths(rlocator->dbOid, rlocator->spcOid, db_map_path, NULL);
ereport(FATAL, ereport(FATAL,
(errcode_for_file_access(), (errcode_for_file_access(),
@ -434,6 +443,7 @@ pg_tde_write_one_map_entry(int fd, const RelFileLocator *rlocator, uint32 flags,
if (pg_fsync(fd) != 0) if (pg_fsync(fd) != 0)
{ {
char db_map_path[MAXPGPATH] = {0}; char db_map_path[MAXPGPATH] = {0};
pg_tde_set_db_file_paths(rlocator->dbOid, rlocator->spcOid, db_map_path, NULL); pg_tde_set_db_file_paths(rlocator->dbOid, rlocator->spcOid, db_map_path, NULL);
ereport(data_sync_elevel(ERROR), ereport(data_sync_elevel(ERROR),
(errcode_for_file_access(), (errcode_for_file_access(),
@ -528,7 +538,8 @@ pg_tde_write_key_map_entry(const RelFileLocator *rlocator, RelKeyData *enc_rel_k
* Deletes a map entry by setting marking it as unused. We don't have to delete * Deletes a map entry by setting marking it as unused. We don't have to delete
* the actual key data as valid key data entries are identify by valid map entries. * the actual key data as valid key data entries are identify by valid map entries.
*/ */
void pg_tde_delete_key_map_entry(const RelFileLocator *rlocator, uint32 key_type) void
pg_tde_delete_key_map_entry(const RelFileLocator *rlocator, uint32 key_type)
{ {
int32 key_index = 0; int32 key_index = 0;
off_t offset = 0; off_t offset = 0;
@ -575,7 +586,8 @@ void pg_tde_delete_key_map_entry(const RelFileLocator *rlocator, uint32 key_type
* *
* A caller should hold an EXCLUSIVE tde_lwlock_enc_keys lock. * A caller should hold an EXCLUSIVE tde_lwlock_enc_keys lock.
*/ */
void pg_tde_free_key_map_entry(const RelFileLocator *rlocator, uint32 key_type, off_t offset) void
pg_tde_free_key_map_entry(const RelFileLocator *rlocator, uint32 key_type, off_t offset)
{ {
int32 key_index = 0; int32 key_index = 0;
char db_map_path[MAXPGPATH] = {0}; char db_map_path[MAXPGPATH] = {0};
@ -621,7 +633,10 @@ void pg_tde_free_key_map_entry(const RelFileLocator *rlocator, uint32 key_type,
static File static File
keyrotation_init_file(TDEPrincipalKeyInfo *new_principal_key_info, char *rotated_filename, char *filename, bool *is_new_file, off_t *curr_pos) keyrotation_init_file(TDEPrincipalKeyInfo *new_principal_key_info, char *rotated_filename, char *filename, bool *is_new_file, off_t *curr_pos)
{ {
/* Set the new filenames for the key rotation process - temporary at the moment */ /*
* Set the new filenames for the key rotation process - temporary at the
* moment
*/
snprintf(rotated_filename, MAXPGPATH, "%s.r", filename); snprintf(rotated_filename, MAXPGPATH, "%s.r", filename);
/* Create file, truncate if the rotate file already exits */ /* Create file, truncate if the rotate file already exits */
@ -677,11 +692,17 @@ pg_tde_perform_rotate_key(TDEPrincipalKey *principal_key, TDEPrincipalKey *new_p
principal_key->keyInfo.tablespaceId, principal_key->keyInfo.tablespaceId,
db_map_path, db_keydata_path); db_map_path, db_keydata_path);
/* Let's update the pathnames in the local variable for ease of use/readability */ /*
* Let's update the pathnames in the local variable for ease of
* use/readability
*/
strncpy(m_path[OLD_PRINCIPAL_KEY], db_map_path, MAXPGPATH); strncpy(m_path[OLD_PRINCIPAL_KEY], db_map_path, MAXPGPATH);
strncpy(k_path[OLD_PRINCIPAL_KEY], db_keydata_path, MAXPGPATH); strncpy(k_path[OLD_PRINCIPAL_KEY], db_keydata_path, MAXPGPATH);
/* Open both files in read only mode. We don't need to track the current position of the keydata file. We always use the key index */ /*
* Open both files in read only mode. We don't need to track the current
* position of the keydata file. We always use the key index
*/
m_fd[OLD_PRINCIPAL_KEY] = pg_tde_open_file(m_path[OLD_PRINCIPAL_KEY], &principal_key->keyInfo, false, O_RDONLY, &is_new_file, &curr_pos[OLD_PRINCIPAL_KEY]); m_fd[OLD_PRINCIPAL_KEY] = pg_tde_open_file(m_path[OLD_PRINCIPAL_KEY], &principal_key->keyInfo, false, O_RDONLY, &is_new_file, &curr_pos[OLD_PRINCIPAL_KEY]);
k_fd[OLD_PRINCIPAL_KEY] = pg_tde_open_file(k_path[OLD_PRINCIPAL_KEY], &principal_key->keyInfo, false, O_RDONLY, &is_new_file, &read_pos_tmp); k_fd[OLD_PRINCIPAL_KEY] = pg_tde_open_file(k_path[OLD_PRINCIPAL_KEY], &principal_key->keyInfo, false, O_RDONLY, &is_new_file, &read_pos_tmp);
@ -691,7 +712,8 @@ pg_tde_perform_rotate_key(TDEPrincipalKey *principal_key, TDEPrincipalKey *new_p
/* Read all entries until EOF */ /* Read all entries until EOF */
for (key_index[OLD_PRINCIPAL_KEY] = 0;; key_index[OLD_PRINCIPAL_KEY]++) for (key_index[OLD_PRINCIPAL_KEY] = 0;; key_index[OLD_PRINCIPAL_KEY]++)
{ {
TDEMapEntry read_map_entry, write_map_entry; TDEMapEntry read_map_entry,
write_map_entry;
RelFileLocator rloc; RelFileLocator rloc;
prev_pos[OLD_PRINCIPAL_KEY] = curr_pos[OLD_PRINCIPAL_KEY]; prev_pos[OLD_PRINCIPAL_KEY] = curr_pos[OLD_PRINCIPAL_KEY];
@ -705,7 +727,10 @@ pg_tde_perform_rotate_key(TDEPrincipalKey *principal_key, TDEPrincipalKey *new_p
if (found == false) if (found == false)
continue; continue;
/* Set the relNumber of rlocator. Ignore the tablespace Oid since we only place our files under the default. */ /*
* Set the relNumber of rlocator. Ignore the tablespace Oid since we
* only place our files under the default.
*/
rloc.relNumber = read_map_entry.relNumber; rloc.relNumber = read_map_entry.relNumber;
rloc.dbOid = principal_key->keyInfo.databaseId; rloc.dbOid = principal_key->keyInfo.databaseId;
rloc.spcOid = DEFAULTTABLESPACE_OID; /* TODO. Revisit */ rloc.spcOid = DEFAULTTABLESPACE_OID; /* TODO. Revisit */
@ -955,12 +980,11 @@ pg_tde_get_key_from_file(const RelFileLocator *rlocator, uint32 key_type, bool n
* *
* We should hold the lock until the internal key is loaded to be sure the * We should hold the lock until the internal key is loaded to be sure the
* retrieved key was encrypted with the obtained principal key. Otherwise, * retrieved key was encrypted with the obtained principal key. Otherwise,
* the next may happen: * the next may happen: - GetPrincipalKey returns key "PKey_1". - Some
* - GetPrincipalKey returns key "PKey_1". * other process rotates the Principal key and re-encrypt an Internal key
* - Some other process rotates the Principal key and re-encrypt an * with "PKey_2". - We read the Internal key and decrypt it with "PKey_1"
* Internal key with "PKey_2". * (that's what we've got). As the result we return an invalid Internal
* - We read the Internal key and decrypt it with "PKey_1" (that's what * key.
* we've got). As the result we return an invalid Internal key.
*/ */
LWLockAcquire(lock_pk, LW_SHARED); LWLockAcquire(lock_pk, LW_SHARED);
principal_key = GetPrincipalKey(rlocator->dbOid, rlocator->spcOid, LW_SHARED); principal_key = GetPrincipalKey(rlocator->dbOid, rlocator->spcOid, LW_SHARED);
@ -1031,8 +1055,8 @@ pg_tde_process_map_entry(const RelFileLocator *rlocator, uint32 key_type, char *
Assert(offset); Assert(offset);
/* /*
* Open and validate file for basic correctness. DO NOT create it. * Open and validate file for basic correctness. DO NOT create it. The
* The file should pre-exist otherwise we should never be here. * file should pre-exist otherwise we should never be here.
*/ */
map_fd = pg_tde_open_file(db_map_path, NULL, false, O_RDWR, &is_new_file, &curr_pos); map_fd = pg_tde_open_file(db_map_path, NULL, false, O_RDWR, &is_new_file, &curr_pos);
@ -1061,8 +1085,8 @@ pg_tde_process_map_entry(const RelFileLocator *rlocator, uint32 key_type, char *
/* /*
* Read until we find an empty slot. Otherwise, read until end. This seems * Read until we find an empty slot. Otherwise, read until end. This seems
* to be less frequent than vacuum. So let's keep this function here rather * to be less frequent than vacuum. So let's keep this function here
* than overloading the vacuum process. * rather than overloading the vacuum process.
*/ */
while (1) while (1)
{ {
@ -1300,6 +1324,7 @@ pg_tde_read_one_keydata(int keydata_fd, int32 key_index, TDEPrincipalKey *princi
if ((read_pos + INTERNAL_KEY_DAT_LEN) > lseek(keydata_fd, 0, SEEK_END)) if ((read_pos + INTERNAL_KEY_DAT_LEN) > lseek(keydata_fd, 0, SEEK_END))
{ {
char db_keydata_path[MAXPGPATH] = {0}; char db_keydata_path[MAXPGPATH] = {0};
pg_tde_set_db_file_paths(principal_key->keyInfo.databaseId, principal_key->keyInfo.tablespaceId, NULL, db_keydata_path); pg_tde_set_db_file_paths(principal_key->keyInfo.databaseId, principal_key->keyInfo.tablespaceId, NULL, db_keydata_path);
ereport(FATAL, ereport(FATAL,
(errcode(ERRCODE_NO_DATA_FOUND), (errcode(ERRCODE_NO_DATA_FOUND),
@ -1313,6 +1338,7 @@ pg_tde_read_one_keydata(int keydata_fd, int32 key_index, TDEPrincipalKey *princi
if (pg_pread(keydata_fd, &(enc_rel_key_data->internal_key), INTERNAL_KEY_DAT_LEN, read_pos) != INTERNAL_KEY_DAT_LEN) if (pg_pread(keydata_fd, &(enc_rel_key_data->internal_key), INTERNAL_KEY_DAT_LEN, read_pos) != INTERNAL_KEY_DAT_LEN)
{ {
char db_keydata_path[MAXPGPATH] = {0}; char db_keydata_path[MAXPGPATH] = {0};
pg_tde_set_db_file_paths(principal_key->keyInfo.databaseId, principal_key->keyInfo.tablespaceId, NULL, db_keydata_path); pg_tde_set_db_file_paths(principal_key->keyInfo.databaseId, principal_key->keyInfo.tablespaceId, NULL, db_keydata_path);
ereport(FATAL, ereport(FATAL,
(errcode_for_file_access(), (errcode_for_file_access(),
@ -1356,7 +1382,10 @@ pg_tde_get_principal_key_info(Oid dbOid, Oid spcOid)
close(fd); close(fd);
/* It's not a new file. So we can memcpy the principal key info from the header */ /*
* It's not a new file. So we can memcpy the principal key info from the
* header
*/
if (!is_new_file) if (!is_new_file)
{ {
size_t sz = sizeof(TDEPrincipalKeyInfo); size_t sz = sizeof(TDEPrincipalKeyInfo);
@ -1479,7 +1508,8 @@ pg_tde_put_key_into_cache(RelFileNumber rel_num, RelKeyData *key)
tde_rel_key_cache->cap = pageSize / sizeof(RelKeyCacheRec); tde_rel_key_cache->cap = pageSize / sizeof(RelKeyCacheRec);
} }
/* Add another mem page if there is no more room left for another key. We /*
* Add another mem page if there is no more room left for another key. We
* allocate `current_memory_size` + 1 page and copy data there. * allocate `current_memory_size` + 1 page and copy data there.
*/ */
if (tde_rel_key_cache->len + 1 > if (tde_rel_key_cache->len + 1 >

@ -65,6 +65,7 @@ tdeheap_rmgr_redo(XLogReaderState *record)
else if (info == XLOG_TDE_ADD_KEY_PROVIDER_KEY) else if (info == XLOG_TDE_ADD_KEY_PROVIDER_KEY)
{ {
KeyringProviderXLRecord *xlrec = (KeyringProviderXLRecord *) XLogRecGetData(record); KeyringProviderXLRecord *xlrec = (KeyringProviderXLRecord *) XLogRecGetData(record);
redo_key_provider_info(xlrec); redo_key_provider_info(xlrec);
} }

@ -134,13 +134,13 @@ TDEXLogWriteEncryptedPages(int fd, const void *buf, size_t count, off_t offset)
#endif #endif
/* /*
* Go through the buf page-by-page and encrypt them. * Go through the buf page-by-page and encrypt them. We may start or
* We may start or finish writing from/in the middle of the page * finish writing from/in the middle of the page (walsender or
* (walsender or `full_page_writes = off`). So preserve a page header * `full_page_writes = off`). So preserve a page header for the IV init
* for the IV init data. * data.
* *
* TODO: check if walsender restarts form the beggining of the page * TODO: check if walsender restarts form the beggining of the page in
* in case of the crash. * case of the crash.
*/ */
for (enc_off = 0; enc_off < count;) for (enc_off = 0; enc_off < count;)
{ {
@ -151,8 +151,9 @@ TDEXLogWriteEncryptedPages(int fd, const void *buf, size_t count, off_t offset)
memcpy((char *) curr_page_hdr, (char *) buf + enc_off, SizeOfXLogShortPHD); memcpy((char *) curr_page_hdr, (char *) buf + enc_off, SizeOfXLogShortPHD);
/* /*
* Need to use a separate buf for the encryption so the page remains non-crypted * Need to use a separate buf for the encryption so the page
* in the XLog buf (XLogInsert has to have access to records' lsn). * remains non-crypted in the XLog buf (XLogInsert has to have
* access to records' lsn).
*/ */
enc_buf_page = (XLogPageHeader) (TDEXLogEncryptBuf + enc_off); enc_buf_page = (XLogPageHeader) (TDEXLogEncryptBuf + enc_off);
memcpy((char *) enc_buf_page, (char *) buf + enc_off, (Size) XLogPageHeaderSize(curr_page_hdr)); memcpy((char *) enc_buf_page, (char *) buf + enc_off, (Size) XLogPageHeaderSize(curr_page_hdr));
@ -175,9 +176,9 @@ TDEXLogWriteEncryptedPages(int fd, const void *buf, size_t count, off_t offset)
} }
/* /*
* The page is zeroed (no data), no sense to enctypt. * The page is zeroed (no data), no sense to enctypt. This may happen
* This may happen when base_backup or other requests XLOG SWITCH and * when base_backup or other requests XLOG SWITCH and some pages in
* some pages in XLog buffer still not used. * XLog buffer still not used.
*/ */
if (curr_page_hdr->xlp_magic == 0) if (curr_page_hdr->xlp_magic == 0)
{ {
@ -241,13 +242,13 @@ tdeheap_xlog_seg_read(int fd, void *buf, size_t count, off_t offset)
readsz = pg_pread(fd, buf, count, offset); readsz = pg_pread(fd, buf, count, offset);
/* /*
* Read the buf page by page and decypt ecnrypted pages. * Read the buf page by page and decypt ecnrypted pages. We may start or
* We may start or fihish reading from/in the middle of the page (walreceiver) * fihish reading from/in the middle of the page (walreceiver) in such a
* in such a case we should preserve the last read page header for * case we should preserve the last read page header for the IV data and
* the IV data and the encryption state. * the encryption state.
* *
* TODO: check if walsender/receiver restarts form the beggining of the page * TODO: check if walsender/receiver restarts form the beggining of the
* in case of the crash. * page in case of the crash.
*/ */
for (dec_off = 0; dec_off < readsz;) for (dec_off = 0; dec_off < readsz;)
{ {

@ -200,6 +200,7 @@ create_principal_key(const char *key_name, GenericKeyring * keyring,
} }
principalKey->keyLength = keyInfo->data.len; principalKey->keyLength = keyInfo->data.len;
memcpy(principalKey->keyData, keyInfo->data.data, keyInfo->data.len); memcpy(principalKey->keyData, keyInfo->data.data, keyInfo->data.len);
return principalKey; return principalKey;

@ -120,7 +120,8 @@ tde_provider_info_lock(void)
return &sharedPrincipalKeyState->Locks[TDE_LWLOCK_PI_FILES].lock; return &sharedPrincipalKeyState->Locks[TDE_LWLOCK_PI_FILES].lock;
} }
void InitializeKeyProviderInfo(void) void
InitializeKeyProviderInfo(void)
{ {
ereport(LOG, (errmsg("initializing TDE key provider info"))); ereport(LOG, (errmsg("initializing TDE key provider info")));
RegisterShmemRequest(&key_provider_info_shmem_routine); RegisterShmemRequest(&key_provider_info_shmem_routine);
@ -178,6 +179,7 @@ GetKeyProviderByName(const char *provider_name, Oid dbOid, Oid spcOid)
{ {
GenericKeyring *keyring = NULL; GenericKeyring *keyring = NULL;
List *providers = scan_key_provider_file(PROVIDER_SCAN_BY_NAME, (void *) provider_name, dbOid, spcOid); List *providers = scan_key_provider_file(PROVIDER_SCAN_BY_NAME, (void *) provider_name, dbOid, spcOid);
if (providers != NIL) if (providers != NIL)
{ {
keyring = (GenericKeyring *) linitial(providers); keyring = (GenericKeyring *) linitial(providers);
@ -221,7 +223,10 @@ write_key_provider_info(KeyringProvideRecord *provider, Oid database_id,
} }
if (position == -1) if (position == -1)
{ {
/* we also need to verify the name conflict and generate the next provider ID */ /*
* we also need to verify the name conflict and generate the next
* provider ID
*/
while (fetch_next_key_provider(fd, &curr_pos, &existing_provider)) while (fetch_next_key_provider(fd, &curr_pos, &existing_provider))
{ {
if (strcmp(existing_provider.provider_name, provider->provider_name) == 0) if (strcmp(existing_provider.provider_name, provider->provider_name) == 0)
@ -244,7 +249,8 @@ write_key_provider_info(KeyringProvideRecord *provider, Oid database_id,
provider->provider_id = max_provider_id + 1; provider->provider_id = max_provider_id + 1;
curr_pos = lseek(fd, 0, SEEK_END); curr_pos = lseek(fd, 0, SEEK_END);
/* emit the xlog here. So that we can handle partial file write errors /*
* emit the xlog here. So that we can handle partial file write errors
* but cannot make new WAL entries during recovery. * but cannot make new WAL entries during recovery.
*/ */
if (write_xlog) if (write_xlog)
@ -263,12 +269,14 @@ write_key_provider_info(KeyringProvideRecord *provider, Oid database_id,
} }
else else
{ {
/* we are performing redo, just go to the position received from the /*
* xlog and write the record there. * we are performing redo, just go to the position received from the
* No need to verify the name conflict and generate the provider ID * xlog and write the record there. No need to verify the name
* conflict and generate the provider ID
*/ */
curr_pos = lseek(fd, position, SEEK_SET); curr_pos = lseek(fd, position, SEEK_SET);
} }
/* /*
* All good, Just add a new provider * All good, Just add a new provider
*/ */
@ -365,6 +373,7 @@ pg_tde_list_all_key_providers(PG_FUNCTION_ARGS)
MemoryContext per_query_ctx; MemoryContext per_query_ctx;
MemoryContext oldcontext; MemoryContext oldcontext;
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
/* check to see if caller supports us returning a tuplestore */ /* check to see if caller supports us returning a tuplestore */
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
ereport(ERROR, ereport(ERROR,
@ -414,6 +423,7 @@ GetKeyProviderByID(int provider_id, Oid dbOid, Oid spcOid)
{ {
GenericKeyring *keyring = NULL; GenericKeyring *keyring = NULL;
List *providers = scan_key_provider_file(PROVIDER_SCAN_BY_ID, &provider_id, dbOid, spcOid); List *providers = scan_key_provider_file(PROVIDER_SCAN_BY_ID, &provider_id, dbOid, spcOid);
if (providers != NIL) if (providers != NIL)
{ {
keyring = (GenericKeyring *) linitial(providers); keyring = (GenericKeyring *) linitial(providers);
@ -430,6 +440,7 @@ GetKeyProviderByID(int provider_id, Oid dbOid, Oid spcOid)
{ {
GenericKeyring *keyring = NULL; GenericKeyring *keyring = NULL;
SimplePtrList *providers = scan_key_provider_file(PROVIDER_SCAN_BY_ID, &provider_id, dbOid, spcOid); SimplePtrList *providers = scan_key_provider_file(PROVIDER_SCAN_BY_ID, &provider_id, dbOid, spcOid);
if (providers != NULL) if (providers != NULL)
{ {
keyring = (GenericKeyring *) providers->head->ptr; keyring = (GenericKeyring *) providers->head->ptr;
@ -494,6 +505,7 @@ scan_key_provider_file(ProviderScanType scanType, void *scanKey, Oid dbOid, Oid
while (fetch_next_key_provider(fd, &curr_pos, &provider)) while (fetch_next_key_provider(fd, &curr_pos, &provider))
{ {
bool match = false; bool match = false;
ereport(DEBUG2, ereport(DEBUG2,
(errmsg("read key provider ID=%d %s", provider.provider_id, provider.provider_name))); (errmsg("read key provider ID=%d %s", provider.provider_id, provider.provider_name)));
@ -518,6 +530,7 @@ scan_key_provider_file(ProviderScanType scanType, void *scanKey, Oid dbOid, Oid
if (match) if (match)
{ {
GenericKeyring *keyring = load_keyring_provider_from_record(&provider); GenericKeyring *keyring = load_keyring_provider_from_record(&provider);
if (keyring) if (keyring)
{ {
#ifndef FRONTEND #ifndef FRONTEND
@ -627,6 +640,7 @@ static void
debug_print_kerying(GenericKeyring *keyring) debug_print_kerying(GenericKeyring *keyring)
{ {
int debug_level = DEBUG2; int debug_level = DEBUG2;
elog(debug_level, "Keyring type: %d", keyring->type); elog(debug_level, "Keyring type: %d", keyring->type);
elog(debug_level, "Keyring name: %s", keyring->provider_name); elog(debug_level, "Keyring name: %s", keyring->provider_name);
elog(debug_level, "Keyring id: %d", keyring->key_id); elog(debug_level, "Keyring id: %d", keyring->key_id);
@ -651,6 +665,7 @@ static char*
get_keyring_infofile_path(char *resPath, Oid dbOid, Oid spcOid) get_keyring_infofile_path(char *resPath, Oid dbOid, Oid spcOid)
{ {
char *db_path = pg_tde_get_tde_file_dir(dbOid, spcOid); char *db_path = pg_tde_get_tde_file_dir(dbOid, spcOid);
Assert(db_path != NULL); Assert(db_path != NULL);
join_path_components(resPath, db_path, PG_TDE_KEYRING_FILENAME); join_path_components(resPath, db_path, PG_TDE_KEYRING_FILENAME);
pfree(db_path); pfree(db_path);

@ -53,8 +53,7 @@ typedef struct TdePrincipalKeylocalState
{ {
TdePrincipalKeySharedState *sharedPrincipalKeyState; TdePrincipalKeySharedState *sharedPrincipalKeyState;
dsa_area *dsa; /* local dsa area for backend attached to the dsa_area *dsa; /* local dsa area for backend attached to the
* dsa area created by postmaster at startup. * dsa area created by postmaster at startup. */
*/
dshash_table *sharedHash; dshash_table *sharedHash;
} TdePrincipalKeylocalState; } TdePrincipalKeylocalState;
@ -95,7 +94,8 @@ static const TDEShmemSetupRoutine principal_key_info_shmem_routine = {
.shmem_kill = shared_memory_shutdown .shmem_kill = shared_memory_shutdown
}; };
void InitializePrincipalKeyInfo(void) void
InitializePrincipalKeyInfo(void)
{ {
ereport(LOG, (errmsg("Initializing TDE principal key info"))); ereport(LOG, (errmsg("Initializing TDE principal key info")));
RegisterShmemRequest(&principal_key_info_shmem_routine); RegisterShmemRequest(&principal_key_info_shmem_routine);
@ -124,6 +124,7 @@ static Size
required_shared_mem_size(void) required_shared_mem_size(void)
{ {
Size sz = cache_area_size(); Size sz = cache_area_size();
sz = add_size(sz, sizeof(TdePrincipalKeySharedState)); sz = add_size(sz, sizeof(TdePrincipalKeySharedState));
return MAXALIGN(sz); return MAXALIGN(sz);
} }
@ -137,6 +138,7 @@ static Size
initialize_shared_state(void *start_address) initialize_shared_state(void *start_address)
{ {
TdePrincipalKeySharedState *sharedState = (TdePrincipalKeySharedState *) start_address; TdePrincipalKeySharedState *sharedState = (TdePrincipalKeySharedState *) start_address;
ereport(LOG, (errmsg("initializing shared state for principal key"))); ereport(LOG, (errmsg("initializing shared state for principal key")));
principalKeyLocalState.dsa = NULL; principalKeyLocalState.dsa = NULL;
principalKeyLocalState.sharedHash = NULL; principalKeyLocalState.sharedHash = NULL;
@ -147,7 +149,8 @@ initialize_shared_state(void *start_address)
return sizeof(TdePrincipalKeySharedState); return sizeof(TdePrincipalKeySharedState);
} }
void initialize_objects_in_dsa_area(dsa_area *dsa, void *raw_dsa_area) void
initialize_objects_in_dsa_area(dsa_area *dsa, void *raw_dsa_area)
{ {
dshash_table *dsh; dshash_table *dsh;
TdePrincipalKeySharedState *sharedState = principalKeyLocalState.sharedPrincipalKeyState; TdePrincipalKeySharedState *sharedState = principalKeyLocalState.sharedPrincipalKeyState;
@ -263,6 +266,7 @@ set_principal_key_with_keyring(const char *key_name, GenericKeyring *keyring,
} }
principalKey->keyLength = keyInfo->data.len; principalKey->keyLength = keyInfo->data.len;
memcpy(principalKey->keyData, keyInfo->data.data, keyInfo->data.len); memcpy(principalKey->keyData, keyInfo->data.data, keyInfo->data.len);
save_principal_key_info(&principalKey->keyInfo); save_principal_key_info(&principalKey->keyInfo);
@ -280,8 +284,8 @@ set_principal_key_with_keyring(const char *key_name, GenericKeyring *keyring,
if (is_dup_key) if (is_dup_key)
{ {
/* /*
* Seems like just before we got the lock, the key was installed by some other caller * Seems like just before we got the lock, the key was installed by
* Throw an error and mover no * some other caller Throw an error and mover no
*/ */
ereport(ERROR, ereport(ERROR,
@ -322,9 +326,9 @@ RotatePrincipalKey(TDEPrincipalKey *current_key, const char *new_key_name, const
oldCtx = MemoryContextSwitchTo(keyRotateCtx); oldCtx = MemoryContextSwitchTo(keyRotateCtx);
/* /*
* Let's set everything the same as the older principal key and * Let's set everything the same as the older principal key and update
* update only the required attributes. * only the required attributes.
* */ */
memcpy(&new_principal_key, current_key, sizeof(TDEPrincipalKey)); memcpy(&new_principal_key, current_key, sizeof(TDEPrincipalKey));
if (new_key_name == NULL) if (new_key_name == NULL)
@ -361,9 +365,11 @@ RotatePrincipalKey(TDEPrincipalKey *current_key, const char *new_key_name, const
} }
new_principal_key.keyLength = keyInfo->data.len; new_principal_key.keyLength = keyInfo->data.len;
memcpy(new_principal_key.keyData, keyInfo->data.data, keyInfo->data.len); memcpy(new_principal_key.keyData, keyInfo->data.data, keyInfo->data.len);
is_rotated = pg_tde_perform_rotate_key(current_key, &new_principal_key); is_rotated = pg_tde_perform_rotate_key(current_key, &new_principal_key);
if (is_rotated && current_key->keyInfo.tablespaceId != GLOBALTABLESPACE_OID) { if (is_rotated && current_key->keyInfo.tablespaceId != GLOBALTABLESPACE_OID)
{
clear_principal_key_cache(current_key->keyInfo.databaseId); clear_principal_key_cache(current_key->keyInfo.databaseId);
push_principal_key_to_cache(&new_principal_key); push_principal_key_to_cache(&new_principal_key);
} }
@ -399,12 +405,15 @@ load_latest_versioned_key_name(TDEPrincipalKeyInfo *principal_key_info, GenericK
KeyringReturnCodes kr_ret; KeyringReturnCodes kr_ret;
keyInfo *keyInfo = NULL; keyInfo *keyInfo = NULL;
int base_version = principal_key_info->keyId.version; int base_version = principal_key_info->keyId.version;
Assert(principal_key_info != NULL); Assert(principal_key_info != NULL);
Assert(keyring != NULL); Assert(keyring != NULL);
Assert(strlen(principal_key_info->keyId.name) > 0); Assert(strlen(principal_key_info->keyId.name) > 0);
/* Start with the passed in version number
* We expect the name and the version number are already properly initialized /*
* and contain the correct values * Start with the passed in version number We expect the name and the
* version number are already properly initialized and contain the correct
* values
*/ */
snprintf(principal_key_info->keyId.versioned_name, TDE_KEY_NAME_LEN, snprintf(principal_key_info->keyId.versioned_name, TDE_KEY_NAME_LEN,
"%s_%d", principal_key_info->keyId.name, principal_key_info->keyId.version); "%s_%d", principal_key_info->keyId.name, principal_key_info->keyId.version);
@ -412,7 +421,11 @@ load_latest_versioned_key_name(TDEPrincipalKeyInfo *principal_key_info, GenericK
while (true) while (true)
{ {
keyInfo = KeyringGetKey(keyring, principal_key_info->keyId.versioned_name, false, &kr_ret); keyInfo = KeyringGetKey(keyring, principal_key_info->keyId.versioned_name, false, &kr_ret);
/* vault-v2 returns 404 (KEYRING_CODE_RESOURCE_NOT_AVAILABLE) when key is not found */
/*
* vault-v2 returns 404 (KEYRING_CODE_RESOURCE_NOT_AVAILABLE) when key
* is not found
*/
if (kr_ret != KEYRING_CODE_SUCCESS && kr_ret != KEYRING_CODE_RESOURCE_NOT_AVAILABLE) if (kr_ret != KEYRING_CODE_SUCCESS && kr_ret != KEYRING_CODE_RESOURCE_NOT_AVAILABLE)
{ {
ereport(FATAL, ereport(FATAL,
@ -443,7 +456,8 @@ load_latest_versioned_key_name(TDEPrincipalKeyInfo *principal_key_info, GenericK
snprintf(principal_key_info->keyId.versioned_name, TDE_KEY_NAME_LEN, "%s_%d", principal_key_info->keyId.name, principal_key_info->keyId.version); snprintf(principal_key_info->keyId.versioned_name, TDE_KEY_NAME_LEN, "%s_%d", principal_key_info->keyId.name, principal_key_info->keyId.version);
/* /*
* Not really required. Just to break the infinite loop in case the key provider is not behaving sane. * Not really required. Just to break the infinite loop in case the
* key provider is not behaving sane.
*/ */
if (principal_key_info->keyId.version > MAX_PRINCIPAL_KEY_VERSION_NUM) if (principal_key_info->keyId.version > MAX_PRINCIPAL_KEY_VERSION_NUM)
{ {
@ -453,6 +467,7 @@ load_latest_versioned_key_name(TDEPrincipalKeyInfo *principal_key_info, GenericK
} }
return NULL; /* Just to keep compiler quite */ return NULL; /* Just to keep compiler quite */
} }
/* /*
* Returns the provider ID of the keyring that holds the principal key * Returns the provider ID of the keyring that holds the principal key
* Return InvalidOid if the principal key is not set for the database * Return InvalidOid if the principal key is not set for the database
@ -474,7 +489,10 @@ GetPrincipalKeyProviderId(void)
keyringId = principalKey->keyInfo.keyringId; keyringId = principalKey->keyInfo.keyringId;
} }
{ {
/* Principal key not present in cache. Try Loading it from the info file */ /*
* Principal key not present in cache. Try Loading it from the info
* file
*/
principalKeyInfo = pg_tde_get_principal_key_info(dbOid, MyDatabaseTableSpace); principalKeyInfo = pg_tde_get_principal_key_info(dbOid, MyDatabaseTableSpace);
if (principalKeyInfo) if (principalKeyInfo)
{ {
@ -532,6 +550,7 @@ push_principal_key_to_cache(TDEPrincipalKey *principalKey)
TDEPrincipalKey *cacheEntry = NULL; TDEPrincipalKey *cacheEntry = NULL;
Oid databaseId = principalKey->keyInfo.databaseId; Oid databaseId = principalKey->keyInfo.databaseId;
bool found = false; bool found = false;
cacheEntry = dshash_find_or_insert(get_principal_key_Hash(), cacheEntry = dshash_find_or_insert(get_principal_key_Hash(),
&databaseId, &found); &databaseId, &found);
if (!found) if (!found)
@ -570,6 +589,7 @@ void
cleanup_principal_key_info(Oid databaseId, Oid tablespaceId) cleanup_principal_key_info(Oid databaseId, Oid tablespaceId)
{ {
clear_principal_key_cache(databaseId); clear_principal_key_cache(databaseId);
/* /*
* TODO: Although should never happen. Still verify if any table in the * TODO: Although should never happen. Still verify if any table in the
* database is using tde * database is using tde
@ -599,7 +619,8 @@ clear_principal_key_cache(Oid databaseId)
PG_FUNCTION_INFO_V1(pg_tde_set_principal_key); PG_FUNCTION_INFO_V1(pg_tde_set_principal_key);
Datum pg_tde_set_principal_key(PG_FUNCTION_ARGS); Datum pg_tde_set_principal_key(PG_FUNCTION_ARGS);
Datum pg_tde_set_principal_key(PG_FUNCTION_ARGS) Datum
pg_tde_set_principal_key(PG_FUNCTION_ARGS)
{ {
char *principal_key_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); char *principal_key_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
char *provider_name = text_to_cstring(PG_GETARG_TEXT_PP(1)); char *provider_name = text_to_cstring(PG_GETARG_TEXT_PP(1));
@ -656,7 +677,8 @@ pg_tde_rotate_principal_key_internal(PG_FUNCTION_ARGS)
} }
PG_FUNCTION_INFO_V1(pg_tde_principal_key_info_internal); PG_FUNCTION_INFO_V1(pg_tde_principal_key_info_internal);
Datum pg_tde_principal_key_info_internal(PG_FUNCTION_ARGS) Datum
pg_tde_principal_key_info_internal(PG_FUNCTION_ARGS)
{ {
Oid dbOid = MyDatabaseId; Oid dbOid = MyDatabaseId;
Oid spcOid = MyDatabaseTableSpace; Oid spcOid = MyDatabaseTableSpace;
@ -770,6 +792,7 @@ get_principal_key_from_keyring(Oid dbOid, Oid spcOid)
} }
keyInfo = KeyringGetKey(keyring, principalKeyInfo->keyId.versioned_name, false, &keyring_ret); keyInfo = KeyringGetKey(keyring, principalKeyInfo->keyId.versioned_name, false, &keyring_ret);
if (keyInfo == NULL) if (keyInfo == NULL)
{ {
return NULL; return NULL;

@ -27,8 +27,7 @@ typedef struct TDELocalState
{ {
TdeSharedState *sharedTdeState; TdeSharedState *sharedTdeState;
dsa_area **dsa; /* local dsa area for backend attached to the dsa_area **dsa; /* local dsa area for backend attached to the
* dsa area created by postmaster at startup. * dsa area created by postmaster at startup. */
*/
dshash_table *principalKeySharedHash; dshash_table *principalKeySharedHash;
} TDELocalState; } TDELocalState;
@ -37,19 +36,23 @@ static void tde_shmem_shutdown(int code, Datum arg);
List *registeredShmemRequests = NIL; List *registeredShmemRequests = NIL;
bool shmemInited = false; bool shmemInited = false;
void RegisterShmemRequest(const TDEShmemSetupRoutine *routine) void
RegisterShmemRequest(const TDEShmemSetupRoutine *routine)
{ {
Assert(shmemInited == false); Assert(shmemInited == false);
registeredShmemRequests = lappend(registeredShmemRequests, (void *) routine); registeredShmemRequests = lappend(registeredShmemRequests, (void *) routine);
} }
Size TdeRequiredSharedMemorySize(void) Size
TdeRequiredSharedMemorySize(void)
{ {
Size sz = 0; Size sz = 0;
ListCell *lc; ListCell *lc;
foreach(lc, registeredShmemRequests) foreach(lc, registeredShmemRequests)
{ {
TDEShmemSetupRoutine *routine = (TDEShmemSetupRoutine *) lfirst(lc); TDEShmemSetupRoutine *routine = (TDEShmemSetupRoutine *) lfirst(lc);
if (routine->required_shared_mem_size) if (routine->required_shared_mem_size)
sz = add_size(sz, routine->required_shared_mem_size()); sz = add_size(sz, routine->required_shared_mem_size());
} }
@ -57,12 +60,14 @@ Size TdeRequiredSharedMemorySize(void)
return MAXALIGN(sz); return MAXALIGN(sz);
} }
int TdeRequiredLocksCount(void) int
TdeRequiredLocksCount(void)
{ {
return TDE_LWLOCK_COUNT; return TDE_LWLOCK_COUNT;
} }
void TdeShmemInit(void) void
TdeShmemInit(void)
{ {
bool found; bool found;
TdeSharedState *tdeState; TdeSharedState *tdeState;
@ -89,6 +94,7 @@ void TdeShmemInit(void)
{ {
Size sz = 0; Size sz = 0;
TDEShmemSetupRoutine *routine = (TDEShmemSetupRoutine *) lfirst(lc); TDEShmemSetupRoutine *routine = (TDEShmemSetupRoutine *) lfirst(lc);
if (routine->init_shared_state) if (routine->init_shared_state)
{ {
sz = routine->init_shared_state(p); sz = routine->init_shared_state(p);
@ -113,12 +119,14 @@ void TdeShmemInit(void)
foreach(lc, registeredShmemRequests) foreach(lc, registeredShmemRequests)
{ {
TDEShmemSetupRoutine *routine = (TDEShmemSetupRoutine *) lfirst(lc); TDEShmemSetupRoutine *routine = (TDEShmemSetupRoutine *) lfirst(lc);
if (routine->init_dsa_area_objects) if (routine->init_dsa_area_objects)
routine->init_dsa_area_objects(dsa, tdeState->rawDsaArea); routine->init_dsa_area_objects(dsa, tdeState->rawDsaArea);
} }
ereport(LOG, (errmsg("setting no limit to DSA area of size %lu", dsa_area_size))); ereport(LOG, (errmsg("setting no limit to DSA area of size %lu", dsa_area_size)));
dsa_set_size_limit(dsa, -1); /* Let it grow outside the shared memory */ dsa_set_size_limit(dsa, -1); /* Let it grow outside the shared
* memory */
shmemInited = true; shmemInited = true;
} }
@ -130,9 +138,11 @@ static void
tde_shmem_shutdown(int code, Datum arg) tde_shmem_shutdown(int code, Datum arg)
{ {
ListCell *lc; ListCell *lc;
foreach(lc, registeredShmemRequests) foreach(lc, registeredShmemRequests)
{ {
TDEShmemSetupRoutine *routine = (TDEShmemSetupRoutine *) lfirst(lc); TDEShmemSetupRoutine *routine = (TDEShmemSetupRoutine *) lfirst(lc);
if (routine->shmem_kill) if (routine->shmem_kill)
routine->shmem_kill(code, arg); routine->shmem_kill(code, arg);
} }

@ -78,6 +78,7 @@ get_tde_tables_count(void)
{ {
List *tde_tables = get_all_tde_tables(); List *tde_tables = get_all_tde_tables();
int count = list_length(tde_tables); int count = list_length(tde_tables);
list_free(tde_tables); list_free(tde_tables);
return count; return count;
} }
@ -97,8 +98,10 @@ pg_tde_set_globalspace_dir(const char *dir)
char * char *
pg_tde_get_tde_file_dir(Oid dbOid, Oid spcOid) pg_tde_get_tde_file_dir(Oid dbOid, Oid spcOid)
{ {
/* `dbOid` is set to a value for the XLog keys caching but GetDatabasePath() /*
* expects it (`dbOid`) to be `0` if this is a global space. * `dbOid` is set to a value for the XLog keys caching but
* GetDatabasePath() expects it (`dbOid`) to be `0` if this is a global
* space.
*/ */
if (spcOid == GLOBALTABLESPACE_OID) if (spcOid == GLOBALTABLESPACE_OID)
{ {

@ -48,23 +48,26 @@ const EVP_CIPHER* cipher = NULL;
const EVP_CIPHER *cipher2 = NULL; const EVP_CIPHER *cipher2 = NULL;
int cipher_block_size = 0; int cipher_block_size = 0;
void AesInit(void) void
AesInit(void)
{ {
static int initialized = 0; static int initialized = 0;
if(!initialized) { if (!initialized)
{
OpenSSL_add_all_algorithms(); OpenSSL_add_all_algorithms();
ERR_load_crypto_strings(); ERR_load_crypto_strings();
cipher = EVP_aes_128_cbc(); cipher = EVP_aes_128_cbc();
cipher_block_size = EVP_CIPHER_block_size(cipher); // == buffer size cipher_block_size = EVP_CIPHER_block_size(cipher);
//== buffer size
cipher2 = EVP_aes_128_ecb(); cipher2 = EVP_aes_128_ecb();
initialized = 1; initialized = 1;
} }
} }
// TODO: a few things could be optimized in this. It's good enough for a prototype. /* TODO: a few things could be optimized in this. It's good enough for a prototype. */
static void static void
AesRunCtr(EVP_CIPHER_CTX **ctxPtr, int enc, const unsigned char *key, const unsigned char *iv, const unsigned char *in, int in_len, unsigned char *out, int *out_len) AesRunCtr(EVP_CIPHER_CTX **ctxPtr, int enc, const unsigned char *key, const unsigned char *iv, const unsigned char *in, int in_len, unsigned char *out, int *out_len)
{ {
@ -100,10 +103,12 @@ AesRunCtr(EVP_CIPHER_CTX** ctxPtr, int enc, const unsigned char* key, const unsi
} }
} }
static void AesRunCbc(int enc, const unsigned char* key, const unsigned char* iv, const unsigned char* in, int in_len, unsigned char* out, int* out_len) static void
AesRunCbc(int enc, const unsigned char *key, const unsigned char *iv, const unsigned char *in, int in_len, unsigned char *out, int *out_len)
{ {
int out_len_final = 0; int out_len_final = 0;
EVP_CIPHER_CTX *ctx = NULL; EVP_CIPHER_CTX *ctx = NULL;
ctx = EVP_CIPHER_CTX_new(); ctx = EVP_CIPHER_CTX_new();
EVP_CIPHER_CTX_init(ctx); EVP_CIPHER_CTX_init(ctx);
@ -143,8 +148,9 @@ static void AesRunCbc(int enc, const unsigned char* key, const unsigned char* iv
goto cleanup; goto cleanup;
} }
/* We encrypt one block (16 bytes) /*
* Our expectation is that the result should also be 16 bytes, without any additional padding * We encrypt one block (16 bytes) Our expectation is that the result
* should also be 16 bytes, without any additional padding
*/ */
*out_len += out_len_final; *out_len += out_len_final;
Assert(in_len == *out_len); Assert(in_len == *out_len);
@ -154,19 +160,22 @@ cleanup:
EVP_CIPHER_CTX_free(ctx); EVP_CIPHER_CTX_free(ctx);
} }
void AesEncrypt(const unsigned char* key, const unsigned char* iv, const unsigned char* in, int in_len, unsigned char* out, int* out_len) void
AesEncrypt(const unsigned char *key, const unsigned char *iv, const unsigned char *in, int in_len, unsigned char *out, int *out_len)
{ {
AesRunCbc(1, key, iv, in, in_len, out, out_len); AesRunCbc(1, key, iv, in, in_len, out, out_len);
} }
void AesDecrypt(const unsigned char* key, const unsigned char* iv, const unsigned char* in, int in_len, unsigned char* out, int* out_len) void
AesDecrypt(const unsigned char *key, const unsigned char *iv, const unsigned char *in, int in_len, unsigned char *out, int *out_len)
{ {
AesRunCbc(0, key, iv, in, in_len, out, out_len); AesRunCbc(0, key, iv, in, in_len, out, out_len);
} }
/* This function assumes that the out buffer is big enough: at least (blockNumber2 - blockNumber1) * 16 bytes /* This function assumes that the out buffer is big enough: at least (blockNumber2 - blockNumber1) * 16 bytes
*/ */
void Aes128EncryptedZeroBlocks(void* ctxPtr, const unsigned char* key, const char* iv_prefix, uint64_t blockNumber1, uint64_t blockNumber2, unsigned char* out) void
Aes128EncryptedZeroBlocks(void *ctxPtr, const unsigned char *key, const char *iv_prefix, uint64_t blockNumber1, uint64_t blockNumber2, unsigned char *out)
{ {
const unsigned char iv[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; const unsigned char iv[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
@ -178,10 +187,10 @@ void Aes128EncryptedZeroBlocks(void* ctxPtr, const unsigned char* key, const cha
for (int j = blockNumber1; j < blockNumber2; ++j) for (int j = blockNumber1; j < blockNumber2; ++j)
{ {
/* /*
* We have 16 bytes, and a 4 byte counter. The counter is the last 4 bytes. * We have 16 bytes, and a 4 byte counter. The counter is the last 4
* Technically, this isn't correct: the byte order of the counter depends * bytes. Technically, this isn't correct: the byte order of the
* on the endianness of the CPU running it. * counter depends on the endianness of the CPU running it. As this is
* As this is a generic limitation of Postgres, it's fine. * a generic limitation of Postgres, it's fine.
*/ */
memcpy(out + (16 * (j - blockNumber1)), iv_prefix, 12); memcpy(out + (16 * (j - blockNumber1)), iv_prefix, 12);
memcpy(out + (16 * (j - blockNumber1)) + 12, (char *) &j, 4); memcpy(out + (16 * (j - blockNumber1)) + 12, (char *) &j, 4);

@ -11,9 +11,11 @@
#include "keyring/keyring_api.h" #include "keyring/keyring_api.h"
#ifdef ENCRYPTION_DEBUG #ifdef ENCRYPTION_DEBUG
static void iv_prefix_debug(const char* iv_prefix, char* out_hex) static void
iv_prefix_debug(const char *iv_prefix, char *out_hex)
{
for (int i = 0; i < 16; ++i)
{ {
for(int i =0;i<16;++i) {
sprintf(out_hex + i * 2, "%02x", (int) *(iv_prefix + i)); sprintf(out_hex + i * 2, "%02x", (int) *(iv_prefix + i));
} }
out_hex[32] = 0; out_hex[32] = 0;
@ -23,11 +25,12 @@ static void iv_prefix_debug(const char* iv_prefix, char* out_hex)
static void static void
SetIVPrefix(ItemPointerData *ip, char *iv_prefix) SetIVPrefix(ItemPointerData *ip, char *iv_prefix)
{ {
/* We have up to 16 bytes for the entire IV /*
* The higher bytes (starting with 15) are used for the incrementing counter * We have up to 16 bytes for the entire IV The higher bytes (starting
* The lower bytes (in this case, 0..5) are used for the tuple identification * with 15) are used for the incrementing counter The lower bytes (in this
* Tuple identification is based on CTID, which currently is 48 bytes in * case, 0..5) are used for the tuple identification Tuple identification
* postgres: 4 bytes for the block id and 2 bytes for the position id * is based on CTID, which currently is 48 bytes in postgres: 4 bytes for
* the block id and 2 bytes for the position id
*/ */
iv_prefix[0] = ip->ip_blkid.bi_hi / 256; iv_prefix[0] = ip->ip_blkid.bi_hi / 256;
iv_prefix[1] = ip->ip_blkid.bi_hi % 256; iv_prefix[1] = ip->ip_blkid.bi_hi % 256;
@ -65,6 +68,7 @@ pg_tde_crypt_simple(const char* iv_prefix, uint32 start_offset, const char* data
#ifdef ENCRYPTION_DEBUG #ifdef ENCRYPTION_DEBUG
{ {
char ivp_debug[33]; char ivp_debug[33];
iv_prefix_debug(iv_prefix, ivp_debug); iv_prefix_debug(iv_prefix, ivp_debug);
ereport(LOG, ereport(LOG,
(errmsg("%s: Start offset: %lu Data_Len: %u, aes_start_block: %lu, aes_end_block: %lu, IV prefix: %s", (errmsg("%s: Start offset: %lu Data_Len: %u, aes_start_block: %lu, aes_end_block: %lu, IV prefix: %s",
@ -106,6 +110,7 @@ pg_tde_crypt_complex(const char* iv_prefix, uint32 start_offset, const char* dat
#ifdef ENCRYPTION_DEBUG #ifdef ENCRYPTION_DEBUG
{ {
char ivp_debug[33]; char ivp_debug[33];
iv_prefix_debug(iv_prefix, ivp_debug); iv_prefix_debug(iv_prefix, ivp_debug);
ereport(LOG, ereport(LOG,
(errmsg("%s: Batch-No:%d Start offset: %lu Data_Len: %u, batch_start_block: %lu, batch_end_block: %lu, IV prefix: %s", (errmsg("%s: Batch-No:%d Start offset: %lu Data_Len: %u, batch_start_block: %lu, batch_end_block: %lu, IV prefix: %s",
@ -114,29 +119,31 @@ pg_tde_crypt_complex(const char* iv_prefix, uint32 start_offset, const char* dat
#endif #endif
current_batch_bytes = ((batch_end_block - batch_start_block) * AES_BLOCK_SIZE) current_batch_bytes = ((batch_end_block - batch_start_block) * AES_BLOCK_SIZE)
- (batch_no > 0 ? 0 : aes_block_no); /* first batch skips `aes_block_no`-th bytes of enc_key */ - (batch_no > 0 ? 0 : aes_block_no); /* first batch skips
* `aes_block_no`-th bytes
* of enc_key */
if ((data_index + current_batch_bytes) > data_len) if ((data_index + current_batch_bytes) > data_len)
current_batch_bytes = data_len - data_index; current_batch_bytes = data_len - data_index;
for (uint32 i = 0; i < current_batch_bytes; ++i) for (uint32 i = 0; i < current_batch_bytes; ++i)
{ {
/* /*
* As the size of enc_key always is a multiple of 16 we * As the size of enc_key always is a multiple of 16 we start from
* start from `aes_block_no`-th index of the enc_key[] * `aes_block_no`-th index of the enc_key[] so N-th will be
* so N-th will be crypted with the same enc_key byte despite * crypted with the same enc_key byte despite what start_offset
* what start_offset the function was called with. * the function was called with. For example start_offset = 10;
* For example start_offset = 10; MAX_AES_ENC_BATCH_KEY_SIZE = 6: * MAX_AES_ENC_BATCH_KEY_SIZE = 6: data: [10 11 12
* data: [10 11 12 13 14 15 16] * 13 14 15 16] encKey: [...][0 1 2 3 4 5][0 1 2 3 4 5] so
* encKey: [...][0 1 2 3 4 5][0 1 2 3 4 5] * the 10th data byte is encoded with the 4th byte of the 2nd
* so the 10th data byte is encoded with the 4th byte of the 2nd enc_key etc. * enc_key etc. We need this shift so each byte will be coded the
* We need this shift so each byte will be coded the same despite * same despite the initial offset. Let's see the same data but
* the initial offset. * sent to the func starting from the offset 0: data: [0 1 2 3
* Let's see the same data but sent to the func starting from the offset 0: * 4 5 6 7 8 9 10 11 12 13 14 15 16] encKey: [0 1 2 3 4 5][0 1 2 3
* data: [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16] * 4 5][ 0 1 2 3 4 5] again, the 10th data byte is encoded
* encKey: [0 1 2 3 4 5][0 1 2 3 4 5][ 0 1 2 3 4 5] * with the 4th byte of the 2nd enc_key etc.
* again, the 10th data byte is encoded with the 4th byte of the 2nd enc_key etc.
*/ */
uint32 enc_key_index = i + (batch_no > 0 ? 0 : aes_block_no); uint32 enc_key_index = i + (batch_no > 0 ? 0 : aes_block_no);
out[data_index] = data[data_index] ^ enc_key[enc_key_index]; out[data_index] = data[data_index] ^ enc_key[enc_key_index];
data_index++; data_index++;
@ -157,7 +164,8 @@ pg_tde_crypt(const char* iv_prefix, uint32 start_offset, const char* data, uint3
if (data_len >= DATA_BYTES_PER_AES_BATCH) if (data_len >= DATA_BYTES_PER_AES_BATCH)
{ {
pg_tde_crypt_complex(iv_prefix, start_offset, data, data_len, out, key, context); pg_tde_crypt_complex(iv_prefix, start_offset, data, data_len, out, key, context);
} else }
else
{ {
pg_tde_crypt_simple(iv_prefix, start_offset, data, data_len, out, key, context); pg_tde_crypt_simple(iv_prefix, start_offset, data, data_len, out, key, context);
} }
@ -191,9 +199,9 @@ pg_tde_crypt_tuple(HeapTuple tuple, HeapTuple out_tuple, RelKeyData* key, const
} }
// ================================================================ /* ================================================================ */
// HELPER FUNCTIONS FOR ENCRYPTION /* HELPER FUNCTIONS FOR ENCRYPTION */
// ================================================================ /* ================================================================ */
OffsetNumber OffsetNumber
PGTdePageAddItemExtended(RelFileLocator rel, PGTdePageAddItemExtended(RelFileLocator rel,
@ -212,6 +220,7 @@ PGTdePageAddItemExtended(RelFileLocator rel,
char *toAddr = ((char *) phdr) + phdr->pd_upper + header_size; char *toAddr = ((char *) phdr) + phdr->pd_upper + header_size;
char *data = item + header_size; char *data = item + header_size;
uint32 data_len = size - header_size; uint32 data_len = size - header_size;
/* ctid stored in item is incorrect (not set) at this point */ /* ctid stored in item is incorrect (not set) at this point */
ItemPointerData ip; ItemPointerData ip;
RelKeyData *key = GetHeapBaiscRelationKey(rel); RelKeyData *key = GetHeapBaiscRelationKey(rel);
@ -257,7 +266,8 @@ AesEncryptKey(const TDEPrincipalKey *principal_key, const RelFileLocator *rlocat
* to note that memory is allocated in the TopMemoryContext so we expect this to be added * to note that memory is allocated in the TopMemoryContext so we expect this to be added
* to our key cache. * to our key cache.
*/ */
void AesDecryptKey(const TDEPrincipalKey *principal_key, const RelFileLocator *rlocator, RelKeyData **p_rel_key_data, RelKeyData *enc_rel_key_data, size_t *key_bytes) void
AesDecryptKey(const TDEPrincipalKey *principal_key, const RelFileLocator *rlocator, RelKeyData **p_rel_key_data, RelKeyData *enc_rel_key_data, size_t *key_bytes)
{ {
unsigned char iv[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; unsigned char iv[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

@ -22,7 +22,8 @@
#define FILE_KEYRING_TYPE "file" #define FILE_KEYRING_TYPE "file"
#define VAULTV2_KEYRING_TYPE "vault-v2" #define VAULTV2_KEYRING_TYPE "vault-v2"
#define MAX_PROVIDER_NAME_LEN 128 /* pg_tde_key_provider's provider_name size*/ #define MAX_PROVIDER_NAME_LEN 128 /* pg_tde_key_provider's provider_name
* size */
#define MAX_VAULT_V2_KEY_LEN 128 /* From hashi corp docs */ #define MAX_VAULT_V2_KEY_LEN 128 /* From hashi corp docs */
#define MAX_KEYRING_OPTION_LEN 1024 #define MAX_KEYRING_OPTION_LEN 1024
typedef enum ProviderType typedef enum ProviderType

@ -27,26 +27,29 @@ typedef enum
typedef struct TDEShmemSetupRoutine typedef struct TDEShmemSetupRoutine
{ {
/* init_shared_state gets called at the time of extension load /*
* you can initialize the data structures required to be placed in * init_shared_state gets called at the time of extension load you can
* shared memory in this callback * initialize the data structures required to be placed in shared memory
* The callback must return the size of the shared memory area acquired. * in this callback The callback must return the size of the shared memory
* The argument to the function is the start of the shared memory address * area acquired. The argument to the function is the start of the shared
* that can be used to store the shared data structures. * memory address that can be used to store the shared data structures.
*/ */
Size (*init_shared_state) (void *raw_dsa_area); Size (*init_shared_state) (void *raw_dsa_area);
/* /*
* shmem_startup gets called at the time of postmaster shutdown * shmem_startup gets called at the time of postmaster shutdown
*/ */
void (*shmem_kill) (int code, Datum arg); void (*shmem_kill) (int code, Datum arg);
/* /*
* The callback must return the size of the shared memory acquired. * The callback must return the size of the shared memory acquired.
*/ */
Size (*required_shared_mem_size) (void); Size (*required_shared_mem_size) (void);
/* /*
* Gets called after all shared memory structures are initialized and * Gets called after all shared memory structures are initialized and here
* here you can create shared memory hash tables or any other shared * you can create shared memory hash tables or any other shared objects
* objects that needs to live in DSA area. * that needs to live in DSA area.
*/ */
void (*init_dsa_area_objects) (dsa_area *dsa, void *raw_dsa_area); void (*init_dsa_area_objects) (dsa_area *dsa, void *raw_dsa_area);
} TDEShmemSetupRoutine; } TDEShmemSetupRoutine;

@ -19,7 +19,8 @@
#include <stdbool.h> #include <stdbool.h>
#include <curl/curl.h> #include <curl/curl.h>
typedef struct CurlString { typedef struct CurlString
{
char *ptr; char *ptr;
size_t len; size_t len;
} CurlString; } CurlString;
@ -28,4 +29,4 @@ extern CURL* keyringCurl;
bool curlSetupSession(const char *url, const char *caFile, CurlString *outStr); bool curlSetupSession(const char *url, const char *caFile, CurlString *outStr);
#endif //KEYRING_CURL_H #endif /* //KEYRING_CURL_H */

@ -14,4 +14,4 @@
extern bool InstallVaultV2Keyring(void); extern bool InstallVaultV2Keyring(void);
#endif // KEYRING_FILE_H #endif /* KEYRING_FILE_H */

@ -19,10 +19,10 @@
* ---------- * ----------
*/ */
//#define ENCRYPTION_DEBUG 1 /* #define ENCRYPTION_DEBUG 1 */
//#define KEYRING_DEBUG 1 /* #define KEYRING_DEBUG 1 */
//#define TDE_FORK_DEBUG 1 /* #define TDE_FORK_DEBUG 1 */
// #define TDE_XLOG_DEBUG 1 /* #define TDE_XLOG_DEBUG 1 */
#define tdeheap_fill_tuple heap_fill_tuple #define tdeheap_fill_tuple heap_fill_tuple
#define tdeheap_form_tuple heap_form_tuple #define tdeheap_form_tuple heap_form_tuple

@ -34,9 +34,11 @@ static KeyProviders *
find_key_provider(ProviderType type) find_key_provider(ProviderType type)
{ {
ListCell *lc; ListCell *lc;
foreach(lc, registeredKeyProviders) foreach(lc, registeredKeyProviders)
{ {
KeyProviders *kp = (KeyProviders *) lfirst(lc); KeyProviders *kp = (KeyProviders *) lfirst(lc);
if (kp->type == type) if (kp->type == type)
{ {
return kp; return kp;
@ -49,9 +51,11 @@ static KeyProviders *
find_key_provider(ProviderType type) find_key_provider(ProviderType type)
{ {
SimplePtrListCell *lc; SimplePtrListCell *lc;
for (lc = registeredKeyProviders.head; lc; lc = lc->next) for (lc = registeredKeyProviders.head; lc; lc = lc->next)
{ {
KeyProviders *kp = (KeyProviders *) lc->ptr; KeyProviders *kp = (KeyProviders *) lc->ptr;
if (kp->type == type) if (kp->type == type)
{ {
return kp; return kp;
@ -61,7 +65,8 @@ find_key_provider(ProviderType type)
} }
#endif /* !FRONTEND */ #endif /* !FRONTEND */
bool RegisterKeyProvider(const TDEKeyringRoutine *routine, ProviderType type) bool
RegisterKeyProvider(const TDEKeyringRoutine *routine, ProviderType type)
{ {
KeyProviders *kp; KeyProviders *kp;
@ -79,6 +84,7 @@ bool RegisterKeyProvider(const TDEKeyringRoutine *routine, ProviderType type)
#ifndef FRONTEND #ifndef FRONTEND
MemoryContext oldcontext; MemoryContext oldcontext;
oldcontext = MemoryContextSwitchTo(TopMemoryContext); oldcontext = MemoryContextSwitchTo(TopMemoryContext);
#endif #endif
kp = palloc(sizeof(KeyProviders)); kp = palloc(sizeof(KeyProviders));
@ -98,6 +104,7 @@ keyInfo *
KeyringGetKey(GenericKeyring *keyring, const char *key_name, bool throw_error, KeyringReturnCodes * returnCode) KeyringGetKey(GenericKeyring *keyring, const char *key_name, bool throw_error, KeyringReturnCodes * returnCode)
{ {
KeyProviders *kp = find_key_provider(keyring->type); KeyProviders *kp = find_key_provider(keyring->type);
if (kp == NULL) if (kp == NULL)
{ {
ereport(throw_error ? ERROR : WARNING, ereport(throw_error ? ERROR : WARNING,
@ -112,6 +119,7 @@ KeyringReturnCodes
KeyringStoreKey(GenericKeyring *keyring, keyInfo *key, bool throw_error) KeyringStoreKey(GenericKeyring *keyring, keyInfo *key, bool throw_error)
{ {
KeyProviders *kp = find_key_provider(keyring->type); KeyProviders *kp = find_key_provider(keyring->type);
if (kp == NULL) if (kp == NULL)
{ {
ereport(throw_error ? ERROR : WARNING, ereport(throw_error ? ERROR : WARNING,
@ -125,6 +133,7 @@ keyInfo *
KeyringGenerateNewKey(const char *key_name, unsigned key_len) KeyringGenerateNewKey(const char *key_name, unsigned key_len)
{ {
keyInfo *key; keyInfo *key;
Assert(key_len <= 32); Assert(key_len <= 32);
key = palloc(sizeof(keyInfo)); key = palloc(sizeof(keyInfo));
key->data.len = key_len; key->data.len = key_len;
@ -141,6 +150,7 @@ keyInfo *
KeyringGenerateNewKeyAndStore(GenericKeyring *keyring, const char *key_name, unsigned key_len, bool throw_error) KeyringGenerateNewKeyAndStore(GenericKeyring *keyring, const char *key_name, unsigned key_len, bool throw_error)
{ {
keyInfo *key = KeyringGenerateNewKey(key_name, key_len); keyInfo *key = KeyringGenerateNewKey(key_name, key_len);
if (key == NULL) if (key == NULL)
{ {
ereport(throw_error ? ERROR : WARNING, ereport(throw_error ? ERROR : WARNING,

@ -17,11 +17,14 @@
CURL *keyringCurl = NULL; CURL *keyringCurl = NULL;
static static
size_t write_func(void *ptr, size_t size, size_t nmemb, struct CurlString *s) size_t
write_func(void *ptr, size_t size, size_t nmemb, struct CurlString *s)
{ {
size_t new_len = s->len + size * nmemb; size_t new_len = s->len + size * nmemb;
s->ptr = repalloc(s->ptr, new_len + 1); s->ptr = repalloc(s->ptr, new_len + 1);
if (s->ptr == NULL) { if (s->ptr == NULL)
{
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
memcpy(s->ptr + s->len, ptr, size * nmemb); memcpy(s->ptr + s->len, ptr, size * nmemb);
@ -31,33 +34,49 @@ size_t write_func(void *ptr, size_t size, size_t nmemb, struct CurlString *s)
return size * nmemb; return size * nmemb;
} }
bool curlSetupSession(const char* url, const char* caFile, CurlString* outStr) bool
curlSetupSession(const char *url, const char *caFile, CurlString *outStr)
{ {
if (keyringCurl == NULL) if (keyringCurl == NULL)
{ {
keyringCurl = curl_easy_init(); keyringCurl = curl_easy_init();
if(keyringCurl == NULL) return 0; if (keyringCurl == NULL)
} else { return 0;
}
else
{
curl_easy_reset(keyringCurl); curl_easy_reset(keyringCurl);
} }
if(curl_easy_setopt(keyringCurl, CURLOPT_SSL_VERIFYPEER, 1) != CURLE_OK) return 0; if (curl_easy_setopt(keyringCurl, CURLOPT_SSL_VERIFYPEER, 1) != CURLE_OK)
if(curl_easy_setopt(keyringCurl, CURLOPT_USE_SSL, CURLUSESSL_ALL) != CURLE_OK) return 0; return 0;
if (curl_easy_setopt(keyringCurl, CURLOPT_USE_SSL, CURLUSESSL_ALL) != CURLE_OK)
return 0;
if (caFile != NULL && strlen(caFile) != 0) if (caFile != NULL && strlen(caFile) != 0)
{ {
if(curl_easy_setopt(keyringCurl, CURLOPT_CAINFO, caFile) != CURLE_OK) return 0; if (curl_easy_setopt(keyringCurl, CURLOPT_CAINFO, caFile) != CURLE_OK)
return 0;
} }
if(curl_easy_setopt(keyringCurl, CURLOPT_FOLLOWLOCATION, 1L) != CURLE_OK) return 0; if (curl_easy_setopt(keyringCurl, CURLOPT_FOLLOWLOCATION, 1L) != CURLE_OK)
if(curl_easy_setopt(keyringCurl, CURLOPT_CONNECTTIMEOUT, 3) != CURLE_OK) return 0; return 0;
if(curl_easy_setopt(keyringCurl, CURLOPT_TIMEOUT, 10) != CURLE_OK) return 0; if (curl_easy_setopt(keyringCurl, CURLOPT_CONNECTTIMEOUT, 3) != CURLE_OK)
if(curl_easy_setopt(keyringCurl, CURLOPT_HTTP_VERSION,(long)CURL_HTTP_VERSION_1_1) != CURLE_OK) return 0; return 0;
if(curl_easy_setopt(keyringCurl, CURLOPT_WRITEFUNCTION,write_func) != CURLE_OK) return 0; if (curl_easy_setopt(keyringCurl, CURLOPT_TIMEOUT, 10) != CURLE_OK)
if(curl_easy_setopt(keyringCurl, CURLOPT_WRITEDATA,outStr) != CURLE_OK) return 0; return 0;
if(curl_easy_setopt(keyringCurl, CURLOPT_URL, url) != CURLE_OK) return 0; if (curl_easy_setopt(keyringCurl, CURLOPT_HTTP_VERSION, (long) CURL_HTTP_VERSION_1_1) != CURLE_OK)
return 0;
if(curl_easy_setopt(keyringCurl, CURLOPT_POSTFIELDS, NULL) != CURLE_OK) return 0; if (curl_easy_setopt(keyringCurl, CURLOPT_WRITEFUNCTION, write_func) != CURLE_OK)
if(curl_easy_setopt(keyringCurl, CURLOPT_POST, 0) != CURLE_OK) return 0; return 0;
if (curl_easy_setopt(keyringCurl, CURLOPT_WRITEDATA, outStr) != CURLE_OK)
return 0;
if (curl_easy_setopt(keyringCurl, CURLOPT_URL, url) != CURLE_OK)
return 0;
if (curl_easy_setopt(keyringCurl, CURLOPT_POSTFIELDS, NULL) != CURLE_OK)
return 0;
if (curl_easy_setopt(keyringCurl, CURLOPT_POST, 0) != CURLE_OK)
return 0;
return 1; return 1;
} }

@ -65,7 +65,8 @@ get_key_by_name(GenericKeyring* keyring, const char* key_name, bool throw_error,
if (bytes_read == 0) if (bytes_read == 0)
{ {
/* /*
* Empty keyring file is considered as a valid keyring file that has no keys * Empty keyring file is considered as a valid keyring file that
* has no keys
*/ */
close(fd); close(fd);
pfree(key); pfree(key);

@ -77,7 +77,8 @@ const TDEKeyringRoutine keyringVaultV2Routine = {
}; };
bool InstallVaultV2Keyring(void) bool
InstallVaultV2Keyring(void)
{ {
return RegisterKeyProvider(&keyringVaultV2Routine, VAULT_V2_KEY_PROVIDER); return RegisterKeyProvider(&keyringVaultV2Routine, VAULT_V2_KEY_PROVIDER);
} }
@ -88,17 +89,21 @@ curl_setup_token(VaultV2Keyring *keyring)
if (curlList == NULL) if (curlList == NULL)
{ {
char tokenHeader[256]; char tokenHeader[256];
strcpy(tokenHeader, "X-Vault-Token:"); strcpy(tokenHeader, "X-Vault-Token:");
strcat(tokenHeader, keyring->vault_token); strcat(tokenHeader, keyring->vault_token);
curlList = curl_slist_append(curlList, tokenHeader); curlList = curl_slist_append(curlList, tokenHeader);
if(curlList == NULL) return 0; if (curlList == NULL)
return 0;
curlList = curl_slist_append(curlList, "Content-Type: application/json"); curlList = curl_slist_append(curlList, "Content-Type: application/json");
if(curlList == NULL) return 0; if (curlList == NULL)
return 0;
} }
if(curl_easy_setopt(keyringCurl, CURLOPT_HTTPHEADER, curlList) != CURLE_OK) return 0; if (curl_easy_setopt(keyringCurl, CURLOPT_HTTPHEADER, curlList) != CURLE_OK)
return 0;
return 1; return 1;
} }
@ -125,7 +130,8 @@ curl_perform(VaultV2Keyring *keyring, const char *url, CurlString *outStr, long
if (postData != NULL) if (postData != NULL)
{ {
if(curl_easy_setopt(keyringCurl, CURLOPT_POSTFIELDS, postData) != CURLE_OK) return 0; if (curl_easy_setopt(keyringCurl, CURLOPT_POSTFIELDS, postData) != CURLE_OK)
return 0;
} }
ret = curl_easy_perform(keyringCurl); ret = curl_easy_perform(keyringCurl);
@ -135,7 +141,8 @@ curl_perform(VaultV2Keyring *keyring, const char *url, CurlString *outStr, long
return 0; return 0;
} }
if(curl_easy_getinfo(keyringCurl, CURLINFO_RESPONSE_CODE, httpCode) != CURLE_OK) return 0; if (curl_easy_getinfo(keyringCurl, CURLINFO_RESPONSE_CODE, httpCode) != CURLE_OK)
return 0;
#if KEYRING_DEBUG #if KEYRING_DEBUG
elog(DEBUG2, "Vault response [%li] '%s'", *httpCode, outStr->ptr != NULL ? outStr->ptr : ""); elog(DEBUG2, "Vault response [%li] '%s'", *httpCode, outStr->ptr != NULL ? outStr->ptr : "");
@ -172,8 +179,11 @@ set_key_by_name(GenericKeyring* keyring, keyInfo *key, bool throw_error)
Assert(key != NULL); Assert(key != NULL);
// Since we are only building a very limited JSON with a single base64 string, we build it by hand /*
// Simpler than using the limited pg json api * Since we are only building a very limited JSON with a single base64
* string, we build it by hand
*/
/* Simpler than using the limited pg json api */
keyLen = pg_b64_encode((char *) key->data.data, key->data.len, keyData, 64); keyLen = pg_b64_encode((char *) key->data.data, key->data.len, keyData, 64);
keyData[keyLen] = 0; keyData[keyLen] = 0;

@ -122,14 +122,20 @@ _PG_init(void)
RegisterStorageMgr(); RegisterStorageMgr();
} }
Datum pg_tde_extension_initialize(PG_FUNCTION_ARGS) Datum
pg_tde_extension_initialize(PG_FUNCTION_ARGS)
{ {
/* Initialize the TDE map */ /* Initialize the TDE map */
XLogExtensionInstall xlrec; XLogExtensionInstall xlrec;
xlrec.database_id = MyDatabaseId; xlrec.database_id = MyDatabaseId;
xlrec.tablespace_id = MyDatabaseTableSpace; xlrec.tablespace_id = MyDatabaseTableSpace;
run_extension_install_callbacks(&xlrec, false); run_extension_install_callbacks(&xlrec, false);
/* Also put this info in xlog, so we can replicate the same on the other side */
/*
* Also put this info in xlog, so we can replicate the same on the other
* side
*/
XLogBeginInsert(); XLogBeginInsert();
XLogRegisterData((char *) &xlrec, sizeof(XLogExtensionInstall)); XLogRegisterData((char *) &xlrec, sizeof(XLogExtensionInstall));
XLogInsert(RM_TDERMGR_ID, XLOG_TDE_EXTENSION_INSTALL_KEY); XLogInsert(RM_TDERMGR_ID, XLOG_TDE_EXTENSION_INSTALL_KEY);
@ -149,7 +155,8 @@ extension_install_redo(XLogExtensionInstall *xlrec)
* run at the time of pg_tde extension installs. * run at the time of pg_tde extension installs.
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
void on_ext_install(pg_tde_on_ext_install_callback function, void *arg) void
on_ext_install(pg_tde_on_ext_install_callback function, void *arg)
{ {
if (on_ext_install_index >= MAX_ON_INSTALLS) if (on_ext_install_index >= MAX_ON_INSTALLS)
ereport(FATAL, ereport(FATAL,
@ -171,10 +178,10 @@ run_extension_install_callbacks(XLogExtensionInstall* xlrec , bool redo)
{ {
int i; int i;
int tde_table_count = 0; int tde_table_count = 0;
/* /*
* Get the number of tde tables in this database * Get the number of tde tables in this database should always be zero.
* should always be zero. But still, it prevents * But still, it prevents the cleanup if someone explicitly calls this
* the cleanup if someone explicitly calls this
* function. * function.
*/ */
if (!redo) if (!redo)

@ -110,7 +110,8 @@ pg_tde_ddl_command_start_capture(PG_FUNCTION_ARGS)
if (stmt->accessMethod && strcmp(stmt->accessMethod, "tde_heap") == 0) if (stmt->accessMethod && strcmp(stmt->accessMethod, "tde_heap") == 0)
{ {
tdeCurrentCreateEvent.encryptMode = true; tdeCurrentCreateEvent.encryptMode = true;
} else if ((stmt->accessMethod == NULL || stmt->accessMethod[0] ==0) && strcmp(default_table_access_method, "tde_heap") == 0) }
else if ((stmt->accessMethod == NULL || stmt->accessMethod[0] == 0) && strcmp(default_table_access_method, "tde_heap") == 0)
{ {
tdeCurrentCreateEvent.encryptMode = true; tdeCurrentCreateEvent.encryptMode = true;
} }
@ -151,7 +152,10 @@ pg_tde_ddl_command_start_capture(PG_FUNCTION_ARGS)
} }
} }
// TODO: also check for tablespace change, if current or new AM is tde_heap! /*
* TODO: also check for tablespace change, if current or new AM is
* tde_heap!
*/
if (tdeCurrentCreateEvent.encryptMode) if (tdeCurrentCreateEvent.encryptMode)
{ {

@ -14,6 +14,7 @@ typedef struct TDESMgrRelationData
{ {
/* parent data */ /* parent data */
SMgrRelationData reln; SMgrRelationData reln;
/* /*
* for md.c; per-fork arrays of the number of open segments * for md.c; per-fork arrays of the number of open segments
* (md_num_open_segs) and the segments themselves (md_seg_fds). * (md_num_open_segs) and the segments themselves (md_seg_fds).
@ -45,7 +46,7 @@ tde_smgr_get_key(SMgrRelation reln)
if (IsCatalogRelationOid(reln->smgr_rlocator.locator.relNumber)) if (IsCatalogRelationOid(reln->smgr_rlocator.locator.relNumber))
{ {
// do not try to encrypt/decrypt catalog tables /* do not try to encrypt/decrypt catalog tables */
return NULL; return NULL;
} }
@ -59,7 +60,7 @@ tde_smgr_get_key(SMgrRelation reln)
event = GetCurrentTdeCreateEvent(); event = GetCurrentTdeCreateEvent();
// see if we have a key for the relation, and return if yes /* see if we have a key for the relation, and return if yes */
rkd = GetSMGRRelationKey(reln->smgr_rlocator.locator); rkd = GetSMGRRelationKey(reln->smgr_rlocator.locator);
if (rkd != NULL) if (rkd != NULL)
@ -67,17 +68,20 @@ tde_smgr_get_key(SMgrRelation reln)
return rkd; return rkd;
} }
// if this is a CREATE TABLE, we have to generate the key /* if this is a CREATE TABLE, we have to generate the key */
if (event->encryptMode == true && event->eventType == TDE_TABLE_CREATE_EVENT) if (event->encryptMode == true && event->eventType == TDE_TABLE_CREATE_EVENT)
{ {
return pg_tde_create_smgr_key(&reln->smgr_rlocator.locator); return pg_tde_create_smgr_key(&reln->smgr_rlocator.locator);
} }
// if this is a CREATE INDEX, we have to load the key based on the table /* if this is a CREATE INDEX, we have to load the key based on the table */
if (event->encryptMode == true && event->eventType == TDE_INDEX_CREATE_EVENT) if (event->encryptMode == true && event->eventType == TDE_INDEX_CREATE_EVENT)
{ {
// For now keep it simple and create separate key for indexes /* For now keep it simple and create separate key for indexes */
// Later we might modify the map infrastructure to support the same keys /*
* Later we might modify the map infrastructure to support the same
* keys
*/
return pg_tde_create_smgr_key(&reln->smgr_rlocator.locator); return pg_tde_create_smgr_key(&reln->smgr_rlocator.locator);
} }
@ -106,10 +110,12 @@ tde_mdwritev(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
for (int i = 0; i < nblocks; ++i) for (int i = 0; i < nblocks; ++i)
{ {
int out_len = BLCKSZ; int out_len = BLCKSZ;
local_buffers[i] = &local_blocks_aligned[i * BLCKSZ]; local_buffers[i] = &local_blocks_aligned[i * BLCKSZ];
BlockNumber bn = blocknum + i; BlockNumber bn = blocknum + i;
unsigned char iv[16] = {0,}; unsigned char iv[16] = {0,};
memcpy(iv + 4, &bn, sizeof(BlockNumber)); memcpy(iv + 4, &bn, sizeof(BlockNumber));
AesEncrypt(rkd->internal_key.key, iv, ((char **) buffers)[i], BLCKSZ, local_buffers[i], &out_len); AesEncrypt(rkd->internal_key.key, iv, ((char **) buffers)[i], BLCKSZ, local_buffers[i], &out_len);
@ -179,11 +185,20 @@ tde_mdreadv(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
{ {
if (((char **) buffers)[i][j] != 0) if (((char **) buffers)[i][j] != 0)
{ {
// Postgres creates all zero blocks in an optimized route, which we do not try /*
// to encrypt. * Postgres creates all zero blocks in an optimized route,
// Instead we detect if a block is all zero at decryption time, and * which we do not try
// leave it as is. */
// This could be a security issue later, but it is a good first prototype /* to encrypt. */
/*
* Instead we detect if a block is all zero at decryption
* time, and
*/
/* leave it as is. */
/*
* This could be a security issue later, but it is a good
* first prototype
*/
allZero = false; allZero = false;
break; break;
} }
@ -201,10 +216,19 @@ static void
tde_mdcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo) tde_mdcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo)
{ {
TDESMgrRelation tdereln = (TDESMgrRelation) reln; TDESMgrRelation tdereln = (TDESMgrRelation) reln;
// This is the only function that gets called during actual CREATE TABLE/INDEX (EVENT TRIGGER)
// so we create the key here by loading it /*
// Later calls then decide to encrypt or not based on the existence of the key * This is the only function that gets called during actual CREATE
* TABLE/INDEX (EVENT TRIGGER)
*/
/* so we create the key here by loading it */
/*
* Later calls then decide to encrypt or not based on the existence of the
* key
*/
RelKeyData *key = tde_smgr_get_key(reln); RelKeyData *key = tde_smgr_get_key(reln);
if (key) if (key)
{ {
tdereln->encrypted_relation = true; tdereln->encrypted_relation = true;
@ -226,6 +250,7 @@ tde_mdopen(SMgrRelation reln)
{ {
TDESMgrRelation tdereln = (TDESMgrRelation) reln; TDESMgrRelation tdereln = (TDESMgrRelation) reln;
RelKeyData *key = tde_smgr_get_key(reln); RelKeyData *key = tde_smgr_get_key(reln);
if (key) if (key)
{ {
tdereln->encrypted_relation = true; tdereln->encrypted_relation = true;
@ -260,16 +285,18 @@ static const struct f_smgr tde_smgr = {
.smgr_registersync = mdregistersync, .smgr_registersync = mdregistersync,
}; };
void RegisterStorageMgr(void) void
RegisterStorageMgr(void)
{ {
tde_smgr_id = smgr_register(&tde_smgr, sizeof(TDESMgrRelationData)); tde_smgr_id = smgr_register(&tde_smgr, sizeof(TDESMgrRelationData));
// TODO: figure out how this part should work in a real extension /* TODO: figure out how this part should work in a real extension */
storage_manager_id = tde_smgr_id; storage_manager_id = tde_smgr_id;
} }
#else #else
void RegisterStorageMgr(void) void
RegisterStorageMgr(void)
{ {
} }
#endif /* PERCONA_EXT */ #endif /* PERCONA_EXT */

@ -65,7 +65,8 @@ pg_tde_subxact_callback(SubXactEvent event, SubTransactionId mySubid,
ereport(DEBUG2, ereport(DEBUG2,
(errmsg("pg_tde_subxact_callback: aborting subtransaction"))); (errmsg("pg_tde_subxact_callback: aborting subtransaction")));
do_pending_deletes(false); do_pending_deletes(false);
} else if (event == SUBXACT_EVENT_COMMIT_SUB) }
else if (event == SUBXACT_EVENT_COMMIT_SUB)
{ {
ereport(DEBUG2, ereport(DEBUG2,
(errmsg("pg_tde_subxact_callback: committing subtransaction"))); (errmsg("pg_tde_subxact_callback: committing subtransaction")));
@ -77,6 +78,7 @@ void
RegisterEntryForDeletion(const RelFileLocator *rlocator, off_t map_entry_offset, bool atCommit) RegisterEntryForDeletion(const RelFileLocator *rlocator, off_t map_entry_offset, bool atCommit)
{ {
PendingMapEntryDelete *pending; PendingMapEntryDelete *pending;
pending = (PendingMapEntryDelete *) MemoryContextAlloc(TopMemoryContext, sizeof(PendingMapEntryDelete)); pending = (PendingMapEntryDelete *) MemoryContextAlloc(TopMemoryContext, sizeof(PendingMapEntryDelete));
pending->map_entry_offset = map_entry_offset; pending->map_entry_offset = map_entry_offset;
memcpy(&pending->rlocator, rlocator, sizeof(RelFileLocator)); memcpy(&pending->rlocator, rlocator, sizeof(RelFileLocator));

@ -0,0 +1,113 @@
BulkInsertStateData
BulkInsertStateData
BulkInsertStateData
BulkInsertStateData
CurlString
FileKeyring
GenericKeyring
HeapPageFreeze
HeapPageFreeze
HeapScanDescData
HeapScanDescData
HeapScanDescData
HeapScanDescData
HeapTupleFreeze
HeapTupleFreeze
IndexDeleteCounts
IndexDeleteCounts
IndexFetchHeapData
IndexFetchHeapData
InternalKey
JsonKeringSemState
JsonKeyringField
JsonKeyringState
JsonVaultRespField
JsonVaultRespSemState
JsonVaultRespState
KeyProviders
KeyringProvideRecord
KeyringProviderXLRecord
KeyringReturnCode
LVPagePruneState
LVRelState
LVRelState
LVSavedErrInfo
LVSavedErrInfo
LogicalRewriteMappingData
LogicalRewriteMappingData
PendingMapEntryDelete
ProviderScanType
PruneFreezeResult
RelKeyCache
RelKeyCacheRec
RelKeyData
RewriteMappingDataEntry
RewriteMappingDataEntry
RewriteMappingFile
RewriteMappingFile
RewriteStateData
RewriteStateData
RewriteStateData
RewriteStateData *RewriteState;
TDEBufferHeapTupleTableSlot
TDEFileHeader
TDEKeyringRoutine
TDELocalState
TDELockTypes
TDEMapEntry
TDEMapFilePath
TDEPrincipalKey
TDEPrincipalKeyId
TDEPrincipalKeyInfo
TDEShmemSetupRoutine
TdeCreateEvent
TdeCreateEventType
TdeKeyProviderInfoSharedState
TdePrincipalKeySharedState
TdePrincipalKeylocalState
TdeSharedState
VaultV2Keyring
XLogExtensionInstall
XLogPrincipalKeyRotate
XLogRelKey
itemIdCompactData
itemIdCompactData
keyData
keyInfo
keyName
xl_multi_insert_tuple
xl_multi_insert_tuple
xl_tdeheap_confirm
xl_tdeheap_confirm
xl_tdeheap_delete
xl_tdeheap_delete
xl_tdeheap_freeze_page
xl_tdeheap_freeze_plan
xl_tdeheap_header
xl_tdeheap_header
xl_tdeheap_inplace
xl_tdeheap_inplace
xl_tdeheap_insert
xl_tdeheap_insert
xl_tdeheap_lock
xl_tdeheap_lock
xl_tdeheap_lock_updated
xl_tdeheap_lock_updated
xl_tdeheap_multi_insert
xl_tdeheap_multi_insert
xl_tdeheap_new_cid
xl_tdeheap_new_cid
xl_tdeheap_prune
xl_tdeheap_prune
xl_tdeheap_rewrite_mapping
xl_tdeheap_rewrite_mapping
xl_tdeheap_truncate
xl_tdeheap_truncate
xl_tdeheap_update
xl_tdeheap_update
xl_tdeheap_vacuum
xl_tdeheap_visible
xl_tdeheap_visible
xlhp_freeze_plan
xlhp_freeze_plans
xlhp_prune_items
Loading…
Cancel
Save