Commit 180e74bd authored by 's avatar

Bug#27606 GRANT statement should be replicated with DEFINER information

"Grantor" columns' data is lost when replicating mysql.tables_priv.
Slave SQL thread used its default user ''@'' as the grantor of GRANT|REVOKE
statements executing on it.

In this patch, current user is put in query log event for all GRANT and REVOKE
statement, SQL thread uses the user in query log event as grantor.
parent aa235b1b
...@@ -260,4 +260,27 @@ Log_name Pos Event_type Server_id End_log_pos Info ...@@ -260,4 +260,27 @@ Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # use `test`; grant all on *.* to foo@"1.2.3.4" master-bin.000001 # Query # # use `test`; grant all on *.* to foo@"1.2.3.4"
master-bin.000001 # Query # # use `test`; revoke all privileges, grant option from "foo" master-bin.000001 # Query # # use `test`; revoke all privileges, grant option from "foo"
DROP USER foo@"1.2.3.4"; DROP USER foo@"1.2.3.4";
# Bug#27606 GRANT statement should be replicated with DEFINER information
stop slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
GRANT SELECT, INSERT ON mysql.user TO user_bug27606@localhost;
SELECT Grantor FROM mysql.tables_priv WHERE User='user_bug27606';
Grantor
root@localhost
SELECT Grantor FROM mysql.tables_priv WHERE User='user_bug27606';
Grantor
root@localhost
REVOKE SELECT ON mysql.user FROM user_bug27606@localhost;
SELECT Grantor FROM mysql.tables_priv WHERE User='user_bug27606';
Grantor
root@localhost
SELECT Grantor FROM mysql.tables_priv WHERE User='user_bug27606';
Grantor
root@localhost
DROP USER user_bug27606@localhost;
"End of test" "End of test"
...@@ -355,4 +355,25 @@ revoke all privileges, grant option from "foo"; ...@@ -355,4 +355,25 @@ revoke all privileges, grant option from "foo";
DROP USER foo@"1.2.3.4"; DROP USER foo@"1.2.3.4";
-- sync_slave_with_master -- sync_slave_with_master
--echo
--echo # Bug#27606 GRANT statement should be replicated with DEFINER information
--connection master
--source include/master-slave-reset.inc
--connection master
GRANT SELECT, INSERT ON mysql.user TO user_bug27606@localhost;
SELECT Grantor FROM mysql.tables_priv WHERE User='user_bug27606';
sync_slave_with_master;
SELECT Grantor FROM mysql.tables_priv WHERE User='user_bug27606';
--connection master
REVOKE SELECT ON mysql.user FROM user_bug27606@localhost;
SELECT Grantor FROM mysql.tables_priv WHERE User='user_bug27606';
sync_slave_with_master;
SELECT Grantor FROM mysql.tables_priv WHERE User='user_bug27606';
--connection master
DROP USER user_bug27606@localhost;
--source include/master-slave-end.inc
--echo "End of test" --echo "End of test"
...@@ -2314,7 +2314,7 @@ bool Query_log_event::write(IO_CACHE* file) ...@@ -2314,7 +2314,7 @@ bool Query_log_event::write(IO_CACHE* file)
start+= 4; start+= 4;
} }
if (thd && thd->is_current_user_used()) if (thd && thd->need_binlog_invoker())
{ {
LEX_STRING user; LEX_STRING user;
LEX_STRING host; LEX_STRING host;
......
...@@ -738,7 +738,7 @@ THD::THD() ...@@ -738,7 +738,7 @@ THD::THD()
thr_lock_owner_init(&main_lock_id, &lock_info); thr_lock_owner_init(&main_lock_id, &lock_info);
m_internal_handler= NULL; m_internal_handler= NULL;
current_user_used= FALSE; m_binlog_invoker= FALSE;
memset(&invoker_user, 0, sizeof(invoker_user)); memset(&invoker_user, 0, sizeof(invoker_user));
memset(&invoker_host, 0, sizeof(invoker_host)); memset(&invoker_host, 0, sizeof(invoker_host));
} }
...@@ -1247,7 +1247,7 @@ void THD::cleanup_after_query() ...@@ -1247,7 +1247,7 @@ void THD::cleanup_after_query()
where= THD::DEFAULT_WHERE; where= THD::DEFAULT_WHERE;
/* reset table map for multi-table update */ /* reset table map for multi-table update */
table_map_for_update= 0; table_map_for_update= 0;
clean_current_user_used(); m_binlog_invoker= FALSE;
} }
...@@ -3281,7 +3281,7 @@ void THD::set_query(char *query_arg, uint32 query_length_arg) ...@@ -3281,7 +3281,7 @@ void THD::set_query(char *query_arg, uint32 query_length_arg)
void THD::get_definer(LEX_USER *definer) void THD::get_definer(LEX_USER *definer)
{ {
set_current_user_used(); binlog_invoker();
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
if (slave_thread && has_invoker()) if (slave_thread && has_invoker())
{ {
......
...@@ -2344,9 +2344,8 @@ class THD :public Statement, ...@@ -2344,9 +2344,8 @@ class THD :public Statement,
Protected with LOCK_thd_data mutex. Protected with LOCK_thd_data mutex.
*/ */
void set_query(char *query_arg, uint32 query_length_arg); void set_query(char *query_arg, uint32 query_length_arg);
void set_current_user_used() { current_user_used= TRUE; } void binlog_invoker() { m_binlog_invoker= TRUE; }
bool is_current_user_used() { return current_user_used; } bool need_binlog_invoker() { return m_binlog_invoker; }
void clean_current_user_used() { current_user_used= FALSE; }
void get_definer(LEX_USER *definer); void get_definer(LEX_USER *definer);
void set_invoker(const LEX_STRING *user, const LEX_STRING *host) void set_invoker(const LEX_STRING *user, const LEX_STRING *host)
{ {
...@@ -2384,7 +2383,7 @@ class THD :public Statement, ...@@ -2384,7 +2383,7 @@ class THD :public Statement,
Current user will be binlogged into Query_log_event if current_user_used Current user will be binlogged into Query_log_event if current_user_used
is TRUE; It will be stored into invoker_host and invoker_user by SQL thread. is TRUE; It will be stored into invoker_host and invoker_user by SQL thread.
*/ */
bool current_user_used; bool m_binlog_invoker;
/** /**
It points to the invoker in the Query_log_event. It points to the invoker in the Query_log_event.
......
...@@ -3923,6 +3923,10 @@ mysql_execute_command(THD *thd) ...@@ -3923,6 +3923,10 @@ mysql_execute_command(THD *thd)
if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1, 0) && if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1, 0) &&
check_global_access(thd,CREATE_USER_ACL)) check_global_access(thd,CREATE_USER_ACL))
break; break;
/* Replicate current user as grantor */
thd->binlog_invoker();
/* Conditionally writes to binlog */ /* Conditionally writes to binlog */
if (!(res = mysql_revoke_all(thd, lex->users_list))) if (!(res = mysql_revoke_all(thd, lex->users_list)))
my_ok(thd); my_ok(thd);
...@@ -3943,6 +3947,9 @@ mysql_execute_command(THD *thd) ...@@ -3943,6 +3947,9 @@ mysql_execute_command(THD *thd)
is_schema_db(select_lex->db) : 0)) is_schema_db(select_lex->db) : 0))
goto error; goto error;
/* Replicate current user as grantor */
thd->binlog_invoker();
if (thd->security_ctx->user) // If not replication if (thd->security_ctx->user) // If not replication
{ {
LEX_USER *user, *tmp_user; LEX_USER *user, *tmp_user;
......
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