1
0
mirror of https://github.com/MariaDB/server.git synced 2025-09-02 09:41:40 +03:00

10.0-base merge (roles)

This commit is contained in:
Sergei Golubchik
2013-10-29 15:08:44 +01:00
248 changed files with 10725 additions and 1899 deletions

View File

@@ -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;
}
@@ -8087,27 +8152,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.