Encrypt password for user mapping.
This commit is contained in:
@ -824,6 +824,11 @@ void decode_cipher_files(
|
||||
securec_check_ss_c(ret, "\0", "\0");
|
||||
ret = snprintf_s(randfile, MAXPGPATH, MAXPGPATH - 1, "%s/datasource%s", datadir, RAN_KEY_FILE);
|
||||
securec_check_ss_c(ret, "\0", "\0");
|
||||
} else if (mode == USER_MAPPING_MODE) {
|
||||
ret = snprintf_s(cipherkeyfile, MAXPGPATH, MAXPGPATH - 1, "%s/usermapping%s", datadir, CIPHER_KEY_FILE);
|
||||
securec_check_ss_c(ret, "\0", "\0");
|
||||
ret = snprintf_s(randfile, MAXPGPATH, MAXPGPATH - 1, "%s/usermapping%s", datadir, RAN_KEY_FILE);
|
||||
securec_check_ss_c(ret, "\0", "\0");
|
||||
}
|
||||
/*
|
||||
* in client_mode,check with the user name is appointed.if so, read the files begin
|
||||
|
@ -344,6 +344,48 @@ bool isSpecifiedSrvTypeFromSrvName(const char* srvName, const char* SepcifiedTyp
|
||||
return isSpecifiedSrvType;
|
||||
}
|
||||
|
||||
static void DecryptOptions(List *options)
|
||||
{
|
||||
if (options == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
ListCell *cell = NULL;
|
||||
foreach(cell, options) {
|
||||
DefElem* def = (DefElem*)lfirst(cell);
|
||||
if (def->defname == NULL || def->arg == NULL || !IsA(def->arg, String)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
char *str = strVal(def->arg);
|
||||
if (str == NULL || strlen(str) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int i = 0; i < sensitiveArrayLength; i++) {
|
||||
if (pg_strcasecmp(def->defname, sensitiveOptionsArray[i]) == 0) {
|
||||
char plainText[EC_CIPHER_TEXT_LENGTH] = {0};
|
||||
|
||||
/*
|
||||
* If decryptECString return false, it means the stored values is not encrypted.
|
||||
* This happened when user mapping was created in old gaussdb version.
|
||||
*/
|
||||
if (decryptECString(str, plainText, EC_CIPHER_TEXT_LENGTH, false)) {
|
||||
pfree_ext(str);
|
||||
pfree_ext(def->arg);
|
||||
def->arg = (Node*)makeString(pstrdup(plainText));
|
||||
|
||||
/* Clear buffer */
|
||||
errno_t errCode = memset_s(plainText, EC_CIPHER_TEXT_LENGTH, 0, EC_CIPHER_TEXT_LENGTH);
|
||||
securec_check(errCode, "\0", "\0");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* GetUserMapping - look up the user mapping.
|
||||
*
|
||||
@ -381,6 +423,8 @@ UserMapping* GetUserMapping(Oid userid, Oid serverid)
|
||||
um->options = untransformRelOptions(datum);
|
||||
}
|
||||
|
||||
DecryptOptions(um->options);
|
||||
|
||||
ReleaseSysCache(tp);
|
||||
|
||||
return um;
|
||||
|
@ -42,10 +42,11 @@
|
||||
#include "openssl/rand.h"
|
||||
#include "openssl/evp.h"
|
||||
#include "openssl/crypto.h"
|
||||
#include "commands/defrem.h"
|
||||
|
||||
const char* pgname = "gs_encrypt";
|
||||
void getOBSKeyString(GS_UCHAR** cipherKey);
|
||||
static GS_UCHAR* getECKeyString(void);
|
||||
static GS_UCHAR* getECKeyString(KeyMode mode);
|
||||
char prefixCipherKey[2] = {'\0'};
|
||||
char suffixCipherKey[100] = {'\0'};
|
||||
bool gs_encrypt_aes_speed(GS_UCHAR* plaintext, GS_UCHAR* key, GS_UCHAR* ciphertext, GS_UINT32* cipherlen);
|
||||
@ -804,12 +805,14 @@ bool gs_decrypt_aes_speed(
|
||||
* @IN/OUT cipherKey: get key string and stored in cipherKey
|
||||
* @RETURN: void
|
||||
*/
|
||||
static GS_UCHAR* getECKeyString(void)
|
||||
static GS_UCHAR* getECKeyString(KeyMode mode)
|
||||
{
|
||||
Assert(mode == SOURCE_MODE || mode == USER_MAPPING_MODE);
|
||||
GS_UCHAR* plainkey = NULL;
|
||||
char* gshome = NULL;
|
||||
char cipherdir[MAXPGPATH] = {0};
|
||||
char cipherfile[MAXPGPATH] = {0};
|
||||
const char *cipherPrefix = (mode == SOURCE_MODE ? "datasource" : "usermapping");
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
@ -827,7 +830,7 @@ static GS_UCHAR* getECKeyString(void)
|
||||
|
||||
ret = snprintf_s(cipherdir, MAXPGPATH, MAXPGPATH - 1, "%s/bin", gshome);
|
||||
securec_check_ss(ret, "\0", "\0");
|
||||
ret = snprintf_s(cipherfile, MAXPGPATH, MAXPGPATH - 1, "%s/bin/datasource.key.cipher", gshome);
|
||||
ret = snprintf_s(cipherfile, MAXPGPATH, MAXPGPATH - 1, "%s/bin/%s.key.cipher", gshome, cipherPrefix);
|
||||
securec_check_ss_c(ret, "\0", "\0");
|
||||
|
||||
gshome = NULL;
|
||||
@ -841,13 +844,13 @@ static GS_UCHAR* getECKeyString(void)
|
||||
* Decode cipher file, if not given SOURCE cipher file, we use SERVER mode
|
||||
*/
|
||||
if (file_exists(cipherfile)) {
|
||||
decode_cipher_files(SOURCE_MODE, NULL, cipherdir, plainkey);
|
||||
decode_cipher_files(mode, NULL, cipherdir, plainkey);
|
||||
} else {
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_FILE),
|
||||
errmsg("No key file datasource.key.cipher"),
|
||||
errhint("Please create datasource.key.cipher file with gs_guc and gs_ssh, such as : gs_ssh -c \"gs_guc generate -S XXX -D "
|
||||
"$GAUSSHOME/bin -o datasource\"")));
|
||||
errmsg("No key file %s.key.cipher", cipherPrefix),
|
||||
errhint("Please create %s.key.cipher file with gs_guc and gs_ssh, such as : gs_ssh -c \"gs_guc generate -S XXX -D "
|
||||
"$GAUSSHOME/bin -o %s\"", cipherPrefix, cipherPrefix)));
|
||||
}
|
||||
/*
|
||||
* Note: plainkey is of length RANDOM_LEN + 1
|
||||
@ -866,7 +869,7 @@ static GS_UCHAR* getECKeyString(void)
|
||||
* @IN dest_cipher_length: dest buffer length which is given by the caller
|
||||
* @RETURN: void
|
||||
*/
|
||||
void encryptECString(char* src_plain_text, char* dest_cipher_text, uint32 dest_cipher_length)
|
||||
void encryptECString(char* src_plain_text, char* dest_cipher_text, uint32 dest_cipher_length, bool isDataSource)
|
||||
{
|
||||
GS_UINT32 ciphertextlen = 0;
|
||||
GS_UCHAR ciphertext[1024];
|
||||
@ -879,7 +882,7 @@ void encryptECString(char* src_plain_text, char* dest_cipher_text, uint32 dest_c
|
||||
}
|
||||
|
||||
/* First, get encrypt key */
|
||||
cipherkey = getECKeyString();
|
||||
cipherkey = getECKeyString(isDataSource ? SOURCE_MODE : USER_MAPPING_MODE);
|
||||
|
||||
/* Clear cipher buffer which will be used later */
|
||||
ret = memset_s(ciphertext, sizeof(ciphertext), 0, sizeof(ciphertext));
|
||||
@ -962,9 +965,9 @@ void encryptECString(char* src_plain_text, char* dest_cipher_text, uint32 dest_c
|
||||
* @OUT dest_plain_text: dest buffer to be filled with plain text, this buffer
|
||||
* should be given by caller
|
||||
* @IN dest_plain_length: dest buffer length which is given by the caller
|
||||
* @RETURN: void
|
||||
* @RETURN: bool, true if encrypt success, false if not
|
||||
*/
|
||||
void decryptECString(const char* src_cipher_text, char* dest_plain_text, uint32 dest_plain_length)
|
||||
bool decryptECString(const char* src_cipher_text, char* dest_plain_text, uint32 dest_plain_length, bool isDataSource)
|
||||
{
|
||||
GS_UCHAR* ciphertext = NULL;
|
||||
GS_UINT32 ciphertextlen = 0;
|
||||
@ -974,11 +977,11 @@ void decryptECString(const char* src_cipher_text, char* dest_plain_text, uint32
|
||||
errno_t ret = EOK;
|
||||
|
||||
if (NULL == src_cipher_text || !IsECEncryptedString(src_cipher_text)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Get key string */
|
||||
cipherkey = getECKeyString();
|
||||
cipherkey = getECKeyString(isDataSource ? SOURCE_MODE : USER_MAPPING_MODE);
|
||||
|
||||
/* Step-1: Decode */
|
||||
ciphertext = (GS_UCHAR*)(SEC_decodeBase64((char*)(src_cipher_text + strlen(EC_ENCRYPT_PREFIX)), &ciphertextlen));
|
||||
@ -1036,6 +1039,7 @@ void decryptECString(const char* src_cipher_text, char* dest_plain_text, uint32
|
||||
pfree_ext(cipherkey);
|
||||
OPENSSL_free(ciphertext);
|
||||
ciphertext = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1058,6 +1062,75 @@ bool IsECEncryptedString(const char* src_cipher_text)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* EncryptGenericOptions:
|
||||
* Encrypt data source or foreign data wrapper generic options, before transformation
|
||||
*
|
||||
* @IN src_options: source options to be encrypted
|
||||
* @RETURN: void
|
||||
*/
|
||||
void EncryptGenericOptions(List* options, const char** sensitiveOptionsArray, int arrayLength, bool isDataSource)
|
||||
{
|
||||
int i;
|
||||
char* srcString = NULL;
|
||||
char encryptString[EC_CIPHER_TEXT_LENGTH];
|
||||
errno_t ret;
|
||||
ListCell* cell = NULL;
|
||||
bool isPrint = false;
|
||||
|
||||
foreach (cell, options) {
|
||||
DefElem* def = (DefElem*)lfirst(cell);
|
||||
Node* arg = def->arg;
|
||||
|
||||
if (def->defaction == DEFELEM_DROP || def->arg == NULL || !IsA(def->arg, String))
|
||||
continue;
|
||||
|
||||
/* Get src string to be encrypted */
|
||||
srcString = strVal(def->arg);
|
||||
/* For empty value, we do not encrypt */
|
||||
if (srcString == NULL || strlen(srcString) == 0)
|
||||
continue;
|
||||
|
||||
for (i = 0; i < arrayLength; i++) {
|
||||
if (0 == pg_strcasecmp(def->defname, sensitiveOptionsArray[i])) {
|
||||
/* For string with prefix='encryptOpt' (probably encrypted), we do not encrypt again */
|
||||
if (IsECEncryptedString(srcString)) {
|
||||
/* We report warning only once in a CREATE/ALTER stmt. */
|
||||
if (!isPrint) {
|
||||
ereport(NOTICE,
|
||||
(errmodule(MOD_EC),
|
||||
errcode(ERRCODE_INVALID_PASSWORD),
|
||||
errmsg("Using probably encrypted option (prefix='encryptOpt') directly and it is not "
|
||||
"recommended."),
|
||||
errhint("The %s object can't be used if the option is not encrypted correctly.",
|
||||
isDataSource ? "DATA SOURCE" : "USER MAPPING")));
|
||||
isPrint = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Encrypt the src string */
|
||||
encryptECString(srcString, encryptString, EC_CIPHER_TEXT_LENGTH, isDataSource);
|
||||
|
||||
/* Substitute the src */
|
||||
def->arg = (Node*)makeString(pstrdup(encryptString));
|
||||
|
||||
/* Clear the encrypted string */
|
||||
ret = memset_s(encryptString, sizeof(encryptString), 0, sizeof(encryptString));
|
||||
securec_check(ret, "\0", "\0");
|
||||
|
||||
/* Clear the src string */
|
||||
ret = memset_s(srcString, strlen(srcString), 0, strlen(srcString));
|
||||
securec_check(ret, "\0", "\0");
|
||||
pfree_ext(srcString);
|
||||
pfree_ext(arg);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* encryptBlockAndCU:
|
||||
* encrypt block or CU exclude header and filling,user data must encrypt,if block or cu encrypt failed,
|
||||
|
@ -107,76 +107,6 @@ static void check_source_generic_options(const List* src_options)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* encrypt_source_generic_options:
|
||||
* Encrypt data source generic options, before transformation
|
||||
*
|
||||
* @IN src_options: source options to be encrypted
|
||||
* @RETURN: void
|
||||
*/
|
||||
static void encrypt_source_generic_options(List* src_options)
|
||||
{
|
||||
int i;
|
||||
int NumSensitiveOptions = sizeof(SensitiveOptionsArray) / sizeof(SensitiveOptionsArray[0]);
|
||||
char* srcString = NULL;
|
||||
char encryptString[EC_CIPHER_TEXT_LENGTH];
|
||||
errno_t ret;
|
||||
ListCell* cell = NULL;
|
||||
bool isPrint = false;
|
||||
|
||||
foreach (cell, src_options) {
|
||||
DefElem* def = (DefElem*)lfirst(cell);
|
||||
Node* arg = def->arg;
|
||||
|
||||
if (def->defaction == DEFELEM_DROP || def->arg == NULL)
|
||||
continue;
|
||||
|
||||
/* Get src string to be encrypted */
|
||||
srcString = defGetString(def);
|
||||
/* For empty value, we do not encrypt */
|
||||
if (srcString == NULL || strlen(srcString) == 0)
|
||||
continue;
|
||||
|
||||
for (i = 0; i < NumSensitiveOptions; i++) {
|
||||
if (0 == pg_strcasecmp(def->defname, SensitiveOptionsArray[i])) {
|
||||
/* For string with prefix='encryptOpt' (probably encrypted), we do not encrypt again */
|
||||
if (IsECEncryptedString(srcString)) {
|
||||
/* We report warning only once in a CREATE/ALTER stmt. */
|
||||
if (!isPrint) {
|
||||
ereport(NOTICE,
|
||||
(errmodule(MOD_EC),
|
||||
errcode(ERRCODE_INVALID_PASSWORD),
|
||||
errmsg("Using probably encrypted option (prefix='encryptOpt') directly and it is not "
|
||||
"recommended."),
|
||||
errhint(
|
||||
"The DATA SOURCE object can't be used if the option is not encrypted correctly.")));
|
||||
isPrint = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Encrypt the src string */
|
||||
encryptECString(srcString, encryptString, EC_CIPHER_TEXT_LENGTH);
|
||||
|
||||
/* Substitute the src */
|
||||
def->arg = (Node*)makeString(pstrdup(encryptString));
|
||||
|
||||
/* Clear the encrypted string */
|
||||
ret = memset_s(encryptString, sizeof(encryptString), 0, sizeof(encryptString));
|
||||
securec_check(ret, "\0", "\0");
|
||||
|
||||
/* Clear the src string */
|
||||
ret = memset_s(srcString, strlen(srcString), 0, strlen(srcString));
|
||||
securec_check(ret, "\0", "\0");
|
||||
pfree_ext(srcString);
|
||||
pfree_ext(arg);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* CreateDataSource:
|
||||
* Create a Data Source, only allowed by superuser!
|
||||
@ -249,7 +179,7 @@ void CreateDataSource(CreateDataSourceStmt* stmt)
|
||||
check_source_generic_options(stmt->options);
|
||||
|
||||
/* Encrypt sensitive options before any operations */
|
||||
encrypt_source_generic_options(stmt->options);
|
||||
EncryptGenericOptions(stmt->options, SensitiveOptionsArray, lengthof(SensitiveOptionsArray), true);
|
||||
|
||||
/* Add source options */
|
||||
srcoptions = transformGenericOptions(DataSourceRelationId, PointerGetDatum(NULL), stmt->options, InvalidOid);
|
||||
@ -361,7 +291,7 @@ void AlterDataSource(AlterDataSourceStmt* stmt)
|
||||
check_source_generic_options((const List*)stmt->options);
|
||||
|
||||
/* Encrypt sensitive options before any operations */
|
||||
encrypt_source_generic_options(stmt->options);
|
||||
EncryptGenericOptions(stmt->options, SensitiveOptionsArray, lengthof(SensitiveOptionsArray), true);
|
||||
|
||||
/* Prepare the options array */
|
||||
datum = transformGenericOptions(DataSourceRelationId, datum, stmt->options, InvalidOid);
|
||||
|
@ -53,6 +53,10 @@
|
||||
#include "catalog/toasting.h"
|
||||
#include "bulkload/dist_fdw.h"
|
||||
|
||||
/* Sensitive options for user mapping, will be encrypted when saved to catalog. */
|
||||
const char* sensitiveOptionsArray[] = {"password"};
|
||||
const int sensitiveArrayLength = lengthof(sensitiveOptionsArray);
|
||||
|
||||
/*
|
||||
* Convert a DefElem list to the text array format that is used in
|
||||
* pg_foreign_data_wrapper, pg_foreign_server, and pg_user_mapping.
|
||||
@ -1153,6 +1157,8 @@ void CreateUserMapping(CreateUserMappingStmt* stmt)
|
||||
values[Anum_pg_user_mapping_umuser - 1] = ObjectIdGetDatum(useId);
|
||||
values[Anum_pg_user_mapping_umserver - 1] = ObjectIdGetDatum(srv->serverid);
|
||||
|
||||
EncryptGenericOptions(stmt->options, sensitiveOptionsArray, sensitiveArrayLength, false);
|
||||
|
||||
/* Add user options */
|
||||
useoptions =
|
||||
transformGenericOptions(UserMappingRelationId, PointerGetDatum(NULL), stmt->options, fdw->fdwvalidator);
|
||||
@ -1248,6 +1254,8 @@ void AlterUserMapping(AlterUserMappingStmt* stmt)
|
||||
if (isnull)
|
||||
datum = PointerGetDatum(NULL);
|
||||
|
||||
EncryptGenericOptions(stmt->options, sensitiveOptionsArray, sensitiveArrayLength, false);
|
||||
|
||||
/* Prepare the options array */
|
||||
datum = transformGenericOptions(UserMappingRelationId, datum, stmt->options, fdw->fdwvalidator);
|
||||
|
||||
|
@ -54,5 +54,8 @@ typedef FormData_pg_user_mapping *Form_pg_user_mapping;
|
||||
#define Anum_pg_user_mapping_umserver 2
|
||||
#define Anum_pg_user_mapping_umoptions 3
|
||||
|
||||
extern const char* sensitiveOptionsArray[];
|
||||
extern const int sensitiveArrayLength;
|
||||
|
||||
#endif /* PG_USER_MAPPING_H */
|
||||
|
||||
|
@ -82,7 +82,8 @@ typedef enum {
|
||||
CLIENT_MODE,
|
||||
OBS_MODE,
|
||||
SOURCE_MODE,
|
||||
GDS_MODE
|
||||
GDS_MODE,
|
||||
USER_MAPPING_MODE
|
||||
} KeyMode;
|
||||
|
||||
typedef struct {
|
||||
|
@ -40,6 +40,4 @@ extern Oid get_data_source_oid(const char* sourcename, bool missing_ok);
|
||||
extern DataSource* GetDataSource(Oid sourceid);
|
||||
extern DataSource* GetDataSourceByName(const char* sourcename, bool missing_ok);
|
||||
|
||||
#define EC_CIPHER_TEXT_LENGTH 1024
|
||||
|
||||
#endif /* DATASOURCE_H */
|
||||
|
@ -1513,9 +1513,12 @@ extern Datum text_timestamp(PG_FUNCTION_ARGS);
|
||||
extern void encryptOBS(char* srcplaintext, char destciphertext[], uint32 destcipherlength);
|
||||
extern void decryptOBS(
|
||||
const char* srcciphertext, char destplaintext[], uint32 destplainlength, const char* obskey = NULL);
|
||||
extern void encryptECString(char* src_plain_text, char* dest_cipher_text, uint32 dest_cipher_length);
|
||||
extern void decryptECString(const char* src_cipher_text, char* dest_plain_text, uint32 dest_plain_length);
|
||||
extern void encryptECString(char* src_plain_text, char* dest_cipher_text, uint32 dest_cipher_length, bool isDataSource);
|
||||
extern bool decryptECString(const char* src_cipher_text, char* dest_plain_text, uint32 dest_plain_length, bool isDataSource = true);
|
||||
extern bool IsECEncryptedString(const char* src_cipher_text);
|
||||
extern void EncryptGenericOptions(List* options, const char** sensitiveOptionsArray, int arrayLength, bool isDataSource);
|
||||
|
||||
#define EC_CIPHER_TEXT_LENGTH 1024
|
||||
|
||||
/* fencedudf.cpp */
|
||||
extern Datum fenced_udf_process(PG_FUNCTION_ARGS);
|
||||
|
Reference in New Issue
Block a user