summaryrefslogtreecommitdiff
path: root/sql/sql_parse.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_parse.cc')
-rw-r--r--sql/sql_parse.cc174
1 files changed, 109 insertions, 65 deletions
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 0353ec7fde9..92d628bbfe1 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -401,8 +401,11 @@ void init_update_queries(void)
sql_command_flags[SQLCOM_CREATE_USER]= CF_CHANGES_DATA;
sql_command_flags[SQLCOM_RENAME_USER]= CF_CHANGES_DATA;
sql_command_flags[SQLCOM_DROP_USER]= CF_CHANGES_DATA;
+ sql_command_flags[SQLCOM_CREATE_ROLE]= CF_CHANGES_DATA;
sql_command_flags[SQLCOM_GRANT]= CF_CHANGES_DATA;
+ sql_command_flags[SQLCOM_GRANT_ROLE]= CF_CHANGES_DATA;
sql_command_flags[SQLCOM_REVOKE]= CF_CHANGES_DATA;
+ sql_command_flags[SQLCOM_REVOKE_ROLE]= CF_CHANGES_DATA;
sql_command_flags[SQLCOM_OPTIMIZE]= CF_CHANGES_DATA;
/*
@todo SQLCOM_CREATE_FUNCTION should have CF_AUTO_COMMIT_TRANS
@@ -461,9 +464,13 @@ void init_update_queries(void)
sql_command_flags[SQLCOM_CREATE_USER]|= CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_DROP_USER]|= CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_RENAME_USER]|= CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_CREATE_ROLE]|= CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_DROP_ROLE]|= CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_REVOKE_ALL]= CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_REVOKE]|= CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_REVOKE_ROLE]|= CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_GRANT]|= CF_AUTO_COMMIT_TRANS;
+ sql_command_flags[SQLCOM_GRANT_ROLE]|= CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_ASSIGN_TO_KEYCACHE]= CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_PRELOAD_KEYS]= CF_AUTO_COMMIT_TRANS;
@@ -664,7 +671,8 @@ static void handle_bootstrap_impl(THD *thd)
#endif /* EMBEDDED_LIBRARY */
thd->security_ctx->user= (char*) my_strdup("boot", MYF(MY_WME));
- thd->security_ctx->priv_user[0]= thd->security_ctx->priv_host[0]=0;
+ thd->security_ctx->priv_user[0]= thd->security_ctx->priv_host[0]=
+ thd->security_ctx->priv_role[0]= 0;
/*
Make the "client" handle multiple results. This is necessary
to enable stored procedures with SELECTs and Dynamic SQL
@@ -1878,8 +1886,8 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
DBUG_RETURN(1);
lex->query_tables_last= query_tables_last;
break;
- }
#endif
+ }
case SCH_PROFILES:
/*
Mark this current profiling record to be discarded. We don't
@@ -2006,7 +2014,6 @@ static void reset_one_shot_variables(THD *thd)
}
-static
bool sp_process_definer(THD *thd)
{
DBUG_ENTER("sp_process_definer");
@@ -2043,7 +2050,7 @@ bool sp_process_definer(THD *thd)
Query_arena original_arena;
Query_arena *ps_arena= thd->activate_stmt_arena_if_needed(&original_arena);
- lex->definer= create_default_definer(thd);
+ lex->definer= create_default_definer(thd, false);
if (ps_arena)
thd->restore_active_arena(ps_arena, &original_arena);
@@ -2057,20 +2064,24 @@ bool sp_process_definer(THD *thd)
}
else
{
+ LEX_USER *d= lex->definer= get_current_user(thd, lex->definer);
+ if (!d)
+ DBUG_RETURN(TRUE);
+
/*
- If the specified definer differs from the current user, we
+ If the specified definer differs from the current user or role, we
should check that the current user has SUPER privilege (in order
to create a stored routine under another user one must have
SUPER privilege).
*/
- if ((strcmp(lex->definer->user.str, thd->security_ctx->priv_user) ||
- my_strcasecmp(system_charset_info, lex->definer->host.str,
- thd->security_ctx->priv_host)) &&
- check_global_access(thd, SUPER_ACL, true))
- {
- my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER");
+ bool curuser= !strcmp(d->user.str, thd->security_ctx->priv_user);
+ bool currole= !curuser && !strcmp(d->user.str, thd->security_ctx->priv_role);
+ bool curuserhost= curuser && d->host.str &&
+ !my_strcasecmp(system_charset_info, d->host.str,
+ thd->security_ctx->priv_host);
+ if (!curuserhost && !currole &&
+ check_global_access(thd, SUPER_ACL, false))
DBUG_RETURN(TRUE);
- }
}
/* Check that the specified definer exists. Emit a warning if not. */
@@ -3991,22 +4002,26 @@ end_with_restore_list:
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
case SQLCOM_CREATE_USER:
+ case SQLCOM_CREATE_ROLE:
{
if (check_access(thd, INSERT_ACL, "mysql", NULL, NULL, 1, 1) &&
check_global_access(thd,CREATE_USER_ACL))
break;
/* Conditionally writes to binlog */
- if (!(res= mysql_create_user(thd, lex->users_list)))
+ if (!(res= mysql_create_user(thd, lex->users_list,
+ lex->sql_command == SQLCOM_CREATE_ROLE)))
my_ok(thd);
break;
}
case SQLCOM_DROP_USER:
+ case SQLCOM_DROP_ROLE:
{
if (check_access(thd, DELETE_ACL, "mysql", NULL, NULL, 1, 1) &&
check_global_access(thd,CREATE_USER_ACL))
break;
/* Conditionally writes to binlog */
- if (!(res= mysql_drop_user(thd, lex->users_list)))
+ if (!(res= mysql_drop_user(thd, lex->users_list,
+ lex->sql_command == SQLCOM_DROP_ROLE)))
my_ok(thd);
break;
}
@@ -4026,9 +4041,6 @@ end_with_restore_list:
check_global_access(thd,CREATE_USER_ACL))
break;
- /* Replicate current user as grantor */
- thd->binlog_invoker();
-
/* Conditionally writes to binlog */
if (!(res = mysql_revoke_all(thd, lex->users_list)))
my_ok(thd);
@@ -4046,42 +4058,58 @@ end_with_restore_list:
goto error;
/* Replicate current user as grantor */
- thd->binlog_invoker();
+ thd->binlog_invoker(false);
if (thd->security_ctx->user) // If not replication
{
- LEX_USER *user, *tmp_user;
+ LEX_USER *user;
bool first_user= TRUE;
List_iterator <LEX_USER> user_list(lex->users_list);
- while ((tmp_user= user_list++))
+ while ((user= user_list++))
{
- if (!(user= get_current_user(thd, tmp_user)))
- goto error;
if (specialflag & SPECIAL_NO_RESOLVE &&
hostname_requires_resolving(user->host.str))
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_WARN_HOSTNAME_WONT_WORK,
ER(ER_WARN_HOSTNAME_WONT_WORK));
- // Are we trying to change a password of another user
- DBUG_ASSERT(user->host.str != 0);
/*
GRANT/REVOKE PROXY has the target user as a first entry in the list.
*/
if (lex->type == TYPE_ENUM_PROXY && first_user)
{
+ if (!(user= get_current_user(thd, user)) || !user->host.str)
+ goto error;
+
first_user= FALSE;
if (acl_check_proxy_grant_access (thd, user->host.str, user->user.str,
lex->grant & GRANT_ACL))
goto error;
}
- else if (is_acl_user(user->host.str, user->user.str) &&
- user->password.str &&
- check_change_password (thd, user->host.str, user->user.str,
- user->password.str,
- user->password.length))
- goto error;
+ else if (user->password.str)
+ {
+ // Are we trying to change a password of another user?
+ const char *hostname= user->host.str, *username=user->user.str;
+ bool userok;
+ if (username == current_user.str)
+ {
+ username= thd->security_ctx->priv_user;
+ hostname= thd->security_ctx->priv_host;
+ userok= true;
+ }
+ else
+ {
+ if (!hostname)
+ hostname= host_not_specified.str;
+ userok= is_acl_user(hostname, username);
+ }
+
+ if (userok && check_change_password (thd, hostname, username,
+ user->password.str,
+ user->password.length))
+ goto error;
+ }
}
}
if (first_table)
@@ -4125,9 +4153,9 @@ end_with_restore_list:
else
{
/* Conditionally writes to binlog */
- res = mysql_grant(thd, select_lex->db, lex->users_list, lex->grant,
- lex->sql_command == SQLCOM_REVOKE,
- lex->type == TYPE_ENUM_PROXY);
+ res= mysql_grant(thd, select_lex->db, lex->users_list, lex->grant,
+ lex->sql_command == SQLCOM_REVOKE,
+ lex->type == TYPE_ENUM_PROXY);
}
if (!res)
{
@@ -4146,6 +4174,14 @@ end_with_restore_list:
}
break;
}
+ case SQLCOM_REVOKE_ROLE:
+ case SQLCOM_GRANT_ROLE:
+ {
+ if (!(res= mysql_grant_role(thd, lex->users_list,
+ lex->sql_command != SQLCOM_GRANT_ROLE)))
+ my_ok(thd);
+ break;
+ }
#endif /*!NO_EMBEDDED_ACCESS_CHECKS*/
case SQLCOM_RESET:
/*
@@ -4243,11 +4279,17 @@ end_with_restore_list:
#ifndef NO_EMBEDDED_ACCESS_CHECKS
case SQLCOM_SHOW_GRANTS:
{
- LEX_USER *grant_user= get_current_user(thd, lex->grant_user);
+ LEX_USER *grant_user= lex->grant_user;
if (!grant_user)
goto error;
- if ((thd->security_ctx->priv_user &&
- !strcmp(thd->security_ctx->priv_user, grant_user->user.str)) ||
+
+ if (grant_user->user.str &&
+ !strcmp(thd->security_ctx->priv_user, grant_user->user.str))
+ grant_user->user= current_user;
+
+ if (grant_user->user.str == current_user.str ||
+ grant_user->user.str == current_role.str ||
+ grant_user->user.str == current_user_and_current_role.str ||
!check_access(thd, SELECT_ACL, "mysql", NULL, NULL, 1, 0))
{
res = mysql_show_grants(thd, grant_user);
@@ -5363,8 +5405,12 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
if (!(sctx->master_access & SELECT_ACL))
{
if (db && (!thd->db || db_is_pattern || strcmp(db, thd->db)))
+ {
db_access= acl_get(sctx->host, sctx->ip, sctx->priv_user, db,
db_is_pattern);
+ if (sctx->priv_role[0])
+ db_access|= acl_get("", "", sctx->priv_role, db, db_is_pattern);
+ }
else
{
/* get access for current db */
@@ -5408,8 +5454,14 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
}
if (db && (!thd->db || db_is_pattern || strcmp(db,thd->db)))
+ {
db_access= acl_get(sctx->host, sctx->ip, sctx->priv_user, db,
db_is_pattern);
+ if (sctx->priv_role[0])
+ {
+ db_access|= acl_get("", "", sctx->priv_role, db, db_is_pattern);
+ }
+ }
else
db_access= sctx->db_access;
DBUG_PRINT("info",("db_access: %lu want_access: %lu",
@@ -8016,16 +8068,23 @@ Item *negate_expression(THD *thd, Item *expr)
@param[out] definer definer
*/
-void get_default_definer(THD *thd, LEX_USER *definer)
+void get_default_definer(THD *thd, LEX_USER *definer, bool role)
{
const Security_context *sctx= thd->security_ctx;
- definer->user.str= (char *) sctx->priv_user;
+ if (role)
+ {
+ definer->user.str= const_cast<char*>(sctx->priv_role);
+ definer->host= empty_lex_str;
+ }
+ else
+ {
+ definer->user.str= const_cast<char*>(sctx->priv_user);
+ definer->host.str= const_cast<char*>(sctx->priv_host);
+ definer->host.length= strlen(definer->host.str);
+ }
definer->user.length= strlen(definer->user.str);
- definer->host.str= (char *) sctx->priv_host;
- definer->host.length= strlen(definer->host.str);
-
definer->password= null_lex_str;
definer->plugin= empty_lex_str;
definer->auth= empty_lex_str;
@@ -8043,16 +8102,22 @@ void get_default_definer(THD *thd, LEX_USER *definer)
- On error, return 0.
*/
-LEX_USER *create_default_definer(THD *thd)
+LEX_USER *create_default_definer(THD *thd, bool role)
{
LEX_USER *definer;
if (! (definer= (LEX_USER*) thd->alloc(sizeof(LEX_USER))))
return 0;
- thd->get_definer(definer);
+ thd->get_definer(definer, role);
- return definer;
+ if (role && definer->user.length == 0)
+ {
+ my_error(ER_MALFORMED_DEFINER, MYF(0));
+ return 0;
+ }
+ else
+ return definer;
}
@@ -8088,27 +8153,6 @@ LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name)
/**
- Retuns information about user or current user.
-
- @param[in] thd thread handler
- @param[in] user user
-
- @return
- - On success, return a valid pointer to initialized
- LEX_USER, which contains user information.
- - On error, return 0.
-*/
-
-LEX_USER *get_current_user(THD *thd, LEX_USER *user)
-{
- if (!user->user.str) // current_user
- return create_default_definer(thd);
-
- return user;
-}
-
-
-/**
Check that byte length of a string does not exceed some limit.
@param str string to be checked