diff --git a/mysql-test/suite/rpl/r/rpl_do_grant.result b/mysql-test/suite/rpl/r/rpl_do_grant.result index ce0417cce07..0739fcbcc5c 100644 --- a/mysql-test/suite/rpl/r/rpl_do_grant.result +++ b/mysql-test/suite/rpl/r/rpl_do_grant.result @@ -264,4 +264,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`; revoke all privileges, grant option from "foo" 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" diff --git a/mysql-test/suite/rpl/t/rpl_do_grant.test b/mysql-test/suite/rpl/t/rpl_do_grant.test index 37358077145..2ac36e62563 100644 --- a/mysql-test/suite/rpl/t/rpl_do_grant.test +++ b/mysql-test/suite/rpl/t/rpl_do_grant.test @@ -347,4 +347,25 @@ revoke all privileges, grant option from "foo"; DROP USER foo@"1.2.3.4"; -- 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" diff --git a/sql/log_event.cc b/sql/log_event.cc index e96f45aedc8..b4641af07c5 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -2332,7 +2332,7 @@ bool Query_log_event::write(IO_CACHE* file) start+= 4; } - if (thd && thd->is_current_user_used()) + if (thd && thd->need_binlog_invoker()) { LEX_STRING user; LEX_STRING host; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 15fbc6a1480..daf9217a5a1 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -631,7 +631,7 @@ THD::THD() thr_lock_info_init(&lock_info); /* safety: will be reset after start */ m_internal_handler= NULL; - current_user_used= FALSE; + m_binlog_invoker= FALSE; memset(&invoker_user, 0, sizeof(invoker_user)); memset(&invoker_host, 0, sizeof(invoker_host)); } @@ -1336,7 +1336,7 @@ void THD::cleanup_after_query() where= THD::DEFAULT_WHERE; /* reset table map for multi-table update */ table_map_for_update= 0; - clean_current_user_used(); + m_binlog_invoker= FALSE; } @@ -3467,7 +3467,7 @@ void THD::leave_locked_tables_mode() void THD::get_definer(LEX_USER *definer) { - set_current_user_used(); + binlog_invoker(); #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) if (slave_thread && has_invoker()) { diff --git a/sql/sql_class.h b/sql/sql_class.h index aa0f6cf1aa3..24fd765d653 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2696,9 +2696,8 @@ public: } void leave_locked_tables_mode(); int decide_logging_format(TABLE_LIST *tables); - void set_current_user_used() { current_user_used= TRUE; } - bool is_current_user_used() { return current_user_used; } - void clean_current_user_used() { current_user_used= FALSE; } + void binlog_invoker() { m_binlog_invoker= TRUE; } + bool need_binlog_invoker() { return m_binlog_invoker; } void get_definer(LEX_USER *definer); void set_invoker(const LEX_STRING *user, const LEX_STRING *host) { @@ -2739,7 +2738,7 @@ private: 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. */ - bool current_user_used; + bool m_binlog_invoker; /** It points to the invoker in the Query_log_event. diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 4ed22e3a355..daf8971fb68 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3414,6 +3414,10 @@ end_with_restore_list: if (check_access(thd, UPDATE_ACL, "mysql", NULL, NULL, 1, 1) && check_global_access(thd,CREATE_USER_ACL)) break; + + /* Replicate current user as grantor */ + thd->binlog_invoker(); + /* Conditionally writes to binlog */ if (!(res = mysql_revoke_all(thd, lex->users_list))) my_ok(thd); @@ -3430,6 +3434,9 @@ end_with_restore_list: first_table ? 0 : 1, 0)) goto error; + /* Replicate current user as grantor */ + thd->binlog_invoker(); + if (thd->security_ctx->user) // If not replication { LEX_USER *user, *tmp_user;