From 376090caaad39444784f33895fb9aa072395cd6f Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Fri, 19 Nov 2010 16:35:04 +0200 Subject: [PATCH] Bug #57551: Live upgrade fails between 5.1.52 -> 5.5.7-rc Updated the server to treat a missing mysql.proxies_priv table as empty. Added some grants to make sure tables are correctly opened when they must be opened. Fixed a mysql_upgrade omission not adding rights to root to execute GRANT PROXY on other users. Removed a redundant CREATE TABLE from mysql_system_tables_fix.sql since it's always executed after mysql_system_tables.sql and the first file has CREATE TABLE in it. Added a test case for the above. Fixed error handling code to close the cursor --- mysql-test/r/plugin_auth.result | 64 ++++++++++++++++++++++++++++ mysql-test/t/plugin_auth.test | 60 ++++++++++++++++++++++++++ scripts/mysql_system_tables_fix.sql | 9 +++- sql/sql_acl.cc | 65 ++++++++++++++++++----------- 4 files changed, 173 insertions(+), 25 deletions(-) diff --git a/mysql-test/r/plugin_auth.result b/mysql-test/r/plugin_auth.result index 7119ba11077..8a649f63598 100644 --- a/mysql-test/r/plugin_auth.result +++ b/mysql-test/r/plugin_auth.result @@ -255,3 +255,67 @@ GRANT PROXY ON standard_user TO ''@''; DROP USER ''@''; DROP USER standard_user; DROP DATABASE shared; +# +# Bug #57551 : Live upgrade fails between 5.1.52 -> 5.5.7-rc +# +CALL mtr.add_suppression("Missing system table mysql.proxies_priv."); +DROP TABLE mysql.proxies_priv; +# Must come back with mysql.proxies_priv absent. +SELECT * FROM mysql.proxies_priv; +ERROR 42S02: Table 'mysql.proxies_priv' doesn't exist +CREATE USER u1@localhost; +GRANT ALL PRIVILEGES ON *.* TO u1@localhost; +REVOKE ALL PRIVILEGES ON *.* FROM u1@localhost; +GRANT ALL PRIVILEGES ON *.* TO u1@localhost; +CREATE USER u2@localhost; +GRANT ALL PRIVILEGES ON *.* TO u2@localhost; +# access denied because of no privileges to root +GRANT PROXY ON u2@localhost TO u1@localhost; +ERROR 28000: Access denied for user 'root'@'localhost' +# access denied because of no privileges to root +REVOKE PROXY ON u2@localhost FROM u1@localhost; +ERROR 28000: Access denied for user 'root'@'localhost' +# go try graning proxy on itself, so that it will need the table +GRANT PROXY ON u2@localhost TO u1@localhost; +ERROR 42S02: Table 'mysql.proxies_priv' doesn't exist +REVOKE PROXY ON u2@localhost FROM u1@localhost; +ERROR 42S02: Table 'mysql.proxies_priv' doesn't exist +# test if REVOKE works without the proxies_priv table +REVOKE ALL PRIVILEGES ON *.* FROM u1@localhost, u2@localhost; +# test if DROP USER work without the proxies_priv table +DROP USER u1@localhost,u2@localhost; +# test if FLUSH PRIVILEGES works without the proxies_priv table +FLUSH PRIVILEGES; +mtr.global_suppressions OK +mtr.test_suppressions OK +mysql.columns_priv OK +mysql.db OK +mysql.event OK +mysql.func OK +mysql.general_log OK +mysql.help_category OK +mysql.help_keyword OK +mysql.help_relation OK +mysql.help_topic OK +mysql.host OK +mysql.ndb_binlog_index OK +mysql.plugin OK +mysql.proc OK +mysql.procs_priv OK +mysql.servers OK +mysql.slow_log OK +mysql.tables_priv OK +mysql.time_zone OK +mysql.time_zone_leap_second OK +mysql.time_zone_name OK +mysql.time_zone_transition OK +mysql.time_zone_transition_type OK +mysql.user OK +SELECT Host,User,Proxied_host,Proxied_user,With_grant FROM mysql.proxies_priv; +Host localhost +User root +Proxied_host +Proxied_user +With_grant 1 +FLUSH PRIVILEGES; +End of 5.5 tests diff --git a/mysql-test/t/plugin_auth.test b/mysql-test/t/plugin_auth.test index 439cabaef18..3b1dd93c4d1 100644 --- a/mysql-test/t/plugin_auth.test +++ b/mysql-test/t/plugin_auth.test @@ -1,5 +1,6 @@ --source include/have_plugin_auth.inc --source include/not_embedded.inc +--source include/mysql_upgrade_preparation.inc query_vertical SELECT PLUGIN_STATUS, PLUGIN_TYPE, PLUGIN_DESCRIPTION FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME='test_plugin_server'; @@ -335,3 +336,62 @@ GRANT PROXY ON standard_user TO ''@''; DROP USER ''@''; DROP USER standard_user; DROP DATABASE shared; + + +--echo # +--echo # Bug #57551 : Live upgrade fails between 5.1.52 -> 5.5.7-rc +--echo # + +CALL mtr.add_suppression("Missing system table mysql.proxies_priv."); + +DROP TABLE mysql.proxies_priv; + +--echo # Must come back with mysql.proxies_priv absent. +--source include/restart_mysqld.inc + +--error ER_NO_SUCH_TABLE +SELECT * FROM mysql.proxies_priv; + +CREATE USER u1@localhost; +GRANT ALL PRIVILEGES ON *.* TO u1@localhost; +REVOKE ALL PRIVILEGES ON *.* FROM u1@localhost; +GRANT ALL PRIVILEGES ON *.* TO u1@localhost; + +CREATE USER u2@localhost; +GRANT ALL PRIVILEGES ON *.* TO u2@localhost; + +--echo # access denied because of no privileges to root +--error ER_ACCESS_DENIED_NO_PASSWORD_ERROR +GRANT PROXY ON u2@localhost TO u1@localhost; + +--echo # access denied because of no privileges to root +--error ER_ACCESS_DENIED_NO_PASSWORD_ERROR +REVOKE PROXY ON u2@localhost FROM u1@localhost; + +--echo # go try graning proxy on itself, so that it will need the table +connect(proxy_granter_con,localhost,u2,); +connection proxy_granter_con; + +--error ER_NO_SUCH_TABLE +GRANT PROXY ON u2@localhost TO u1@localhost; +--error ER_NO_SUCH_TABLE +REVOKE PROXY ON u2@localhost FROM u1@localhost; + +connection default; +disconnect proxy_granter_con; + +--echo # test if REVOKE works without the proxies_priv table +REVOKE ALL PRIVILEGES ON *.* FROM u1@localhost, u2@localhost; + +--echo # test if DROP USER work without the proxies_priv table +DROP USER u1@localhost,u2@localhost; + +--echo # test if FLUSH PRIVILEGES works without the proxies_priv table +FLUSH PRIVILEGES; + +--exec $MYSQL_UPGRADE --skip-verbose --force 2>&1 +--query_vertical SELECT Host,User,Proxied_host,Proxied_user,With_grant FROM mysql.proxies_priv + +FLUSH PRIVILEGES; + +--echo End of 5.5 tests diff --git a/scripts/mysql_system_tables_fix.sql b/scripts/mysql_system_tables_fix.sql index b51e4c6f549..399c42b1b2d 100644 --- a/scripts/mysql_system_tables_fix.sql +++ b/scripts/mysql_system_tables_fix.sql @@ -643,7 +643,14 @@ drop procedure mysql.die; ALTER TABLE user ADD plugin char(60) DEFAULT '' NOT NULL, ADD authentication_string TEXT NOT NULL; ALTER TABLE user MODIFY plugin char(60) DEFAULT '' NOT NULL; -CREATE TABLE IF NOT EXISTS proxies_priv (Host char(60) binary DEFAULT '' NOT NULL, User char(16) binary DEFAULT '' NOT NULL, Proxied_host char(60) binary DEFAULT '' NOT NULL, Proxied_user char(16) binary DEFAULT '' NOT NULL, With_grant BOOL DEFAULT 0 NOT NULL, Grantor char(77) DEFAULT '' NOT NULL, Timestamp timestamp, PRIMARY KEY Host (Host,User,Proxied_host,Proxied_user), KEY Grantor (Grantor) ) engine=MyISAM CHARACTER SET utf8 COLLATE utf8_bin comment='User proxy privileges'; +-- Need to pre-fill mysql.proxies_priv with access for root even when upgrading from +-- older versions + +CREATE TEMPORARY TABLE tmp_proxies_priv LIKE proxies_priv; +INSERT INTO tmp_proxies_priv VALUES ('localhost', 'root', '', '', TRUE, '', now()); +INSERT INTO proxies_priv SELECT * FROM tmp_proxies_priv WHERE @had_proxies_priv_table=0; +DROP TABLE tmp_proxies_priv; + # Activate the new, possible modified privilege tables # This should not be needed, but gives us some extra testing that the above diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index abd8f50cb9f..f21f204ef3f 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1029,24 +1029,35 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) end_read_record(&read_record_info); freeze_size(&acl_dbs); - init_read_record(&read_record_info, thd, table= tables[3].table, NULL, 1, - 0, FALSE); - table->use_all_columns(); (void) my_init_dynamic_array(&acl_proxy_users, sizeof(ACL_PROXY_USER), 50, 100); - while (!(read_record_info.read_record(&read_record_info))) + if (tables[3].table) { - ACL_PROXY_USER proxy; - proxy.init(table, &mem); - if (proxy.check_validity(check_no_resolve)) - continue; - if (push_dynamic(&acl_proxy_users, (uchar*) &proxy)) - return TRUE; + init_read_record(&read_record_info, thd, table= tables[3].table, NULL, 1, + 0, FALSE); + table->use_all_columns(); + while (!(read_record_info.read_record(&read_record_info))) + { + ACL_PROXY_USER proxy; + proxy.init(table, &mem); + if (proxy.check_validity(check_no_resolve)) + continue; + if (push_dynamic(&acl_proxy_users, (uchar*) &proxy)) + { + end_read_record(&read_record_info); + goto end; + } + } + my_qsort((uchar*) dynamic_element(&acl_proxy_users, 0, ACL_PROXY_USER*), + acl_proxy_users.elements, + sizeof(ACL_PROXY_USER), (qsort_cmp) acl_compare); + end_read_record(&read_record_info); + } + else + { + sql_print_error("Missing system table mysql.proxies_priv; " + "please run mysql_upgrade to create it"); } - my_qsort((uchar*) dynamic_element(&acl_proxy_users, 0, ACL_PROXY_USER*), - acl_proxy_users.elements, - sizeof(ACL_PROXY_USER), (qsort_cmp) acl_compare); - end_read_record(&read_record_info); freeze_size(&acl_proxy_users); init_check_host(); @@ -1127,6 +1138,7 @@ my_bool acl_reload(THD *thd) tables[2].next_local= tables[2].next_global= tables + 3; tables[0].open_type= tables[1].open_type= tables[2].open_type= tables[3].open_type= OT_BASE_ONLY; + tables[3].open_strategy= TABLE_LIST::OPEN_IF_EXISTS; if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { @@ -5703,6 +5715,8 @@ int open_grant_tables(THD *thd, TABLE_LIST *tables) (tables+5)->init_one_table(C_STRING_WITH_LEN("mysql"), C_STRING_WITH_LEN("proxies_priv"), "proxies_priv", TL_WRITE); + tables[5].open_strategy= TABLE_LIST::OPEN_IF_EXISTS; + tables->next_local= tables->next_global= tables + 1; (tables+1)->next_local= (tables+1)->next_global= tables + 2; (tables+2)->next_local= (tables+2)->next_global= tables + 3; @@ -6295,17 +6309,20 @@ static int handle_grant_data(TABLE_LIST *tables, bool drop, } /* Handle proxies_priv table. */ - if ((found= handle_grant_table(tables, 5, drop, user_from, user_to)) < 0) + if (tables[5].table) { - /* Handle of table failed, don't touch the in-memory array. */ - result= -1; - } - else - { - /* Handle proxies_priv array. */ - if ((handle_grant_struct(5, drop, user_from, user_to) && !result) || - found) - result= 1; /* At least one record/element found. */ + if ((found= handle_grant_table(tables, 5, drop, user_from, user_to)) < 0) + { + /* Handle of table failed, don't touch the in-memory array. */ + result= -1; + } + else + { + /* Handle proxies_priv array. */ + if ((handle_grant_struct(5, drop, user_from, user_to) && !result) || + found) + result= 1; /* At least one record/element found. */ + } } end: DBUG_RETURN(result);