From 1f0368658b8992c88e2f6304de80f11be097ba1a Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 2 Nov 2013 16:26:01 +0100 Subject: [PATCH 1/2] MDEV-5225 Server crashes on CREATE USER|ROLE CURRENT_ROLE or DROP ROLE CURRENT_ROLE --- .../roles/create_and_drop_current.result | 39 ++++++++++++++ .../suite/roles/create_and_drop_current.test | 52 +++++++++++++++++++ sql/sql_acl.cc | 31 ++++++++++- 3 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 mysql-test/suite/roles/create_and_drop_current.result create mode 100644 mysql-test/suite/roles/create_and_drop_current.test diff --git a/mysql-test/suite/roles/create_and_drop_current.result b/mysql-test/suite/roles/create_and_drop_current.result new file mode 100644 index 00000000000..fa319440080 --- /dev/null +++ b/mysql-test/suite/roles/create_and_drop_current.result @@ -0,0 +1,39 @@ +grant create user on *.* to foo@localhost; +create user current_user; +ERROR HY000: Operation CREATE USER failed for CURRENT_USER +create user current_role; +ERROR HY000: Operation CREATE USER failed for CURRENT_ROLE +create role current_user; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'current_user' at line 1 +create role current_role; +ERROR HY000: Operation CREATE ROLE failed for CURRENT_ROLE +drop user current_user; +drop user current_role; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'current_role' at line 1 +drop role current_user; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'current_user' at line 1 +drop role current_role; +ERROR HY000: Operation DROP ROLE failed for CURRENT_ROLE +show warnings; +Level Code Message +Error 1446 Invalid definer +Error 1396 Operation DROP ROLE failed for CURRENT_ROLE +create role r1; +grant r1 to current_user; +set role r1; +select current_role(); +current_role() +r1 +create user current_role; +ERROR HY000: Operation CREATE USER failed for CURRENT_ROLE +create role current_role; +ERROR HY000: Operation CREATE ROLE failed for CURRENT_ROLE +drop user current_role; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'current_role' at line 1 +drop role current_role; +select user,host,is_role from mysql.user; +user host is_role +root localhost N +root meddwl N +root 127.0.0.1 N +root ::1 N diff --git a/mysql-test/suite/roles/create_and_drop_current.test b/mysql-test/suite/roles/create_and_drop_current.test new file mode 100644 index 00000000000..ad606376615 --- /dev/null +++ b/mysql-test/suite/roles/create_and_drop_current.test @@ -0,0 +1,52 @@ +# +# MDEV-5225 Server crashes on CREATE USER|ROLE CURRENT_ROLE or DROP ROLE CURRENT_ROLE +# + +# Where CURRENT_USER/CURRENT_ROLE is explicitly allowed by the grammar +# the error (if any) should be ER_CANNOT_USER +# +# Where it's not explicitly allowed, the error is ER_PARSE_ERROR, +# because CURRENT_USER/CURRENT_ROLE are reserved words and cannot be +# accepted as an identifier. +# + +--source include/not_embedded.inc + +grant create user on *.* to foo@localhost; +--change_user foo + +--error ER_CANNOT_USER +create user current_user; +--error ER_CANNOT_USER +create user current_role; +--error ER_PARSE_ERROR +create role current_user; +--error ER_CANNOT_USER +create role current_role; +# this works +drop user current_user; +--error ER_PARSE_ERROR +drop user current_role; +--error ER_PARSE_ERROR +drop role current_user; +--error ER_CANNOT_USER +drop role current_role; +show warnings; + +--change_user root + +create role r1; +grant r1 to current_user; +set role r1; +select current_role(); + +--error ER_CANNOT_USER +create user current_role; +--error ER_CANNOT_USER +create role current_role; +--error ER_PARSE_ERROR +drop user current_role; +drop role current_role; + +select user,host,is_role from mysql.user; + diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 28628e313f8..adc073f7117 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -9043,6 +9043,13 @@ static void append_user(String *str, LEX_USER *user) str->append('\''); } +static void append_str(String *str, const char *s, size_t l) +{ + if (str->length()) + str->append(','); + str->append(s, l); +} + /* Create a list of users. @@ -9080,6 +9087,20 @@ bool mysql_create_user(THD *thd, List &list, bool handle_as_role) while ((user_name= user_list++)) { + if (user_name->user.str == current_user.str) + { + append_str(&wrong_users, STRING_WITH_LEN("CURRENT_USER")); + result= TRUE; + continue; + } + + if (user_name->user.str == current_role.str) + { + append_str(&wrong_users, STRING_WITH_LEN("CURRENT_ROLE")); + result= TRUE; + continue; + } + if (handle_as_role && is_invalid_role_name(user_name->user.str)) { append_user(&wrong_users, user_name); @@ -9189,7 +9210,15 @@ bool mysql_drop_user(THD *thd, List &list, bool handle_as_role) while ((tmp_user_name= user_list++)) { user_name= get_current_user(thd, tmp_user_name, false); - if (!user_name || handle_as_role != user_name->is_role()) + if (!user_name) + { + thd->clear_error(); + append_str(&wrong_users, STRING_WITH_LEN("CURRENT_ROLE")); + result= TRUE; + continue; + } + + if (handle_as_role != user_name->is_role()) { append_user(&wrong_users, tmp_user_name); result= TRUE; From 320b85286bd5ebb41d59ff526b74277661906fdd Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 2 Nov 2013 16:26:35 +0100 Subject: [PATCH 2/2] grant/revoke ... to/from current_role --- .../suite/roles/grant_revoke_current.result | 27 +++++++++++++++++++ .../suite/roles/grant_revoke_current.test | 24 +++++++++++++++++ sql/sql_yacc.yy | 4 ++- 3 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 mysql-test/suite/roles/grant_revoke_current.result create mode 100644 mysql-test/suite/roles/grant_revoke_current.test diff --git a/mysql-test/suite/roles/grant_revoke_current.result b/mysql-test/suite/roles/grant_revoke_current.result new file mode 100644 index 00000000000..644454685b4 --- /dev/null +++ b/mysql-test/suite/roles/grant_revoke_current.result @@ -0,0 +1,27 @@ +grant select on *.* to current_role; +ERROR 0L000: Invalid definer +revoke select on *.* from current_role; +ERROR 0L000: Invalid definer +revoke all, grant option from current_role; +ERROR 0L000: Invalid definer +create role r1; +grant insert on test.* to r1; +grant r1 to current_user; +set role r1; +select current_role(); +current_role() +r1 +grant select on *.* to current_role; +show grants for current_role; +Grants for r1 +GRANT SELECT ON *.* TO 'r1' +GRANT INSERT ON `test`.* TO 'r1' +revoke insert on test.* from current_role; +show grants for current_role; +Grants for r1 +GRANT SELECT ON *.* TO 'r1' +revoke all, grant option from current_role; +show grants for current_role; +Grants for r1 +GRANT USAGE ON *.* TO 'r1' +drop role r1; diff --git a/mysql-test/suite/roles/grant_revoke_current.test b/mysql-test/suite/roles/grant_revoke_current.test new file mode 100644 index 00000000000..96a27fd5697 --- /dev/null +++ b/mysql-test/suite/roles/grant_revoke_current.test @@ -0,0 +1,24 @@ +--source include/not_embedded.inc + +--error ER_MALFORMED_DEFINER +grant select on *.* to current_role; +--error ER_MALFORMED_DEFINER +revoke select on *.* from current_role; +--error ER_MALFORMED_DEFINER +revoke all, grant option from current_role; + +create role r1; +grant insert on test.* to r1; +grant r1 to current_user; +set role r1; +select current_role(); + +grant select on *.* to current_role; +show grants for current_role; +revoke insert on test.* from current_role; +show grants for current_role; +revoke all, grant option from current_role; +show grants for current_role; + +drop role r1; + diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index f0d68c453be..19d8d1854a1 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -14356,9 +14356,11 @@ role_list: current_role: CURRENT_ROLE optional_braces { - if (!($$=(LEX_USER*) thd->alloc(sizeof(LEX_USER)))) + if (!($$=(LEX_USER*) thd->calloc(sizeof(LEX_USER)))) MYSQL_YYABORT; $$->user= current_role; + $$->plugin= empty_lex_str; + $$->auth= empty_lex_str; } ;