From ad26a667e69b964c60d1a30916dea3c7fbefaf4a Mon Sep 17 00:00:00 2001 From: "mysqldev@mysql.com" <> Date: Tue, 22 Mar 2005 15:54:18 +0100 Subject: [PATCH] sql_acl.cc, sql_acl.h, sql_parse.cc New privilege CREATE USER (CREATE_USER_ACL, Create_user_priv) added grant2.test: new tests (mostly backported from jani's patch) system_mysql_db.result, sp.result, grant2.result, grant.result: results updated --- BitKeeper/etc/logging_ok | 1 + mysql-test/r/grant.result | 13 +++--- mysql-test/r/grant2.result | 39 +++++++++++------ mysql-test/r/sp.result | 2 + mysql-test/r/system_mysql_db.result | 1 + mysql-test/t/grant2.test | 50 ++++++++++++++++----- scripts/mysql_create_system_tables.sh | 13 +++--- scripts/mysql_fix_privilege_tables.sql | 12 ++++++ sql/sql_acl.cc | 36 ++++++++++++---- sql/sql_acl.h | 37 ++++++++-------- sql/sql_parse.cc | 60 ++++++++++++++------------ sql/sql_show.cc | 1 + sql/sql_yacc.yy | 1 + 13 files changed, 176 insertions(+), 90 deletions(-) diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index eff53f4a789..6c6065277fe 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -225,6 +225,7 @@ salle@vafla.online.bg sasha@mysql.sashanet.com serg@build.mysql.com serg@build.mysql2.com +serg@mysql.com serg@serg.mylan serg@serg.mysql.com serg@sergbook.mylan diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result index e5f7f535ae2..ecd2758fd1c 100644 --- a/mysql-test/r/grant.result +++ b/mysql-test/r/grant.result @@ -10,8 +10,8 @@ GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' REQUIRE CIPHER 'EDH-RSA-DES-CBC3 GRANT SELECT ON `mysqltest`.* TO 'mysqltest_1'@'localhost' grant delete on mysqltest.* to mysqltest_1@localhost; select * from mysql.user where user="mysqltest_1"; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections -localhost mysqltest_1 N N N N N N N N N N N N N N N N N N N N N N N N N SPECIFIED EDH-RSA-DES-CBC3-SHA 0 0 0 0 +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections +localhost mysqltest_1 N N N N N N N N N N N N N N N N N N N N N N N N N N SPECIFIED EDH-RSA-DES-CBC3-SHA 0 0 0 0 show grants for mysqltest_1@localhost; Grants for mysqltest_1@localhost GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' REQUIRE CIPHER 'EDH-RSA-DES-CBC3-SHA' @@ -41,15 +41,15 @@ delete from mysql.user where user='mysqltest_1'; flush privileges; grant usage on *.* to mysqltest_1@localhost with max_queries_per_hour 10; select * from mysql.user where user="mysqltest_1"; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections -localhost mysqltest_1 N N N N N N N N N N N N N N N N N N N N N N N N N 10 0 0 0 +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections +localhost mysqltest_1 N N N N N N N N N N N N N N N N N N N N N N N N N N 10 0 0 0 show grants for mysqltest_1@localhost; Grants for mysqltest_1@localhost GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' WITH MAX_QUERIES_PER_HOUR 10 grant usage on *.* to mysqltest_1@localhost with max_updates_per_hour 20 max_connections_per_hour 30; select * from mysql.user where user="mysqltest_1"; -Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections -localhost mysqltest_1 N N N N N N N N N N N N N N N N N N N N N N N N N 10 20 30 0 +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Create_user_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections max_user_connections +localhost mysqltest_1 N N N N N N N N N N N N N N N N N N N N N N N N N N 10 20 30 0 show grants for mysqltest_1@localhost; Grants for mysqltest_1@localhost GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' WITH MAX_QUERIES_PER_HOUR 10 MAX_UPDATES_PER_HOUR 20 MAX_CONNECTIONS_PER_HOUR 30 @@ -440,6 +440,7 @@ Create Databases,Tables,Indexes To create new databases and tables Create routine Functions,Procedures To use CREATE FUNCTION/PROCEDURE Create temporary tables Databases To use CREATE TEMPORARY TABLE Create view Tables To create new views +Create user Server Admin To create new users Delete Tables To delete existing rows Drop Databases,Tables To drop databases, tables, and views Execute Functions,Procedures To execute stored routines diff --git a/mysql-test/r/grant2.result b/mysql-test/r/grant2.result index e6c78fdfdd4..7b3598ab4d9 100644 --- a/mysql-test/r/grant2.result +++ b/mysql-test/r/grant2.result @@ -5,7 +5,25 @@ delete from mysql.db where user like 'mysqltest\_%'; delete from mysql.tables_priv where user like 'mysqltest\_%'; delete from mysql.columns_priv where user like 'mysqltest\_%'; flush privileges; +grant all privileges on `my\_1`.* to mysqltest_1@localhost with grant option; +grant create user on *.* to mysqltest_1@localhost; +create user mysqltest_2@localhost; +grant select on `my\_1`.* to mysqltest_2@localhost; +grant select on `my\_1`.* to mysqltest_2@localhost identified by 'pass'; +ERROR 42000: You must have privileges to update tables in the mysql database to be able to change passwords for others +grant update on mysql.* to mysqltest_1@localhost; +grant select on `my\_1`.* to mysqltest_2@localhost identified by 'pass'; +grant select on `my\_1`.* to mysqltest_3@localhost; +grant insert on mysql.* to mysqltest_1@localhost; +grant select on `my\_1`.* to mysqltest_3@localhost; +grant select on `my\_1`.* to mysqltest_4@localhost identified by 'pass'; +delete from mysql.user where user like 'mysqltest\_%'; +delete from mysql.db where user like 'mysqltest\_%'; +delete from mysql.tables_priv where user like 'mysqltest\_%'; +delete from mysql.columns_priv where user like 'mysqltest\_%'; +flush privileges; grant all privileges on `my\_%`.* to mysqltest_1@localhost with grant option; +grant create user on *.* to mysqltest_1@localhost; select current_user(); current_user() mysqltest_1@localhost @@ -23,10 +41,9 @@ grant select on `my\_1`.* to mysqltest_4@localhost with grant option; ERROR 42000: 'mysqltest_1'@'localhost' is not allowed to create new users grant select on `my\_1`.* to mysqltest_4@localhost identified by 'mypass' with grant option; -ERROR 42000: Access denied for user 'mysqltest_1'@'localhost' to database 'mysql' show grants for mysqltest_1@localhost; Grants for mysqltest_1@localhost -GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +GRANT CREATE USER ON *.* TO 'mysqltest_1'@'localhost' GRANT ALL PRIVILEGES ON `my\_%`.* TO 'mysqltest_1'@'localhost' WITH GRANT OPTION show grants for mysqltest_2@localhost; Grants for mysqltest_2@localhost @@ -212,7 +229,7 @@ GRANT USAGE ON *.* TO '%@a'@'a' GRANT SELECT ON "mysql".* TO '%@a'@'a' drop user '%@a'@'a'; create user mysqltest_2@localhost; -grant usage on *.* to mysqltest_2@localhost with grant option; +grant create user on *.* to mysqltest_2@localhost; select host,user,password from mysql.user where user like 'mysqltest_%' order by host,user,password; ERROR 42000: SELECT command denied to user 'mysqltest_2'@'localhost' for table 'user' create user mysqltest_A@'%'; @@ -220,19 +237,17 @@ rename user mysqltest_A@'%' to mysqltest_B@'%'; drop user mysqltest_B@'%'; drop user mysqltest_2@localhost; create user mysqltest_3@localhost; -grant all privileges on mysql.* to mysqltest_3@localhost; +grant INSERT,DELETE,UPDATE on mysql.* to mysqltest_3@localhost; +show grants; +Grants for mysqltest_3@localhost +GRANT USAGE ON *.* TO 'mysqltest_3'@'localhost' +GRANT INSERT, UPDATE, DELETE ON `mysql`.* TO 'mysqltest_3'@'localhost' select host,user,password from mysql.user where user like 'mysqltest_%' order by host,user,password; -host user password -% mysqltest_2 *BD447CBA355AF58578D3AE33BA2E2CD388BA08D1 -localhost mysqltest_3 +ERROR 42000: SELECT command denied to user 'mysqltest_3'@'localhost' for table 'user' insert into mysql.user set host='%', user='mysqltest_B'; create user mysqltest_A@'%'; -ERROR 42000: Access denied for user 'mysqltest_3'@'localhost' to database 'mysql' rename user mysqltest_B@'%' to mysqltest_C@'%'; -ERROR 42000: Access denied for user 'mysqltest_3'@'localhost' to database 'mysql' -drop user mysqltest_B@'%'; -ERROR 42000: Access denied for user 'mysqltest_3'@'localhost' to database 'mysql' -drop user mysqltest_B@'%'; +drop user mysqltest_C@'%'; drop user mysqltest_3@localhost; set @@sql_mode=''; create database mysqltest_1; diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 5366ecb2be3..93884bf4cf4 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -2185,6 +2185,7 @@ Create Databases,Tables,Indexes To create new databases and tables Create routine Functions,Procedures To use CREATE FUNCTION/PROCEDURE Create temporary tables Databases To use CREATE TEMPORARY TABLE Create view Tables To create new views +Create user Server Admin To create new users Delete Tables To delete existing rows Drop Databases,Tables To drop databases, tables, and views Execute Functions,Procedures To execute stored routines @@ -2238,6 +2239,7 @@ Create Databases,Tables,Indexes To create new databases and tables Create routine Functions,Procedures To use CREATE FUNCTION/PROCEDURE Create temporary tables Databases To use CREATE TEMPORARY TABLE Create view Tables To create new views +Create user Server Admin To create new users Delete Tables To delete existing rows Drop Databases,Tables To drop databases, tables, and views Execute Functions,Procedures To execute stored routines diff --git a/mysql-test/r/system_mysql_db.result b/mysql-test/r/system_mysql_db.result index 532f0eca014..40a9c3b9af5 100644 --- a/mysql-test/r/system_mysql_db.result +++ b/mysql-test/r/system_mysql_db.result @@ -96,6 +96,7 @@ user CREATE TABLE `user` ( `Show_view_priv` enum('N','Y') character set utf8 NOT NULL default 'N', `Create_routine_priv` enum('N','Y') character set utf8 NOT NULL default 'N', `Alter_routine_priv` enum('N','Y') character set utf8 NOT NULL default 'N', + `Create_user_priv` enum('N','Y') character set utf8 NOT NULL default 'N', `ssl_type` enum('','ANY','X509','SPECIFIED') character set utf8 NOT NULL default '', `ssl_cipher` blob NOT NULL, `x509_issuer` blob NOT NULL, diff --git a/mysql-test/t/grant2.test b/mysql-test/t/grant2.test index 58f91fddcc2..e480cfc4f5b 100644 --- a/mysql-test/t/grant2.test +++ b/mysql-test/t/grant2.test @@ -17,11 +17,42 @@ delete from mysql.columns_priv where user like 'mysqltest\_%'; flush privileges; +grant all privileges on `my\_1`.* to mysqltest_1@localhost with grant option; +grant create user on *.* to mysqltest_1@localhost; +create user mysqltest_2@localhost; +connect (user_a,localhost,mysqltest_1,,); +connection user_a; +grant select on `my\_1`.* to mysqltest_2@localhost; +--error 1132 +grant select on `my\_1`.* to mysqltest_2@localhost identified by 'pass'; +disconnect user_a; +connection default; +grant update on mysql.* to mysqltest_1@localhost; +connect (user_b,localhost,mysqltest_1,,); +connection user_b; +grant select on `my\_1`.* to mysqltest_2@localhost identified by 'pass'; +grant select on `my\_1`.* to mysqltest_3@localhost; +disconnect user_b; +connection default; +grant insert on mysql.* to mysqltest_1@localhost; +connect (user_c,localhost,mysqltest_1,,); +connection user_c; +grant select on `my\_1`.* to mysqltest_3@localhost; +grant select on `my\_1`.* to mysqltest_4@localhost identified by 'pass'; +disconnect user_c; +connection default; +delete from mysql.user where user like 'mysqltest\_%'; +delete from mysql.db where user like 'mysqltest\_%'; +delete from mysql.tables_priv where user like 'mysqltest\_%'; +delete from mysql.columns_priv where user like 'mysqltest\_%'; +flush privileges; + # # wild_compare fun # grant all privileges on `my\_%`.* to mysqltest_1@localhost with grant option; +grant create user on *.* to mysqltest_1@localhost; connect (user1,localhost,mysqltest_1,,); connection user1; select current_user(); @@ -29,6 +60,7 @@ select current_user; grant all privileges on `my\_1`.* to mysqltest_2@localhost with grant option; --error 1044 grant all privileges on `my_%`.* to mysqltest_3@localhost with grant option; + # # NO_AUTO_CREATE_USER mode # @@ -36,7 +68,6 @@ set @@sql_mode='NO_AUTO_CREATE_USER'; select @@sql_mode; --error 1211 grant select on `my\_1`.* to mysqltest_4@localhost with grant option; ---error 1044 grant select on `my\_1`.* to mysqltest_4@localhost identified by 'mypass' with grant option; disconnect user1; @@ -215,9 +246,10 @@ show grants for '%@b'@'b'; show grants for '%@a'@'a'; drop user '%@a'@'a'; # -# USAGE WITH GRANT OPTION is sufficient. +# CREATE USER privilege is enough +# create user mysqltest_2@localhost; -grant usage on *.* to mysqltest_2@localhost with grant option; +grant create user on *.* to mysqltest_2@localhost; connect (user2,localhost,mysqltest_2,,); connection user2; --error 1142 @@ -229,22 +261,20 @@ disconnect user2; connection default; drop user mysqltest_2@localhost; # -# ALL PRIVILEGES without GRANT OPTION is not sufficient. +# INSERT/UPDATE/DELETE is ok too create user mysqltest_3@localhost; -grant all privileges on mysql.* to mysqltest_3@localhost; +grant INSERT,DELETE,UPDATE on mysql.* to mysqltest_3@localhost; connect (user3,localhost,mysqltest_3,,); connection user3; +show grants; +--error 1142 select host,user,password from mysql.user where user like 'mysqltest_%' order by host,user,password; insert into mysql.user set host='%', user='mysqltest_B'; ---error 1044 create user mysqltest_A@'%'; ---error 1044 rename user mysqltest_B@'%' to mysqltest_C@'%'; ---error 1044 -drop user mysqltest_B@'%'; +drop user mysqltest_C@'%'; disconnect user3; connection default; -drop user mysqltest_B@'%'; drop user mysqltest_3@localhost; # # Bug #3309: Test IP addresses with netmask diff --git a/scripts/mysql_create_system_tables.sh b/scripts/mysql_create_system_tables.sh index d87113d3656..29f6f7b41e1 100644 --- a/scripts/mysql_create_system_tables.sh +++ b/scripts/mysql_create_system_tables.sh @@ -146,6 +146,7 @@ then c_u="$c_u Show_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL," c_u="$c_u Create_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL," c_u="$c_u Alter_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL," + c_u="$c_u Create_user_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL," c_u="$c_u ssl_type enum('','ANY','X509', 'SPECIFIED') COLLATE utf8_general_ci DEFAULT '' NOT NULL," c_u="$c_u ssl_cipher BLOB NOT NULL," c_u="$c_u x509_issuer BLOB NOT NULL," @@ -161,22 +162,22 @@ then if test "$1" = "test" then - i_u="INSERT INTO user VALUES ('localhost','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0); - INSERT INTO user VALUES ('$hostname','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0); - REPLACE INTO user VALUES ('127.0.0.1','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0); + i_u="INSERT INTO user VALUES ('localhost','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0); + INSERT INTO user VALUES ('$hostname','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0); + REPLACE INTO user VALUES ('127.0.0.1','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0); INSERT INTO user (host,user) values ('localhost',''); INSERT INTO user (host,user) values ('$hostname','');" else - i_u="INSERT INTO user VALUES ('localhost','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0);" + i_u="INSERT INTO user VALUES ('localhost','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0);" if test "$windows" = "0" then i_u="$i_u - INSERT INTO user VALUES ('$hostname','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0); + INSERT INTO user VALUES ('$hostname','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0); INSERT INTO user (host,user) values ('$hostname',''); INSERT INTO user (host,user) values ('localhost','');" else i_u="$i_u - INSERT INTO user VALUES ('localhost','','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0);" + INSERT INTO user VALUES ('localhost','','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0);" fi fi fi diff --git a/scripts/mysql_fix_privilege_tables.sql b/scripts/mysql_fix_privilege_tables.sql index 2310e8d0bef..628b034362d 100644 --- a/scripts/mysql_fix_privilege_tables.sql +++ b/scripts/mysql_fix_privilege_tables.sql @@ -290,6 +290,18 @@ UPDATE db SET Create_routine_priv=Create_priv, Alter_routine_priv=Alter_priv, Ex # ALTER TABLE user ADD max_user_connections int(11) unsigned DEFAULT '0' NOT NULL AFTER max_connections; +# +# user.Create_user_priv +# + +SET @hadCreateUserPriv:=0; +SELECT @hadCreateUserPriv:=1 FROM user WHERE Create_user_priv LIKE '%'; + +ALTER TABLE user ADD Create_user_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL AFTER Alter_routine_priv; +UPDATE user LEFT JOIN db USING (Host,User) SET Create_user_priv='Y' + WHERE @hadCreateUserPriv = 0 AND + (user.Grant_priv = 'Y' OR db.Grant_priv = 'Y'); + # # Create some possible missing tables # diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index c51e5e00aa1..582fd4cf425 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -239,7 +239,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) DBUG_PRINT("info",("user table fields: %d, password length: %d", table->s->fields, table->field[2]->field_length)); - + pthread_mutex_lock(&LOCK_global_system_variables); if (table->field[2]->field_length < SCRAMBLED_PASSWORD_CHAR_LENGTH) { @@ -323,6 +323,12 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) if (table->s->fields <= 33 && (user.access & ALTER_ACL)) user.access|= ALTER_PROC_ACL; + /* + pre 5.0.3 did not have CREATE_USER_ACL + */ + if (table->s->fields <= 36 && (user.access & GRANT_ACL)) + user.access|= CREATE_USER_ACL; + user.sort= get_sort(2,user.host.hostname,user.user); user.hostname_length= (user.host.hostname ? (uint) strlen(user.host.hostname) : 0); @@ -1541,18 +1547,26 @@ end: } -/* Return 1 if we are allowed to create new users */ +/* + Return 1 if we are allowed to create new users + the logic here is: INSERT_ACL is sufficient. + It's also a requirement in opt_safe_user_create, + otherwise CREATE_USER_ACL is enough. +*/ static bool test_if_create_new_users(THD *thd) { - bool create_new_users=1; // Assume that we are allowed to create new users - if (opt_safe_user_create && !(thd->master_access & INSERT_ACL)) + bool create_new_users= test(thd->master_access & INSERT_ACL) || + (!opt_safe_user_create && + test(thd->master_access & CREATE_USER_ACL)); + if (!create_new_users) { TABLE_LIST tl; ulong db_access; bzero((char*) &tl,sizeof(tl)); tl.db= (char*) "mysql"; tl.table_name= (char*) "user"; + create_new_users= 1; db_access=acl_get(thd->host, thd->ip, thd->priv_user, tl.db, 0); @@ -1614,8 +1628,8 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, goto end; } /* - There are four options which affect the process of creation of - a new user(mysqld option --safe-create-user, 'insert' privilege + There are four options which affect the process of creation of + a new user (mysqld option --safe-create-user, 'insert' privilege on 'mysql.user' table, using 'GRANT' with 'IDENTIFIED BY' and SQL_MODE flag NO_AUTO_CREATE_USER). Below is the simplified rule how it should work. @@ -1623,6 +1637,8 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, else if (identified_by) => create else if (no_auto_create_user) => reject else create + + see also test_if_create_new_users() */ else if (((thd->variables.sql_mode & MODE_NO_AUTO_CREATE_USER) && !password_len) || !create_user) @@ -2925,7 +2941,7 @@ bool mysql_procedure_grant(THD *thd, TABLE_LIST *table_list, table_name= table_list->table_name; grant_name= proc_hash_search(Str->host.str, NullS, db_name, - Str->user.str, table_name, 1); + Str->user.str, table_name, 1); if (!grant_name) { if (revoke_grant) @@ -2946,7 +2962,7 @@ bool mysql_procedure_grant(THD *thd, TABLE_LIST *table_list, } my_hash_insert(&proc_priv_hash,(byte*) grant_name); } - + if (replace_proc_table(thd, grant_name, tables[1].table, *Str, db_name, table_name, rights, revoke_grant)) { @@ -3688,11 +3704,13 @@ static const char *command_array[]= "ALTER", "SHOW DATABASES", "SUPER", "CREATE TEMPORARY TABLES", "LOCK TABLES", "EXECUTE", "REPLICATION SLAVE", "REPLICATION CLIENT", "CREATE VIEW", "SHOW VIEW", "CREATE ROUTINE", "ALTER ROUTINE", + "CREATE USER" }; static uint command_lengths[]= { - 6, 6, 6, 6, 6, 4, 6, 8, 7, 4, 5, 10, 5, 5, 14, 5, 23, 11, 7, 17, 18, 11, 9, 14, 13 + 6, 6, 6, 6, 6, 4, 6, 8, 7, 4, 5, 10, 5, 5, 14, 5, 23, 11, 7, 17, 18, 11, 9, + 14, 13, 11 }; diff --git a/sql/sql_acl.h b/sql/sql_acl.h index 24916fd4385..18eb123d402 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -39,12 +39,17 @@ #define SHOW_VIEW_ACL (1L << 22) #define CREATE_PROC_ACL (1L << 23) #define ALTER_PROC_ACL (1L << 24) +#define CREATE_USER_ACL (1L << 25) /* don't forget to update - static struct show_privileges_st sys_privileges[] - in sql_show.cc when adding new privileges! + 1. static struct show_privileges_st sys_privileges[] + 2. static const char *command_array[] and static uint command_lengths[] + 3. mysql_create_system_tables.sh, mysql_fix_privilege_tables.sql + 4. acl_init() or whatever - to define behaviour for old privilege tables + 5. sql_yacc.yy - for GRANT/REVOKE to work */ - +#define EXTRA_ACL (1L << 29) +#define NO_ACCESS (1L << 30) #define DB_ACLS \ (UPDATE_ACL | SELECT_ACL | INSERT_ACL | DELETE_ACL | CREATE_ACL | DROP_ACL | \ @@ -72,10 +77,7 @@ REFERENCES_ACL | INDEX_ACL | ALTER_ACL | SHOW_DB_ACL | SUPER_ACL | \ CREATE_TMP_ACL | LOCK_TABLES_ACL | REPL_SLAVE_ACL | REPL_CLIENT_ACL | \ EXECUTE_ACL | CREATE_VIEW_ACL | SHOW_VIEW_ACL | CREATE_PROC_ACL | \ - ALTER_PROC_ACL ) - -#define EXTRA_ACL (1L << 29) -#define NO_ACCESS (1L << 30) + ALTER_PROC_ACL | CREATE_USER_ACL) #define DEFAULT_CREATE_PROC_ACLS \ (ALTER_PROC_ACL | EXECUTE_ACL) @@ -85,25 +87,21 @@ This is needed as the 'host' and 'db' table is missing a few privileges */ -/* Continius bit-segments that needs to be shifted */ -#define DB_REL1 ((1L << 6) | (1L << 7) | (1L << 8) | (1L << 9)) -#define DB_REL2 ((1L << 10) | (1L << 11)) -#define DB_REL3 ((1L << 12) | (1L << 13) | (1L << 14) | (1L << 15)) -#define DB_REL4 ((1L << 16)) - /* Privileges that needs to be reallocated (in continous chunks) */ +#define DB_CHUNK0 (SELECT_ACL | INSERT_ACL | UPDATE_ACL | DELETE_ACL | \ + CREATE_ACL | DROP_ACL) #define DB_CHUNK1 (GRANT_ACL | REFERENCES_ACL | INDEX_ACL | ALTER_ACL) #define DB_CHUNK2 (CREATE_TMP_ACL | LOCK_TABLES_ACL) #define DB_CHUNK3 (CREATE_VIEW_ACL | SHOW_VIEW_ACL | \ CREATE_PROC_ACL | ALTER_PROC_ACL ) #define DB_CHUNK4 (EXECUTE_ACL) -#define fix_rights_for_db(A) (((A) & 63) | \ - (((A) & DB_REL1) << 4) | \ - (((A) & DB_REL2) << 6) | \ - (((A) & DB_REL3) << 9) | \ - (((A) & DB_REL4) << 2)) -#define get_rights_for_db(A) (((A) & 63) | \ +#define fix_rights_for_db(A) (((A) & DB_CHUNK0) | \ + (((A) << 4) & DB_CHUNK1) | \ + (((A) << 6) & DB_CHUNK2) | \ + (((A) << 9) & DB_CHUNK3) | \ + (((A) << 2) & DB_CHUNK4)) +#define get_rights_for_db(A) (((A) & DB_CHUNK0) | \ (((A) & DB_CHUNK1) >> 4) | \ (((A) & DB_CHUNK2) >> 6) | \ (((A) & DB_CHUNK3) >> 9) | \ @@ -190,6 +188,7 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table, List &user_list, bool mysql_procedure_grant(THD *thd, TABLE_LIST *table, List &user_list, ulong rights, bool revoke, bool no_error); +ACL_USER *check_acl_user(LEX_USER *user_name, uint *acl_acl_userdx); my_bool grant_init(THD *thd); void grant_free(void); void grant_reload(THD *thd); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index cc5bd90e4f2..dc5c644d9a1 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3559,7 +3559,8 @@ unsent_create_error: #ifndef NO_EMBEDDED_ACCESS_CHECKS case SQLCOM_CREATE_USER: { - if (check_access(thd, GRANT_ACL,"mysql",0,1,0)) + if (check_access(thd, INSERT_ACL, "mysql", 0, 1, 1) && + check_global_access(thd,CREATE_USER_ACL)) break; if (!(res= mysql_create_user(thd, lex->users_list))) { @@ -3574,7 +3575,8 @@ unsent_create_error: } case SQLCOM_DROP_USER: { - if (check_access(thd, GRANT_ACL,"mysql",0,1,0)) + if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 1) && + check_global_access(thd,CREATE_USER_ACL)) break; if (!(res= mysql_drop_user(thd, lex->users_list))) { @@ -3589,7 +3591,8 @@ unsent_create_error: } case SQLCOM_RENAME_USER: { - if (check_access(thd, GRANT_ACL,"mysql",0,1,0)) + if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1) && + check_global_access(thd,CREATE_USER_ACL)) break; if (!(res= mysql_rename_user(thd, lex->users_list))) { @@ -3604,7 +3607,8 @@ unsent_create_error: } case SQLCOM_REVOKE_ALL: { - if (check_access(thd, GRANT_ACL ,"mysql",0,1,0)) + if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1) && + check_global_access(thd,CREATE_USER_ACL)) break; if (!(res = mysql_revoke_all(thd, lex->users_list))) { @@ -3629,32 +3633,32 @@ unsent_create_error: if (thd->user) // If not replication { LEX_USER *user; + uint counter; + List_iterator user_list(lex->users_list); - while ((user=user_list++)) + while ((user= user_list++)) { - if (user->password.str && - (strcmp(thd->user, user->user.str) || - user->host.str && - my_strcasecmp(system_charset_info, - user->host.str, thd->host_or_ip))) - { - if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 0)) - goto error; - break; // We are allowed to do changes - } - } - } - if (specialflag & SPECIAL_NO_RESOLVE) - { - LEX_USER *user; - List_iterator user_list(lex->users_list); - while ((user=user_list++)) - { - if (hostname_requires_resolving(user->host.str)) - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_WARN_HOSTNAME_WONT_WORK, - ER(ER_WARN_HOSTNAME_WONT_WORK), - user->host.str); + if (specialflag & SPECIAL_NO_RESOLVE && + hostname_requires_resolving(user->host.str)) + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WARN_HOSTNAME_WONT_WORK, + ER(ER_WARN_HOSTNAME_WONT_WORK), + user->host.str); + // Are we trying to change a password of another user + DBUG_ASSERT(user->host.str != 0); + if (strcmp(thd->user, user->user.str) || + my_strcasecmp(system_charset_info, + user->host.str, thd->host_or_ip)) + { + // TODO: use check_change_password() + if (check_acl_user(user, &counter) && user->password.str && + check_access(thd, UPDATE_ACL,"mysql",0,1,1)) + { + my_message(ER_PASSWORD_NOT_ALLOWED, + ER(ER_PASSWORD_NOT_ALLOWED), MYF(0)); + goto error; + } + } } } if (first_table) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 124ce1805db..fadc445e85d 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -102,6 +102,7 @@ static struct show_privileges_st sys_privileges[]= {"Create routine","Functions,Procedures","To use CREATE FUNCTION/PROCEDURE"}, {"Create temporary tables","Databases","To use CREATE TEMPORARY TABLE"}, {"Create view", "Tables", "To create new views"}, + {"Create user", "Server Admin", "To create new users"}, {"Delete", "Tables", "To delete existing rows"}, {"Drop", "Databases,Tables", "To drop databases, tables, and views"}, {"Execute", "Functions,Procedures", "To execute stored routines"}, diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index cc6eadf5fd5..8141de31275 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -7903,6 +7903,7 @@ object_privilege: | SHOW VIEW_SYM { Lex->grant |= SHOW_VIEW_ACL; } | CREATE ROUTINE_SYM { Lex->grant |= CREATE_PROC_ACL; } | ALTER ROUTINE_SYM { Lex->grant |= ALTER_PROC_ACL; } + | CREATE USER { Lex->grant |= CREATE_USER_ACL; } ;