diff options
-rw-r--r-- | client/mysqlbinlog.cc | 29 | ||||
-rw-r--r-- | mysql-test/r/grant.result | 75 | ||||
-rw-r--r-- | mysql-test/t/grant.test | 144 | ||||
-rw-r--r-- | sql/mysql_priv.h | 2 | ||||
-rw-r--r-- | sql/sql_db.cc | 43 | ||||
-rw-r--r-- | sql/sql_parse.cc | 98 | ||||
-rw-r--r-- | sql/sql_show.cc | 2 |
7 files changed, 342 insertions, 51 deletions
diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index e9ce861ab29..06ae20da8cf 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -1099,7 +1099,7 @@ static int dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info, uint logname_len; NET* net; int error= 0; - my_off_t old_off= min(start_position_mot, BIN_LOG_HEADER_SIZE); + my_off_t old_off= start_position_mot; char fname[FN_REFLEN+1]; DBUG_ENTER("dump_remote_log_entries"); @@ -1217,6 +1217,18 @@ could be out of memory"); len= 1; // fake Rotate, so don't increment old_off } } + else if (type == FORMAT_DESCRIPTION_EVENT) + { + /* + This could be an fake Format_description_log_event that server + (5.0+) automatically sends to a slave on connect, before sending + a first event at the requested position. If this is the case, + don't increment old_off. Real Format_description_log_event always + starts from BIN_LOG_HEADER_SIZE position. + */ + if (old_off != BIN_LOG_HEADER_SIZE) + len= 1; // fake event, don't increment old_off + } if ((error= process_event(print_event_info, ev, old_off))) { error= ((error < 0) ? 0 : 1); @@ -1229,16 +1241,16 @@ could be out of memory"); const char *old_fname= le->fname; uint old_len= le->fname_len; File file; - + if ((file= load_processor.prepare_new_file_for_old_format(le,fname)) < 0) { error= 1; goto err; } - + if ((error= process_event(print_event_info, ev, old_off))) { - my_close(file,MYF(MY_WME)); + my_close(file,MYF(MY_WME)); error= ((error < 0) ? 0 : 1); goto err; } @@ -1253,15 +1265,8 @@ could be out of memory"); /* Let's adjust offset for remote log as for local log to produce similar text and to have --stop-position to work identically. - - Exception - the server sends Format_description_log_event - in the beginning of the dump, and only after it the event from - start_position. Let the old_off reflect it. */ - if (old_off < start_position_mot) - old_off= start_position_mot; - else - old_off+= len-1; + old_off+= len-1; } err: diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result index 124e0c3aaf0..2dcfaf13198 100644 --- a/mysql-test/r/grant.result +++ b/mysql-test/r/grant.result @@ -1116,3 +1116,78 @@ drop user юзер_юзер@localhost; grant select on test.* to очень_длинный_юзер@localhost; ERROR HY000: String 'очень_длинный_юзер' is too long for user name (should be no longer than 16) set names default; +DROP DATABASE IF EXISTS mysqltest1; +DROP DATABASE IF EXISTS mysqltest2; +CREATE DATABASE mysqltest1; +CREATE DATABASE mysqltest2; +GRANT ALL PRIVILEGES ON mysqltest1.* TO mysqltest_1@localhost; +GRANT SELECT ON mysqltest2.* TO mysqltest_1@localhost; +CREATE PROCEDURE mysqltest1.p1() SQL SECURITY INVOKER +SELECT 1; + +---> connection: bug27337_con1 +CREATE TABLE t1(c INT); +ERROR 42000: CREATE command denied to user 'mysqltest_1'@'localhost' for table 't1' +CALL mysqltest1.p1(); +1 +1 +CREATE TABLE t1(c INT); +ERROR 42000: CREATE command denied to user 'mysqltest_1'@'localhost' for table 't1' + +---> connection: bug27337_con2 +CREATE TABLE t1(c INT); +ERROR 42000: CREATE command denied to user 'mysqltest_1'@'localhost' for table 't1' +SHOW TABLES; +Tables_in_mysqltest2 + +---> connection: default +DROP DATABASE mysqltest1; +DROP DATABASE mysqltest2; +DROP USER mysqltest_1@localhost; +DROP DATABASE IF EXISTS mysqltest1; +DROP DATABASE IF EXISTS mysqltest2; +CREATE DATABASE mysqltest1; +CREATE DATABASE mysqltest2; +CREATE TABLE mysqltest1.t1(c INT); +CREATE TABLE mysqltest2.t2(c INT); +GRANT SELECT ON mysqltest1.t1 TO mysqltest_1@localhost; +GRANT SELECT ON mysqltest2.t2 TO mysqltest_2@localhost; + +---> connection: bug27337_con1 +SHOW TABLES FROM mysqltest1; +Tables_in_mysqltest1 +t1 +PREPARE stmt1 FROM 'SHOW TABLES FROM mysqltest1'; +EXECUTE stmt1; +Tables_in_mysqltest1 +t1 + +---> connection: bug27337_con2 +SHOW COLUMNS FROM mysqltest2.t2; +Field Type Null Key Default Extra +c int(11) YES NULL +PREPARE stmt2 FROM 'SHOW COLUMNS FROM mysqltest2.t2'; +EXECUTE stmt2; +Field Type Null Key Default Extra +c int(11) YES NULL + +---> connection: default +REVOKE SELECT ON mysqltest1.t1 FROM mysqltest_1@localhost; +REVOKE SELECT ON mysqltest2.t2 FROM mysqltest_2@localhost; + +---> connection: bug27337_con1 +SHOW TABLES FROM mysqltest1; +ERROR 42000: Access denied for user 'mysqltest_1'@'localhost' to database 'mysqltest1' +EXECUTE stmt1; +ERROR 42000: Access denied for user 'mysqltest_1'@'localhost' to database 'mysqltest1' + +---> connection: bug27337_con2 +SHOW COLUMNS FROM mysqltest2.t2; +ERROR 42000: SELECT command denied to user 'mysqltest_2'@'localhost' for table 't2' +EXECUTE stmt2; +ERROR 42000: SELECT command denied to user 'mysqltest_2'@'localhost' for table 't2' + +---> connection: default +DROP DATABASE mysqltest1; +DROP DATABASE mysqltest2; +DROP USER mysqltest_1@localhost; diff --git a/mysql-test/t/grant.test b/mysql-test/t/grant.test index b9de8cb5d16..4867a6386c4 100644 --- a/mysql-test/t/grant.test +++ b/mysql-test/t/grant.test @@ -1068,6 +1068,150 @@ DROP DATABASE mysqltest4; DROP USER mysqltest_1@localhost; +# +# BUG#27337: Privileges are not restored properly. +# +# Actually, the patch for this bugs fixes two problems. So, here are two test +# cases. + +# Test case 1: privileges are not restored properly after calling a stored +# routine defined with SQL SECURITY INVOKER clause. + +# Prepare. + +--disable_warnings +DROP DATABASE IF EXISTS mysqltest1; +DROP DATABASE IF EXISTS mysqltest2; +--enable_warnings + +CREATE DATABASE mysqltest1; +CREATE DATABASE mysqltest2; + +GRANT ALL PRIVILEGES ON mysqltest1.* TO mysqltest_1@localhost; +GRANT SELECT ON mysqltest2.* TO mysqltest_1@localhost; + +CREATE PROCEDURE mysqltest1.p1() SQL SECURITY INVOKER + SELECT 1; + +# Test. + +--connect (bug27337_con1,localhost,mysqltest_1,,mysqltest2) +--echo +--echo ---> connection: bug27337_con1 + +--error ER_TABLEACCESS_DENIED_ERROR +CREATE TABLE t1(c INT); + +CALL mysqltest1.p1(); + +--error ER_TABLEACCESS_DENIED_ERROR +CREATE TABLE t1(c INT); + +--disconnect bug27337_con1 + +--connect (bug27337_con2,localhost,mysqltest_1,,mysqltest2) +--echo +--echo ---> connection: bug27337_con2 + +--error ER_TABLEACCESS_DENIED_ERROR +CREATE TABLE t1(c INT); + +SHOW TABLES; + +# Cleanup. + +--connection default +--echo +--echo ---> connection: default + +--disconnect bug27337_con2 + +DROP DATABASE mysqltest1; +DROP DATABASE mysqltest2; + +DROP USER mysqltest_1@localhost; + +# Test case 2: priveleges are not checked properly for prepared statements. + +# Prepare. + +--disable_warnings +DROP DATABASE IF EXISTS mysqltest1; +DROP DATABASE IF EXISTS mysqltest2; +--enable_warnings + +CREATE DATABASE mysqltest1; +CREATE DATABASE mysqltest2; + +CREATE TABLE mysqltest1.t1(c INT); +CREATE TABLE mysqltest2.t2(c INT); + +GRANT SELECT ON mysqltest1.t1 TO mysqltest_1@localhost; +GRANT SELECT ON mysqltest2.t2 TO mysqltest_2@localhost; + +# Test. + +--connect (bug27337_con1,localhost,mysqltest_1,,mysqltest1) +--echo +--echo ---> connection: bug27337_con1 + +SHOW TABLES FROM mysqltest1; + +PREPARE stmt1 FROM 'SHOW TABLES FROM mysqltest1'; + +EXECUTE stmt1; + +--connect (bug27337_con2,localhost,mysqltest_2,,mysqltest2) +--echo +--echo ---> connection: bug27337_con2 + +SHOW COLUMNS FROM mysqltest2.t2; + +PREPARE stmt2 FROM 'SHOW COLUMNS FROM mysqltest2.t2'; + +EXECUTE stmt2; + +--connection default +--echo +--echo ---> connection: default + +REVOKE SELECT ON mysqltest1.t1 FROM mysqltest_1@localhost; +REVOKE SELECT ON mysqltest2.t2 FROM mysqltest_2@localhost; + +--connection bug27337_con1 +--echo +--echo ---> connection: bug27337_con1 + +--error ER_DBACCESS_DENIED_ERROR +SHOW TABLES FROM mysqltest1; + +--error ER_DBACCESS_DENIED_ERROR +EXECUTE stmt1; + +--connection bug27337_con2 +--echo +--echo ---> connection: bug27337_con2 + +--error ER_TABLEACCESS_DENIED_ERROR +SHOW COLUMNS FROM mysqltest2.t2; + +--error ER_TABLEACCESS_DENIED_ERROR +EXECUTE stmt2; + +# Cleanup. + +--connection default +--echo +--echo ---> connection: default + +--disconnect bug27337_con2 + +DROP DATABASE mysqltest1; +DROP DATABASE mysqltest2; + +DROP USER mysqltest_1@localhost; + + --echo End of 5.0 tests # diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index fe7a567365e..85792727f34 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1134,6 +1134,8 @@ int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond); int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond); bool get_schema_tables_result(JOIN *join, enum enum_schema_table_state executed_place); +enum enum_schema_tables get_schema_table_idx(ST_SCHEMA_TABLE *schema_table); + #define is_schema_db(X) \ !my_strcasecmp(system_charset_info, INFORMATION_SCHEMA_NAME.str, (X)) diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 618b9d515bb..cfd610638ce 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -1437,30 +1437,27 @@ bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch) DBUG_PRINT("info",("Use database: %s", new_db_file_name.str)); #ifndef NO_EMBEDDED_ACCESS_CHECKS - if (!force_switch) /* FIXME: this is BUG#27337. */ + db_access= + test_all_bits(sctx->master_access, DB_ACLS) ? + DB_ACLS : + acl_get(sctx->host, + sctx->ip, + sctx->priv_user, + new_db_file_name.str, + FALSE) | sctx->master_access; + + if (!force_switch && + !(db_access & DB_ACLS) && + (!grant_option || check_grant_db(thd, new_db_file_name.str))) { - db_access= (test_all_bits(sctx->master_access, DB_ACLS) ? - DB_ACLS : - acl_get(sctx->host, - sctx->ip, - sctx->priv_user, - new_db_file_name.str, - FALSE) | sctx->master_access); - - if (!force_switch && - !(db_access & DB_ACLS) && - (!grant_option || check_grant_db(thd, new_db_file_name.str))) - { - my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), - sctx->priv_user, - sctx->priv_host, - new_db_file_name.str); - general_log_print(thd, COM_INIT_DB, ER(ER_DBACCESS_DENIED_ERROR), - sctx->priv_user, sctx->priv_host, - new_db_file_name.str); - my_free(new_db_file_name.str, MYF(0)); - DBUG_RETURN(TRUE); - } + my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), + sctx->priv_user, + sctx->priv_host, + new_db_file_name.str); + general_log_print(thd, COM_INIT_DB, ER(ER_DBACCESS_DENIED_ERROR), + sctx->priv_user, sctx->priv_host, new_db_file_name.str); + my_free(new_db_file_name.str, MYF(0)); + DBUG_RETURN(TRUE); } #endif diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 9c9a41a81fe..53404792dea 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1359,7 +1359,8 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, enum enum_schema_tables schema_table_idx) { DBUG_ENTER("prepare_schema_table"); - SELECT_LEX *sel= 0; + SELECT_LEX *schema_select_lex= NULL; + switch (schema_table_idx) { case SCH_SCHEMATA: #if defined(DONT_ALLOW_SHOW_COMMANDS) @@ -1367,11 +1368,9 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */ DBUG_RETURN(1); #else - if ((specialflag & SPECIAL_SKIP_SHOW_DB) && - check_global_access(thd, SHOW_DB_ACL)) - DBUG_RETURN(1); break; #endif + case SCH_TABLE_NAMES: case SCH_TABLES: case SCH_VIEWS: @@ -1390,23 +1389,15 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, { DBUG_RETURN(1); } - db.str= lex->select_lex.db; + schema_select_lex= new SELECT_LEX(); + db.str= schema_select_lex->db= lex->select_lex.db; + schema_select_lex->table_list.first= NULL; db.length= strlen(db.str); if (check_db_name(&db)) { my_error(ER_WRONG_DB_NAME, MYF(0), db.str); DBUG_RETURN(1); } - if (check_access(thd, SELECT_ACL, db.str, &thd->col_access, 0, 0, - is_schema_db(db.str))) - DBUG_RETURN(1); /* purecov: inspected */ - if (!thd->col_access && check_grant_db(thd, db.str)) - { - my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), - thd->security_ctx->priv_user, thd->security_ctx->priv_host, - db.str); - DBUG_RETURN(1); - } break; } #endif @@ -4698,6 +4689,83 @@ bool check_global_access(THD *thd, ulong want_access) } +static bool check_show_access(THD *thd, TABLE_LIST *table) +{ + switch (get_schema_table_idx(table->schema_table)) + { + case SCH_SCHEMATA: + return (specialflag & SPECIAL_SKIP_SHOW_DB) && + check_global_access(thd, SHOW_DB_ACL); + + case SCH_TABLE_NAMES: + case SCH_TABLES: + case SCH_VIEWS: + case SCH_TRIGGERS: + { + const char *dst_db_name= table->schema_select_lex->db; + + DBUG_ASSERT(dst_db_name); + + if (check_access(thd, SELECT_ACL, dst_db_name, + &thd->col_access, FALSE, FALSE, + is_schema_db(dst_db_name))) + { + return TRUE; + } + + if (!thd->col_access && check_grant_db(thd, dst_db_name)) + { + my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), + thd->security_ctx->priv_user, + thd->security_ctx->priv_host, + dst_db_name); + return TRUE; + } + + return FALSE; + } + + case SCH_COLUMNS: + case SCH_STATISTICS: + { + TABLE_LIST *dst_table= + (TABLE_LIST *) table->schema_select_lex->table_list.first; + + DBUG_ASSERT(dst_table); + + if (check_access(thd, SELECT_ACL | EXTRA_ACL, + dst_table->db, + &dst_table->grant.privilege, + FALSE, FALSE, + test(dst_table->schema_table))) + { + return FALSE; + } + + return grant_option && + check_grant(thd, SELECT_ACL, dst_table, 2, UINT_MAX, FALSE); + } + + case SCH_OPEN_TABLES: + case SCH_VARIABLES: + case SCH_STATUS: + case SCH_PROCEDURES: + case SCH_CHARSETS: + case SCH_COLLATIONS: + case SCH_COLLATION_CHARACTER_SET_APPLICABILITY: + case SCH_USER_PRIVILEGES: + case SCH_SCHEMA_PRIVILEGES: + case SCH_TABLE_PRIVILEGES: + case SCH_COLUMN_PRIVILEGES: + case SCH_TABLE_CONSTRAINTS: + case SCH_KEY_COLUMN_USAGE: + break; + } + + return FALSE; +} + + /* Check the privilege for all used tables. diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 19cabb874b9..0a04ba3e8cf 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2564,7 +2564,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) */ thd->reset_n_backup_open_tables_state(&open_tables_state_backup); - if (lsel) + if (lsel && lsel->table_list.first) { TABLE_LIST *show_table_list= (TABLE_LIST*) lsel->table_list.first; bool res; |