diff options
Diffstat (limited to 'sql/sql_acl.cc')
-rw-r--r-- | sql/sql_acl.cc | 167 |
1 files changed, 58 insertions, 109 deletions
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index b20dcc82fc2..af8685c458b 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -2047,70 +2047,10 @@ static int check_role_is_granted_callback(ACL_USER_BASE *grantee, void *data) return 0; } -/** - @brief Helper function to handle the error when using check_user_can_set_role() - @param type { ER_INVALID_CURRENT_USER - user doesn't exist, - -1: ER_INVALID_ROLE - role doesn't exist - 1: ER_INVALID_ROLE - role exist's but we don't know the does the - current user has access to see the role in - which case different type of error is generated - } - @param curr_user A current user - @param curr_host A current host - @param user A user for which we are setting the role - @param host A host of a user - @param rolename The name of the role - @param read_access A read access of mysql.* aquired -*/ -static void handle_error_set_role(int type, const char *curr_user, - const char* curr_host, const char *curr_ip, - const char *user, - const char *host, const char *rolename, - bool read_access) -{ - switch (type) - { - case ER_INVALID_CURRENT_USER: - my_error(ER_INVALID_CURRENT_USER, MYF(0), rolename); - break; - case -1: - /* Role doesn't exist at all */ - my_error(ER_INVALID_ROLE, MYF(0), rolename); - break; - case 1: - StringBuffer<1024> c_usr; - LEX_CSTRING role_lex; - role_lex.str= rolename; - role_lex.length= strlen(rolename); - - mysql_mutex_lock(&acl_cache->lock); - ACL_USER *cur_user= find_user_or_anon(curr_host, curr_user, curr_ip); - - if (cur_user && (read_access || traverse_role_graph_down(cur_user, &role_lex, - check_role_is_granted_callback, NULL) == -1)) - { - /* Role is not granted but current user can see the role */ - c_usr.append(user, strlen(user)); - c_usr.append('@'); - c_usr.append(host, strlen(host)); - my_printf_error(ER_INVALID_ROLE, "User %`s has not been granted a role %`s", - MYF(0), c_usr.c_ptr(), rolename); - } - else - { - /* Role is not granted and current user cannot see the role */ - my_error(ER_INVALID_ROLE, MYF(0), rolename); - } - mysql_mutex_unlock(&acl_cache->lock); - break; - } -} - -static int check_user_can_set_role(const char *user, const char *host, - const char *ip, const char *rolename, ulonglong *access, - ulong read_access= 0, const char *curr_user= NULL, - const char *curr_host= NULL, const char *curr_ip= NULL) +static int check_user_can_set_role(THD *thd, const char *user, const char *host, + const char *ip, const char *rolename, + ulonglong *access) { ACL_ROLE *role; ACL_USER_BASE *acl_user_base; @@ -2141,7 +2081,7 @@ static int check_user_can_set_role(const char *user, const char *host, /* According to SQL standard, the same error message must be presented */ if (role == NULL) { - result= -1; + result= ER_INVALID_ROLE; goto end; } @@ -2170,29 +2110,66 @@ static int check_user_can_set_role(const char *user, const char *host, { *access = acl_user->access | role->access; } + end: mysql_mutex_unlock(&acl_cache->lock); - if(result) + + /* We present different error messages depending if the user has sufficient + privileges to know if the INVALID_ROLE exists. */ + switch (result) { - handle_error_set_role(result, curr_user, - curr_host, curr_ip, user, host, - rolename, read_access); + case ER_INVALID_CURRENT_USER: + my_error(ER_INVALID_CURRENT_USER, MYF(0), rolename); + break; + case ER_INVALID_ROLE: + /* Role doesn't exist at all */ + my_error(ER_INVALID_ROLE, MYF(0), rolename); + break; + case 1: + StringBuffer<1024> c_usr; + LEX_CSTRING role_lex; + /* First, check if current user can see mysql database. */ + bool read_access= !check_access(thd, SELECT_ACL, "mysql", NULL, NULL, 1, 1); + + role_lex.str= rolename; + role_lex.length= strlen(rolename); + mysql_mutex_lock(&acl_cache->lock); + ACL_USER *cur_user= find_user_or_anon(thd->security_ctx->priv_host, + thd->security_ctx->priv_user, + thd->security_ctx->ip); + + /* If the current user does not have select priv to mysql database, + see if the current user can discover the role if it was granted to him. + */ + if (cur_user && (read_access || + traverse_role_graph_down(cur_user, &role_lex, + check_role_is_granted_callback, + NULL) == -1)) + { + /* Role is not granted but current user can see the role */ + c_usr.append(user, strlen(user)); + c_usr.append('@'); + c_usr.append(host, strlen(host)); + my_printf_error(ER_INVALID_ROLE, "User %`s has not been granted role %`s", + MYF(0), c_usr.c_ptr(), rolename); + } + else + { + /* Role is not granted and current user cannot see the role */ + my_error(ER_INVALID_ROLE, MYF(0), rolename); + } + mysql_mutex_unlock(&acl_cache->lock); + break; } return result; - } + int acl_check_setrole(THD *thd, char *rolename, ulonglong *access) { - ulong read_access= acl_get(thd->security_ctx->priv_host, thd->security_ctx->ip, - thd->security_ctx->priv_user, "mysql", 0); - - return check_user_can_set_role(thd->security_ctx->priv_user, - thd->security_ctx->host, thd->security_ctx->ip, rolename, access, - read_access, thd->security_ctx->priv_user, - thd->security_ctx->priv_host, thd->security_ctx->ip); - + return check_user_can_set_role(thd, thd->security_ctx->priv_user, + thd->security_ctx->host, thd->security_ctx->ip, rolename, access); } @@ -2974,27 +2951,13 @@ WSREP_ERROR_LABEL: int acl_check_set_default_role(THD *thd, const char *host, const char *user, const char *role) { - /* If the user has a read access on mysql.user table, it can see the roles, - granted or not and different kind of error may be allowed. - There is no handling of NONE and PUBLIC roles for read access. - Make sure role exists and that role is not the same as current_role. - */ - if (!check_access(thd, SELECT_ACL, "mysql", NULL, NULL, 1, 1) && - strcasecmp(role, "PUBLIC") && strcasecmp(role, "NONE") && - role != current_role.str) - { - if(check_access(thd, UPDATE_ACL, "mysql", NULL, NULL, 1, 1)) - { - ulong read_access= 1; - acl_set_default_role(thd, host, user, role, read_access); - return 1; - } - } - return check_alter_user(thd, host, user); + DBUG_ENTER("acl_check_set_default_role"); + DBUG_RETURN(check_alter_user(thd, host, user) || + check_user_can_set_role(thd, user, host, NULL, role, NULL)); } int acl_set_default_role(THD *thd, const char *host, const char *user, - const char *rolename, ulong read_access) + const char *rolename) { TABLE_LIST tables[TABLES_MAX]; TABLE *table; @@ -3012,20 +2975,6 @@ int acl_set_default_role(THD *thd, const char *host, const char *user, DBUG_PRINT("enter",("host: '%s' user: '%s' rolename: '%s'", safe_str(user), safe_str(host), safe_str(rolename))); - if (rolename == current_role.str) { - if (!thd->security_ctx->priv_role[0]) - rolename= "NONE"; - else - rolename= thd->security_ctx->priv_role; - } - - if (check_user_can_set_role(user, host, host, rolename, NULL, read_access, - thd->security_ctx->priv_user, thd->security_ctx->priv_host, - thd->security_ctx->ip)) - { - DBUG_RETURN(result); - } - if (!strcasecmp(rolename, "NONE")) clear_role= TRUE; |