WL#2787 (part 2, ver 3 (merged)) changed securety context switching

This commit is contained in:
bell@sanja.is.com.ua 2005-09-15 22:29:07 +03:00
parent a9b3767874
commit aec371f910
27 changed files with 449 additions and 379 deletions

View File

@ -532,10 +532,9 @@ err:
int check_embedded_connection(MYSQL *mysql) int check_embedded_connection(MYSQL *mysql)
{ {
THD *thd= (THD*)mysql->thd; THD *thd= (THD*)mysql->thd;
thd->host= (char*)my_localhost; st_security_context *sctx= thd->security_ctx;
thd->host_or_ip= thd->host; sctx->host_or_ip= sctx->host= (char*)my_localhost;
thd->user= my_strdup(mysql->user, MYF(0)); sctx->priv_user= sctx->user= my_strdup(mysql->user, MYF(0));
thd->priv_user= thd->user;
return check_user(thd, COM_CONNECT, NULL, 0, thd->db, true); return check_user(thd, COM_CONNECT, NULL, 0, thd->db, true);
} }

View File

@ -121,7 +121,7 @@ call foo4();
Got one of the listed errors Got one of the listed errors
show warnings; show warnings;
Level Code Message Level Code Message
Error 1142 INSERT command denied to user 'zedjzlcsjhd'@'localhost' for table 't1' Error 1142 INSERT command denied to user 'zedjzlcsjhd'@'127.0.0.1' for table 't1'
Warning 1417 A routine failed and has neither NO SQL nor READS SQL DATA in its declaration and binary logging is enabled; if non-transactional tables were updated, the binary log will miss their changes Warning 1417 A routine failed and has neither NO SQL nor READS SQL DATA in its declaration and binary logging is enabled; if non-transactional tables were updated, the binary log will miss their changes
alter procedure foo4 sql security invoker; alter procedure foo4 sql security invoker;
call foo4(); call foo4();

View File

@ -563,25 +563,29 @@ innobase_mysql_print_thd(
use the default max length */ use the default max length */
{ {
const THD* thd; const THD* thd;
const st_security_context *sctx;
const char* s; const char* s;
thd = (const THD*) input_thd; thd = (const THD*) input_thd;
/* We probably want to have original user as part of debug output. */
sctx = &thd->main_security_ctx;
fprintf(f, "MySQL thread id %lu, query id %lu", fprintf(f, "MySQL thread id %lu, query id %lu",
thd->thread_id, (ulong) thd->query_id); thd->thread_id, (ulong) thd->query_id);
if (thd->host) { if (sctx->host) {
putc(' ', f); putc(' ', f);
fputs(thd->host, f); fputs(sctx->host, f);
} }
if (thd->ip) { if (sctx->ip) {
putc(' ', f); putc(' ', f);
fputs(thd->ip, f); fputs(sctx->ip, f);
} }
if (thd->user) { if (sctx->user) {
putc(' ', f); putc(' ', f);
fputs(thd->user, f); fputs(sctx->user, f);
} }
if ((s = thd->proc_info)) { if ((s = thd->proc_info)) {

View File

@ -3443,8 +3443,8 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
VIEW_ANY_ACL))) VIEW_ANY_ACL)))
{ {
my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0),
"ANY", thd->priv_user, thd->host_or_ip, "ANY", thd->security_ctx->priv_user,
field_name, tab); thd->security_ctx->host_or_ip, field_name, tab);
goto error; goto error;
} }
} }

View File

@ -4713,7 +4713,7 @@ Item_func_sp::execute(Item **itp)
Sub_statement_state statement_state; Sub_statement_state statement_state;
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
st_sp_security_context save_ctx; st_security_context *save_ctx;
#endif #endif
if (! m_sp && ! (m_sp= sp_find_function(thd, m_name, TRUE))) if (! m_sp && ! (m_sp= sp_find_function(thd, m_name, TRUE)))
@ -4723,11 +4723,11 @@ Item_func_sp::execute(Item **itp)
} }
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
if (check_routine_access(thd, EXECUTE_ACL, if (check_routine_access(thd, EXECUTE_ACL,
m_sp->m_db.str, m_sp->m_name.str, 0, 0)) m_sp->m_db.str, m_sp->m_name.str, 0, 0) ||
sp_change_security_context(thd, m_sp, &save_ctx))
goto error; goto error;
sp_change_security_context(thd, m_sp, &save_ctx); if (save_ctx &&
if (save_ctx.changed &&
check_routine_access(thd, EXECUTE_ACL, check_routine_access(thd, EXECUTE_ACL,
m_sp->m_db.str, m_sp->m_name.str, 0, 0)) m_sp->m_db.str, m_sp->m_name.str, 0, 0))
goto error_check_ctx; goto error_check_ctx;
@ -4750,7 +4750,7 @@ Item_func_sp::execute(Item **itp)
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
error_check_ctx: error_check_ctx:
sp_restore_security_context(thd, m_sp, &save_ctx); sp_restore_security_context(thd, save_ctx);
#endif #endif
error: error:

View File

@ -473,7 +473,8 @@ String *Item_func_des_decrypt::val_str(String *str)
{ {
uint key_number=(uint) (*res)[0] & 127; uint key_number=(uint) (*res)[0] & 127;
// Check if automatic key and that we have privilege to uncompress using it // Check if automatic key and that we have privilege to uncompress using it
if (!(current_thd->master_access & SUPER_ACL) || key_number > 9) if (!(current_thd->security_ctx->master_access & SUPER_ACL) ||
key_number > 9)
goto error; goto error;
VOID(pthread_mutex_lock(&LOCK_des_key_file)); VOID(pthread_mutex_lock(&LOCK_des_key_file));
@ -1601,13 +1602,13 @@ String *Item_func_user::val_str(String *str)
if (is_current) if (is_current)
{ {
user= thd->priv_user; user= thd->security_ctx->priv_user;
host= thd->priv_host; host= thd->security_ctx->priv_host;
} }
else else
{ {
user= thd->user; user= thd->main_security_ctx.user;
host= thd->host_or_ip; host= thd->main_security_ctx.priv_host;
} }
// For system threads (e.g. replication SQL thread) user may be empty // For system threads (e.g. replication SQL thread) user may be empty
@ -2518,7 +2519,7 @@ String *Item_load_file::val_str(String *str)
if (!(file_name= args[0]->val_str(str)) if (!(file_name= args[0]->val_str(str))
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
|| !(current_thd->master_access & FILE_ACL) || !(current_thd->security_ctx->master_access & FILE_ACL)
#endif #endif
) )
goto err; goto err;

View File

@ -1476,7 +1476,7 @@ bool MYSQL_LOG::write(THD *thd,enum enum_server_command command,
{ // Normal thread { // Normal thread
if ((thd->options & OPTION_LOG_OFF) if ((thd->options & OPTION_LOG_OFF)
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
&& (thd->master_access & SUPER_ACL) && (thd->security_ctx->master_access & SUPER_ACL)
#endif #endif
) )
{ {
@ -1935,10 +1935,12 @@ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length,
tmp_errno=errno; tmp_errno=errno;
} }
if (my_b_printf(&log_file, "# User@Host: %s[%s] @ %s [%s]\n", if (my_b_printf(&log_file, "# User@Host: %s[%s] @ %s [%s]\n",
thd->priv_user ? thd->priv_user : "", thd->security_ctx->priv_user ?
thd->user ? thd->user : "", thd->security_ctx->priv_user : "",
thd->host ? thd->host : "", thd->security_ctx->user ? thd->security_ctx->user : "",
thd->ip ? thd->ip : "") == (uint) -1) thd->security_ctx->host ? thd->security_ctx->host : "",
thd->security_ctx->ip ? thd->security_ctx->ip : "") ==
(uint) -1)
tmp_errno=errno; tmp_errno=errno;
} }
if (query_start_arg) if (query_start_arg)

View File

@ -484,6 +484,7 @@ typedef my_bool (*qc_engine_callback)(THD *thd, char *table_key,
#include "protocol.h" #include "protocol.h"
#include "sql_udf.h" #include "sql_udf.h"
class user_var_entry; class user_var_entry;
class st_security_context;
enum enum_var_type enum enum_var_type
{ {
OPT_DEFAULT= 0, OPT_SESSION, OPT_GLOBAL OPT_DEFAULT= 0, OPT_SESSION, OPT_GLOBAL
@ -515,7 +516,7 @@ bool delete_precheck(THD *thd, TABLE_LIST *tables);
bool insert_precheck(THD *thd, TABLE_LIST *tables); bool insert_precheck(THD *thd, TABLE_LIST *tables);
bool create_table_precheck(THD *thd, TABLE_LIST *tables, bool create_table_precheck(THD *thd, TABLE_LIST *tables,
TABLE_LIST *create_table); TABLE_LIST *create_table);
bool default_view_definer(THD *thd, st_lex_user *definer); bool default_view_definer(st_security_context *sctx, st_lex_user *definer);
enum enum_mysql_completiontype { enum enum_mysql_completiontype {

View File

@ -776,7 +776,9 @@ static void close_connections(void)
{ {
if (global_system_variables.log_warnings) if (global_system_variables.log_warnings)
sql_print_warning(ER(ER_FORCING_CLOSE),my_progname, sql_print_warning(ER(ER_FORCING_CLOSE),my_progname,
tmp->thread_id,tmp->user ? tmp->user : ""); tmp->thread_id,
(tmp->security_ctx->user ?
tmp->security_ctx->user : ""));
close_connection(tmp,0,0); close_connection(tmp,0,0);
} }
#endif #endif
@ -3582,7 +3584,7 @@ static void bootstrap(FILE *file)
thd->client_capabilities=0; thd->client_capabilities=0;
my_net_init(&thd->net,(st_vio*) 0); my_net_init(&thd->net,(st_vio*) 0);
thd->max_client_packet_length= thd->net.max_packet; thd->max_client_packet_length= thd->net.max_packet;
thd->master_access= ~(ulong)0; thd->security_ctx->master_access= ~(ulong)0;
thd->thread_id=thread_id++; thd->thread_id=thread_id++;
thread_count++; thread_count++;
@ -3922,7 +3924,7 @@ extern "C" pthread_handler_decl(handle_connections_sockets,
continue; continue;
} }
if (sock == unix_sock) if (sock == unix_sock)
thd->host=(char*) my_localhost; thd->security_ctx->host=(char*) my_localhost;
#ifdef __WIN__ #ifdef __WIN__
/* Set default wait_timeout */ /* Set default wait_timeout */
ulong wait_timeout= global_system_variables.net_wait_timeout * 1000; ulong wait_timeout= global_system_variables.net_wait_timeout * 1000;

View File

@ -66,13 +66,11 @@ static int init_failsafe_rpl_thread(THD* thd)
this thread has no other error reporting method). this thread has no other error reporting method).
*/ */
thd->system_thread = thd->bootstrap = 1; thd->system_thread = thd->bootstrap = 1;
thd->host_or_ip= ""; thd->security_ctx->skip_grants();
thd->client_capabilities = 0; thd->client_capabilities = 0;
my_net_init(&thd->net, 0); my_net_init(&thd->net, 0);
thd->net.read_timeout = slave_net_timeout; thd->net.read_timeout = slave_net_timeout;
thd->max_client_packet_length=thd->net.max_packet; thd->max_client_packet_length=thd->net.max_packet;
thd->master_access= ~(ulong)0;
thd->priv_user = 0;
pthread_mutex_lock(&LOCK_thread_count); pthread_mutex_lock(&LOCK_thread_count);
thd->thread_id = thread_id++; thd->thread_id = thread_id++;
pthread_mutex_unlock(&LOCK_thread_count); pthread_mutex_unlock(&LOCK_thread_count);

View File

@ -1092,9 +1092,10 @@ static void sys_default_init_slave(THD* thd, enum_var_type type)
static int sys_check_ftb_syntax(THD *thd, set_var *var) static int sys_check_ftb_syntax(THD *thd, set_var *var)
{ {
if (thd->master_access & SUPER_ACL) if (thd->security_ctx->master_access & SUPER_ACL)
return ft_boolean_check_syntax_string((byte*) var->value->str_value.c_ptr()) ? return (ft_boolean_check_syntax_string((byte*)
-1 : 0; var->value->str_value.c_ptr()) ?
-1 : 0);
else else
{ {
my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER"); my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER");
@ -2689,7 +2690,7 @@ static bool set_option_autocommit(THD *thd, set_var *var)
static int check_log_update(THD *thd, set_var *var) static int check_log_update(THD *thd, set_var *var)
{ {
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
if (!(thd->master_access & SUPER_ACL)) if (!(thd->security_ctx->master_access & SUPER_ACL))
{ {
my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER"); my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER");
return 1; return 1;
@ -2735,7 +2736,7 @@ static int check_pseudo_thread_id(THD *thd, set_var *var)
{ {
var->save_result.ulonglong_value= var->value->val_int(); var->save_result.ulonglong_value= var->value->val_int();
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
if (thd->master_access & SUPER_ACL) if (thd->security_ctx->master_access & SUPER_ACL)
return 0; return 0;
else else
{ {
@ -3100,10 +3101,10 @@ int set_var_password::check(THD *thd)
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
if (!user->host.str) if (!user->host.str)
{ {
if (thd->priv_host != 0) if (*thd->security_ctx->priv_host != 0)
{ {
user->host.str= (char *) thd->priv_host; user->host.str= (char *) thd->security_ctx->priv_host;
user->host.length= strlen(thd->priv_host); user->host.length= strlen(thd->security_ctx->priv_host);
} }
else else
{ {

View File

@ -2809,17 +2809,10 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
DBUG_ENTER("init_slave_thread"); DBUG_ENTER("init_slave_thread");
thd->system_thread = (thd_type == SLAVE_THD_SQL) ? thd->system_thread = (thd_type == SLAVE_THD_SQL) ?
SYSTEM_THREAD_SLAVE_SQL : SYSTEM_THREAD_SLAVE_IO; SYSTEM_THREAD_SLAVE_SQL : SYSTEM_THREAD_SLAVE_IO;
/* thd->security_ctx->skip_grants();
The two next lines are needed for replication of SP (CREATE PROCEDURE
needs a valid user to store in mysql.proc).
*/
thd->priv_user= (char *) "";
thd->priv_host[0]= '\0';
thd->host_or_ip= "";
thd->client_capabilities = 0; thd->client_capabilities = 0;
my_net_init(&thd->net, 0); my_net_init(&thd->net, 0);
thd->net.read_timeout = slave_net_timeout; thd->net.read_timeout = slave_net_timeout;
thd->master_access= ~(ulong)0;
thd->slave_thread = 1; thd->slave_thread = 1;
set_slave_thread_options(thd); set_slave_thread_options(thd);
/* /*

View File

@ -494,7 +494,8 @@ db_create_routine(THD *thd, int type, sp_head *sp)
else else
{ {
restore_record(table, s->default_values); // Get default values for fields restore_record(table, s->default_values); // Get default values for fields
strxmov(definer, thd->priv_user, "@", thd->priv_host, NullS); strxmov(definer, thd->security_ctx->priv_user, "@",
thd->security_ctx->priv_host, NullS);
if (table->s->fields != MYSQL_PROC_FIELD_COUNT) if (table->s->fields != MYSQL_PROC_FIELD_COUNT)
{ {
@ -569,7 +570,7 @@ db_create_routine(THD *thd, int type, sp_head *sp)
goto done; goto done;
} }
} }
if (!(thd->master_access & SUPER_ACL)) if (!(thd->security_ctx->master_access & SUPER_ACL))
{ {
my_message(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER, my_message(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER,
ER(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER), MYF(0)); ER(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER), MYF(0));

View File

@ -1636,8 +1636,10 @@ bool check_show_routine_access(THD *thd, sp_head *sp, bool *full_access)
tables.db= (char*) "mysql"; tables.db= (char*) "mysql";
tables.table_name= tables.alias= (char*) "proc"; tables.table_name= tables.alias= (char*) "proc";
*full_access= (!check_table_access(thd, SELECT_ACL, &tables, 1) || *full_access= (!check_table_access(thd, SELECT_ACL, &tables, 1) ||
(!strcmp(sp->m_definer_user.str, thd->priv_user) && (!strcmp(sp->m_definer_user.str,
!strcmp(sp->m_definer_host.str, thd->priv_host))); thd->security_ctx->priv_user) &&
!strcmp(sp->m_definer_host.str,
thd->security_ctx->priv_host)));
if (!*full_access) if (!*full_access)
return check_some_routine_access(thd, sp->m_db.str, sp->m_name.str, return check_some_routine_access(thd, sp->m_db.str, sp->m_name.str,
sp->m_type == TYPE_ENUM_PROCEDURE); sp->m_type == TYPE_ENUM_PROCEDURE);
@ -2645,54 +2647,38 @@ sp_instr_error::print(String *str)
*/ */
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
void bool
sp_change_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp) sp_change_security_context(THD *thd, sp_head *sp, st_security_context **backup)
{ {
ctxp->changed= (sp->m_chistics->suid != SP_IS_NOT_SUID && bool changed= (sp->m_chistics->suid != SP_IS_NOT_SUID &&
(strcmp(sp->m_definer_user.str, thd->priv_user) || (strcmp(sp->m_definer_user.str,
strcmp(sp->m_definer_host.str, thd->priv_host))); thd->security_ctx->priv_user) ||
my_strcasecmp(system_charset_info, sp->m_definer_host.str,
thd->security_ctx->priv_host)));
if (ctxp->changed) *backup= 0;
if (changed)
{ {
ctxp->master_access= thd->master_access; if (acl_getroot_no_password(&sp->m_security_ctx, sp->m_definer_user.str,
ctxp->db_access= thd->db_access; sp->m_definer_host.str,
ctxp->priv_user= thd->priv_user; sp->m_definer_host.str,
strncpy(ctxp->priv_host, thd->priv_host, sizeof(ctxp->priv_host)); sp->m_db.str))
ctxp->user= thd->user; {
ctxp->host= thd->host; my_error(ER_NO_SUCH_USER, MYF(0), sp->m_definer_user.str,
ctxp->ip= thd->ip; sp->m_definer_host.str);
return TRUE;
/* Change thise just to do the acl_getroot_no_password */
thd->user= sp->m_definer_user.str;
thd->host= thd->ip = sp->m_definer_host.str;
if (acl_getroot_no_password(thd))
{ // Failed, run as invoker for now
ctxp->changed= FALSE;
thd->master_access= ctxp->master_access;
thd->db_access= ctxp->db_access;
thd->priv_user= ctxp->priv_user;
strncpy(thd->priv_host, ctxp->priv_host, sizeof(thd->priv_host));
} }
*backup= thd->security_ctx;
/* Restore these immiediately */ thd->security_ctx= &sp->m_security_ctx;
thd->user= ctxp->user;
thd->host= ctxp->host;
thd->ip= ctxp->ip;
} }
return FALSE;
} }
void void
sp_restore_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp) sp_restore_security_context(THD *thd, st_security_context *backup)
{ {
if (ctxp->changed) if (backup)
{ thd->security_ctx= backup;
ctxp->changed= FALSE;
thd->master_access= ctxp->master_access;
thd->db_access= ctxp->db_access;
thd->priv_user= ctxp->priv_user;
strncpy(thd->priv_host, ctxp->priv_host, sizeof(thd->priv_host));
}
} }
#endif /* NO_EMBEDDED_ACCESS_CHECKS */ #endif /* NO_EMBEDDED_ACCESS_CHECKS */

View File

@ -151,6 +151,9 @@ public:
// Pointers set during parsing // Pointers set during parsing
uchar *m_param_begin, *m_param_end, *m_body_begin; uchar *m_param_begin, *m_param_end, *m_body_begin;
/* security context for SP procedure/function in case we switch it*/
st_security_context m_security_ctx;
static void * static void *
operator new(size_t size); operator new(size_t size);
@ -1017,23 +1020,12 @@ private:
}; // class sp_instr_error : public sp_instr }; // class sp_instr_error : public sp_instr
struct st_sp_security_context
{
bool changed;
uint master_access;
uint db_access;
char *priv_user;
char priv_host[MAX_HOSTNAME];
char *user;
char *host;
char *ip;
};
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
bool
sp_change_security_context(THD *thd, sp_head *sp,
st_security_context **backup);
void void
sp_change_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp); sp_restore_security_context(THD *thd, st_security_context *backup);
void
sp_restore_security_context(THD *thd, sp_head *sp,st_sp_security_context *ctxp);
#endif /* NO_EMBEDDED_ACCESS_CHECKS */ #endif /* NO_EMBEDDED_ACCESS_CHECKS */
TABLE_LIST * TABLE_LIST *

View File

@ -719,6 +719,7 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh,
ulong user_access= NO_ACCESS; ulong user_access= NO_ACCESS;
int res= 1; int res= 1;
ACL_USER *acl_user= 0; ACL_USER *acl_user= 0;
st_security_context *sctx= thd->security_ctx;
DBUG_ENTER("acl_getroot"); DBUG_ENTER("acl_getroot");
if (!initialized) if (!initialized)
@ -726,10 +727,7 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh,
/* /*
here if mysqld's been started with --skip-grant-tables option. here if mysqld's been started with --skip-grant-tables option.
*/ */
thd->priv_user= (char *) ""; // privileges for sctx->skip_grants();
*thd->priv_host= '\0'; // the user are unknown
thd->master_access= ~NO_ACCESS; // everything is allowed
bzero((char*) mqh, sizeof(*mqh));
DBUG_RETURN(0); DBUG_RETURN(0);
} }
@ -744,9 +742,9 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh,
for (uint i=0 ; i < acl_users.elements ; i++) for (uint i=0 ; i < acl_users.elements ; i++)
{ {
ACL_USER *acl_user_tmp= dynamic_element(&acl_users,i,ACL_USER*); ACL_USER *acl_user_tmp= dynamic_element(&acl_users,i,ACL_USER*);
if (!acl_user_tmp->user || !strcmp(thd->user, acl_user_tmp->user)) if (!acl_user_tmp->user || !strcmp(sctx->user, acl_user_tmp->user))
{ {
if (compare_hostname(&acl_user_tmp->host, thd->host, thd->ip)) if (compare_hostname(&acl_user_tmp->host, sctx->host, sctx->ip))
{ {
/* check password: it should be empty or valid */ /* check password: it should be empty or valid */
if (passwd_len == acl_user_tmp->salt_len) if (passwd_len == acl_user_tmp->salt_len)
@ -893,14 +891,14 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh,
break; break;
#endif /* HAVE_OPENSSL */ #endif /* HAVE_OPENSSL */
} }
thd->master_access= user_access; sctx->master_access= user_access;
thd->priv_user= acl_user->user ? thd->user : (char *) ""; sctx->priv_user= acl_user->user ? sctx->user : (char *) "";
*mqh= acl_user->user_resource; *mqh= acl_user->user_resource;
if (acl_user->host.hostname) if (acl_user->host.hostname)
strmake(thd->priv_host, acl_user->host.hostname, MAX_HOSTNAME); strmake(sctx->priv_host, acl_user->host.hostname, MAX_HOSTNAME);
else else
*thd->priv_host= 0; *sctx->priv_host= 0;
} }
VOID(pthread_mutex_unlock(&acl_cache->lock)); VOID(pthread_mutex_unlock(&acl_cache->lock));
DBUG_RETURN(res); DBUG_RETURN(res);
@ -913,42 +911,46 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh,
* Used to get access rights for SQL SECURITY DEFINER invocation of * Used to get access rights for SQL SECURITY DEFINER invocation of
* stored procedures. * stored procedures.
*/ */
int acl_getroot_no_password(THD *thd) int acl_getroot_no_password(st_security_context *sctx, char *user, char *host,
char *ip, char *db)
{ {
int res= 1; int res= 1;
uint i; uint i;
ACL_USER *acl_user= 0; ACL_USER *acl_user= 0;
DBUG_ENTER("acl_getroot_no_password"); DBUG_ENTER("acl_getroot_no_password");
sctx->user= user;
sctx->host= host;
sctx->ip= ip;
sctx->host_or_ip= host ? host : (ip ? ip : "");
if (!initialized) if (!initialized)
{ {
/* /*
here if mysqld's been started with --skip-grant-tables option. here if mysqld's been started with --skip-grant-tables option.
*/ */
thd->priv_user= (char *) ""; // privileges for sctx->skip_grants();
*thd->priv_host= '\0'; // the user are unknown
thd->master_access= ~NO_ACCESS; // everything is allowed
DBUG_RETURN(0); DBUG_RETURN(0);
} }
VOID(pthread_mutex_lock(&acl_cache->lock)); VOID(pthread_mutex_lock(&acl_cache->lock));
thd->master_access= 0; sctx->master_access= 0;
thd->db_access= 0; sctx->db_access= 0;
/* /*
Find acl entry in user database. Find acl entry in user database.
This is specially tailored to suit the check we do for CALL of This is specially tailored to suit the check we do for CALL of
a stored procedure; thd->user is set to what is actually a a stored procedure; user is set to what is actually a
priv_user, which can be ''. priv_user, which can be ''.
*/ */
for (i=0 ; i < acl_users.elements ; i++) for (i=0 ; i < acl_users.elements ; i++)
{ {
acl_user= dynamic_element(&acl_users,i,ACL_USER*); acl_user= dynamic_element(&acl_users,i,ACL_USER*);
if ((!acl_user->user && (!thd->user || !thd->user[0])) || if ((!acl_user->user && (!user || !user[0])) ||
(acl_user->user && strcmp(thd->user, acl_user->user) == 0)) (acl_user->user && strcmp(user, acl_user->user) == 0))
{ {
if (compare_hostname(&acl_user->host, thd->host, thd->ip)) if (compare_hostname(&acl_user->host, host, ip))
{ {
res= 0; res= 0;
break; break;
@ -962,25 +964,25 @@ int acl_getroot_no_password(THD *thd)
{ {
ACL_DB *acl_db= dynamic_element(&acl_dbs, i, ACL_DB*); ACL_DB *acl_db= dynamic_element(&acl_dbs, i, ACL_DB*);
if (!acl_db->user || if (!acl_db->user ||
(thd->user && thd->user[0] && !strcmp(thd->user, acl_db->user))) (user && user[0] && !strcmp(user, acl_db->user)))
{ {
if (compare_hostname(&acl_db->host, thd->host, thd->ip)) if (compare_hostname(&acl_db->host, host, ip))
{ {
if (!acl_db->db || (thd->db && !strcmp(acl_db->db, thd->db))) if (!acl_db->db || (db && !strcmp(acl_db->db, db)))
{ {
thd->db_access= acl_db->access; sctx->db_access= acl_db->access;
break; break;
} }
} }
} }
} }
thd->master_access= acl_user->access; sctx->master_access= acl_user->access;
thd->priv_user= acl_user->user ? thd->user : (char *) ""; sctx->priv_user= acl_user->user ? user : (char *) "";
if (acl_user->host.hostname) if (acl_user->host.hostname)
strmake(thd->priv_host, acl_user->host.hostname, MAX_HOSTNAME); strmake(sctx->priv_host, acl_user->host.hostname, MAX_HOSTNAME);
else else
*thd->priv_host= 0; *sctx->priv_host= 0;
} }
VOID(pthread_mutex_unlock(&acl_cache->lock)); VOID(pthread_mutex_unlock(&acl_cache->lock));
DBUG_RETURN(res); DBUG_RETURN(res);
@ -1334,13 +1336,14 @@ bool check_change_password(THD *thd, const char *host, const char *user,
return(1); return(1);
} }
if (!thd->slave_thread && if (!thd->slave_thread &&
(strcmp(thd->user,user) || (strcmp(thd->security_ctx->user, user) ||
my_strcasecmp(system_charset_info, host, thd->priv_host))) my_strcasecmp(system_charset_info, host,
thd->security_ctx->priv_host)))
{ {
if (check_access(thd, UPDATE_ACL, "mysql",0,1,0,0)) if (check_access(thd, UPDATE_ACL, "mysql",0,1,0,0))
return(1); return(1);
} }
if (!thd->slave_thread && !thd->user[0]) if (!thd->slave_thread && !thd->security_ctx->user[0])
{ {
my_message(ER_PASSWORD_ANONYMOUS_USER, ER(ER_PASSWORD_ANONYMOUS_USER), my_message(ER_PASSWORD_ANONYMOUS_USER, ER(ER_PASSWORD_ANONYMOUS_USER),
MYF(0)); MYF(0));
@ -1646,9 +1649,10 @@ static bool update_user_table(THD *thd, TABLE *table,
static bool test_if_create_new_users(THD *thd) static bool test_if_create_new_users(THD *thd)
{ {
bool create_new_users= test(thd->master_access & INSERT_ACL) || st_security_context *sctx= thd->security_ctx;
bool create_new_users= test(sctx->master_access & INSERT_ACL) ||
(!opt_safe_user_create && (!opt_safe_user_create &&
test(thd->master_access & CREATE_USER_ACL)); test(sctx->master_access & CREATE_USER_ACL));
if (!create_new_users) if (!create_new_users)
{ {
TABLE_LIST tl; TABLE_LIST tl;
@ -1658,8 +1662,8 @@ static bool test_if_create_new_users(THD *thd)
tl.table_name= (char*) "user"; tl.table_name= (char*) "user";
create_new_users= 1; create_new_users= 1;
db_access=acl_get(thd->host, thd->ip, db_access=acl_get(sctx->host, sctx->ip,
thd->priv_user, tl.db, 0); sctx->priv_user, tl.db, 0);
if (!(db_access & INSERT_ACL)) if (!(db_access & INSERT_ACL))
{ {
if (check_grant(thd, INSERT_ACL, &tl, 0, UINT_MAX, 1)) if (check_grant(thd, INSERT_ACL, &tl, 0, UINT_MAX, 1))
@ -1738,7 +1742,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
else if (!can_create_user) else if (!can_create_user)
{ {
my_error(ER_CANT_CREATE_USER_WITH_GRANT, MYF(0), my_error(ER_CANT_CREATE_USER_WITH_GRANT, MYF(0),
thd->user, thd->host_or_ip); thd->security_ctx->user, thd->security_ctx->host_or_ip);
goto end; goto end;
} }
old_row_exists = 0; old_row_exists = 0;
@ -2450,7 +2454,8 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
byte user_key[MAX_KEY_LENGTH]; byte user_key[MAX_KEY_LENGTH];
DBUG_ENTER("replace_table_table"); DBUG_ENTER("replace_table_table");
strxmov(grantor, thd->user, "@", thd->host_or_ip, NullS); strxmov(grantor, thd->security_ctx->user, "@",
thd->security_ctx->host_or_ip, NullS);
/* /*
The following should always succeed as new users are created before The following should always succeed as new users are created before
@ -2572,7 +2577,8 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name,
DBUG_RETURN(-1); DBUG_RETURN(-1);
} }
strxmov(grantor, thd->user, "@", thd->host_or_ip, NullS); strxmov(grantor, thd->security_ctx->user, "@",
thd->security_ctx->host_or_ip, NullS);
/* /*
The following should always succeed as new users are created before The following should always succeed as new users are created before
@ -2763,7 +2769,8 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list,
get_privilege_desc(command, sizeof(command), get_privilege_desc(command, sizeof(command),
table_list->grant.want_privilege); table_list->grant.want_privilege);
my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0),
command, thd->priv_user, thd->host_or_ip, table_list->alias); command, thd->security_ctx->priv_user,
thd->security_ctx->host_or_ip, table_list->alias);
DBUG_RETURN(-1); DBUG_RETURN(-1);
} }
} }
@ -3486,11 +3493,11 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
uint show_table, uint number, bool no_errors) uint show_table, uint number, bool no_errors)
{ {
TABLE_LIST *table; TABLE_LIST *table;
char *user = thd->priv_user; st_security_context *sctx= thd->security_ctx;
DBUG_ENTER("check_grant"); DBUG_ENTER("check_grant");
DBUG_ASSERT(number > 0); DBUG_ASSERT(number > 0);
want_access&= ~thd->master_access; want_access&= ~sctx->master_access;
if (!want_access) if (!want_access)
DBUG_RETURN(0); // ok DBUG_RETURN(0); // ok
@ -3508,8 +3515,9 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
table->grant.want_privilege= 0; table->grant.want_privilege= 0;
continue; // Already checked continue; // Already checked
} }
if (!(grant_table= table_hash_search(thd->host,thd->ip, if (!(grant_table= table_hash_search(sctx->host, sctx->ip,
table->db,user, table->table_name,0))) table->db, sctx->priv_user,
table->table_name,0)))
{ {
want_access &= ~table->grant.privilege; want_access &= ~table->grant.privilege;
goto err; // No grants goto err; // No grants
@ -3543,8 +3551,8 @@ err:
get_privilege_desc(command, sizeof(command), want_access); get_privilege_desc(command, sizeof(command), want_access);
my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0),
command, command,
thd->priv_user, sctx->priv_user,
thd->host_or_ip, sctx->host_or_ip,
table ? table->table_name : "unknown"); table ? table->table_name : "unknown");
} }
DBUG_RETURN(1); DBUG_RETURN(1);
@ -3555,6 +3563,7 @@ bool check_grant_column(THD *thd, GRANT_INFO *grant,
const char *db_name, const char *table_name, const char *db_name, const char *table_name,
const char *name, uint length, uint show_tables) const char *name, uint length, uint show_tables)
{ {
st_security_context *sctx= thd->security_ctx;
GRANT_TABLE *grant_table; GRANT_TABLE *grant_table;
GRANT_COLUMN *grant_column; GRANT_COLUMN *grant_column;
ulong want_access= grant->want_privilege & ~grant->privilege; ulong want_access= grant->want_privilege & ~grant->privilege;
@ -3571,8 +3580,8 @@ bool check_grant_column(THD *thd, GRANT_INFO *grant,
if (grant->version != grant_version) if (grant->version != grant_version)
{ {
grant->grant_table= grant->grant_table=
table_hash_search(thd->host, thd->ip, db_name, table_hash_search(sctx->host, sctx->ip, db_name,
thd->priv_user, sctx->priv_user,
table_name, 0); /* purecov: inspected */ table_name, 0); /* purecov: inspected */
grant->version= grant_version; /* purecov: inspected */ grant->version= grant_version; /* purecov: inspected */
} }
@ -3601,8 +3610,8 @@ err:
get_privilege_desc(command, sizeof(command), want_access); get_privilege_desc(command, sizeof(command), want_access);
my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0),
command, command,
thd->priv_user, sctx->priv_user,
thd->host_or_ip, sctx->host_or_ip,
name, name,
table_name); table_name);
} }
@ -3614,6 +3623,7 @@ bool check_grant_all_columns(THD *thd, ulong want_access, GRANT_INFO *grant,
const char* db_name, const char *table_name, const char* db_name, const char *table_name,
Field_iterator *fields) Field_iterator *fields)
{ {
st_security_context *sctx= thd->security_ctx;
GRANT_TABLE *grant_table; GRANT_TABLE *grant_table;
GRANT_COLUMN *grant_column; GRANT_COLUMN *grant_column;
@ -3630,8 +3640,8 @@ bool check_grant_all_columns(THD *thd, ulong want_access, GRANT_INFO *grant,
if (grant->version != grant_version) if (grant->version != grant_version)
{ {
grant->grant_table= grant->grant_table=
table_hash_search(thd->host, thd->ip, db_name, table_hash_search(sctx->host, sctx->ip, db_name,
thd->priv_user, sctx->priv_user,
table_name, 0); /* purecov: inspected */ table_name, 0); /* purecov: inspected */
grant->version= grant_version; /* purecov: inspected */ grant->version= grant_version; /* purecov: inspected */
} }
@ -3657,8 +3667,8 @@ err2:
get_privilege_desc(command, sizeof(command), want_access); get_privilege_desc(command, sizeof(command), want_access);
my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0),
command, command,
thd->priv_user, sctx->priv_user,
thd->host_or_ip, sctx->host_or_ip,
fields->name(), fields->name(),
table_name); table_name);
return 1; return 1;
@ -3673,11 +3683,12 @@ err2:
bool check_grant_db(THD *thd,const char *db) bool check_grant_db(THD *thd,const char *db)
{ {
st_security_context *sctx= thd->security_ctx;
char helping [NAME_LEN+USERNAME_LENGTH+2]; char helping [NAME_LEN+USERNAME_LENGTH+2];
uint len; uint len;
bool error= 1; bool error= 1;
len= (uint) (strmov(strmov(helping,thd->priv_user)+1,db)-helping)+ 1; len= (uint) (strmov(strmov(helping, sctx->priv_user) + 1, db) - helping) + 1;
rw_rdlock(&LOCK_grant); rw_rdlock(&LOCK_grant);
for (uint idx=0 ; idx < column_priv_hash.records ; idx++) for (uint idx=0 ; idx < column_priv_hash.records ; idx++)
@ -3686,7 +3697,7 @@ bool check_grant_db(THD *thd,const char *db)
idx); idx);
if (len < grant_table->key_length && if (len < grant_table->key_length &&
!memcmp(grant_table->hash_key,helping,len) && !memcmp(grant_table->hash_key,helping,len) &&
compare_hostname(&grant_table->host, thd->host, thd->ip)) compare_hostname(&grant_table->host, sctx->host, sctx->ip))
{ {
error=0; // Found match error=0; // Found match
break; break;
@ -3714,15 +3725,16 @@ bool check_grant_db(THD *thd,const char *db)
1 Error: User did not have the requested privielges 1 Error: User did not have the requested privielges
****************************************************************************/ ****************************************************************************/
bool check_grant_routine(THD *thd, ulong want_access, bool check_grant_routine(THD *thd, ulong want_access,
TABLE_LIST *procs, bool is_proc, bool no_errors) TABLE_LIST *procs, bool is_proc, bool no_errors)
{ {
TABLE_LIST *table; TABLE_LIST *table;
char *user= thd->priv_user; st_security_context *sctx= thd->security_ctx;
char *host= thd->priv_host; char *user= sctx->priv_user;
char *host= sctx->priv_host;
DBUG_ENTER("check_grant_routine"); DBUG_ENTER("check_grant_routine");
want_access&= ~thd->master_access; want_access&= ~sctx->master_access;
if (!want_access) if (!want_access)
DBUG_RETURN(0); // ok DBUG_RETURN(0); // ok
@ -3730,7 +3742,7 @@ bool check_grant_routine(THD *thd, ulong want_access,
for (table= procs; table; table= table->next_global) for (table= procs; table; table= table->next_global)
{ {
GRANT_NAME *grant_proc; GRANT_NAME *grant_proc;
if ((grant_proc= routine_hash_search(host,thd->ip, table->db, user, if ((grant_proc= routine_hash_search(host, sctx->ip, table->db, user,
table->table_name, is_proc, 0))) table->table_name, is_proc, 0)))
table->grant.privilege|= grant_proc->privs; table->grant.privilege|= grant_proc->privs;
@ -3786,8 +3798,10 @@ bool check_routine_level_acl(THD *thd, const char *db, const char *name,
{ {
GRANT_NAME *grant_proc; GRANT_NAME *grant_proc;
rw_rdlock(&LOCK_grant); rw_rdlock(&LOCK_grant);
if ((grant_proc= routine_hash_search(thd->priv_host, thd->ip, db, if ((grant_proc= routine_hash_search(thd->security_ctx->priv_host,
thd->priv_user, name, is_proc, 0))) thd->security_ctx->ip, db,
thd->security_ctx->priv_user,
name, is_proc, 0)))
no_routine_acl= !(grant_proc->privs & SHOW_PROC_ACLS); no_routine_acl= !(grant_proc->privs & SHOW_PROC_ACLS);
rw_unlock(&LOCK_grant); rw_unlock(&LOCK_grant);
} }
@ -3802,7 +3816,7 @@ bool check_routine_level_acl(THD *thd, const char *db, const char *name,
ulong get_table_grant(THD *thd, TABLE_LIST *table) ulong get_table_grant(THD *thd, TABLE_LIST *table)
{ {
ulong privilege; ulong privilege;
char *user = thd->priv_user; st_security_context *sctx= thd->security_ctx;
const char *db = table->db ? table->db : thd->db; const char *db = table->db ? table->db : thd->db;
GRANT_TABLE *grant_table; GRANT_TABLE *grant_table;
@ -3810,7 +3824,7 @@ ulong get_table_grant(THD *thd, TABLE_LIST *table)
#ifdef EMBEDDED_LIBRARY #ifdef EMBEDDED_LIBRARY
grant_table= NULL; grant_table= NULL;
#else #else
grant_table= table_hash_search(thd->host, thd->ip, db, user, grant_table= table_hash_search(sctx->host, sctx->ip, db, sctx->priv_user,
table->table_name, 0); table->table_name, 0);
#endif #endif
table->grant.grant_table=grant_table; // Remember for column test table->grant.grant_table=grant_table; // Remember for column test
@ -3854,8 +3868,8 @@ ulong get_column_grant(THD *thd, GRANT_INFO *grant,
if (grant->version != grant_version) if (grant->version != grant_version)
{ {
grant->grant_table= grant->grant_table=
table_hash_search(thd->host, thd->ip, db_name, table_hash_search(thd->security_ctx->host, thd->security_ctx->ip,
thd->priv_user, db_name, thd->security_ctx->priv_user,
table_name, 0); /* purecov: inspected */ table_name, 0); /* purecov: inspected */
grant->version= grant_version; /* purecov: inspected */ grant->version= grant_version; /* purecov: inspected */
} }
@ -5425,22 +5439,24 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name, bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
bool is_proc) bool is_proc)
{ {
st_security_context *sctx= thd->security_ctx;
LEX_USER *combo; LEX_USER *combo;
TABLE_LIST tables[1]; TABLE_LIST tables[1];
List<LEX_USER> user_list; List<LEX_USER> user_list;
bool result; bool result;
DBUG_ENTER("sp_grant_privileges"); DBUG_ENTER("sp_grant_privileges");
if (!(combo=(LEX_USER*) thd->alloc(sizeof(st_lex_user)))) if (!(combo=(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
combo->user.str= thd->user; combo->user.str= sctx->user;
if (!find_acl_user(combo->host.str=(char*)thd->host_or_ip, combo->user.str, if (!find_acl_user(combo->host.str=(char*)sctx->host_or_ip, combo->user.str,
FALSE) && FALSE) &&
!find_acl_user(combo->host.str=(char*)thd->host, combo->user.str, !find_acl_user(combo->host.str=(char*)sctx->host, combo->user.str,
FALSE) &&
!find_acl_user(combo->host.str=(char*)sctx->ip, combo->user.str,
FALSE) && FALSE) &&
!find_acl_user(combo->host.str=(char*)thd->ip, combo->user.str, FALSE) &&
!find_acl_user(combo->host.str=(char*)"%", combo->user.str, FALSE)) !find_acl_user(combo->host.str=(char*)"%", combo->user.str, FALSE))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
@ -5557,7 +5573,7 @@ int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
char buff[100]; char buff[100];
TABLE *table= tables->table; TABLE *table= tables->table;
bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1,0); bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1,0);
char *curr_host= thd->priv_host ? thd->priv_host : (char *) "%"; char *curr_host= thd->security_ctx->get_priv_host();
DBUG_ENTER("fill_schema_user_privileges"); DBUG_ENTER("fill_schema_user_privileges");
for (counter=0 ; counter < acl_users.elements ; counter++) for (counter=0 ; counter < acl_users.elements ; counter++)
@ -5570,7 +5586,7 @@ int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
host= ""; host= "";
if (no_global_access && if (no_global_access &&
(strcmp(thd->priv_user, user) || (strcmp(thd->security_ctx->priv_user, user) ||
my_strcasecmp(system_charset_info, curr_host, host))) my_strcasecmp(system_charset_info, curr_host, host)))
continue; continue;
@ -5610,7 +5626,7 @@ int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
char buff[100]; char buff[100];
TABLE *table= tables->table; TABLE *table= tables->table;
bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1,0); bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1,0);
char *curr_host= thd->priv_host ? thd->priv_host : (char *) "%"; char *curr_host= thd->security_ctx->get_priv_host();
DBUG_ENTER("fill_schema_schema_privileges"); DBUG_ENTER("fill_schema_schema_privileges");
for (counter=0 ; counter < acl_dbs.elements ; counter++) for (counter=0 ; counter < acl_dbs.elements ; counter++)
@ -5624,7 +5640,7 @@ int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
host= ""; host= "";
if (no_global_access && if (no_global_access &&
(strcmp(thd->priv_user, user) || (strcmp(thd->security_ctx->priv_user, user) ||
my_strcasecmp(system_charset_info, curr_host, host))) my_strcasecmp(system_charset_info, curr_host, host)))
continue; continue;
@ -5665,7 +5681,7 @@ int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
char buff[100]; char buff[100];
TABLE *table= tables->table; TABLE *table= tables->table;
bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1,0); bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1,0);
char *curr_host= thd->priv_host ? thd->priv_host : (char *) "%"; char *curr_host= thd->security_ctx->get_priv_host();
DBUG_ENTER("fill_schema_table_privileges"); DBUG_ENTER("fill_schema_table_privileges");
for (index=0 ; index < column_priv_hash.records ; index++) for (index=0 ; index < column_priv_hash.records ; index++)
@ -5677,7 +5693,7 @@ int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
user= ""; user= "";
if (no_global_access && if (no_global_access &&
(strcmp(thd->priv_user, user) || (strcmp(thd->security_ctx->priv_user, user) ||
my_strcasecmp(system_charset_info, curr_host, my_strcasecmp(system_charset_info, curr_host,
grant_table->host.hostname))) grant_table->host.hostname)))
continue; continue;
@ -5727,7 +5743,7 @@ int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
char buff[100]; char buff[100];
TABLE *table= tables->table; TABLE *table= tables->table;
bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1,0); bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1,0);
char *curr_host= thd->priv_host ? thd->priv_host : (char *) "%"; char *curr_host= thd->security_ctx->get_priv_host();
DBUG_ENTER("fill_schema_table_privileges"); DBUG_ENTER("fill_schema_table_privileges");
for (index=0 ; index < column_priv_hash.records ; index++) for (index=0 ; index < column_priv_hash.records ; index++)
@ -5739,7 +5755,7 @@ int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
user= ""; user= "";
if (no_global_access && if (no_global_access &&
(strcmp(thd->priv_user, user) || (strcmp(thd->security_ctx->priv_user, user) ||
my_strcasecmp(system_charset_info, curr_host, my_strcasecmp(system_charset_info, curr_host,
grant_table->host.hostname))) grant_table->host.hostname)))
continue; continue;
@ -5803,6 +5819,7 @@ int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant, void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
const char *db, const char *table) const char *db, const char *table)
{ {
st_security_context *sctx= thd->security_ctx;
/* --skip-grants */ /* --skip-grants */
if (!initialized) if (!initialized)
{ {
@ -5811,13 +5828,13 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
} }
/* global privileges */ /* global privileges */
grant->privilege= thd->master_access; grant->privilege= sctx->master_access;
if (!thd->priv_user) if (!sctx->priv_user)
return; // it is slave return; // it is slave
/* db privileges */ /* db privileges */
grant->privilege|= acl_get(thd->host, thd->ip, thd->priv_user, db, 0); grant->privilege|= acl_get(sctx->host, sctx->ip, sctx->priv_user, db, 0);
if (!grant_option) if (!grant_option)
return; return;
@ -5827,8 +5844,8 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
{ {
rw_rdlock(&LOCK_grant); rw_rdlock(&LOCK_grant);
grant->grant_table= grant->grant_table=
table_hash_search(thd->host, thd->ip, db, table_hash_search(sctx->host, sctx->ip, db,
thd->priv_user, sctx->priv_user,
table, 0); /* purecov: inspected */ table, 0); /* purecov: inspected */
grant->version= grant_version; /* purecov: inspected */ grant->version= grant_version; /* purecov: inspected */
rw_unlock(&LOCK_grant); rw_unlock(&LOCK_grant);

View File

@ -181,7 +181,8 @@ ulong acl_get(const char *host, const char *ip,
const char *user, const char *db, my_bool db_is_pattern); const char *user, const char *db, my_bool db_is_pattern);
int acl_getroot(THD *thd, USER_RESOURCES *mqh, const char *passwd, int acl_getroot(THD *thd, USER_RESOURCES *mqh, const char *passwd,
uint passwd_len); uint passwd_len);
int acl_getroot_no_password(THD *thd); int acl_getroot_no_password(st_security_context *sctx, char *user, char *host,
char *ip, char *db);
bool acl_check_host(const char *host, const char *ip); bool acl_check_host(const char *host, const char *ip);
bool check_change_password(THD *thd, const char *host, const char *user, bool check_change_password(THD *thd, const char *host, const char *user,
char *password, uint password_len); char *password, uint password_len);

View File

@ -4572,7 +4572,8 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
VIEW_ANY_ACL))) VIEW_ANY_ACL)))
{ {
my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), "ANY", my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), "ANY",
thd->priv_user, thd->host_or_ip, thd->security_ctx->priv_user,
thd->security_ctx->host_or_ip,
fld->field_name, field_table_name); fld->field_name, field_table_name);
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }

View File

@ -181,9 +181,10 @@ THD::THD()
spcont(NULL) spcont(NULL)
{ {
stmt_arena= this; stmt_arena= this;
host= user= priv_user= db= ip= 0; db= 0;
catalog= (char*)"std"; // the only catalog we have for now catalog= (char*)"std"; // the only catalog we have for now
host_or_ip= "connecting host"; main_security_ctx.init();
security_ctx= &main_security_ctx;
locked=some_tables_deleted=no_errors=password= 0; locked=some_tables_deleted=no_errors=password= 0;
query_start_used= 0; query_start_used= 0;
count_cuted_fields= CHECK_FIELD_IGNORE; count_cuted_fields= CHECK_FIELD_IGNORE;
@ -236,9 +237,6 @@ THD::THD()
server_id = ::server_id; server_id = ::server_id;
slave_net = 0; slave_net = 0;
command=COM_CONNECT; command=COM_CONNECT;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
db_access=NO_ACCESS;
#endif
*scramble= '\0'; *scramble= '\0';
init(); init();
@ -426,12 +424,8 @@ THD::~THD()
ha_close_connection(this); ha_close_connection(this);
DBUG_PRINT("info", ("freeing host")); DBUG_PRINT("info", ("freeing security context"));
if (host != my_localhost) // If not pointer to constant main_security_ctx.destroy();
safeFree(host);
if (user != delayed_user)
safeFree(user);
safeFree(ip);
safeFree(db); safeFree(db);
free_root(&warn_root,MYF(0)); free_root(&warn_root,MYF(0));
#ifdef USING_TRANSACTIONS #ifdef USING_TRANSACTIONS
@ -1827,6 +1821,38 @@ void THD::set_status_var_init()
bzero((char*) &status_var, sizeof(status_var)); bzero((char*) &status_var, sizeof(status_var));
} }
void st_security_context::init()
{
host= user= priv_user= ip= 0;
host_or_ip= "connecting host";
#ifndef NO_EMBEDDED_ACCESS_CHECKS
db_access= NO_ACCESS;
#endif
}
void st_security_context::destroy()
{
// If not pointer to constant
if (host != my_localhost)
safeFree(host);
if (user != delayed_user)
safeFree(user);
safeFree(ip);
}
void st_security_context::skip_grants()
{
/* privileges for the user are unknown everything is allowed */
host_or_ip= (char *)"";
master_access= ~NO_ACCESS;
priv_user= (char *)"";
*priv_host= '\0';
}
/**************************************************************************** /****************************************************************************
Handling of open and locked tables states. Handling of open and locked tables states.

View File

@ -941,6 +941,32 @@ bool xid_cache_insert(XID *xid, enum xa_states xa_state);
bool xid_cache_insert(XID_STATE *xid_state); bool xid_cache_insert(XID_STATE *xid_state);
void xid_cache_delete(XID_STATE *xid_state); void xid_cache_delete(XID_STATE *xid_state);
struct st_security_context {
/*
host - host of the client
user - user of the client, set to NULL until the user has been read from
the connection
priv_user - The user privilege we are using. May be '' for anonymous user.
ip - client IP
*/
char *host, *user, *priv_user, *ip;
char priv_host[MAX_HOSTNAME];
/* points to host if host is available, otherwise points to ip */
const char *host_or_ip;
ulong master_access; /* Global privileges from mysql.user */
ulong db_access; /* Privileges for current db */
void init();
void destroy();
void skip_grants();
inline char *get_priv_host()
{
return (*priv_host ? priv_host : (char *)"%");
}
};
/* /*
A registry for item tree transformations performed during A registry for item tree transformations performed during
query optimization. We register only those changes which require query optimization. We register only those changes which require
@ -1113,13 +1139,8 @@ public:
char *thread_stack; char *thread_stack;
/* /*
host - host of the client
user - user of the client, set to NULL until the user has been read from
the connection
priv_user - The user privilege we are using. May be '' for anonymous user.
db - currently selected database db - currently selected database
catalog - currently selected catalog catalog - currently selected catalog
ip - client IP
WARNING: some members of THD (currently 'db', 'catalog' and 'query') are WARNING: some members of THD (currently 'db', 'catalog' and 'query') are
set and alloced by the slave SQL thread (for the THD of that thread); that set and alloced by the slave SQL thread (for the THD of that thread); that
thread is (and must remain, for now) the only responsible for freeing these thread is (and must remain, for now) the only responsible for freeing these
@ -1128,8 +1149,10 @@ public:
properly. For details see the 'err:' label of the pthread_handler_decl of properly. For details see the 'err:' label of the pthread_handler_decl of
the slave SQL thread, in sql/slave.cc. the slave SQL thread, in sql/slave.cc.
*/ */
char *host,*user,*priv_user,*db,*catalog,*ip; char *db, *catalog;
char priv_host[MAX_HOSTNAME]; st_security_context main_security_ctx;
st_security_context *security_ctx;
/* remote (peer) port */ /* remote (peer) port */
uint16 peer_port; uint16 peer_port;
/* /*
@ -1138,13 +1161,9 @@ public:
a time-consuming piece that MySQL can get stuck in for a long time. a time-consuming piece that MySQL can get stuck in for a long time.
*/ */
const char *proc_info; const char *proc_info;
/* points to host if host is available, otherwise points to ip */
const char *host_or_ip;
ulong client_capabilities; /* What the client supports */ ulong client_capabilities; /* What the client supports */
ulong max_client_packet_length; ulong max_client_packet_length;
ulong master_access; /* Global privileges from mysql.user */
ulong db_access; /* Privileges for current db */
HASH handler_tables_hash; HASH handler_tables_hash;
/* /*

View File

@ -1093,6 +1093,7 @@ bool mysql_change_db(THD *thd, const char *name, bool no_access_check)
bool system_db= 0; bool system_db= 0;
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
ulong db_access; ulong db_access;
st_security_context *sctx= thd->security_ctx;
#endif #endif
DBUG_ENTER("mysql_change_db"); DBUG_ENTER("mysql_change_db");
DBUG_PRINT("enter",("name: '%s'",name)); DBUG_PRINT("enter",("name: '%s'",name));
@ -1130,22 +1131,20 @@ bool mysql_change_db(THD *thd, const char *name, bool no_access_check)
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
if (!no_access_check) if (!no_access_check)
{ {
if (test_all_bits(thd->master_access,DB_ACLS)) if (test_all_bits(sctx->master_access,DB_ACLS))
db_access=DB_ACLS; db_access=DB_ACLS;
else else
db_access= (acl_get(thd->host,thd->ip, thd->priv_user,dbname,0) | db_access= (acl_get(sctx->host, sctx->ip, sctx->priv_user, dbname, 0) |
thd->master_access); sctx->master_access);
if (!(db_access & DB_ACLS) && (!grant_option || if (!(db_access & DB_ACLS) && (!grant_option ||
check_grant_db(thd,dbname))) check_grant_db(thd,dbname)))
{ {
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
thd->priv_user, sctx->priv_user,
thd->priv_host, sctx->priv_host,
dbname); dbname);
mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR), mysql_log.write(thd, COM_INIT_DB, ER(ER_DBACCESS_DENIED_ERROR),
thd->priv_user, sctx->priv_user, sctx->priv_host, dbname);
thd->priv_host,
dbname);
my_free(dbname,MYF(0)); my_free(dbname,MYF(0));
DBUG_RETURN(1); DBUG_RETURN(1);
} }
@ -1167,7 +1166,7 @@ end:
thd->db_length=db_length; thd->db_length=db_length;
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
if (!no_access_check) if (!no_access_check)
thd->db_access=db_access; sctx->db_access=db_access;
#endif #endif
if (system_db) if (system_db)
{ {

View File

@ -272,7 +272,8 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
By default, both logs are enabled (this won't cause problems if the server By default, both logs are enabled (this won't cause problems if the server
runs without --log-update or --log-bin). runs without --log-update or --log-bin).
*/ */
bool log_on= (thd->options & OPTION_BIN_LOG) || (!(thd->master_access & SUPER_ACL)); bool log_on= (thd->options & OPTION_BIN_LOG) ||
(!(thd->security_ctx->master_access & SUPER_ACL));
bool transactional_table; bool transactional_table;
uint value_count; uint value_count;
ulong counter = 1; ulong counter = 1;
@ -1264,8 +1265,8 @@ public:
table(0),tables_in_use(0),stacked_inserts(0), status(0), dead(0), table(0),tables_in_use(0),stacked_inserts(0), status(0), dead(0),
group_count(0) group_count(0)
{ {
thd.user=thd.priv_user=(char*) delayed_user; thd.security_ctx->user=thd.security_ctx->priv_user=(char*) delayed_user;
thd.host=(char*) my_localhost; thd.security_ctx->host=(char*) my_localhost;
thd.current_tablenr=0; thd.current_tablenr=0;
thd.version=refresh_version; thd.version=refresh_version;
thd.command=COM_DELAYED_INSERT; thd.command=COM_DELAYED_INSERT;
@ -1275,7 +1276,7 @@ public:
bzero((char*) &thd.net, sizeof(thd.net)); // Safety bzero((char*) &thd.net, sizeof(thd.net)); // Safety
bzero((char*) &table_list, sizeof(table_list)); // Safety bzero((char*) &table_list, sizeof(table_list)); // Safety
thd.system_thread= SYSTEM_THREAD_DELAYED_INSERT; thd.system_thread= SYSTEM_THREAD_DELAYED_INSERT;
thd.host_or_ip= ""; thd.security_ctx->host_or_ip= "";
bzero((char*) &info,sizeof(info)); bzero((char*) &info,sizeof(info));
pthread_mutex_init(&mutex,MY_MUTEX_INIT_FAST); pthread_mutex_init(&mutex,MY_MUTEX_INIT_FAST);
pthread_cond_init(&cond,NULL); pthread_cond_init(&cond,NULL);
@ -1298,7 +1299,7 @@ public:
pthread_cond_destroy(&cond_client); pthread_cond_destroy(&cond_client);
thd.unlink(); // Must be unlinked under lock thd.unlink(); // Must be unlinked under lock
x_free(thd.query); x_free(thd.query);
thd.user=thd.host=0; thd.security_ctx->user= thd.security_ctx->host=0;
thread_count--; thread_count--;
delayed_insert_threads--; delayed_insert_threads--;
VOID(pthread_mutex_unlock(&LOCK_thread_count)); VOID(pthread_mutex_unlock(&LOCK_thread_count));

View File

@ -270,10 +270,11 @@ int check_user(THD *thd, enum enum_server_command command,
const char *passwd, uint passwd_len, const char *db, const char *passwd, uint passwd_len, const char *db,
bool check_count) bool check_count)
{ {
st_security_context *sctx= thd->security_ctx;
DBUG_ENTER("check_user"); DBUG_ENTER("check_user");
#ifdef NO_EMBEDDED_ACCESS_CHECKS #ifdef NO_EMBEDDED_ACCESS_CHECKS
thd->master_access= GLOBAL_ACLS; // Full rights sctx->master_access= GLOBAL_ACLS; // Full rights
/* Change database if necessary */ /* Change database if necessary */
if (db && db[0]) if (db && db[0])
{ {
@ -340,9 +341,9 @@ int check_user(THD *thd, enum enum_server_command command,
if (opt_secure_auth_local) if (opt_secure_auth_local)
{ {
net_printf_error(thd, ER_SERVER_IS_IN_SECURE_AUTH_MODE, net_printf_error(thd, ER_SERVER_IS_IN_SECURE_AUTH_MODE,
thd->user, thd->host_or_ip); sctx->user, sctx->host_or_ip);
mysql_log.write(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE), mysql_log.write(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE),
thd->user, thd->host_or_ip); sctx->user, sctx->host_or_ip);
DBUG_RETURN(-1); DBUG_RETURN(-1);
} }
/* We have to read very specific packet size */ /* We have to read very specific packet size */
@ -360,22 +361,22 @@ int check_user(THD *thd, enum enum_server_command command,
/* here res is always >= 0 */ /* here res is always >= 0 */
if (res == 0) if (res == 0)
{ {
if (!(thd->master_access & NO_ACCESS)) // authentication is OK if (!(sctx->master_access & NO_ACCESS)) // authentication is OK
{ {
DBUG_PRINT("info", DBUG_PRINT("info",
("Capabilities: %d packet_length: %ld Host: '%s' " ("Capabilities: %d packet_length: %ld Host: '%s' "
"Login user: '%s' Priv_user: '%s' Using password: %s " "Login user: '%s' Priv_user: '%s' Using password: %s "
"Access: %u db: '%s'", "Access: %u db: '%s'",
thd->client_capabilities, thd->max_client_packet_length, thd->client_capabilities, thd->max_client_packet_length,
thd->host_or_ip, thd->user, thd->priv_user, sctx->host_or_ip, sctx->user, sctx->priv_user,
passwd_len ? "yes": "no", passwd_len ? "yes": "no",
thd->master_access, thd->db ? thd->db : "*none*")); sctx->master_access, thd->db ? thd->db : "*none*"));
if (check_count) if (check_count)
{ {
VOID(pthread_mutex_lock(&LOCK_thread_count)); VOID(pthread_mutex_lock(&LOCK_thread_count));
bool count_ok= thread_count <= max_connections + delayed_insert_threads bool count_ok= thread_count <= max_connections + delayed_insert_threads
|| (thd->master_access & SUPER_ACL); || (sctx->master_access & SUPER_ACL);
VOID(pthread_mutex_unlock(&LOCK_thread_count)); VOID(pthread_mutex_unlock(&LOCK_thread_count));
if (!count_ok) if (!count_ok)
{ // too many connections { // too many connections
@ -385,11 +386,11 @@ int check_user(THD *thd, enum enum_server_command command,
} }
/* Why logging is performed before all checks've passed? */ /* Why logging is performed before all checks've passed? */
mysql_log.write(thd,command, mysql_log.write(thd, command,
(thd->priv_user == thd->user ? (sctx->priv_user == sctx->user ?
(char*) "%s@%s on %s" : (char*) "%s@%s on %s" :
(char*) "%s@%s as anonymous on %s"), (char*) "%s@%s as anonymous on %s"),
thd->user, thd->host_or_ip, sctx->user, sctx->host_or_ip,
db ? db : (char*) ""); db ? db : (char*) "");
/* /*
@ -397,14 +398,14 @@ int check_user(THD *thd, enum enum_server_command command,
set to 0 here because we don't have an active database yet (and we set to 0 here because we don't have an active database yet (and we
may not have an active database to set. may not have an active database to set.
*/ */
thd->db_access=0; sctx->db_access=0;
/* Don't allow user to connect if he has done too many queries */ /* Don't allow user to connect if he has done too many queries */
if ((ur.questions || ur.updates || ur.conn_per_hour || ur.user_conn || if ((ur.questions || ur.updates || ur.conn_per_hour || ur.user_conn ||
max_user_connections) && max_user_connections) &&
get_or_create_user_conn(thd, get_or_create_user_conn(thd,
opt_old_style_user_limits ? thd->user : thd->priv_user, (opt_old_style_user_limits ? sctx->user : sctx->priv_user),
opt_old_style_user_limits ? thd->host_or_ip : thd->priv_host, (opt_old_style_user_limits ? sctx->host_or_ip : sctx->priv_host),
&ur)) &ur))
DBUG_RETURN(-1); DBUG_RETURN(-1);
if (thd->user_connect && if (thd->user_connect &&
@ -439,12 +440,12 @@ int check_user(THD *thd, enum enum_server_command command,
DBUG_RETURN(-1); DBUG_RETURN(-1);
} }
net_printf_error(thd, ER_ACCESS_DENIED_ERROR, net_printf_error(thd, ER_ACCESS_DENIED_ERROR,
thd->user, sctx->user,
thd->host_or_ip, sctx->host_or_ip,
passwd_len ? ER(ER_YES) : ER(ER_NO)); passwd_len ? ER(ER_YES) : ER(ER_NO));
mysql_log.write(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR), mysql_log.write(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR),
thd->user, sctx->user,
thd->host_or_ip, sctx->host_or_ip,
passwd_len ? ER(ER_YES) : ER(ER_NO)); passwd_len ? ER(ER_YES) : ER(ER_NO));
DBUG_RETURN(-1); DBUG_RETURN(-1);
#endif /* NO_EMBEDDED_ACCESS_CHECKS */ #endif /* NO_EMBEDDED_ACCESS_CHECKS */
@ -764,45 +765,46 @@ static int check_connection(THD *thd)
NET *net= &thd->net; NET *net= &thd->net;
ulong pkt_len= 0; ulong pkt_len= 0;
char *end; char *end;
st_security_context *sctx= thd->security_ctx;
DBUG_PRINT("info", DBUG_PRINT("info",
("New connection received on %s", vio_description(net->vio))); ("New connection received on %s", vio_description(net->vio)));
if (!thd->host) // If TCP/IP connection if (!sctx->host) // If TCP/IP connection
{ {
char ip[30]; char ip[30];
if (vio_peer_addr(net->vio, ip, &thd->peer_port)) if (vio_peer_addr(net->vio, ip, &thd->peer_port))
return (ER_BAD_HOST_ERROR); return (ER_BAD_HOST_ERROR);
if (!(thd->ip= my_strdup(ip,MYF(0)))) if (!(sctx->ip= my_strdup(ip,MYF(0))))
return (ER_OUT_OF_RESOURCES); return (ER_OUT_OF_RESOURCES);
thd->host_or_ip= thd->ip; sctx->host_or_ip= sctx->ip;
vio_in_addr(net->vio,&thd->remote.sin_addr); vio_in_addr(net->vio,&thd->remote.sin_addr);
if (!(specialflag & SPECIAL_NO_RESOLVE)) if (!(specialflag & SPECIAL_NO_RESOLVE))
{ {
vio_in_addr(net->vio,&thd->remote.sin_addr); vio_in_addr(net->vio,&thd->remote.sin_addr);
thd->host=ip_to_hostname(&thd->remote.sin_addr,&connect_errors); sctx->host=ip_to_hostname(&thd->remote.sin_addr,&connect_errors);
/* Cut very long hostnames to avoid possible overflows */ /* Cut very long hostnames to avoid possible overflows */
if (thd->host) if (sctx->host)
{ {
if (thd->host != my_localhost) if (sctx->host != my_localhost)
thd->host[min(strlen(thd->host), HOSTNAME_LENGTH)]= 0; sctx->host[min(strlen(sctx->host), HOSTNAME_LENGTH)]= 0;
thd->host_or_ip= thd->host; sctx->host_or_ip= sctx->host;
} }
if (connect_errors > max_connect_errors) if (connect_errors > max_connect_errors)
return(ER_HOST_IS_BLOCKED); return(ER_HOST_IS_BLOCKED);
} }
DBUG_PRINT("info",("Host: %s ip: %s", DBUG_PRINT("info",("Host: %s ip: %s",
thd->host ? thd->host : "unknown host", sctx->host ? sctx->host : "unknown host",
thd->ip ? thd->ip : "unknown ip")); sctx->ip ? sctx->ip : "unknown ip"));
if (acl_check_host(thd->host,thd->ip)) if (acl_check_host(sctx->host, sctx->ip))
return(ER_HOST_NOT_PRIVILEGED); return(ER_HOST_NOT_PRIVILEGED);
} }
else /* Hostname given means that the connection was on a socket */ else /* Hostname given means that the connection was on a socket */
{ {
DBUG_PRINT("info",("Host: %s",thd->host)); DBUG_PRINT("info",("Host: %s", sctx->host));
thd->host_or_ip= thd->host; sctx->host_or_ip= sctx->host;
thd->ip= 0; sctx->ip= 0;
/* Reset sin_addr */ /* Reset sin_addr */
bzero((char*) &thd->remote, sizeof(thd->remote)); bzero((char*) &thd->remote, sizeof(thd->remote));
} }
@ -985,9 +987,9 @@ static int check_connection(THD *thd)
thd->charset(), &dummy_errors)]= '\0'; thd->charset(), &dummy_errors)]= '\0';
user= user_buff; user= user_buff;
if (thd->user) if (sctx->user)
x_free(thd->user); x_free(sctx->user);
if (!(thd->user= my_strdup(user, MYF(0)))) if (!(sctx->user= my_strdup(user, MYF(0))))
return (ER_OUT_OF_RESOURCES); return (ER_OUT_OF_RESOURCES);
return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE); return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE);
} }
@ -1075,13 +1077,14 @@ pthread_handler_decl(handle_one_connection,arg)
{ {
int error; int error;
NET *net= &thd->net; NET *net= &thd->net;
st_security_context *sctx= thd->security_ctx;
thd->thread_stack= (char*) &thd; thd->thread_stack= (char*) &thd;
net->no_send_error= 0; net->no_send_error= 0;
if ((error=check_connection(thd))) if ((error=check_connection(thd)))
{ // Wrong permissions { // Wrong permissions
if (error > 0) if (error > 0)
net_printf_error(thd, error, thd->host_or_ip); net_printf_error(thd, error, sctx->host_or_ip);
#ifdef __NT__ #ifdef __NT__
if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE) if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE)
my_sleep(1000); /* must wait after eof() */ my_sleep(1000); /* must wait after eof() */
@ -1090,7 +1093,7 @@ pthread_handler_decl(handle_one_connection,arg)
goto end_thread; goto end_thread;
} }
#ifdef __NETWARE__ #ifdef __NETWARE__
netware_reg_user(thd->ip, thd->user, "MySQL"); netware_reg_user(sctx->ip, sctx->user, "MySQL");
#endif #endif
if (thd->variables.max_join_size == HA_POS_ERROR) if (thd->variables.max_join_size == HA_POS_ERROR)
thd->options |= OPTION_BIG_SELECTS; thd->options |= OPTION_BIG_SELECTS;
@ -1103,7 +1106,7 @@ pthread_handler_decl(handle_one_connection,arg)
thd->set_time(); thd->set_time();
thd->init_for_queries(); thd->init_for_queries();
if (sys_init_connect.value_length && !(thd->master_access & SUPER_ACL)) if (sys_init_connect.value_length && !(sctx->master_access & SUPER_ACL))
{ {
execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect); execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect);
if (thd->query_error) if (thd->query_error)
@ -1127,8 +1130,8 @@ pthread_handler_decl(handle_one_connection,arg)
if (!thd->killed && thd->variables.log_warnings > 1) if (!thd->killed && thd->variables.log_warnings > 1)
sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION), sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
thd->thread_id,(thd->db ? thd->db : "unconnected"), thd->thread_id,(thd->db ? thd->db : "unconnected"),
thd->user ? thd->user : "unauthenticated", sctx->user ? sctx->user : "unauthenticated",
thd->host_or_ip, sctx->host_or_ip,
(net->last_errno ? ER(net->last_errno) : (net->last_errno ? ER(net->last_errno) :
ER(ER_UNKNOWN_ERROR))); ER(ER_UNKNOWN_ERROR)));
net_send_error(thd, net->last_errno, NullS); net_send_error(thd, net->last_errno, NullS);
@ -1191,7 +1194,8 @@ extern "C" pthread_handler_decl(handle_bootstrap,arg)
thd->proc_info=0; thd->proc_info=0;
thd->version=refresh_version; thd->version=refresh_version;
thd->priv_user=thd->user=(char*) my_strdup("boot", MYF(MY_WME)); thd->security_ctx->priv_user=
thd->security_ctx->user= (char*) my_strdup("boot", MYF(MY_WME));
buff= (char*) thd->net.buff; buff= (char*) thd->net.buff;
thd->init_for_queries(); thd->init_for_queries();
@ -1586,17 +1590,14 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
db= db_buff; db= db_buff;
/* Save user and privileges */ /* Save user and privileges */
uint save_master_access= thd->master_access;
uint save_db_access= thd->db_access;
uint save_db_length= thd->db_length; uint save_db_length= thd->db_length;
char *save_user= thd->user;
char *save_priv_user= thd->priv_user;
char *save_db= thd->db; char *save_db= thd->db;
st_security_context save_security_ctx= *thd->security_ctx;
USER_CONN *save_user_connect= thd->user_connect; USER_CONN *save_user_connect= thd->user_connect;
if (!(thd->user= my_strdup(user, MYF(0)))) if (!(thd->security_ctx->user= my_strdup(user, MYF(0))))
{ {
thd->user= save_user; thd->security_ctx->user= save_security_ctx.user;
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
break; break;
} }
@ -1610,12 +1611,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
/* authentication failure, we shall restore old user */ /* authentication failure, we shall restore old user */
if (res > 0) if (res > 0)
my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0)); my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
x_free(thd->user); x_free(thd->security_ctx->user);
thd->user= save_user; *thd->security_ctx= save_security_ctx;
thd->priv_user= save_priv_user;
thd->user_connect= save_user_connect; thd->user_connect= save_user_connect;
thd->master_access= save_master_access;
thd->db_access= save_db_access;
thd->db= save_db; thd->db= save_db;
thd->db_length= save_db_length; thd->db_length= save_db_length;
} }
@ -1625,7 +1623,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if (save_user_connect) if (save_user_connect)
decrease_user_connections(save_user_connect); decrease_user_connections(save_user_connect);
x_free((gptr) save_db); x_free((gptr) save_db);
x_free((gptr) save_user); x_free((gptr) save_security_ctx.user);
} }
break; break;
} }
@ -1967,12 +1965,13 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
case COM_PROCESS_INFO: case COM_PROCESS_INFO:
statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_PROCESSLIST], statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_PROCESSLIST],
&LOCK_status); &LOCK_status);
if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL)) if (!thd->security_ctx->priv_user[0] &&
check_global_access(thd, PROCESS_ACL))
break; break;
mysql_log.write(thd,command,NullS); mysql_log.write(thd,command,NullS);
mysqld_list_processes(thd, mysqld_list_processes(thd,
thd->master_access & PROCESS_ACL ? thd->security_ctx->master_access & PROCESS_ACL ?
NullS : thd->priv_user, 0); NullS : thd->security_ctx->priv_user, 0);
break; break;
case COM_PROCESS_KILL: case COM_PROCESS_KILL:
{ {
@ -2140,7 +2139,8 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
if (!thd->col_access && check_grant_db(thd,db)) if (!thd->col_access && check_grant_db(thd,db))
{ {
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
thd->priv_user, thd->priv_host, db); thd->security_ctx->priv_user, thd->security_ctx->priv_host,
db);
DBUG_RETURN(1); DBUG_RETURN(1);
} }
/* /*
@ -2398,7 +2398,8 @@ mysql_execute_command(THD *thd)
Except for the replication thread and the 'super' users. Except for the replication thread and the 'super' users.
*/ */
if (opt_readonly && if (opt_readonly &&
!(thd->slave_thread || (thd->master_access & SUPER_ACL)) && !(thd->slave_thread ||
(thd->security_ctx->master_access & SUPER_ACL)) &&
uc_update_queries[lex->sql_command]) uc_update_queries[lex->sql_command])
{ {
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only"); my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
@ -3377,11 +3378,14 @@ end_with_restore_list:
res = mysql_drop_index(thd, first_table, &lex->alter_info); res = mysql_drop_index(thd, first_table, &lex->alter_info);
break; break;
case SQLCOM_SHOW_PROCESSLIST: case SQLCOM_SHOW_PROCESSLIST:
if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL)) if (!thd->security_ctx->priv_user[0] &&
check_global_access(thd,PROCESS_ACL))
break; break;
mysqld_list_processes(thd, mysqld_list_processes(thd,
thd->master_access & PROCESS_ACL ? NullS : (thd->security_ctx->master_access & PROCESS_ACL ?
thd->priv_user,lex->verbose); NullS :
thd->security_ctx->priv_user),
lex->verbose);
break; break;
case SQLCOM_SHOW_STORAGE_ENGINES: case SQLCOM_SHOW_STORAGE_ENGINES:
res= mysqld_show_storage_engines(thd); res= mysqld_show_storage_engines(thd);
@ -3719,7 +3723,7 @@ end_with_restore_list:
select_lex->db ? is_schema_db(select_lex->db) : 0)) select_lex->db ? is_schema_db(select_lex->db) : 0))
goto error; goto error;
if (thd->user) // If not replication if (thd->security_ctx->user) // If not replication
{ {
LEX_USER *user; LEX_USER *user;
uint counter; uint counter;
@ -3735,9 +3739,9 @@ end_with_restore_list:
user->host.str); user->host.str);
// Are we trying to change a password of another user // Are we trying to change a password of another user
DBUG_ASSERT(user->host.str != 0); DBUG_ASSERT(user->host.str != 0);
if (strcmp(thd->user, user->user.str) || if (strcmp(thd->security_ctx->user, user->user.str) ||
my_strcasecmp(system_charset_info, my_strcasecmp(system_charset_info,
user->host.str, thd->host_or_ip)) user->host.str, thd->security_ctx->host_or_ip))
{ {
// TODO: use check_change_password() // TODO: use check_change_password()
if (check_acl_user(user, &counter) && user->password.str && if (check_acl_user(user, &counter) && user->password.str &&
@ -3864,8 +3868,8 @@ end_with_restore_list:
} }
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
case SQLCOM_SHOW_GRANTS: case SQLCOM_SHOW_GRANTS:
if ((thd->priv_user && if ((thd->security_ctx->priv_user &&
!strcmp(thd->priv_user,lex->grant_user->user.str)) || !strcmp(thd->security_ctx->priv_user, lex->grant_user->user.str)) ||
!check_access(thd, SELECT_ACL, "mysql",0,1,0,0)) !check_access(thd, SELECT_ACL, "mysql",0,1,0,0))
{ {
res = mysql_show_grants(thd,lex->grant_user); res = mysql_show_grants(thd,lex->grant_user);
@ -4139,7 +4143,7 @@ end_with_restore_list:
else else
{ {
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
st_sp_security_context save_ctx; st_security_context *save_ctx;
#endif #endif
ha_rows select_limit; ha_rows select_limit;
/* bits that should be cleared in thd->server_status */ /* bits that should be cleared in thd->server_status */
@ -4185,23 +4189,23 @@ end_with_restore_list:
} }
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
if (check_routine_access(thd, EXECUTE_ACL, if (check_routine_access(thd, EXECUTE_ACL,
sp->m_db.str, sp->m_name.str, TRUE, 0)) sp->m_db.str, sp->m_name.str, TRUE, 0) ||
sp_change_security_context(thd, sp, &save_ctx))
{ {
#ifndef EMBEDDED_LIBRARY #ifndef EMBEDDED_LIBRARY
thd->net.no_send_ok= nsok; thd->net.no_send_ok= nsok;
#endif #endif
goto error; goto error;
} }
sp_change_security_context(thd, sp, &save_ctx); if (save_ctx &&
if (save_ctx.changed && check_routine_access(thd, EXECUTE_ACL,
check_routine_access(thd, EXECUTE_ACL, sp->m_db.str, sp->m_name.str, TRUE, 0))
sp->m_db.str, sp->m_name.str, TRUE, 0))
{ {
#ifndef EMBEDDED_LIBRARY #ifndef EMBEDDED_LIBRARY
thd->net.no_send_ok= nsok; thd->net.no_send_ok= nsok;
#endif #endif
sp_restore_security_context(thd, sp, &save_ctx); sp_restore_security_context(thd, save_ctx);
goto error; goto error;
} }
@ -4241,7 +4245,7 @@ end_with_restore_list:
thd->variables.select_limit= select_limit; thd->variables.select_limit= select_limit;
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
sp_restore_security_context(thd, sp, &save_ctx); sp_restore_security_context(thd, save_ctx);
#endif #endif
#ifndef EMBEDDED_LIBRARY #ifndef EMBEDDED_LIBRARY
@ -4803,6 +4807,7 @@ bool
check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
bool dont_check_global_grants, bool no_errors, bool schema_db) bool dont_check_global_grants, bool no_errors, bool schema_db)
{ {
st_security_context *sctx= thd->security_ctx;
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
ulong db_access; ulong db_access;
bool db_is_pattern= test(want_access & GRANT_ACL); bool db_is_pattern= test(want_access & GRANT_ACL);
@ -4811,7 +4816,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
const char *db_name; const char *db_name;
DBUG_ENTER("check_access"); DBUG_ENTER("check_access");
DBUG_PRINT("enter",("db: %s want_access: %lu master_access: %lu", DBUG_PRINT("enter",("db: %s want_access: %lu master_access: %lu",
db ? db : "", want_access, thd->master_access)); db ? db : "", want_access, sctx->master_access));
if (save_priv) if (save_priv)
*save_priv=0; *save_priv=0;
else else
@ -4833,7 +4838,8 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
{ {
if (!no_errors) if (!no_errors)
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
thd->priv_user, thd->priv_host, db_name); thd->security_ctx->priv_user,
thd->security_ctx->priv_host, db_name);
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
else else
@ -4846,28 +4852,29 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
#ifdef NO_EMBEDDED_ACCESS_CHECKS #ifdef NO_EMBEDDED_ACCESS_CHECKS
DBUG_RETURN(0); DBUG_RETURN(0);
#else #else
if ((thd->master_access & want_access) == want_access) if ((sctx->master_access & want_access) == want_access)
{ {
/* /*
If we don't have a global SELECT privilege, we have to get the database If we don't have a global SELECT privilege, we have to get the database
specific access rights to be able to handle queries of type specific access rights to be able to handle queries of type
UPDATE t1 SET a=1 WHERE b > 0 UPDATE t1 SET a=1 WHERE b > 0
*/ */
db_access= thd->db_access; db_access= sctx->db_access;
if (!(thd->master_access & SELECT_ACL) && if (!(sctx->master_access & SELECT_ACL) &&
(db && (!thd->db || db_is_pattern || strcmp(db,thd->db)))) (db && (!thd->db || db_is_pattern || strcmp(db,thd->db))))
db_access=acl_get(thd->host, thd->ip, thd->priv_user, db, db_is_pattern); db_access=acl_get(sctx->host, sctx->ip, sctx->priv_user, db,
*save_priv=thd->master_access | db_access; db_is_pattern);
*save_priv=sctx->master_access | db_access;
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
} }
if (((want_access & ~thd->master_access) & ~(DB_ACLS | EXTRA_ACL)) || if (((want_access & ~sctx->master_access) & ~(DB_ACLS | EXTRA_ACL)) ||
! db && dont_check_global_grants) ! db && dont_check_global_grants)
{ // We can never grant this { // We can never grant this
DBUG_PRINT("error",("No possible access")); DBUG_PRINT("error",("No possible access"));
if (!no_errors) if (!no_errors)
my_error(ER_ACCESS_DENIED_ERROR, MYF(0), my_error(ER_ACCESS_DENIED_ERROR, MYF(0),
thd->priv_user, sctx->priv_user,
thd->priv_host, sctx->priv_host,
(thd->password ? (thd->password ?
ER(ER_YES) : ER(ER_YES) :
ER(ER_NO))); /* purecov: tested */ ER(ER_NO))); /* purecov: tested */
@ -4878,15 +4885,16 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
DBUG_RETURN(FALSE); // Allow select on anything DBUG_RETURN(FALSE); // Allow select on anything
if (db && (!thd->db || db_is_pattern || strcmp(db,thd->db))) if (db && (!thd->db || db_is_pattern || strcmp(db,thd->db)))
db_access=acl_get(thd->host, thd->ip, thd->priv_user, db, db_is_pattern); db_access= acl_get(sctx->host, sctx->ip, sctx->priv_user, db,
db_is_pattern);
else else
db_access=thd->db_access; db_access= sctx->db_access;
DBUG_PRINT("info",("db_access: %lu", db_access)); DBUG_PRINT("info",("db_access: %lu", db_access));
/* Remove SHOW attribute and access rights we already have */ /* Remove SHOW attribute and access rights we already have */
want_access &= ~(thd->master_access | EXTRA_ACL); want_access &= ~(sctx->master_access | EXTRA_ACL);
DBUG_PRINT("info",("db_access: %lu want_access: %lu", DBUG_PRINT("info",("db_access: %lu want_access: %lu",
db_access, want_access)); db_access, want_access));
db_access= ((*save_priv=(db_access | thd->master_access)) & want_access); db_access= ((*save_priv=(db_access | sctx->master_access)) & want_access);
/* grant_option is set if there exists a single table or column grant */ /* grant_option is set if there exists a single table or column grant */
if (db_access == want_access || if (db_access == want_access ||
@ -4897,8 +4905,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
DBUG_PRINT("error",("Access denied")); DBUG_PRINT("error",("Access denied"));
if (!no_errors) if (!no_errors)
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
thd->priv_user, sctx->priv_user, sctx->priv_host,
thd->priv_host,
(db ? db : (thd->db ? (db ? db : (thd->db ?
thd->db : thd->db :
"unknown"))); /* purecov: tested */ "unknown"))); /* purecov: tested */
@ -4932,7 +4939,7 @@ bool check_global_access(THD *thd, ulong want_access)
return 0; return 0;
#else #else
char command[128]; char command[128];
if ((thd->master_access & want_access)) if ((thd->security_ctx->master_access & want_access))
return 0; return 0;
get_privilege_desc(command, sizeof(command), want_access); get_privilege_desc(command, sizeof(command), want_access);
my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), command); my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), command);
@ -4960,7 +4967,7 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
{ {
if (!no_errors) if (!no_errors)
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
thd->priv_user, thd->priv_host, thd->security_ctx->priv_user, thd->security_ctx->priv_host,
information_schema_name.str); information_schema_name.str);
return TRUE; return TRUE;
} }
@ -4969,7 +4976,8 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
my_tz_check_n_skip_implicit_tables(&tables, my_tz_check_n_skip_implicit_tables(&tables,
thd->lex->time_zone_tables_used)) thd->lex->time_zone_tables_used))
continue; continue;
if ((thd->master_access & want_access) == (want_access & ~EXTRA_ACL) && if ((thd->security_ctx->master_access & want_access) ==
(want_access & ~EXTRA_ACL) &&
thd->db) thd->db)
tables->grant.privilege= want_access; tables->grant.privilege= want_access;
else if (tables->db && tables->db == thd->db) else if (tables->db && tables->db == thd->db)
@ -5006,7 +5014,8 @@ check_routine_access(THD *thd, ulong want_access,char *db, char *name,
tables->db= db; tables->db= db;
tables->table_name= tables->alias= name; tables->table_name= tables->alias= name;
if ((thd->master_access & want_access) == want_access && !thd->db) if ((thd->security_ctx->master_access & want_access) == want_access &&
!thd->db)
tables->grant.privilege= want_access; tables->grant.privilege= want_access;
else if (check_access(thd,want_access,db,&tables->grant.privilege, else if (check_access(thd,want_access,db,&tables->grant.privilege,
0, no_errors, test(tables->schema_table))) 0, no_errors, test(tables->schema_table)))
@ -5039,7 +5048,7 @@ bool check_some_routine_access(THD *thd, const char *db, const char *name,
bool is_proc) bool is_proc)
{ {
ulong save_priv; ulong save_priv;
if (thd->master_access & SHOW_PROC_ACLS) if (thd->security_ctx->master_access & SHOW_PROC_ACLS)
return FALSE; return FALSE;
/* /*
There are no routines in information_schema db. So we can safely There are no routines in information_schema db. So we can safely
@ -5236,6 +5245,7 @@ void mysql_reset_thd_for_next_command(THD *thd)
thd->server_status&= ~ (SERVER_MORE_RESULTS_EXISTS | thd->server_status&= ~ (SERVER_MORE_RESULTS_EXISTS |
SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_INDEX_USED |
SERVER_QUERY_NO_GOOD_INDEX_USED); SERVER_QUERY_NO_GOOD_INDEX_USED);
thd->security_ctx= &thd->main_security_ctx;
thd->tmp_table_used= 0; thd->tmp_table_used= 0;
if (!thd->in_sub_stmt) if (!thd->in_sub_stmt)
{ {
@ -6760,8 +6770,8 @@ void kill_one_thread(THD *thd, ulong id, bool only_kill_query)
VOID(pthread_mutex_unlock(&LOCK_thread_count)); VOID(pthread_mutex_unlock(&LOCK_thread_count));
if (tmp) if (tmp)
{ {
if ((thd->master_access & SUPER_ACL) || if ((thd->security_ctx->master_access & SUPER_ACL) ||
!strcmp(thd->user,tmp->user)) !strcmp(thd->security_ctx->user, tmp->security_ctx->user))
{ {
tmp->awake(only_kill_query ? THD::KILL_QUERY : THD::KILL_CONNECTION); tmp->awake(only_kill_query ? THD::KILL_QUERY : THD::KILL_CONNECTION);
error=0; error=0;
@ -7394,14 +7404,14 @@ Item *negate_expression(THD *thd, Item *expr)
TRUE Error TRUE Error
*/ */
bool default_view_definer(THD *thd, st_lex_user *definer) bool default_view_definer(st_security_context *sctx, st_lex_user *definer)
{ {
definer->user.str= thd->priv_user; definer->user.str= sctx->priv_user;
definer->user.length= strlen(thd->priv_user); definer->user.length= strlen(sctx->priv_user);
if (*thd->priv_host != 0) if (*sctx->priv_host != 0)
{ {
definer->host.str= thd->priv_host; definer->host.str= sctx->priv_host;
definer->host.length= strlen(thd->priv_host); definer->host.length= strlen(sctx->priv_host);
} }
else else
{ {

View File

@ -415,8 +415,9 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
bool mysqld_show_create_db(THD *thd, char *dbname, bool mysqld_show_create_db(THD *thd, char *dbname,
HA_CREATE_INFO *create_info) HA_CREATE_INFO *create_info)
{ {
st_security_context *sctx= thd->security_ctx;
int length; int length;
char path[FN_REFLEN]; char path[FN_REFLEN];
char buff[2048]; char buff[2048];
String buffer(buff, sizeof(buff), system_charset_info); String buffer(buff, sizeof(buff), system_charset_info);
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
@ -435,17 +436,17 @@ bool mysqld_show_create_db(THD *thd, char *dbname,
} }
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
if (test_all_bits(thd->master_access,DB_ACLS)) if (test_all_bits(sctx->master_access,DB_ACLS))
db_access=DB_ACLS; db_access=DB_ACLS;
else else
db_access= (acl_get(thd->host,thd->ip, thd->priv_user,dbname,0) | db_access= (acl_get(sctx->host, sctx->ip, sctx->priv_user, dbname, 0) |
thd->master_access); sctx->master_access);
if (!(db_access & DB_ACLS) && (!grant_option || check_grant_db(thd,dbname))) if (!(db_access & DB_ACLS) && (!grant_option || check_grant_db(thd,dbname)))
{ {
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
thd->priv_user, thd->host_or_ip, dbname); sctx->priv_user, sctx->host_or_ip, dbname);
mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR), mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR),
thd->priv_user, thd->host_or_ip, dbname); sctx->priv_user, sctx->host_or_ip, dbname);
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
#endif #endif
@ -1185,24 +1186,26 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
THD *tmp; THD *tmp;
while ((tmp=it++)) while ((tmp=it++))
{ {
st_security_context *tmp_sctx= tmp->security_ctx;
struct st_my_thread_var *mysys_var; struct st_my_thread_var *mysys_var;
if ((tmp->vio_ok() || tmp->system_thread) && if ((tmp->vio_ok() || tmp->system_thread) &&
(!user || (tmp->user && !strcmp(tmp->user,user)))) (!user || (tmp_sctx->user && !strcmp(tmp_sctx->user, user))))
{ {
thread_info *thd_info=new thread_info; thread_info *thd_info= new thread_info;
thd_info->thread_id=tmp->thread_id; thd_info->thread_id=tmp->thread_id;
thd_info->user=thd->strdup(tmp->user ? tmp->user : thd_info->user= thd->strdup(tmp_sctx->user ? tmp_sctx->user :
(tmp->system_thread ? (tmp->system_thread ?
"system user" : "unauthenticated user")); "system user" : "unauthenticated user"));
if (tmp->peer_port && (tmp->host || tmp->ip) && thd->host_or_ip[0]) if (tmp->peer_port && (tmp_sctx->host || tmp_sctx->ip) &&
thd->security_ctx->host_or_ip[0])
{ {
if ((thd_info->host= thd->alloc(LIST_PROCESS_HOST_LEN+1))) if ((thd_info->host= thd->alloc(LIST_PROCESS_HOST_LEN+1)))
my_snprintf((char *) thd_info->host, LIST_PROCESS_HOST_LEN, my_snprintf((char *) thd_info->host, LIST_PROCESS_HOST_LEN,
"%s:%u", tmp->host_or_ip, tmp->peer_port); "%s:%u", tmp_sctx->host_or_ip, tmp->peer_port);
} }
else else
thd_info->host= thd->strdup(tmp->host_or_ip); thd_info->host= thd->strdup(tmp_sctx->host_or_ip);
if ((thd_info->db=tmp->db)) // Safe test if ((thd_info->db=tmp->db)) // Safe test
thd_info->db=thd->strdup(thd_info->db); thd_info->db=thd->strdup(thd_info->db);
thd_info->command=(int) tmp->command; thd_info->command=(int) tmp->command;
@ -1253,6 +1256,9 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
VOID(pthread_mutex_unlock(&LOCK_thread_count)); VOID(pthread_mutex_unlock(&LOCK_thread_count));
thread_info *thd_info; thread_info *thd_info;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
st_security_context *sctx;
#endif
time_t now= time(0); time_t now= time(0);
while ((thd_info=thread_infos.get())) while ((thd_info=thread_infos.get()))
{ {
@ -1989,7 +1995,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
enum enum_schema_tables schema_table_idx; enum enum_schema_tables schema_table_idx;
List<char> bases; List<char> bases;
List_iterator_fast<char> it(bases); List_iterator_fast<char> it(bases);
COND *partial_cond; COND *partial_cond;
st_security_context *sctx= thd->security_ctx;
uint derived_tables= lex->derived_tables; uint derived_tables= lex->derived_tables;
int error= 1; int error= 1;
Open_tables_state open_tables_state_backup; Open_tables_state open_tables_state_backup;
@ -2061,8 +2068,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
if (!check_access(thd,SELECT_ACL, base_name, if (!check_access(thd,SELECT_ACL, base_name,
&thd->col_access, 0, 1, with_i_schema) || &thd->col_access, 0, 1, with_i_schema) ||
thd->master_access & (DB_ACLS | SHOW_DB_ACL) || sctx->master_access & (DB_ACLS | SHOW_DB_ACL) ||
acl_get(thd->host, thd->ip, thd->priv_user, base_name,0) || acl_get(sctx->host, sctx->ip, sctx->priv_user, base_name,0) ||
(grant_option && !check_grant_db(thd, base_name))) (grant_option && !check_grant_db(thd, base_name)))
#endif #endif
{ {
@ -2194,6 +2201,7 @@ int fill_schema_shemata(THD *thd, TABLE_LIST *tables, COND *cond)
bool with_i_schema; bool with_i_schema;
HA_CREATE_INFO create; HA_CREATE_INFO create;
TABLE *table= tables->table; TABLE *table= tables->table;
st_security_context *sctx= thd->security_ctx;
DBUG_ENTER("fill_schema_shemata"); DBUG_ENTER("fill_schema_shemata");
if (make_db_list(thd, &files, &idx_field_vals, if (make_db_list(thd, &files, &idx_field_vals,
@ -2212,8 +2220,8 @@ int fill_schema_shemata(THD *thd, TABLE_LIST *tables, COND *cond)
continue; continue;
} }
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
if (thd->master_access & (DB_ACLS | SHOW_DB_ACL) || if (sctx->master_access & (DB_ACLS | SHOW_DB_ACL) ||
acl_get(thd->host, thd->ip, thd->priv_user, file_name,0) || acl_get(sctx->host, sctx->ip, sctx->priv_user, file_name,0) ||
(grant_option && !check_grant_db(thd, file_name))) (grant_option && !check_grant_db(thd, file_name)))
#endif #endif
{ {
@ -2814,7 +2822,8 @@ int fill_schema_proc(THD *thd, TABLE_LIST *tables, COND *cond)
Open_tables_state open_tables_state_backup; Open_tables_state open_tables_state_backup;
DBUG_ENTER("fill_schema_proc"); DBUG_ENTER("fill_schema_proc");
strxmov(definer, thd->priv_user, "@", thd->priv_host, NullS); strxmov(definer, thd->security_ctx->priv_user, "@",
thd->security_ctx->priv_host, NullS);
/* We use this TABLE_LIST instance only for checking of privileges. */ /* We use this TABLE_LIST instance only for checking of privileges. */
bzero((char*) &proc_tables,sizeof(proc_tables)); bzero((char*) &proc_tables,sizeof(proc_tables));
proc_tables.db= (char*) "mysql"; proc_tables.db= (char*) "mysql";

View File

@ -172,7 +172,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
stronger test will be removed, the test below will hold. stronger test will be removed, the test below will hold.
*/ */
if (!trust_routine_creators && mysql_bin_log.is_open() && if (!trust_routine_creators && mysql_bin_log.is_open() &&
!(thd->master_access & SUPER_ACL)) !(thd->security_ctx->master_access & SUPER_ACL))
{ {
my_message(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER, my_message(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER,
ER(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER), MYF(0)); ER(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER), MYF(0));

View File

@ -214,12 +214,13 @@ bool mysql_create_view(THD *thd,
- same as current user - same as current user
- current user has SUPER_ACL - current user has SUPER_ACL
*/ */
if (strcmp(lex->create_view_definer->user.str, thd->priv_user) != 0 || if (strcmp(lex->create_view_definer->user.str,
thd->security_ctx->priv_user) != 0 ||
my_strcasecmp(system_charset_info, my_strcasecmp(system_charset_info,
lex->create_view_definer->host.str, lex->create_view_definer->host.str,
thd->priv_host) != 0) thd->security_ctx->priv_host) != 0)
{ {
if (!(thd->master_access & SUPER_ACL)) if (!(thd->security_ctx->master_access & SUPER_ACL))
{ {
my_error(ER_VIEW_OTHER_USER, MYF(0), lex->create_view_definer->user.str, my_error(ER_VIEW_OTHER_USER, MYF(0), lex->create_view_definer->user.str,
lex->create_view_definer->host.str); lex->create_view_definer->host.str);
@ -275,7 +276,8 @@ bool mysql_create_view(THD *thd,
if (check_some_access(thd, VIEW_ANY_ACL, tbl)) if (check_some_access(thd, VIEW_ANY_ACL, tbl))
{ {
my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0),
"ANY", thd->priv_user, thd->host_or_ip, tbl->table_name); "ANY", thd->security_ctx->priv_user,
thd->security_ctx->priv_host, tbl->table_name);
res= TRUE; res= TRUE;
goto err; goto err;
} }
@ -441,7 +443,8 @@ bool mysql_create_view(THD *thd,
{ {
/* VIEW column has more privileges */ /* VIEW column has more privileges */
my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0),
"create view", thd->priv_user, thd->host_or_ip, item->name, "create view", thd->security_ctx->priv_user,
thd->security_ctx->priv_host, item->name,
view->table_name); view->table_name);
res= TRUE; res= TRUE;
goto err; goto err;
@ -786,7 +789,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_VIEW_FRM_NO_USER, ER(ER_VIEW_FRM_NO_USER), ER_VIEW_FRM_NO_USER, ER(ER_VIEW_FRM_NO_USER),
table->db, table->table_name); table->db, table->table_name);
if (default_view_definer(thd, &table->definer)) if (default_view_definer(thd->security_ctx, &table->definer))
goto err; goto err;
} }

View File

@ -6554,15 +6554,16 @@ show_param:
LEX *lex=Lex; LEX *lex=Lex;
lex->sql_command= SQLCOM_SHOW_GRANTS; lex->sql_command= SQLCOM_SHOW_GRANTS;
THD *thd= lex->thd; THD *thd= lex->thd;
st_security_context *sctx= thd->security_ctx;
LEX_USER *curr_user; LEX_USER *curr_user;
if (!(curr_user= (LEX_USER*) thd->alloc(sizeof(st_lex_user)))) if (!(curr_user= (LEX_USER*) thd->alloc(sizeof(st_lex_user))))
YYABORT; YYABORT;
curr_user->user.str= thd->priv_user; curr_user->user.str= sctx->priv_user;
curr_user->user.length= strlen(thd->priv_user); curr_user->user.length= strlen(sctx->priv_user);
if (*thd->priv_host != 0) if (*sctx->priv_host != 0)
{ {
curr_user->host.str= thd->priv_host; curr_user->host.str= sctx->priv_host;
curr_user->host.length= strlen(thd->priv_host); curr_user->host.length= strlen(sctx->priv_host);
} }
else else
{ {
@ -7463,14 +7464,15 @@ user:
| CURRENT_USER optional_braces | CURRENT_USER optional_braces
{ {
THD *thd= YYTHD; THD *thd= YYTHD;
st_security_context *sctx= thd->security_ctx;
if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user)))) if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
YYABORT; YYABORT;
$$->user.str= thd->priv_user; $$->user.str= sctx->priv_user;
$$->user.length= strlen(thd->priv_user); $$->user.length= strlen(sctx->priv_user);
if (*thd->priv_host != 0) if (*sctx->priv_host != 0)
{ {
$$->host.str= thd->priv_host; $$->host.str= sctx->priv_host;
$$->host.length= strlen(thd->priv_host); $$->host.length= strlen(sctx->priv_host);
} }
else else
{ {
@ -7986,7 +7988,7 @@ option_value:
if (!(user=(LEX_USER*) thd->alloc(sizeof(LEX_USER)))) if (!(user=(LEX_USER*) thd->alloc(sizeof(LEX_USER))))
YYABORT; YYABORT;
user->host=null_lex_str; user->host=null_lex_str;
user->user.str=thd->priv_user; user->user.str=thd->security_ctx->priv_user;
thd->lex->var_list.push_back(new set_var_password(user, $3)); thd->lex->var_list.push_back(new set_var_password(user, $3));
} }
| PASSWORD FOR_SYM user equal text_or_password | PASSWORD FOR_SYM user equal text_or_password
@ -8919,7 +8921,8 @@ view_user:
if (!(thd->lex->create_view_definer= if (!(thd->lex->create_view_definer=
(LEX_USER*) thd->alloc(sizeof(st_lex_user)))) (LEX_USER*) thd->alloc(sizeof(st_lex_user))))
YYABORT; YYABORT;
if (default_view_definer(thd, thd->lex->create_view_definer)) if (default_view_definer(thd->security_ctx,
thd->lex->create_view_definer))
YYABORT; YYABORT;
} }
| CURRENT_USER optional_braces | CURRENT_USER optional_braces
@ -8928,7 +8931,8 @@ view_user:
if (!(thd->lex->create_view_definer= if (!(thd->lex->create_view_definer=
(LEX_USER*) thd->alloc(sizeof(st_lex_user)))) (LEX_USER*) thd->alloc(sizeof(st_lex_user))))
YYABORT; YYABORT;
if (default_view_definer(thd, thd->lex->create_view_definer)) if (default_view_definer(thd->security_ctx,
thd->lex->create_view_definer))
YYABORT; YYABORT;
} }
| DEFINER_SYM EQ ident_or_text '@' ident_or_text | DEFINER_SYM EQ ident_or_text '@' ident_or_text