summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/mysqlbinlog.cc29
-rw-r--r--mysql-test/r/grant.result75
-rw-r--r--mysql-test/t/grant.test144
-rw-r--r--sql/mysql_priv.h2
-rw-r--r--sql/sql_db.cc43
-rw-r--r--sql/sql_parse.cc98
-rw-r--r--sql/sql_show.cc2
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;