diff --git a/mysql-test/main/grant2.result b/mysql-test/main/grant2.result index d238d26100684..626c69afff080 100644 --- a/mysql-test/main/grant2.result +++ b/mysql-test/main/grant2.result @@ -162,7 +162,7 @@ connection con10; set sql_log_off = 1; ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation set sql_log_bin = 0; -ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation +ERROR 42000: Access denied; you need (at least one of) the SUPER, BINLOG ADMIN privilege(s) for this operation disconnect con10; connection default; delete from mysql.user where user like 'mysqltest\_1'; diff --git a/mysql-test/suite/binlog/r/binlog_grant.result b/mysql-test/suite/binlog/r/binlog_grant.result index c3de2c0d9819a..f715a9a719e78 100644 --- a/mysql-test/suite/binlog/r/binlog_grant.result +++ b/mysql-test/suite/binlog/r/binlog_grant.result @@ -14,7 +14,7 @@ set session sql_log_bin = 1; connection plain; [plain] set session sql_log_bin = 1; -ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation +ERROR 42000: Access denied; you need (at least one of) the SUPER, BINLOG ADMIN privilege(s) for this operation **** Variable BINLOG_FORMAT **** connection root; [root] @@ -23,9 +23,9 @@ set session binlog_format = row; connection plain; [plain] set global binlog_format = row; -ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation +ERROR 42000: Access denied; you need (at least one of) the SUPER, BINLOG ADMIN privilege(s) for this operation set session binlog_format = row; -ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation +ERROR 42000: Access denied; you need (at least one of) the SUPER, BINLOG ADMIN privilege(s) for this operation **** Clean up **** disconnect plain; disconnect root; diff --git a/mysql-test/suite/rpl/r/rpl_temporary.result b/mysql-test/suite/rpl/r/rpl_temporary.result index e2999cdd2255a..1d29ff3e8f196 100644 --- a/mysql-test/suite/rpl/r/rpl_temporary.result +++ b/mysql-test/suite/rpl/r/rpl_temporary.result @@ -45,7 +45,7 @@ SELECT @@session.sql_select_limit = @save_select_limit; @@session.sql_select_limit = @save_select_limit 1 SET @@session.sql_select_limit=10, @@session.sql_log_bin=0; -ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation +ERROR 42000: Access denied; you need (at least one of) the SUPER, BINLOG ADMIN privilege(s) for this operation SELECT @@session.sql_select_limit = @save_select_limit; @@session.sql_select_limit = @save_select_limit 1 diff --git a/mysql-test/suite/sys_vars/r/binlog_direct_non_transactional_updates_grant.result b/mysql-test/suite/sys_vars/r/binlog_direct_non_transactional_updates_grant.result new file mode 100644 index 0000000000000..e70dbbf408f02 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/binlog_direct_non_transactional_updates_grant.result @@ -0,0 +1,44 @@ +SET @global= @@global.binlog_direct_non_transactional_updates; +SET @session= @@global.binlog_direct_non_transactional_updates; +# +# +# +# Test that "SET binlog_direct_non_transactional_updates" is not allowed without BINLOG ADMIN or SUPER +CREATE USER user1@localhost; +GRANT ALL PRIVILEGES ON *.* TO user1@localhost; +REVOKE BINLOG ADMIN, SUPER ON *.* FROM user1@localhost; +connect user1,localhost,user1,,; +connection user1; +SET binlog_direct_non_transactional_updates=0; +ERROR 42000: Access denied; you need (at least one of) the SUPER, BINLOG ADMIN privilege(s) for this operation +SET GLOBAL binlog_direct_non_transactional_updates=0; +ERROR 42000: Access denied; you need (at least one of) the SUPER, BINLOG ADMIN privilege(s) for this operation +SET SESSION binlog_direct_non_transactional_updates=0; +ERROR 42000: Access denied; you need (at least one of) the SUPER, BINLOG ADMIN privilege(s) for this operation +disconnect user1; +connection default; +DROP USER user1@localhost; +# Test that "SET binlog_direct_non_transactional_updates" is allowed with BINLOG ADMIN +CREATE USER user1@localhost; +GRANT BINLOG ADMIN ON *.* TO user1@localhost; +connect user1,localhost,user1,,; +connection user1; +SET binlog_direct_non_transactional_updates=0; +SET GLOBAL binlog_direct_non_transactional_updates=0; +SET SESSION binlog_direct_non_transactional_updates=0; +disconnect user1; +connection default; +DROP USER user1@localhost; +# Test that "SET binlog_direct_non_transactional_updates" is allowed with SUPER +CREATE USER user1@localhost; +GRANT SUPER ON *.* TO user1@localhost; +connect user1,localhost,user1,,; +connection user1; +SET binlog_direct_non_transactional_updates=0; +SET GLOBAL binlog_direct_non_transactional_updates=0; +SET SESSION binlog_direct_non_transactional_updates=0; +disconnect user1; +connection default; +DROP USER user1@localhost; +SET GLOBAL binlog_direct_non_transactional_updates=@global; +SET SESSION binlog_direct_non_transactional_updates=@session; diff --git a/mysql-test/suite/sys_vars/r/binlog_format_grant.result b/mysql-test/suite/sys_vars/r/binlog_format_grant.result new file mode 100644 index 0000000000000..b3cd77a6bd488 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/binlog_format_grant.result @@ -0,0 +1,40 @@ +# +# +# +# Test that "SET binlog_format" is not allowed without BINLOG ADMIN or SUPER +CREATE USER user1@localhost; +GRANT ALL PRIVILEGES ON *.* TO user1@localhost; +REVOKE BINLOG ADMIN, SUPER ON *.* FROM user1@localhost; +connect user1,localhost,user1,,; +connection user1; +SET binlog_format=mixed; +ERROR 42000: Access denied; you need (at least one of) the SUPER, BINLOG ADMIN privilege(s) for this operation +SET GLOBAL binlog_format=mixed; +ERROR 42000: Access denied; you need (at least one of) the SUPER, BINLOG ADMIN privilege(s) for this operation +SET SESSION binlog_format=mixed; +ERROR 42000: Access denied; you need (at least one of) the SUPER, BINLOG ADMIN privilege(s) for this operation +disconnect user1; +connection default; +DROP USER user1@localhost; +# Test that "SET binlog_format" is allowed with BINLOG ADMIN +CREATE USER user1@localhost; +GRANT BINLOG ADMIN ON *.* TO user1@localhost; +connect user1,localhost,user1,,; +connection user1; +SET binlog_format=mixed; +SET GLOBAL binlog_format=mixed; +SET SESSION binlog_format=mixed; +disconnect user1; +connection default; +DROP USER user1@localhost; +# Test that "SET binlog_format" is allowed with SUPER +CREATE USER user1@localhost; +GRANT SUPER ON *.* TO user1@localhost; +connect user1,localhost,user1,,; +connection user1; +SET binlog_format=mixed; +SET GLOBAL binlog_format=mixed; +SET SESSION binlog_format=mixed; +disconnect user1; +connection default; +DROP USER user1@localhost; diff --git a/mysql-test/suite/sys_vars/r/sql_log_bin_grant.result b/mysql-test/suite/sys_vars/r/sql_log_bin_grant.result new file mode 100644 index 0000000000000..574c53e1f0a1a --- /dev/null +++ b/mysql-test/suite/sys_vars/r/sql_log_bin_grant.result @@ -0,0 +1,42 @@ +# +# +# +# Test that "SET sql_log_bin" is not allowed without BINLOG ADMIN or SUPER +CREATE USER user1@localhost; +GRANT ALL PRIVILEGES ON *.* TO user1@localhost; +REVOKE BINLOG ADMIN, SUPER ON *.* FROM user1@localhost; +connect user1,localhost,user1,,; +connection user1; +SET sql_log_bin=1; +ERROR 42000: Access denied; you need (at least one of) the SUPER, BINLOG ADMIN privilege(s) for this operation +SET GLOBAL sql_log_bin=1; +ERROR 42000: Access denied; you need (at least one of) the SUPER, BINLOG ADMIN privilege(s) for this operation +SET SESSION sql_log_bin=1; +ERROR 42000: Access denied; you need (at least one of) the SUPER, BINLOG ADMIN privilege(s) for this operation +disconnect user1; +connection default; +DROP USER user1@localhost; +# Test that "SET sql_log_bin" is allowed with BINLOG ADMIN +CREATE USER user1@localhost; +GRANT BINLOG ADMIN ON *.* TO user1@localhost; +connect user1,localhost,user1,,; +connection user1; +SET sql_log_bin=1; +SET GLOBAL sql_log_bin=1; +ERROR HY000: Variable 'sql_log_bin' is a SESSION variable +SET SESSION sql_log_bin=1; +disconnect user1; +connection default; +DROP USER user1@localhost; +# Test that "SET sql_log_bin" is allowed with SUPER +CREATE USER user1@localhost; +GRANT SUPER ON *.* TO user1@localhost; +connect user1,localhost,user1,,; +connection user1; +SET sql_log_bin=1; +SET GLOBAL sql_log_bin=1; +ERROR HY000: Variable 'sql_log_bin' is a SESSION variable +SET SESSION sql_log_bin=1; +disconnect user1; +connection default; +DROP USER user1@localhost; diff --git a/mysql-test/suite/sys_vars/t/binlog_direct_non_transactional_updates_grant.test b/mysql-test/suite/sys_vars/t/binlog_direct_non_transactional_updates_grant.test new file mode 100644 index 0000000000000..7de1a1193089d --- /dev/null +++ b/mysql-test/suite/sys_vars/t/binlog_direct_non_transactional_updates_grant.test @@ -0,0 +1,56 @@ +source include/have_log_bin.inc; + +SET @global= @@global.binlog_direct_non_transactional_updates; +SET @session= @@global.binlog_direct_non_transactional_updates; + + +--echo # +--echo # +--echo # + +--echo # Test that "SET binlog_direct_non_transactional_updates" is not allowed without BINLOG ADMIN or SUPER + +CREATE USER user1@localhost; +GRANT ALL PRIVILEGES ON *.* TO user1@localhost; +REVOKE BINLOG ADMIN, SUPER ON *.* FROM user1@localhost; +--connect(user1,localhost,user1,,) +--connection user1 +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +SET binlog_direct_non_transactional_updates=0; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +SET GLOBAL binlog_direct_non_transactional_updates=0; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +SET SESSION binlog_direct_non_transactional_updates=0; +--disconnect user1 +--connection default +DROP USER user1@localhost; + +--echo # Test that "SET binlog_direct_non_transactional_updates" is allowed with BINLOG ADMIN + +CREATE USER user1@localhost; +GRANT BINLOG ADMIN ON *.* TO user1@localhost; +--connect(user1,localhost,user1,,) +--connection user1 +SET binlog_direct_non_transactional_updates=0; +SET GLOBAL binlog_direct_non_transactional_updates=0; +SET SESSION binlog_direct_non_transactional_updates=0; +--disconnect user1 +--connection default +DROP USER user1@localhost; + +--echo # Test that "SET binlog_direct_non_transactional_updates" is allowed with SUPER + +CREATE USER user1@localhost; +GRANT SUPER ON *.* TO user1@localhost; +--connect(user1,localhost,user1,,) +--connection user1 +SET binlog_direct_non_transactional_updates=0; +SET GLOBAL binlog_direct_non_transactional_updates=0; +SET SESSION binlog_direct_non_transactional_updates=0; +--disconnect user1 +--connection default +DROP USER user1@localhost; + + +SET GLOBAL binlog_direct_non_transactional_updates=@global; +SET SESSION binlog_direct_non_transactional_updates=@session; diff --git a/mysql-test/suite/sys_vars/t/binlog_format_grant.test b/mysql-test/suite/sys_vars/t/binlog_format_grant.test new file mode 100644 index 0000000000000..6f89c75a79edb --- /dev/null +++ b/mysql-test/suite/sys_vars/t/binlog_format_grant.test @@ -0,0 +1,49 @@ +source include/have_log_bin.inc; + + +--echo # +--echo # +--echo # + +--echo # Test that "SET binlog_format" is not allowed without BINLOG ADMIN or SUPER + +CREATE USER user1@localhost; +GRANT ALL PRIVILEGES ON *.* TO user1@localhost; +REVOKE BINLOG ADMIN, SUPER ON *.* FROM user1@localhost; +--connect(user1,localhost,user1,,) +--connection user1 +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +SET binlog_format=mixed; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +SET GLOBAL binlog_format=mixed; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +SET SESSION binlog_format=mixed; +--disconnect user1 +--connection default +DROP USER user1@localhost; + +--echo # Test that "SET binlog_format" is allowed with BINLOG ADMIN + +CREATE USER user1@localhost; +GRANT BINLOG ADMIN ON *.* TO user1@localhost; +--connect(user1,localhost,user1,,) +--connection user1 +SET binlog_format=mixed; +SET GLOBAL binlog_format=mixed; +SET SESSION binlog_format=mixed; +--disconnect user1 +--connection default +DROP USER user1@localhost; + +--echo # Test that "SET binlog_format" is allowed with SUPER + +CREATE USER user1@localhost; +GRANT SUPER ON *.* TO user1@localhost; +--connect(user1,localhost,user1,,) +--connection user1 +SET binlog_format=mixed; +SET GLOBAL binlog_format=mixed; +SET SESSION binlog_format=mixed; +--disconnect user1 +--connection default +DROP USER user1@localhost; diff --git a/mysql-test/suite/sys_vars/t/sql_log_bin_grant.test b/mysql-test/suite/sys_vars/t/sql_log_bin_grant.test new file mode 100644 index 0000000000000..d7ffc2b613b58 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/sql_log_bin_grant.test @@ -0,0 +1,51 @@ +source include/have_log_bin.inc; + + +--echo # +--echo # +--echo # + +--echo # Test that "SET sql_log_bin" is not allowed without BINLOG ADMIN or SUPER + +CREATE USER user1@localhost; +GRANT ALL PRIVILEGES ON *.* TO user1@localhost; +REVOKE BINLOG ADMIN, SUPER ON *.* FROM user1@localhost; +--connect(user1,localhost,user1,,) +--connection user1 +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +SET sql_log_bin=1; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +SET GLOBAL sql_log_bin=1; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +SET SESSION sql_log_bin=1; +--disconnect user1 +--connection default +DROP USER user1@localhost; + +--echo # Test that "SET sql_log_bin" is allowed with BINLOG ADMIN + +CREATE USER user1@localhost; +GRANT BINLOG ADMIN ON *.* TO user1@localhost; +--connect(user1,localhost,user1,,) +--connection user1 +SET sql_log_bin=1; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SET GLOBAL sql_log_bin=1; +SET SESSION sql_log_bin=1; +--disconnect user1 +--connection default +DROP USER user1@localhost; + +--echo # Test that "SET sql_log_bin" is allowed with SUPER + +CREATE USER user1@localhost; +GRANT SUPER ON *.* TO user1@localhost; +--connect(user1,localhost,user1,,) +--connection user1 +SET sql_log_bin=1; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SET GLOBAL sql_log_bin=1; +SET SESSION sql_log_bin=1; +--disconnect user1 +--connection default +DROP USER user1@localhost; diff --git a/sql/privilege.h b/sql/privilege.h index c5c13186743fa..13289d3803170 100644 --- a/sql/privilege.h +++ b/sql/privilege.h @@ -315,6 +315,15 @@ constexpr privilege_t PRIV_DEBUG= SUPER_ACL; constexpr privilege_t PRIV_SET_GLOBAL_SYSTEM_VARIABLE= SUPER_ACL; constexpr privilege_t PRIV_SET_RESTRICTED_SESSION_SYSTEM_VARIABLE= SUPER_ACL; +/* The following variables respected only SUPER_ACL prior to 10.5.2 */ +constexpr privilege_t PRIV_SET_SYSTEM_VAR_BINLOG_FORMAT= + SUPER_ACL | BINLOG_ADMIN_ACL; +constexpr privilege_t PRIV_SET_SYSTEM_VAR_BINLOG_DIRECT_NON_TRANSACTIONAL_UPDATES= + SUPER_ACL | BINLOG_ADMIN_ACL; +constexpr privilege_t PRIV_SET_SYSTEM_VAR_SQL_LOG_BIN= + SUPER_ACL | BINLOG_ADMIN_ACL; + + /* Privileges related to --read-only */ constexpr privilege_t PRIV_IGNORE_READ_ONLY= READ_ONLY_ADMIN_ACL | SUPER_ACL; diff --git a/sql/set_var.cc b/sql/set_var.cc index b2cc41b2d1574..0ace4658be70b 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -756,6 +756,11 @@ int sql_set_variables(THD *thd, List *var_list, bool free) Functions to handle SET mysql_internal_variable=const_expr *****************************************************************************/ +bool sys_var::on_check_access_global(THD *thd) const +{ + return check_global_access(thd, PRIV_SET_GLOBAL_SYSTEM_VARIABLE); +} + /** Verify that the supplied value is correct. @@ -780,8 +785,7 @@ int set_var::check(THD *thd) my_error(err, MYF(0), var->name.str); return -1; } - if (type == OPT_GLOBAL && - check_global_access(thd, PRIV_SET_GLOBAL_SYSTEM_VARIABLE)) + if (type == OPT_GLOBAL && var->on_check_access_global(thd)) return 1; /* value is a NULL pointer if we are using SET ... = DEFAULT */ if (!value) @@ -794,6 +798,16 @@ int set_var::check(THD *thd) my_error(ER_WRONG_TYPE_FOR_VAR, MYF(0), var->name.str); return -1; } + switch (type) { + case SHOW_OPT_DEFAULT: + case SHOW_OPT_SESSION: + DBUG_ASSERT(var->scope() != sys_var::GLOBAL); + if (var->on_check_access_session(thd)) + return -1; + break; + case SHOW_OPT_GLOBAL: // Checked earlier + break; + } return var->check(thd, this) ? -1 : 0; } diff --git a/sql/set_var.h b/sql/set_var.h index 1573965885fbf..41a0010acf231 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -214,6 +214,12 @@ class sys_var: protected Value_source // for double_from_string_with_check virtual uchar *default_value_ptr(THD *thd) { return (uchar*)&option.def_value; } + virtual bool on_check_access_global(THD *thd) const; + virtual bool on_check_access_session(THD *thd) const + { + return false; + } + private: virtual bool do_check(THD *thd, set_var *var) = 0; /** diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 7eeea54352b7f..d6374813c2750 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -601,9 +601,6 @@ static Sys_var_bit Sys_core_file("core_file", "write a core-file on crashes", static bool binlog_format_check(sys_var *self, THD *thd, set_var *var) { - if (check_has_super(self, thd, var)) - return true; - /* MariaDB Galera does not support STATEMENT or MIXED binlog format currently. */ @@ -674,7 +671,10 @@ static bool fix_binlog_format_after_update(sys_var *self, THD *thd, return false; } -static Sys_var_enum Sys_binlog_format( +static Sys_var_on_access +Sys_binlog_format( "binlog_format", "What form of binary logging the master will " "use: either ROW for row-based binary logging, STATEMENT " "for statement-based binary logging, or MIXED. MIXED is statement-" @@ -689,9 +689,6 @@ static Sys_var_enum Sys_binlog_format( static bool binlog_direct_check(sys_var *self, THD *thd, set_var *var) { - if (check_has_super(self, thd, var)) - return true; - if (var->type == OPT_GLOBAL) return false; @@ -703,7 +700,10 @@ static bool binlog_direct_check(sys_var *self, THD *thd, set_var *var) return false; } -static Sys_var_mybool Sys_binlog_direct( +static Sys_var_on_access +Sys_binlog_direct( "binlog_direct_non_transactional_updates", "Causes updates to non-transactional engines using statement format to " "be written directly to binary log. Before using this option make sure " @@ -4297,9 +4297,6 @@ static bool check_session_only_variable(sys_var *self, THD *,set_var *var) */ static bool check_sql_log_bin(sys_var *self, THD *thd, set_var *var) { - if (check_has_super(self, thd, var)) - return true; - if (check_session_only_variable(self, thd, var)) return true; @@ -4311,7 +4308,10 @@ static bool check_sql_log_bin(sys_var *self, THD *thd, set_var *var) return false; } -static Sys_var_mybool Sys_log_binlog( +static Sys_var_on_access +Sys_sql_log_bin( "sql_log_bin", "If set to 0 (1 is the default), no logging to the binary " "log is done for the client. Only clients with the SUPER privilege can " "update this variable. Can have unintended consequences if set globally, " diff --git a/sql/sys_vars.ic b/sql/sys_vars.ic index 4d4af3ed0aa8b..363a61b3f8012 100644 --- a/sql/sys_vars.ic +++ b/sql/sys_vars.ic @@ -31,6 +31,7 @@ #include "tztime.h" // my_tz_find, my_tz_SYSTEM, struct Time_zone #include "rpl_mi.h" // For Multi-Source Replication #include "debug_sync.h" +#include "sql_acl.h" // check_global_access() /* a set of mostly trivial (as in f(X)=X) defines below to make system variable @@ -101,6 +102,22 @@ static const char *bool_values[3]= {"OFF", "ON", 0}; TYPELIB bool_typelib={ array_elements(bool_values)-1, "", bool_values, 0 }; + +template +class Sys_var_on_access: public BASE +{ + using BASE::BASE; + bool on_check_access_global(THD *thd) const override + { + return check_global_access(thd, GLOBAL_PRIV); + } + bool on_check_access_session(THD *thd) const override + { + return check_global_access(thd, SESSION_PRIV); + } +}; + + /** A small wrapper class to pass getopt arguments as a pair to the Sys_var_* constructors. It improves type safety and helps