summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--BitKeeper/etc/logging_ok1
-rw-r--r--mysql-test/r/grant.result13
-rw-r--r--mysql-test/r/grant2.result39
-rw-r--r--mysql-test/r/sp.result2
-rw-r--r--mysql-test/r/system_mysql_db.result1
-rw-r--r--mysql-test/t/grant2.test50
-rw-r--r--scripts/mysql_create_system_tables.sh13
-rw-r--r--scripts/mysql_fix_privilege_tables.sql12
-rw-r--r--sql/sql_acl.cc36
-rw-r--r--sql/sql_acl.h37
-rw-r--r--sql/sql_parse.cc60
-rw-r--r--sql/sql_show.cc1
-rw-r--r--sql/sql_yacc.yy1
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
@@ -291,6 +291,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
#
CREATE TABLE IF NOT EXISTS procs_priv (
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 <LEX_USER> &user_list,
bool mysql_procedure_grant(THD *thd, TABLE_LIST *table,
List <LEX_USER> &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 <LEX_USER> user_list(lex->users_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 <LEX_USER> user_list(lex->users_list);
- while ((user=user_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; }
;