#At file:///home/acorreia/workspace.oracle/repository.mysql/bzrwork/wl-4143/mysql-trunk/ based on revid:alexander.barkov@stripped
3345 Alfranio Correia 2011-04-18
WL#4143
@ mysql-test/suite/funcs_1/r/is_columns_mysql.result
Updated test case due to change in slave_master_info.
@ mysql-test/suite/rpl/r/rpl_master_connection.result
Created a new test case. Plugins are not enabled yet.
@ mysql-test/suite/rpl/t/rpl_master_connection-master.opt
Created a new test case. Plugins are not enabled yet.
@ mysql-test/suite/rpl/t/rpl_master_connection-slave.opt
Created a new test case. Plugins are not enabled yet.
@ mysql-test/suite/rpl/t/rpl_master_connection.test
Created a new test case. Plugins are not enabled yet.
@ scripts/mysql_system_tables.sql
Changed password's definition to store encrypted passwords.
@ sql/CMakeLists.txt
Added secure_store to cmake lists.
@ sql/lex.h
Changed the parser to allow:
. START SLAVE USER=<xxxx> PASSWORD=<yyyy> DEFAULT_AUTH=<zzzz> PLUGIN_DIR=<wwww>
@ sql/rpl_handler.cc
User is now private and there is a function to retrieve it.
@ sql/rpl_info_file.cc
Defined methods to store and retrieve binary data from replication files.
@ sql/rpl_info_file.h
Defined methods to store and retrieve binary data from replication files.
@ sql/rpl_info_handler.h
Defined methods to store and retrieve binary data from replication repository.
@ sql/rpl_info_table.cc
Defined methods to store and retrieve binary data from replication tables.
@ sql/rpl_info_table.h
Defined methods to store and retrieve binary data from replication tables.
@ sql/rpl_mi.cc
Added information to process the new START SLAVE syntax and to use the
secure store to retrieve and store passwords.
In this WL, we provide a sketch of the secure store passowrd and in
fact the password is stored in the master.info repository. Currently
, the secure store is used to keep an encrypted password in memory
and to decrypt it if necessary.
@ sql/rpl_mi.h
Added information to process the new START SLAVE syntax. Note that the
password is not kept in the Master_info anymore.
@ sql/rpl_rli.cc
Updated this due to changes in the rpl_info_handler.h.
@ sql/rpl_slave.cc
Before connecting the password is decrypted and if authentication
plugins were provide, they are used.
@ sql/secure_store.cc
Sketch of the secure store. See WL#5769.
@ sql/secure_store.h
Sketch of the secure store. See WL#5769.
@ sql/sql_lex.h
Added a structure to carry on the new information:
. START SLAVE USER=<xxxx> PASSWORD=<yyyy> DEFAULT_AUTH=<zzzz> PLUGIN_DIR=<wwww>
@ sql/sql_parse.cc
Set information in in-memory master.info.
@ sql/sql_yacc.yy
Changed the parser to allow:
. START SLAVE USER=<xxxx> PASSWORD=<yyyy> DEFAULT_AUTH=<zzzz> PLUGIN_DIR=<wwww>
added:
mysql-test/suite/rpl/r/rpl_master_connection.result
mysql-test/suite/rpl/t/rpl_master_connection-master.opt
mysql-test/suite/rpl/t/rpl_master_connection-slave.opt
mysql-test/suite/rpl/t/rpl_master_connection.test
sql/secure_store.cc
sql/secure_store.h
modified:
mysql-test/suite/funcs_1/r/is_columns_mysql.result
scripts/mysql_system_tables.sql
sql/CMakeLists.txt
sql/lex.h
sql/rpl_handler.cc
sql/rpl_info_file.cc
sql/rpl_info_file.h
sql/rpl_info_handler.h
sql/rpl_info_table.cc
sql/rpl_info_table.h
sql/rpl_mi.cc
sql/rpl_mi.h
sql/rpl_rli.cc
sql/rpl_slave.cc
sql/sql_lex.h
sql/sql_parse.cc
sql/sql_yacc.yy
=== modified file 'mysql-test/suite/funcs_1/r/is_columns_mysql.result'
--- a/mysql-test/suite/funcs_1/r/is_columns_mysql.result 2011-03-18 14:58:27 +0000
+++ b/mysql-test/suite/funcs_1/r/is_columns_mysql.result 2011-04-18 06:30:30 +0000
@@ -169,7 +169,7 @@ def mysql slave_master_info Ssl_cipher 1
def mysql slave_master_info Ssl_key 15 NULL YES text 65535 65535 NULL NULL utf8 utf8_bin text select,insert,update,references
def mysql slave_master_info Ssl_verify_servert_cert 16 NULL NO tinyint NULL NULL 3 0 NULL NULL tinyint(1) select,insert,update,references
def mysql slave_master_info User_name 6 NULL YES text 65535 65535 NULL NULL utf8 utf8_bin text select,insert,update,references
-def mysql slave_master_info User_password 7 NULL YES text 65535 65535 NULL NULL utf8 utf8_bin text select,insert,update,references
+def mysql slave_master_info User_password 7 NULL NO blob 65535 65535 NULL NULL NULL NULL blob select,insert,update,references
def mysql slave_master_info Uuid 20 NULL YES text 65535 65535 NULL NULL utf8 utf8_bin text select,insert,update,references
def mysql slave_relay_log_info Master_id 1 NULL NO int NULL NULL 10 0 NULL NULL int(10) unsigned PRI select,insert,update,references
def mysql slave_relay_log_info Master_log_name 5 NULL NO text 65535 65535 NULL NULL utf8 utf8_bin text select,insert,update,references
@@ -479,7 +479,7 @@ NULL mysql slave_master_info Number_of_l
NULL mysql slave_master_info Master_log_pos bigint NULL NULL NULL NULL bigint(20) unsigned
1.0000 mysql slave_master_info Host text 65535 65535 utf8 utf8_bin text
1.0000 mysql slave_master_info User_name text 65535 65535 utf8 utf8_bin text
-1.0000 mysql slave_master_info User_password text 65535 65535 utf8 utf8_bin text
+1.0000 mysql slave_master_info User_password blob 65535 65535 NULL NULL blob
NULL mysql slave_master_info Port int NULL NULL NULL NULL int(10) unsigned
NULL mysql slave_master_info Connect_retry int NULL NULL NULL NULL int(10) unsigned
NULL mysql slave_master_info Enabled_ssl tinyint NULL NULL NULL NULL tinyint(1)
=== added file 'mysql-test/suite/rpl/r/rpl_master_connection.result'
--- a/mysql-test/suite/rpl/r/rpl_master_connection.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/r/rpl_master_connection.result 2011-04-18 06:30:30 +0000
@@ -0,0 +1,104 @@
+include/master-slave.inc
+[connection master]
+SET SQL_LOG_BIN=0;
+SELECT user, plugin, authentication_string FROM mysql.user WHERE user != 'root';
+user plugin authentication_string
+CREATE USER plug_user_p IDENTIFIED WITH test_plugin_server AS 'password';
+CREATE USER plug_user_wp IDENTIFIED WITH test_plugin_server AS '';
+CREATE USER regular_user_p IDENTIFIED BY 'password';
+CREATE USER regular_user_wp IDENTIFIED BY '';
+SELECT user, plugin, authentication_string FROM mysql.user WHERE user != 'root';
+user plugin authentication_string
+plug_user_p test_plugin_server password
+plug_user_wp test_plugin_server
+regular_user_p NULL
+regular_user_wp NULL
+GRANT REPLICATION SLAVE ON *.* TO plug_user_p;
+GRANT REPLICATION SLAVE ON *.* TO plug_user_wp;
+GRANT REPLICATION SLAVE ON *.* TO regular_user_p;
+GRANT REPLICATION SLAVE ON *.* TO regular_user_wp;
+SET SQL_LOG_BIN=1;
+include/stop_slave.inc
+SET @@GLOBAL.master_info_repository= "TABLE";
+include/stop_slave.inc
+Warnings:
+Note 1255 Slave already has been stopped
+CHANGE MASTER TO MASTER_USER= 'DOES NOT EXIST', MASTER_PASSWORD = 'DOES NOT EXIST';
+START SLAVE USER= 'regular_user_p' PASSWORD= 'password';
+include/wait_for_slave_to_start.inc
+include/check_slave_is_running.inc
+include/stop_slave.inc
+CHANGE MASTER TO MASTER_USER= 'DOES NOT EXIST', MASTER_PASSWORD = 'DOES NOT EXIST';
+START SLAVE USER= 'regular_user_wp' PASSWORD= '';
+include/wait_for_slave_to_start.inc
+include/check_slave_is_running.inc
+include/stop_slave.inc
+CHANGE MASTER TO MASTER_USER= 'regular_user_p', MASTER_PASSWORD= 'password';
+START SLAVE;
+include/wait_for_slave_io_to_start.inc
+include/check_slave_is_running.inc
+include/rpl_restart_server.inc [server_number=2]
+include/start_slave.inc
+include/check_slave_is_running.inc
+include/stop_slave.inc
+CHANGE MASTER TO MASTER_USER= 'regular_user_wp', MASTER_PASSWORD= '';
+START SLAVE;
+include/wait_for_slave_io_to_start.inc
+include/check_slave_is_running.inc
+include/rpl_restart_server.inc [server_number=2]
+include/start_slave.inc
+include/check_slave_is_running.inc
+include/stop_slave.inc
+CHANGE MASTER TO MASTER_USER= 'plug_user_p', MASTER_PASSWORD= 'password';
+START SLAVE;
+include/wait_for_slave_io_error.inc [errno=1251]
+include/stop_slave.inc
+CHANGE MASTER TO MASTER_USER= 'plug_user_wp', MASTER_PASSWORD= '';
+START SLAVE;
+include/wait_for_slave_io_error.inc [errno=1251]
+include/stop_slave.inc
+SET @@GLOBAL.master_info_repository= "FILE";
+include/stop_slave.inc
+Warnings:
+Note 1255 Slave already has been stopped
+CHANGE MASTER TO MASTER_USER= 'DOES NOT EXIST', MASTER_PASSWORD = 'DOES NOT EXIST';
+START SLAVE USER= 'regular_user_p' PASSWORD= 'password';
+include/wait_for_slave_to_start.inc
+include/check_slave_is_running.inc
+include/stop_slave.inc
+CHANGE MASTER TO MASTER_USER= 'DOES NOT EXIST', MASTER_PASSWORD = 'DOES NOT EXIST';
+START SLAVE USER= 'regular_user_wp' PASSWORD= '';
+include/wait_for_slave_to_start.inc
+include/check_slave_is_running.inc
+include/stop_slave.inc
+CHANGE MASTER TO MASTER_USER= 'regular_user_p', MASTER_PASSWORD= 'password';
+START SLAVE;
+include/wait_for_slave_io_to_start.inc
+include/check_slave_is_running.inc
+include/rpl_restart_server.inc [server_number=2]
+include/start_slave.inc
+include/check_slave_is_running.inc
+include/stop_slave.inc
+CHANGE MASTER TO MASTER_USER= 'regular_user_wp', MASTER_PASSWORD= '';
+START SLAVE;
+include/wait_for_slave_io_to_start.inc
+include/check_slave_is_running.inc
+include/rpl_restart_server.inc [server_number=2]
+include/start_slave.inc
+include/check_slave_is_running.inc
+include/stop_slave.inc
+CHANGE MASTER TO MASTER_USER= 'plug_user_p', MASTER_PASSWORD= 'password';
+START SLAVE;
+include/wait_for_slave_io_error.inc [errno=1251]
+include/stop_slave.inc
+CHANGE MASTER TO MASTER_USER= 'plug_user_wp', MASTER_PASSWORD= '';
+START SLAVE;
+include/wait_for_slave_io_error.inc [errno=1251]
+SET SQL_LOG_BIN=0;
+DROP USER plug_user_p, plug_user_wp, regular_user_p, regular_user_wp;
+SET SQL_LOG_BIN=1;
+include/stop_slave.inc
+CHANGE MASTER TO MASTER_USER= 'root', MASTER_PASSWORD = '';
+SET @@GLOBAL.master_info_repository="FILE";
+include/start_slave.inc
+include/rpl_end.inc
=== added file 'mysql-test/suite/rpl/t/rpl_master_connection-master.opt'
--- a/mysql-test/suite/rpl/t/rpl_master_connection-master.opt 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/t/rpl_master_connection-master.opt 2011-04-18 06:30:30 +0000
@@ -0,0 +1,2 @@
+$PLUGIN_AUTH_OPT
+$PLUGIN_AUTH_LOAD
=== added file 'mysql-test/suite/rpl/t/rpl_master_connection-slave.opt'
--- a/mysql-test/suite/rpl/t/rpl_master_connection-slave.opt 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/t/rpl_master_connection-slave.opt 2011-04-18 06:30:30 +0000
@@ -0,0 +1 @@
+--master-retry-count=1
=== added file 'mysql-test/suite/rpl/t/rpl_master_connection.test'
--- a/mysql-test/suite/rpl/t/rpl_master_connection.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/t/rpl_master_connection.test 2011-04-18 06:30:30 +0000
@@ -0,0 +1,116 @@
+--source include/have_plugin_auth.inc
+--source include/not_embedded.inc
+--source include/master-slave.inc
+
+############################
+
+SET SQL_LOG_BIN=0;
+--sorted_result
+SELECT user, plugin, authentication_string FROM mysql.user WHERE user != 'root';
+
+CREATE USER plug_user_p IDENTIFIED WITH test_plugin_server AS 'password';
+CREATE USER plug_user_wp IDENTIFIED WITH test_plugin_server AS '';
+CREATE USER regular_user_p IDENTIFIED BY 'password';
+CREATE USER regular_user_wp IDENTIFIED BY '';
+
+--sorted_result
+SELECT user, plugin, authentication_string FROM mysql.user WHERE user != 'root';
+
+GRANT REPLICATION SLAVE ON *.* TO plug_user_p;
+GRANT REPLICATION SLAVE ON *.* TO plug_user_wp;
+GRANT REPLICATION SLAVE ON *.* TO regular_user_p;
+GRANT REPLICATION SLAVE ON *.* TO regular_user_wp;
+SET SQL_LOG_BIN=1;
+
+###########################
+--connection slave
+--let $slave_io_errno= 1251
+--let $show_slave_io_error= 0
+--let $master_info_repository_old= `SELECT @@GLOBAL.master_info_repository`
+--let $count= 2
+
+while ($count != 0)
+{
+ --source include/stop_slave.inc
+ if ($count == 1)
+ {
+ SET @@GLOBAL.master_info_repository= "FILE";
+ }
+
+ if ($count == 2)
+ {
+ SET @@GLOBAL.master_info_repository= "TABLE";
+ }
+
+ --source include/stop_slave.inc
+ CHANGE MASTER TO MASTER_USER= 'DOES NOT EXIST', MASTER_PASSWORD = 'DOES NOT EXIST';
+ --eval START SLAVE USER= 'regular_user_p' PASSWORD= 'password'
+ --source include/wait_for_slave_to_start.inc
+ --source include/check_slave_is_running.inc
+
+ --source include/stop_slave.inc
+ CHANGE MASTER TO MASTER_USER= 'DOES NOT EXIST', MASTER_PASSWORD = 'DOES NOT EXIST';
+ --eval START SLAVE USER= 'regular_user_wp' PASSWORD= ''
+ --source include/wait_for_slave_to_start.inc
+ --source include/check_slave_is_running.inc
+
+ #--source include/stop_slave.inc
+ #CHANGE MASTER TO MASTER_USER= 'DOES NOT EXIST', MASTER_PASSWORD = 'DOES NOT EXIST';
+ #--eval START SLAVE USER= 'plug_user_p' PASSWORD= 'password'
+ #--source include/wait_for_slave_to_start.inc
+ #--source include/check_slave_is_running.inc
+
+ #--source include/stop_slave.inc
+ #CHANGE MASTER TO MASTER_USER= 'DOES NOT EXIST', MASTER_PASSWORD = 'DOES NOT EXIST';
+ #--eval START SLAVE USER= 'plug_user_wp' PASSWORD= ''
+ #--source include/wait_for_slave_to_start.inc
+ #--source include/check_slave_is_running.inc
+
+ --source include/stop_slave.inc
+ CHANGE MASTER TO MASTER_USER= 'regular_user_p', MASTER_PASSWORD= 'password';
+ START SLAVE;
+ --source include/wait_for_slave_io_to_start.inc
+ --source include/check_slave_is_running.inc
+ --let $rpl_server_number= 2
+ --source include/rpl_restart_server.inc
+ --connection slave
+ --source include/start_slave.inc
+ --source include/check_slave_is_running.inc
+
+ --source include/stop_slave.inc
+ CHANGE MASTER TO MASTER_USER= 'regular_user_wp', MASTER_PASSWORD= '';
+ START SLAVE;
+ --source include/wait_for_slave_io_to_start.inc
+ --source include/check_slave_is_running.inc
+ --let $rpl_server_number= 2
+ --source include/rpl_restart_server.inc
+ --connection slave
+ --source include/start_slave.inc
+ --source include/check_slave_is_running.inc
+
+ --source include/stop_slave.inc
+ CHANGE MASTER TO MASTER_USER= 'plug_user_p', MASTER_PASSWORD= 'password';
+ START SLAVE;
+ --source include/wait_for_slave_io_error.inc
+
+ --source include/stop_slave.inc
+ CHANGE MASTER TO MASTER_USER= 'plug_user_wp', MASTER_PASSWORD= '';
+ START SLAVE;
+ --source include/wait_for_slave_io_error.inc
+
+ --dec $count
+}
+
+###########################
+
+--connection master
+SET SQL_LOG_BIN=0;
+DROP USER plug_user_p, plug_user_wp, regular_user_p, regular_user_wp;
+SET SQL_LOG_BIN=1;
+
+--connection slave
+--source include/stop_slave.inc
+CHANGE MASTER TO MASTER_USER= 'root', MASTER_PASSWORD = '';
+--eval SET @@GLOBAL.master_info_repository="$master_info_repository_old"
+--source include/start_slave.inc
+--source include/rpl_end.inc
=== modified file 'scripts/mysql_system_tables.sql'
--- a/scripts/mysql_system_tables.sql 2011-03-18 22:51:17 +0000
+++ b/scripts/mysql_system_tables.sql 2011-04-18 06:30:30 +0000
@@ -102,7 +102,7 @@ CREATE TABLE IF NOT EXISTS ndb_binlog_in
CREATE TABLE IF NOT EXISTS slave_relay_log_info (Master_id INTEGER UNSIGNED NOT NULL, Number_of_lines INTEGER UNSIGNED NOT NULL, Relay_log_name TEXT CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, Relay_log_pos BIGINT UNSIGNED NOT NULL, Master_log_name TEXT CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, Master_log_pos BIGINT UNSIGNED NOT NULL, Sql_delay INTEGER NOT NULL, PRIMARY KEY(Master_id)) ENGINE=MYISAM DEFAULT CHARSET=utf8 COMMENT 'Relay Log Information';
-CREATE TABLE IF NOT EXISTS slave_master_info (Master_id INTEGER UNSIGNED NOT NULL, Number_of_lines INTEGER UNSIGNED NOT NULL, Master_log_name TEXT CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, Master_log_pos BIGINT UNSIGNED NOT NULL, Host TEXT CHARACTER SET utf8 COLLATE utf8_bin, User_name TEXT CHARACTER SET utf8 COLLATE utf8_bin, User_password TEXT CHARACTER SET utf8 COLLATE utf8_bin, Port INTEGER UNSIGNED NOT NULL, Connect_retry INTEGER UNSIGNED NOT NULL, Enabled_ssl BOOLEAN NOT NULL, Ssl_ca TEXT CHARACTER SET utf8 COLLATE utf8_bin, Ssl_capath TEXT CHARACTER SET utf8 COLLATE utf8_bin, Ssl_cert TEXT CHARACTER SET utf8 COLLATE utf8_bin, Ssl_cipher TEXT CHARACTER SET utf8 COLLATE utf8_bin, Ssl_key TEXT CHARACTER SET utf8 COLLATE utf8_bin, Ssl_verify_servert_cert BOOLEAN NOT NULL, Heartbeat FLOAT NOT NULL, Bind TEXT CHARACTER SET utf8 COLLATE utf8_bin, Ignored_server_ids TEXT CHARACTER SET utf8 COLLATE utf8_bin, Uuid TEXT CHARACTER SET utf8 COLLATE utf8_bin, Retry_count BIGIN!
T UNSIGNED NOT NULL, PRIMARY KEY(Master_id)) ENGINE=MYISAM DEFAULT CHARSET=utf8 COMMENT 'Master Information';
+CREATE TABLE IF NOT EXISTS slave_master_info (Master_id INTEGER UNSIGNED NOT NULL, Number_of_lines INTEGER UNSIGNED NOT NULL, Master_log_name TEXT CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, Master_log_pos BIGINT UNSIGNED NOT NULL, Host TEXT CHARACTER SET utf8 COLLATE utf8_bin, User_name TEXT CHARACTER SET utf8 COLLATE utf8_bin, User_password BLOB NOT NULL, Port INTEGER UNSIGNED NOT NULL, Connect_retry INTEGER UNSIGNED NOT NULL, Enabled_ssl BOOLEAN NOT NULL, Ssl_ca TEXT CHARACTER SET utf8 COLLATE utf8_bin, Ssl_capath TEXT CHARACTER SET utf8 COLLATE utf8_bin, Ssl_cert TEXT CHARACTER SET utf8 COLLATE utf8_bin, Ssl_cipher TEXT CHARACTER SET utf8 COLLATE utf8_bin, Ssl_key TEXT CHARACTER SET utf8 COLLATE utf8_bin, Ssl_verify_servert_cert BOOLEAN NOT NULL, Heartbeat FLOAT NOT NULL, Bind TEXT CHARACTER SET utf8 COLLATE utf8_bin, Ignored_server_ids TEXT CHARACTER SET utf8 COLLATE utf8_bin, Uuid TEXT CHARACTER SET utf8 COLLATE utf8_bin, Retry_count BIGINT UNSIGNED NOT NULL, PRIMAR!
Y KEY(Master_id)) ENGINE=MYISAM DEFAULT CHARSET=utf8 COMMENT 'Master Information';
--
-- PERFORMANCE SCHEMA INSTALLATION
=== modified file 'sql/CMakeLists.txt'
--- a/sql/CMakeLists.txt 2011-02-02 08:30:13 +0000
+++ b/sql/CMakeLists.txt 2011-04-18 06:30:30 +0000
@@ -149,6 +149,7 @@ SET(SQL_SHARED_SOURCES
tztime.cc
uniques.cc
unireg.cc
+ secure_store.cc
)
SET(SQL_EXPORTED_SOURCES ${SQL_SHARED_SOURCES} PARENT_SCOPE)
=== modified file 'sql/lex.h'
--- a/sql/lex.h 2010-11-25 11:20:16 +0000
+++ b/sql/lex.h 2011-04-18 06:30:30 +0000
@@ -164,6 +164,7 @@ static SYMBOL symbols[] = {
{ "DECIMAL", SYM(DECIMAL_SYM)},
{ "DECLARE", SYM(DECLARE_SYM)},
{ "DEFAULT", SYM(DEFAULT)},
+ { "DEFAULT_AUTH", SYM(DEFAULT_AUTH_SYM)},
{ "DEFINER", SYM(DEFINER_SYM)},
{ "DELAYED", SYM(DELAYED_SYM)},
{ "DELAY_KEY_WRITE", SYM(DELAY_KEY_WRITE_SYM)},
@@ -412,6 +413,7 @@ static SYMBOL symbols[] = {
{ "PHASE", SYM(PHASE_SYM)},
{ "PLUGIN", SYM(PLUGIN_SYM)},
{ "PLUGINS", SYM(PLUGINS_SYM)},
+ { "PLUGIN_DIR", SYM(PLUGIN_DIR_SYM)},
{ "POINT", SYM(POINT_SYM)},
{ "POLYGON", SYM(POLYGON)},
{ "PORT", SYM(PORT_SYM)},
=== modified file 'sql/rpl_handler.cc'
--- a/sql/rpl_handler.cc 2010-11-05 22:14:29 +0000
+++ b/sql/rpl_handler.cc 2011-04-18 06:30:30 +0000
@@ -429,7 +429,7 @@ void Binlog_relay_IO_delegate::init_para
Master_info *mi)
{
param->mysql= mi->mysql;
- param->user= mi->user;
+ param->user= const_cast<char *>(mi->get_user());
param->host= mi->host;
param->port= mi->port;
param->master_log_name= const_cast<char *>(mi->get_master_log_name());
=== modified file 'sql/rpl_info_file.cc'
--- a/sql/rpl_info_file.cc 2011-04-05 16:46:24 +0000
+++ b/sql/rpl_info_file.cc 2011-04-18 06:30:30 +0000
@@ -304,6 +304,47 @@ bool Rpl_info_file::do_get_info(const in
return error;
}
+bool Rpl_info_file::do_set_binary_info(const int pos, const char *value,
+ const size_t size)
+{
+ uchar buffer[STORE_SIZE_BINARY];
+
+ /*
+ There is only 32 bits to store the size of the binary information.
+ So if size is greater than 2^32 = 4.294.967.295, an error is then
+ returned.
+ */
+ if (size > 4294967295)
+ return TRUE;
+
+ int4store(buffer, size);
+ if (my_b_write(&info_file, buffer, STORE_SIZE_BINARY) ||
+ my_b_write(&info_file, value, size))
+ return TRUE;
+
+ return FALSE;
+}
+
+bool Rpl_info_file::do_get_binary_info(const int pos, char *value, size_t *size)
+{
+ uint32 length= 0;
+ uchar buffer[STORE_SIZE_BINARY];
+
+ if (my_b_read(&info_file, buffer, STORE_SIZE_BINARY))
+ return TRUE;
+
+ *size= length= uint4korr(buffer);
+ /*
+ There is only 32 bits to store the size of the binary information.
+ So if size is greater than 2^32 = 4.294.967.295, an error is then
+ returned.
+ */
+ if (*size > 4294967295 || my_b_read(&info_file, (uchar *) value, *size))
+ return TRUE;
+
+ return FALSE;
+}
+
char* Rpl_info_file::do_get_description_info()
{
return info_fname;
=== modified file 'sql/rpl_info_file.h'
--- a/sql/rpl_info_file.h 2011-03-23 23:28:49 +0000
+++ b/sql/rpl_info_file.h 2011-04-18 06:30:30 +0000
@@ -71,6 +71,11 @@ private:
bool do_is_transactional();
bool do_update_is_transactional();
+ bool do_set_binary_info(const int pos, const char *value,
+ const size_t size);
+ bool do_get_binary_info(const int pos, char *value,
+ size_t *size);
+
Rpl_info_file(int const nparam, const char* param_info_fname);
Rpl_info_file(const Rpl_info_file& info);
=== modified file 'sql/rpl_info_handler.h'
--- a/sql/rpl_info_handler.h 2011-03-23 23:28:49 +0000
+++ b/sql/rpl_info_handler.h 2011-04-18 06:30:30 +0000
@@ -24,6 +24,12 @@ class Rpl_info_handler
{
public:
/**
+ Defines the space reserved to store the size of the binary
+ information.
+ */
+ static const int STORE_SIZE_BINARY= 4;
+
+ /**
After creating an object and assembling components, this method is
used to initialize internal structures. Everything that does not
depend on other components (e.g. mutexes) should be placed in the
@@ -142,6 +148,23 @@ public:
}
/**
+ Sets the value of a binary field to @c value.
+ Any call must be done in the right order which
+ is defined by the caller that wants to persist
+ the information.
+ */
+ bool set_binary_info(char* const value, const size_t size)
+ {
+ if (cursor >= ninfo || prv_error)
+ return TRUE;
+
+ if (!(prv_error= do_set_binary_info(cursor, value, size)))
+ cursor++;
+
+ return(prv_error);
+ }
+
+ /**
Returns the value of a field.
Any call must be done in the right order which
is defined by the caller that wants to return
@@ -182,8 +205,8 @@ public:
@retval FALSE No error
@retval TRUE Failure
*/
- bool get_info(char *value, const size_t size,
- const char *default_value)
+ bool get_info(char* value, const size_t size,
+ char* const default_value)
{
if (cursor >= ninfo || prv_error)
return TRUE;
@@ -220,6 +243,32 @@ public:
}
/**
+ Returns the value of a binary field.
+ Any call must be done in the right order which
+ is defined by the caller that wants to return
+ the information.
+
+ @param[in] value Value to be returned.
+ @param[in] size Max size of the string to be
+ returned.
+ @param[in] default_value Returns a default value
+ if the field is empty.
+
+ @retval FALSE No error
+ @retval TRUE Failure
+ */
+ bool get_binary_info(char* value, size_t *size)
+ {
+ if (cursor >= ninfo || prv_error)
+ return TRUE;
+
+ if (!(prv_error= do_get_binary_info(cursor, value, size)))
+ cursor++;
+
+ return(prv_error);
+ }
+
+ /**
Returns the number of fields handled by this handler.
@return Number of fields handled by the handler.
@@ -329,12 +378,17 @@ private:
const float default_value)= 0;
virtual bool do_get_info(const int pos, Server_ids *value,
const Server_ids *default_value)= 0;
+
+ virtual bool do_set_binary_info(const int pos, const char *value,
+ const size_t size)= 0;
+ virtual bool do_get_binary_info(const int pos, char *value,
+ size_t *size)= 0;
+
virtual char* do_get_description_info()= 0;
virtual bool do_is_transactional()= 0;
virtual bool do_update_is_transactional()= 0;
Rpl_info_handler(const Rpl_info_handler& handler);
-
Rpl_info_handler& operator=(const Rpl_info_handler& handler);
};
#endif /* RPL_INFO_HANDLER_H */
=== modified file 'sql/rpl_info_table.cc'
--- a/sql/rpl_info_table.cc 2011-04-04 10:06:13 +0000
+++ b/sql/rpl_info_table.cc 2011-04-18 06:30:30 +0000
@@ -289,7 +289,7 @@ int Rpl_info_table::do_check_info()
}
/*
- Points the cursor at the row to be deleted where the the master_id
+ Points the cursor at the row to be used where the the master_id
equals to the server_id. If the row is not found, an error is
reported.
*/
@@ -441,6 +441,51 @@ bool Rpl_info_table::do_get_info(const i
return FALSE;
}
+bool Rpl_info_table::do_set_binary_info(const int pos, const char *value,
+ const size_t size)
+{
+ char *buffer= NULL;
+ /*
+ There is only 32 bits to store the size of the binary information.
+ So if size is greater than 2^32 = 4.294.967.295, an error is then
+ returned.
+ */
+ if (size > 4294967295)
+ return TRUE;
+
+ if (field_values->value[pos].alloc(size + STORE_SIZE_BINARY))
+ return TRUE;
+ buffer= field_values->value[pos].c_ptr_safe();
+
+ int4store(buffer, size);
+ memcpy(buffer + STORE_SIZE_BINARY, value, size);
+ field_values->value[pos].length(size + STORE_SIZE_BINARY);
+
+ return FALSE;
+}
+
+bool Rpl_info_table::do_get_binary_info(const int pos, char *value, size_t *size)
+{
+ uint32 length= 0;
+ char* buffer= field_values->value[pos].c_ptr_safe();
+ *size= 0;
+
+ if (field_values->value[pos].length() < (uint32) STORE_SIZE_BINARY)
+ return FALSE;
+
+ *size= length= uint4korr(buffer);
+ /*
+ There is only 32 bits to store the size of the binary information.
+ So if size is greater than 2^32 = 4.294.967.295, an error is then
+ returned.
+ */
+ if (*size > 4294967295)
+ return TRUE;
+ memcpy(value, buffer + STORE_SIZE_BINARY, *size);
+
+ return FALSE;
+}
+
char* Rpl_info_table::do_get_description_info()
{
return description;
=== modified file 'sql/rpl_info_table.h'
--- a/sql/rpl_info_table.h 2011-03-23 23:28:49 +0000
+++ b/sql/rpl_info_table.h 2011-04-18 06:30:30 +0000
@@ -87,6 +87,10 @@ private:
const float default_value);
bool do_get_info(const int pos, Server_ids *value,
const Server_ids *default_value);
+ bool do_set_binary_info(const int pos, const char *value,
+ const size_t size);
+ bool do_get_binary_info(const int pos, char *value,
+ size_t *size);
char* do_get_description_info();
bool do_is_transactional();
bool do_update_is_transactional();
=== modified file 'sql/rpl_mi.cc'
--- a/sql/rpl_mi.cc 2011-04-04 09:42:22 +0000
+++ b/sql/rpl_mi.cc 2011-04-18 06:30:30 +0000
@@ -21,6 +21,19 @@
#include "rpl_slave.h" // SLAVE_MAX_HEARTBEAT_PERIOD
#ifdef HAVE_REPLICATION
+/**
+ Key used to encrypt passwords stored in the master.info. Note that
+ passwords provided through the START SLAVE are encrypted with a
+ random key.
+ If you want to change this behavior, please, check set_password()
+ for further information.
+*/
+char PASSWORD_ENCRYPTION_KEY[]= "005F8976EA0192828877087476617874";
+size_t PASSWORD_ENCRYPTION_KEY_SIZE= strlen(PASSWORD_ENCRYPTION_KEY);
+char PASSWORD_SEARCH_KEY[] = "PASSWORD_SEARCH_KEY";
+size_t PASSWORD_SEARCH_KEY_SIZE= strlen(PASSWORD_SEARCH_KEY);
+char START_PASSWORD_SEARCH_KEY[]= "START_SEARCH_PASSWORD_KEY";
+size_t START_PASSWORD_SEARCH_KEY_SIZE= strlen(START_PASSWORD_SEARCH_KEY);
enum {
LINES_IN_MASTER_INFO_WITH_SSL= 14,
@@ -92,6 +105,8 @@ Master_info::Master_info(
param_key_info_stop_cond
#endif
),
+ start_user_configured(0), start_plugin_configured(0),
+ store_password(0), store_start_password(0),
ssl(0), ssl_verify_server_cert(0),
port(MYSQL_PORT), connect_retry(DEFAULT_CONNECT_RETRY),
clock_diff_with_master(0), heartbeat_period(0),
@@ -99,10 +114,13 @@ Master_info::Master_info(
checksum_alg_before_fd(BINLOG_CHECKSUM_ALG_UNDEF),
retry_count(master_retry_count)
{
- host[0] = 0; user[0] = 0; password[0] = 0; bind_addr[0] = 0;
+ host[0] = 0; user[0] = 0; bind_addr[0] = 0;
ssl_ca[0]= 0; ssl_capath[0]= 0; ssl_cert[0]= 0;
ssl_cipher[0]= 0; ssl_key[0]= 0;
master_uuid[0]= 0;
+ start_plugin_auth[0]= 0; start_plugin_dir[0]= 0;
+ start_user[0]= 0;
+ strcpy(start_command, "START SLAVE");
ignore_server_ids= new Server_ids();
}
@@ -183,6 +201,14 @@ void Master_info::end_info()
inited = 0;
+ /*
+ The structure that encrypts and decrypts the password stored in
+ the master.info is initialized and deinitialized, respectively
+ by secure_store_open and secure_store_close.
+ */
+ secure_store_close(store_password);
+ store_password= NULL;
+
DBUG_VOID_RETURN;
}
@@ -251,6 +277,21 @@ int Master_info::init_info()
DBUG_RETURN(0);
/*
+ The structure that encrypts and decrypts the password stored in the
+ master.info is initialized and deinitialized, respectively by
+ secure_store_open and secure_store_close.
+ */
+ if (!(store_password= secure_store_open(PASSWORD_SEARCH_KEY, MYF(0))))
+ DBUG_RETURN(TRUE);
+ if (secure_store_init(store_password, PASSWORD_ENCRYPTION_KEY,
+ PASSWORD_ENCRYPTION_KEY_SIZE))
+ {
+ secure_store_close(store_password);
+ store_password= NULL;
+ DBUG_RETURN(TRUE);
+ }
+
+ /*
The init_info() is used to either create or read information
from the repository, in order to initialize the Master_info.
*/
@@ -290,6 +331,8 @@ bool Master_info::read_info(Rpl_info_han
ulong temp_master_log_pos= 0;
int temp_ssl= 0;
int temp_ssl_verify_server_cert= 0;
+ char password[MAX_PASSWORD_LENGTH + ENCRYPTION_BLOCK_SIZE + 1];
+ size_t password_size= 0;
DBUG_ENTER("Master_info::read_info");
@@ -313,7 +356,7 @@ bool Master_info::read_info(Rpl_info_han
*/
if (from->prepare_info_for_read() ||
- from->get_info(master_log_name, sizeof(master_log_name), ""))
+ from->get_info(master_log_name, sizeof(master_log_name), (char *) ""))
DBUG_RETURN(TRUE);
lines= strtoul(master_log_name, &first_non_digit, 10);
@@ -322,20 +365,18 @@ bool Master_info::read_info(Rpl_info_han
*first_non_digit=='\0' && lines >= LINES_IN_MASTER_INFO_WITH_SSL)
{
/* Seems to be new format => read master log name */
- if (from->get_info(master_log_name, sizeof(master_log_name), ""))
+ if (from->get_info(master_log_name, sizeof(master_log_name), (char *) ""))
DBUG_RETURN(TRUE);
}
else
lines= 7;
- if (from->get_info(&temp_master_log_pos,
- (ulong) BIN_LOG_HEADER_SIZE) ||
- from->get_info(host, sizeof(host), 0) ||
- from->get_info(user, sizeof(user), "test") ||
- from->get_info(password, sizeof(password), 0) ||
+ if (from->get_info(&temp_master_log_pos, (ulong) BIN_LOG_HEADER_SIZE) ||
+ from->get_info(host, sizeof(host), (char *) 0) ||
+ from->get_info(user, sizeof(user), (char *) "test") ||
+ from->get_binary_info(password, (size_t *) &password_size) ||
from->get_info((int *) &port, (int) MYSQL_PORT) ||
- from->get_info((int *) &connect_retry,
- (int) DEFAULT_CONNECT_RETRY))
+ from->get_info((int *) &connect_retry, (int) DEFAULT_CONNECT_RETRY))
DBUG_RETURN(TRUE);
/*
@@ -346,12 +387,12 @@ bool Master_info::read_info(Rpl_info_han
*/
if (lines >= LINES_IN_MASTER_INFO_WITH_SSL)
{
- if (from->get_info(&temp_ssl, 0) ||
- from->get_info(ssl_ca, sizeof(ssl_ca), 0) ||
- from->get_info(ssl_capath, sizeof(ssl_capath), 0) ||
- from->get_info(ssl_cert, sizeof(ssl_cert), 0) ||
- from->get_info(ssl_cipher, sizeof(ssl_cipher), 0) ||
- from->get_info(ssl_key, sizeof(ssl_key), 0))
+ if (from->get_info(&temp_ssl, (int) 0) ||
+ from->get_info(ssl_ca, sizeof(ssl_ca), (char *) 0) ||
+ from->get_info(ssl_capath, sizeof(ssl_capath), (char *) 0) ||
+ from->get_info(ssl_cert, sizeof(ssl_cert), (char *) 0) ||
+ from->get_info(ssl_cipher, sizeof(ssl_cipher), (char *) 0) ||
+ from->get_info(ssl_key, sizeof(ssl_key), (char *) 0))
DBUG_RETURN(TRUE);
}
@@ -361,7 +402,7 @@ bool Master_info::read_info(Rpl_info_han
*/
if (lines >= LINE_FOR_MASTER_SSL_VERIFY_SERVER_CERT)
{
- if (from->get_info(&temp_ssl_verify_server_cert, 0))
+ if (from->get_info(&temp_ssl_verify_server_cert, (int) 0))
DBUG_RETURN(TRUE);
}
@@ -380,7 +421,7 @@ bool Master_info::read_info(Rpl_info_han
*/
if (lines >= LINE_FOR_MASTER_BIND)
{
- if (from->get_info(bind_addr, sizeof(bind_addr), ""))
+ if (from->get_info(bind_addr, sizeof(bind_addr), (char *) 0))
DBUG_RETURN(TRUE);
}
@@ -397,7 +438,7 @@ bool Master_info::read_info(Rpl_info_han
/* Starting from 5.5 the master_uuid may be in the repository. */
if (lines >= LINE_FOR_MASTER_UUID)
{
- if (from->get_info(master_uuid, sizeof(master_uuid), 0))
+ if (from->get_info(master_uuid, sizeof(master_uuid), (char *) 0))
DBUG_RETURN(TRUE);
}
@@ -409,15 +450,45 @@ bool Master_info::read_info(Rpl_info_han
DBUG_RETURN(TRUE);
}
+ /*
+ The structure that encrypts and decrypts the password stored in the
+ master.info is initialized and deinitialized, respectively by
+ secure_store_open and secure_store_close.
+ */
+ if (!inited && !(store_password= secure_store_open(PASSWORD_SEARCH_KEY, MYF(0))))
+ DBUG_RETURN(TRUE);
+ if (!inited && secure_store_init(store_password, PASSWORD_ENCRYPTION_KEY,
+ PASSWORD_ENCRYPTION_KEY_SIZE))
+ {
+ secure_store_close(store_password);
+ store_password= NULL;
+ DBUG_RETURN(TRUE);
+ }
+
+ /*
+ Emtpty passwords are not stored in the secure store as there is
+ nothing to be protected.
+ */
+ if (password_size &&
+ !secure_store_check_item(store_password, PASSWORD_SEARCH_KEY,
+ PASSWORD_SEARCH_KEY_SIZE))
+ {
+ char *key_ptr= PASSWORD_SEARCH_KEY;
+ if (secure_store_put_item(store_password, (void **) &key_ptr,
+ PASSWORD_SEARCH_KEY_SIZE, password,
+ password_size, FALSE))
+ DBUG_RETURN(TRUE);
+ }
+
ssl= (my_bool) test(temp_ssl);
ssl_verify_server_cert= (my_bool) test(temp_ssl_verify_server_cert);
master_log_pos= (my_off_t) temp_master_log_pos;
-#ifndef HAVE_OPENSSL
+#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) && !defined(HAVE_YASSL)
if (ssl)
sql_print_warning("SSL information in the master info file "
"are ignored because this MySQL slave was "
"compiled without SSL support.");
-#endif /* HAVE_OPENSSL */
+#endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY && !HAVE_YASSL */
DBUG_RETURN(FALSE);
}
@@ -426,6 +497,24 @@ bool Master_info::write_info(Rpl_info_ha
{
DBUG_ENTER("Master_info::write_info");
+ char error= TRUE;
+ char *password= NULL;
+ size_t password_size= 0;
+ char empty_password[]= "";
+
+ /*
+ Emtpty passwords are not stored in the secure store as there is
+ nothing to be protected.
+ */
+ if (!(password= (char *) secure_store_get_item(store_password,
+ (void *) PASSWORD_SEARCH_KEY,
+ PASSWORD_SEARCH_KEY_SIZE,
+ &password_size, FALSE)))
+ {
+ password= empty_password;
+ password_size= 0;
+ }
+
/*
In certain cases this code may create master.info files that seems
corrupted, because of extra lines filled with garbage in the end
@@ -433,14 +522,13 @@ bool Master_info::write_info(Rpl_info_ha
contents of file). But because of number of lines in the first line
of file we don't care about this garbage.
*/
-
if (to->prepare_info_for_write() ||
to->set_info((int) LINES_IN_MASTER_INFO) ||
to->set_info(master_log_name) ||
- to->set_info((ulong)master_log_pos) ||
+ to->set_info((ulong) master_log_pos) ||
to->set_info(host) ||
to->set_info(user) ||
- to->set_info(password) ||
+ to->set_binary_info(password, password_size) ||
to->set_info((int) port) ||
to->set_info((int) connect_retry) ||
to->set_info((int) ssl) ||
@@ -449,17 +537,246 @@ bool Master_info::write_info(Rpl_info_ha
to->set_info(ssl_cert) ||
to->set_info(ssl_cipher) ||
to->set_info(ssl_key) ||
- to->set_info(ssl_verify_server_cert) ||
+ to->set_info((int) ssl_verify_server_cert) ||
to->set_info(heartbeat_period) ||
to->set_info(bind_addr) ||
to->set_info(ignore_server_ids) ||
to->set_info(master_uuid) ||
to->set_info(retry_count))
- DBUG_RETURN(TRUE);
+ goto err;
if (to->flush_info(force))
- DBUG_RETURN(TRUE);
+ goto err;
- DBUG_RETURN(FALSE);
+ error= FALSE;
+
+err:
+ DBUG_ASSERT(password != NULL);
+ /*
+ Releases memory allocated to return the encrypted password,
+ if there is any.
+ */
+ if (password != empty_password) my_free(password);
+ DBUG_RETURN(error);
+}
+
+bool Master_info::set_password(const char* password_arg, int password_arg_size)
+{
+ DBUG_ENTER("Master_info::set_password");
+ bool error= TRUE;
+
+#ifndef DBUG_OFF
+ THD* thd= current_thd;
+ DBUG_PRINT("info", ("Command' %s'. Encrypting password '%s' whose size is %d\n",
+ thd->query(), password_arg, password_arg_size));
+#endif
+
+ if (password_arg && start_user_configured)
+ {
+ if (password_arg_size != 0)
+ {
+ if (!(store_start_password= secure_store_open(START_PASSWORD_SEARCH_KEY,
+ MYF(0))))
+ DBUG_RETURN(TRUE);
+ /*
+ In this case, the key is random to avoid security issues and as
+ such the second and third parameter are null.
+ */
+ if (secure_store_init(store_start_password, NULL, 0))
+ {
+ secure_store_close(store_start_password);
+ store_start_password= 0;
+ DBUG_RETURN(TRUE);
+ }
+
+ /*
+ Note that one is added to the size of the password to incorporate
+ the null-terminated character.
+ */
+ char *key_ptr= START_PASSWORD_SEARCH_KEY;
+ error= secure_store_put_item(store_start_password,
+ (void **) &key_ptr,
+ START_PASSWORD_SEARCH_KEY_SIZE,
+ (void *) password_arg,
+ password_arg_size + 1, TRUE);
+#ifndef DBUG_OFF
+ if (!error) debug_password(store_start_password,
+ START_PASSWORD_SEARCH_KEY,
+ START_PASSWORD_SEARCH_KEY_SIZE);
+#endif
+ }
+ else if (password_arg_size == 0 && !error)
+ {
+ error= FALSE;
+ DBUG_PRINT("info", ("SET ENCRYPTED PASSWORD - ENCRYPTED VERSION "
+ "'' SIZE 0, DECRYPTED VERSION '' SIZE 0\n"));
+ }
+ }
+ else if (password_arg)
+ {
+ /*
+ We assume that the key to encrypt passwords stored in the master.info
+ is not changed after starting the server. In fact, such key is hard
+ coded now.
+ In the future, if we decide to change this behavior and allow users
+ to define this key, we need to call secure_store_open, similar as
+ above.
+ */
+ if (password_arg_size != 0)
+ {
+ /*
+ Note that one is added to the size of the password to incorporate
+ the null-terminated character.
+ */
+ char *key_ptr= PASSWORD_SEARCH_KEY;
+ error= secure_store_put_item(store_password,
+ (void **) &key_ptr,
+ PASSWORD_SEARCH_KEY_SIZE,
+ (void *) password_arg,
+ password_arg_size + 1, TRUE);
+#ifndef DBUG_OFF
+ if (!error) debug_password(store_password, PASSWORD_SEARCH_KEY,
+ PASSWORD_SEARCH_KEY_SIZE);
+#endif
+ }
+ else if (password_arg_size == 0)
+ {
+ error= FALSE;
+ char* plain_password= NULL;
+ size_t plain_password_size= 0;
+ plain_password= (char *) secure_store_delete_item(store_password,
+ PASSWORD_SEARCH_KEY,
+ PASSWORD_SEARCH_KEY_SIZE,
+ &plain_password_size,
+ TRUE);
+#ifndef DBUG_OFF
+ debug_password(plain_password, plain_password_size);
+#endif
+ my_free(plain_password);
+ }
+ }
+ DBUG_RETURN(error);
}
+
+void Master_info::get_password(char *password_arg, int *password_arg_size)
+{
+ char *plain_password= NULL;
+ size_t plain_password_size= 0;
+
+ DBUG_ENTER("Master_info::get_password");
+
+ if (password_arg && start_user_configured)
+ {
+ plain_password=
+ (char *) secure_store_get_item(store_start_password,
+ (void *) START_PASSWORD_SEARCH_KEY,
+ START_PASSWORD_SEARCH_KEY_SIZE,
+ &plain_password_size, TRUE);
+ if (plain_password)
+ {
+ strmake(password_arg, plain_password, plain_password_size);
+ *password_arg_size= plain_password_size;
+ }
+ else
+ {
+ *password_arg= 0;
+ *password_arg_size= 0;
+ }
+#ifndef DBUG_OFF
+ debug_password(store_start_password,
+ START_PASSWORD_SEARCH_KEY,
+ START_PASSWORD_SEARCH_KEY_SIZE);
+#endif
+ }
+ else if (password_arg)
+ {
+ plain_password= (char *) secure_store_get_item(store_password,
+ (void *) PASSWORD_SEARCH_KEY,
+ PASSWORD_SEARCH_KEY_SIZE,
+ &plain_password_size, TRUE);
+ if (plain_password)
+ {
+ strmake(password_arg, plain_password, plain_password_size);
+ *password_arg_size= plain_password_size;
+ }
+ else
+ {
+ *password_arg= 0;
+ *password_arg_size= 0;
+ }
+#ifndef DBUG_OFF
+ debug_password(store_start_password,
+ START_PASSWORD_SEARCH_KEY,
+ START_PASSWORD_SEARCH_KEY_SIZE);
+#endif
+ }
+ my_free(plain_password);
+ DBUG_VOID_RETURN;
+}
+
+void Master_info::clean_start_information()
+{
+ DBUG_ENTER("Master_info::clean_start_information");
+ char* plain_start_password= NULL;
+ size_t plain_start_password_size= 0;
+ start_plugin_configured= FALSE;
+ start_plugin_auth[0]= 0;
+ start_plugin_dir[0]= 0;
+ start_user_configured= FALSE;
+ start_user[0]= 0;
+ /*
+ This makes sure that any information on the password provided through
+ the START SLAVE is erased. However, if we want to reset the key used
+ to encrypt passwords, we need to close the secure store too.
+ */
+ plain_start_password= (char *)
+ secure_store_delete_item(store_start_password,
+ START_PASSWORD_SEARCH_KEY,
+ START_PASSWORD_SEARCH_KEY_SIZE,
+ &plain_start_password_size,
+ TRUE);
+#ifndef DBUG_OFF
+ debug_password(plain_start_password, plain_start_password_size);
+#endif
+ my_free(plain_start_password);
+ DBUG_VOID_RETURN;
+}
+
+#ifndef DBUG_OFF
+void Master_info::debug_password(const char* password, size_t password_size)
+{
+ DBUG_PRINT("info", ("USER %s DELETING ENCRYPTED PASSWORD - "
+ "DECRYPTED VERSION '%s' SIZE %lu",
+ start_user_configured ? start_user : user,
+ password, password_size));
+}
+
+void Master_info::debug_password(Secure_Store* store, const char* key,
+ size_t key_size)
+{
+ char *plain_password= NULL;
+ size_t plain_password_size= 0;
+ char *encrypted_password= NULL;
+ size_t encrypted_password_size= 0;
+
+ plain_password= (char *) secure_store_get_item(store, (void *) key,
+ key_size,
+ &plain_password_size,
+ TRUE);
+
+ encrypted_password= (char *) secure_store_get_item(store, (void *) key,
+ key_size,
+ &encrypted_password_size,
+ FALSE);
+
+ DBUG_PRINT("info", ("USER %s UPDATING ENCRYPTED PASSWORD - ENCRYPTED VERSION "
+ "'%s' SIZE %lu, DECRYPTED VERSION '%s' SIZE %lu",
+ start_user_configured ? start_user : user,
+ encrypted_password, encrypted_password_size,
+ plain_password, plain_password_size));
+
+ my_free(plain_password);
+ my_free(encrypted_password);
+}
+#endif
#endif /* HAVE_REPLICATION */
=== modified file 'sql/rpl_mi.h'
--- a/sql/rpl_mi.h 2011-03-23 23:28:49 +0000
+++ b/sql/rpl_mi.h 2011-04-18 06:30:30 +0000
@@ -24,6 +24,7 @@
#define DEFAULT_CONNECT_RETRY 60
#include "rpl_rli.h"
+#include "secure_store.h"
#include "my_sys.h"
typedef struct st_mysql MYSQL;
@@ -63,13 +64,173 @@ class Rpl_info_factory;
class Master_info : public Rpl_info
{
+public:
friend class Rpl_info_factory;
+ /**
+ Stores a fake command that replaces thd->query() if START SLAVE was
+ used with USER/PASSWORD.
+ */
+ char start_command[FN_REFLEN + 1];
+ /**
+ The variables below are needed because we can change masters on the
+ fly.
+ */
+ char host[HOSTNAME_LENGTH + 1];
+
+private:
+ /**
+ If true, USER/PASSWORD was specified while running START SLAVE.
+ */
+ bool start_user_configured;
+ /**
+ If true, DEFAULT_AUTH/PLUGIN_DIR was specified while running
+ START SLAVE.
+ */
+ bool start_plugin_configured;
+ /**
+ User's name stored in the master.info.
+ */
+ char user[USERNAME_LENGTH + 1];
+ /**
+ Pointer to a secure store that is used to encrypt and decrypt password
+ stored in the master.info. In the feature, we may choose to store the
+ password in another persistent repository such as a system table.
+ */
+ Secure_Store* store_password;
+ /**
+ USER specified while running START SLAVE.
+ */
+ char start_user[USERNAME_LENGTH + 1];
+ /**
+ Pointer to a secure store that is used to encrypt and decrypt password
+ used while running START SLAVE. This password should not be written to
+ a repository.
+ */
+ Secure_Store* store_start_password;
+ /**
+ Stores the autentication plugin specified while running START SLAVE.
+ */
+ char start_plugin_auth[FN_REFLEN + 1];
+ /**
+ Stores the autentication plugin directory specified while running
+ START SLAVE.
+ */
+ char start_plugin_dir[FN_REFLEN + 1];
+
public:
- /* the variables below are needed because we can change masters on the fly */
- char host[HOSTNAME_LENGTH+1];
- char user[USERNAME_LENGTH+1];
- char password[MAX_PASSWORD_LENGTH+1];
+ /**
+ Returns if USER/PASSWORD was specified while running
+ START SLAVE.
+
+ @return true or false.
+ */
+ bool is_start_user_configured()
+ {
+ return start_user_configured;
+ }
+ /**
+ Returns if DEFAULT_AUTH/PLUGIN_DIR was specified while running
+ START SLAVE.
+
+ @return true or false.
+ */
+ bool is_start_plugin_configured()
+ {
+ return start_plugin_configured;
+ }
+ /**
+ Defines that USER/PASSWORD was specified or not while running
+ START SLAVE.
+
+ @param config is true or false.
+ */
+ void set_start_user_configured(bool config)
+ {
+ start_user_configured= config;
+ }
+ /**
+ Defines that DEFAULT_AUTH/PLUGIN_DIR was specified or not while
+ running START SLAVE.
+
+ @param config is true or false.
+ */
+ void set_start_plugin_configured(bool config)
+ {
+ start_plugin_configured= config;
+ }
+ /**
+ Sets either user's name in the master.info repository when CHANGE
+ MASTER is executed or user's name used in START SLAVE if USER is
+ specified.
+
+ @param user_arg is user's name.
+ */
+ void set_user(const char* user_arg)
+ {
+ if (user_arg && start_user_configured)
+ {
+ strmake(start_user, user_arg, sizeof(start_user) - 1);
+ }
+ else if (user_arg)
+ {
+ strmake(user, user_arg, sizeof(user) - 1);
+ }
+ }
+ size_t get_user_size()
+ {
+ return (start_user_configured ? sizeof(start_user) : sizeof(user));
+ }
+ /**
+ If an user was specified while running START SLAVE, this function returns
+ such user. Otherwise, it returns the user stored in master.info.
+
+ @return user's name.
+ */
+ const char *get_user()
+ {
+ return start_user_configured ? start_user : user;
+ }
+ /**
+ Sets either user's password in the master.info repository when CHANGE
+ MASTER is executed or user's password used in START SLAVE if PASSWORD
+ is specified.
+
+ @param password_arg is user's password.
+ */
+ bool set_password(const char* password_arg, int password_arg_size);
+ /**
+ Returns either user's password in the master.info repository or
+ user's password used in START SLAVE.
+
+ @param password_arg is user's password.
+ */
+ void get_password(char *password_arg, int *password_arg_size);
+#ifndef DBUG_OFF
+ /**
+ Prints out debug information on encrypted and decrypted passwords.
+ */
+ void debug_password(Secure_Store* store, const char* key,
+ size_t key_size);
+ void debug_password(const char* password, size_t password_size);
+#endif
+ /*
+ Erase password and key stored in memory when START SLAVE is executed.
+ */
+ void clean_start_information();
+ const char *get_start_plugin_auth() { return start_plugin_auth; }
+ const char *get_start_plugin_dir() { return start_plugin_dir; }
+ void set_plugin_auth(const char* src)
+ {
+ if (src)
+ strmake(start_plugin_auth, src, sizeof(start_plugin_auth) - 1);
+ }
+ void set_plugin_dir(const char* src)
+ {
+ if (src)
+ strmake(start_plugin_dir, src, sizeof(start_plugin_dir) - 1);
+ }
+
my_bool ssl; // enables use of SSL connection if true
char ssl_ca[FN_REFLEN], ssl_capath[FN_REFLEN], ssl_cert[FN_REFLEN];
char ssl_cipher[FN_REFLEN], ssl_key[FN_REFLEN];
=== modified file 'sql/rpl_rli.cc'
--- a/sql/rpl_rli.cc 2011-04-04 09:42:22 +0000
+++ b/sql/rpl_rli.cc 2011-04-18 06:30:30 +0000
@@ -1449,7 +1449,7 @@ bool Relay_log_info::read_info(Rpl_info_
overwritten by the second row later.
*/
if (from->prepare_info_for_read() ||
- from->get_info(group_relay_log_name, sizeof(group_relay_log_name), ""))
+ from->get_info(group_relay_log_name, sizeof(group_relay_log_name), (char *) ""))
DBUG_RETURN(TRUE);
lines= strtoul(group_relay_log_name, &first_non_digit, 10);
@@ -1458,23 +1458,23 @@ bool Relay_log_info::read_info(Rpl_info_
*first_non_digit=='\0' && lines >= LINES_IN_RELAY_LOG_INFO_WITH_DELAY)
{
/* Seems to be new format => read group relay log name */
- if (from->get_info(group_relay_log_name, sizeof(group_relay_log_name), ""))
+ if (from->get_info(group_relay_log_name, sizeof(group_relay_log_name), (char *) ""))
DBUG_RETURN(TRUE);
}
else
DBUG_PRINT("info", ("relay_log_info file is in old format."));
if (from->get_info((ulong *) &temp_group_relay_log_pos,
- (ulong) BIN_LOG_HEADER_SIZE) ||
+ (ulong) BIN_LOG_HEADER_SIZE) ||
from->get_info(group_master_log_name,
- sizeof(group_relay_log_name), "") ||
+ sizeof(group_relay_log_name), (char *) "") ||
from->get_info((ulong *) &temp_group_master_log_pos,
- (ulong) 0))
+ (ulong) 0))
DBUG_RETURN(TRUE);
if (lines >= LINES_IN_RELAY_LOG_INFO_WITH_DELAY)
{
- if (from->get_info((int *) &temp_sql_delay,(int) 0))
+ if (from->get_info((int *) &temp_sql_delay, (int) 0))
DBUG_RETURN(TRUE);
}
=== modified file 'sql/rpl_slave.cc'
--- a/sql/rpl_slave.cc 2011-04-04 10:06:13 +0000
+++ b/sql/rpl_slave.cc 2011-04-18 06:30:30 +0000
@@ -1996,7 +1996,7 @@ bool show_master_info(THD* thd, Master_i
field_list.push_back(new Item_empty_string("Master_Host",
sizeof(mi->host)));
field_list.push_back(new Item_empty_string("Master_User",
- sizeof(mi->user)));
+ mi->get_user_size()));
field_list.push_back(new Item_return_int("Master_Port", 7,
MYSQL_TYPE_LONG));
field_list.push_back(new Item_return_int("Connect_Retry", 10,
@@ -2093,7 +2093,7 @@ bool show_master_info(THD* thd, Master_i
mysql_mutex_lock(&mi->rli->err_lock);
protocol->store(mi->host, &my_charset_bin);
- protocol->store(mi->user, &my_charset_bin);
+ protocol->store(mi->get_user(), &my_charset_bin);
protocol->store((uint32) mi->port);
protocol->store((uint32) mi->connect_retry);
protocol->store(mi->get_master_log_name(), &my_charset_bin);
@@ -3165,7 +3165,7 @@ pthread_handler_t handle_slave_io(void *
{
sql_print_information("Slave I/O thread: connected to master '%s@%s:%d',"
"replication started in log '%s' at position %s",
- mi->user, mi->host, mi->port,
+ mi->get_user(), mi->host, mi->port,
mi->get_io_rpl_log_name(),
llstr(mi->get_master_log_pos(), llbuff));
/*
@@ -3441,7 +3441,11 @@ err:
write_ignored_events_info_to_relay_log(thd, mi);
THD_STAGE_INFO(thd, stage_waiting_for_slave_mutex_on_exit);
mysql_mutex_lock(&mi->run_lock);
-
+ /*
+ Clean information used to start slave in order to avoid
+ security issues.
+ */
+ mi->clean_start_information();
/* Forget the relay log's format */
delete mi->rli->relay_log.description_event_for_queue;
mi->rli->relay_log.description_event_for_queue= 0;
@@ -4700,6 +4704,8 @@ static int connect_to_master(THD* thd, M
int last_errno= -2; // impossible error
ulong err_count=0;
char llbuff[22];
+ char password[MAX_PASSWORD_LENGTH + 1];
+ int password_size= sizeof(password);
DBUG_ENTER("connect_to_master");
#ifndef DBUG_OFF
@@ -4736,10 +4742,17 @@ static int connect_to_master(THD* thd, M
/* This one is not strictly needed but we have it here for completeness */
mysql_options(mysql, MYSQL_SET_CHARSET_DIR, (char *) charsets_dir);
- while (!(slave_was_killed = io_slave_killed(thd,mi)) &&
- (reconnect ? mysql_reconnect(mysql) != 0 :
- mysql_real_connect(mysql, mi->host, mi->user, mi->password, 0,
- mi->port, 0, client_flag) == 0))
+ if (mi->is_start_plugin_configured())
+ mysql_options(mysql, MYSQL_DEFAULT_AUTH, mi->get_start_plugin_auth());
+
+ if (mi->is_start_plugin_configured())
+ mysql_options(mysql, MYSQL_PLUGIN_DIR, mi->get_start_plugin_dir());
+
+ mi->get_password(password, &password_size);
+ while (!(slave_was_killed = io_slave_killed(thd,mi))
+ && (reconnect ? mysql_reconnect(mysql) != 0 :
+ mysql_real_connect(mysql, mi->host, mi->get_user(),
+ password, 0, mi->port, 0, client_flag) == 0))
{
/*
SHOW SLAVE STATUS will display the number of retries which
@@ -4752,7 +4765,7 @@ static int connect_to_master(THD* thd, M
"error %s to master '%s@%s:%d'"
" - retry-time: %d retries: %lu",
(reconnect ? "reconnecting" : "connecting"),
- mi->user, mi->host, mi->port,
+ mi->get_user(), mi->host, mi->port,
mi->connect_retry, err_count + 1);
/*
By default we try forever. The reason is that failure will trigger
@@ -4776,7 +4789,7 @@ static int connect_to_master(THD* thd, M
{
if (!suppress_warnings && global_system_variables.log_warnings)
sql_print_information("Slave: connected to master '%s@%s:%d',\
-replication resumed in log '%s' at position %s", mi->user,
+replication resumed in log '%s' at position %s", mi->get_user(),
mi->host, mi->port,
mi->get_io_rpl_log_name(),
llstr(mi->get_master_log_pos(),llbuff));
@@ -4784,7 +4797,7 @@ replication resumed in log '%s' at posit
else
{
general_log_print(thd, COM_CONNECT_OUT, "%s@%s:%d",
- mi->user, mi->host, mi->port);
+ mi->get_user(), mi->host, mi->port);
}
#ifdef SIGNAL_WITH_VIO_CLOSE
thd->set_active_vio(mysql->net.vio);
@@ -4812,9 +4825,22 @@ static int safe_reconnect(THD* thd, MYSQ
}
+/*
+ We need to refactor this function and get rid of this duplicated code.
+ Howerver, I need to check this with Jasonh in order to understand what
+ was the intentation behind the code because the comments are not clear
+ and the function is not used.
+
+ This is a callback function that is part of the replication interface/
+ library and currently there is no plugin calling it.
+
+ \Alfranio
+*/
MYSQL *rpl_connect_master(MYSQL *mysql)
{
THD *thd= current_thd;
+ char password[MAX_PASSWORD_LENGTH + 1];
+ int password_size= sizeof(password);
Master_info *mi= my_pthread_getspecific_ptr(Master_info*, RPL_MASTER_INFO);
if (!mi)
{
@@ -4868,9 +4894,10 @@ MYSQL *rpl_connect_master(MYSQL *mysql)
/* This one is not strictly needed but we have it here for completeness */
mysql_options(mysql, MYSQL_SET_CHARSET_DIR, (char *) charsets_dir);
+ mi->get_password(password, &password_size);
if (io_slave_killed(thd, mi)
- || !mysql_real_connect(mysql, mi->host, mi->user, mi->password, 0,
- mi->port, 0, 0))
+ || !mysql_real_connect(mysql, mi->host, mi->get_user(),
+ password, 0, mi->port, 0, 0))
{
if (!io_slave_killed(thd, mi))
sql_print_error("rpl_connect_master: error connecting to master: %s (server_error: %d)",
@@ -5861,14 +5888,14 @@ bool change_master(THD* thd, Master_info
}
DBUG_PRINT("info", ("master_log_pos: %lu", (ulong) mi->get_master_log_pos()));
+ if (lex_mi->user)
+ mi->set_user(lex_mi->user);
+ if (lex_mi->password)
+ mi->set_password(lex_mi->password, strlen(lex_mi->password));
if (lex_mi->host)
strmake(mi->host, lex_mi->host, sizeof(mi->host)-1);
if (lex_mi->bind_addr)
strmake(mi->bind_addr, lex_mi->bind_addr, sizeof(mi->bind_addr)-1);
- if (lex_mi->user)
- strmake(mi->user, lex_mi->user, sizeof(mi->user)-1);
- if (lex_mi->password)
- strmake(mi->password, lex_mi->password, sizeof(mi->password)-1);
if (lex_mi->port)
mi->port = lex_mi->port;
if (lex_mi->connect_retry)
=== added file 'sql/secure_store.cc'
--- a/sql/secure_store.cc 1970-01-01 00:00:00 +0000
+++ b/sql/secure_store.cc 2011-04-18 06:30:30 +0000
@@ -0,0 +1,910 @@
+#include "secure_store.h"
+#include "hash.h"
+#include "my_sys.h"
+#include "log.h"
+
+class Crypto_Meta_Info
+{
+private:
+ /*
+ This identifies that the secure meta information was correctly
+ initialized and now can be used to encrypt and decrypt data.
+ */
+ bool inited;
+
+#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) && !defined(HAVE_YASSL)
+ /**
+ Crypto structure per key that is used to encrypt data stored into
+ the repository.
+ */
+ EVP_CIPHER_CTX e_ctx;
+ /**
+ Crypto structure per key that is used to decrypt data stored into
+ the repository;
+ */
+ EVP_CIPHER_CTX d_ctx;
+#endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY && !HAVE_YASSL */
+
+public:
+ Crypto_Meta_Info();
+ ~Crypto_Meta_Info();
+
+ bool init(char *key_input, const size_t key_input_size);
+ bool deinit();
+ bool encrypt_data(void *plain_data, const size_t plain_data_size,
+ void *crypt_data, size_t *crypt_data_size);
+ bool decrypt_data(void *plain_data, size_t *plain_data_size,
+ void *crypt_data, const size_t crypt_data_size);
+ size_t get_maximum_encrypted_data_size(size_t plain_data_size) const;
+ bool is_inited();
+
+private:
+ Crypto_Meta_Info(const Crypto_Meta_Info& info);
+ Crypto_Meta_Info& operator=(const Crypto_Meta_Info& info);
+};
+
+Crypto_Meta_Info::Crypto_Meta_Info()
+: inited(FALSE)
+{
+}
+
+Crypto_Meta_Info::~Crypto_Meta_Info()
+{
+ if (inited) deinit();
+}
+
+bool Crypto_Meta_Info::is_inited()
+{
+ return inited;
+}
+
+#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) && !defined(HAVE_YASSL)
+bool Crypto_Meta_Info::init(char *key_input, const size_t key_input_size)
+{
+ int error= 0;
+ int key_size= 0;
+ const int AES_ROUNDS_KEY= 10;
+ uchar key[ENCRYPTION_KEY_SIZE], ini_vector[ENCRYPTION_KEY_SIZE];
+ bool random= false;
+
+ DBUG_ENTER("Crypto_Meta_Info::init");
+
+ if (inited) DBUG_RETURN(FALSE);
+
+ if (key_input == NULL)
+ {
+ key_input= (char *) my_malloc(key_input_size, MYF(MY_WME));
+ if (key_input == NULL ||
+ !(error= RAND_bytes((unsigned char *)(key_input), key_input_size)) ||
+ error == -1)
+ {
+ my_free(key_input);
+ sql_print_warning("Error while generating random input key.");
+ DBUG_RETURN(TRUE);
+ }
+ random= TRUE;
+ }
+
+ /*
+ The input key provided is not directly used to encrypt data but a
+ new key is generated based on the input key and a digest function,
+ in this case, SHA-1.
+ */
+ key_size= EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), NULL,
+ (unsigned char *)key_input, key_input_size,
+ AES_ROUNDS_KEY, key, ini_vector);
+ if (key_size != ENCRYPTION_KEY_SIZE)
+ {
+ if (random) my_free(key_input);
+ sql_print_warning("Error while generating encryption key whose size is %lu.",
+ key_input_size);
+ DBUG_RETURN(TRUE);
+ }
+
+ /*
+ Initialize the structure that is going to be used to encrypt data.
+ */
+ EVP_CIPHER_CTX_init(&e_ctx);
+ if (!(error= EVP_EncryptInit_ex(&e_ctx, EVP_aes_256_cbc(), NULL, key, ini_vector))
+ || error == -1)
+ {
+ if (random) my_free(key_input);
+ sql_print_warning("Error while initializing encryption structure.");
+ DBUG_RETURN(TRUE);
+ }
+
+ /*
+ Initialize the structure that is going to be used to decrypt data.
+ */
+ EVP_CIPHER_CTX_init(&d_ctx);
+ if (!(error= EVP_DecryptInit_ex(&d_ctx, EVP_aes_256_cbc(), NULL, key, ini_vector))
+ || error == -1)
+ {
+ if (random) my_free(key_input);
+ sql_print_warning("Error while initializing decryption structure.");
+ DBUG_RETURN(TRUE);
+ }
+
+ inited= TRUE;
+
+ DBUG_RETURN(FALSE);
+}
+
+bool Crypto_Meta_Info::deinit()
+{
+ int error= 0;
+
+ DBUG_ENTER("Crypto_Meta_Info::deinit");
+
+ /*
+ Clean up the structure used to encrypt data.
+ */
+ if (!(error= EVP_CIPHER_CTX_cleanup(&e_ctx)) || error == -1)
+ {
+ sql_print_warning("Error while cleaning encryption information.");
+ DBUG_RETURN(TRUE);
+ }
+
+ /*
+ Clean up the structure used to decrypt data.
+ */
+ if (!(error= EVP_CIPHER_CTX_cleanup(&d_ctx)) || error == -1)
+ {
+ sql_print_warning("Error while cleaning encryption information");
+ DBUG_RETURN(TRUE);
+ }
+
+ DBUG_RETURN(FALSE);
+}
+
+size_t Crypto_Meta_Info::get_maximum_encrypted_data_size(const size_t plain_data_size) const
+{
+ return (plain_data_size + AES_BLOCK_SIZE);
+}
+
+bool Crypto_Meta_Info::encrypt_data(void *plain_data, const size_t plain_data_size,
+ void *crypt_data, size_t *crypt_data_size)
+{
+ int error= 0;
+ int add_size = 0;
+ unsigned char* uchar_crypt_data= NULL;
+
+ DBUG_ENTER("Crypto_Meta_Info::encrypt_data");
+
+ /*
+ The maximum size of the encrypted data is:
+ . plain_data_size + AES_BLOCK_SIZE.
+ */
+ *crypt_data_size = plain_data_size + AES_BLOCK_SIZE;
+ if (!(error= EVP_EncryptInit_ex(&e_ctx, NULL, NULL, NULL, NULL))
+ || error == -1)
+ {
+ sql_print_warning("Error while initializing encryption function.");
+ DBUG_RETURN(TRUE);
+ }
+ /*
+ Set the encrypted data and its size.
+ */
+ if (!(error= EVP_EncryptUpdate(&e_ctx, (unsigned char *) crypt_data,
+ (int *) crypt_data_size,
+ (unsigned char *) plain_data,
+ (int) plain_data_size))
+ || error == -1)
+ {
+ sql_print_warning("Error while encrypting data.");
+ DBUG_RETURN(TRUE);
+ }
+ /*
+ Set the encrypted data with remaining bytes, if there is any.
+ */
+ uchar_crypt_data= (unsigned char *)crypt_data;
+ if (!(error= EVP_EncryptFinal_ex(&e_ctx,
+ (unsigned char *) (uchar_crypt_data + *crypt_data_size),
+ &add_size))
+ || error == -1)
+ {
+ sql_print_warning("Error while encrypting data.");
+ DBUG_RETURN(TRUE);
+ }
+ /*
+ Calculate the encrypted data size based on the remaining
+ bytes that were appended.
+ */
+ *crypt_data_size = *crypt_data_size + add_size;
+
+ DBUG_RETURN(FALSE);
+}
+
+bool Crypto_Meta_Info::decrypt_data(void *plain_data, size_t *plain_data_size,
+ void *crypt_data, const size_t crypt_data_size)
+{
+ int error= 0;
+ int add_size = 0;
+ unsigned char* uchar_plain_data= NULL;
+
+ DBUG_ENTER("Crypto_Meta_Info::decrypt_data");
+
+ /*
+ The maximum size of the data is:
+ . crypt_data_size
+ */
+ *plain_data_size = crypt_data_size;
+ if (!(error= EVP_DecryptInit_ex(&d_ctx, NULL, NULL, NULL, NULL)) || error == -1)
+ {
+ sql_print_warning("Error while initializing decryption function.");
+ DBUG_RETURN(TRUE);
+ }
+ /*
+ Set the data and its size.
+ */
+ if (!(error= EVP_DecryptUpdate(&d_ctx, (unsigned char *) plain_data,
+ (int *) plain_data_size,
+ (unsigned char *) crypt_data,
+ (int)crypt_data_size)) || error == -1)
+ {
+ sql_print_warning("Error while decrypting data.");
+ DBUG_RETURN(TRUE);
+ }
+ /*
+ Set data with remaining bytes, if there is any.
+ */
+ uchar_plain_data= (unsigned char *)plain_data;
+ if (!(error= EVP_DecryptFinal_ex(&d_ctx,
+ (unsigned char *) (uchar_plain_data + *plain_data_size),
+ &add_size)) || error == -1)
+ {
+ sql_print_warning("Error while decrypting data.");
+ DBUG_RETURN(TRUE);
+ }
+ /*
+ Calculate data size based on the remaining bytes that were
+ appended.
+ */
+ *plain_data_size = *plain_data_size + add_size;
+
+ DBUG_RETURN(FALSE);
+}
+#else
+bool Crypto_Meta_Info::init(char *key_input, const size_t key_input_size)
+{
+ return FALSE;
+}
+
+bool Crypto_Meta_Info::deinit()
+{
+ return FALSE;
+}
+
+size_t Crypto_Meta_Info::get_maximum_encrypted_data_size(const size_t plain_data_size) const
+{
+ return plain_data_size;
+}
+
+bool Crypto_Meta_Info::encrypt_data(void *plain_data, const size_t plain_data_size,
+ void *crypt_data, size_t *crypt_data_size)
+{
+ strmake((char *) crypt_data, (char *) plain_data, plain_data_size);
+ *crypt_data_size= plain_data_size;
+ return FALSE;
+}
+
+bool Crypto_Meta_Info::decrypt_data(void *plain_data, size_t *plain_data_size,
+ void *crypt_data, const size_t crypt_data_size)
+{
+ strmake((char *) plain_data, (char *) crypt_data, crypt_data_size);
+ *plain_data_size= crypt_data_size;
+ return FALSE;
+}
+#endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY && !HAVE_YASSL */
+
+class Key_Info
+{
+private:
+ /**
+ Key used to uniquely identify an encrypted data.
+ */
+ void* key;
+ /**
+ Key's size.
+ */
+ size_t key_size;
+
+public:
+ Key_Info()
+ : key(NULL), key_size(0) { }
+
+ ~Key_Info() { }
+
+ void *get_key()
+ {
+ return key;
+ }
+
+ size_t get_key_size()
+ {
+ return key_size;
+ }
+
+ void set_key(void *key_arg, size_t key_size_arg)
+ {
+ key_size= key_size_arg;
+ key= key_arg;
+ }
+};
+
+class Crypto_Info
+{
+private:
+ /**
+ Encrypted data.
+ */
+ void* crypto;
+ /**
+ Encrypted data's size.
+ */
+ size_t crypto_size;
+
+public:
+ Crypto_Info()
+ : crypto(NULL), crypto_size(0) { }
+
+ ~Crypto_Info() { }
+
+ void *get_crypto()
+ {
+ return crypto;
+ }
+
+ size_t get_crypto_size()
+ {
+ return crypto_size;
+ }
+
+ void set_crypto(void *crypto_arg, size_t crypto_size_arg)
+ {
+ crypto= crypto_arg;
+ crypto_size= crypto_size_arg;
+ }
+};
+
+typedef struct Hash_Secure_Store_Entry
+{
+ Key_Info *key;
+ Crypto_Info *crypto;
+} Hash_Secure_Store_Entry;
+
+extern "C" uchar *get_secure_store_key(const uchar *record, size_t *length,
+ my_bool not_used __attribute__((unused)))
+{
+ Hash_Secure_Store_Entry *entry=(Hash_Secure_Store_Entry *) record;
+ *length= entry->key->get_key_size();
+
+ return((uchar*) entry->key->get_key());
+}
+
+extern "C" void free_secure_store_entry(Hash_Secure_Store_Entry *entry)
+{
+ my_free(entry->key->get_key());
+ delete entry->key;
+ my_free(entry->crypto->get_crypto());
+ delete entry->crypto;
+}
+
+/**
+ This class maps an unique key to encrypted data and provides implementation
+ for: secure_store_init(), secure_store_check_item(), secure_store_put_item()
+ , secure_store_get_item(), secure_store_delete_item().
+ The access to the repository is hidden through some methods: search_data(),
+ insert_data() and delete_data().
+*/
+class Secure_Store_Interface: public Secure_Store
+{
+private:
+ /**
+ Uniquely identifies this secure store. So given a store, one can easly
+ find its reference in Secure_Schema.
+ */
+ char schema[FN_REFLEN + 1];
+ /**
+ Defines how to encrypt and decrypt data stored in this
+ secure store.
+ */
+ Crypto_Meta_Info secure_info;
+ /**
+ Maps unique keys to encrypted data: Key_Info --> Crypto_Info.
+ This is a temporary solution that will be used while WL#5769
+ is not ready.
+ */
+ HASH key_store;
+ /**
+ Identifies if the hash structure was properly initialized.
+ */
+ bool inited_hash;
+
+public:
+ Secure_Store_Interface(const char* schema_arg)
+ {
+ strmake(schema, schema_arg, FN_REFLEN);
+ inited_hash=
+ (my_hash_init(&key_store, &my_charset_bin,
+ 0, 0, 0, get_secure_store_key,
+ (my_hash_free_key) free_secure_store_entry, 0) == 0);
+ }
+
+ ~Secure_Store_Interface()
+ {
+ if (inited_hash) my_hash_free(&key_store);
+ }
+
+ const char* get_schema() const
+ {
+ return schema;
+ }
+
+ Crypto_Info *search_data(Key_Info *key_info)
+ {
+ Hash_Secure_Store_Entry *entry= NULL;
+ if (inited_hash && key_info && key_info->get_key() &&
+ key_info->get_key_size())
+ {
+ entry= (Hash_Secure_Store_Entry *)
+ my_hash_search(&key_store, (uchar *) key_info->get_key(),
+ key_info->get_key_size());
+ }
+ return (entry ? entry->crypto : NULL);
+ }
+
+ bool insert_data(Key_Info *key_info, Crypto_Info* crypto_info)
+ {
+
+ bool error= TRUE;
+ if (inited_hash && key_info && crypto_info &&
+ key_info->get_key() && key_info->get_key_size())
+ {
+ Hash_Secure_Store_Entry *entry= (Hash_Secure_Store_Entry *)
+ my_malloc(sizeof(Hash_Secure_Store_Entry), MYF(MY_WME));
+ if (entry)
+ {
+ entry->key= key_info;
+ entry->crypto= crypto_info;
+ if (my_hash_insert(&key_store, (uchar*) entry))
+ my_free(entry);
+ else
+ error= FALSE;
+ }
+ }
+ return error;
+ }
+
+ void delete_data(Key_Info* key_info)
+ {
+ Hash_Secure_Store_Entry *entry= NULL;
+
+ if (inited_hash && key_info && key_info->get_key() &&
+ key_info->get_key_size())
+ {
+ entry= (Hash_Secure_Store_Entry *)
+ my_hash_search(&key_store, (uchar *) key_info->get_key(),
+ key_info->get_key_size());
+ }
+ if (entry)
+ {
+ my_hash_delete(&key_store, (uchar*) entry);
+ my_free(entry);
+ }
+ }
+
+ bool init(char *key_input, const size_t key_input_size);
+ bool check_item(void *key, size_t key_size);
+ bool put_item(void **key, size_t key_size, void *plain_data,
+ size_t plain_data_size, bool encrypt);
+ void *get_item(void *key, size_t key_size, size_t *plain_data_size,
+ bool decrypt);
+ void *delete_item(void *key, size_t key_size, size_t *plain_data_size,
+ bool decrypt);
+
+private:
+ Secure_Store_Interface(const Secure_Store_Interface& info);
+ Secure_Store_Interface& operator=(const Secure_Store_Interface& info);
+};
+
+bool Secure_Store_Interface::init(char *key_input, const size_t key_input_size)
+{
+ return secure_info.init(key_input, key_input_size);
+}
+
+bool Secure_Store_Interface::check_item(void *key, size_t key_size)
+{
+ /* Structure used to search for encrypted data. */
+ Key_Info key_search;
+ key_search.set_key(key, key_size);
+
+ return (search_data(&key_search) != NULL);
+}
+
+/*
+ In order to ease implementation, we assume that key is always defined
+ and there is no auto-generation for now.
+*/
+bool Secure_Store_Interface::put_item(void **key, size_t key_size,
+ void *plain_data, size_t plain_data_size,
+ bool encrypt)
+{
+ /* Structure used to search for encrypted data. */
+ Key_Info key_search;
+
+ /* Structures to store key and encrypted data. */
+ Key_Info *key_info= NULL;
+ Crypto_Info *crypto_info= NULL;
+
+ /* Stores the data to be inserted and if everything goes fine, this is
+ copied to Crypto_Info.
+ */
+ void *crypto_data= NULL;
+ size_t crypto_data_size= 0;
+
+ /*
+ Defines a key that will be used to search for encrypted data.
+ */
+ key_search.set_key(*key, key_size);
+ key_info= &key_search;
+
+ /*
+ If encrypted data is not found a new Key_Info and Crypto_Info are
+ created and then inserted.
+ */
+ if ((crypto_info= search_data(key_info)) == NULL)
+ {
+ /*
+ Creates Key_Info and if it is not possible due to memory issues,
+ the execution returns with an error.
+ */
+ if ((key_info= new Key_Info()) == NULL)
+ return TRUE;
+
+ /*
+ Populates Key_Info and if it is not possible due to memory issues,
+ the execution returns with an error.
+ */
+ key_info->set_key(my_malloc(key_size, MYF(MY_WME)), key_size);
+ if (key_info->get_key() == NULL)
+ goto err;
+ memcpy(key_info->get_key(), *key, key_size);
+
+ if ((crypto_info= new Crypto_Info()) == NULL)
+ goto err;
+
+ if (insert_data(key_info, crypto_info))
+ goto err;
+ }
+
+ /*
+ Allocates memory to store the encrypted data, then encrypts the
+ data and stores it.
+ */
+ crypto_data_size= encrypt ?
+ secure_info.get_maximum_encrypted_data_size(plain_data_size) :
+ plain_data_size;
+ if ((crypto_data= my_malloc(crypto_data_size, MYF(MY_WME))))
+ {
+ bool done= FALSE;
+
+ if (encrypt)
+ done= !secure_info.encrypt_data(plain_data, plain_data_size,
+ crypto_data, &crypto_data_size);
+ else
+ {
+ done= TRUE;
+ memcpy(crypto_data, plain_data, plain_data_size);
+ crypto_data_size= plain_data_size;
+ }
+
+ if (done)
+ {
+ my_free(crypto_info->get_crypto());
+ crypto_info->set_crypto(crypto_data, crypto_data_size);
+ return FALSE;
+ }
+ }
+
+err:
+ /*
+ Something bad happens and we need to free memory that was allocated.
+ To ease this task, we ensure that at this point key_info is not null
+ and as such either points to key_search or a new created object.
+
+ If it points to key_search, this means that we are updating an item
+ and just need to free memory allocated for the crypto_data because
+ Key_Info and Crypto_Info were not changed.
+
+ However, if it points to another memory location, this means that we
+ had tried to insert data and as such we need to remove it, free
+ memory allocated for the key and delete Key_Info and Crypto_Info.
+ */
+ assert(key_info != NULL);
+
+ if (key_info != &key_search)
+ delete_data(key_info);
+ /*
+ If something bad happens the cryto_data was not assigned to crypto_info
+ and it was not freed by delete_data(). For that reason, we need to free
+ the memory here.
+ */
+ my_free(crypto_data);
+
+ return TRUE;
+}
+
+void *Secure_Store_Interface::get_item(void *key, size_t key_size,
+ size_t *plain_data_size, bool decrypt)
+{
+ /* Structure used to search for encrypted data. */
+ Key_Info key_search;
+ Crypto_Info *crypto_info= NULL;
+ void* plain_data= NULL;
+
+ key_search.set_key(key, key_size);
+ if ((crypto_info= search_data(&key_search)))
+ {
+ /*
+ Maybe we should store the plain data size in order to allocate the exact
+ amount of memory. /Alfranio
+ */
+ if ((plain_data= my_malloc(crypto_info->get_crypto_size(), MYF(MY_WME))))
+ {
+ bool done= FALSE;
+ if (decrypt)
+ done= !secure_info.decrypt_data(plain_data, plain_data_size,
+ crypto_info->get_crypto(),
+ crypto_info->get_crypto_size());
+ else
+ {
+ done= TRUE;
+ memcpy(plain_data, crypto_info->get_crypto(),
+ crypto_info->get_crypto_size());
+ *plain_data_size= crypto_info->get_crypto_size();
+ }
+ if (done) return plain_data;
+ }
+ }
+
+ my_free(plain_data);
+ return NULL;
+}
+
+void *Secure_Store_Interface::delete_item(void *key, size_t key_size,
+ size_t* plain_data_size, bool decrypt)
+{
+ /* Structure used to search for encrypted data. */
+ Key_Info key_search;
+ void* plain_data= get_item(key, key_size, plain_data_size, decrypt);
+
+ if (plain_data)
+ {
+ key_search.set_key(key, key_size);
+ delete_data(&key_search);
+ }
+
+ return plain_data;
+}
+
+typedef struct Hash_Secure_Schema_Entry
+{
+ char *schema;
+ Secure_Store_Interface *secure_store;
+} Hash_Secure_Schema_Entry;
+
+extern "C" uchar *get_secure_schema_key(const uchar *record, size_t *length,
+ my_bool not_used __attribute__((unused)))
+{
+ Hash_Secure_Schema_Entry *entry=(Hash_Secure_Schema_Entry *) record;
+ *length= strlen(entry->schema);
+
+ return((uchar*) entry->schema);
+}
+
+extern "C" void free_secure_schema_entry(Hash_Secure_Schema_Entry *entry)
+{
+ my_free(entry->schema);
+ delete entry->secure_store;
+}
+
+/*
+ This class maps an unique schema to a secure store and provides
+ implementation for: secure_store_open() and secure_store_close().
+ The access to the repository is hidden through some methods:
+ search_data(), insert_data() and delete_data().
+*/
+class Secure_Schema
+{
+private:
+ /**
+ Maps an unique schema to secure store: Schema --> Secure_Store.
+ */
+ HASH key_schema;
+ /**
+ Identifies if the hash structure was properly initialized.
+ */
+ bool inited_hash;
+
+public:
+ Secure_Schema()
+ {
+ inited_hash=
+ (my_hash_init(&key_schema, &my_charset_bin,
+ 0, 0, 0, get_secure_schema_key,
+ (my_hash_free_key) free_secure_schema_entry, 0) == 0);
+ }
+
+ ~Secure_Schema()
+ {
+ if (inited_hash) my_hash_free(&key_schema);
+ }
+
+ Secure_Store_Interface *search_data(char* schema)
+ {
+ Hash_Secure_Schema_Entry *entry= NULL;
+ if (inited_hash && schema)
+ {
+ entry = (Hash_Secure_Schema_Entry *)
+ my_hash_search(&key_schema, (uchar *) schema, strlen(schema));
+ }
+ return (entry ? entry->secure_store : NULL);
+ }
+
+ bool insert_data(char* schema, Secure_Store_Interface* secure_store)
+ {
+ bool error= TRUE;
+ if (inited_hash && schema && secure_store)
+ {
+ Hash_Secure_Schema_Entry *entry= (Hash_Secure_Schema_Entry *)
+ my_malloc(sizeof(Hash_Secure_Schema_Entry), MYF(MY_WME));
+ if (entry)
+ {
+ entry->schema= schema;
+ entry->secure_store= secure_store;
+ if (my_hash_insert(&key_schema, (uchar*) entry))
+ my_free(entry);
+ else
+ error= FALSE;
+ }
+ }
+ return error;
+ }
+
+ void delete_data(char* schema)
+ {
+ Hash_Secure_Schema_Entry *entry= NULL;
+ if (inited_hash && schema)
+ {
+ entry = (Hash_Secure_Schema_Entry *)
+ my_hash_search(&key_schema, (uchar *) schema, strlen(schema));
+ }
+
+ if (entry)
+ {
+ my_hash_delete(&key_schema, (uchar*) entry);
+ my_free(entry);
+ }
+ }
+
+ Secure_Store_Interface *open(char *schema);
+ void close(Secure_Store_Interface* store);
+
+private:
+ Secure_Schema(const Secure_Schema& info);
+ Secure_Schema& operator=(const Secure_Schema& info);
+};
+
+Secure_Store_Interface *Secure_Schema::open(char *schema_arg)
+{
+ Secure_Store_Interface *store= NULL;
+ char *schema= NULL;
+
+ if ((store= search_data(schema_arg)) == NULL)
+ {
+ store= new Secure_Store_Interface(schema_arg);
+ schema= (char *) my_malloc(strlen(schema_arg), MYF(MY_WME));
+ if (store == NULL || schema == NULL)
+ goto err;
+
+ strmake(schema, schema_arg, strlen(schema_arg));
+ if (insert_data(schema, store))
+ goto err;
+ }
+
+ return store;
+
+err:
+ delete store;
+ my_free(schema);
+
+ return NULL;
+}
+
+void Secure_Schema::close(Secure_Store_Interface* store)
+{
+ char* schema= const_cast<char *>(store->get_schema());
+ delete_data(schema);
+}
+
+Secure_Schema secure_schema;
+
+extern "C" {
+Secure_Store *secure_store_open(char *schema,
+ uint32 flags __attribute__((unused)))
+{
+ if (schema)
+ return secure_schema.open(schema);
+
+ return NULL;
+}
+
+bool secure_store_flush(Secure_Store *store_arg __attribute__((unused)))
+{
+ return FALSE;
+}
+
+bool secure_store_init(Secure_Store *store_arg, char *key_input,
+ const size_t key_input_size)
+{
+ if (store_arg != NULL)
+ {
+ Secure_Store_Interface *store= static_cast<Secure_Store_Interface *>(store_arg);
+ return store->init(key_input, key_input_size);
+ }
+ return TRUE;
+}
+
+void secure_store_close(Secure_Store *store_arg)
+{
+ if (store_arg != NULL)
+ {
+ Secure_Store_Interface *store= static_cast<Secure_Store_Interface *>(store_arg);
+ secure_schema.close(store);
+ }
+}
+
+bool secure_store_put_item(Secure_Store *store_arg, void **key, size_t key_len,
+ void *value, size_t value_len, bool encrypt)
+{
+ if (store_arg != NULL && key != NULL && value != NULL && value_len != 0)
+ {
+ Secure_Store_Interface *store= static_cast<Secure_Store_Interface *>(store_arg);
+ return store->put_item(key, key_len, value, value_len, encrypt);
+ }
+ return TRUE;
+}
+
+void *secure_store_get_item(Secure_Store *store_arg, void *key, size_t key_len,
+ size_t *value_len, bool decrypt)
+{
+ if (store_arg != NULL && key != NULL && key_len != 0 && value_len != NULL)
+ {
+ Secure_Store_Interface *store= static_cast<Secure_Store_Interface *>(store_arg);
+ return store->get_item(key, key_len, value_len, decrypt);
+ }
+ return NULL;
+}
+
+void *secure_store_delete_item(Secure_Store *store_arg, void *key, size_t key_len,
+ size_t *value_len, bool decrypt)
+{
+ if (store_arg != NULL && key != NULL && key_len != 0 && value_len != NULL)
+ {
+ Secure_Store_Interface *store= static_cast<Secure_Store_Interface *>(store_arg);
+ return store->delete_item(key, key_len, value_len, decrypt);
+ }
+ return NULL;
+}
+
+bool secure_store_check_item(Secure_Store *store_arg, void *key, size_t key_len)
+{
+ if (store_arg != NULL && key != NULL && key_len != 0)
+ {
+ Secure_Store_Interface *store= static_cast<Secure_Store_Interface *>(store_arg);
+ return store->check_item(key, key_len);
+ }
+ return FALSE;
+}
+} /* extern "C" */
=== added file 'sql/secure_store.h'
--- a/sql/secure_store.h 1970-01-01 00:00:00 +0000
+++ b/sql/secure_store.h 2011-04-18 06:30:30 +0000
@@ -0,0 +1,53 @@
+#ifndef SECURE_STORE_H
+
+#define SECURE_STORE_H
+
+#include <my_global.h>
+#include <sql_priv.h>
+
+#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) && !defined(HAVE_YASSL)
+#include <openssl/evp.h>
+#include <openssl/rand.h>
+#include <openssl/aes.h>
+
+/**
+ Extra space necessary to store encrypted data. Note that this
+ is zero if crypto library is not available.
+*/
+const int ENCRYPTION_BLOCK_SIZE= AES_BLOCK_SIZE;
+/**
+ Size of the key in bytes used to encrypt data.
+*/
+#define ENCRYPTION_KEY_SIZE 32
+
+#else
+const int ENCRYPTION_BLOCK_SIZE= 0;
+
+#endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY && !HAVE_YASSL */
+
+class Secure_Store
+{
+protected:
+ Secure_Store()
+ {
+ }
+private:
+ Secure_Store(const Secure_Store& info);
+ Secure_Store& operator=(const Secure_Store& info);
+};
+
+extern "C" {
+Secure_Store *secure_store_open(char *schema, uint32 flags);
+bool secure_store_init(Secure_Store *store, char *key_input,
+ size_t key_input_size);
+bool secure_store_flush(Secure_Store *store);
+void secure_store_close(Secure_Store *store);
+bool secure_store_put_item(Secure_Store *store, void **key, size_t key_len,
+ void *value, size_t value_len, bool encrypt);
+void *secure_store_get_item(Secure_Store *store, void *key, size_t key_len,
+ size_t *value_len, bool decrypt);
+void *secure_store_delete_item(Secure_Store *store, void *key, size_t key_len,
+ size_t *value_len, bool decrypt);
+bool secure_store_check_item(Secure_Store *store, void *key, size_t key_len);
+}
+#endif /* SECURE_STORE_H */
=== modified file 'sql/sql_lex.h'
--- a/sql/sql_lex.h 2011-03-28 10:56:41 +0000
+++ b/sql/sql_lex.h 2011-04-18 06:30:30 +0000
@@ -984,6 +984,14 @@ private:
Alter_info(const Alter_info &rhs); // not implemented
};
+typedef struct struct_slave_connection
+{
+ char *user;
+ char *password;
+ char *plugin_auth;
+ char *plugin_dir;
+} LEX_SLAVE_CONNECTION;
+
struct st_sp_chistics
{
LEX_STRING comment;
@@ -2122,6 +2130,7 @@ struct LEX: public Query_tables_list
HA_CREATE_INFO create_info;
KEY_CREATE_INFO key_create_info;
LEX_MASTER_INFO mi; // used by CHANGE MASTER
+ LEX_SLAVE_CONNECTION slave_connection;
LEX_SERVER_OPTIONS server_options;
USER_RESOURCES mqh;
ulong type;
=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc 2011-04-01 14:04:52 +0000
+++ b/sql/sql_parse.cc 2011-04-18 06:30:30 +0000
@@ -2590,7 +2590,40 @@ end_with_restore_list:
case SQLCOM_SLAVE_START:
{
mysql_mutex_lock(&LOCK_active_mi);
- start_slave(thd,active_mi,1 /* net report*/);
+
+ if (lex->slave_connection.user)
+ {
+ active_mi->set_start_user_configured(TRUE);
+ active_mi->set_user(lex->slave_connection.user);
+ }
+ if (lex->slave_connection.password)
+ {
+ thd->set_query(active_mi->start_command,
+ strlen(active_mi->start_command));
+ active_mi->set_start_user_configured(TRUE);
+ active_mi->set_password(lex->slave_connection.password,
+ strlen(lex->slave_connection.password));
+ }
+ if (lex->slave_connection.plugin_auth)
+ {
+ active_mi->set_start_plugin_configured(TRUE);
+ active_mi->set_plugin_auth(lex->slave_connection.plugin_auth);
+ }
+ if (lex->slave_connection.plugin_dir)
+ {
+ active_mi->set_start_plugin_configured(TRUE);
+ active_mi->set_plugin_dir(lex->slave_connection.plugin_dir);
+ }
+
+ if (start_slave(thd, active_mi, 1 /* net report*/))
+ {
+ /*
+ Clean information used to start slave in order to avoid
+ security issues.
+ */
+ active_mi->clean_start_information();
+ }
+
mysql_mutex_unlock(&LOCK_active_mi);
break;
}
=== modified file 'sql/sql_yacc.yy'
--- a/sql/sql_yacc.yy 2011-03-09 20:54:55 +0000
+++ b/sql/sql_yacc.yy 2011-04-18 06:30:30 +0000
@@ -919,6 +919,7 @@ bool my_yyoverflow(short **a, YYSTYPE **
%token DECIMAL_SYM /* SQL-2003-R */
%token DECLARE_SYM /* SQL-2003-R */
%token DEFAULT /* SQL-2003-R */
+%token DEFAULT_AUTH_SYM /* INTERNAL */
%token DEFINER_SYM
%token DELAYED_SYM
%token DELAY_KEY_WRITE_SYM
@@ -1176,8 +1177,9 @@ bool my_yyoverflow(short **a, YYSTYPE **
%token PARTITIONING_SYM
%token PASSWORD
%token PHASE_SYM
-%token PLUGINS_SYM
+%token PLUGIN_DIR_SYM /* INTERNAL */
%token PLUGIN_SYM
+%token PLUGINS_SYM
%token POINT_SYM
%token POLYGON
%token PORT_SYM
@@ -6910,6 +6912,8 @@ slave:
}
slave_until
{}
+ slave_connection_opts
+ {}
| STOP_SYM SLAVE slave_thread_opts
{
LEX *lex=Lex;
@@ -6936,6 +6940,50 @@ start_transaction_opts:
}
;
+slave_connection_opts:
+ slave_user_name_opt slave_user_pass_opt
+ slave_plugin_auth_opt slave_plugin_dir_opt
+ ;
+
+slave_user_name_opt:
+ {
+ Lex->slave_connection.user= 0;
+ }
+ | USER EQ TEXT_STRING_sys
+ {
+ Lex->slave_connection.user= $3.str;
+ }
+ ;
+
+slave_user_pass_opt:
+ {
+ Lex->slave_connection.password= 0;
+ }
+ | PASSWORD EQ TEXT_STRING_sys
+ {
+ Lex->slave_connection.password= $3.str;
+ }
+
+slave_plugin_auth_opt:
+ {
+ Lex->slave_connection.plugin_auth= 0;
+ }
+ | DEFAULT_AUTH_SYM EQ TEXT_STRING_sys
+ {
+ Lex->slave_connection.plugin_auth= $3.str;
+ }
+ ;
+
+slave_plugin_dir_opt:
+ {
+ Lex->slave_connection.plugin_dir= 0;
+ }
+ | PLUGIN_DIR_SYM EQ TEXT_STRING_sys
+ {
+ Lex->slave_connection.plugin_dir= $3.str;
+ }
+ ;
+
slave_thread_opts:
{ Lex->slave_thd_opt= 0; }
slave_thread_opt_list
@@ -12623,6 +12671,7 @@ keyword_sp:
| DATETIME {}
| DATE_SYM {}
| DAY_SYM {}
+ | DEFAULT_AUTH_SYM {}
| DEFINER_SYM {}
| DELAY_KEY_WRITE_SYM {}
| DES_KEY_FILE {}
@@ -12747,6 +12796,7 @@ keyword_sp:
| PARTITIONS_SYM {}
| PASSWORD {}
| PHASE_SYM {}
+ | PLUGIN_DIR_SYM {}
| PLUGIN_SYM {}
| PLUGINS_SYM {}
| POINT_SYM {}
Attachment: [text/bzr-bundle] bzr/alfranio.correia@oracle.com-20110418063030-38o7r2l5fxt0e459.bundle
| Thread |
|---|
| • bzr commit into mysql-trunk branch (alfranio.correia:3345) WL#4143 | Alfranio Correia | 18 Apr |