forked from huawei/openGauss-server
1117 lines
46 KiB
C++
1117 lines
46 KiB
C++
/*
|
|
* Copyright (c) 2020 Huawei Technologies Co.,Ltd.
|
|
*
|
|
* openGauss is licensed under Mulan PSL v2.
|
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
* You may obtain a copy of Mulan PSL v2 at:
|
|
*
|
|
* http://license.coscl.org.cn/MulanPSL2
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
* See the Mulan PSL v2 for more details.
|
|
* -------------------------------------------------------------------------
|
|
*
|
|
* client_logic.cpp
|
|
*
|
|
* IDENTIFICATION
|
|
* src\common\backend\client_logic\client_logic.cpp
|
|
*
|
|
* -------------------------------------------------------------------------
|
|
*/
|
|
|
|
#include "client_logic/client_logic.h"
|
|
#include "client_logic/client_logic_common.h"
|
|
#include "access/sysattr.h"
|
|
#include "commands/dbcommands.h"
|
|
#include "catalog/dependency.h"
|
|
#include "catalog/pg_namespace.h"
|
|
#include "client_logic/cache.h"
|
|
#include "client_logic/client_logic_common.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/timestamp.h"
|
|
#include "utils/acl.h"
|
|
#include "access/heapam.h"
|
|
#include "utils/snapmgr.h"
|
|
#include "utils/syscache.h"
|
|
#include "utils/lsyscache.h"
|
|
#include "storage/lock/lock.h"
|
|
#include "access/xact.h"
|
|
#include "catalog/indexing.h"
|
|
#include "catalog/namespace.h"
|
|
#include "commands/sec_rls_cmds.h"
|
|
#include "rewrite/rewriteRlsPolicy.h"
|
|
#include "commands/tablecmds.h"
|
|
#include "nodes/pg_list.h"
|
|
#include "tcop/utility.h"
|
|
#include "pgxc/pgxc.h"
|
|
#include "utils/fmgroids.h"
|
|
#include "MurmurHash3.h"
|
|
|
|
#define INIT_VALUES_NULLS(type, id) \
|
|
do { \
|
|
HeapTuple htup = NULL; \
|
|
Relation rel = heap_open(id, RowExclusiveLock); \
|
|
bool type##_nulls[Natts_gs_sec_##type]; \
|
|
Datum type##_values[Natts_gs_sec_##type]; \
|
|
int rc = memset_s(type##_values, sizeof(type##_values), 0, sizeof(type##_values)); \
|
|
securec_check(rc, "\0", "\0"); \
|
|
rc = memset_s(type##_nulls, sizeof(type##_nulls), false, sizeof(type##_nulls)); \
|
|
securec_check(rc, "\0", "\0"); \
|
|
} while (0)
|
|
|
|
static bool get_cmk_name(const Oid global_key_id, NameData &cmk_name);
|
|
|
|
static Oid check_namespace(const List *key_name, Node * const stmt, char **keyname)
|
|
{
|
|
Oid namespace_id;
|
|
AclResult aclresult;
|
|
namespace_id = QualifiedNameGetCreationNamespace(key_name, keyname);
|
|
|
|
/* Check we have creation rights in target namespace */
|
|
aclresult = pg_namespace_aclcheck(namespace_id, GetUserId(), ACL_CREATE);
|
|
if (aclresult != ACLCHECK_OK)
|
|
aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(namespace_id));
|
|
|
|
/*
|
|
* @Temp Table. Lock Cluster after determine whether is a temp object,
|
|
* so we can decide if locking other coordinator
|
|
*/
|
|
#ifdef ENABLE_MULTIPLE_NODES
|
|
pgxc_lock_for_utility_stmt(stmt, namespace_id == u_sess->catalog_cxt.myTempNamespace);
|
|
#endif
|
|
return namespace_id;
|
|
}
|
|
static Oid check_user(const Oid namespace_id)
|
|
{
|
|
Oid keyowner = InvalidOid;
|
|
AclResult aclresult;
|
|
bool isalter = false;
|
|
if (u_sess->attr.attr_sql.enforce_a_behavior) {
|
|
keyowner = GetUserIdFromNspId(namespace_id, true);
|
|
if (!OidIsValid(keyowner))
|
|
keyowner = GetUserId();
|
|
else if (keyowner != GetUserId())
|
|
isalter = true;
|
|
if (isalter) {
|
|
aclresult = pg_namespace_aclcheck(namespace_id, keyowner, ACL_CREATE);
|
|
if (aclresult != ACLCHECK_OK)
|
|
aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(namespace_id));
|
|
}
|
|
} else {
|
|
keyowner = GetUserId();
|
|
}
|
|
return keyowner;
|
|
}
|
|
|
|
Oid finish_processing(Relation *rel, HeapTuple *tup)
|
|
{
|
|
Oid res = simple_heap_insert(*rel, *tup);
|
|
CatalogUpdateIndexes(*rel, *tup);
|
|
heap_freetuple(*tup);
|
|
heap_close(*rel, RowExclusiveLock);
|
|
return res;
|
|
}
|
|
|
|
Oid get_column_key_id_by_namespace(const char *key_name, const Oid namespace_id, Oid &global_key_id)
|
|
{
|
|
HeapTuple rtup = NULL;
|
|
Form_gs_column_keys rel_data = NULL;
|
|
Oid column_key_id = InvalidOid;
|
|
rtup = search_syscache_cek_name(key_name, namespace_id);
|
|
if (rtup != NULL) {
|
|
rel_data = (Form_gs_column_keys)GETSTRUCT(rtup);
|
|
if (rel_data != NULL && namespace_id == rel_data->key_namespace &&
|
|
strcmp(rel_data->column_key_name.data, key_name) == 0) {
|
|
column_key_id = HeapTupleGetOid(rtup);
|
|
global_key_id = rel_data->global_key_id;
|
|
ReleaseSysCache(rtup);
|
|
return column_key_id;
|
|
}
|
|
ReleaseSysCache(rtup);
|
|
}
|
|
return column_key_id;
|
|
}
|
|
|
|
Oid get_column_key_id(const List *keyname_list, const Oid user_id, Oid &global_key_id)
|
|
{
|
|
Oid column_key_id = InvalidOid;
|
|
char *keyname = NULL;
|
|
ListCell *l = NULL;
|
|
char *schemaname = NULL;
|
|
Oid namespace_id = InvalidOid;
|
|
DeconstructQualifiedName(keyname_list, &schemaname, &keyname);
|
|
if (schemaname != NULL) {
|
|
namespace_id = SchemaNameGetSchemaOid(schemaname);
|
|
Assert(OidIsValid(namespace_id));
|
|
column_key_id = get_column_key_id_by_namespace(keyname, namespace_id, global_key_id);
|
|
if (column_key_id != InvalidOid) {
|
|
AclResult acl_res = gs_sec_cek_aclcheck(column_key_id, user_id, ACL_USAGE);
|
|
if (acl_res != ACLCHECK_OK) {
|
|
aclcheck_error(acl_res, ACL_KIND_COLUMN_SETTING, NameListToString(keyname_list));
|
|
}
|
|
return column_key_id;
|
|
}
|
|
} else { /* keyname_list doesn't include schema */
|
|
recomputeNamespacePath();
|
|
List *temp_active_search_path = NIL;
|
|
temp_active_search_path = list_copy(u_sess->catalog_cxt.activeSearchPath);
|
|
foreach (l, temp_active_search_path) {
|
|
namespace_id = lfirst_oid(l);
|
|
column_key_id = get_column_key_id_by_namespace(keyname, namespace_id, global_key_id);
|
|
if (column_key_id != InvalidOid) {
|
|
AclResult acl_res = gs_sec_cek_aclcheck(column_key_id, user_id, ACL_USAGE);
|
|
if (acl_res != ACLCHECK_OK) {
|
|
aclcheck_error(acl_res, ACL_KIND_COLUMN_SETTING, NameListToString(keyname_list));
|
|
break;
|
|
}
|
|
list_free_ext(temp_active_search_path);
|
|
return column_key_id;
|
|
}
|
|
}
|
|
list_free_ext(temp_active_search_path);
|
|
}
|
|
return column_key_id;
|
|
}
|
|
|
|
void get_catalog_name(const RangeVar * const rel)
|
|
{
|
|
Oid namespace_id;
|
|
Oid existing_relid;
|
|
RangeVar *relation = const_cast<RangeVar *>(rel);
|
|
relation->catalogname = get_database_name(u_sess->proc_cxt.MyDatabaseId);
|
|
namespace_id = RangeVarGetAndCheckCreationNamespace(relation, NoLock, &existing_relid);
|
|
if (relation->schemaname == NULL) {
|
|
relation->schemaname = get_namespace_name(namespace_id);
|
|
}
|
|
}
|
|
|
|
int process_encrypted_columns(const ColumnDef * const def, CeHeapInfo *ce_heap_info)
|
|
{
|
|
(void)namestrcpy(&ce_heap_info->column_name, def->colname);
|
|
ce_heap_info->alg_type = static_cast<int>(def->clientLogicColumnRef->columnEncryptionAlgorithmType);
|
|
ce_heap_info->orig_typ = def->clientLogicColumnRef->orig_typname->typeOid;
|
|
ce_heap_info->orig_mod = def->clientLogicColumnRef->orig_typname->typemod;
|
|
Oid global_key_id(0);
|
|
ce_heap_info->cek_id = get_column_key_id(def->clientLogicColumnRef->column_key_name, GetUserId(), global_key_id);
|
|
if (
|
|
#ifdef ENABLE_MULTIPLE_NODES
|
|
IS_PGXC_COORDINATOR &&
|
|
#endif
|
|
ce_heap_info->cek_id == InvalidOid) {
|
|
ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("object does not exist. column encryption key: %s",
|
|
NameListToString(def->clientLogicColumnRef->column_key_name))));
|
|
return -1;
|
|
}
|
|
AclResult acl_res = gs_sec_cmk_aclcheck(global_key_id, GetUserId(), ACL_USAGE);
|
|
if (acl_res != ACLCHECK_OK) {
|
|
NameData cmk_name;
|
|
(void)get_cmk_name(global_key_id, cmk_name);
|
|
aclcheck_error(acl_res, ACL_KIND_GLOBAL_SETTING, cmk_name.data);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
void insert_gs_sec_encrypted_column_tuple(CeHeapInfo *ce_heap_info, Relation rel, const Oid rel_id,
|
|
CatalogIndexState indstate)
|
|
{
|
|
#ifdef ENABLE_MULTIPLE_NODES
|
|
if (!IS_PGXC_COORDINATOR)
|
|
return;
|
|
#endif
|
|
HeapTuple htup = NULL;
|
|
|
|
bool encrypted_columns_nulls[Natts_gs_encrypted_columns];
|
|
Datum encrypted_columns_values[Natts_gs_encrypted_columns];
|
|
int rc = memset_s(encrypted_columns_values, sizeof(encrypted_columns_values), 0, sizeof(encrypted_columns_values));
|
|
securec_check(rc, "\0", "\0");
|
|
rc = memset_s(encrypted_columns_nulls, sizeof(encrypted_columns_nulls), false, sizeof(encrypted_columns_nulls));
|
|
securec_check(rc, "\0", "\0");
|
|
|
|
encrypted_columns_values[Anum_gs_encrypted_columns_rel_id - 1] = CStringGetDatum(rel_id);
|
|
encrypted_columns_values[Anum_gs_encrypted_columns_column_name - 1] = NameGetDatum(&ce_heap_info->column_name);
|
|
encrypted_columns_values[Anum_gs_encrypted_columns_column_key_id - 1] = ce_heap_info->cek_id;
|
|
encrypted_columns_values[Anum_gs_sec_encrypted_columns_encryption_type - 1] = ce_heap_info->alg_type;
|
|
encrypted_columns_values[Anum_gs_encrypted_columns_data_type_original_oid - 1] = ce_heap_info->orig_typ;
|
|
encrypted_columns_values[Anum_gs_encrypted_columns_data_type_original_mod - 1] = ce_heap_info->orig_mod;
|
|
encrypted_columns_values[Anum_gs_encrypted_columns_create_date - 1] =
|
|
DirectFunctionCall1(timestamptz_timestamp, GetCurrentTimestamp());
|
|
|
|
/* finally insert the new tuple, update the indexes, and clean up */
|
|
htup = heap_form_tuple(RelationGetDescr(rel), encrypted_columns_values, encrypted_columns_nulls);
|
|
const Oid myOid = simple_heap_insert(rel, htup);
|
|
|
|
if (indstate != NULL) {
|
|
CatalogIndexInsert(indstate, htup);
|
|
} else {
|
|
CatalogUpdateIndexes(rel, htup);
|
|
}
|
|
heap_freetuple(htup);
|
|
ObjectAddress pg_attr_addr;
|
|
ObjectAddress column_addr;
|
|
ObjectAddress cek_addr;
|
|
pg_attr_addr.classId = RelationRelationId;
|
|
pg_attr_addr.objectId = rel_id;
|
|
pg_attr_addr.objectSubId = ce_heap_info->attnum;
|
|
column_addr.classId = ClientLogicCachedColumnsId;
|
|
column_addr.objectId = myOid;
|
|
column_addr.objectSubId = 0;
|
|
cek_addr.classId = ClientLogicColumnSettingsId;
|
|
cek_addr.objectId = ce_heap_info->cek_id;
|
|
cek_addr.objectSubId = 0;
|
|
|
|
recordDependencyOn(&column_addr, &cek_addr, DEPENDENCY_NORMAL);
|
|
recordDependencyOn(&column_addr, &pg_attr_addr, DEPENDENCY_AUTO);
|
|
|
|
ce_cache_refresh_type |= 4; /* 4: COLUMNS type */
|
|
pfree_ext(ce_heap_info);
|
|
}
|
|
|
|
static const int MAX_ARGS_SIZE = 1024;
|
|
static bool process_global_settings_flush_args(Oid global_key_id, const char *global_function, const char *key,
|
|
size_t keySize, const char *value, size_t valueSize)
|
|
{
|
|
char key_str[MAX_ARGS_SIZE] = {0};
|
|
char value_str[MAX_ARGS_SIZE] = {0};
|
|
errno_t rc = EOK;
|
|
rc = strncpy_s(key_str, MAX_ARGS_SIZE, key, keySize);
|
|
securec_check(rc, "\0", "\0");
|
|
key_str[keySize] = '\0';
|
|
rc = strncpy_s(value_str, MAX_ARGS_SIZE, value, valueSize);
|
|
securec_check(rc, "\0", "\0");
|
|
value_str[valueSize] = '\0';
|
|
|
|
/* reset catalog variables */
|
|
bool client_master_keys_args_nulls[Natts_gs_client_global_keys_args];
|
|
Datum client_master_keys_args_values[Natts_gs_client_global_keys_args];
|
|
rc = memset_s(client_master_keys_args_values, sizeof(client_master_keys_args_values), 0,
|
|
sizeof(client_master_keys_args_values));
|
|
securec_check(rc, "\0", "\0");
|
|
rc = memset_s(client_master_keys_args_nulls, sizeof(client_master_keys_args_nulls), false,
|
|
sizeof(client_master_keys_args_nulls));
|
|
securec_check(rc, "\0", "\0");
|
|
|
|
/* fill catalog variable */
|
|
client_master_keys_args_values[Anum_gs_client_global_keys_args_global_key_id - 1] = ObjectIdGetDatum(global_key_id);
|
|
client_master_keys_args_values[Anum_gs_client_global_keys_args_function_name - 1] =
|
|
DirectFunctionCall1(namein, CStringGetDatum(global_function));
|
|
client_master_keys_args_values[Anum_gs_client_global_keys_args_key - 1] =
|
|
DirectFunctionCall1(namein, CStringGetDatum(key_str));
|
|
client_master_keys_args_values[Anum_gs_client_global_keys_args_value - 1] =
|
|
DirectFunctionCall1(byteain, CStringGetDatum(value_str));
|
|
|
|
/* write to catalog table */
|
|
Relation rel = heap_open(ClientLogicGlobalSettingsArgsId, RowExclusiveLock);
|
|
HeapTuple htup = heap_form_tuple(rel->rd_att, client_master_keys_args_values, client_master_keys_args_nulls);
|
|
const Oid args_id = finish_processing(&rel, &htup);
|
|
ObjectAddress cmk_addr;
|
|
ObjectAddress args_addr;
|
|
cmk_addr.classId = ClientLogicGlobalSettingsId;
|
|
cmk_addr.objectId = global_key_id;
|
|
cmk_addr.objectSubId = 0;
|
|
args_addr.classId = ClientLogicGlobalSettingsArgsId;
|
|
args_addr.objectId = args_id;
|
|
args_addr.objectSubId = 0;
|
|
recordDependencyOn(&args_addr, &cmk_addr, DEPENDENCY_INTERNAL);
|
|
return true;
|
|
}
|
|
|
|
static void check_key_path(const char *key_path)
|
|
{
|
|
const char *key_path_tag = "gs_ktool/";
|
|
if (key_path == NULL) {
|
|
ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("Invalid key path")));
|
|
}
|
|
if ((strlen(key_path) <= strlen(key_path_tag)) &&
|
|
(strncmp(key_path, key_path_tag, strlen(key_path_tag)) != 0)) {
|
|
ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("Invalid key path")));
|
|
}
|
|
for (size_t i = strlen(key_path_tag); i < strlen(key_path); i++) {
|
|
if (key_path[i] < '0' || key_path[i] > '9') {
|
|
ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("Invalid key path")));
|
|
}
|
|
}
|
|
}
|
|
|
|
static int process_global_settings_args(CreateClientLogicGlobal *parsetree, Oid global_key_id)
|
|
{
|
|
/* get arguments */
|
|
const char *global_function(NULL);
|
|
ListCell *key_item(NULL);
|
|
StringArgsVec string_args;
|
|
foreach (key_item, parsetree->global_setting_params) {
|
|
ClientLogicGlobalParam *global_param = static_cast<ClientLogicGlobalParam *> lfirst(key_item);
|
|
switch (global_param->key) {
|
|
case ClientLogicGlobalProperty::CLIENT_GLOBAL_FUNCTION:
|
|
global_function = global_param->value;
|
|
break;
|
|
case ClientLogicGlobalProperty::CMK_KEY_STORE: {
|
|
CmkKeyStore key_store = get_key_store_from_string(global_param->value);
|
|
if (key_store != CmkKeyStore::LOCALKMS) {
|
|
ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("Invalid key store")));
|
|
}
|
|
string_args.set("KEY_STORE", global_param->value);
|
|
break;
|
|
}
|
|
case ClientLogicGlobalProperty::CMK_KEY_PATH: {
|
|
check_key_path(global_param->value);
|
|
string_args.set("KEY_PATH", global_param->value);
|
|
break;
|
|
}
|
|
case ClientLogicGlobalProperty::CMK_ALGORITHM: {
|
|
CmkAlgorithm cmk_algo = get_algorithm_from_string(global_param->value);
|
|
if (cmk_algo != CmkAlgorithm::RAS_2048) {
|
|
ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("Invalid algorithm")));
|
|
}
|
|
string_args.set("ALGORITHM", global_param->value);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (global_function == NULL || strlen(global_function) == 0) {
|
|
ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("global function is missing")));
|
|
return 1;
|
|
}
|
|
|
|
for (size_t i = 0; i < string_args.Size(); ++i) {
|
|
const char *key = string_args.at(i)->key;
|
|
const char *value = string_args.at(i)->value;
|
|
const size_t valsize = string_args.at(i)->valsize;
|
|
if (!process_global_settings_flush_args(global_key_id, global_function, key, strlen(key), value, valsize)) {
|
|
ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("failed to flush args")));
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
int process_global_settings(CreateClientLogicGlobal *parsetree)
|
|
{
|
|
/* permissions */
|
|
char *keyname = NULL;
|
|
const Oid namespace_id = check_namespace(parsetree->global_key_name, reinterpret_cast<Node *>(parsetree), &keyname);
|
|
const Oid user_id = check_user(namespace_id);
|
|
Acl *key_acl = get_user_default_acl(ACL_OBJECT_GLOBAL_SETTING, user_id, namespace_id);
|
|
|
|
/* reset catalog variables */
|
|
Datum client_master_keys_values[Natts_gs_client_global_keys];
|
|
bool client_master_keys_nulls[Natts_gs_client_global_keys];
|
|
errno_t rc = EOK;
|
|
rc = memset_s(client_master_keys_values, sizeof(client_master_keys_values), 0, sizeof(client_master_keys_values));
|
|
securec_check(rc, "\0", "\0");
|
|
rc = memset_s(client_master_keys_nulls, sizeof(client_master_keys_nulls), false, sizeof(client_master_keys_nulls));
|
|
securec_check(rc, "\0", "\0");
|
|
|
|
/* fill catalog variable */
|
|
client_master_keys_values[Anum_gs_client_global_keys_global_key_name - 1] =
|
|
DirectFunctionCall1(namein, CStringGetDatum(keyname));
|
|
client_master_keys_values[Anum_gs_client_global_keys_key_namespace - 1] = ObjectIdGetDatum(namespace_id);
|
|
client_master_keys_values[Anum_gs_client_global_keys_key_owner - 1] = ObjectIdGetDatum(user_id);
|
|
if (key_acl != NULL)
|
|
client_master_keys_values[Anum_gs_client_global_keys_key_acl - 1] = PointerGetDatum(key_acl);
|
|
else
|
|
client_master_keys_nulls[Anum_gs_client_global_keys_key_acl - 1] = true;
|
|
client_master_keys_values[Anum_gs_client_global_keys_create_date - 1] =
|
|
DirectFunctionCall1(timestamptz_timestamp, GetCurrentTimestamp());
|
|
|
|
/* write to catalog table */
|
|
Relation rel = heap_open(ClientLogicGlobalSettingsId, RowExclusiveLock);
|
|
HeapTuple htup = heap_form_tuple(rel->rd_att, client_master_keys_values, client_master_keys_nulls);
|
|
const Oid global_key_id = finish_processing(&rel, &htup);
|
|
|
|
/* update dependency tables */
|
|
ObjectAddress nsp_addr;
|
|
ObjectAddress cmk_addr;
|
|
nsp_addr.classId = NamespaceRelationId;
|
|
nsp_addr.objectId = namespace_id;
|
|
nsp_addr.objectSubId = 0;
|
|
cmk_addr.classId = ClientLogicGlobalSettingsId;
|
|
cmk_addr.objectId = global_key_id;
|
|
cmk_addr.objectSubId = 0;
|
|
recordDependencyOn(&cmk_addr, &nsp_addr, DEPENDENCY_NORMAL);
|
|
|
|
/* write to arguments table */
|
|
(void)process_global_settings_args(parsetree, global_key_id);
|
|
|
|
ce_cache_refresh_type |= 1; /* 1: CMK type */
|
|
|
|
Oid rlsPolicyId = get_rlspolicy_oid(ClientLogicGlobalSettingsId, "gs_client_global_keys_rls", true);
|
|
if (OidIsValid(rlsPolicyId) == false) {
|
|
CreateRlsPolicyForSystem("pg_catalog", "gs_client_global_keys", "gs_client_global_keys_rls",
|
|
"has_cmk_privilege", "oid", "usage");
|
|
rel = relation_open(ClientLogicGlobalSettingsId, ShareUpdateExclusiveLock);
|
|
ATExecEnableDisableRls(rel, RELATION_RLS_ENABLE, ShareUpdateExclusiveLock);
|
|
relation_close(rel, ShareUpdateExclusiveLock);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static Oid get_cmk_oid(const char *key_name, const Oid namespace_id)
|
|
{
|
|
HeapTuple rtup = NULL;
|
|
Form_gs_client_global_keys rel_data = NULL;
|
|
Oid cmk_oid = InvalidOid;
|
|
rtup = search_syscache_cmk_name(key_name, namespace_id);
|
|
if (rtup != NULL) {
|
|
rel_data = (Form_gs_client_global_keys)GETSTRUCT(rtup);
|
|
if (rel_data != NULL && namespace_id == rel_data->key_namespace &&
|
|
strcmp(rel_data->global_key_name.data, key_name) == 0) {
|
|
cmk_oid = HeapTupleGetOid(rtup);
|
|
ReleaseSysCache(rtup);
|
|
return cmk_oid;
|
|
}
|
|
ReleaseSysCache(rtup);
|
|
}
|
|
return cmk_oid;
|
|
}
|
|
|
|
static Oid get_cmk_oid(const List *key_name, const Oid user_id)
|
|
{
|
|
Oid cmk_oid = InvalidOid;
|
|
char *keyname = NULL;
|
|
ListCell *l = NULL;
|
|
char *schemaname = NULL;
|
|
Oid namespace_id = InvalidOid;
|
|
DeconstructQualifiedName(key_name, &schemaname, &keyname);
|
|
if (schemaname != NULL) {
|
|
namespace_id = SchemaNameGetSchemaOid(schemaname);
|
|
Assert(OidIsValid(namespace_id));
|
|
cmk_oid = get_cmk_oid(keyname, namespace_id);
|
|
if (cmk_oid != InvalidOid) {
|
|
AclResult acl_res = gs_sec_cmk_aclcheck(cmk_oid, user_id, ACL_USAGE);
|
|
if (acl_res != ACLCHECK_OK) {
|
|
aclcheck_error(acl_res, ACL_KIND_GLOBAL_SETTING, NameListToString(key_name));
|
|
}
|
|
return cmk_oid;
|
|
}
|
|
} else { /* key_name doesn't include schema */
|
|
recomputeNamespacePath();
|
|
List *temp_active_search_path = NIL;
|
|
temp_active_search_path = list_copy(u_sess->catalog_cxt.activeSearchPath);
|
|
foreach (l, temp_active_search_path) {
|
|
namespace_id = lfirst_oid(l);
|
|
cmk_oid = get_cmk_oid(keyname, namespace_id);
|
|
if (cmk_oid != InvalidOid) {
|
|
AclResult acl_res = gs_sec_cmk_aclcheck(cmk_oid, user_id, ACL_USAGE);
|
|
if (acl_res != ACLCHECK_OK) {
|
|
aclcheck_error(acl_res, ACL_KIND_GLOBAL_SETTING, NameListToString(key_name));
|
|
break;
|
|
}
|
|
list_free_ext(temp_active_search_path);
|
|
return cmk_oid;
|
|
}
|
|
}
|
|
list_free_ext(temp_active_search_path);
|
|
}
|
|
return cmk_oid;
|
|
}
|
|
|
|
static bool get_cmk_name(const Oid global_key_id, NameData &cmk_name)
|
|
{
|
|
HeapTuple rtup = NULL;
|
|
Relation relation = heap_open(ClientLogicGlobalSettingsId, RowExclusiveLock);
|
|
Form_gs_client_global_keys rel_data = NULL;
|
|
TableScanDesc scan = heap_beginscan(relation, SnapshotNow, 0, NULL);
|
|
while ((rtup = heap_getnext(scan, ForwardScanDirection))) {
|
|
if (HeapTupleGetOid(rtup) != global_key_id) {
|
|
continue;
|
|
}
|
|
rel_data = (Form_gs_client_global_keys)GETSTRUCT(rtup);
|
|
if (rel_data == NULL) {
|
|
continue;
|
|
}
|
|
cmk_name = rel_data->global_key_name;
|
|
heap_endscan(scan);
|
|
heap_close(relation, RowExclusiveLock);
|
|
return true;
|
|
}
|
|
|
|
heap_endscan(scan);
|
|
heap_close(relation, RowExclusiveLock);
|
|
return false;
|
|
}
|
|
|
|
static bool process_column_settings_flush_args(Oid column_key_id, const char *column_function, const char *key,
|
|
size_t keySize, const char *value, size_t valueSize)
|
|
{
|
|
char key_str[MAX_ARGS_SIZE];
|
|
char value_str[MAX_ARGS_SIZE];
|
|
errno_t rc = EOK;
|
|
rc = strncpy_s(key_str, MAX_ARGS_SIZE, key, keySize);
|
|
securec_check(rc, "\0", "\0");
|
|
key_str[keySize] = '\0';
|
|
rc = strncpy_s(value_str, MAX_ARGS_SIZE, value, valueSize);
|
|
securec_check(rc, "\0", "\0");
|
|
value_str[valueSize] = '\0';
|
|
|
|
/* reset catalog variables */
|
|
bool column_settings_args_nulls[Natts_gs_column_keys_args];
|
|
Datum column_settings_args_values[Natts_gs_column_keys_args];
|
|
rc = memset_s(column_settings_args_values, sizeof(column_settings_args_values), 0,
|
|
sizeof(column_settings_args_values));
|
|
securec_check(rc, "\0", "\0");
|
|
rc = memset_s(column_settings_args_nulls, sizeof(column_settings_args_nulls), false,
|
|
sizeof(column_settings_args_nulls));
|
|
securec_check(rc, "\0", "\0");
|
|
|
|
/* fill catalog variable */
|
|
column_settings_args_values[Anum_gs_column_keys_args_column_key_id - 1] =
|
|
ObjectIdGetDatum(column_key_id);
|
|
column_settings_args_values[Anum_gs_column_keys_args_function_name - 1] =
|
|
DirectFunctionCall1(namein, CStringGetDatum(column_function));
|
|
column_settings_args_values[Anum_gs_column_keys_args_key - 1] =
|
|
DirectFunctionCall1(namein, CStringGetDatum(key_str));
|
|
column_settings_args_values[Anum_gs_column_keys_args_value - 1] =
|
|
DirectFunctionCall1(byteain, CStringGetDatum(value_str));
|
|
|
|
/* write to catalog table */
|
|
Relation rel = heap_open(ClientLogicColumnSettingsArgsId, RowExclusiveLock);
|
|
HeapTuple htup = heap_form_tuple(rel->rd_att, column_settings_args_values, column_settings_args_nulls);
|
|
const Oid cek_args_oid = finish_processing(&rel, &htup);
|
|
if (cek_args_oid == 0) {
|
|
return false;
|
|
}
|
|
ObjectAddress cek_addr;
|
|
ObjectAddress args_addr;
|
|
cek_addr.classId = ClientLogicColumnSettingsId;
|
|
cek_addr.objectId = column_key_id;
|
|
cek_addr.objectSubId = 0;
|
|
args_addr.classId = ClientLogicColumnSettingsArgsId;
|
|
args_addr.objectId = cek_args_oid;
|
|
args_addr.objectSubId = 0;
|
|
recordDependencyOn(&args_addr, &cek_addr, DEPENDENCY_INTERNAL);
|
|
return true;
|
|
}
|
|
|
|
static int process_column_settings_args(CreateClientLogicColumn *parsetree, Oid column_key_id)
|
|
{
|
|
/* get arguments */
|
|
const char *column_function(NULL);
|
|
ListCell *key_item(NULL);
|
|
StringArgsVec string_args;
|
|
foreach (key_item, parsetree->column_setting_params) {
|
|
ClientLogicColumnParam *columnParam = static_cast<ClientLogicColumnParam *> lfirst(key_item);
|
|
switch (columnParam->key) {
|
|
case ClientLogicColumnProperty::COLUMN_COLUMN_FUNCTION:
|
|
column_function = columnParam->value;
|
|
break;
|
|
case ClientLogicColumnProperty::CEK_ALGORITHM: {
|
|
ColumnEncryptionAlgorithm column_encryption_algorithm =
|
|
get_cek_algorithm_from_string(columnParam->value);
|
|
if (column_encryption_algorithm == ColumnEncryptionAlgorithm::INVALID_ALGORITHM) {
|
|
ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("Invalid algorithm")));
|
|
}
|
|
string_args.set("ALGORITHM", columnParam->value);
|
|
break;
|
|
}
|
|
case ClientLogicColumnProperty::CEK_EXPECTED_VALUE:
|
|
string_args.set("ENCRYPTED_VALUE", columnParam->value);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (column_function == NULL || strlen(column_function) == 0) {
|
|
ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("column function is missing")));
|
|
return 1;
|
|
}
|
|
|
|
for (size_t i = 0; i < string_args.Size(); ++i) {
|
|
const char *key = string_args.at(i)->key;
|
|
const char *value = string_args.at(i)->value;
|
|
const size_t valsize = string_args.at(i)->valsize;
|
|
if (!process_column_settings_flush_args(column_key_id, column_function, key, strlen(key), value, valsize)) {
|
|
ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("failed to flush column args")));
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int process_column_settings(CreateClientLogicColumn *parsetree)
|
|
{
|
|
/* permissions */
|
|
char *cek_name = NULL;
|
|
char *schema_name = NULL;
|
|
const Oid namespace_id =
|
|
check_namespace(parsetree->column_key_name, reinterpret_cast<Node *>(parsetree), &cek_name);
|
|
const Oid user_id = check_user(namespace_id);
|
|
Acl *key_acl = get_user_default_acl(ACL_OBJECT_COLUMN_SETTING, user_id, namespace_id);
|
|
|
|
schema_name = get_namespace_name(namespace_id);
|
|
/* retrieve global setting id (foreign key) */
|
|
ListCell *key_item(NULL);
|
|
Oid global_key_id(InvalidOid);
|
|
const char *global_key_name = NULL;
|
|
foreach (key_item, parsetree->column_setting_params) {
|
|
ClientLogicColumnParam *kp = static_cast<ClientLogicColumnParam *> lfirst(key_item);
|
|
switch (kp->key) {
|
|
case ClientLogicColumnProperty::CLIENT_GLOBAL_SETTING: {
|
|
global_key_name = NameListToString(kp->qualname);
|
|
global_key_id = get_cmk_oid(kp->qualname, user_id);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
if (global_key_id == InvalidOid) {
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_SYNTAX_ERROR), errmsg("object does not exist. client master key: %s", global_key_name)));
|
|
return 1;
|
|
}
|
|
|
|
/* validate arguments in hook ? */
|
|
const unsigned char buf_size = 2 * NAMEDATALEN + 1;
|
|
char fqdn[buf_size] = {0};
|
|
|
|
errno_t rc = EOK;
|
|
rc = strncpy_s(fqdn, buf_size, schema_name, NAMEDATALEN);
|
|
securec_check(rc, "\0", "\0");
|
|
rc = strncat_s(fqdn, buf_size, ".", 1);
|
|
securec_check(rc, "\0", "\0");
|
|
rc = strncat_s(fqdn, buf_size, cek_name, NAMEDATALEN);
|
|
securec_check(rc, "\0", "\0");
|
|
|
|
/* reset catalog variables */
|
|
Datum column_settings_values[Natts_gs_column_keys];
|
|
bool column_settings_nulls[Natts_gs_column_keys];
|
|
rc = memset_s(column_settings_values, sizeof(column_settings_values), 0, sizeof(column_settings_values));
|
|
securec_check(rc, "\0", "\0");
|
|
rc = memset_s(column_settings_nulls, sizeof(column_settings_nulls), false, sizeof(column_settings_nulls));
|
|
securec_check(rc, "\0", "\0");
|
|
|
|
/* fill catalog variable */
|
|
Oid distid = 0;
|
|
column_settings_values[Anum_gs_column_keys_column_key_name - 1] =
|
|
DirectFunctionCall1(namein, CStringGetDatum(cek_name));
|
|
MurmurHash3_x86_32(fqdn, strlen(fqdn), 0x12345, &distid);
|
|
column_settings_values[Anum_gs_column_keys_column_key_distributed_id - 1] = ObjectIdGetDatum(distid);
|
|
column_settings_values[Anum_gs_column_keys_global_key_id - 1] = ObjectIdGetDatum(global_key_id);
|
|
column_settings_values[Anum_gs_column_keys_key_namespace - 1] = ObjectIdGetDatum(namespace_id);
|
|
if (key_acl != NULL)
|
|
column_settings_values[Anum_gs_column_keys_key_acl - 1] = PointerGetDatum(key_acl);
|
|
else
|
|
column_settings_nulls[Anum_gs_column_keys_key_acl - 1] = true;
|
|
column_settings_values[Anum_gs_column_keys_key_owner - 1] = ObjectIdGetDatum(user_id);
|
|
column_settings_values[Anum_gs_column_keys_create_date - 1] =
|
|
DirectFunctionCall1(timestamptz_timestamp, GetCurrentTimestamp());
|
|
|
|
/* write to catalog table */
|
|
Relation rel = heap_open(ClientLogicColumnSettingsId, RowExclusiveLock);
|
|
HeapTuple htup = heap_form_tuple(rel->rd_att, column_settings_values, column_settings_nulls);
|
|
const Oid column_key_id = finish_processing(&rel, &htup);
|
|
|
|
/* update dependency table */
|
|
ObjectAddress cmk_addr;
|
|
ObjectAddress cek_addr;
|
|
cmk_addr.classId = ClientLogicGlobalSettingsId;
|
|
cmk_addr.objectId = global_key_id;
|
|
cmk_addr.objectSubId = 0;
|
|
cek_addr.classId = ClientLogicColumnSettingsId;
|
|
cek_addr.objectId = column_key_id;
|
|
cek_addr.objectSubId = 0;
|
|
ObjectAddress nsp_addr;
|
|
nsp_addr.classId = NamespaceRelationId;
|
|
nsp_addr.objectId = namespace_id;
|
|
nsp_addr.objectSubId = 0;
|
|
recordDependencyOn(&cek_addr, &cmk_addr, DEPENDENCY_NORMAL);
|
|
recordDependencyOn(&cek_addr, &nsp_addr, DEPENDENCY_NORMAL);
|
|
|
|
/* write to arguments table */
|
|
(void)process_column_settings_args(parsetree, column_key_id);
|
|
|
|
ce_cache_refresh_type |= 2; /* 2: CEK type */
|
|
|
|
Oid rlsPolicyId = get_rlspolicy_oid(ClientLogicColumnSettingsId, "gs_column_keys_rls", true);
|
|
if (OidIsValid(rlsPolicyId) == false) {
|
|
CreateRlsPolicyForSystem(
|
|
"pg_catalog", "gs_column_keys", "gs_column_keys_rls", "has_cek_privilege", "oid", "usage");
|
|
rel = relation_open(ClientLogicColumnSettingsId, ShareUpdateExclusiveLock);
|
|
ATExecEnableDisableRls(rel, RELATION_RLS_ENABLE, ShareUpdateExclusiveLock);
|
|
relation_close(rel, ShareUpdateExclusiveLock);
|
|
}
|
|
return 0;
|
|
}
|
|
int set_column_encryption(const ColumnDef *def, CeHeapInfo *ce_heap_info)
|
|
{
|
|
Oid res = 0;
|
|
#ifdef ENABLE_MULTIPLE_NODES
|
|
if (IS_PGXC_COORDINATOR)
|
|
#endif
|
|
res = process_encrypted_columns(def, ce_heap_info);
|
|
return res;
|
|
}
|
|
|
|
int drop_global_settings(DropStmt *stmt)
|
|
{
|
|
#ifdef ENABLE_MULTIPLE_NODES
|
|
if (!IS_PGXC_COORDINATOR) {
|
|
return 0;
|
|
}
|
|
if (!IsConnFromCoord() && !u_sess->attr.attr_common.enable_full_encryption) {
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_OPERATE_NOT_SUPPORTED),
|
|
errmsg("Un-support to drop client master key when client encryption is disabled.")));
|
|
}
|
|
#else
|
|
if (!u_sess->attr.attr_common.enable_full_encryption) {
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_OPERATE_NOT_SUPPORTED),
|
|
errmsg("Un-support to drop client master key when client encryption is disabled.")));
|
|
}
|
|
#endif
|
|
char *global_key_name = NULL;
|
|
ListCell *cell = NULL;
|
|
foreach (cell, stmt->objects) {
|
|
Oid cmk_oid = InvalidOid;
|
|
Oid namespace_id = InvalidOid;
|
|
char *schema_name = NULL;
|
|
List *namespace_list = NIL;
|
|
ListCell *nslc = NULL;
|
|
DeconstructQualifiedName((List *)lfirst(cell), &schema_name, &global_key_name);
|
|
if (schema_name != NULL) {
|
|
namespace_id = LookupExplicitNamespace(schema_name);
|
|
namespace_list = list_make1_oid(namespace_id);
|
|
} else {
|
|
namespace_list = fetch_search_path(false);
|
|
}
|
|
|
|
foreach (nslc, namespace_list) {
|
|
namespace_id = lfirst_oid(nslc);
|
|
cmk_oid = get_cmk_oid(global_key_name, namespace_id);
|
|
if (cmk_oid != InvalidOid) {
|
|
/* Check we have creation rights in target namespace */
|
|
AclResult aclresult = pg_namespace_aclcheck(namespace_id, GetUserId(), ACL_CREATE);
|
|
if (aclresult != ACLCHECK_OK) {
|
|
aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(namespace_id));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
list_free_ext(namespace_list);
|
|
HeapTuple rtup = SearchSysCache1(GLOBALSETTINGOID, ObjectIdGetDatum(cmk_oid));
|
|
if (!rtup) {
|
|
if (!stmt->missing_ok) {
|
|
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_KEY),
|
|
errmsg("client master key \"%s\" does not exist", global_key_name)));
|
|
} else {
|
|
ereport(NOTICE, (errmsg("client master key \"%s\" does not exist", global_key_name)));
|
|
return 0;
|
|
}
|
|
} else {
|
|
Form_gs_client_global_keys rel_data = NULL;
|
|
rel_data = (Form_gs_client_global_keys)GETSTRUCT(rtup);
|
|
const Oid global_key_id = HeapTupleGetOid(rtup);
|
|
ObjectAddress cmk_addr;
|
|
cmk_addr.classId = ClientLogicGlobalSettingsId;
|
|
cmk_addr.objectId = global_key_id;
|
|
cmk_addr.objectSubId = 0;
|
|
|
|
performDeletion(&cmk_addr, stmt->behavior, 0);
|
|
}
|
|
|
|
ReleaseSysCache(rtup);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int drop_column_settings(DropStmt *stmt)
|
|
{
|
|
#ifdef ENABLE_MULTIPLE_NODES
|
|
if (!IS_PGXC_COORDINATOR) {
|
|
return 0;
|
|
}
|
|
if (!IsConnFromCoord() && !u_sess->attr.attr_common.enable_full_encryption) {
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_OPERATE_NOT_SUPPORTED),
|
|
errmsg("Un-support to drop column encryption key when client encryption is disabled.")));
|
|
}
|
|
#else
|
|
if (!u_sess->attr.attr_common.enable_full_encryption) {
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_OPERATE_NOT_SUPPORTED),
|
|
errmsg("Un-support to drop column encryption key when client encryption is disabled.")));
|
|
}
|
|
#endif
|
|
char *cek_name = NULL;
|
|
ListCell *cell = NULL;
|
|
foreach (cell, stmt->objects) {
|
|
Oid cek_oid = InvalidOid;
|
|
Oid namespace_id = InvalidOid;
|
|
char *schema_name = NULL;
|
|
List *namespace_list = NIL;
|
|
ListCell *nslc = NULL;
|
|
DeconstructQualifiedName((List *)lfirst(cell), &schema_name, &cek_name);
|
|
if (schema_name != NULL) {
|
|
namespace_id = LookupExplicitNamespace(schema_name);
|
|
namespace_list = list_make1_oid(namespace_id);
|
|
} else {
|
|
namespace_list = fetch_search_path(false);
|
|
}
|
|
Oid cmk_oid = InvalidOid;
|
|
foreach (nslc, namespace_list) {
|
|
namespace_id = lfirst_oid(nslc);
|
|
cek_oid = get_column_key_id_by_namespace(cek_name, namespace_id, cmk_oid);
|
|
if (cek_oid != InvalidOid) {
|
|
/* Check we have creation rights in target namespace */
|
|
AclResult aclresult = pg_namespace_aclcheck(namespace_id, GetUserId(), ACL_CREATE);
|
|
if (aclresult != ACLCHECK_OK) {
|
|
aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(namespace_id));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
list_free_ext(namespace_list);
|
|
HeapTuple rtup = SearchSysCache1(COLUMNSETTINGOID, ObjectIdGetDatum(cek_oid));
|
|
Form_gs_column_keys rel_data = NULL;
|
|
if (!rtup) {
|
|
if (!stmt->missing_ok)
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_UNDEFINED_KEY), errmsg("column encryption key \"%s\" does not exist", cek_name)));
|
|
else {
|
|
ereport(NOTICE, (errmsg("column encryption key \"%s\" does not exist", cek_name)));
|
|
return 0;
|
|
}
|
|
} else {
|
|
rel_data = (Form_gs_column_keys)GETSTRUCT(rtup);
|
|
if (rel_data->key_namespace == namespace_id && strcmp(rel_data->column_key_name.data, cek_name) == 0) {
|
|
const Oid column_key_id = HeapTupleGetOid(rtup);
|
|
ObjectAddress cek_addr;
|
|
cek_addr.classId = ClientLogicColumnSettingsId;
|
|
cek_addr.objectId = column_key_id;
|
|
cek_addr.objectSubId = 0;
|
|
|
|
performDeletion(&cek_addr, stmt->behavior, 0);
|
|
}
|
|
ReleaseSysCache(rtup);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
void remove_cek_by_id(Oid id)
|
|
{
|
|
Relation cek_rel = heap_open(ClientLogicColumnSettingsId, RowExclusiveLock);
|
|
HeapTuple tup = SearchSysCache1(COLUMNSETTINGOID, ObjectIdGetDatum(id));
|
|
if (!HeapTupleIsValid(tup)) /* should not happen */
|
|
ereport(ERROR, (errcode(ERRCODE_CACHE_LOOKUP_FAILED), errmsg("cache lookup failed for column encryption key")));
|
|
Form_gs_column_keys rel_data = (Form_gs_column_keys)GETSTRUCT(tup);
|
|
|
|
AclResult acl_res = gs_sec_cek_aclcheck(id, GetUserId(), ACL_DROP);
|
|
if (acl_res == ACLCHECK_OK || pg_namespace_ownercheck(rel_data->key_namespace, GetUserId()) ||
|
|
GetUserId() == rel_data->key_owner) {
|
|
simple_heap_delete(cek_rel, &tup->t_self);
|
|
} else {
|
|
aclcheck_error(acl_res, ACL_KIND_COLUMN_SETTING, rel_data->column_key_name.data);
|
|
}
|
|
|
|
ReleaseSysCache(tup);
|
|
heap_close(cek_rel, RowExclusiveLock);
|
|
}
|
|
void remove_cmk_by_id(Oid id)
|
|
{
|
|
Relation cek_rel = heap_open(ClientLogicGlobalSettingsId, RowExclusiveLock);
|
|
HeapTuple tup = SearchSysCache1(GLOBALSETTINGOID, ObjectIdGetDatum(id));
|
|
if (!HeapTupleIsValid(tup)) /* should not happen */
|
|
ereport(ERROR, (errcode(ERRCODE_CACHE_LOOKUP_FAILED), errmsg("cache lookup failed for client master key")));
|
|
Form_gs_client_global_keys rel_data = (Form_gs_client_global_keys)GETSTRUCT(tup);
|
|
|
|
AclResult acl_res = gs_sec_cmk_aclcheck(id, GetUserId(), ACL_DROP);
|
|
if (acl_res == ACLCHECK_OK || pg_namespace_ownercheck(rel_data->key_namespace, GetUserId()) ||
|
|
GetUserId() == rel_data->key_owner) {
|
|
simple_heap_delete(cek_rel, &tup->t_self);
|
|
} else {
|
|
aclcheck_error(acl_res, ACL_KIND_GLOBAL_SETTING, rel_data->global_key_name.data);
|
|
}
|
|
|
|
ReleaseSysCache(tup);
|
|
heap_close(cek_rel, RowExclusiveLock);
|
|
}
|
|
void remove_encrypted_col_by_id(Oid id)
|
|
{
|
|
Relation ce_rel = heap_open(ClientLogicCachedColumnsId, RowExclusiveLock);
|
|
HeapTuple tup = SearchSysCache1(CEOID, ObjectIdGetDatum(id));
|
|
if (!HeapTupleIsValid(tup)) /* should not happen */
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_CACHE_LOOKUP_FAILED), errmsg("cache lookup failed for encrypted column %u", id)));
|
|
simple_heap_delete(ce_rel, &tup->t_self);
|
|
ReleaseSysCache(tup);
|
|
heap_close(ce_rel, RowExclusiveLock);
|
|
}
|
|
void remove_cmk_args_by_id(Oid id)
|
|
{
|
|
Relation ce_rel = heap_open(ClientLogicGlobalSettingsArgsId, RowExclusiveLock);
|
|
ScanKeyData scankey;
|
|
SysScanDesc scan;
|
|
HeapTuple tuple;
|
|
|
|
ScanKeyInit(&scankey, ObjectIdAttributeNumber, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(id));
|
|
scan = systable_beginscan(ce_rel, ClientLogicGlobalSettingsArgsOidIndexId, true, SnapshotNow, 1, &scankey);
|
|
|
|
tuple = systable_getnext(scan);
|
|
if (!HeapTupleIsValid(tuple))
|
|
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("could not find tuple for cast %u", id)));
|
|
simple_heap_delete(ce_rel, &tuple->t_self);
|
|
|
|
systable_endscan(scan);
|
|
heap_close(ce_rel, RowExclusiveLock);
|
|
}
|
|
void remove_cek_args_by_id(Oid id)
|
|
{
|
|
Relation ce_rel = heap_open(ClientLogicColumnSettingsArgsId, RowExclusiveLock);
|
|
ScanKeyData scankey;
|
|
SysScanDesc scan;
|
|
HeapTuple tuple;
|
|
|
|
ScanKeyInit(&scankey, ObjectIdAttributeNumber, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(id));
|
|
scan = systable_beginscan(ce_rel, ClientLogicColumnSettingsArgsOidIndexId, true, SnapshotNow, 1, &scankey);
|
|
|
|
tuple = systable_getnext(scan);
|
|
if (!HeapTupleIsValid(tuple))
|
|
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("could not find tuple for cast %u", id)));
|
|
simple_heap_delete(ce_rel, &tuple->t_self);
|
|
|
|
systable_endscan(scan);
|
|
heap_close(ce_rel, RowExclusiveLock);
|
|
}
|
|
|
|
void get_global_setting_description(StringInfo buffer, const ObjectAddress *object)
|
|
{
|
|
Relation cmKeys = NULL;
|
|
ScanKeyData skey[1];
|
|
SysScanDesc rcscan = NULL;
|
|
HeapTuple tup = NULL;
|
|
Form_gs_client_global_keys cmk_form = NULL;
|
|
|
|
cmKeys = heap_open(ClientLogicGlobalSettingsId, AccessShareLock);
|
|
|
|
ScanKeyInit(&skey[0], ObjectIdAttributeNumber, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(object->objectId));
|
|
rcscan = systable_beginscan(cmKeys, ClientLogicGlobalSettingsOidIndexId, true, SnapshotNow, 1, skey);
|
|
tup = systable_getnext(rcscan);
|
|
if (!HeapTupleIsValid(tup)) {
|
|
systable_endscan(rcscan);
|
|
heap_close(cmKeys, AccessShareLock);
|
|
ereport(ERROR, (errcode(ERRCODE_CACHE_LOOKUP_FAILED),
|
|
errmsg("could not find tuple for cmk %u", object->objectId)));
|
|
}
|
|
cmk_form = (Form_gs_client_global_keys)GETSTRUCT(tup);
|
|
appendStringInfo(buffer, _("client master key: %s"), cmk_form->global_key_name.data);
|
|
systable_endscan(rcscan);
|
|
heap_close(cmKeys, AccessShareLock);
|
|
}
|
|
|
|
void get_column_setting_description(StringInfo buffer, const ObjectAddress *object)
|
|
{
|
|
Relation column_setting_rel = NULL;
|
|
ScanKeyData skey[1];
|
|
SysScanDesc rcscan = NULL;
|
|
HeapTuple tup = NULL;
|
|
Form_gs_column_keys cek_form = NULL;
|
|
|
|
column_setting_rel = heap_open(ClientLogicColumnSettingsId, AccessShareLock);
|
|
|
|
ScanKeyInit(&skey[0], ObjectIdAttributeNumber, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(object->objectId));
|
|
rcscan = systable_beginscan(column_setting_rel, ClientLogicColumnSettingsOidIndexId, true, SnapshotNow, 1, skey);
|
|
tup = systable_getnext(rcscan);
|
|
if (!HeapTupleIsValid(tup)) {
|
|
systable_endscan(rcscan);
|
|
heap_close(column_setting_rel, AccessShareLock);
|
|
ereport(ERROR, (errcode(ERRCODE_CACHE_LOOKUP_FAILED),
|
|
errmsg("could not find tuple for cek %u", object->objectId)));
|
|
}
|
|
cek_form = (Form_gs_column_keys)GETSTRUCT(tup);
|
|
appendStringInfo(buffer, _("column encryption key: %s"), cek_form->column_key_name.data);
|
|
systable_endscan(rcscan);
|
|
heap_close(column_setting_rel, AccessShareLock);
|
|
}
|
|
|
|
void get_cached_column_description(StringInfo buffer, const ObjectAddress *object)
|
|
{
|
|
Relation encColumns = NULL;
|
|
ScanKeyData skey[1];
|
|
SysScanDesc rcscan = NULL;
|
|
HeapTuple tup = NULL;
|
|
Form_gs_encrypted_columns ec_form = NULL;
|
|
encColumns = heap_open(ClientLogicCachedColumnsId, AccessShareLock);
|
|
|
|
ScanKeyInit(&skey[0], ObjectIdAttributeNumber, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(object->objectId));
|
|
rcscan = systable_beginscan(encColumns, GsSecEncryptedColumnsOidIndexId, true, SnapshotNow, 1, skey);
|
|
tup = systable_getnext(rcscan);
|
|
if (!HeapTupleIsValid(tup)) {
|
|
systable_endscan(rcscan);
|
|
heap_close(encColumns, AccessShareLock);
|
|
ereport(ERROR, (errcode(ERRCODE_CACHE_LOOKUP_FAILED),
|
|
errmsg("could not find tuple for encrypted column %u", object->objectId)));
|
|
}
|
|
ec_form = (Form_gs_encrypted_columns)GETSTRUCT(tup);
|
|
appendStringInfo(buffer, _("encrypted column: %s"), ec_form->column_name.data);
|
|
systable_endscan(rcscan);
|
|
heap_close(encColumns, AccessShareLock);
|
|
}
|
|
|
|
void get_global_setting_args_description(StringInfo buffer, const ObjectAddress *object)
|
|
{
|
|
Relation rel = NULL;
|
|
ScanKeyData skey[1];
|
|
SysScanDesc rcscan = NULL;
|
|
HeapTuple tup = NULL;
|
|
Form_gs_client_global_keys_args cmk_args = NULL;
|
|
rel = heap_open(ClientLogicGlobalSettingsArgsId, AccessShareLock);
|
|
|
|
ScanKeyInit(&skey[0], ObjectIdAttributeNumber, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(object->objectId));
|
|
rcscan = systable_beginscan(rel, ClientLogicGlobalSettingsArgsOidIndexId, true, SnapshotNow, 1, skey);
|
|
tup = systable_getnext(rcscan);
|
|
if (!HeapTupleIsValid(tup)) {
|
|
systable_endscan(rcscan);
|
|
heap_close(rel, AccessShareLock);
|
|
ereport(ERROR, (errcode(ERRCODE_CACHE_LOOKUP_FAILED),
|
|
errmsg("could not find tuple for encrypted column %u", object->objectId)));
|
|
}
|
|
cmk_args = (Form_gs_client_global_keys_args)GETSTRUCT(tup);
|
|
appendStringInfo(buffer, _("ckm args: %s"), cmk_args->function_name.data);
|
|
systable_endscan(rcscan);
|
|
heap_close(rel, AccessShareLock);
|
|
}
|
|
|
|
void get_column_setting_args_description(StringInfo buffer, const ObjectAddress *object)
|
|
{
|
|
Relation rel = NULL;
|
|
ScanKeyData skey[1];
|
|
SysScanDesc rcscan = NULL;
|
|
HeapTuple tup = NULL;
|
|
Form_gs_column_keys_args cek_args = NULL;
|
|
rel = heap_open(ClientLogicColumnSettingsArgsId, AccessShareLock);
|
|
|
|
ScanKeyInit(&skey[0], ObjectIdAttributeNumber, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(object->objectId));
|
|
rcscan = systable_beginscan(rel, ClientLogicColumnSettingsArgsOidIndexId, true, SnapshotNow, 1, skey);
|
|
tup = systable_getnext(rcscan);
|
|
if (!HeapTupleIsValid(tup)) {
|
|
systable_endscan(rcscan);
|
|
heap_close(rel, AccessShareLock);
|
|
ereport(ERROR, (errcode(ERRCODE_CACHE_LOOKUP_FAILED),
|
|
errmsg("could not find tuple for encrypted column %u", object->objectId)));
|
|
}
|
|
cek_args = (Form_gs_column_keys_args)GETSTRUCT(tup);
|
|
appendStringInfo(buffer, _("cek args: %s"), cek_args->function_name.data);
|
|
systable_endscan(rcscan);
|
|
heap_close(rel, AccessShareLock);
|
|
}
|
|
|
|
bool is_exist_encrypted_column(const ObjectAddresses *targetObjects)
|
|
{
|
|
for (int i = 0; i < targetObjects->numrefs; i++) {
|
|
ObjectAddress *object = targetObjects->refs + i;
|
|
if (getObjectClass(object) == OCLASS_CL_CACHED_COLUMN) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|