summaryrefslogtreecommitdiff
path: root/sql/sql_parse.cc
diff options
context:
space:
mode:
authorunknown <thek@adventure.(none)>2007-12-07 15:39:41 +0100
committerunknown <thek@adventure.(none)>2007-12-07 15:39:41 +0100
commit5826a5c490df8540fbc2b5bed6efad38723619c3 (patch)
treee38a712e17087a0838ba2993e6823e49c0e032e5 /sql/sql_parse.cc
parentb8a19c228ce93ff5e57d7d122d8d5a74236670f6 (diff)
downloadmariadb-git-5826a5c490df8540fbc2b5bed6efad38723619c3.tar.gz
Bug #27440 read_only allows create and drop database
When read_only option was enabled, a user without SUPER privilege could perform CREATE DATABASE and DROP DATABASE operations. This patch adds a check to make sure this isn't possible. It also attempts to simplify the logic used to determine if relevant tables are updated, making it more human readable. mysql-test/r/read_only.result: Updated result file mysql-test/t/read_only.test: A test case is added which shows that it is not possible to drop or create a database in read-only mode despite having the GRANT permissions to do so, SUPER user excepted. sql/sql_parse.cc: - Simplified complex predicate by grouping it in a read friendly way. - Added predicate to fail on database updates while running in read-only mode.
Diffstat (limited to 'sql/sql_parse.cc')
-rw-r--r--sql/sql_parse.cc77
1 files changed, 69 insertions, 8 deletions
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index e587a9f3561..a5ba486920d 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1597,6 +1597,74 @@ static bool do_command(THD *thd)
#endif /* EMBEDDED_LIBRARY */
+/**
+ @brief Determine if an attempt to update a non-temporary table while the
+ read-only option was enabled has been made.
+
+ This is a helper function to mysql_execute_command.
+
+ @note SQLCOM_MULTI_UPDATE is an exception and delt with elsewhere.
+
+ @see mysql_execute_command
+ @returns Status code
+ @retval TRUE The statement should be denied.
+ @retval FALSE The statement isn't updating any relevant tables.
+*/
+
+static my_bool deny_updates_if_read_only_option(THD *thd,
+ TABLE_LIST *all_tables)
+{
+ DBUG_ENTER("deny_updates_if_read_only_option");
+
+ if (!opt_readonly)
+ DBUG_RETURN(FALSE);
+
+ LEX *lex= thd->lex;
+
+ const my_bool user_is_super=
+ ((ulong)(thd->security_ctx->master_access & SUPER_ACL) ==
+ (ulong)SUPER_ACL);
+
+ if (user_is_super)
+ DBUG_RETURN(FALSE);
+
+ if (!uc_update_queries[lex->sql_command])
+ DBUG_RETURN(FALSE);
+
+ /* Multi update is an exception and is dealt with later. */
+ if (lex->sql_command == SQLCOM_UPDATE_MULTI)
+ DBUG_RETURN(FALSE);
+
+ const my_bool create_temp_tables=
+ (lex->sql_command == SQLCOM_CREATE_TABLE) &&
+ (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE);
+
+ const my_bool drop_temp_tables=
+ (lex->sql_command == SQLCOM_DROP_TABLE) &&
+ lex->drop_temporary;
+
+ const my_bool update_real_tables=
+ some_non_temp_table_to_be_updated(thd, all_tables) &&
+ !(create_temp_tables || drop_temp_tables);
+
+
+ const my_bool create_or_drop_databases=
+ (lex->sql_command == SQLCOM_CREATE_DB) ||
+ (lex->sql_command == SQLCOM_DROP_DB);
+
+ if (update_real_tables || create_or_drop_databases)
+ {
+ /*
+ An attempt was made to modify one or more non-temporary tables.
+ */
+ DBUG_RETURN(TRUE);
+ }
+
+
+ /* Assuming that only temporary tables are modified. */
+ DBUG_RETURN(FALSE);
+}
+
/*
Perform one connection-level (COM_XXXX) command.
@@ -2590,14 +2658,7 @@ mysql_execute_command(THD *thd)
When option readonly is set deny operations which change non-temporary
tables. Except for the replication thread and the 'super' users.
*/
- if (opt_readonly &&
- !(thd->security_ctx->master_access & SUPER_ACL) &&
- uc_update_queries[lex->sql_command] &&
- !((lex->sql_command == SQLCOM_CREATE_TABLE) &&
- (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)) &&
- !((lex->sql_command == SQLCOM_DROP_TABLE) && lex->drop_temporary) &&
- ((lex->sql_command != SQLCOM_UPDATE_MULTI) &&
- some_non_temp_table_to_be_updated(thd, all_tables)))
+ if (deny_updates_if_read_only_option(thd, all_tables))
{
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
DBUG_RETURN(-1);