Allow one to block an account by using GRANT max_user_connections = -1
One can set @@global.max_user_connections to -1 to block anyone, except SUPER user, to login. If max_user_connection is 0, one can't change it without a restart (needed to get user connections counting to work correctly) mysql-test/r/system_mysql_db.result: Changed max_user_connections to handle negative numbers. mysql-test/r/user_limits-2.result: New test case that one can't change max_user_connection if it was 0 mysql-test/r/user_limits.result: Fixed wrong error messages. mysql-test/r/variables.result: Store / restore max_user_connections (needed as there is now a --master.opt file that changes it) mysql-test/t/subselect_mat_cost-master.opt: Enable slow query log (as this test found some errors in slow query logging) mysql-test/t/user_limits-2.test: New test case that one can't change max_user_connection if it was 0 mysql-test/t/user_limits-master.opt: Set max_user_connections (as one can't change it if it was 0) mysql-test/t/user_limits.test: Test max_user_connections -1 mysql-test/t/variables-master.opt: Set max_user_connections (as one can't change it if it was 0) mysql-test/t/variables.test: Set/restore max_user_connections scripts/Makefile.am: Add a text message to mysql_fix_privilege_tables.sql that it's automaticly generated scripts/mysql_system_tables.sql: Change max_user_connections to signed scripts/mysql_system_tables_fix.sql: Change max_user_connections to signed sql/item_func.cc: Change SHOW_INT to be signed. (Needed for max_user_connections and it's probably a bug that it was not originally signed) sql/log.cc: Remove some code that was not needed (All these variables are reset at start of query) sql/mysql_priv.h: Made max_user_connections signed. Added max_user_connections_checking sql/mysqld.cc: Added max_user_connections_checking so that we know if max_user_connections was 0 at startup (Which means that we will not do connection counting for accounts that don't have user resource limits) Set thd->start_utime at same time as thr_create_utime. (Before start_utime could be < thr_create_utime which lead to wrong query counting) sql/set_var.cc: Don't allow one to change 'max_user_connections' if it was 0 at startup. sql/sql_acl.cc: Change user_connection counting to be negative. sql/sql_connect.cc: If max_user_connections is < 0 then only SUPER user can login. Fixed wrong variable names for error messages. Fixed wrong initial value for questions. Set thd->start_utime and thd->thr_create_utime at startup. Needed to get time_out_user_resource_limits() to work. sql/sql_show.cc: SHOW_INT is now negative sql/sql_yacc.yy: Support negative values for MAX_USER_CONNECTIONS sql/structs.h: Make user connect counting work with signed numbers.
This commit is contained in:
parent
f0c6ce9ade
commit
7800d93bc3
@ -117,7 +117,7 @@ user CREATE TABLE `user` (
|
||||
`max_questions` int(11) unsigned NOT NULL DEFAULT '0',
|
||||
`max_updates` int(11) unsigned NOT NULL DEFAULT '0',
|
||||
`max_connections` int(11) unsigned NOT NULL DEFAULT '0',
|
||||
`max_user_connections` int(11) unsigned NOT NULL DEFAULT '0',
|
||||
`max_user_connections` int(11) NOT NULL DEFAULT '0',
|
||||
`plugin` char(60) CHARACTER SET latin1 NOT NULL DEFAULT '',
|
||||
`auth_string` text COLLATE utf8_bin NOT NULL,
|
||||
PRIMARY KEY (`Host`,`User`)
|
||||
|
2
mysql-test/r/user_limits-2.result
Normal file
2
mysql-test/r/user_limits-2.result
Normal file
@ -0,0 +1,2 @@
|
||||
set global max_user_connections=100;
|
||||
ERROR HY000: The MySQL server is running with the --max-user-connections=0 option so it cannot execute this statement
|
@ -1,3 +1,4 @@
|
||||
set @my_max_user_connections= @@global.max_user_connections;
|
||||
drop table if exists t1;
|
||||
create table t1 (i int);
|
||||
delete from mysql.user where user like 'mysqltest\_%';
|
||||
@ -12,9 +13,9 @@ i
|
||||
select * from t1;
|
||||
i
|
||||
select * from t1;
|
||||
ERROR 42000: User 'mysqltest_1' has exceeded the 'max_questions' resource (current value: 2)
|
||||
ERROR 42000: User 'mysqltest_1' has exceeded the 'max_queries_per_hour' resource (current value: 2)
|
||||
select * from t1;
|
||||
ERROR 42000: User 'mysqltest_1' has exceeded the 'max_questions' resource (current value: 2)
|
||||
ERROR 42000: User 'mysqltest_1' has exceeded the 'max_queries_per_hour' resource (current value: 2)
|
||||
drop user mysqltest_1@localhost;
|
||||
grant usage on *.* to mysqltest_1@localhost with max_updates_per_hour 2;
|
||||
flush user_resources;
|
||||
@ -27,11 +28,11 @@ i
|
||||
delete from t1;
|
||||
delete from t1;
|
||||
delete from t1;
|
||||
ERROR 42000: User 'mysqltest_1' has exceeded the 'max_updates' resource (current value: 2)
|
||||
ERROR 42000: User 'mysqltest_1' has exceeded the 'max_updates_per_hour' resource (current value: 2)
|
||||
select * from t1;
|
||||
i
|
||||
delete from t1;
|
||||
ERROR 42000: User 'mysqltest_1' has exceeded the 'max_updates' resource (current value: 2)
|
||||
ERROR 42000: User 'mysqltest_1' has exceeded the 'max_updates_per_hour' resource (current value: 2)
|
||||
select * from t1;
|
||||
i
|
||||
drop user mysqltest_1@localhost;
|
||||
@ -65,10 +66,20 @@ select * from t1;
|
||||
i
|
||||
connect(localhost,mysqltest_1,,test,MYSQL_PORT,MYSQL_SOCK);
|
||||
ERROR 42000: User 'mysqltest_1' has exceeded the 'max_user_connections' resource (current value: 3)
|
||||
grant usage on *.* to mysqltest_1@localhost with max_user_connections -1;
|
||||
show grants for mysqltest_1@localhost;
|
||||
Grants for mysqltest_1@localhost
|
||||
GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' WITH MAX_USER_CONNECTIONS -1
|
||||
flush user_resources;
|
||||
show grants for mysqltest_1@localhost;
|
||||
Grants for mysqltest_1@localhost
|
||||
GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' WITH MAX_USER_CONNECTIONS -1
|
||||
connect(localhost,mysqltest_1,,test,MYSQL_PORT,MYSQL_SOCK);
|
||||
ERROR 42000: User 'mysqltest_1' has exceeded the 'max_user_connections' resource (current value: -1)
|
||||
drop user mysqltest_1@localhost;
|
||||
select @@session.max_user_connections, @@global.max_user_connections;
|
||||
@@session.max_user_connections @@global.max_user_connections
|
||||
0 0
|
||||
1000 1000
|
||||
set session max_user_connections= 2;
|
||||
ERROR HY000: Variable 'max_user_connections' is a GLOBAL variable and should be set with SET GLOBAL
|
||||
set global max_user_connections= 2;
|
||||
@ -92,5 +103,21 @@ select @@session.max_user_connections, @@global.max_user_connections;
|
||||
connect(localhost,mysqltest_1,,test,MYSQL_PORT,MYSQL_SOCK);
|
||||
ERROR 42000: User 'mysqltest_1' has exceeded the 'max_user_connections' resource (current value: 3)
|
||||
set global max_user_connections= 0;
|
||||
grant usage on *.* to mysqltest_1@localhost with max_user_connections 0;
|
||||
set global max_user_connections=-1;
|
||||
show variables like "max_user_user_connections";
|
||||
Variable_name Value
|
||||
select @@max_user_connections;
|
||||
@@max_user_connections
|
||||
-1
|
||||
select @@global.max_user_connections;
|
||||
@@global.max_user_connections
|
||||
-1
|
||||
connect(localhost,mysqltest_1,,test,MYSQL_PORT,MYSQL_SOCK);
|
||||
ERROR 42000: User mysqltest_1 already has more than 'max_user_connections' active connections
|
||||
set global max_user_connections=1;
|
||||
connect(localhost,mysqltest_1,,test,MYSQL_PORT,MYSQL_SOCK);
|
||||
ERROR 42000: User mysqltest_1 already has more than 'max_user_connections' active connections
|
||||
drop user mysqltest_1@localhost;
|
||||
drop table t1;
|
||||
set global max_user_connections= @my_max_user_connections;
|
||||
|
@ -14,6 +14,7 @@ set @my_max_delayed_threads =@@global.max_delayed_threads;
|
||||
set @my_max_heap_table_size =@@global.max_heap_table_size;
|
||||
set @my_max_insert_delayed_threads=@@global.max_insert_delayed_threads;
|
||||
set @my_max_join_size =@@global.max_join_size;
|
||||
set @my_max_user_connections =@@global.max_user_connections;
|
||||
set @my_myisam_data_pointer_size =@@global.myisam_data_pointer_size;
|
||||
set @my_myisam_max_sort_file_size =@@global.myisam_max_sort_file_size;
|
||||
set @my_net_buffer_length =@@global.net_buffer_length;
|
||||
@ -1049,7 +1050,7 @@ set global max_delayed_threads =@my_max_delayed_threads;
|
||||
set global max_heap_table_size =@my_max_heap_table_size;
|
||||
set global max_insert_delayed_threads=@my_max_insert_delayed_threads;
|
||||
set global max_join_size =@my_max_join_size;
|
||||
set global max_user_connections =default;
|
||||
set global max_user_connections =@my_max_user_connections;
|
||||
set global max_write_lock_count =default;
|
||||
set global myisam_data_pointer_size =@my_myisam_data_pointer_size;
|
||||
set global myisam_max_sort_file_size =@my_myisam_max_sort_file_size;
|
||||
|
1
mysql-test/t/subselect_mat_cost-master.opt
Normal file
1
mysql-test/t/subselect_mat_cost-master.opt
Normal file
@ -0,0 +1 @@
|
||||
--log-output=TABLE,FILE --log --log-slow-queries --slow-query-log=1
|
11
mysql-test/t/user_limits-2.test
Normal file
11
mysql-test/t/user_limits-2.test
Normal file
@ -0,0 +1,11 @@
|
||||
#
|
||||
# Test behavior of various per-account limits (aka quotas)
|
||||
#
|
||||
--source include/not_embedded.inc
|
||||
|
||||
#
|
||||
# We will get an error as it was set to 0 at startup
|
||||
#
|
||||
--error ER_OPTION_PREVENTS_STATEMENT
|
||||
set global max_user_connections=100;
|
||||
|
1
mysql-test/t/user_limits-master.opt
Normal file
1
mysql-test/t/user_limits-master.opt
Normal file
@ -0,0 +1 @@
|
||||
--max-user-connections=1000
|
@ -8,6 +8,8 @@
|
||||
# Save the initial number of concurrent sessions
|
||||
--source include/count_sessions.inc
|
||||
|
||||
set @my_max_user_connections= @@global.max_user_connections;
|
||||
|
||||
# Prepare play-ground
|
||||
--disable_warnings
|
||||
drop table if exists t1;
|
||||
@ -120,8 +122,18 @@ select * from t1;
|
||||
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
|
||||
--error ER_USER_LIMIT_REACHED
|
||||
connect (muc5, localhost, mysqltest_1,,);
|
||||
# Clean up
|
||||
|
||||
connection default;
|
||||
# Test with negative max_user_connections
|
||||
grant usage on *.* to mysqltest_1@localhost with max_user_connections -1;
|
||||
show grants for mysqltest_1@localhost;
|
||||
flush user_resources;
|
||||
show grants for mysqltest_1@localhost;
|
||||
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
|
||||
--error ER_USER_LIMIT_REACHED
|
||||
connect (muc5, localhost, mysqltest_1,,);
|
||||
|
||||
# Clean up
|
||||
disconnect muc2;
|
||||
disconnect muc3;
|
||||
disconnect muc4;
|
||||
@ -165,12 +177,37 @@ disconnect muca1;
|
||||
disconnect muca2;
|
||||
disconnect muca3;
|
||||
set global max_user_connections= 0;
|
||||
drop user mysqltest_1@localhost;
|
||||
--enable_ps_protocol
|
||||
|
||||
#
|
||||
# Test setting negative values of max_user_connections
|
||||
#
|
||||
grant usage on *.* to mysqltest_1@localhost with max_user_connections 0;
|
||||
set global max_user_connections=-1;
|
||||
show variables like "max_user_user_connections";
|
||||
select @@max_user_connections;
|
||||
select @@global.max_user_connections;
|
||||
# Check that we can't connect anymore except as root
|
||||
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
|
||||
--error ER_TOO_MANY_USER_CONNECTIONS
|
||||
connect (muca2, localhost, mysqltest_1,,);
|
||||
connect (muca2, localhost, root,,);
|
||||
disconnect muca2;
|
||||
connection default;
|
||||
set global max_user_connections=1;
|
||||
# Check that we can connect one time, not two
|
||||
connect (muca2, localhost, mysqltest_1,,);
|
||||
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
|
||||
--error ER_TOO_MANY_USER_CONNECTIONS
|
||||
connect (muca3, localhost, mysqltest_1,,);
|
||||
disconnect muca2;
|
||||
connection default;
|
||||
drop user mysqltest_1@localhost;
|
||||
|
||||
# Final cleanup
|
||||
drop table t1;
|
||||
|
||||
# Wait till all disconnects are completed
|
||||
--source include/wait_until_count_sessions.inc
|
||||
|
||||
set global max_user_connections= @my_max_user_connections;
|
||||
|
1
mysql-test/t/variables-master.opt
Normal file
1
mysql-test/t/variables-master.opt
Normal file
@ -0,0 +1 @@
|
||||
--max-user-connections=1
|
@ -23,6 +23,7 @@ set @my_max_delayed_threads =@@global.max_delayed_threads;
|
||||
set @my_max_heap_table_size =@@global.max_heap_table_size;
|
||||
set @my_max_insert_delayed_threads=@@global.max_insert_delayed_threads;
|
||||
set @my_max_join_size =@@global.max_join_size;
|
||||
set @my_max_user_connections =@@global.max_user_connections;
|
||||
set @my_myisam_data_pointer_size =@@global.myisam_data_pointer_size;
|
||||
set @my_myisam_max_sort_file_size =@@global.myisam_max_sort_file_size;
|
||||
set @my_net_buffer_length =@@global.net_buffer_length;
|
||||
@ -830,7 +831,7 @@ set global max_delayed_threads =@my_max_delayed_threads;
|
||||
set global max_heap_table_size =@my_max_heap_table_size;
|
||||
set global max_insert_delayed_threads=@my_max_insert_delayed_threads;
|
||||
set global max_join_size =@my_max_join_size;
|
||||
set global max_user_connections =default;
|
||||
set global max_user_connections =@my_max_user_connections;
|
||||
set global max_write_lock_count =default;
|
||||
set global myisam_data_pointer_size =@my_myisam_data_pointer_size;
|
||||
set global myisam_max_sort_file_size =@my_myisam_max_sort_file_size;
|
||||
|
@ -117,7 +117,10 @@ mysqlbug: ${top_builddir}/config.status mysqlbug.sh
|
||||
mysql_fix_privilege_tables.sql: mysql_system_tables.sql \
|
||||
mysql_system_tables_fix.sql
|
||||
@echo "Building $@";
|
||||
@cat mysql_system_tables.sql mysql_system_tables_fix.sql > $@
|
||||
@echo "-- This file is automaticly generated from" > $@
|
||||
@echo "-- mysql_system_tables.sql & mysql_system_tables_fix.sql" >> $@
|
||||
@echo "" >> $@
|
||||
@cat mysql_system_tables.sql mysql_system_tables_fix.sql >> $@
|
||||
|
||||
#
|
||||
# Build mysql_fix_privilege_tables_sql.c from
|
||||
|
@ -13,7 +13,7 @@ set @had_db_table= @@warning_count != 0;
|
||||
CREATE TABLE IF NOT EXISTS host ( Host char(60) binary DEFAULT '' NOT NULL, Db char(64) binary DEFAULT '' NOT NULL, Select_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Insert_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Update_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Delete_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Drop_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Grant_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, References_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Index_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Alter_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_tmp_table_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Lock_tables_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Show_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Alter_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Execute_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Trigger_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, PRIMARY KEY Host (Host,Db) ) engine=MyISAM CHARACTER SET utf8 COLLATE utf8_bin comment='Host privileges; Merged with database privileges';
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user ( Host char(60) binary DEFAULT '' NOT NULL, User char(16) binary DEFAULT '' NOT NULL, Password char(41) character set latin1 collate latin1_bin DEFAULT '' NOT NULL, Select_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Insert_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Update_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Delete_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Drop_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Reload_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Shutdown_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Process_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, File_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Grant_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, References_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Index_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Alter_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Show_db_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Super_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_tmp_table_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Lock_tables_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Execute_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Repl_slave_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Repl_client_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Show_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Alter_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_user_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Event_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Trigger_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, ssl_type enum('','ANY','X509', 'SPECIFIED') COLLATE utf8_general_ci DEFAULT '' NOT NULL, ssl_cipher BLOB NOT NULL, x509_issuer BLOB NOT NULL, x509_subject BLOB NOT NULL, max_questions int(11) unsigned DEFAULT 0 NOT NULL, max_updates int(11) unsigned DEFAULT 0 NOT NULL, max_connections int(11) unsigned DEFAULT 0 NOT NULL, max_user_connections int(11) unsigned DEFAULT 0 NOT NULL, plugin char(60) CHARACTER SET latin1 DEFAULT '' NOT NULL, auth_string TEXT NOT NULL, PRIMARY KEY Host (Host,User) ) engine=MyISAM CHARACTER SET utf8 COLLATE utf8_bin comment='Users and global privileges';
|
||||
CREATE TABLE IF NOT EXISTS user ( Host char(60) binary DEFAULT '' NOT NULL, User char(16) binary DEFAULT '' NOT NULL, Password char(41) character set latin1 collate latin1_bin DEFAULT '' NOT NULL, Select_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Insert_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Update_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Delete_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Drop_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Reload_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Shutdown_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Process_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, File_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Grant_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, References_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Index_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Alter_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Show_db_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Super_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_tmp_table_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Lock_tables_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Execute_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Repl_slave_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Repl_client_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Show_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Alter_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Create_user_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Event_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Trigger_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, ssl_type enum('','ANY','X509', 'SPECIFIED') COLLATE utf8_general_ci DEFAULT '' NOT NULL, ssl_cipher BLOB NOT NULL, x509_issuer BLOB NOT NULL, x509_subject BLOB NOT NULL, max_questions int(11) unsigned DEFAULT 0 NOT NULL, max_updates int(11) unsigned DEFAULT 0 NOT NULL, max_connections int(11) unsigned DEFAULT 0 NOT NULL, max_user_connections int(11) DEFAULT 0 NOT NULL, plugin char(60) CHARACTER SET latin1 DEFAULT '' NOT NULL, auth_string TEXT NOT NULL, PRIMARY KEY Host (Host,User) ) engine=MyISAM CHARACTER SET utf8 COLLATE utf8_bin comment='Users and global privileges';
|
||||
|
||||
-- Remember for later if user table already existed
|
||||
set @had_user_table= @@warning_count != 0;
|
||||
|
@ -326,8 +326,11 @@ UPDATE host SET Create_routine_priv=Create_priv, Alter_routine_priv=Alter_priv,
|
||||
|
||||
#
|
||||
# Add max_user_connections resource limit
|
||||
# this is signed in MariaDB so that if one sets it's to -1 then the user
|
||||
# can't connect anymore.
|
||||
#
|
||||
ALTER TABLE user ADD max_user_connections int(11) unsigned DEFAULT '0' NOT NULL AFTER max_connections;
|
||||
ALTER TABLE user ADD max_user_connections int(11) DEFAULT '0' NOT NULL AFTER max_connections;
|
||||
ALTER TABLE user MODIFY max_user_connections int(11) DEFAULT '0' NOT NULL AFTER max_connections;
|
||||
|
||||
#
|
||||
# user.Create_user_priv
|
||||
|
@ -5063,12 +5063,16 @@ void Item_func_get_system_var::fix_length_and_dec()
|
||||
switch (var->show_type())
|
||||
{
|
||||
case SHOW_LONG:
|
||||
case SHOW_INT:
|
||||
case SHOW_HA_ROWS:
|
||||
unsigned_flag= TRUE;
|
||||
max_length= MY_INT64_NUM_DECIMAL_DIGITS;
|
||||
decimals=0;
|
||||
break;
|
||||
case SHOW_INT:
|
||||
unsigned_flag= FALSE;
|
||||
max_length= MY_INT64_NUM_DECIMAL_DIGITS;
|
||||
decimals=0;
|
||||
break;
|
||||
case SHOW_LONGLONG:
|
||||
unsigned_flag= TRUE;
|
||||
max_length= MY_INT64_NUM_DECIMAL_DIGITS;
|
||||
@ -5209,7 +5213,7 @@ longlong Item_func_get_system_var::val_int()
|
||||
|
||||
switch (var->show_type())
|
||||
{
|
||||
case SHOW_INT: get_sys_var_safe (uint);
|
||||
case SHOW_INT: get_sys_var_safe (int);
|
||||
case SHOW_LONG: get_sys_var_safe (ulong);
|
||||
case SHOW_LONGLONG: get_sys_var_safe (ulonglong);
|
||||
case SHOW_HA_ROWS: get_sys_var_safe (ha_rows);
|
||||
|
11
sql/log.cc
11
sql/log.cc
@ -1062,17 +1062,6 @@ bool LOGGER::slow_log_print(THD *thd, const char *query, uint query_length,
|
||||
query_length= command_name[thd->command].length;
|
||||
}
|
||||
|
||||
if (!query_length)
|
||||
{
|
||||
/*
|
||||
Not a real query; Reset counts for slow query logging
|
||||
(QQ: Wonder if this is really needed)
|
||||
*/
|
||||
thd->sent_row_count= thd->examined_row_count= 0;
|
||||
thd->query_plan_flags= QPLAN_INIT;
|
||||
thd->query_plan_fsort_passes= 0;
|
||||
}
|
||||
|
||||
for (current_handler= slow_log_handler_list; *current_handler ;)
|
||||
error= (*current_handler++)->log_slow(thd, current_time,
|
||||
user_host_buff, user_host_len,
|
||||
|
@ -2151,7 +2151,8 @@ extern MYSQL_PLUGIN_IMPORT ulong max_connections;
|
||||
extern ulong max_connect_errors, connect_timeout;
|
||||
extern ulong extra_max_connections;
|
||||
extern ulong slave_net_timeout, slave_trans_retries;
|
||||
extern uint max_user_connections;
|
||||
extern int max_user_connections;
|
||||
extern bool max_user_connections_checking;
|
||||
extern ulonglong denied_connections;
|
||||
extern ulong what_to_log,flush_time;
|
||||
extern ulong query_buff_size;
|
||||
|
@ -669,7 +669,8 @@ ulong extra_max_connections;
|
||||
*/
|
||||
ulong max_long_data_size;
|
||||
|
||||
uint max_user_connections= 0;
|
||||
int max_user_connections= 0;
|
||||
bool max_user_connections_checking=0;
|
||||
ulonglong denied_connections;
|
||||
/**
|
||||
Limit of the total number of prepared statements in the server.
|
||||
@ -2142,6 +2143,7 @@ static bool cache_thread()
|
||||
*/
|
||||
thd->mysys_var->abort= 0;
|
||||
thd->thr_create_utime= microsecond_interval_timer();
|
||||
thd->start_utime= thd->thr_create_utime;
|
||||
threads.append(thd);
|
||||
return(1);
|
||||
}
|
||||
@ -5263,7 +5265,7 @@ void create_thread_to_handle_connection(THD *thd)
|
||||
thread_created++;
|
||||
threads.append(thd);
|
||||
DBUG_PRINT("info",(("creating thread %lu"), thd->thread_id));
|
||||
thd->prior_thr_create_utime= thd->start_utime= microsecond_interval_timer();
|
||||
thd->prior_thr_create_utime= microsecond_interval_timer();
|
||||
if ((error=pthread_create(&thd->real_id,&connection_attrib,
|
||||
handle_one_connection,
|
||||
(void*) thd)))
|
||||
@ -7432,9 +7434,9 @@ each time the SQL thread starts.",
|
||||
&max_system_variables.max_tmp_tables, 0, GET_ULONG,
|
||||
REQUIRED_ARG, 32, 1, (longlong) ULONG_MAX, 0, 1, 0},
|
||||
{"max_user_connections", OPT_MAX_USER_CONNECTIONS,
|
||||
"The maximum number of active connections for a single user (0 = no limit).",
|
||||
&max_user_connections, &max_user_connections, 0, GET_UINT,
|
||||
REQUIRED_ARG, 0, 0, UINT_MAX, 0, 1, 0},
|
||||
"The maximum number of active connections for a single user (0 = no limit. In addition global max_user_connections counting and checking is permanently disabled).",
|
||||
&max_user_connections, &max_user_connections, 0, GET_INT,
|
||||
REQUIRED_ARG, 0, 0, INT_MAX, 0, 1, 0},
|
||||
{"max_write_lock_count", OPT_MAX_WRITE_LOCK_COUNT,
|
||||
"After this many write locks, allow some read locks to run in between.",
|
||||
&max_write_lock_count, &max_write_lock_count, 0, GET_ULONG,
|
||||
@ -9641,6 +9643,8 @@ static int get_options(int *argc,char **argv)
|
||||
if (!max_long_data_size_used)
|
||||
max_long_data_size= global_system_variables.max_allowed_packet;
|
||||
|
||||
/* Rember if max_user_connections was 0 at startup */
|
||||
max_user_connections_checking= max_user_connections != 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -3082,7 +3082,19 @@ void sys_var_thd_time_zone::set_default(THD *thd, enum_var_type type)
|
||||
bool sys_var_max_user_conn::check(THD *thd, set_var *var)
|
||||
{
|
||||
if (var->type == OPT_GLOBAL)
|
||||
{
|
||||
if (! max_user_connections_checking)
|
||||
{
|
||||
/*
|
||||
We can't change the value of max_user_connections from 0 as then
|
||||
connect counting would be wrong.
|
||||
*/
|
||||
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0),
|
||||
"--max-user-connections=0");
|
||||
return TRUE;
|
||||
}
|
||||
return sys_var_thd::check(thd, var);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
@ -3098,7 +3110,7 @@ bool sys_var_max_user_conn::update(THD *thd, set_var *var)
|
||||
{
|
||||
DBUG_ASSERT(var->type == OPT_GLOBAL);
|
||||
pthread_mutex_lock(&LOCK_global_system_variables);
|
||||
max_user_connections= (uint)var->save_result.ulonglong_value;
|
||||
max_user_connections= (int) var->save_result.ulonglong_value;
|
||||
pthread_mutex_unlock(&LOCK_global_system_variables);
|
||||
return 0;
|
||||
}
|
||||
|
@ -2089,7 +2089,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
|
||||
table->field[next_field+2]->store((longlong) mqh.conn_per_hour, TRUE);
|
||||
if (table->s->fields >= 36 &&
|
||||
(mqh.specified_limits & USER_RESOURCES::USER_CONNECTIONS))
|
||||
table->field[next_field+3]->store((longlong) mqh.user_conn, TRUE);
|
||||
table->field[next_field+3]->store((longlong) mqh.user_conn, FALSE);
|
||||
mqh_used= mqh_used || mqh.questions || mqh.updates || mqh.conn_per_hour;
|
||||
|
||||
next_field+=4;
|
||||
@ -4578,7 +4578,8 @@ ulong get_column_grant(THD *thd, GRANT_INFO *grant,
|
||||
|
||||
/* Help function for mysql_show_grants */
|
||||
|
||||
static void add_user_option(String *grant, ulong value, const char *name)
|
||||
static void add_user_option(String *grant, long value, const char *name,
|
||||
my_bool is_signed)
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
@ -4586,7 +4587,7 @@ static void add_user_option(String *grant, ulong value, const char *name)
|
||||
grant->append(' ');
|
||||
grant->append(name, strlen(name));
|
||||
grant->append(' ');
|
||||
p=int10_to_str(value, buff, 10);
|
||||
p=int10_to_str(value, buff, is_signed ? -10 : 10);
|
||||
grant->append(buff,p-buff);
|
||||
}
|
||||
}
|
||||
@ -4768,13 +4769,13 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
|
||||
if (want_access & GRANT_ACL)
|
||||
global.append(STRING_WITH_LEN(" GRANT OPTION"));
|
||||
add_user_option(&global, acl_user->user_resource.questions,
|
||||
"MAX_QUERIES_PER_HOUR");
|
||||
"MAX_QUERIES_PER_HOUR", 0);
|
||||
add_user_option(&global, acl_user->user_resource.updates,
|
||||
"MAX_UPDATES_PER_HOUR");
|
||||
"MAX_UPDATES_PER_HOUR", 0);
|
||||
add_user_option(&global, acl_user->user_resource.conn_per_hour,
|
||||
"MAX_CONNECTIONS_PER_HOUR");
|
||||
"MAX_CONNECTIONS_PER_HOUR", 0);
|
||||
add_user_option(&global, acl_user->user_resource.user_conn,
|
||||
"MAX_USER_CONNECTIONS");
|
||||
"MAX_USER_CONNECTIONS", 1);
|
||||
}
|
||||
protocol->prepare_for_resend();
|
||||
protocol->store(global.ptr(),global.length(),global.charset());
|
||||
@ -8147,10 +8148,16 @@ bool acl_authenticate(THD *thd, uint connect_errors,
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
/* Don't allow the user to connect if he has done too many queries */
|
||||
if ((acl_user->user_resource.questions || acl_user->user_resource.updates ||
|
||||
/*
|
||||
Don't allow the user to connect if he has done too many queries.
|
||||
As we are testing max_user_connections == 0 here, it means that we
|
||||
can't let the user change max_user_connections from 0 in the server
|
||||
without a restart as it would lead to wrong connect counting.
|
||||
*/
|
||||
if ((acl_user->user_resource.questions ||
|
||||
acl_user->user_resource.updates ||
|
||||
acl_user->user_resource.conn_per_hour ||
|
||||
acl_user->user_resource.user_conn || max_user_connections) &&
|
||||
acl_user->user_resource.user_conn || max_user_connections_checking) &&
|
||||
get_or_create_user_conn(thd,
|
||||
(opt_old_style_user_limits ? sctx->user : sctx->priv_user),
|
||||
(opt_old_style_user_limits ? sctx->host_or_ip : sctx->priv_host),
|
||||
@ -8163,7 +8170,7 @@ bool acl_authenticate(THD *thd, uint connect_errors,
|
||||
if (thd->user_connect &&
|
||||
(thd->user_connect->user_resources.conn_per_hour ||
|
||||
thd->user_connect->user_resources.user_conn ||
|
||||
max_user_connections) &&
|
||||
max_user_connections_checking) &&
|
||||
check_for_max_user_connections(thd, thd->user_connect))
|
||||
{
|
||||
/* Ensure we don't decrement thd->user_connections->connections twice */
|
||||
|
@ -113,8 +113,11 @@ int check_for_max_user_connections(THD *thd, USER_CONN *uc)
|
||||
DBUG_ENTER("check_for_max_user_connections");
|
||||
|
||||
(void) pthread_mutex_lock(&LOCK_user_conn);
|
||||
|
||||
/* Root is not affected by the value of max_user_connections */
|
||||
if (max_user_connections && !uc->user_resources.user_conn &&
|
||||
max_user_connections < (uint) uc->connections)
|
||||
max_user_connections < uc->connections &&
|
||||
!(thd->security_ctx->master_access & SUPER_ACL))
|
||||
{
|
||||
my_error(ER_TOO_MANY_USER_CONNECTIONS, MYF(0), uc->user);
|
||||
goto end;
|
||||
@ -202,7 +205,7 @@ void time_out_user_resource_limits(THD *thd, USER_CONN *uc)
|
||||
/* If more than a hour since last check, reset resource checking */
|
||||
if (check_time - uc->reset_utime >= LL(3600000000))
|
||||
{
|
||||
uc->questions=1;
|
||||
uc->questions=0;
|
||||
uc->updates=0;
|
||||
uc->conn_per_hour=0;
|
||||
uc->reset_utime= check_time;
|
||||
@ -231,7 +234,7 @@ bool check_mqh(THD *thd, uint check_command)
|
||||
if (uc->user_resources.questions &&
|
||||
uc->questions++ >= uc->user_resources.questions)
|
||||
{
|
||||
my_error(ER_USER_LIMIT_REACHED, MYF(0), uc->user, "max_questions",
|
||||
my_error(ER_USER_LIMIT_REACHED, MYF(0), uc->user, "max_queries_per_hour",
|
||||
(long) uc->user_resources.questions);
|
||||
error=1;
|
||||
goto end;
|
||||
@ -243,7 +246,7 @@ bool check_mqh(THD *thd, uint check_command)
|
||||
(sql_command_flags[check_command] & CF_CHANGES_DATA) &&
|
||||
uc->updates++ >= uc->user_resources.updates)
|
||||
{
|
||||
my_error(ER_USER_LIMIT_REACHED, MYF(0), uc->user, "max_updates",
|
||||
my_error(ER_USER_LIMIT_REACHED, MYF(0), uc->user, "max_updates_per_hour",
|
||||
(long) uc->user_resources.updates);
|
||||
error=1;
|
||||
goto end;
|
||||
@ -1131,6 +1134,8 @@ pthread_handler_t handle_one_connection(void *arg)
|
||||
THD *thd= (THD*) arg;
|
||||
|
||||
thd->thr_create_utime= microsecond_interval_timer();
|
||||
/* We need to set this because of time_out_user_resource_limits */
|
||||
thd->start_utime= thd->thr_create_utime;
|
||||
|
||||
if (thread_scheduler.init_new_connection_thread())
|
||||
{
|
||||
|
@ -2439,7 +2439,7 @@ static bool show_status_array(THD *thd, const char *wild,
|
||||
end= strmov(buff, *(my_bool*) value ? "ON" : "OFF");
|
||||
break;
|
||||
case SHOW_INT:
|
||||
end= int10_to_str((long) *(uint32*) value, buff, 10);
|
||||
end= int10_to_str((long) *(int*) value, buff, -10);
|
||||
break;
|
||||
case SHOW_HAVE:
|
||||
{
|
||||
|
@ -1350,7 +1350,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
|
||||
opt_ev_status opt_ev_on_completion ev_on_completion opt_ev_comment
|
||||
ev_alter_on_schedule_completion opt_ev_rename_to opt_ev_sql_stmt
|
||||
optional_flush_tables_arguments opt_dyncol_type dyncol_type
|
||||
opt_time_precision kill_type kill_option
|
||||
opt_time_precision kill_type kill_option int_num
|
||||
|
||||
%type <ulong_num>
|
||||
ulong_num real_ulong_num merge_insert_types
|
||||
@ -9676,6 +9676,12 @@ delete_limit_clause:
|
||||
}
|
||||
;
|
||||
|
||||
int_num:
|
||||
NUM { int error; $$= (int) my_strtoll10($1.str, (char**) 0, &error); }
|
||||
| '-' NUM { int error; $$= -(int) my_strtoll10($2.str, (char**) 0, &error); }
|
||||
| '-' LONG_NUM { int error; $$= -(int) my_strtoll10($2.str, (char**) 0, &error); }
|
||||
;
|
||||
|
||||
ulong_num:
|
||||
NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); }
|
||||
| HEX_NUM { $$= (ulong) strtol($1.str, (char**) 0, 16); }
|
||||
@ -13434,7 +13440,7 @@ grant_option:
|
||||
lex->mqh.conn_per_hour= $2;
|
||||
lex->mqh.specified_limits|= USER_RESOURCES::CONNECTIONS_PER_HOUR;
|
||||
}
|
||||
| MAX_USER_CONNECTIONS_SYM ulong_num
|
||||
| MAX_USER_CONNECTIONS_SYM int_num
|
||||
{
|
||||
LEX *lex=Lex;
|
||||
lex->mqh.user_conn= $2;
|
||||
|
@ -222,8 +222,11 @@ typedef struct user_resources {
|
||||
uint updates;
|
||||
/* Maximum number of connections established per hour. */
|
||||
uint conn_per_hour;
|
||||
/* Maximum number of concurrent connections. */
|
||||
uint user_conn;
|
||||
/*
|
||||
Maximum number of concurrent connections. If -1 then no new
|
||||
connections allowed
|
||||
*/
|
||||
int user_conn;
|
||||
/*
|
||||
Values of this enum and specified_limits member are used by the
|
||||
parser to store which user limits were specified in GRANT statement.
|
||||
@ -256,7 +259,7 @@ typedef struct user_conn {
|
||||
/* Total length of the key. */
|
||||
uint len;
|
||||
/* Current amount of concurrent connections for this account. */
|
||||
uint connections;
|
||||
int connections;
|
||||
/*
|
||||
Current number of connections per hour, number of updating statements
|
||||
per hour and total number of statements per hour for this account.
|
||||
|
Loading…
x
Reference in New Issue
Block a user