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
This commit is contained in:
Sergei Golubchik 2013-10-18 15:52:26 -07:00
parent 4ec26a7c2d
commit f74b9eca6e
7 changed files with 187 additions and 50 deletions

View File

@ -0,0 +1,56 @@
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';

View File

@ -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

View File

@ -0,0 +1,55 @@
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';

View File

@ -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."

View File

@ -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) :
} }
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)
*/ */
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)
} }
(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,
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)
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)
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)
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,
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)
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)
/* 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)
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)
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)
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)
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))

View File

@ -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;

View File

@ -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:
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:
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:
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:
$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; }
; ;