Commit 7d4e47bc authored by Sergei Golubchik's avatar Sergei Golubchik

remove ER_RESERVED_ROLE.

Only allow NONE instead of a role name in SET ROLE.
Don't allow PUBLIC as a role name anywhere (to be fixed later)
Fix db_access calculations on SET ROLE
Reduce the size of role_grants and parent_grantee per-user/role arrays.
Fix the wording and specify the correct sqlstate for ER_INVALID_ROLE
parent 918c622a
create role role1;
create role none;
ERROR OP000: Invalid role specification `none`.
create role public;
ERROR OP000: Invalid role specification `public`.
drop role none;
ERROR HY000: Operation DROP ROLE failed for 'none'
grant none to role1;
ERROR OP000: Invalid role specification `none`.
grant role1 to none;
ERROR OP000: Invalid role specification `none`.
grant select on *.* to none;
ERROR OP000: Invalid role specification `none`.
grant public to role1;
ERROR OP000: Invalid role specification `public`.
grant role1 to public;
ERROR OP000: Invalid role specification `public`.
grant select on *.* to public;
ERROR OP000: Invalid role specification `public`.
grant role1 to current_role;
ERROR OP000: Invalid role specification `NONE`.
revoke none from role1;
ERROR OP000: Invalid role specification `none`.
revoke role1 from none;
ERROR OP000: Invalid role specification `none`.
revoke select on *.* from none;
ERROR OP000: Invalid role specification `none`.
revoke public from role1;
ERROR OP000: Invalid role specification `public`.
revoke role1 from public;
ERROR OP000: Invalid role specification `public`.
revoke select on *.* from public;
ERROR OP000: Invalid role specification `public`.
show grants for none;
ERROR OP000: Invalid role specification `none`.
show grants for public;
ERROR OP000: Invalid role specification `public`.
create definer=none view test.v1 as select 1;
ERROR OP000: Invalid role specification `none`.
create definer=public view test.v1 as select 1;
ERROR OP000: Invalid role specification `public`.
drop role role1;
optimize table mysql.user;
Table Op Msg_type Msg_text
mysql.user optimize status OK
insert mysql.user (user, is_role) values ('none', 'Y'), ('public', 'Y');
Warnings:
Warning 1364 Field 'ssl_cipher' doesn't have a default value
Warning 1364 Field 'x509_issuer' doesn't have a default value
Warning 1364 Field 'x509_subject' doesn't have a default value
Warning 1364 Field 'authentication_string' doesn't have a default value
flush privileges;
Warnings:
Error 1958 Invalid role specification `none`.
Error 1958 Invalid role specification `public`.
delete from mysql.user where is_role='Y';
...@@ -66,7 +66,7 @@ Grants for test_user@localhost ...@@ -66,7 +66,7 @@ Grants for test_user@localhost
GRANT USAGE ON *.* TO 'test_user'@'localhost' GRANT USAGE ON *.* TO 'test_user'@'localhost'
GRANT test_role1 TO 'test_user'@'localhost' GRANT test_role1 TO 'test_user'@'localhost'
set role test_role2; set role test_role2;
ERROR HY000: The role 'test_role2' has not been granted or is invalid. ERROR OP000: Invalid role specification `test_role2`.
select current_user(), current_role(); select current_user(), current_role();
current_user() current_role() current_user() current_role()
test_user@localhost NULL test_user@localhost NULL
......
create role role1;
--error ER_INVALID_ROLE
create role none;
--error ER_INVALID_ROLE
create role public;
--error ER_CANNOT_USER
drop role none;
--error ER_INVALID_ROLE
grant none to role1;
--error ER_INVALID_ROLE
grant role1 to none;
--error ER_INVALID_ROLE
grant select on *.* to none;
--error ER_INVALID_ROLE
grant public to role1;
--error ER_INVALID_ROLE
grant role1 to public;
--error ER_INVALID_ROLE
grant select on *.* to public;
--error ER_INVALID_ROLE
grant role1 to current_role;
--error ER_INVALID_ROLE
revoke none from role1;
--error ER_INVALID_ROLE
revoke role1 from none;
--error ER_INVALID_ROLE
revoke select on *.* from none;
--error ER_INVALID_ROLE
revoke public from role1;
--error ER_INVALID_ROLE
revoke role1 from public;
--error ER_INVALID_ROLE
revoke select on *.* from public;
--error ER_INVALID_ROLE
show grants for none;
--error ER_INVALID_ROLE
show grants for public;
--error ER_INVALID_ROLE
create definer=none view test.v1 as select 1;
--error ER_INVALID_ROLE
create definer=public view test.v1 as select 1;
drop role role1;
optimize table mysql.user; # to remove deleted rows and have stable row order
insert mysql.user (user, is_role) values ('none', 'Y'), ('public', 'Y');
flush privileges;
delete from mysql.user where is_role='Y';
...@@ -6562,15 +6562,12 @@ ER_NO_SUCH_QUERY ...@@ -6562,15 +6562,12 @@ ER_NO_SUCH_QUERY
eng "Unknown query id: %lld" eng "Unknown query id: %lld"
ger "Unbekannte Abfrage-ID: %lld" ger "Unbekannte Abfrage-ID: %lld"
rus "Неизвестный номер запроса: %lld" rus "Неизвестный номер запроса: %lld"
ER_INVALID_ROLE ER_INVALID_ROLE OP000
eng "The role '%s' has not been granted or is invalid." eng "Invalid role specification %`s."
rum "Rolul '%s' este invalid sau nu a fost acordat." rum "Rolul %`s este invalid."
ER_INVALID_CURRENT_USER ER_INVALID_CURRENT_USER
eng "The current user is invalid." eng "The current user is invalid."
rum "Utilizatorul curent este invalid." rum "Utilizatorul curent este invalid."
ER_RESERVED_ROLE
eng "Role name '%s' is reserved."
rum "Numele de rol '%s' este rezervat."
ER_CANNOT_GRANT_ROLE ER_CANNOT_GRANT_ROLE
eng "Cannot grant role '%s' to: %s." eng "Cannot grant role '%s' to: %s."
rum "Rolul '%s' nu poate fi acordat catre: %s." rum "Rolul '%s' nu poate fi acordat catre: %s."
......
...@@ -190,10 +190,6 @@ LEX_STRING *default_auth_plugin_name= &native_password_plugin_name; ...@@ -190,10 +190,6 @@ LEX_STRING *default_auth_plugin_name= &native_password_plugin_name;
*/ */
LEX_STRING host_not_specified= { C_STRING_WITH_LEN("%") }; LEX_STRING host_not_specified= { C_STRING_WITH_LEN("%") };
/*
Constant used in the SET ROLE NONE command
*/
LEX_STRING none_role= { C_STRING_WITH_LEN("NONE") };
/* /*
Constants, used in the SHOW GRANTS command. Constants, used in the SHOW GRANTS command.
Their actual string values are irrelevant, they're always compared Their actual string values are irrelevant, they're always compared
...@@ -781,6 +777,16 @@ ACL_ROLE::ACL_ROLE(const char * rolename, ulong privileges, MEM_ROOT *root) : ...@@ -781,6 +777,16 @@ ACL_ROLE::ACL_ROLE(const char * rolename, ulong privileges, MEM_ROOT *root) :
} }
static bool is_invalid_role_name(const char *str)
{
if (strcasecmp(str, "PUBLIC") && strcasecmp(str, "NONE"))
return false;
my_error(ER_INVALID_ROLE, MYF(0), str);
return true;
}
static void free_acl_user(ACL_USER *user) static void free_acl_user(ACL_USER *user)
{ {
delete_dynamic(&(user->role_grants)); delete_dynamic(&(user->role_grants));
...@@ -1115,6 +1121,12 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) ...@@ -1115,6 +1121,12 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
*/ */
is_role= check_is_role(table); is_role= check_is_role(table);
if (is_role && is_invalid_role_name(username))
{
thd->clear_error();
continue;
}
if (!is_role && check_no_resolve && if (!is_role && check_no_resolve &&
hostname_requires_resolving(user.host.hostname)) hostname_requires_resolving(user.host.hostname))
{ {
...@@ -1254,14 +1266,15 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) ...@@ -1254,14 +1266,15 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
} }
(void) my_init_dynamic_array(&user.role_grants,sizeof(ACL_ROLE *), (void) my_init_dynamic_array(&user.role_grants,sizeof(ACL_ROLE *),
50, 100, MYF(0)); 8, 8, MYF(0));
if (is_role) { if (is_role)
{
DBUG_PRINT("info", ("Found role %s", user.user.str)); DBUG_PRINT("info", ("Found role %s", user.user.str));
ACL_ROLE *entry= new (&mem) ACL_ROLE(&user, &mem); ACL_ROLE *entry= new (&mem) ACL_ROLE(&user, &mem);
entry->role_grants = user.role_grants; entry->role_grants = user.role_grants;
(void) my_init_dynamic_array(&entry->parent_grantee, (void) my_init_dynamic_array(&entry->parent_grantee,
sizeof(ACL_USER_BASE *), 50, 100, MYF(0)); sizeof(ACL_USER_BASE *), 8, 8, MYF(0));
my_hash_insert(&acl_roles, (uchar *)entry); my_hash_insert(&acl_roles, (uchar *)entry);
continue; continue;
...@@ -1830,17 +1843,17 @@ bool acl_getroot(Security_context *sctx, char *user, char *host, ...@@ -1830,17 +1843,17 @@ bool acl_getroot(Security_context *sctx, char *user, char *host,
int acl_check_setrole(THD *thd, char *rolename, ulonglong *access) int acl_check_setrole(THD *thd, char *rolename, ulonglong *access)
{ {
ACL_ROLE *role;
ACL_USER_BASE *acl_user_base;
ACL_USER *UNINIT_VAR(acl_user);
bool is_granted= FALSE; bool is_granted= FALSE;
int result= 0; int result= 0;
/* clear role privileges */ /* clear role privileges */
mysql_mutex_lock(&acl_cache->lock); mysql_mutex_lock(&acl_cache->lock);
ACL_ROLE *role= find_acl_role(rolename); if (!strcasecmp(rolename, "NONE"))
ACL_USER_BASE *acl_user_base; {
ACL_USER *UNINIT_VAR(acl_user);
if (!strcasecmp(rolename, "NONE")) {
/* have to clear the privileges */ /* have to clear the privileges */
/* get the current user */ /* get the current user */
acl_user= find_user(thd->security_ctx->host, thd->security_ctx->user, acl_user= find_user(thd->security_ctx->host, thd->security_ctx->user,
...@@ -1856,6 +1869,8 @@ int acl_check_setrole(THD *thd, char *rolename, ulonglong *access) ...@@ -1856,6 +1869,8 @@ int acl_check_setrole(THD *thd, char *rolename, ulonglong *access)
goto end; goto end;
} }
role= find_acl_role(rolename);
/* According to SQL standard, the same error message must be presented */ /* According to SQL standard, the same error message must be presented */
if (role == NULL) { if (role == NULL) {
my_error(ER_INVALID_ROLE, MYF(0), rolename); my_error(ER_INVALID_ROLE, MYF(0), rolename);
...@@ -1907,20 +1922,18 @@ int acl_setrole(THD *thd, char *rolename, ulonglong access) ...@@ -1907,20 +1922,18 @@ int acl_setrole(THD *thd, char *rolename, ulonglong access)
Security_context *sctx= thd->security_ctx; Security_context *sctx= thd->security_ctx;
sctx->master_access= access; sctx->master_access= access;
if (thd->db) if (thd->db)
{ sctx->db_access= acl_get(sctx->host, sctx->ip, sctx->user, thd->db, FALSE);
sctx->db_access= acl_get(sctx->host,
sctx->ip, sctx->user, thd->db, FALSE);
sctx->db_access= acl_get("", "", rolename, thd->db, FALSE);
}
if (!strcasecmp(rolename, "NONE")) if (!strcasecmp(rolename, "NONE"))
{ {
thd->security_ctx->priv_role[0]= 0; thd->security_ctx->priv_role[0]= 0;
} }
else else
{ {
if (thd->db)
sctx->db_access|= acl_get("", "", rolename, thd->db, FALSE);
/* mark the current role */ /* mark the current role */
strmake(thd->security_ctx->priv_role, rolename, strmake_buf(thd->security_ctx->priv_role, rolename);
sizeof(thd->security_ctx->priv_role)-1);
} }
return 0; return 0;
} }
...@@ -2016,9 +2029,9 @@ static void acl_insert_role(const char *rolename, ulong privileges) ...@@ -2016,9 +2029,9 @@ static void acl_insert_role(const char *rolename, ulong privileges)
mysql_mutex_assert_owner(&acl_cache->lock); mysql_mutex_assert_owner(&acl_cache->lock);
entry= new (&mem) ACL_ROLE(rolename, privileges, &mem); entry= new (&mem) ACL_ROLE(rolename, privileges, &mem);
(void) my_init_dynamic_array(&entry->parent_grantee, (void) my_init_dynamic_array(&entry->parent_grantee,
sizeof(ACL_USER_BASE *), 50, 100, MYF(0)); sizeof(ACL_USER_BASE *), 8, 8, MYF(0));
(void) my_init_dynamic_array(&entry->role_grants,sizeof(ACL_ROLE *), (void) my_init_dynamic_array(&entry->role_grants,sizeof(ACL_ROLE *),
50, 100, MYF(0)); 8, 8, MYF(0));
my_hash_insert(&acl_roles, (uchar *)entry); my_hash_insert(&acl_roles, (uchar *)entry);
} }
...@@ -2070,7 +2083,7 @@ static void acl_insert_user(const char *user, const char *host, ...@@ -2070,7 +2083,7 @@ static void acl_insert_user(const char *user, const char *host,
acl_user.x509_issuer= x509_issuer ? strdup_root(&mem,x509_issuer) : 0; acl_user.x509_issuer= x509_issuer ? strdup_root(&mem,x509_issuer) : 0;
acl_user.x509_subject=x509_subject ? strdup_root(&mem,x509_subject) : 0; acl_user.x509_subject=x509_subject ? strdup_root(&mem,x509_subject) : 0;
(void) my_init_dynamic_array(&acl_user.role_grants, sizeof(ACL_USER *), (void) my_init_dynamic_array(&acl_user.role_grants, sizeof(ACL_USER *),
50, 100, MYF(0)); 8, 8, MYF(0));
(void) push_dynamic(&acl_users,(uchar*) &acl_user); (void) push_dynamic(&acl_users,(uchar*) &acl_user);
if (!acl_user.host.hostname || if (!acl_user.host.hostname ||
...@@ -5800,20 +5813,11 @@ bool mysql_grant_role(THD *thd, List <LEX_USER> &list, bool revoke) ...@@ -5800,20 +5813,11 @@ bool mysql_grant_role(THD *thd, List <LEX_USER> &list, bool revoke)
List_iterator <LEX_USER> user_list(list); List_iterator <LEX_USER> user_list(list);
granted_role= user_list++; granted_role= user_list++;
if (granted_role->user.str == current_role.str) if (!(granted_role= get_current_user(thd, granted_role)))
{ DBUG_RETURN(TRUE);
rolename.str= thd->security_ctx->priv_role;
if (!rolename.str[0]) DBUG_ASSERT(granted_role->is_role());
{ rolename= granted_role->user;
my_error(ER_RESERVED_ROLE, MYF(0), "NONE");
DBUG_RETURN(TRUE);
}
rolename.length= strlen(rolename.str);
}
else
{
rolename= granted_role->user;
}
TABLE_LIST tables; TABLE_LIST tables;
tables.init_one_table(C_STRING_WITH_LEN("mysql"), tables.init_one_table(C_STRING_WITH_LEN("mysql"),
...@@ -5856,6 +5860,7 @@ bool mysql_grant_role(THD *thd, List <LEX_USER> &list, bool revoke) ...@@ -5856,6 +5860,7 @@ bool mysql_grant_role(THD *thd, List <LEX_USER> &list, bool revoke)
/* current_role is NONE */ /* current_role is NONE */
if (!thd->security_ctx->priv_role[0]) if (!thd->security_ctx->priv_role[0])
{ {
my_error(ER_INVALID_ROLE, MYF(0), "NONE");
append_user(&wrong_users, "NONE", ""); append_user(&wrong_users, "NONE", "");
result= 1; result= 1;
continue; continue;
...@@ -5894,7 +5899,15 @@ bool mysql_grant_role(THD *thd, List <LEX_USER> &list, bool revoke) ...@@ -5894,7 +5899,15 @@ bool mysql_grant_role(THD *thd, List <LEX_USER> &list, bool revoke)
if ((role_as_user= find_acl_role(user->user.str))) if ((role_as_user= find_acl_role(user->user.str)))
hostname= empty_lex_str; hostname= empty_lex_str;
else else
{
if (is_invalid_role_name(username.str))
{
append_user(&wrong_users, username.str, "");
result= 1;
continue;
}
hostname= host_not_specified; hostname= host_not_specified;
}
} }
ROLE_GRANT_PAIR *hash_entry= find_role_grant_pair(&username, &hostname, ROLE_GRANT_PAIR *hash_entry= find_role_grant_pair(&username, &hostname,
...@@ -7453,6 +7466,13 @@ bool mysql_show_grants(THD *thd, LEX_USER *lex_user) ...@@ -7453,6 +7466,13 @@ bool mysql_show_grants(THD *thd, LEX_USER *lex_user)
else else
{ {
lex_user= get_current_user(thd, lex_user, false); lex_user= get_current_user(thd, lex_user, false);
if (!lex_user)
{
mysql_mutex_unlock(&acl_cache->lock);
mysql_rwlock_unlock(&LOCK_grant);
DBUG_RETURN(TRUE);
}
if (lex_user->is_role()) if (lex_user->is_role())
{ {
rolename= lex_user->user.str; rolename= lex_user->user.str;
...@@ -9111,6 +9131,13 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list, bool handle_as_role) ...@@ -9111,6 +9131,13 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list, bool handle_as_role)
while ((user_name= user_list++)) while ((user_name= user_list++))
{ {
if (handle_as_role && is_invalid_role_name(user_name->user.str))
{
append_user(&wrong_users, user_name);
result= TRUE;
continue;
}
if (!user_name->host.str) if (!user_name->host.str)
user_name->host= host_not_specified; user_name->host= host_not_specified;
...@@ -10511,6 +10538,9 @@ LEX_USER *get_current_user(THD *thd, LEX_USER *user, bool lock) ...@@ -10511,6 +10538,9 @@ LEX_USER *get_current_user(THD *thd, LEX_USER *user, bool lock)
if (!dup) if (!dup)
return 0; return 0;
if (is_invalid_role_name(user->user.str))
return 0;
if (lock) if (lock)
mysql_mutex_lock(&acl_cache->lock); mysql_mutex_lock(&acl_cache->lock);
if (find_acl_role(dup->user.str)) if (find_acl_role(dup->user.str))
......
...@@ -174,7 +174,6 @@ extern const TABLE_FIELD_DEF mysql_db_table_def; ...@@ -174,7 +174,6 @@ extern const TABLE_FIELD_DEF mysql_db_table_def;
extern bool mysql_user_table_is_in_short_password_format; extern bool mysql_user_table_is_in_short_password_format;
extern LEX_STRING host_not_specified; extern LEX_STRING host_not_specified;
extern LEX_STRING none_role;
extern LEX_STRING current_user; extern LEX_STRING current_user;
extern LEX_STRING current_role; extern LEX_STRING current_role;
extern LEX_STRING current_user_and_current_role; extern LEX_STRING current_user_and_current_role;
......
...@@ -14221,13 +14221,13 @@ revoke: ...@@ -14221,13 +14221,13 @@ revoke:
; ;
revoke_command: revoke_command:
grant_privileges ON opt_table grant_ident FROM user_list grant_privileges ON opt_table grant_ident FROM user_and_role_list
{ {
LEX *lex= Lex; LEX *lex= Lex;
lex->sql_command= SQLCOM_REVOKE; lex->sql_command= SQLCOM_REVOKE;
lex->type= 0; lex->type= 0;
} }
| grant_privileges ON FUNCTION_SYM grant_ident FROM user_list | grant_privileges ON FUNCTION_SYM grant_ident FROM user_and_role_list
{ {
LEX *lex= Lex; LEX *lex= Lex;
if (lex->columns.elements) if (lex->columns.elements)
...@@ -14238,7 +14238,7 @@ revoke_command: ...@@ -14238,7 +14238,7 @@ revoke_command:
lex->sql_command= SQLCOM_REVOKE; lex->sql_command= SQLCOM_REVOKE;
lex->type= TYPE_ENUM_FUNCTION; lex->type= TYPE_ENUM_FUNCTION;
} }
| grant_privileges ON PROCEDURE_SYM grant_ident FROM user_list | grant_privileges ON PROCEDURE_SYM grant_ident FROM user_and_role_list
{ {
LEX *lex= Lex; LEX *lex= Lex;
if (lex->columns.elements) if (lex->columns.elements)
...@@ -14249,7 +14249,7 @@ revoke_command: ...@@ -14249,7 +14249,7 @@ revoke_command:
lex->sql_command= SQLCOM_REVOKE; lex->sql_command= SQLCOM_REVOKE;
lex->type= TYPE_ENUM_PROCEDURE; lex->type= TYPE_ENUM_PROCEDURE;
} }
| ALL opt_privileges ',' GRANT OPTION FROM user_list | ALL opt_privileges ',' GRANT OPTION FROM user_and_role_list
{ {
Lex->sql_command = SQLCOM_REVOKE_ALL; Lex->sql_command = SQLCOM_REVOKE_ALL;
} }
...@@ -14319,7 +14319,7 @@ grant_command: ...@@ -14319,7 +14319,7 @@ grant_command:
lex->sql_command= SQLCOM_GRANT; lex->sql_command= SQLCOM_GRANT;
lex->type= TYPE_ENUM_PROXY; lex->type= TYPE_ENUM_PROXY;
} }
| grant_role TO_SYM user_and_role_list opt_with_admin_option | grant_role TO_SYM grant_list opt_with_admin_option
{ {
LEX *lex= Lex; LEX *lex= Lex;
lex->sql_command= SQLCOM_GRANT_ROLE; lex->sql_command= SQLCOM_GRANT_ROLE;
...@@ -14627,7 +14627,7 @@ grant_user: ...@@ -14627,7 +14627,7 @@ grant_user:
$1->plugin= $4; $1->plugin= $4;
$1->auth= $6; $1->auth= $6;
} }
| user | user_or_role
{ $$= $1; $1->password= null_lex_str; } { $$= $1; $1->password= null_lex_str; }
; ;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment