diff options
author | Sergei Golubchik <serg@mariadb.org> | 2016-03-23 22:36:46 +0100 |
---|---|---|
committer | Sergei Golubchik <serg@mariadb.org> | 2016-03-23 22:36:46 +0100 |
commit | f67a2211ec48b1b1502a7095c50cd9195d8235f8 (patch) | |
tree | 93e5d158a4a2a1dca4be915f8cf9dc79b3b6d96c /plugin | |
parent | a75d26946423d2142921411bf7bdc731eba4df1a (diff) | |
parent | 2783fc7d14bc8ad16acfeb509d3b19615023f47a (diff) | |
download | mariadb-git-f67a2211ec48b1b1502a7095c50cd9195d8235f8.tar.gz |
Merge branch '10.1' into 10.2
Diffstat (limited to 'plugin')
20 files changed, 766 insertions, 24 deletions
diff --git a/plugin/auth_gssapi/mysql-test/auth_gssapi/suite.pm b/plugin/auth_gssapi/mysql-test/auth_gssapi/suite.pm index 50137ca0211..aa225536a1e 100644 --- a/plugin/auth_gssapi/mysql-test/auth_gssapi/suite.pm +++ b/plugin/auth_gssapi/mysql-test/auth_gssapi/suite.pm @@ -19,7 +19,7 @@ else { if (!$ENV{'GSSAPI_FULLNAME'}) { - my $s = `klist |grep 'Default principal: '`; + my $s = `klist 2>/dev/null |grep 'Default principal: '`; if ($s) { chomp($s); diff --git a/plugin/aws_key_management/CMakeLists.txt b/plugin/aws_key_management/CMakeLists.txt new file mode 100644 index 00000000000..97bcfbb04db --- /dev/null +++ b/plugin/aws_key_management/CMakeLists.txt @@ -0,0 +1,154 @@ +# We build parts of AWS C++ SDK as CMake external project +# The restrictions of the SDK (https://github.com/awslabs/aws-sdk-cpp/blob/master/README.md) +# are + +# - OS : Windows,Linux or OSX +# - C++11 compiler : VS2013+, gcc 4.7+, clang 3.3+ +# - libcurl development package needs to be present on Unixes +# +# If we build SDK outselves, we'll need require GIT to be present on the build machine + + +# Give message why the building this plugin is skipped (only if -DVERBOSE is defined) +# or if plugin is explicitely requested to build. Then bail out. +MACRO(SKIP_AWS_PLUGIN msg) + IF(VERBOSE OR "${PLUGIN_AWS_KEY_MANAGEMENT}" MATCHES "^(STATIC|DYNAMIC)$") + MESSAGE(STATUS "Skip aws_key_management - ${msg}") + ENDIF() + RETURN() +ENDMACRO() + +MYSQL_ADD_PLUGIN(aws_key_management aws_key_management_plugin.cc DISABLED + COMPONENT aws-key-management) + +IF(NOT TARGET aws_key_management) + RETURN() +ENDIF() + +# This plugin needs recent C++ compilers (AWS C++ SDK header files are using C++11 features) +SET(CXX11_FLAGS) +SET(OLD_COMPILER_MSG "AWS SDK requires c++11 -capable compiler (minimal supported versions are g++ 4.7, clang 3.3, VS2103)") + +IF(CMAKE_CXX_COMPILER_ID MATCHES "GNU") + EXECUTE_PROCESS(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) + IF (GCC_VERSION VERSION_LESS 4.8) + SKIP_AWS_PLUGIN("${OLD_COMPILER_MSG}") + ENDIF() + SET(CXX11_FLAGS "-std=c++11") +ELSEIF (CMAKE_CXX_COMPILER_ID MATCHES "Clang") + IF ((CMAKE_CXX_COMPILER_VERSION AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.3) OR + (CLANG_VERSION_STRING AND CLANG_VERSION_STRING VERSION_LESS 3.3)) + SKIP_AWS_PLUGIN("${OLD_COMPILER_MSG}") + ENDIF() + SET(CXX11_FLAGS "-stdlib=libc++") +ELSEIF(MSVC) + IF (MSVC_VERSION LESS 1800) + SKIP_AWS_PLUGIN("${OLD_COMPILER_MSG}") + ENDIF() +ELSE() + SKIP_AWS_PLUGIN("Compiler not supported by AWS C++ SDK") +ENDIF() + +IF (NOT(WIN32 OR APPLE OR (CMAKE_SYSTEM_NAME MATCHES "Linux"))) + SKIP_AWS_PLUGIN("OS unsupported by AWS SDK") +ENDIF() + + +# Figure out where AWS installs SDK libraries +# The below is defined in AWS SDK's CMakeLists.txt +# (and their handling is weird, every OS has special install directory) +IF(WIN32) + SET(SDK_INSTALL_BINARY_PREFIX "windows") +ELSEIF(APPLE) + SET(SDK_INSTALL_BINARY_PREFIX "mac") +ELSEIF(UNIX) + SET(SDK_INSTALL_BINARY_PREFIX "linux") +ENDIF() +IF(NOT APPLE) + IF(CMAKE_SIZEOF_VOID_P EQUAL 8) + SET(SDK_INSTALL_BINARY_PREFIX "${SDK_INSTALL_BINARY_PREFIX}/intel64") + ELSE() + SET(SDK_INSTALL_BINARY_PREFIX "${SDK_INSTALL_BINARY_PREFIX}/ia32") + ENDIF() +ENDIF() +IF(CMAKE_CONFIGURATION_TYPES) + SET(SDK_INSTALL_BINARY_PREFIX "${SDK_INSTALL_BINARY_PREFIX}/${CMAKE_CFG_INTDIR}") +ENDIF() + +FIND_LIBRARY(AWS_CPP_SDK_CORE NAMES aws-cpp-sdk-core PATH_SUFFIXES "${SDK_INSTALL_BINARY_PREFIX}") +FIND_LIBRARY(AWS_CPP_SDK_KMS NAMES aws-cpp-sdk-core PATH_SUFFIXES "${SDK_INSTALL_BINARY_PREFIX}") +SET(CMAKE_REQUIRED_FLAGS ${CXX11_FLAGS}) +CHECK_INCLUDE_FILE_CXX(aws/kms/KMSClient.h HAVE_AWS_HEADERS) + +IF(AWS_CPP_SDK_CORE AND AWS_CPP_SDK_KMS AND HAVE_AWS_HEADERS) + # AWS C++ SDK installed + SET(AWS_SDK_LIBS ${AWS_CPP_SDK_CORE} ${AWS_CPP_SDK_KMS}) +ELSE() + # Build from source, using ExternalProject_Add + IF(CMAKE_VERSION VERSION_LESS "2.8.8") + SKIP_AWS_PLUGIN("CMake is too old") + ENDIF() + FIND_PACKAGE(Git) + IF(NOT GIT_FOUND) + SKIP_AWS_PLUGIN("no GIT") + ENDIF() + INCLUDE(ExternalProject) + IF(UNIX) + FIND_PACKAGE(CURL) + IF(NOT CURL_FOUND) + SKIP_AWS_PLUGIN("AWS C++ SDK requires libcurl development package") + ENDIF() + SET(PIC_FLAG -fPIC) + ENDIF() + IF(MSVC) + SET(EXTRA_SDK_CMAKE_FLAGS -DCMAKE_CXX_FLAGS_DEBUGOPT="" -DCMAKE_EXE_LINKER_FLAGS_DEBUGOPT="" -DCMAKE_CXX_FLAGS=/wd4592) + ENDIF() + IF(CMAKE_CXX_COMPILER) + SET(EXTRA_SDK_CMAKE_FLAGS ${EXTRA_SDK_CMAKE_FLAGS} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}) + ENDIF() + + # Relax AWS C++ SDK unreasonably high requirements for CMake version. Use replace utility (from MariaDB build) + # to patch their CMakeLists.txt + SET(AWS_SDK_PATCH_COMMAND ) + ExternalProject_Add( + aws_sdk_cpp + GIT_REPOSITORY "https://github.com/awslabs/aws-sdk-cpp.git" + GIT_TAG "0.9.6" # single tag + UPDATE_COMMAND "" + PATCH_COMMAND replace 3.1.2 2.8 -- ${CMAKE_BINARY_DIR}/aws-sdk-cpp/CMakeLists.txt + SOURCE_DIR "${CMAKE_BINARY_DIR}/aws-sdk-cpp" + CMAKE_ARGS + -DBUILD_ONLY=aws-cpp-sdk-kms -DSTATIC_LINKING=1 + "-DCMAKE_CXX_FLAGS_DEBUG=${CMAKE_CXX_FLAGS_DEBUG} ${PIC_FLAG}" + "-DCMAKE_CXX_FLAGS_RELWITHDEBINFO=${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${PIC_FLAG}" + "-DCMAKE_CXX_FLAGS_RELEASE=${CMAKE_CXX_FLAGS_RELEASE} ${PIC_FLAG}" + "-DCMAKE_CXX_FLAGS_MINSIZEREL=${CMAKE_CXX_FLAGS_MINSIZEREL} ${PIC_FLAG}" + ${EXTRA_SDK_CMAKE_FLAGS} + -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/aws_sdk_cpp + TEST_COMMAND "" + ) + + # We do not need to build the whole SDK , just 2 of its libs + set(AWS_SDK_LIBS aws-cpp-sdk-core aws-cpp-sdk-kms) + FOREACH(lib ${AWS_SDK_LIBS}) + ADD_LIBRARY(${lib} STATIC IMPORTED GLOBAL) + ADD_DEPENDENCIES(${lib} aws_sdk_cpp) + SET(loc "${CMAKE_BINARY_DIR}/aws_sdk_cpp/lib/${SDK_INSTALL_BINARY_PREFIX}/${CMAKE_STATIC_LIBRARY_PREFIX}${lib}${CMAKE_STATIC_LIBRARY_SUFFIX}") + SET_TARGET_PROPERTIES(${lib} PROPERTIES IMPORTED_LOCATION ${loc}) + IF(WIN32) + SET_TARGET_PROPERTIES(${lib} PROPERTIES IMPORTED_LINK_INTERFACE_LIBRARIES "bcrypt;winhttp;wininet;userenv") + ELSE() + SET_TARGET_PROPERTIES(${lib} PROPERTIES IMPORTED_LINK_INTERFACE_LIBRARIES "${SSL_LIBRARIES};${CURL_LIBRARIES}") + ENDIF() + ENDFOREACH() + + IF(CMAKE_SYSTEM_NAME MATCHES "Linux") + # Need whole-archive , otherwise static libraries are not linked + SET(AWS_SDK_LIBS -Wl,--whole-archive ${AWS_SDK_LIBS} -Wl,--no-whole-archive) + ENDIF() + SET_TARGET_PROPERTIES(aws_sdk_cpp PROPERTIES EXCLUDE_FROM_ALL TRUE) + INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR}/aws_sdk_cpp/include) +ENDIF() + +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX11_FLAGS}") +TARGET_LINK_LIBRARIES(aws_key_management ${AWS_SDK_LIBS}) diff --git a/plugin/aws_key_management/aws_key_management_plugin.cc b/plugin/aws_key_management/aws_key_management_plugin.cc new file mode 100644 index 00000000000..3913d2c3145 --- /dev/null +++ b/plugin/aws_key_management/aws_key_management_plugin.cc @@ -0,0 +1,587 @@ +/* + Copyright (c) 2016 MariaDB Corporation + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + + +#include <my_global.h> +#include <my_pthread.h> +#include <my_sys.h> +#include <my_dir.h> +#include <mysql/plugin_encryption.h> +#include <my_crypt.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <mysqld_error.h> +#include <base64.h> +#include <map> +#include <algorithm> +#include <string> +#include <vector> +#include <iterator> +#include <sstream> +#include <fstream> + +#include <aws/core/client/AWSError.h> +#include <aws/core/utils/logging/AWSLogging.h> +#include <aws/core/utils/logging/ConsoleLogSystem.h> +#include <aws/kms/KMSClient.h> +#include <aws/kms/model/DecryptRequest.h> +#include <aws/kms/model/DecryptResult.h> +#include <aws/kms/model/GenerateDataKeyWithoutPlaintextRequest.h> +#include <aws/kms/model/GenerateDataKeyWithoutPlaintextResult.h> +#include <aws/core/utils/Outcome.h> + +using namespace std; +using namespace Aws::KMS; +using namespace Aws::KMS::Model; +using namespace Aws::Utils::Logging; +extern void sql_print_error(const char *format, ...); +extern void sql_print_warning(const char *format, ...); +extern void sql_print_information(const char *format, ...); + + +/* Plaintext key info struct */ +struct KEY_INFO +{ + unsigned int key_id; + unsigned int key_version; + unsigned int length; + unsigned char data[MY_AES_MAX_KEY_LENGTH]; + bool load_failed; /* if true, do not attempt to reload?*/ +public: + KEY_INFO() : key_id(0), key_version(0), length(0), load_failed(false){}; +}; +#define KEY_ID_AND_VERSION(key_id,version) ((longlong)key_id << 32 | version) + +/* Cache for the latest version, per key id */ +static std::map<uint, uint> latest_version_cache; + +/* Cache for plaintext keys */ +static std::map<ulonglong, KEY_INFO> key_info_cache; + +static const char *key_spec_names[]={ "AES_128", "AES_256", 0 }; + +/* Plugin variables */ +static char* master_key_id; +static unsigned long key_spec; +static unsigned long log_level; +static int rotate_key; + +/* AWS functionality*/ +static int aws_decrypt_key(const char *path, KEY_INFO *info); +static int aws_generate_datakey(uint key_id, uint version); + +static int extract_id_and_version(const char *name, uint *id, uint *ver); +static unsigned int get_latest_key_version(unsigned int key_id); +static unsigned int get_latest_key_version_nolock(unsigned int key_id); +static int load_key(KEY_INFO *info); + +/* Mutex to serialize access to caches */ +static mysql_mutex_t mtx; + +#ifdef HAVE_PSI_INTERFACE +static uint mtx_key; +static PSI_mutex_info mtx_info = {&mtx_key, "mtx", 0}; +#endif + +static Aws::KMS::KMSClient *client; + +/* Redirect AWS trace to error log */ +class MySQLLogSystem : public Aws::Utils::Logging::FormattedLogSystem +{ +public: + + using Base = FormattedLogSystem; + MySQLLogSystem(LogLevel logLevel) : + Base(logLevel) + { + } + virtual LogLevel GetLogLevel(void) const override + { + return (LogLevel)log_level; + } + virtual ~MySQLLogSystem() + { + } + +protected: + virtual void ProcessFormattedStatement(Aws::String&& statement) override + { +#ifdef _WIN32 + /* + On Windows, we can't use C runtime functions to write to stdout, + because we compile with static C runtime, so plugin has a stdout + different from server. Thus we're using WriteFile(). + */ + DWORD nSize= (DWORD)statement.size(); + DWORD nWritten; + const char *s= statement.c_str(); + HANDLE h= GetStdHandle(STD_OUTPUT_HANDLE); + + WriteFile(h, s, nSize, &nWritten, NULL); +#else + printf("%s", statement.c_str()); +#endif + } +}; + + +/* + Plugin initialization. + + Create KMS client and scan datadir to find out which keys and versions + are present. +*/ +static int plugin_init(void *p) +{ + DBUG_ENTER("plugin_init"); + client = new KMSClient(); + if (!client) + { + sql_print_error("Can not initialize KMS client"); + DBUG_RETURN(-1); + } + InitializeAWSLogging(Aws::MakeShared<MySQLLogSystem>("aws_key_management_plugin", (Aws::Utils::Logging::LogLevel) log_level)); +#ifdef HAVE_PSI_INTERFACE + mysql_mutex_register("aws_key_management", &mtx_info, 1); +#endif + mysql_mutex_init(mtx_key, &mtx, NULL); + + MY_DIR *dirp = my_dir(".", MYF(0)); + if (!dirp) + { + sql_print_error("Can't scan current directory"); + DBUG_RETURN(-1); + } + for (unsigned int i=0; i < dirp->number_of_files; i++) + { + + KEY_INFO info; + if (extract_id_and_version(dirp->dir_entry[i].name, &info.key_id, &info.key_version) == 0) + { + key_info_cache[KEY_ID_AND_VERSION(info.key_id, info.key_version)]= info; + latest_version_cache[info.key_id]= max(info.key_version, latest_version_cache[info.key_id]); + } + } + my_dirend(dirp); + DBUG_RETURN(0); +} + + +static int plugin_deinit(void *p) +{ + DBUG_ENTER("plugin_deinit"); + latest_version_cache.clear(); + key_info_cache.clear(); + mysql_mutex_destroy(&mtx); + delete client; + ShutdownAWSLogging(); + DBUG_RETURN(0); +} + +/* Generate filename to store the ciphered key */ +static void format_keyfile_name(char *buf, size_t size, uint key_id, uint version) +{ + snprintf(buf, size, "aws-kms-key.%u.%u", key_id, version); +} + +/* Extract key id and version from file name */ +static int extract_id_and_version(const char *name, uint *id, uint *ver) +{ + int len; + int n= sscanf(name, "aws-kms-key.%u.%u%n", id, ver, &len); + if (n == 2 && *id > 0 && *ver > 0 && len == (int)strlen(name)) + return 0; + return 1; +} + +/* + Decrypt key stored in aws-kms-key.<id>.<version> + Cache the decrypted key. +*/ +static int load_key(KEY_INFO *info) +{ + int ret; + char path[256]; + DBUG_ENTER("load_key"); + DBUG_PRINT("enter", ("id=%u,ver=%u", info->key_id, info->key_version)); + format_keyfile_name(path, sizeof(path), info->key_id, info->key_version); + ret= aws_decrypt_key(path, info); + if (ret) + info->load_failed= true; + + latest_version_cache[info->key_id]= max(latest_version_cache[info->key_id], info->key_version); + key_info_cache[KEY_ID_AND_VERSION(info->key_id, info->key_version)]= *info; + + if (!ret) + { + sql_print_information("AWS KMS plugin: loaded key %u, version %u, key length %u bit", + info->key_id, info->key_version,(uint)info->length*8); + } + else + { + sql_print_warning("AWS KMS plugin: key %u, version %u could not be decrypted", + info->key_id, info->key_version); + } + DBUG_RETURN(ret); +} + + +/* + Get latest version for the key. + + If key is not decrypted yet, this function also decrypt the key + and error will be returned if decryption fails. + + The reason for that is that Innodb crashes + in case errors are returned by get_key(), + + A new key will be created if it does not exist, provided there is + valid master_key_id. +*/ +static unsigned int get_latest_key_version(unsigned int key_id) +{ + unsigned int ret; + DBUG_ENTER("get_latest_key_version"); + mysql_mutex_lock(&mtx); + ret= get_latest_key_version_nolock(key_id); + mysql_mutex_unlock(&mtx); + DBUG_PRINT("info", ("key=%u,ret=%u", key_id, ret)); + DBUG_RETURN(ret); +} + +static unsigned int get_latest_key_version_nolock(unsigned int key_id) +{ + KEY_INFO info; + uint ver; + DBUG_ENTER("get_latest_key_version_nolock"); + ver= latest_version_cache[key_id]; + if (ver > 0) + { + info= key_info_cache[KEY_ID_AND_VERSION(key_id, ver)]; + } + if (info.load_failed) + { + /* Decryption failed previously, don't retry */ + DBUG_RETURN(ENCRYPTION_KEY_VERSION_INVALID); + } + else if (ver > 0) + { + /* Key exists already, return it*/ + if (info.length > 0) + DBUG_RETURN(ver); + } + else // (ver == 0) + { + /* Generate a new key, version 1 */ + if (!master_key_id[0]) + { + my_printf_error(ER_UNKNOWN_ERROR, + "Can't generate encryption key %u, because 'aws_key_management_master_key_id' parameter is not set", + MYF(0), key_id); + DBUG_RETURN(ENCRYPTION_KEY_VERSION_INVALID); + } + if (aws_generate_datakey(key_id, 1) != 0) + DBUG_RETURN(ENCRYPTION_KEY_VERSION_INVALID); + info.key_id= key_id; + info.key_version= 1; + info.length= 0; + } + + if (load_key(&info)) + DBUG_RETURN(ENCRYPTION_KEY_VERSION_INVALID); + DBUG_RETURN(info.key_version); +} + + +/* + Decrypt a file with KMS +*/ +static int aws_decrypt_key(const char *path, KEY_INFO *info) +{ + DBUG_ENTER("aws_decrypt_key"); + + /* Read file content into memory */ + ifstream ifs(path, ios::binary | ios::ate); + if (!ifs.good()) + { + sql_print_error("can't open file %s", path); + DBUG_RETURN(-1); + } + size_t pos = (size_t)ifs.tellg(); + if (!pos || pos == SIZE_T_MAX) + { + sql_print_error("invalid key file %s", path); + DBUG_RETURN(-1); + } + std::vector<char> contents(pos); + ifs.seekg(0, ios::beg); + ifs.read(&contents[0], pos); + + /* Decrypt data the with AWS */ + DecryptRequest request; + Aws::Utils::ByteBuffer byteBuffer((unsigned char *)contents.data(), pos); + request.SetCiphertextBlob(byteBuffer); + DecryptOutcome outcome = client->Decrypt(request); + if (!outcome.IsSuccess()) + { + sql_print_error("AWS KMS plugin: Decrypt failed for %s : %s", path, + outcome.GetError().GetMessage().c_str()); + DBUG_RETURN(-1); + } + Aws::Utils::ByteBuffer plaintext = outcome.GetResult().GetPlaintext(); + size_t len = plaintext.GetLength(); + + if (len > (int)sizeof(info->data)) + { + sql_print_error("AWS KMS plugin: encoding key too large for %s", path); + DBUG_RETURN(ENCRYPTION_KEY_BUFFER_TOO_SMALL); + } + memcpy(info->data, plaintext.GetUnderlyingData(), len); + info->length= len; + DBUG_RETURN(0); +} + + +/* Generate a new datakey and store it a file */ +static int aws_generate_datakey(uint keyid, uint version) +{ + + DBUG_ENTER("aws_generate_datakey"); + GenerateDataKeyWithoutPlaintextRequest request; + request.SetKeyId(master_key_id); + request.SetKeySpec(DataKeySpecMapper::GetDataKeySpecForName(key_spec_names[key_spec])); + + GenerateDataKeyWithoutPlaintextOutcome outcome; + outcome= client->GenerateDataKeyWithoutPlaintext(request); + if (!outcome.IsSuccess()) + { + sql_print_error("AWS KMS plugin : GenerateDataKeyWithoutPlaintext failed : %s - %s", + outcome.GetError().GetExceptionName().c_str(), + outcome.GetError().GetMessage().c_str()); + DBUG_RETURN(-1); + } + + string out; + char filename[20]; + Aws::Utils::ByteBuffer byteBuffer = outcome.GetResult().GetCiphertextBlob(); + + format_keyfile_name(filename, sizeof(filename), keyid, version); + int fd= my_open(filename, O_RDWR | O_CREAT, 0); + if (fd < 0) + { + sql_print_error("AWS KMS plugin: Can't create file %s", filename); + DBUG_RETURN(-1); + } + size_t len= byteBuffer.GetLength(); + if (my_write(fd, byteBuffer.GetUnderlyingData(), len, 0) != len) + { + sql_print_error("AWS KMS plugin: can't write to %s", filename); + my_close(fd, 0); + my_delete(filename, 0); + DBUG_RETURN(-1); + } + my_close(fd, 0); + sql_print_information("AWS KMS plugin: generated encrypted datakey for key id=%u, version=%u", + keyid, version); + DBUG_RETURN(0); +} + +/* Key rotation for a single key */ +static int rotate_single_key(uint key_id) +{ + uint ver; + ver= latest_version_cache[key_id]; + + if (!ver) + { + my_printf_error(ER_UNKNOWN_ERROR, "key %u does not exist", MYF(ME_JUST_WARNING), key_id); + return -1; + } + else if (aws_generate_datakey(key_id, ver + 1)) + { + my_printf_error(ER_UNKNOWN_ERROR, "Could not generate datakey for key id= %u, ver= %u", + MYF(ME_JUST_WARNING), key_id, ver); + return -1; + } + else + { + KEY_INFO info; + info.key_id= key_id; + info.key_version = ver + 1; + if (load_key(&info)) + { + my_printf_error(ER_UNKNOWN_ERROR, "Could not load datakey for key id= %u, ver= %u", + MYF(ME_JUST_WARNING), key_id, ver); + return -1; + } + } + return 0; +} + +/* Key rotation for all key ids */ +static int rotate_all_keys() +{ + int ret= 0; + for (map<uint, uint>::iterator it= latest_version_cache.begin(); it != latest_version_cache.end(); it++) + { + ret= rotate_single_key(it->first); + if (ret) + break; + } + return ret; +} + +static void update_rotate(MYSQL_THD, struct st_mysql_sys_var *, void *, const void *val) +{ + if (!master_key_id[0]) + { + my_printf_error(ER_UNKNOWN_ERROR, + "aws_key_management_master_key_id must be set to generate new data keys", MYF(ME_JUST_WARNING)); + return; + } + mysql_mutex_lock(&mtx); + rotate_key= *(int *)val; + switch (rotate_key) + { + case 0: + break; + case -1: + rotate_all_keys(); + break; + default: + rotate_single_key(rotate_key); + break; + } + rotate_key= 0; + mysql_mutex_unlock(&mtx); +} + +static unsigned int get_key( + unsigned int key_id, + unsigned int version, + unsigned char* dstbuf, + unsigned int* buflen) +{ + KEY_INFO info; + + DBUG_ENTER("get_key"); + mysql_mutex_lock(&mtx); + info= key_info_cache[KEY_ID_AND_VERSION(key_id, version)]; + if (info.length == 0 && !info.load_failed) + { + info.key_id= key_id; + info.key_version= version; + load_key(&info); + } + mysql_mutex_unlock(&mtx); + if (info.load_failed) + DBUG_RETURN(ENCRYPTION_KEY_VERSION_INVALID); + if (*buflen < info.length) + { + *buflen= info.length; + DBUG_RETURN(ENCRYPTION_KEY_BUFFER_TOO_SMALL); + } + *buflen= info.length; + memcpy(dstbuf, info.data, info.length); + DBUG_RETURN(0); +} + + +/* Plugin defs */ +struct st_mariadb_encryption aws_key_management_plugin= { + MariaDB_ENCRYPTION_INTERFACE_VERSION, + get_latest_key_version, + get_key, + // use default encrypt/decrypt functions + 0, 0, 0, 0, 0 +}; + + +static TYPELIB key_spec_typelib = +{ + array_elements(key_spec_names) - 1, "", + key_spec_names, NULL +}; + +const char *log_level_names[] = +{ + "Off", + "Fatal", + "Error", + "Warn", + "Info", + "Debug", + "Trace", + 0 +}; + +static TYPELIB log_level_typelib = +{ + array_elements(log_level_names) - 1, "", + log_level_names, NULL +}; + +static MYSQL_SYSVAR_STR(master_key_id, master_key_id, + PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC, + "Key id for master encryption key. Used to create new datakeys. If not set, no new keys will be created", + NULL, NULL, ""); + +static MYSQL_SYSVAR_ENUM(key_spec, key_spec, + PLUGIN_VAR_RQCMDARG, + "Encryption algorithm used to create new keys.", + NULL, NULL, 0, &key_spec_typelib); + + +static MYSQL_SYSVAR_ENUM(log_level, log_level, + PLUGIN_VAR_RQCMDARG, + "Logging for AWS API", + NULL, NULL, 0, &log_level_typelib); + + +static MYSQL_SYSVAR_INT(rotate_key, rotate_key, + PLUGIN_VAR_RQCMDARG, + "Set this variable to key id to perform rotation of the key. Specify -1 to rotate all keys", + NULL, update_rotate, 0, -1, INT_MAX, 1); + +static struct st_mysql_sys_var* settings[]= { + MYSQL_SYSVAR(master_key_id), + MYSQL_SYSVAR(key_spec), + MYSQL_SYSVAR(rotate_key), + MYSQL_SYSVAR(log_level), + NULL +}; + +/* + Plugin library descriptor +*/ +maria_declare_plugin(aws_key_management) +{ + MariaDB_ENCRYPTION_PLUGIN, + &aws_key_management_plugin, + "aws_key_management", + "MariaDB Corporation", + "AWS key management plugin", + PLUGIN_LICENSE_GPL, + plugin_init, + plugin_deinit, + 0x0100, + NULL, + settings, + "1.0", + MariaDB_PLUGIN_MATURITY_EXPERIMENTAL +} +maria_declare_plugin_end; diff --git a/plugin/cracklib_password_check/cracklib_password_check.c b/plugin/cracklib_password_check/cracklib_password_check.c index c16075df74b..c593173942d 100644 --- a/plugin/cracklib_password_check/cracklib_password_check.c +++ b/plugin/cracklib_password_check/cracklib_password_check.c @@ -78,6 +78,6 @@ maria_declare_plugin(cracklib_password_check) NULL, sysvars, "1.0", - MariaDB_PLUGIN_MATURITY_ALPHA, + MariaDB_PLUGIN_MATURITY_GAMMA, } maria_declare_plugin_end; diff --git a/plugin/file_key_management/file_key_management_plugin.cc b/plugin/file_key_management/file_key_management_plugin.cc index 970fae9c189..e0afbd68cc9 100644 --- a/plugin/file_key_management/file_key_management_plugin.cc +++ b/plugin/file_key_management/file_key_management_plugin.cc @@ -186,6 +186,6 @@ maria_declare_plugin(file_key_management) NULL, /* status variables */ settings, "1.0", - MariaDB_PLUGIN_MATURITY_ALPHA + MariaDB_PLUGIN_MATURITY_GAMMA } maria_declare_plugin_end; diff --git a/plugin/file_key_management/parser.cc b/plugin/file_key_management/parser.cc index 28cd981df79..628412bc171 100644 --- a/plugin/file_key_management/parser.cc +++ b/plugin/file_key_management/parser.cc @@ -220,7 +220,7 @@ bool Parser::parse_file(Dynamic_array<keyentry> *keys, const char *secret) keys->sort(sort_keys); my_free(buffer); - if (keys->at(0).id != 1) + if (keys->elements() == 0 || keys->at(0).id != 1) { report_error("System key id 1 is missing", 0); return 1; diff --git a/plugin/handler_socket/docs-en/perl-client.en.txt b/plugin/handler_socket/docs-en/perl-client.en.txt index 448d33b5f12..cc9138518ee 100644 --- a/plugin/handler_socket/docs-en/perl-client.en.txt +++ b/plugin/handler_socket/docs-en/perl-client.en.txt @@ -42,7 +42,7 @@ to be retrieved are specified by the 5th argument for the corresponding open_index call. The execute_single method always returns an arrayref. The first -element is the error code, which is 0 when no error is occured. +element is the error code, which is 0 when no error is occurred. The remaining are the field values. If more than one record is returned, it is flatten to an 1-dimensional array. For example, when 5 records that have 3 columns are returned, you can retrieve @@ -125,9 +125,9 @@ methods. die $hs->get_error() if $res->[0] != 0; ----------------------------------------------------------------- -When an error is occured, the first element of the returned +When an error is occurred, the first element of the returned arrayref becomes a non-zero value. A negative value indicates -that an I/O error is occured and the Net::HandlerSocket object +that an I/O error is occurred and the Net::HandlerSocket object should be disposed. A positive value means that the connection is still active and the Net::HandlerSocket object can be reused later. diff --git a/plugin/handler_socket/handlersocket/database.cpp b/plugin/handler_socket/handlersocket/database.cpp index cfed9c42c0a..94eedbf6d04 100644 --- a/plugin/handler_socket/handlersocket/database.cpp +++ b/plugin/handler_socket/handlersocket/database.cpp @@ -304,6 +304,7 @@ dbcontext::init_thread(const void *stack_bottom, volatile int& shutdown_flag) thd->db = 0; thd->db = my_strdup("handlersocket", MYF(0)); } + thd->variables.option_bits |= OPTION_TABLE_LOCK; my_pthread_setspecific_ptr(THR_THD, thd); DBG_THR(fprintf(stderr, "HNDSOCK x0 %p\n", thd)); } @@ -341,7 +342,7 @@ void dbcontext::term_thread() { DBG_THR(fprintf(stderr, "HNDSOCK thread end %p\n", thd)); - unlock_tables_if(); + close_tables_if(); my_pthread_setspecific_ptr(THR_THD, 0); { pthread_mutex_lock(&LOCK_thread_count); diff --git a/plugin/locale_info/locale_info.cc b/plugin/locale_info/locale_info.cc index dd14dcbb769..3d775c0be7c 100644 --- a/plugin/locale_info/locale_info.cc +++ b/plugin/locale_info/locale_info.cc @@ -117,6 +117,6 @@ maria_declare_plugin(locales) NULL, /* Status variables */ NULL, /* System variables */ "1.0", /* String version representation */ - MariaDB_PLUGIN_MATURITY_GAMMA /* Maturity (see include/mysql/plugin.h)*/ + MariaDB_PLUGIN_MATURITY_STABLE /* Maturity (see include/mysql/plugin.h)*/ } maria_declare_plugin_end; diff --git a/plugin/metadata_lock_info/metadata_lock_info.cc b/plugin/metadata_lock_info/metadata_lock_info.cc index fcfdb59da30..83db2c7ca5c 100644 --- a/plugin/metadata_lock_info/metadata_lock_info.cc +++ b/plugin/metadata_lock_info/metadata_lock_info.cc @@ -164,7 +164,7 @@ maria_declare_plugin(metadata_lock_info) NULL, NULL, NULL, - MariaDB_PLUGIN_MATURITY_GAMMA, + MariaDB_PLUGIN_MATURITY_STABLE } maria_declare_plugin_end; #else diff --git a/plugin/qc_info/qc_info.cc b/plugin/qc_info/qc_info.cc index 998076dadf7..4ccfdc8f8c2 100644 --- a/plugin/qc_info/qc_info.cc +++ b/plugin/qc_info/qc_info.cc @@ -282,7 +282,7 @@ maria_declare_plugin(query_cache_info) NULL, /* status variables */ NULL, /* system variables */ "1.1", /* version as a string */ - MariaDB_PLUGIN_MATURITY_GAMMA + MariaDB_PLUGIN_MATURITY_STABLE } maria_declare_plugin_end; diff --git a/plugin/query_response_time/mysql-test/query_response_time/basic.result b/plugin/query_response_time/mysql-test/query_response_time/basic.result index 15746424b1d..86fba87e056 100644 --- a/plugin/query_response_time/mysql-test/query_response_time/basic.result +++ b/plugin/query_response_time/mysql-test/query_response_time/basic.result @@ -17,7 +17,7 @@ PLUGIN_TYPE INFORMATION SCHEMA PLUGIN_AUTHOR Percona and Sergey Vojtovich PLUGIN_DESCRIPTION Query Response Time Distribution INFORMATION_SCHEMA Plugin PLUGIN_LICENSE GPL -PLUGIN_MATURITY Gamma +PLUGIN_MATURITY Stable PLUGIN_NAME QUERY_RESPONSE_TIME_AUDIT PLUGIN_VERSION 1.0 PLUGIN_TYPE AUDIT diff --git a/plugin/query_response_time/plugin.cc b/plugin/query_response_time/plugin.cc index c34e4cb6e02..37d52c3ce85 100644 --- a/plugin/query_response_time/plugin.cc +++ b/plugin/query_response_time/plugin.cc @@ -144,7 +144,7 @@ maria_declare_plugin(query_response_time) NULL, query_response_time_info_vars, "1.0", - MariaDB_PLUGIN_MATURITY_GAMMA + MariaDB_PLUGIN_MATURITY_STABLE }, { MYSQL_AUDIT_PLUGIN, diff --git a/plugin/semisync/semisync_master.h b/plugin/semisync/semisync_master.h index d9dc4ce024b..c2862476ec8 100644 --- a/plugin/semisync/semisync_master.h +++ b/plugin/semisync/semisync_master.h @@ -102,7 +102,7 @@ public: it are in use. A new Block is allocated and is put into the rear of the Block link table if no Block is free. - @return Return a TranxNode *, or NULL if an error occured. + @return Return a TranxNode *, or NULL if an error occurred. */ TranxNode *allocate_node() { @@ -134,7 +134,7 @@ public: /** All nodes are freed. - @return Return 0, or 1 if an error occured. + @return Return 0, or 1 if an error occurred. */ int free_all_nodes() { @@ -150,7 +150,7 @@ public: @param node All nodes before 'node' will be freed - @return Return 0, or 1 if an error occured. + @return Return 0, or 1 if an error occurred. */ int free_nodes_before(TranxNode* node) { diff --git a/plugin/semisync/semisync_master_plugin.cc b/plugin/semisync/semisync_master_plugin.cc index 7bb0eea44ee..309910312c4 100644 --- a/plugin/semisync/semisync_master_plugin.cc +++ b/plugin/semisync/semisync_master_plugin.cc @@ -489,7 +489,7 @@ maria_declare_plugin(semisync_master) semi_sync_master_status_vars, /* status variables */ semi_sync_master_system_vars, /* system variables */ "1.0", - MariaDB_PLUGIN_MATURITY_GAMMA + MariaDB_PLUGIN_MATURITY_STABLE } maria_declare_plugin_end; diff --git a/plugin/semisync/semisync_slave_plugin.cc b/plugin/semisync/semisync_slave_plugin.cc index 572ead214de..3a6c7625d93 100644 --- a/plugin/semisync/semisync_slave_plugin.cc +++ b/plugin/semisync/semisync_slave_plugin.cc @@ -227,7 +227,7 @@ maria_declare_plugin(semisync_slave) semi_sync_slave_status_vars, /* status variables */ semi_sync_slave_system_vars, /* system variables */ "1.0", - MariaDB_PLUGIN_MATURITY_GAMMA + MariaDB_PLUGIN_MATURITY_STABLE } maria_declare_plugin_end; diff --git a/plugin/simple_password_check/simple_password_check.c b/plugin/simple_password_check/simple_password_check.c index f6d3e5b7a69..7ad8bfc811a 100644 --- a/plugin/simple_password_check/simple_password_check.c +++ b/plugin/simple_password_check/simple_password_check.c @@ -104,6 +104,6 @@ maria_declare_plugin(simple_password_check) NULL, sysvars, "1.0", - MariaDB_PLUGIN_MATURITY_ALPHA, + MariaDB_PLUGIN_MATURITY_GAMMA } maria_declare_plugin_end; diff --git a/plugin/sql_errlog/sql_errlog.c b/plugin/sql_errlog/sql_errlog.c index 1c7e141c022..6ec4659d407 100644 --- a/plugin/sql_errlog/sql_errlog.c +++ b/plugin/sql_errlog/sql_errlog.c @@ -158,6 +158,6 @@ maria_declare_plugin(sql_errlog) NULL, vars, "1.0", - MariaDB_PLUGIN_MATURITY_GAMMA + MariaDB_PLUGIN_MATURITY_STABLE } maria_declare_plugin_end; diff --git a/plugin/userstat/userstat.cc b/plugin/userstat/userstat.cc index 6ffee44f43c..69832f817c1 100644 --- a/plugin/userstat/userstat.cc +++ b/plugin/userstat/userstat.cc @@ -31,7 +31,7 @@ maria_declare_plugin(userstat) NULL, NULL, "2.0", - MariaDB_PLUGIN_MATURITY_GAMMA + MariaDB_PLUGIN_MATURITY_STABLE }, { MYSQL_INFORMATION_SCHEMA_PLUGIN, @@ -46,7 +46,7 @@ maria_declare_plugin(userstat) NULL, NULL, "2.0", - MariaDB_PLUGIN_MATURITY_GAMMA + MariaDB_PLUGIN_MATURITY_STABLE }, { MYSQL_INFORMATION_SCHEMA_PLUGIN, diff --git a/plugin/wsrep_info/plugin.cc b/plugin/wsrep_info/plugin.cc index f3de177c85f..b8aaee5a132 100644 --- a/plugin/wsrep_info/plugin.cc +++ b/plugin/wsrep_info/plugin.cc @@ -245,7 +245,7 @@ maria_declare_plugin(wsrep_info) NULL, /* Status variables */ NULL, /* System variables */ "1.0", /* Version (string) */ - MariaDB_PLUGIN_MATURITY_ALPHA /* Maturity */ + MariaDB_PLUGIN_MATURITY_GAMMA /* Maturity */ }, { MYSQL_INFORMATION_SCHEMA_PLUGIN, @@ -260,7 +260,7 @@ maria_declare_plugin(wsrep_info) NULL, /* Status variables */ NULL, /* System variables */ "1.0", /* Version (string) */ - MariaDB_PLUGIN_MATURITY_ALPHA /* Maturity */ + MariaDB_PLUGIN_MATURITY_GAMMA /* Maturity */ } maria_declare_plugin_end; |