diff options
author | Sergei Golubchik <sergii@pisem.net> | 2013-10-18 15:52:26 -0700 |
---|---|---|
committer | Sergei Golubchik <sergii@pisem.net> | 2013-10-18 15:52:26 -0700 |
commit | f74b9eca6ebe83367fd742f6f537814dcdd6cc2f (patch) | |
tree | 0f411f14c6e73ca4720966e73e94e9d22a460d70 | |
parent | 4ec26a7c2dbb2a49fbedf14f0ca7d126703916ae (diff) | |
download | mariadb-git-f74b9eca6ebe83367fd742f6f537814dcdd6cc2f.tar.gz |
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
-rw-r--r-- | mysql-test/r/acl_roles_none_public.result | 56 | ||||
-rw-r--r-- | mysql-test/r/acl_roles_set_role-recursive.result | 2 | ||||
-rw-r--r-- | mysql-test/t/acl_roles_none_public.test | 55 | ||||
-rw-r--r-- | sql/share/errmsg-utf8.txt | 9 | ||||
-rw-r--r-- | sql/sql_acl.cc | 102 | ||||
-rw-r--r-- | sql/sql_acl.h | 1 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 12 |
7 files changed, 187 insertions, 50 deletions
diff --git a/mysql-test/r/acl_roles_none_public.result b/mysql-test/r/acl_roles_none_public.result new file mode 100644 index 00000000000..a0c7a0db707 --- /dev/null +++ b/mysql-test/r/acl_roles_none_public.result @@ -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'; diff --git a/mysql-test/r/acl_roles_set_role-recursive.result b/mysql-test/r/acl_roles_set_role-recursive.result index 54965157612..a4442d8caa3 100644 --- a/mysql-test/r/acl_roles_set_role-recursive.result +++ b/mysql-test/r/acl_roles_set_role-recursive.result @@ -66,7 +66,7 @@ Grants for test_user@localhost GRANT USAGE ON *.* TO 'test_user'@'localhost' GRANT test_role1 TO 'test_user'@'localhost' 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(); current_user() current_role() test_user@localhost NULL diff --git a/mysql-test/t/acl_roles_none_public.test b/mysql-test/t/acl_roles_none_public.test new file mode 100644 index 00000000000..af3d6bf3f68 --- /dev/null +++ b/mysql-test/t/acl_roles_none_public.test @@ -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'; + diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 6135f8f1b96..cf2aa33f96e 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -6562,15 +6562,12 @@ ER_NO_SUCH_QUERY eng "Unknown query id: %lld" ger "Unbekannte Abfrage-ID: %lld" rus "Неизвестный номер запроса: %lld" -ER_INVALID_ROLE - eng "The role '%s' has not been granted or is invalid." - rum "Rolul '%s' este invalid sau nu a fost acordat." +ER_INVALID_ROLE OP000 + eng "Invalid role specification %`s." + rum "Rolul %`s este invalid." ER_INVALID_CURRENT_USER eng "The current user is 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 eng "Cannot grant role '%s' to: %s." rum "Rolul '%s' nu poate fi acordat catre: %s." diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index b188b909600..a57f2d9f115 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -191,10 +191,6 @@ LEX_STRING *default_auth_plugin_name= &native_password_plugin_name; 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. Their actual string values are irrelevant, they're always compared as pointers to these string constants. @@ -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) { 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); + if (is_role && is_invalid_role_name(username)) + { + thd->clear_error(); + continue; + } + if (!is_role && check_no_resolve && 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 *), - 50, 100, MYF(0)); + 8, 8, MYF(0)); - if (is_role) { + if (is_role) + { DBUG_PRINT("info", ("Found role %s", user.user.str)); ACL_ROLE *entry= new (&mem) ACL_ROLE(&user, &mem); entry->role_grants = user.role_grants; (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); 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) { + ACL_ROLE *role; + ACL_USER_BASE *acl_user_base; + ACL_USER *UNINIT_VAR(acl_user); bool is_granted= FALSE; int result= 0; /* clear role privileges */ mysql_mutex_lock(&acl_cache->lock); - ACL_ROLE *role= find_acl_role(rolename); - ACL_USER_BASE *acl_user_base; - ACL_USER *UNINIT_VAR(acl_user); - - if (!strcasecmp(rolename, "NONE")) { + if (!strcasecmp(rolename, "NONE")) + { /* have to clear the privileges */ /* get the current 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; } + role= find_acl_role(rolename); + /* According to SQL standard, the same error message must be presented */ if (role == NULL) { 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; sctx->master_access= access; if (thd->db) - { - sctx->db_access= acl_get(sctx->host, - sctx->ip, sctx->user, thd->db, FALSE); - sctx->db_access= acl_get("", "", rolename, thd->db, FALSE); - } + sctx->db_access= acl_get(sctx->host, sctx->ip, sctx->user, thd->db, FALSE); + if (!strcasecmp(rolename, "NONE")) { thd->security_ctx->priv_role[0]= 0; } else { + if (thd->db) + sctx->db_access|= acl_get("", "", rolename, thd->db, FALSE); /* mark the current role */ - strmake(thd->security_ctx->priv_role, rolename, - sizeof(thd->security_ctx->priv_role)-1); + strmake_buf(thd->security_ctx->priv_role, rolename); } return 0; } @@ -2016,9 +2029,9 @@ static void acl_insert_role(const char *rolename, ulong privileges) mysql_mutex_assert_owner(&acl_cache->lock); entry= new (&mem) ACL_ROLE(rolename, privileges, &mem); (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 *), - 50, 100, MYF(0)); + 8, 8, MYF(0)); 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_subject=x509_subject ? strdup_root(&mem,x509_subject) : 0; (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); 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); granted_role= user_list++; - if (granted_role->user.str == current_role.str) - { - rolename.str= thd->security_ctx->priv_role; - if (!rolename.str[0]) - { - my_error(ER_RESERVED_ROLE, MYF(0), "NONE"); - DBUG_RETURN(TRUE); - } - rolename.length= strlen(rolename.str); - } - else - { - rolename= granted_role->user; - } + if (!(granted_role= get_current_user(thd, granted_role))) + DBUG_RETURN(TRUE); + + DBUG_ASSERT(granted_role->is_role()); + rolename= granted_role->user; TABLE_LIST tables; 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 */ if (!thd->security_ctx->priv_role[0]) { + my_error(ER_INVALID_ROLE, MYF(0), "NONE"); append_user(&wrong_users, "NONE", ""); result= 1; 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))) hostname= empty_lex_str; else + { + if (is_invalid_role_name(username.str)) + { + append_user(&wrong_users, username.str, ""); + result= 1; + continue; + } hostname= host_not_specified; + } } 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 { 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()) { 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++)) { + 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) user_name->host= host_not_specified; @@ -10511,6 +10538,9 @@ LEX_USER *get_current_user(THD *thd, LEX_USER *user, bool lock) if (!dup) return 0; + if (is_invalid_role_name(user->user.str)) + return 0; + if (lock) mysql_mutex_lock(&acl_cache->lock); if (find_acl_role(dup->user.str)) diff --git a/sql/sql_acl.h b/sql/sql_acl.h index 8766f78ecee..1b09b4bbdd4 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -174,7 +174,6 @@ extern const TABLE_FIELD_DEF mysql_db_table_def; extern bool mysql_user_table_is_in_short_password_format; extern LEX_STRING host_not_specified; -extern LEX_STRING none_role; extern LEX_STRING current_user; extern LEX_STRING current_role; extern LEX_STRING current_user_and_current_role; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 5f68d79a763..38b6d990aa5 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -14221,13 +14221,13 @@ revoke: ; 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->sql_command= SQLCOM_REVOKE; 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; if (lex->columns.elements) @@ -14238,7 +14238,7 @@ revoke_command: lex->sql_command= SQLCOM_REVOKE; 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; if (lex->columns.elements) @@ -14249,7 +14249,7 @@ revoke_command: lex->sql_command= SQLCOM_REVOKE; 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; } @@ -14319,7 +14319,7 @@ grant_command: lex->sql_command= SQLCOM_GRANT; 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->sql_command= SQLCOM_GRANT_ROLE; @@ -14627,7 +14627,7 @@ grant_user: $1->plugin= $4; $1->auth= $6; } - | user + | user_or_role { $$= $1; $1->password= null_lex_str; } ; |