Commit 7bf40959 authored by Vladislav Vaintroub's avatar Vladislav Vaintroub Committed by Sergei Golubchik

MDEV-11660 Make encryption plugins "pure"

Do not exporting mysqld entry points directly.
This is needed for mariabackup, to load encryption plugins on Windows.

All plugins are "pure" by default. To mark plugin "impure"
it should use RECOMPILE_FOR_EMBEDDED or STORAGE_ENGINE keyword.
parent db391074
......@@ -201,13 +201,15 @@ MACRO(MYSQL_ADD_PLUGIN)
# executable to the linker command line (it would result into link error).
# Thus we skip TARGET_LINK_LIBRARIES on Linux, as it would only generate
# an additional dependency.
IF(NOT ARG_CLIENT)
IF(ARG_RECOMPILE_FOR_EMBEDDED OR ARG_STORAGE_ENGINE)
IF(MSVC)
ADD_DEPENDENCIES(${target} gen_mysqld_lib)
TARGET_LINK_LIBRARIES(${target} mysqld_import_lib)
ELSEIF(NOT CMAKE_SYSTEM_NAME STREQUAL "Linux")
TARGET_LINK_LIBRARIES (${target} mysqld)
ENDIF()
ELSEIF(CMAKE_SYSTEM_NAME STREQUAL "Linux")
TARGET_LINK_LIBRARIES (${target} "-Wl,--no-undefined")
ENDIF()
IF(ARG_LINK_LIBRARIES)
......
......@@ -28,7 +28,7 @@ select plugin_status from information_schema.plugins
where plugin_name = 'file_key_management';
plugin_status
install soname 'file_key_management';
ERROR HY000: Invalid key id at MYSQL_TMP_DIR/keys.txt line 2, column 11
ERROR HY000: Invalid key id at MYSQL_TMP_DIR/keys.txt line 2, column 10
call mtr.add_suppression("Invalid key id");
call mtr.add_suppression("Plugin 'file_key_management' init function returned error");
call mtr.add_suppression("Plugin 'file_key_management' registration.*failed");
......
......@@ -15,5 +15,8 @@
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
ADD_DEFINITIONS(-DNO_GET_TTY_PASSWORD)
IF(LIBDL)
SET(LLDL LINK_LIBRARIES dl)
ENDIF()
MYSQL_ADD_PLUGIN(dialog dialog.c ${CMAKE_SOURCE_DIR}/libmysql/get_password.c
MODULE_ONLY CLIENT COMPONENT ClientPlugins)
MODULE_ONLY CLIENT ${LLDL} COMPONENT ClientPlugins)
......@@ -13,7 +13,8 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
MYSQL_ADD_PLUGIN(daemon_example daemon_example.cc
MYSQL_ADD_PLUGIN(daemon_example daemon_example.cc RECOMPILE_FOR_EMBEDDED
MODULE_ONLY MODULE_OUTPUT_NAME "libdaemon_example" COMPONENT Test)
INSTALL(FILES daemon_example.ini DESTINATION ${INSTALL_PLUGINDIR} COMPONENT Test)
INSTALL(FILES daemon_example.ini DESTINATION ${INSTALL_PLUGINDIR}
COMPONENT Test)
......@@ -28,18 +28,24 @@
#include <my_global.h>
#include <my_pthread.h>
#include <mysql/plugin_encryption.h>
#include <my_rnd.h>
#include <my_crypt.h>
/* rotate key randomly between 45 and 90 seconds */
#define KEY_ROTATION_MIN 45
#define KEY_ROTATION_MAX 90
static struct my_rnd_struct seed;
static time_t key_version = 0;
static time_t next_key_version = 0;
static pthread_mutex_t mutex;
/* Random double value in 0..1 range */
static double double_rnd()
{
return ((double)rand()) / RAND_MAX;
}
static unsigned int
get_latest_key_version(unsigned int key_id)
{
......@@ -50,7 +56,7 @@ get_latest_key_version(unsigned int key_id)
key_version = now;
unsigned int interval = KEY_ROTATION_MAX - KEY_ROTATION_MIN;
next_key_version = (time_t) (now + KEY_ROTATION_MIN +
my_rnd(&seed) * interval);
double_rnd() * interval);
}
pthread_mutex_unlock(&mutex);
......@@ -101,7 +107,6 @@ static unsigned int get_length(unsigned int slen, unsigned int key_id,
static int example_key_management_plugin_init(void *p)
{
/* init */
my_rnd_init(&seed, time(0), 0);
pthread_mutex_init(&mutex, NULL);
get_latest_key_version(1);
......
......@@ -66,22 +66,14 @@ static struct st_mysql_sys_var* settings[] = {
NULL
};
Dynamic_array<keyentry> keys(static_cast<uint>(0));
std::map<unsigned int,keyentry> keys;
static keyentry *get_key(unsigned int key_id)
{
keyentry *a= keys.front(), *b= keys.back() + 1, *c;
while (b - a > 1)
{
c= a + (b - a)/2;
if (c->id == key_id)
return c;
else if (c->id < key_id)
a= c;
else
b= c;
}
return a->id == key_id ? a : 0;
keyentry &key= keys[key_id];
if (key.id == 0)
return 0;
return &key;
}
/* the version is always the same, no automatic key rotation */
......
......@@ -143,13 +143,13 @@ void Parser::bytes_to_key(const unsigned char *salt, const char *input,
}
bool Parser::parse(Dynamic_array<keyentry> *keys)
bool Parser::parse(std::map<uint,keyentry> *keys)
{
const char *secret= filekey;
char buf[MAX_SECRET_SIZE + 1];
//If secret starts with FILE: interpret the secret as a filename.
if (is_prefix(filekey, FILE_PREFIX))
if (strncmp(filekey, FILE_PREFIX,sizeof(FILE_PREFIX) -1) == 0)
{
if (read_filekey(filekey + sizeof(FILE_PREFIX) - 1, buf))
return 1;
......@@ -166,22 +166,26 @@ bool Parser::parse(Dynamic_array<keyentry> *keys)
bool Parser::read_filekey(const char *filekey, char *secret)
{
int f= my_open(filekey, O_RDONLY, MYF(MY_WME));
int f= open(filekey, O_RDONLY|O_BINARY);
if (f == -1)
{
my_error(EE_FILENOTFOUND,ME_ERROR_LOG, filekey, errno);
return 1;
int len= my_read(f, (uchar*)secret, MAX_SECRET_SIZE, MYF(MY_WME));
my_close(f, MYF(MY_WME));
}
int len= read(f, secret, MAX_SECRET_SIZE);
if (len <= 0)
{
my_error(EE_READ,ME_ERROR_LOG, filekey, errno);
close(f);
return 1;
}
close(f);
while (secret[len - 1] == '\r' || secret[len - 1] == '\n') len--;
secret[len]= '\0';
return 0;
}
static int sort_keys(const keyentry *k1, const keyentry *k2)
{
return k1->id < k2->id ? -1 : k1->id > k2->id;
}
/**
Get the keys from the key file <filename> and decrypt it with the
......@@ -191,7 +195,7 @@ static int sort_keys(const keyentry *k1, const keyentry *k2)
@return 0 when ok, 1 for an error
*/
bool Parser::parse_file(Dynamic_array<keyentry> *keys, const char *secret)
bool Parser::parse_file(std::map<uint,keyentry> *keys, const char *secret)
{
char *buffer= read_and_decrypt_file(secret);
......@@ -208,19 +212,16 @@ bool Parser::parse_file(Dynamic_array<keyentry> *keys, const char *secret)
case 1: // comment
break;
case -1: // error
my_free(buffer);
free(buffer);
return 1;
case 0:
if (keys->push(key))
return 1;
(*keys)[key.id] = key;
break;
}
}
keys->sort(sort_keys);
my_free(buffer);
if (keys->elements() == 0 || keys->at(0).id != 1)
free(buffer);
if (keys->size() == 0 || (*keys)[1].id == 0)
{
report_error("System key id 1 is missing", 0);
return 1;
......@@ -247,16 +248,25 @@ int Parser::parse_line(char **line_ptr, keyentry *key)
while (isspace(*p) && *p != '\n') p++;
if (*p != '#' && *p != '\n')
{
int error;
p+= 100; // the number will surely end here (on a non-digit or with an overflow)
longlong id= my_strtoll10(p - 100, &p, &error);
if (error)
if (!isdigit(*p))
{
report_error("Syntax error", p - *line_ptr);
return -1;
}
if (id < 1 || id > UINT_MAX32)
longlong id = 0;
while (isdigit(*p))
{
id = id * 10 + *p - '0';
if (id > UINT_MAX32)
{
report_error("Invalid key id", p - *line_ptr);
return -1;
}
p++;
}
if (id < 1)
{
report_error("Invalid key id", p - *line_ptr);
return -1;
......@@ -269,7 +279,7 @@ int Parser::parse_line(char **line_ptr, keyentry *key)
}
p++;
key->id= id;
key->id= (unsigned int)id;
key->length=0;
while (isxdigit(p[0]) && isxdigit(p[1]) && key->length < sizeof(key->key))
{
......@@ -295,9 +305,13 @@ int Parser::parse_line(char **line_ptr, keyentry *key)
'secret'. Store the content of the decrypted file in 'buffer'. The
buffer has to be freed in the calling function.
*/
#ifdef _WIN32
#define lseek _lseeki64
#endif
char* Parser::read_and_decrypt_file(const char *secret)
{
int f;
if (!filename || !filename[0])
{
my_printf_error(EE_CANT_OPEN_STREAM, "file-key-management-filename is not set",
......@@ -305,15 +319,21 @@ char* Parser::read_and_decrypt_file(const char *secret)
goto err0;
}
int f;
if ((f= my_open(filename, O_RDONLY, MYF(MY_WME))) < 0)
f= open(filename, O_RDONLY|O_BINARY, 0);
if (f < 0)
{
my_error(EE_FILENOTFOUND, ME_ERROR_LOG, filename, errno);
goto err0;
}
my_off_t file_size;
file_size= my_seek(f, 0, SEEK_END, MYF(MY_WME));
file_size= lseek(f, 0, SEEK_END);
if (file_size == MY_FILEPOS_ERROR)
if (file_size == MY_FILEPOS_ERROR || (my_off_t)lseek(f, 0, SEEK_SET) == MY_FILEPOS_ERROR)
{
my_error(EE_CANT_SEEK, MYF(0), filename, errno);
goto err1;
}
if (file_size > MAX_KEY_FILE_SIZE)
{
......@@ -323,29 +343,39 @@ char* Parser::read_and_decrypt_file(const char *secret)
//Read file into buffer
uchar *buffer;
buffer= (uchar*)my_malloc(file_size + 1, MYF(MY_WME));
buffer= (uchar*)malloc((size_t)file_size + 1);
if (!buffer)
{
my_error(EE_OUTOFMEMORY, ME_ERROR_LOG| ME_FATAL, file_size);
goto err1;
}
if (my_pread(f, buffer, file_size, 0, MYF(MY_WME)) != file_size)
if (read(f, buffer, (int)file_size) != (int)file_size)
{
my_printf_error(EE_READ,
"read from %s failed, errno %d",
MYF(ME_ERROR_LOG|ME_FATAL), filename, errno);
goto err2;
}
// Check for file encryption
uchar *decrypted;
if (file_size > OpenSSL_prefix_len && is_prefix((char*)buffer, OpenSSL_prefix))
if (file_size > OpenSSL_prefix_len && strncmp((char*)buffer, OpenSSL_prefix, OpenSSL_prefix_len) == 0)
{
uchar key[OpenSSL_key_len];
uchar iv[OpenSSL_iv_len];
decrypted= (uchar*)my_malloc(file_size, MYF(MY_WME));
decrypted= (uchar*)malloc((size_t)file_size);
if (!decrypted)
{
my_error(EE_OUTOFMEMORY, ME_ERROR_LOG | ME_FATAL, file_size);
goto err2;
}
bytes_to_key(buffer + OpenSSL_prefix_len, secret, key, iv);
uint32 d_size;
if (my_aes_crypt(MY_AES_CBC, ENCRYPTION_FLAG_DECRYPT,
buffer + OpenSSL_prefix_len + OpenSSL_salt_len,
file_size - OpenSSL_prefix_len - OpenSSL_salt_len,
(unsigned int)file_size - OpenSSL_prefix_len - OpenSSL_salt_len,
decrypted, &d_size, key, OpenSSL_key_len,
iv, OpenSSL_iv_len))
......@@ -354,7 +384,7 @@ char* Parser::read_and_decrypt_file(const char *secret)
goto err3;
}
my_free(buffer);
free(buffer);
buffer= decrypted;
file_size= d_size;
}
......@@ -365,15 +395,15 @@ char* Parser::read_and_decrypt_file(const char *secret)
}
buffer[file_size]= '\0';
my_close(f, MYF(MY_WME));
close(f);
return (char*) buffer;
err3:
my_free(decrypted);
free(decrypted);
err2:
my_free(buffer);
free(buffer);
err1:
my_close(f, MYF(MY_WME));
close(f);
err0:
return NULL;
}
......@@ -22,7 +22,7 @@ Created 09/15/2014
#include <my_crypt.h>
#include <ctype.h>
#include <sql_array.h>
#include <map>
struct keyentry {
unsigned int id;
......@@ -42,7 +42,7 @@ class Parser
void bytes_to_key(const unsigned char *salt, const char *secret,
unsigned char *key, unsigned char *iv);
bool read_filekey(const char *filekey, char *secret);
bool parse_file(Dynamic_array<keyentry> *keys, const char *secret);
bool parse_file(std::map<unsigned int ,keyentry> *keys, const char *secret);
void report_error(const char *reason, unsigned int position);
int parse_line(char **line_ptr, keyentry *key);
char* read_and_decrypt_file(const char *secret);
......@@ -50,5 +50,5 @@ class Parser
public:
Parser(const char* fn, const char *fk) :
filename(fn), filekey(fk), line_number(0) { }
bool parse(Dynamic_array<keyentry> *keys);
bool parse(std::map<unsigned int ,keyentry> *keys);
};
......@@ -34,6 +34,6 @@ SET(HANDLERSOCKET_SOURCES
MYSQL_ADD_PLUGIN(handlersocket
${HANDLERSOCKET_SOURCES}
MODULE_ONLY COMPONENT Server
LINK_LIBRARIES hsclient
LINK_LIBRARIES hsclient RECOMPILE_FOR_EMBEDDED
)
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/sql ${CMAKE_SOURCE_DIR}/regex
${CMAKE_SOURCE_DIR}/extra/yassl/include)
MYSQL_ADD_PLUGIN(LOCALES locale_info.cc)
MYSQL_ADD_PLUGIN(LOCALES locale_info.cc RECOMPILE_FOR_EMBEDDED)
SET(METADATA_LOCK_INFO_SOURCES metadata_lock_info.cc)
MYSQL_ADD_PLUGIN(metadata_lock_info ${METADATA_LOCK_INFO_SOURCES} MODULE_OUTPUT_NAME "metadata_lock_info")
MYSQL_ADD_PLUGIN(metadata_lock_info ${METADATA_LOCK_INFO_SOURCES}
RECOMPILE_FOR_EMBEDDED)
......@@ -2,4 +2,4 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/sql
${PCRE_INCLUDES}
${CMAKE_SOURCE_DIR}/extra/yassl/include)
MYSQL_ADD_PLUGIN(QUERY_CACHE_INFO qc_info.cc)
MYSQL_ADD_PLUGIN(QUERY_CACHE_INFO qc_info.cc RECOMPILE_FOR_EMBEDDED)
ADD_DEFINITIONS(-DHAVE_RESPONSE_TIME_DISTRIBUTION)
MYSQL_ADD_PLUGIN(QUERY_RESPONSE_TIME query_response_time.cc plugin.cc)
MYSQL_ADD_PLUGIN(QUERY_RESPONSE_TIME query_response_time.cc plugin.cc
RECOMPILE_FOR_EMBEDDED)
......@@ -17,10 +17,12 @@ SET(SEMISYNC_MASTER_SOURCES
semisync.cc semisync_master.cc semisync_master_plugin.cc
semisync.h semisync_master.h)
MYSQL_ADD_PLUGIN(semisync_master ${SEMISYNC_MASTER_SOURCES})
MYSQL_ADD_PLUGIN(semisync_master ${SEMISYNC_MASTER_SOURCES}
RECOMPILE_FOR_EMBEDDED)
SET(SEMISYNC_SLAVE_SOURCES semisync.cc semisync_slave.cc
semisync_slave_plugin.cc semisync.h semisync_slave.h )
MYSQL_ADD_PLUGIN(semisync_slave ${SEMISYNC_SLAVE_SOURCES})
MYSQL_ADD_PLUGIN(semisync_slave ${SEMISYNC_SLAVE_SOURCES}
RECOMPILE_FOR_EMBEDDED)
......@@ -13,7 +13,6 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
SET(SERVER_AUDIT_SOURCES
server_audit.c test_audit_v4.c plugin_audit_v4.h)
SET(SOURCES server_audit.c test_audit_v4.c plugin_audit_v4.h)
MYSQL_ADD_PLUGIN(server_audit ${SERVER_AUDIT_SOURCES} MODULE_ONLY)
MYSQL_ADD_PLUGIN(server_audit ${SOURCES} MODULE_ONLY RECOMPILE_FOR_EMBEDDED)
IF (WITH_WSREP)
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/sql
${CMAKE_SOURCE_DIR}/wsrep)
MYSQL_ADD_PLUGIN(WSREP_INFO plugin.cc MODULE_ONLY)
MYSQL_ADD_PLUGIN(WSREP_INFO plugin.cc MODULE_ONLY RECOMPILE_FOR_EMBEDDED)
ENDIF()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment