From 84f029a448fc822f2fa150ab13e61b233b1e4027 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 15 Sep 2005 22:29:07 +0300 Subject: [PATCH 1/7] WL#2787 (part 2, ver 3 (merged)) changed securety context switching libmysqld/lib_sql.cc: changed securety context switching mysql-test/r/rpl_sp.result: now it show real information from changed security context of SP (checked) sql/ha_innodb.cc: changed securety context switching sql/item.cc: changed securety context switching sql/item_func.cc: changed securety context switching sql/item_strfunc.cc: changed securety context switching sql/log.cc: changed securety context switching sql/mysql_priv.h: changed securety context switching sql/mysqld.cc: changed securety context switching sql/repl_failsafe.cc: changed securety context switching sql/set_var.cc: changed securety context switching sql/slave.cc: changed securety context switching sql/sp.cc: changed securety context switching sql/sp_head.cc: changed securety context switching in case of inability to switch context we return error now sql/sp_head.h: changed securety context switching sql/sql_acl.cc: changed securety context switching sql/sql_acl.h: changed securety context switching sql/sql_base.cc: changed securety context switching sql/sql_class.cc: changed securety context switching sql/sql_class.h: changed securety context switching sql/sql_db.cc: changed securety context switching sql/sql_insert.cc: changed securety context switching sql/sql_parse.cc: changed securety context switching sql/sql_show.cc: changed securety context switching sql/sql_trigger.cc: changed securety context switching sql/sql_view.cc: changed securety context switching sql/sql_yacc.yy: changed securety context switching --- libmysqld/lib_sql.cc | 7 +- mysql-test/r/rpl_sp.result | 2 +- sql/ha_innodb.cc | 16 ++- sql/item.cc | 4 +- sql/item_func.cc | 12 +- sql/item_strfunc.cc | 13 ++- sql/log.cc | 12 +- sql/mysql_priv.h | 3 +- sql/mysqld.cc | 8 +- sql/repl_failsafe.cc | 4 +- sql/set_var.cc | 17 +-- sql/slave.cc | 9 +- sql/sp.cc | 5 +- sql/sp_head.cc | 68 +++++------- sql/sp_head.h | 22 ++-- sql/sql_acl.cc | 187 ++++++++++++++++--------------- sql/sql_acl.h | 3 +- sql/sql_base.cc | 3 +- sql/sql_class.cc | 48 ++++++-- sql/sql_class.h | 41 +++++-- sql/sql_db.cc | 19 ++-- sql/sql_insert.cc | 11 +- sql/sql_parse.cc | 218 +++++++++++++++++++------------------ sql/sql_show.cc | 49 +++++---- sql/sql_trigger.cc | 2 +- sql/sql_view.cc | 15 ++- sql/sql_yacc.yy | 30 ++--- 27 files changed, 449 insertions(+), 379 deletions(-) diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index a86d467299c..d6f41fda5f6 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -532,10 +532,9 @@ err: int check_embedded_connection(MYSQL *mysql) { THD *thd= (THD*)mysql->thd; - thd->host= (char*)my_localhost; - thd->host_or_ip= thd->host; - thd->user= my_strdup(mysql->user, MYF(0)); - thd->priv_user= thd->user; + st_security_context *sctx= thd->security_ctx; + sctx->host_or_ip= sctx->host= (char*)my_localhost; + sctx->priv_user= sctx->user= my_strdup(mysql->user, MYF(0)); return check_user(thd, COM_CONNECT, NULL, 0, thd->db, true); } diff --git a/mysql-test/r/rpl_sp.result b/mysql-test/r/rpl_sp.result index 394f93f2ea0..b1f564a0791 100644 --- a/mysql-test/r/rpl_sp.result +++ b/mysql-test/r/rpl_sp.result @@ -121,7 +121,7 @@ call foo4(); Got one of the listed errors show warnings; 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 alter procedure foo4 sql security invoker; call foo4(); diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 4ed5fadb603..fd5db6da722 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -563,25 +563,29 @@ innobase_mysql_print_thd( use the default max length */ { const THD* thd; + const st_security_context *sctx; const char* s; 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", thd->thread_id, (ulong) thd->query_id); - if (thd->host) { + if (sctx->host) { putc(' ', f); - fputs(thd->host, f); + fputs(sctx->host, f); } - if (thd->ip) { + if (sctx->ip) { putc(' ', f); - fputs(thd->ip, f); + fputs(sctx->ip, f); } - if (thd->user) { + if (sctx->user) { putc(' ', f); - fputs(thd->user, f); + fputs(sctx->user, f); } if ((s = thd->proc_info)) { diff --git a/sql/item.cc b/sql/item.cc index df57c301327..45c12d3840f 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3443,8 +3443,8 @@ bool Item_field::fix_fields(THD *thd, Item **reference) VIEW_ANY_ACL))) { my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), - "ANY", thd->priv_user, thd->host_or_ip, - field_name, tab); + "ANY", thd->security_ctx->priv_user, + thd->security_ctx->host_or_ip, field_name, tab); goto error; } } diff --git a/sql/item_func.cc b/sql/item_func.cc index 518fb011e0f..338bb4db4fe 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -4713,7 +4713,7 @@ Item_func_sp::execute(Item **itp) Sub_statement_state statement_state; #ifndef NO_EMBEDDED_ACCESS_CHECKS - st_sp_security_context save_ctx; + st_security_context *save_ctx; #endif 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 - if (check_routine_access(thd, EXECUTE_ACL, - m_sp->m_db.str, m_sp->m_name.str, 0, 0)) + if (check_routine_access(thd, EXECUTE_ACL, + m_sp->m_db.str, m_sp->m_name.str, 0, 0) || + sp_change_security_context(thd, m_sp, &save_ctx)) goto error; - sp_change_security_context(thd, m_sp, &save_ctx); - if (save_ctx.changed && + if (save_ctx && check_routine_access(thd, EXECUTE_ACL, m_sp->m_db.str, m_sp->m_name.str, 0, 0)) goto error_check_ctx; @@ -4750,7 +4750,7 @@ Item_func_sp::execute(Item **itp) #ifndef NO_EMBEDDED_ACCESS_CHECKS error_check_ctx: - sp_restore_security_context(thd, m_sp, &save_ctx); + sp_restore_security_context(thd, save_ctx); #endif error: diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 4fd33c06095..6a51ecd307d 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -473,7 +473,8 @@ String *Item_func_des_decrypt::val_str(String *str) { uint key_number=(uint) (*res)[0] & 127; // 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; VOID(pthread_mutex_lock(&LOCK_des_key_file)); @@ -1601,13 +1602,13 @@ String *Item_func_user::val_str(String *str) if (is_current) { - user= thd->priv_user; - host= thd->priv_host; + user= thd->security_ctx->priv_user; + host= thd->security_ctx->priv_host; } else { - user= thd->user; - host= thd->host_or_ip; + user= thd->main_security_ctx.user; + host= thd->main_security_ctx.priv_host; } // 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)) #ifndef NO_EMBEDDED_ACCESS_CHECKS - || !(current_thd->master_access & FILE_ACL) + || !(current_thd->security_ctx->master_access & FILE_ACL) #endif ) goto err; diff --git a/sql/log.cc b/sql/log.cc index 920a3fcff42..032ac392c00 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1476,7 +1476,7 @@ bool MYSQL_LOG::write(THD *thd,enum enum_server_command command, { // Normal thread if ((thd->options & OPTION_LOG_OFF) #ifndef NO_EMBEDDED_ACCESS_CHECKS - && (thd->master_access & SUPER_ACL) + && (thd->security_ctx->master_access & SUPER_ACL) #endif ) { @@ -1935,10 +1935,12 @@ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length, tmp_errno=errno; } if (my_b_printf(&log_file, "# User@Host: %s[%s] @ %s [%s]\n", - thd->priv_user ? thd->priv_user : "", - thd->user ? thd->user : "", - thd->host ? thd->host : "", - thd->ip ? thd->ip : "") == (uint) -1) + thd->security_ctx->priv_user ? + thd->security_ctx->priv_user : "", + thd->security_ctx->user ? thd->security_ctx->user : "", + thd->security_ctx->host ? thd->security_ctx->host : "", + thd->security_ctx->ip ? thd->security_ctx->ip : "") == + (uint) -1) tmp_errno=errno; } if (query_start_arg) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 2d45360ab64..059b9cca48e 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -484,6 +484,7 @@ typedef my_bool (*qc_engine_callback)(THD *thd, char *table_key, #include "protocol.h" #include "sql_udf.h" class user_var_entry; +class st_security_context; enum enum_var_type { 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 create_table_precheck(THD *thd, TABLE_LIST *tables, 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 { diff --git a/sql/mysqld.cc b/sql/mysqld.cc index a28ae38c675..daabb53a39d 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -776,7 +776,9 @@ static void close_connections(void) { if (global_system_variables.log_warnings) 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); } #endif @@ -3582,7 +3584,7 @@ static void bootstrap(FILE *file) thd->client_capabilities=0; my_net_init(&thd->net,(st_vio*) 0); 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++; thread_count++; @@ -3922,7 +3924,7 @@ extern "C" pthread_handler_decl(handle_connections_sockets, continue; } if (sock == unix_sock) - thd->host=(char*) my_localhost; + thd->security_ctx->host=(char*) my_localhost; #ifdef __WIN__ /* Set default wait_timeout */ ulong wait_timeout= global_system_variables.net_wait_timeout * 1000; diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 59e29d1d80c..d4d26c2ccf1 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -66,13 +66,11 @@ static int init_failsafe_rpl_thread(THD* thd) this thread has no other error reporting method). */ thd->system_thread = thd->bootstrap = 1; - thd->host_or_ip= ""; + thd->security_ctx->skip_grants(); thd->client_capabilities = 0; my_net_init(&thd->net, 0); thd->net.read_timeout = slave_net_timeout; thd->max_client_packet_length=thd->net.max_packet; - thd->master_access= ~(ulong)0; - thd->priv_user = 0; pthread_mutex_lock(&LOCK_thread_count); thd->thread_id = thread_id++; pthread_mutex_unlock(&LOCK_thread_count); diff --git a/sql/set_var.cc b/sql/set_var.cc index ff997158941..853f3570003 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -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) { - if (thd->master_access & SUPER_ACL) - return ft_boolean_check_syntax_string((byte*) var->value->str_value.c_ptr()) ? - -1 : 0; + if (thd->security_ctx->master_access & SUPER_ACL) + return (ft_boolean_check_syntax_string((byte*) + var->value->str_value.c_ptr()) ? + -1 : 0); else { 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) { #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"); 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(); #ifndef NO_EMBEDDED_ACCESS_CHECKS - if (thd->master_access & SUPER_ACL) + if (thd->security_ctx->master_access & SUPER_ACL) return 0; else { @@ -3100,10 +3101,10 @@ int set_var_password::check(THD *thd) #ifndef NO_EMBEDDED_ACCESS_CHECKS 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.length= strlen(thd->priv_host); + user->host.str= (char *) thd->security_ctx->priv_host; + user->host.length= strlen(thd->security_ctx->priv_host); } else { diff --git a/sql/slave.cc b/sql/slave.cc index d2a60076cef..7bbad84debb 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -2809,17 +2809,10 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type) DBUG_ENTER("init_slave_thread"); thd->system_thread = (thd_type == SLAVE_THD_SQL) ? SYSTEM_THREAD_SLAVE_SQL : SYSTEM_THREAD_SLAVE_IO; - /* - 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->security_ctx->skip_grants(); thd->client_capabilities = 0; my_net_init(&thd->net, 0); thd->net.read_timeout = slave_net_timeout; - thd->master_access= ~(ulong)0; thd->slave_thread = 1; set_slave_thread_options(thd); /* diff --git a/sql/sp.cc b/sql/sp.cc index 80b18571d7d..4f7b544f5c7 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -494,7 +494,8 @@ db_create_routine(THD *thd, int type, sp_head *sp) else { 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) { @@ -569,7 +570,7 @@ db_create_routine(THD *thd, int type, sp_head *sp) goto done; } } - if (!(thd->master_access & SUPER_ACL)) + if (!(thd->security_ctx->master_access & SUPER_ACL)) { my_message(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER, ER(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER), MYF(0)); diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 1a7599d7bbc..0d481047849 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1636,8 +1636,10 @@ bool check_show_routine_access(THD *thd, sp_head *sp, bool *full_access) tables.db= (char*) "mysql"; tables.table_name= tables.alias= (char*) "proc"; *full_access= (!check_table_access(thd, SELECT_ACL, &tables, 1) || - (!strcmp(sp->m_definer_user.str, thd->priv_user) && - !strcmp(sp->m_definer_host.str, thd->priv_host))); + (!strcmp(sp->m_definer_user.str, + thd->security_ctx->priv_user) && + !strcmp(sp->m_definer_host.str, + thd->security_ctx->priv_host))); if (!*full_access) return check_some_routine_access(thd, sp->m_db.str, sp->m_name.str, sp->m_type == TYPE_ENUM_PROCEDURE); @@ -2645,54 +2647,38 @@ sp_instr_error::print(String *str) */ #ifndef NO_EMBEDDED_ACCESS_CHECKS -void -sp_change_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp) +bool +sp_change_security_context(THD *thd, sp_head *sp, st_security_context **backup) { - ctxp->changed= (sp->m_chistics->suid != SP_IS_NOT_SUID && - (strcmp(sp->m_definer_user.str, thd->priv_user) || - strcmp(sp->m_definer_host.str, thd->priv_host))); + bool changed= (sp->m_chistics->suid != SP_IS_NOT_SUID && + (strcmp(sp->m_definer_user.str, + 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; - ctxp->db_access= thd->db_access; - ctxp->priv_user= thd->priv_user; - strncpy(ctxp->priv_host, thd->priv_host, sizeof(ctxp->priv_host)); - ctxp->user= thd->user; - ctxp->host= thd->host; - ctxp->ip= thd->ip; - - /* 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)); + if (acl_getroot_no_password(&sp->m_security_ctx, sp->m_definer_user.str, + sp->m_definer_host.str, + sp->m_definer_host.str, + sp->m_db.str)) + { + my_error(ER_NO_SUCH_USER, MYF(0), sp->m_definer_user.str, + sp->m_definer_host.str); + return TRUE; } - - /* Restore these immiediately */ - thd->user= ctxp->user; - thd->host= ctxp->host; - thd->ip= ctxp->ip; + *backup= thd->security_ctx; + thd->security_ctx= &sp->m_security_ctx; } + return FALSE; } 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) - { - 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)); - } + if (backup) + thd->security_ctx= backup; } #endif /* NO_EMBEDDED_ACCESS_CHECKS */ diff --git a/sql/sp_head.h b/sql/sp_head.h index 9888fe74149..ccf8c48a5eb 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -151,6 +151,9 @@ public: // Pointers set during parsing 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 * operator new(size_t size); @@ -1017,23 +1020,12 @@ private: }; // 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 +bool +sp_change_security_context(THD *thd, sp_head *sp, + st_security_context **backup); void -sp_change_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp); -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); #endif /* NO_EMBEDDED_ACCESS_CHECKS */ TABLE_LIST * diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 5e2fd17377a..95f7fed358d 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -719,6 +719,7 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh, ulong user_access= NO_ACCESS; int res= 1; ACL_USER *acl_user= 0; + st_security_context *sctx= thd->security_ctx; DBUG_ENTER("acl_getroot"); 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. */ - thd->priv_user= (char *) ""; // privileges for - *thd->priv_host= '\0'; // the user are unknown - thd->master_access= ~NO_ACCESS; // everything is allowed - bzero((char*) mqh, sizeof(*mqh)); + sctx->skip_grants(); DBUG_RETURN(0); } @@ -744,9 +742,9 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh, for (uint i=0 ; i < acl_users.elements ; i++) { 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 */ if (passwd_len == acl_user_tmp->salt_len) @@ -893,14 +891,14 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh, break; #endif /* HAVE_OPENSSL */ } - thd->master_access= user_access; - thd->priv_user= acl_user->user ? thd->user : (char *) ""; + sctx->master_access= user_access; + sctx->priv_user= acl_user->user ? sctx->user : (char *) ""; *mqh= acl_user->user_resource; 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 - *thd->priv_host= 0; + *sctx->priv_host= 0; } VOID(pthread_mutex_unlock(&acl_cache->lock)); 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 * 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; uint i; ACL_USER *acl_user= 0; 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) { - /* + /* here if mysqld's been started with --skip-grant-tables option. */ - thd->priv_user= (char *) ""; // privileges for - *thd->priv_host= '\0'; // the user are unknown - thd->master_access= ~NO_ACCESS; // everything is allowed + sctx->skip_grants(); DBUG_RETURN(0); } VOID(pthread_mutex_lock(&acl_cache->lock)); - thd->master_access= 0; - thd->db_access= 0; + sctx->master_access= 0; + sctx->db_access= 0; /* Find acl entry in user database. 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 ''. */ for (i=0 ; i < acl_users.elements ; i++) { acl_user= dynamic_element(&acl_users,i,ACL_USER*); - if ((!acl_user->user && (!thd->user || !thd->user[0])) || - (acl_user->user && strcmp(thd->user, acl_user->user) == 0)) + if ((!acl_user->user && (!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; break; @@ -962,25 +964,25 @@ int acl_getroot_no_password(THD *thd) { ACL_DB *acl_db= dynamic_element(&acl_dbs, i, ACL_DB*); 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; } } } } - thd->master_access= acl_user->access; - thd->priv_user= acl_user->user ? thd->user : (char *) ""; + sctx->master_access= acl_user->access; + sctx->priv_user= acl_user->user ? user : (char *) ""; 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 - *thd->priv_host= 0; + *sctx->priv_host= 0; } VOID(pthread_mutex_unlock(&acl_cache->lock)); DBUG_RETURN(res); @@ -1334,13 +1336,14 @@ bool check_change_password(THD *thd, const char *host, const char *user, return(1); } if (!thd->slave_thread && - (strcmp(thd->user,user) || - my_strcasecmp(system_charset_info, host, thd->priv_host))) + (strcmp(thd->security_ctx->user, user) || + my_strcasecmp(system_charset_info, host, + thd->security_ctx->priv_host))) { if (check_access(thd, UPDATE_ACL, "mysql",0,1,0,0)) 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), MYF(0)); @@ -1646,9 +1649,10 @@ static bool update_user_table(THD *thd, TABLE *table, 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 && - test(thd->master_access & CREATE_USER_ACL)); + test(sctx->master_access & CREATE_USER_ACL)); if (!create_new_users) { TABLE_LIST tl; @@ -1658,8 +1662,8 @@ static bool test_if_create_new_users(THD *thd) tl.table_name= (char*) "user"; create_new_users= 1; - db_access=acl_get(thd->host, thd->ip, - thd->priv_user, tl.db, 0); + db_access=acl_get(sctx->host, sctx->ip, + sctx->priv_user, tl.db, 0); if (!(db_access & INSERT_ACL)) { 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) { 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; } 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]; 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 @@ -2572,7 +2577,8 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name, 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 @@ -2763,7 +2769,8 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list, get_privilege_desc(command, sizeof(command), table_list->grant.want_privilege); 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); } } @@ -3486,11 +3493,11 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, uint show_table, uint number, bool no_errors) { TABLE_LIST *table; - char *user = thd->priv_user; + st_security_context *sctx= thd->security_ctx; DBUG_ENTER("check_grant"); DBUG_ASSERT(number > 0); - want_access&= ~thd->master_access; + want_access&= ~sctx->master_access; if (!want_access) DBUG_RETURN(0); // ok @@ -3508,8 +3515,9 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, table->grant.want_privilege= 0; continue; // Already checked } - if (!(grant_table= table_hash_search(thd->host,thd->ip, - table->db,user, table->table_name,0))) + if (!(grant_table= table_hash_search(sctx->host, sctx->ip, + table->db, sctx->priv_user, + table->table_name,0))) { want_access &= ~table->grant.privilege; goto err; // No grants @@ -3543,8 +3551,8 @@ err: get_privilege_desc(command, sizeof(command), want_access); my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), command, - thd->priv_user, - thd->host_or_ip, + sctx->priv_user, + sctx->host_or_ip, table ? table->table_name : "unknown"); } 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 *name, uint length, uint show_tables) { + st_security_context *sctx= thd->security_ctx; GRANT_TABLE *grant_table; GRANT_COLUMN *grant_column; 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) { grant->grant_table= - table_hash_search(thd->host, thd->ip, db_name, - thd->priv_user, + table_hash_search(sctx->host, sctx->ip, db_name, + sctx->priv_user, table_name, 0); /* purecov: inspected */ grant->version= grant_version; /* purecov: inspected */ } @@ -3601,8 +3610,8 @@ err: get_privilege_desc(command, sizeof(command), want_access); my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), command, - thd->priv_user, - thd->host_or_ip, + sctx->priv_user, + sctx->host_or_ip, 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, Field_iterator *fields) { + st_security_context *sctx= thd->security_ctx; GRANT_TABLE *grant_table; 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) { grant->grant_table= - table_hash_search(thd->host, thd->ip, db_name, - thd->priv_user, + table_hash_search(sctx->host, sctx->ip, db_name, + sctx->priv_user, table_name, 0); /* purecov: inspected */ grant->version= grant_version; /* purecov: inspected */ } @@ -3657,8 +3667,8 @@ err2: get_privilege_desc(command, sizeof(command), want_access); my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), command, - thd->priv_user, - thd->host_or_ip, + sctx->priv_user, + sctx->host_or_ip, fields->name(), table_name); return 1; @@ -3673,11 +3683,12 @@ err2: bool check_grant_db(THD *thd,const char *db) { + st_security_context *sctx= thd->security_ctx; char helping [NAME_LEN+USERNAME_LENGTH+2]; uint len; 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); for (uint idx=0 ; idx < column_priv_hash.records ; idx++) @@ -3686,7 +3697,7 @@ bool check_grant_db(THD *thd,const char *db) idx); if (len < grant_table->key_length && !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 break; @@ -3714,15 +3725,16 @@ bool check_grant_db(THD *thd,const char *db) 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 *table; - char *user= thd->priv_user; - char *host= thd->priv_host; + st_security_context *sctx= thd->security_ctx; + char *user= sctx->priv_user; + char *host= sctx->priv_host; DBUG_ENTER("check_grant_routine"); - want_access&= ~thd->master_access; + want_access&= ~sctx->master_access; if (!want_access) 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) { 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->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; rw_rdlock(&LOCK_grant); - if ((grant_proc= routine_hash_search(thd->priv_host, thd->ip, db, - thd->priv_user, name, is_proc, 0))) + if ((grant_proc= routine_hash_search(thd->security_ctx->priv_host, + thd->security_ctx->ip, db, + thd->security_ctx->priv_user, + name, is_proc, 0))) no_routine_acl= !(grant_proc->privs & SHOW_PROC_ACLS); 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 privilege; - char *user = thd->priv_user; + st_security_context *sctx= thd->security_ctx; const char *db = table->db ? table->db : thd->db; GRANT_TABLE *grant_table; @@ -3810,7 +3824,7 @@ ulong get_table_grant(THD *thd, TABLE_LIST *table) #ifdef EMBEDDED_LIBRARY grant_table= NULL; #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); #endif 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) { grant->grant_table= - table_hash_search(thd->host, thd->ip, db_name, - thd->priv_user, + table_hash_search(thd->security_ctx->host, thd->security_ctx->ip, + db_name, thd->security_ctx->priv_user, table_name, 0); /* 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 is_proc) { + st_security_context *sctx= thd->security_ctx; LEX_USER *combo; TABLE_LIST tables[1]; List user_list; bool result; - DBUG_ENTER("sp_grant_privileges"); + DBUG_ENTER("sp_grant_privileges"); if (!(combo=(LEX_USER*) thd->alloc(sizeof(st_lex_user)))) 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) && - !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) && - !find_acl_user(combo->host.str=(char*)thd->ip, combo->user.str, FALSE) && !find_acl_user(combo->host.str=(char*)"%", combo->user.str, FALSE)) DBUG_RETURN(TRUE); @@ -5557,7 +5573,7 @@ int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond) char buff[100]; TABLE *table= tables->table; 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"); 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= ""; if (no_global_access && - (strcmp(thd->priv_user, user) || + (strcmp(thd->security_ctx->priv_user, user) || my_strcasecmp(system_charset_info, curr_host, host))) continue; @@ -5610,7 +5626,7 @@ int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond) char buff[100]; TABLE *table= tables->table; 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"); 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= ""; if (no_global_access && - (strcmp(thd->priv_user, user) || + (strcmp(thd->security_ctx->priv_user, user) || my_strcasecmp(system_charset_info, curr_host, host))) continue; @@ -5665,7 +5681,7 @@ int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond) char buff[100]; TABLE *table= tables->table; 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"); 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= ""; if (no_global_access && - (strcmp(thd->priv_user, user) || + (strcmp(thd->security_ctx->priv_user, user) || my_strcasecmp(system_charset_info, curr_host, grant_table->host.hostname))) continue; @@ -5727,7 +5743,7 @@ int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond) char buff[100]; TABLE *table= tables->table; 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"); 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= ""; if (no_global_access && - (strcmp(thd->priv_user, user) || + (strcmp(thd->security_ctx->priv_user, user) || my_strcasecmp(system_charset_info, curr_host, grant_table->host.hostname))) 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, const char *db, const char *table) { + st_security_context *sctx= thd->security_ctx; /* --skip-grants */ if (!initialized) { @@ -5811,13 +5828,13 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant, } /* global privileges */ - grant->privilege= thd->master_access; + grant->privilege= sctx->master_access; - if (!thd->priv_user) + if (!sctx->priv_user) return; // it is slave /* 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) return; @@ -5827,8 +5844,8 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant, { rw_rdlock(&LOCK_grant); grant->grant_table= - table_hash_search(thd->host, thd->ip, db, - thd->priv_user, + table_hash_search(sctx->host, sctx->ip, db, + sctx->priv_user, table, 0); /* purecov: inspected */ grant->version= grant_version; /* purecov: inspected */ rw_unlock(&LOCK_grant); diff --git a/sql/sql_acl.h b/sql/sql_acl.h index 344302de9be..f62f3c12b28 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -181,7 +181,8 @@ ulong acl_get(const char *host, const char *ip, const char *user, const char *db, my_bool db_is_pattern); int acl_getroot(THD *thd, USER_RESOURCES *mqh, const char *passwd, 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 check_change_password(THD *thd, const char *host, const char *user, char *password, uint password_len); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index fb23093731a..1b8d65e21f0 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -4572,7 +4572,8 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, VIEW_ANY_ACL))) { 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); DBUG_RETURN(TRUE); } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 2699a4fa628..85bf520b56e 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -181,9 +181,10 @@ THD::THD() spcont(NULL) { stmt_arena= this; - host= user= priv_user= db= ip= 0; + db= 0; 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; query_start_used= 0; count_cuted_fields= CHECK_FIELD_IGNORE; @@ -236,9 +237,6 @@ THD::THD() server_id = ::server_id; slave_net = 0; command=COM_CONNECT; -#ifndef NO_EMBEDDED_ACCESS_CHECKS - db_access=NO_ACCESS; -#endif *scramble= '\0'; init(); @@ -426,12 +424,8 @@ THD::~THD() ha_close_connection(this); - DBUG_PRINT("info", ("freeing host")); - if (host != my_localhost) // If not pointer to constant - safeFree(host); - if (user != delayed_user) - safeFree(user); - safeFree(ip); + DBUG_PRINT("info", ("freeing security context")); + main_security_ctx.destroy(); safeFree(db); free_root(&warn_root,MYF(0)); #ifdef USING_TRANSACTIONS @@ -1827,6 +1821,38 @@ void THD::set_status_var_init() 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. diff --git a/sql/sql_class.h b/sql/sql_class.h index 1a215d39841..ddc8b092311 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -941,6 +941,32 @@ bool xid_cache_insert(XID *xid, enum xa_states xa_state); bool xid_cache_insert(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 query optimization. We register only those changes which require @@ -1113,13 +1139,8 @@ public: 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 catalog - currently selected catalog - ip - client IP 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 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 the slave SQL thread, in sql/slave.cc. */ - char *host,*user,*priv_user,*db,*catalog,*ip; - char priv_host[MAX_HOSTNAME]; + char *db, *catalog; + st_security_context main_security_ctx; + st_security_context *security_ctx; + /* remote (peer) port */ uint16 peer_port; /* @@ -1138,13 +1161,9 @@ public: a time-consuming piece that MySQL can get stuck in for a long time. */ 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 max_client_packet_length; - ulong master_access; /* Global privileges from mysql.user */ - ulong db_access; /* Privileges for current db */ HASH handler_tables_hash; /* diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 69ccbe690db..e4d8c1b8164 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -1093,6 +1093,7 @@ bool mysql_change_db(THD *thd, const char *name, bool no_access_check) bool system_db= 0; #ifndef NO_EMBEDDED_ACCESS_CHECKS ulong db_access; + st_security_context *sctx= thd->security_ctx; #endif DBUG_ENTER("mysql_change_db"); 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 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; else - db_access= (acl_get(thd->host,thd->ip, thd->priv_user,dbname,0) | - thd->master_access); + db_access= (acl_get(sctx->host, sctx->ip, sctx->priv_user, dbname, 0) | + sctx->master_access); if (!(db_access & DB_ACLS) && (!grant_option || check_grant_db(thd,dbname))) { my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), - thd->priv_user, - thd->priv_host, + sctx->priv_user, + sctx->priv_host, dbname); - mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR), - thd->priv_user, - thd->priv_host, - dbname); + mysql_log.write(thd, COM_INIT_DB, ER(ER_DBACCESS_DENIED_ERROR), + sctx->priv_user, sctx->priv_host, dbname); my_free(dbname,MYF(0)); DBUG_RETURN(1); } @@ -1167,7 +1166,7 @@ end: thd->db_length=db_length; #ifndef NO_EMBEDDED_ACCESS_CHECKS if (!no_access_check) - thd->db_access=db_access; + sctx->db_access=db_access; #endif if (system_db) { diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index f548a917bf8..cc4b291b5d1 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -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 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; uint value_count; ulong counter = 1; @@ -1264,8 +1265,8 @@ public: table(0),tables_in_use(0),stacked_inserts(0), status(0), dead(0), group_count(0) { - thd.user=thd.priv_user=(char*) delayed_user; - thd.host=(char*) my_localhost; + thd.security_ctx->user=thd.security_ctx->priv_user=(char*) delayed_user; + thd.security_ctx->host=(char*) my_localhost; thd.current_tablenr=0; thd.version=refresh_version; thd.command=COM_DELAYED_INSERT; @@ -1275,7 +1276,7 @@ public: bzero((char*) &thd.net, sizeof(thd.net)); // Safety bzero((char*) &table_list, sizeof(table_list)); // Safety thd.system_thread= SYSTEM_THREAD_DELAYED_INSERT; - thd.host_or_ip= ""; + thd.security_ctx->host_or_ip= ""; bzero((char*) &info,sizeof(info)); pthread_mutex_init(&mutex,MY_MUTEX_INIT_FAST); pthread_cond_init(&cond,NULL); @@ -1298,7 +1299,7 @@ public: pthread_cond_destroy(&cond_client); thd.unlink(); // Must be unlinked under lock x_free(thd.query); - thd.user=thd.host=0; + thd.security_ctx->user= thd.security_ctx->host=0; thread_count--; delayed_insert_threads--; VOID(pthread_mutex_unlock(&LOCK_thread_count)); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index e83530b7239..d056215c19b 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -270,10 +270,11 @@ int check_user(THD *thd, enum enum_server_command command, const char *passwd, uint passwd_len, const char *db, bool check_count) { + st_security_context *sctx= thd->security_ctx; DBUG_ENTER("check_user"); #ifdef NO_EMBEDDED_ACCESS_CHECKS - thd->master_access= GLOBAL_ACLS; // Full rights + sctx->master_access= GLOBAL_ACLS; // Full rights /* Change database if necessary */ if (db && db[0]) { @@ -340,9 +341,9 @@ int check_user(THD *thd, enum enum_server_command command, if (opt_secure_auth_local) { 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), - thd->user, thd->host_or_ip); + sctx->user, sctx->host_or_ip); DBUG_RETURN(-1); } /* 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 */ if (res == 0) { - if (!(thd->master_access & NO_ACCESS)) // authentication is OK + if (!(sctx->master_access & NO_ACCESS)) // authentication is OK { DBUG_PRINT("info", ("Capabilities: %d packet_length: %ld Host: '%s' " "Login user: '%s' Priv_user: '%s' Using password: %s " "Access: %u db: '%s'", 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", - thd->master_access, thd->db ? thd->db : "*none*")); + sctx->master_access, thd->db ? thd->db : "*none*")); if (check_count) { VOID(pthread_mutex_lock(&LOCK_thread_count)); 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)); if (!count_ok) { // 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? */ - mysql_log.write(thd,command, - (thd->priv_user == thd->user ? + mysql_log.write(thd, command, + (sctx->priv_user == sctx->user ? (char*) "%s@%s on %s" : (char*) "%s@%s as anonymous on %s"), - thd->user, thd->host_or_ip, + sctx->user, sctx->host_or_ip, 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 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 */ if ((ur.questions || ur.updates || ur.conn_per_hour || ur.user_conn || max_user_connections) && get_or_create_user_conn(thd, - opt_old_style_user_limits ? thd->user : thd->priv_user, - opt_old_style_user_limits ? thd->host_or_ip : thd->priv_host, + (opt_old_style_user_limits ? sctx->user : sctx->priv_user), + (opt_old_style_user_limits ? sctx->host_or_ip : sctx->priv_host), &ur)) DBUG_RETURN(-1); if (thd->user_connect && @@ -439,12 +440,12 @@ int check_user(THD *thd, enum enum_server_command command, DBUG_RETURN(-1); } net_printf_error(thd, ER_ACCESS_DENIED_ERROR, - thd->user, - thd->host_or_ip, + sctx->user, + sctx->host_or_ip, passwd_len ? ER(ER_YES) : ER(ER_NO)); mysql_log.write(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR), - thd->user, - thd->host_or_ip, + sctx->user, + sctx->host_or_ip, passwd_len ? ER(ER_YES) : ER(ER_NO)); DBUG_RETURN(-1); #endif /* NO_EMBEDDED_ACCESS_CHECKS */ @@ -764,45 +765,46 @@ static int check_connection(THD *thd) NET *net= &thd->net; ulong pkt_len= 0; char *end; + st_security_context *sctx= thd->security_ctx; DBUG_PRINT("info", ("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]; if (vio_peer_addr(net->vio, ip, &thd->peer_port)) 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); - thd->host_or_ip= thd->ip; + sctx->host_or_ip= sctx->ip; vio_in_addr(net->vio,&thd->remote.sin_addr); if (!(specialflag & SPECIAL_NO_RESOLVE)) { 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 */ - if (thd->host) + if (sctx->host) { - if (thd->host != my_localhost) - thd->host[min(strlen(thd->host), HOSTNAME_LENGTH)]= 0; - thd->host_or_ip= thd->host; + if (sctx->host != my_localhost) + sctx->host[min(strlen(sctx->host), HOSTNAME_LENGTH)]= 0; + sctx->host_or_ip= sctx->host; } if (connect_errors > max_connect_errors) return(ER_HOST_IS_BLOCKED); } DBUG_PRINT("info",("Host: %s ip: %s", - thd->host ? thd->host : "unknown host", - thd->ip ? thd->ip : "unknown ip")); - if (acl_check_host(thd->host,thd->ip)) + sctx->host ? sctx->host : "unknown host", + sctx->ip ? sctx->ip : "unknown ip")); + if (acl_check_host(sctx->host, sctx->ip)) return(ER_HOST_NOT_PRIVILEGED); } else /* Hostname given means that the connection was on a socket */ { - DBUG_PRINT("info",("Host: %s",thd->host)); - thd->host_or_ip= thd->host; - thd->ip= 0; + DBUG_PRINT("info",("Host: %s", sctx->host)); + sctx->host_or_ip= sctx->host; + sctx->ip= 0; /* Reset sin_addr */ bzero((char*) &thd->remote, sizeof(thd->remote)); } @@ -985,9 +987,9 @@ static int check_connection(THD *thd) thd->charset(), &dummy_errors)]= '\0'; user= user_buff; - if (thd->user) - x_free(thd->user); - if (!(thd->user= my_strdup(user, MYF(0)))) + if (sctx->user) + x_free(sctx->user); + if (!(sctx->user= my_strdup(user, MYF(0)))) return (ER_OUT_OF_RESOURCES); return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE); } @@ -1075,13 +1077,14 @@ pthread_handler_decl(handle_one_connection,arg) { int error; NET *net= &thd->net; + st_security_context *sctx= thd->security_ctx; thd->thread_stack= (char*) &thd; net->no_send_error= 0; if ((error=check_connection(thd))) { // Wrong permissions if (error > 0) - net_printf_error(thd, error, thd->host_or_ip); + net_printf_error(thd, error, sctx->host_or_ip); #ifdef __NT__ if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE) my_sleep(1000); /* must wait after eof() */ @@ -1090,7 +1093,7 @@ pthread_handler_decl(handle_one_connection,arg) goto end_thread; } #ifdef __NETWARE__ - netware_reg_user(thd->ip, thd->user, "MySQL"); + netware_reg_user(sctx->ip, sctx->user, "MySQL"); #endif if (thd->variables.max_join_size == HA_POS_ERROR) thd->options |= OPTION_BIG_SELECTS; @@ -1103,7 +1106,7 @@ pthread_handler_decl(handle_one_connection,arg) thd->set_time(); 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); if (thd->query_error) @@ -1127,8 +1130,8 @@ pthread_handler_decl(handle_one_connection,arg) if (!thd->killed && thd->variables.log_warnings > 1) sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION), thd->thread_id,(thd->db ? thd->db : "unconnected"), - thd->user ? thd->user : "unauthenticated", - thd->host_or_ip, + sctx->user ? sctx->user : "unauthenticated", + sctx->host_or_ip, (net->last_errno ? ER(net->last_errno) : ER(ER_UNKNOWN_ERROR))); 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->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; thd->init_for_queries(); @@ -1586,17 +1590,14 @@ bool dispatch_command(enum enum_server_command command, THD *thd, db= db_buff; /* 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; - char *save_user= thd->user; - char *save_priv_user= thd->priv_user; char *save_db= thd->db; + st_security_context save_security_ctx= *thd->security_ctx; 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)); break; } @@ -1610,12 +1611,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd, /* authentication failure, we shall restore old user */ if (res > 0) my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0)); - x_free(thd->user); - thd->user= save_user; - thd->priv_user= save_priv_user; + x_free(thd->security_ctx->user); + *thd->security_ctx= save_security_ctx; thd->user_connect= save_user_connect; - thd->master_access= save_master_access; - thd->db_access= save_db_access; thd->db= save_db; thd->db_length= save_db_length; } @@ -1625,7 +1623,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if (save_user_connect) decrease_user_connections(save_user_connect); x_free((gptr) save_db); - x_free((gptr) save_user); + x_free((gptr) save_security_ctx.user); } break; } @@ -1967,12 +1965,13 @@ bool dispatch_command(enum enum_server_command command, THD *thd, case COM_PROCESS_INFO: statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_PROCESSLIST], &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; mysql_log.write(thd,command,NullS); mysqld_list_processes(thd, - thd->master_access & PROCESS_ACL ? - NullS : thd->priv_user, 0); + thd->security_ctx->master_access & PROCESS_ACL ? + NullS : thd->security_ctx->priv_user, 0); break; 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)) { 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); } /* @@ -2398,7 +2398,8 @@ mysql_execute_command(THD *thd) Except for the replication thread and the 'super' users. */ 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]) { 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); break; 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; mysqld_list_processes(thd, - thd->master_access & PROCESS_ACL ? NullS : - thd->priv_user,lex->verbose); + (thd->security_ctx->master_access & PROCESS_ACL ? + NullS : + thd->security_ctx->priv_user), + lex->verbose); break; case SQLCOM_SHOW_STORAGE_ENGINES: res= mysqld_show_storage_engines(thd); @@ -3719,7 +3723,7 @@ end_with_restore_list: select_lex->db ? is_schema_db(select_lex->db) : 0)) goto error; - if (thd->user) // If not replication + if (thd->security_ctx->user) // If not replication { LEX_USER *user; uint counter; @@ -3735,9 +3739,9 @@ end_with_restore_list: user->host.str); // Are we trying to change a password of another user 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, - user->host.str, thd->host_or_ip)) + user->host.str, thd->security_ctx->host_or_ip)) { // TODO: use check_change_password() if (check_acl_user(user, &counter) && user->password.str && @@ -3864,8 +3868,8 @@ end_with_restore_list: } #ifndef NO_EMBEDDED_ACCESS_CHECKS case SQLCOM_SHOW_GRANTS: - if ((thd->priv_user && - !strcmp(thd->priv_user,lex->grant_user->user.str)) || + if ((thd->security_ctx->priv_user && + !strcmp(thd->security_ctx->priv_user, lex->grant_user->user.str)) || !check_access(thd, SELECT_ACL, "mysql",0,1,0,0)) { res = mysql_show_grants(thd,lex->grant_user); @@ -4139,7 +4143,7 @@ end_with_restore_list: else { #ifndef NO_EMBEDDED_ACCESS_CHECKS - st_sp_security_context save_ctx; + st_security_context *save_ctx; #endif ha_rows select_limit; /* bits that should be cleared in thd->server_status */ @@ -4185,23 +4189,23 @@ end_with_restore_list: } #ifndef NO_EMBEDDED_ACCESS_CHECKS - if (check_routine_access(thd, EXECUTE_ACL, - sp->m_db.str, sp->m_name.str, TRUE, 0)) + if (check_routine_access(thd, EXECUTE_ACL, + sp->m_db.str, sp->m_name.str, TRUE, 0) || + sp_change_security_context(thd, sp, &save_ctx)) { #ifndef EMBEDDED_LIBRARY thd->net.no_send_ok= nsok; #endif goto error; } - sp_change_security_context(thd, sp, &save_ctx); - if (save_ctx.changed && - check_routine_access(thd, EXECUTE_ACL, - sp->m_db.str, sp->m_name.str, TRUE, 0)) + if (save_ctx && + check_routine_access(thd, EXECUTE_ACL, + sp->m_db.str, sp->m_name.str, TRUE, 0)) { #ifndef EMBEDDED_LIBRARY thd->net.no_send_ok= nsok; #endif - sp_restore_security_context(thd, sp, &save_ctx); + sp_restore_security_context(thd, save_ctx); goto error; } @@ -4241,7 +4245,7 @@ end_with_restore_list: thd->variables.select_limit= select_limit; #ifndef NO_EMBEDDED_ACCESS_CHECKS - sp_restore_security_context(thd, sp, &save_ctx); + sp_restore_security_context(thd, save_ctx); #endif #ifndef EMBEDDED_LIBRARY @@ -4803,6 +4807,7 @@ bool check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, bool dont_check_global_grants, bool no_errors, bool schema_db) { + st_security_context *sctx= thd->security_ctx; #ifndef NO_EMBEDDED_ACCESS_CHECKS ulong db_access; 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; DBUG_ENTER("check_access"); 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) *save_priv=0; else @@ -4833,7 +4838,8 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, { if (!no_errors) 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); } else @@ -4846,28 +4852,29 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, #ifdef NO_EMBEDDED_ACCESS_CHECKS DBUG_RETURN(0); #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 specific access rights to be able to handle queries of type UPDATE t1 SET a=1 WHERE b > 0 */ - db_access= thd->db_access; - if (!(thd->master_access & SELECT_ACL) && + db_access= sctx->db_access; + if (!(sctx->master_access & SELECT_ACL) && (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); - *save_priv=thd->master_access | db_access; + db_access=acl_get(sctx->host, sctx->ip, sctx->priv_user, db, + db_is_pattern); + *save_priv=sctx->master_access | db_access; 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) { // We can never grant this DBUG_PRINT("error",("No possible access")); if (!no_errors) my_error(ER_ACCESS_DENIED_ERROR, MYF(0), - thd->priv_user, - thd->priv_host, + sctx->priv_user, + sctx->priv_host, (thd->password ? ER(ER_YES) : 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 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 - db_access=thd->db_access; + db_access= sctx->db_access; DBUG_PRINT("info",("db_access: %lu", db_access)); /* 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", 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 */ 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")); if (!no_errors) my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), - thd->priv_user, - thd->priv_host, + sctx->priv_user, sctx->priv_host, (db ? db : (thd->db ? thd->db : "unknown"))); /* purecov: tested */ @@ -4932,7 +4939,7 @@ bool check_global_access(THD *thd, ulong want_access) return 0; #else char command[128]; - if ((thd->master_access & want_access)) + if ((thd->security_ctx->master_access & want_access)) return 0; get_privilege_desc(command, sizeof(command), want_access); 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) 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); 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, thd->lex->time_zone_tables_used)) 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) tables->grant.privilege= want_access; 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->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; else if (check_access(thd,want_access,db,&tables->grant.privilege, 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) { ulong save_priv; - if (thd->master_access & SHOW_PROC_ACLS) + if (thd->security_ctx->master_access & SHOW_PROC_ACLS) return FALSE; /* 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 | SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED); + thd->security_ctx= &thd->main_security_ctx; thd->tmp_table_used= 0; 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)); if (tmp) { - if ((thd->master_access & SUPER_ACL) || - !strcmp(thd->user,tmp->user)) + if ((thd->security_ctx->master_access & SUPER_ACL) || + !strcmp(thd->security_ctx->user, tmp->security_ctx->user)) { tmp->awake(only_kill_query ? THD::KILL_QUERY : THD::KILL_CONNECTION); error=0; @@ -7394,14 +7404,14 @@ Item *negate_expression(THD *thd, Item *expr) 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.length= strlen(thd->priv_user); - if (*thd->priv_host != 0) + definer->user.str= sctx->priv_user; + definer->user.length= strlen(sctx->priv_user); + if (*sctx->priv_host != 0) { - definer->host.str= thd->priv_host; - definer->host.length= strlen(thd->priv_host); + definer->host.str= sctx->priv_host; + definer->host.length= strlen(sctx->priv_host); } else { diff --git a/sql/sql_show.cc b/sql/sql_show.cc index e6a81538d90..528876a6bbb 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -415,8 +415,9 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) bool mysqld_show_create_db(THD *thd, char *dbname, HA_CREATE_INFO *create_info) { + st_security_context *sctx= thd->security_ctx; int length; - char path[FN_REFLEN]; + char path[FN_REFLEN]; char buff[2048]; String buffer(buff, sizeof(buff), system_charset_info); #ifndef NO_EMBEDDED_ACCESS_CHECKS @@ -435,17 +436,17 @@ bool mysqld_show_create_db(THD *thd, char *dbname, } #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; else - db_access= (acl_get(thd->host,thd->ip, thd->priv_user,dbname,0) | - thd->master_access); + db_access= (acl_get(sctx->host, sctx->ip, sctx->priv_user, dbname, 0) | + sctx->master_access); if (!(db_access & DB_ACLS) && (!grant_option || check_grant_db(thd,dbname))) { 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), - thd->priv_user, thd->host_or_ip, dbname); + sctx->priv_user, sctx->host_or_ip, dbname); DBUG_RETURN(TRUE); } #endif @@ -1185,24 +1186,26 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) THD *tmp; while ((tmp=it++)) { + st_security_context *tmp_sctx= tmp->security_ctx; struct st_my_thread_var *mysys_var; 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->user=thd->strdup(tmp->user ? tmp->user : - (tmp->system_thread ? - "system user" : "unauthenticated user")); - if (tmp->peer_port && (tmp->host || tmp->ip) && thd->host_or_ip[0]) + thd_info->user= thd->strdup(tmp_sctx->user ? tmp_sctx->user : + (tmp->system_thread ? + "system user" : "unauthenticated user")); + 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))) 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 - 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 thd_info->db=thd->strdup(thd_info->db); 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)); thread_info *thd_info; +#ifndef NO_EMBEDDED_ACCESS_CHECKS + st_security_context *sctx; +#endif time_t now= time(0); 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; List bases; List_iterator_fast it(bases); - COND *partial_cond; + COND *partial_cond; + st_security_context *sctx= thd->security_ctx; uint derived_tables= lex->derived_tables; int error= 1; 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 if (!check_access(thd,SELECT_ACL, base_name, &thd->col_access, 0, 1, with_i_schema) || - thd->master_access & (DB_ACLS | SHOW_DB_ACL) || - acl_get(thd->host, thd->ip, thd->priv_user, base_name,0) || + sctx->master_access & (DB_ACLS | SHOW_DB_ACL) || + acl_get(sctx->host, sctx->ip, sctx->priv_user, base_name,0) || (grant_option && !check_grant_db(thd, base_name))) #endif { @@ -2194,6 +2201,7 @@ int fill_schema_shemata(THD *thd, TABLE_LIST *tables, COND *cond) bool with_i_schema; HA_CREATE_INFO create; TABLE *table= tables->table; + st_security_context *sctx= thd->security_ctx; DBUG_ENTER("fill_schema_shemata"); 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; } #ifndef NO_EMBEDDED_ACCESS_CHECKS - if (thd->master_access & (DB_ACLS | SHOW_DB_ACL) || - acl_get(thd->host, thd->ip, thd->priv_user, file_name,0) || + if (sctx->master_access & (DB_ACLS | SHOW_DB_ACL) || + acl_get(sctx->host, sctx->ip, sctx->priv_user, file_name,0) || (grant_option && !check_grant_db(thd, file_name))) #endif { @@ -2814,7 +2822,8 @@ int fill_schema_proc(THD *thd, TABLE_LIST *tables, COND *cond) Open_tables_state open_tables_state_backup; 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. */ bzero((char*) &proc_tables,sizeof(proc_tables)); proc_tables.db= (char*) "mysql"; diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 7342c146045..df8de59508d 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -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. */ 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, ER(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER), MYF(0)); diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 5155e605ce0..62b5169a781 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -214,12 +214,13 @@ bool mysql_create_view(THD *thd, - same as current user - 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, 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, 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)) { 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; goto err; } @@ -441,7 +443,8 @@ bool mysql_create_view(THD *thd, { /* VIEW column has more privileges */ 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); res= TRUE; goto err; @@ -786,7 +789,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_VIEW_FRM_NO_USER, ER(ER_VIEW_FRM_NO_USER), table->db, table->table_name); - if (default_view_definer(thd, &table->definer)) + if (default_view_definer(thd->security_ctx, &table->definer)) goto err; } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 20a9d945a87..26f8e0dfbd9 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -6554,15 +6554,16 @@ show_param: LEX *lex=Lex; lex->sql_command= SQLCOM_SHOW_GRANTS; THD *thd= lex->thd; + st_security_context *sctx= thd->security_ctx; LEX_USER *curr_user; if (!(curr_user= (LEX_USER*) thd->alloc(sizeof(st_lex_user)))) YYABORT; - curr_user->user.str= thd->priv_user; - curr_user->user.length= strlen(thd->priv_user); - if (*thd->priv_host != 0) + curr_user->user.str= sctx->priv_user; + curr_user->user.length= strlen(sctx->priv_user); + if (*sctx->priv_host != 0) { - curr_user->host.str= thd->priv_host; - curr_user->host.length= strlen(thd->priv_host); + curr_user->host.str= sctx->priv_host; + curr_user->host.length= strlen(sctx->priv_host); } else { @@ -7463,14 +7464,15 @@ user: | CURRENT_USER optional_braces { THD *thd= YYTHD; + st_security_context *sctx= thd->security_ctx; if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user)))) YYABORT; - $$->user.str= thd->priv_user; - $$->user.length= strlen(thd->priv_user); - if (*thd->priv_host != 0) + $$->user.str= sctx->priv_user; + $$->user.length= strlen(sctx->priv_user); + if (*sctx->priv_host != 0) { - $$->host.str= thd->priv_host; - $$->host.length= strlen(thd->priv_host); + $$->host.str= sctx->priv_host; + $$->host.length= strlen(sctx->priv_host); } else { @@ -7986,7 +7988,7 @@ option_value: if (!(user=(LEX_USER*) thd->alloc(sizeof(LEX_USER)))) YYABORT; 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)); } | PASSWORD FOR_SYM user equal text_or_password @@ -8919,7 +8921,8 @@ view_user: if (!(thd->lex->create_view_definer= (LEX_USER*) thd->alloc(sizeof(st_lex_user)))) YYABORT; - if (default_view_definer(thd, thd->lex->create_view_definer)) + if (default_view_definer(thd->security_ctx, + thd->lex->create_view_definer)) YYABORT; } | CURRENT_USER optional_braces @@ -8928,7 +8931,8 @@ view_user: if (!(thd->lex->create_view_definer= (LEX_USER*) thd->alloc(sizeof(st_lex_user)))) YYABORT; - if (default_view_definer(thd, thd->lex->create_view_definer)) + if (default_view_definer(thd->security_ctx, + thd->lex->create_view_definer)) YYABORT; } | DEFINER_SYM EQ ident_or_text '@' ident_or_text From 43dd29dfaade07858fb7e11ed791f811c6d6d33b Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 20 Sep 2005 03:05:35 +0400 Subject: [PATCH 2/7] Fix bug #12812 create view calling a function works without execute right on function Execution rigths on function was checked just before function execution, thus it was unknown on prepare stage whether user have right to execute particular function. Added access rights checking function which is called right after fixing Item_func_sp. This have additional effect that if user don't have rights for execution query will fail on earlier stage and will not waste resources on optimizing with failing on execution stage. sql/item_func.h: Fix bug#12812 create view calling a function works without execute right on function sql/item_func.cc: Fix bug#12812 create view calling a function works without execute right on function Added function Item_func_sp::check_access() which checks access rights. Added function Item_func_sp::fix_field() which calls check_access() after fixing. Item_func_sp::execute() now calls to check_access() to check access rights. mysql-test/t/sp.test: Test case for bug#12812 create view calling a function works without execute right on function mysql-test/r/sp.result: Test case for bug#12812 create view calling a function works without execute right on function --- mysql-test/r/sp.result | 12 ++++++ mysql-test/t/sp.test | 23 +++++++++++ sql/item_func.cc | 89 ++++++++++++++++++++++++++++++++++++++---- sql/item_func.h | 6 ++- 4 files changed, 121 insertions(+), 9 deletions(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 4424f4e6ad4..5cce9f9ff50 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -3193,4 +3193,16 @@ set f1= concat( 'hello', f1 ); return f1; end| drop function bug9048| +drop function if exists bug12812| +create function bug12812() returns char(2) +begin +return 'ok'; +end; +create user user_bug12812@localhost IDENTIFIED BY 'ABC'| +SELECT test.bug12812()| +ERROR 42000: execute command denied to user 'user_bug12812'@'localhost' for routine 'test.bug12812' +CREATE VIEW v1 AS SELECT test.bug12812()| +ERROR 42000: execute command denied to user 'user_bug12812'@'localhost' for routine 'test.bug12812' +DROP USER user_bug12812@localhost| +drop function bug12812| drop table t1,t2; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index f1662a57c1b..24df6ec904d 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -4043,6 +4043,29 @@ begin end| drop function bug9048| +# +# BUG#12812 create view calling a function works without execute right +# on function +--disable_warnings +drop function if exists bug12812| +--enable_warnings +create function bug12812() returns char(2) +begin + return 'ok'; +end; +create user user_bug12812@localhost IDENTIFIED BY 'ABC'| +--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK +connect (test_user_12812,localhost,user_bug12812,ABC,test)| +--error 1370 +SELECT test.bug12812()| +--error 1370 +CREATE VIEW v1 AS SELECT test.bug12812()| +# Cleanup +connection default| +disconnect test_user_12812| +DROP USER user_bug12812@localhost| +drop function bug12812| + # # BUG#NNNN: New bug synopsis # diff --git a/sql/item_func.cc b/sql/item_func.cc index 8125264ab15..f7f23ab7bf8 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -4711,14 +4711,8 @@ Item_func_sp::execute(Item **itp) } #ifndef NO_EMBEDDED_ACCESS_CHECKS - if (check_routine_access(thd, EXECUTE_ACL, - m_sp->m_db.str, m_sp->m_name.str, 0, 0)) + if (check_access(EXECUTE_ACL, 0, &save_ctx)) goto error; - sp_change_security_context(thd, m_sp, &save_ctx); - if (save_ctx.changed && - check_routine_access(thd, EXECUTE_ACL, - m_sp->m_db.str, m_sp->m_name.str, 0, 0)) - goto error_check_ctx; #endif /* Disable the binlogging if this is not a SELECT statement. If this is a @@ -4737,7 +4731,6 @@ Item_func_sp::execute(Item **itp) ER(ER_FAILED_ROUTINE_BREAK_BINLOG)); #ifndef NO_EMBEDDED_ACCESS_CHECKS -error_check_ctx: sp_restore_security_context(thd, m_sp, &save_ctx); #endif @@ -4845,3 +4838,83 @@ Item_func_sp::tmp_table_field(TABLE *t_arg) DBUG_RETURN(res); } + +/* + Check access rigths to function + + SYNOPSIS + check_access() + want_access requested access + report_error whether to set error to thd->net.report_error + sp_ctx sp security context for switching + + RETURN + 0 Access granted + 1 Requested access can't be granted or function doesn't exists + + NOTES + Checks if requested access to function can be granted to user. + If function isn't found yet, it searches function first. + If function can't be found or user don't have requested access + and report_error is true error is raised. + If security context sp_ctx is provided and access can be granted then + switch back to previous context isn't performed. + In case of access error or if context is not provided then check_access() + switches back to previous security context. +*/ +bool +Item_func_sp::check_access(ulong want_access, bool report_error, st_sp_security_context *sp_ctx) +{ + bool res; +#ifndef NO_EMBEDDED_ACCESS_CHECKS + THD *thd= current_thd; + st_sp_security_context save_ctx, *curr_ctx= sp_ctx?sp_ctx:&save_ctx; + bool ctx_switched= 0; + res= 1; + if (! m_sp && ! (m_sp= sp_find_function(thd, m_name, TRUE))) + { + my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str); + if (report_error) + thd->net.report_error= 1; + goto error; + } + + if (check_routine_access(thd, want_access, + m_sp->m_db.str, m_sp->m_name.str, 0, 0)) + { + if (report_error) + thd->net.report_error= 1; + goto error; + } + + sp_change_security_context(thd, m_sp, curr_ctx); + ctx_switched= curr_ctx->changed; + if (save_ctx.changed && + check_routine_access(thd, want_access, + m_sp->m_db.str, m_sp->m_name.str, 0, 0)) + { + if (report_error) + thd->net.report_error= 1; + goto error_check_ctx; + } + res= 0; +error_check_ctx: + if (ctx_switched && (res || !sp_ctx)) + sp_restore_security_context(thd, m_sp, curr_ctx); +error: +#else + res= 0; +#endif + return res; +}; + +bool +Item_func_sp::fix_fields(THD *thd, Item **ref) +{ + bool res; + DBUG_ASSERT(fixed == 0); + res= Item_func::fix_fields(thd, ref); + if (!res && check_access(EXECUTE_ACL, 1, NULL)) + res= 1; + return res; +} diff --git a/sql/item_func.h b/sql/item_func.h index 019abb0c072..adc1dd1b1be 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -55,7 +55,7 @@ public: NOT_FUNC, NOT_ALL_FUNC, NOW_FUNC, TRIG_COND_FUNC, GUSERVAR_FUNC, COLLATE_FUNC, - EXTRACT_FUNC, CHAR_TYPECAST_FUNC }; + EXTRACT_FUNC, CHAR_TYPECAST_FUNC, FUNC_SP }; enum optimize_type { OPTIMIZE_NONE,OPTIMIZE_KEY,OPTIMIZE_OP, OPTIMIZE_NULL, OPTIMIZE_EQUAL }; enum Type type() const { return FUNC_ITEM; } @@ -1365,6 +1365,7 @@ public: class sp_head; class sp_name; +struct st_sp_security_context; class Item_func_sp :public Item_func { @@ -1434,7 +1435,10 @@ public: { context= (Name_resolution_context *)cntx; return FALSE; } void fix_length_and_dec(); + bool check_access(ulong want_access, bool report_error, st_sp_security_context *sp_ctx); + virtual enum Functype functype() const { return FUNC_SP; } + bool fix_fields(THD *thd, Item **ref); }; From 03045ee70ab6a3adf93c2a7506a3281f411d66fa Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 20 Sep 2005 17:41:47 +0200 Subject: [PATCH 3/7] Fix fur BUG#13348: "multi-table updates and deletes are not logged if no rows were affected". Not fixed in 4.1 as not critical. Also I'm correcting error checking of multi-UPDATE/DELETE when it comes to binlogging, to make it consistent with when we rollback the statement. mysql-test/r/rpl_multi_delete.result: result update mysql-test/r/rpl_multi_update.result: result update mysql-test/t/rpl_multi_delete.test: test for BUG#13348 mysql-test/t/rpl_multi_update.test: test of BUG#13348 sql/sql_delete.cc: We now binlog multi-DELETE even if no row was updated (like we do for DELETE). I'm also correcting some error checking (< instead of <=), basing myself on when we rollback. sql/sql_update.cc: we now binlog multi-UPDATE even if no row was updated (like we do for UPDATE). Adding to existing tests to test new behaviour. I'm also correcting some error checking (< instead of <=), basing myself on when we rollback. --- mysql-test/r/rpl_multi_delete.result | 9 +++++++++ mysql-test/r/rpl_multi_update.result | 13 +++++++++++++ mysql-test/t/rpl_multi_delete.test | 26 +++++++++++++++++++++----- mysql-test/t/rpl_multi_update.test | 23 +++++++++++++++++++++++ sql/sql_delete.cc | 28 ++++++++-------------------- sql/sql_update.cc | 21 ++++++++++++++------- 6 files changed, 88 insertions(+), 32 deletions(-) diff --git a/mysql-test/r/rpl_multi_delete.result b/mysql-test/r/rpl_multi_delete.result index e94a4e7947e..d2c68eee62e 100644 --- a/mysql-test/r/rpl_multi_delete.result +++ b/mysql-test/r/rpl_multi_delete.result @@ -19,4 +19,13 @@ a select * from t2; a 1 +delete from t1; +delete from t2; +insert into t1 values(1); +insert into t2 values(1); +DELETE t1.*, t2.* from t1, t2; +select * from t1; +a +select * from t2; +a drop table t1,t2; diff --git a/mysql-test/r/rpl_multi_update.result b/mysql-test/r/rpl_multi_update.result index 34f99746c7d..04cb1bc7460 100644 --- a/mysql-test/r/rpl_multi_update.result +++ b/mysql-test/r/rpl_multi_update.result @@ -24,3 +24,16 @@ a b 1 0 2 1 UPDATE t1, t2 SET t1.b = t2.b WHERE t1.a = t2.a; +delete from t1; +delete from t2; +insert into t1 values(1,1); +insert into t2 values(1,1); +update t1 set a=2; +UPDATE t1, t2 SET t1.a = t2.a; +select * from t1; +a b +1 1 +select * from t2; +a b +1 1 +drop table t1, t2; diff --git a/mysql-test/t/rpl_multi_delete.test b/mysql-test/t/rpl_multi_delete.test index 2fd7b820b1a..0538d0d7bae 100644 --- a/mysql-test/t/rpl_multi_delete.test +++ b/mysql-test/t/rpl_multi_delete.test @@ -16,10 +16,26 @@ sync_with_master; select * from t1; select * from t2; +# End of 4.1 tests + +# Check if deleting 0 rows is binlogged (BUG#13348) + +connection master; +delete from t1; +delete from t2; + +connection slave; +# force a difference to see if master's multi-DELETE will correct it +insert into t1 values(1); +insert into t2 values(1); + +connection master; +DELETE t1.*, t2.* from t1, t2; + +sync_slave_with_master; +select * from t1; +select * from t2; + connection master; drop table t1,t2; -save_master_pos; -connection slave; -sync_with_master; - -# End of 4.1 tests +sync_slave_with_master; diff --git a/mysql-test/t/rpl_multi_update.test b/mysql-test/t/rpl_multi_update.test index dd75edb3055..f400e722556 100644 --- a/mysql-test/t/rpl_multi_update.test +++ b/mysql-test/t/rpl_multi_update.test @@ -24,3 +24,26 @@ connection slave; sync_with_master; # End of 4.1 tests + +# Check if updating 0 rows is binlogged (BUG#13348) + +connection master; +delete from t1; +delete from t2; +insert into t1 values(1,1); +insert into t2 values(1,1); + +connection slave; +# force a difference to see if master's multi-UPDATE will correct it +update t1 set a=2; + +connection master; +UPDATE t1, t2 SET t1.a = t2.a; + +sync_slave_with_master; +select * from t1; +select * from t2; + +connection master; +drop table t1, t2; +sync_slave_with_master; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 7fb9f9eccdd..7e99a5c65ee 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -258,19 +258,12 @@ cleanup: delete select; transactional_table= table->file->has_transactions(); - /* - We write to the binary log even if we deleted no row, because maybe the - user is using this command to ensure that a table is clean on master *and - on slave*. Think of the case of a user having played separately with the - master's table and slave's table and wanting to take a fresh identical - start now. - error < 0 means "really no error". error <= 0 means "maybe some error". - */ - if ((deleted || (error < 0)) && (error <= 0 || !transactional_table)) + /* See similar binlogging code in sql_update.cc, for comments */ + if ((error < 0) || (deleted && !transactional_table)) { if (mysql_bin_log.is_open()) { - if (error <= 0) + if (error < 0) thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, transactional_table, FALSE); @@ -718,6 +711,9 @@ bool multi_delete::send_eof() /* Does deletes for the last n - 1 tables, returns 0 if ok */ int local_error= do_deletes(); // returns 0 if success + /* compute a total error to know if something failed */ + local_error= local_error || error; + /* reset used flags */ thd->proc_info="end"; @@ -730,19 +726,11 @@ bool multi_delete::send_eof() query_cache_invalidate3(thd, delete_tables, 1); } - /* - Write the SQL statement to the binlog if we deleted - rows and we succeeded, or also in an error case when there - was a non-transaction-safe table involved, since - modifications in it cannot be rolled back. - Note that if we deleted nothing we don't write to the binlog (TODO: - fix this). - */ - if (deleted && ((error <= 0 && !local_error) || normal_tables)) + if ((local_error == 0) || (deleted && normal_tables)) { if (mysql_bin_log.is_open()) { - if (error <= 0 && !local_error) + if (local_error == 0) thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, transactional_tables, FALSE); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index a75eef9324c..efdf1291305 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -475,11 +475,20 @@ int mysql_update(THD *thd, query_cache_invalidate3(thd, table_list, 1); } - if ((updated || (error < 0)) && (error <= 0 || !transactional_table)) + /* + error < 0 means really no error at all: we processed all rows until the + last one without error. error > 0 means an error (e.g. unique key + violation and no IGNORE or REPLACE). error == 0 is also an error (if + preparing the record or invoking before triggers fails). See + ha_autocommit_or_rollback(error>=0) and DBUG_RETURN(error>=0) below. + Sometimes we want to binlog even if we updated no rows, in case user used + it to be sure master and slave are in same state. + */ + if ((error < 0) || (updated && !transactional_table)) { if (mysql_bin_log.is_open()) { - if (error <= 0) + if (error < 0) thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, transactional_table, FALSE); @@ -1439,16 +1448,14 @@ bool multi_update::send_eof() /* Write the SQL statement to the binlog if we updated rows and we succeeded or if we updated some non - transacational tables. - Note that if we updated nothing we don't write to the binlog (TODO: - fix this). + transactional tables. */ - if (updated && (local_error <= 0 || !trans_safe)) + if ((local_error == 0) || (updated && !trans_safe)) { if (mysql_bin_log.is_open()) { - if (local_error <= 0) + if (local_error == 0) thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, transactional_tables, FALSE); From 58dbcea4b4b1ad35559f0836286dfb93f1f93fb5 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 20 Sep 2005 21:35:57 +0400 Subject: [PATCH 4/7] item_func.cc: Fixed mistake in fix for bug#12812 sql/item_func.cc: Fixed mistake in fix for bug#12812 --- sql/item_func.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/item_func.cc b/sql/item_func.cc index 9503318e145..de221621ac0 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -4901,7 +4901,7 @@ Item_func_sp::check_access(ulong want_access, bool report_error, st_sp_security_ sp_change_security_context(thd, m_sp, curr_ctx); ctx_switched= curr_ctx->changed; - if (save_ctx.changed && + if (curr_ctx->changed && check_routine_access(thd, want_access, m_sp->m_db.str, m_sp->m_name.str, 0, 0)) { From 3fe752f527895bcd6b32f9cf7f1dcd983d4b4313 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 20 Sep 2005 21:20:38 +0300 Subject: [PATCH 5/7] WL#2787 (Add view definer/owner to the view definition (.frm) to check privileges on used tables and stored routines when using a VIEW.) Part 2 postreview fixes. sql/ha_innodb.cc: Renamed structure st_security_context to class Security_context sql/item_func.cc: Renamed structure st_security_context to class Security_context sql/item_strfunc.cc: fixed USER() function sql/log.cc: variable used to optimize access to security context sql/mysql_priv.h: Renamed structure st_security_context to class Security_context sql/mysqld.cc: main security context used direcly sql/sp_head.cc: Renamed structure st_security_context to class Security_context removed unneed variable sql/sp_head.h: Comment inmroved Renamed structure st_security_context to class Security_context sql/sql_acl.cc: Renamed structure st_security_context to class Security_context fixed function comment and return value variable used to optimize access to security context Renamed method of Security_ontext sql/sql_acl.h: fixed return value type sql/sql_class.cc: Renamed structure st_security_context to class Security_context sql/sql_class.h: Renamed structure st_security_context to class Security_context Method renamed sql/sql_db.cc: Renamed structure st_security_context to class Security_context fixed layout sql/sql_parse.cc: registration of wanted access for underlying tables sql/sql_show.cc: Renamed structure st_security_context to class Security_context fixed layout sql/sql_yacc.yy: Renamed structure st_security_context to class Security_context --- sql/ha_innodb.cc | 2 +- sql/item_func.cc | 2 +- sql/item_strfunc.cc | 2 +- sql/log.cc | 11 ++--- sql/mysql_priv.h | 4 +- sql/mysqld.cc | 4 +- sql/sp_head.cc | 16 +++---- sql/sp_head.h | 11 +++-- sql/sql_acl.cc | 68 ++++++++++++++++------------ sql/sql_acl.h | 4 +- sql/sql_class.cc | 6 +-- sql/sql_class.h | 12 ++--- sql/sql_db.cc | 6 +-- sql/sql_parse.cc | 105 +++++++++++++++++++++++++------------------- sql/sql_show.cc | 14 +++--- sql/sql_yacc.yy | 4 +- 16 files changed, 151 insertions(+), 120 deletions(-) diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index fd5db6da722..5ded583ded6 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -563,7 +563,7 @@ innobase_mysql_print_thd( use the default max length */ { const THD* thd; - const st_security_context *sctx; + const Security_context *sctx; const char* s; thd = (const THD*) input_thd; diff --git a/sql/item_func.cc b/sql/item_func.cc index 338bb4db4fe..95ac2f9a697 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -4713,7 +4713,7 @@ Item_func_sp::execute(Item **itp) Sub_statement_state statement_state; #ifndef NO_EMBEDDED_ACCESS_CHECKS - st_security_context *save_ctx; + Security_context *save_ctx; #endif if (! m_sp && ! (m_sp= sp_find_function(thd, m_name, TRUE))) diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 6a51ecd307d..1876a5ecaf7 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1608,7 +1608,7 @@ String *Item_func_user::val_str(String *str) else { user= thd->main_security_ctx.user; - host= thd->main_security_ctx.priv_host; + host= thd->main_security_ctx.host; } // For system threads (e.g. replication SQL thread) user may be empty diff --git a/sql/log.cc b/sql/log.cc index 032ac392c00..8010d03b46a 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1915,6 +1915,7 @@ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length, } if (!(specialflag & SPECIAL_SHORT_LOG_FORMAT) || query_start_arg) { + Security_context *sctx= thd->security_ctx; current_time=time(NULL); if (current_time != last_time) { @@ -1935,11 +1936,11 @@ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length, tmp_errno=errno; } if (my_b_printf(&log_file, "# User@Host: %s[%s] @ %s [%s]\n", - thd->security_ctx->priv_user ? - thd->security_ctx->priv_user : "", - thd->security_ctx->user ? thd->security_ctx->user : "", - thd->security_ctx->host ? thd->security_ctx->host : "", - thd->security_ctx->ip ? thd->security_ctx->ip : "") == + sctx->priv_user ? + sctx->priv_user : "", + sctx->user ? sctx->user : "", + sctx->host ? sctx->host : "", + sctx->ip ? sctx->ip : "") == (uint) -1) tmp_errno=errno; } diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 059b9cca48e..fc7bac89274 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -484,7 +484,7 @@ typedef my_bool (*qc_engine_callback)(THD *thd, char *table_key, #include "protocol.h" #include "sql_udf.h" class user_var_entry; -class st_security_context; +class Security_context; enum enum_var_type { OPT_DEFAULT= 0, OPT_SESSION, OPT_GLOBAL @@ -516,7 +516,7 @@ bool delete_precheck(THD *thd, TABLE_LIST *tables); bool insert_precheck(THD *thd, TABLE_LIST *tables); bool create_table_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *create_table); -bool default_view_definer(st_security_context *sctx, st_lex_user *definer); +bool default_view_definer(Security_context *sctx, st_lex_user *definer); enum enum_mysql_completiontype { diff --git a/sql/mysqld.cc b/sql/mysqld.cc index daabb53a39d..c76481f6583 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -777,8 +777,8 @@ static void close_connections(void) if (global_system_variables.log_warnings) sql_print_warning(ER(ER_FORCING_CLOSE),my_progname, tmp->thread_id, - (tmp->security_ctx->user ? - tmp->security_ctx->user : "")); + (tmp->main_security_ctx.user ? + tmp->main_security_ctx.user : "")); close_connection(tmp,0,0); } #endif diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 0d481047849..157672f2a86 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -2648,16 +2648,14 @@ sp_instr_error::print(String *str) #ifndef NO_EMBEDDED_ACCESS_CHECKS bool -sp_change_security_context(THD *thd, sp_head *sp, st_security_context **backup) +sp_change_security_context(THD *thd, sp_head *sp, Security_context **backup) { - bool changed= (sp->m_chistics->suid != SP_IS_NOT_SUID && - (strcmp(sp->m_definer_user.str, - thd->security_ctx->priv_user) || - my_strcasecmp(system_charset_info, sp->m_definer_host.str, - thd->security_ctx->priv_host))); - *backup= 0; - if (changed) + if (sp->m_chistics->suid != SP_IS_NOT_SUID && + (strcmp(sp->m_definer_user.str, + thd->security_ctx->priv_user) || + my_strcasecmp(system_charset_info, sp->m_definer_host.str, + thd->security_ctx->priv_host))) { if (acl_getroot_no_password(&sp->m_security_ctx, sp->m_definer_user.str, sp->m_definer_host.str, @@ -2675,7 +2673,7 @@ sp_change_security_context(THD *thd, sp_head *sp, st_security_context **backup) } void -sp_restore_security_context(THD *thd, st_security_context *backup) +sp_restore_security_context(THD *thd, Security_context *backup) { if (backup) thd->security_ctx= backup; diff --git a/sql/sp_head.h b/sql/sp_head.h index ccf8c48a5eb..59169dc35cd 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -151,8 +151,11 @@ public: // Pointers set during parsing 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; + /* + Security context for stored routine which should be run under + definer privileges. + */ + Security_context m_security_ctx; static void * operator new(size_t size); @@ -1023,9 +1026,9 @@ private: #ifndef NO_EMBEDDED_ACCESS_CHECKS bool sp_change_security_context(THD *thd, sp_head *sp, - st_security_context **backup); + Security_context **backup); void -sp_restore_security_context(THD *thd, st_security_context *backup); +sp_restore_security_context(THD *thd, Security_context *backup); #endif /* NO_EMBEDDED_ACCESS_CHECKS */ TABLE_LIST * diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 95f7fed358d..d6c473ec8bc 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -719,7 +719,7 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh, ulong user_access= NO_ACCESS; int res= 1; ACL_USER *acl_user= 0; - st_security_context *sctx= thd->security_ctx; + Security_context *sctx= thd->security_ctx; DBUG_ENTER("acl_getroot"); if (!initialized) @@ -728,6 +728,7 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh, here if mysqld's been started with --skip-grant-tables option. */ sctx->skip_grants(); + bzero((char*) mqh, sizeof(*mqh)); DBUG_RETURN(0); } @@ -906,13 +907,24 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh, /* - * This is like acl_getroot() above, but it doesn't check password, - * and we don't care about the user resources. - * Used to get access rights for SQL SECURITY DEFINER invocation of - * stored procedures. - */ -int acl_getroot_no_password(st_security_context *sctx, char *user, char *host, - char *ip, char *db) + This is like acl_getroot() above, but it doesn't check password, + and we don't care about the user resources. + + SYNOPSIS + acl_getroot_no_password() + sctx Context which should be initialized + user user name + host host name + ip IP + db current data base name + + RETURN + FALSE OK + TRUE Error +*/ + +bool acl_getroot_no_password(Security_context *sctx, char *user, char *host, + char *ip, char *db) { int res= 1; uint i; @@ -930,7 +942,7 @@ int acl_getroot_no_password(st_security_context *sctx, char *user, char *host, here if mysqld's been started with --skip-grant-tables option. */ sctx->skip_grants(); - DBUG_RETURN(0); + DBUG_RETURN(FALSE); } VOID(pthread_mutex_lock(&acl_cache->lock)); @@ -1649,7 +1661,7 @@ static bool update_user_table(THD *thd, TABLE *table, static bool test_if_create_new_users(THD *thd) { - st_security_context *sctx= thd->security_ctx; + Security_context *sctx= thd->security_ctx; bool create_new_users= test(sctx->master_access & INSERT_ACL) || (!opt_safe_user_create && test(sctx->master_access & CREATE_USER_ACL)); @@ -3493,7 +3505,7 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, uint show_table, uint number, bool no_errors) { TABLE_LIST *table; - st_security_context *sctx= thd->security_ctx; + Security_context *sctx= thd->security_ctx; DBUG_ENTER("check_grant"); DBUG_ASSERT(number > 0); @@ -3563,7 +3575,7 @@ bool check_grant_column(THD *thd, GRANT_INFO *grant, const char *db_name, const char *table_name, const char *name, uint length, uint show_tables) { - st_security_context *sctx= thd->security_ctx; + Security_context *sctx= thd->security_ctx; GRANT_TABLE *grant_table; GRANT_COLUMN *grant_column; ulong want_access= grant->want_privilege & ~grant->privilege; @@ -3623,7 +3635,7 @@ bool check_grant_all_columns(THD *thd, ulong want_access, GRANT_INFO *grant, const char* db_name, const char *table_name, Field_iterator *fields) { - st_security_context *sctx= thd->security_ctx; + Security_context *sctx= thd->security_ctx; GRANT_TABLE *grant_table; GRANT_COLUMN *grant_column; @@ -3683,7 +3695,7 @@ err2: bool check_grant_db(THD *thd,const char *db) { - st_security_context *sctx= thd->security_ctx; + Security_context *sctx= thd->security_ctx; char helping [NAME_LEN+USERNAME_LENGTH+2]; uint len; bool error= 1; @@ -3729,7 +3741,7 @@ bool check_grant_routine(THD *thd, ulong want_access, TABLE_LIST *procs, bool is_proc, bool no_errors) { TABLE_LIST *table; - st_security_context *sctx= thd->security_ctx; + Security_context *sctx= thd->security_ctx; char *user= sctx->priv_user; char *host= sctx->priv_host; DBUG_ENTER("check_grant_routine"); @@ -3797,10 +3809,11 @@ bool check_routine_level_acl(THD *thd, const char *db, const char *name, if (grant_option) { GRANT_NAME *grant_proc; + Security_context *sctx= thd->security_ctx; rw_rdlock(&LOCK_grant); - if ((grant_proc= routine_hash_search(thd->security_ctx->priv_host, - thd->security_ctx->ip, db, - thd->security_ctx->priv_user, + if ((grant_proc= routine_hash_search(sctx->priv_host, + sctx->ip, db, + sctx->priv_user, name, is_proc, 0))) no_routine_acl= !(grant_proc->privs & SHOW_PROC_ACLS); rw_unlock(&LOCK_grant); @@ -3816,7 +3829,7 @@ bool check_routine_level_acl(THD *thd, const char *db, const char *name, ulong get_table_grant(THD *thd, TABLE_LIST *table) { ulong privilege; - st_security_context *sctx= thd->security_ctx; + Security_context *sctx= thd->security_ctx; const char *db = table->db ? table->db : thd->db; GRANT_TABLE *grant_table; @@ -3867,9 +3880,10 @@ ulong get_column_grant(THD *thd, GRANT_INFO *grant, /* reload table if someone has modified any grants */ if (grant->version != grant_version) { + Security_context *sctx= thd->security_ctx; grant->grant_table= - table_hash_search(thd->security_ctx->host, thd->security_ctx->ip, - db_name, thd->security_ctx->priv_user, + table_hash_search(sctx->host, sctx->ip, + db_name, sctx->priv_user, table_name, 0); /* purecov: inspected */ grant->version= grant_version; /* purecov: inspected */ } @@ -5439,7 +5453,7 @@ 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 is_proc) { - st_security_context *sctx= thd->security_ctx; + Security_context *sctx= thd->security_ctx; LEX_USER *combo; TABLE_LIST tables[1]; List user_list; @@ -5573,7 +5587,7 @@ int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond) char buff[100]; TABLE *table= tables->table; bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1,0); - char *curr_host= thd->security_ctx->get_priv_host(); + char *curr_host= thd->security_ctx->priv_host_name(); DBUG_ENTER("fill_schema_user_privileges"); for (counter=0 ; counter < acl_users.elements ; counter++) @@ -5626,7 +5640,7 @@ int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond) char buff[100]; TABLE *table= tables->table; bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1,0); - char *curr_host= thd->security_ctx->get_priv_host(); + char *curr_host= thd->security_ctx->priv_host_name(); DBUG_ENTER("fill_schema_schema_privileges"); for (counter=0 ; counter < acl_dbs.elements ; counter++) @@ -5681,7 +5695,7 @@ int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond) char buff[100]; TABLE *table= tables->table; bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1,0); - char *curr_host= thd->security_ctx->get_priv_host(); + char *curr_host= thd->security_ctx->priv_host_name(); DBUG_ENTER("fill_schema_table_privileges"); for (index=0 ; index < column_priv_hash.records ; index++) @@ -5743,7 +5757,7 @@ int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond) char buff[100]; TABLE *table= tables->table; bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1,0); - char *curr_host= thd->security_ctx->get_priv_host(); + char *curr_host= thd->security_ctx->priv_host_name(); DBUG_ENTER("fill_schema_table_privileges"); for (index=0 ; index < column_priv_hash.records ; index++) @@ -5819,7 +5833,7 @@ int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond) void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant, const char *db, const char *table) { - st_security_context *sctx= thd->security_ctx; + Security_context *sctx= thd->security_ctx; /* --skip-grants */ if (!initialized) { diff --git a/sql/sql_acl.h b/sql/sql_acl.h index f62f3c12b28..0e50737f84c 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -181,8 +181,8 @@ ulong acl_get(const char *host, const char *ip, const char *user, const char *db, my_bool db_is_pattern); int acl_getroot(THD *thd, USER_RESOURCES *mqh, const char *passwd, uint passwd_len); -int acl_getroot_no_password(st_security_context *sctx, char *user, char *host, - char *ip, char *db); +bool acl_getroot_no_password(Security_context *sctx, char *user, char *host, + char *ip, char *db); bool acl_check_host(const char *host, const char *ip); bool check_change_password(THD *thd, const char *host, const char *user, char *password, uint password_len); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 85bf520b56e..3d2322f7fff 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1822,7 +1822,7 @@ void THD::set_status_var_init() } -void st_security_context::init() +void Security_context::init() { host= user= priv_user= ip= 0; host_or_ip= "connecting host"; @@ -1832,7 +1832,7 @@ void st_security_context::init() } -void st_security_context::destroy() +void Security_context::destroy() { // If not pointer to constant if (host != my_localhost) @@ -1843,7 +1843,7 @@ void st_security_context::destroy() } -void st_security_context::skip_grants() +void Security_context::skip_grants() { /* privileges for the user are unknown everything is allowed */ host_or_ip= (char *)""; diff --git a/sql/sql_class.h b/sql/sql_class.h index ddc8b092311..08194d6bd52 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -942,15 +942,17 @@ bool xid_cache_insert(XID_STATE *xid_state); void xid_cache_delete(XID_STATE *xid_state); -struct st_security_context { +class Security_context { +public: /* 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. + priv_user - The user privilege we are using. May be "" for anonymous user. ip - client IP */ char *host, *user, *priv_user, *ip; + /* The host privilege we are using */ char priv_host[MAX_HOSTNAME]; /* points to host if host is available, otherwise points to ip */ const char *host_or_ip; @@ -960,7 +962,7 @@ struct st_security_context { void init(); void destroy(); void skip_grants(); - inline char *get_priv_host() + inline char *priv_host_name() { return (*priv_host ? priv_host : (char *)"%"); } @@ -1150,8 +1152,8 @@ public: the slave SQL thread, in sql/slave.cc. */ char *db, *catalog; - st_security_context main_security_ctx; - st_security_context *security_ctx; + Security_context main_security_ctx; + Security_context *security_ctx; /* remote (peer) port */ uint16 peer_port; diff --git a/sql/sql_db.cc b/sql/sql_db.cc index e4d8c1b8164..d89800e34f8 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -1093,7 +1093,7 @@ bool mysql_change_db(THD *thd, const char *name, bool no_access_check) bool system_db= 0; #ifndef NO_EMBEDDED_ACCESS_CHECKS ulong db_access; - st_security_context *sctx= thd->security_ctx; + Security_context *sctx= thd->security_ctx; #endif DBUG_ENTER("mysql_change_db"); DBUG_PRINT("enter",("name: '%s'",name)); @@ -1131,7 +1131,7 @@ bool mysql_change_db(THD *thd, const char *name, bool no_access_check) #ifndef NO_EMBEDDED_ACCESS_CHECKS if (!no_access_check) { - if (test_all_bits(sctx->master_access,DB_ACLS)) + if (test_all_bits(sctx->master_access, DB_ACLS)) db_access=DB_ACLS; else db_access= (acl_get(sctx->host, sctx->ip, sctx->priv_user, dbname, 0) | @@ -1166,7 +1166,7 @@ end: thd->db_length=db_length; #ifndef NO_EMBEDDED_ACCESS_CHECKS if (!no_access_check) - sctx->db_access=db_access; + sctx->db_access= db_access; #endif if (system_db) { diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index d056215c19b..8f259b21919 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -270,11 +270,10 @@ int check_user(THD *thd, enum enum_server_command command, const char *passwd, uint passwd_len, const char *db, bool check_count) { - st_security_context *sctx= thd->security_ctx; DBUG_ENTER("check_user"); #ifdef NO_EMBEDDED_ACCESS_CHECKS - sctx->master_access= GLOBAL_ACLS; // Full rights + thd->ain_security_ctx.master_access= GLOBAL_ACLS; // Full rights /* Change database if necessary */ if (db && db[0]) { @@ -341,15 +340,17 @@ int check_user(THD *thd, enum enum_server_command command, if (opt_secure_auth_local) { net_printf_error(thd, ER_SERVER_IS_IN_SECURE_AUTH_MODE, - sctx->user, sctx->host_or_ip); + thd->main_security_ctx.user, + thd->main_security_ctx.host_or_ip); mysql_log.write(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE), - sctx->user, sctx->host_or_ip); + thd->main_security_ctx.user, + thd->main_security_ctx.host_or_ip); DBUG_RETURN(-1); } /* We have to read very specific packet size */ if (send_old_password_request(thd) || my_net_read(net) != SCRAMBLE_LENGTH_323 + 1) - { + { inc_host_errors(&thd->remote.sin_addr); DBUG_RETURN(ER_HANDSHAKE_ERROR); } @@ -361,22 +362,27 @@ int check_user(THD *thd, enum enum_server_command command, /* here res is always >= 0 */ if (res == 0) { - if (!(sctx->master_access & NO_ACCESS)) // authentication is OK + if (!(thd->main_security_ctx.master_access & + NO_ACCESS)) // authentication is OK { DBUG_PRINT("info", ("Capabilities: %d packet_length: %ld Host: '%s' " "Login user: '%s' Priv_user: '%s' Using password: %s " "Access: %u db: '%s'", - thd->client_capabilities, thd->max_client_packet_length, - sctx->host_or_ip, sctx->user, sctx->priv_user, + thd->client_capabilities, + thd->max_client_packet_length, + thd->main_security_ctx.host_or_ip, + thd->main_security_ctx.user, + thd->main_security_ctx.priv_user, passwd_len ? "yes": "no", - sctx->master_access, thd->db ? thd->db : "*none*")); + thd->main_security_ctx.master_access, + (thd->db ? thd->db : "*none*"))); if (check_count) { VOID(pthread_mutex_lock(&LOCK_thread_count)); bool count_ok= thread_count <= max_connections + delayed_insert_threads - || (sctx->master_access & SUPER_ACL); + || (thd->main_security_ctx.master_access & SUPER_ACL); VOID(pthread_mutex_unlock(&LOCK_thread_count)); if (!count_ok) { // too many connections @@ -387,10 +393,12 @@ int check_user(THD *thd, enum enum_server_command command, /* Why logging is performed before all checks've passed? */ mysql_log.write(thd, command, - (sctx->priv_user == sctx->user ? + (thd->main_security_ctx.priv_user == + thd->main_security_ctx.user ? (char*) "%s@%s on %s" : (char*) "%s@%s as anonymous on %s"), - sctx->user, sctx->host_or_ip, + thd->main_security_ctx.user, + thd->main_security_ctx.host_or_ip, db ? db : (char*) ""); /* @@ -398,14 +406,16 @@ 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 may not have an active database to set. */ - sctx->db_access=0; + thd->main_security_ctx.db_access=0; /* 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 || max_user_connections) && get_or_create_user_conn(thd, - (opt_old_style_user_limits ? sctx->user : sctx->priv_user), - (opt_old_style_user_limits ? sctx->host_or_ip : sctx->priv_host), + (opt_old_style_user_limits ? thd->main_security_ctx.user : + thd->main_security_ctx.priv_user), + (opt_old_style_user_limits ? thd->main_security_ctx.host_or_ip : + thd->main_security_ctx.priv_host), &ur)) DBUG_RETURN(-1); if (thd->user_connect && @@ -440,12 +450,12 @@ int check_user(THD *thd, enum enum_server_command command, DBUG_RETURN(-1); } net_printf_error(thd, ER_ACCESS_DENIED_ERROR, - sctx->user, - sctx->host_or_ip, + thd->main_security_ctx.user, + thd->main_security_ctx.host_or_ip, passwd_len ? ER(ER_YES) : ER(ER_NO)); mysql_log.write(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR), - sctx->user, - sctx->host_or_ip, + thd->main_security_ctx.user, + thd->main_security_ctx.host_or_ip, passwd_len ? ER(ER_YES) : ER(ER_NO)); DBUG_RETURN(-1); #endif /* NO_EMBEDDED_ACCESS_CHECKS */ @@ -765,46 +775,49 @@ static int check_connection(THD *thd) NET *net= &thd->net; ulong pkt_len= 0; char *end; - st_security_context *sctx= thd->security_ctx; DBUG_PRINT("info", ("New connection received on %s", vio_description(net->vio))); - if (!sctx->host) // If TCP/IP connection + if (!thd->main_security_ctx.host) // If TCP/IP connection { char ip[30]; if (vio_peer_addr(net->vio, ip, &thd->peer_port)) return (ER_BAD_HOST_ERROR); - if (!(sctx->ip= my_strdup(ip,MYF(0)))) + if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(0)))) return (ER_OUT_OF_RESOURCES); - sctx->host_or_ip= sctx->ip; + thd->main_security_ctx.host_or_ip= thd->main_security_ctx.ip; vio_in_addr(net->vio,&thd->remote.sin_addr); if (!(specialflag & SPECIAL_NO_RESOLVE)) { vio_in_addr(net->vio,&thd->remote.sin_addr); - sctx->host=ip_to_hostname(&thd->remote.sin_addr,&connect_errors); + thd->main_security_ctx.host= + ip_to_hostname(&thd->remote.sin_addr, &connect_errors); /* Cut very long hostnames to avoid possible overflows */ - if (sctx->host) + if (thd->main_security_ctx.host) { - if (sctx->host != my_localhost) - sctx->host[min(strlen(sctx->host), HOSTNAME_LENGTH)]= 0; - sctx->host_or_ip= sctx->host; + if (thd->main_security_ctx.host != my_localhost) + thd->main_security_ctx.host[min(strlen(thd->main_security_ctx.host), + HOSTNAME_LENGTH)]= 0; + thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host; } if (connect_errors > max_connect_errors) return(ER_HOST_IS_BLOCKED); } DBUG_PRINT("info",("Host: %s ip: %s", - sctx->host ? sctx->host : "unknown host", - sctx->ip ? sctx->ip : "unknown ip")); - if (acl_check_host(sctx->host, sctx->ip)) + (thd->main_security_ctx.host ? + thd->main_security_ctx.host : "unknown host"), + (thd->main_security_ctx.ip ? + thd->main_security_ctx.ip : "unknown ip"))); + if (acl_check_host(thd->main_security_ctx.host, thd->main_security_ctx.ip)) return(ER_HOST_NOT_PRIVILEGED); } else /* Hostname given means that the connection was on a socket */ { - DBUG_PRINT("info",("Host: %s", sctx->host)); - sctx->host_or_ip= sctx->host; - sctx->ip= 0; + DBUG_PRINT("info",("Host: %s", thd->main_security_ctx.host)); + thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host; + thd->main_security_ctx.ip= 0; /* Reset sin_addr */ bzero((char*) &thd->remote, sizeof(thd->remote)); } @@ -987,9 +1000,9 @@ static int check_connection(THD *thd) thd->charset(), &dummy_errors)]= '\0'; user= user_buff; - if (sctx->user) - x_free(sctx->user); - if (!(sctx->user= my_strdup(user, MYF(0)))) + if (thd->main_security_ctx.user) + x_free(thd->main_security_ctx.user); + if (!(thd->main_security_ctx.user= my_strdup(user, MYF(0)))) return (ER_OUT_OF_RESOURCES); return check_user(thd, COM_CONNECT, passwd, passwd_len, db, TRUE); } @@ -1077,7 +1090,7 @@ pthread_handler_decl(handle_one_connection,arg) { int error; NET *net= &thd->net; - st_security_context *sctx= thd->security_ctx; + Security_context *sctx= thd->security_ctx; thd->thread_stack= (char*) &thd; net->no_send_error= 0; @@ -1592,7 +1605,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, /* Save user and privileges */ uint save_db_length= thd->db_length; char *save_db= thd->db; - st_security_context save_security_ctx= *thd->security_ctx; + Security_context save_security_ctx= *thd->security_ctx; USER_CONN *save_user_connect= thd->user_connect; if (!(thd->security_ctx->user= my_strdup(user, MYF(0)))) @@ -4143,7 +4156,7 @@ end_with_restore_list: else { #ifndef NO_EMBEDDED_ACCESS_CHECKS - st_security_context *save_ctx; + Security_context *save_ctx; #endif ha_rows select_limit; /* bits that should be cleared in thd->server_status */ @@ -4807,7 +4820,7 @@ bool check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, bool dont_check_global_grants, bool no_errors, bool schema_db) { - st_security_context *sctx= thd->security_ctx; + Security_context *sctx= thd->security_ctx; #ifndef NO_EMBEDDED_ACCESS_CHECKS ulong db_access; bool db_is_pattern= test(want_access & GRANT_ACL); @@ -4838,8 +4851,8 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, { if (!no_errors) my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), - thd->security_ctx->priv_user, - thd->security_ctx->priv_host, db_name); + sctx->priv_user, + sctx->priv_host, db_name); DBUG_RETURN(TRUE); } else @@ -5245,7 +5258,7 @@ void mysql_reset_thd_for_next_command(THD *thd) thd->server_status&= ~ (SERVER_MORE_RESULTS_EXISTS | SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED); - thd->security_ctx= &thd->main_security_ctx; + DBUG_ASSERT(thd->security_ctx== &thd->main_security_ctx); thd->tmp_table_used= 0; if (!thd->in_sub_stmt) { @@ -7396,7 +7409,7 @@ Item *negate_expression(THD *thd, Item *expr) SYNOPSIS default_definer() - thd thread handler + Secytity_context current decurity context definer structure where it should be assigned RETURN @@ -7404,7 +7417,7 @@ Item *negate_expression(THD *thd, Item *expr) TRUE Error */ -bool default_view_definer(st_security_context *sctx, st_lex_user *definer) +bool default_view_definer(Security_context *sctx, st_lex_user *definer) { definer->user.str= sctx->priv_user; definer->user.length= strlen(sctx->priv_user); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 528876a6bbb..a146a489e91 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -415,7 +415,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) bool mysqld_show_create_db(THD *thd, char *dbname, HA_CREATE_INFO *create_info) { - st_security_context *sctx= thd->security_ctx; + Security_context *sctx= thd->security_ctx; int length; char path[FN_REFLEN]; char buff[2048]; @@ -436,7 +436,7 @@ bool mysqld_show_create_db(THD *thd, char *dbname, } #ifndef NO_EMBEDDED_ACCESS_CHECKS - if (test_all_bits(sctx->master_access,DB_ACLS)) + if (test_all_bits(sctx->master_access, DB_ACLS)) db_access=DB_ACLS; else db_access= (acl_get(sctx->host, sctx->ip, sctx->priv_user, dbname, 0) | @@ -1186,7 +1186,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) THD *tmp; while ((tmp=it++)) { - st_security_context *tmp_sctx= tmp->security_ctx; + Security_context *tmp_sctx= tmp->security_ctx; struct st_my_thread_var *mysys_var; if ((tmp->vio_ok() || tmp->system_thread) && (!user || (tmp_sctx->user && !strcmp(tmp_sctx->user, user)))) @@ -1205,7 +1205,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) "%s:%u", tmp_sctx->host_or_ip, tmp->peer_port); } else - thd_info->host= thd->strdup(tmp_sctx->host_or_ip); + thd_info->host= thd->strdup(tmp_sctx->host); if ((thd_info->db=tmp->db)) // Safe test thd_info->db=thd->strdup(thd_info->db); thd_info->command=(int) tmp->command; @@ -1257,7 +1257,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) thread_info *thd_info; #ifndef NO_EMBEDDED_ACCESS_CHECKS - st_security_context *sctx; + Security_context *sctx; #endif time_t now= time(0); while ((thd_info=thread_infos.get())) @@ -1996,7 +1996,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) List bases; List_iterator_fast it(bases); COND *partial_cond; - st_security_context *sctx= thd->security_ctx; + Security_context *sctx= thd->security_ctx; uint derived_tables= lex->derived_tables; int error= 1; Open_tables_state open_tables_state_backup; @@ -2201,7 +2201,7 @@ int fill_schema_shemata(THD *thd, TABLE_LIST *tables, COND *cond) bool with_i_schema; HA_CREATE_INFO create; TABLE *table= tables->table; - st_security_context *sctx= thd->security_ctx; + Security_context *sctx= thd->security_ctx; DBUG_ENTER("fill_schema_shemata"); if (make_db_list(thd, &files, &idx_field_vals, diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 26f8e0dfbd9..52ac35abc19 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -6554,7 +6554,7 @@ show_param: LEX *lex=Lex; lex->sql_command= SQLCOM_SHOW_GRANTS; THD *thd= lex->thd; - st_security_context *sctx= thd->security_ctx; + Security_context *sctx= thd->security_ctx; LEX_USER *curr_user; if (!(curr_user= (LEX_USER*) thd->alloc(sizeof(st_lex_user)))) YYABORT; @@ -7464,7 +7464,7 @@ user: | CURRENT_USER optional_braces { THD *thd= YYTHD; - st_security_context *sctx= thd->security_ctx; + Security_context *sctx= thd->security_ctx; if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user)))) YYABORT; $$->user.str= sctx->priv_user; From f679e33cf98a7ebd57bb1d4bd3a0eae78def5e5f Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 20 Sep 2005 15:26:10 -0700 Subject: [PATCH 6/7] Fixed a typo in handler.cc if CSV was built. I also added CSV to the default MAX builds so that more people test it. BUILD/SETUP.sh: Adding CVS engine to default max builds. sql/handler.cc: Fixed typo --- BUILD/SETUP.sh | 5 ++--- sql/handler.cc | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh index 1bf3bad5abe..4c8a8839bdf 100755 --- a/BUILD/SETUP.sh +++ b/BUILD/SETUP.sh @@ -52,9 +52,8 @@ global_warnings="-Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wch #debug_extra_warnings="-Wuninitialized" c_warnings="$global_warnings -Wunused" cxx_warnings="$global_warnings -Woverloaded-virtual -Wsign-promo -Wreorder -Wctor-dtor-privacy -Wnon-virtual-dtor" - -base_max_configs="--with-innodb --with-berkeley-db --with-ndbcluster --with-archive-storage-engine --with-openssl --with-big-tables --with-blackhole-storage-engine --with-federated-storage-engine" -max_leave_isam_configs="--with-innodb --with-berkeley-db --with-ndbcluster --with-archive-storage-engine --with-federated-storage-engine --with-blackhole-storage-engine --with-openssl --with-embedded-server --with-big-tables" +base_max_configs="--with-innodb --with-berkeley-db --with-ndbcluster --with-archive-storage-engine --with-openssl --with-big-tables --with-blackhole-storage-engine --with-federated-storage-engine --with-csv-storage-engine" +max_leave_isam_configs="--with-innodb --with-berkeley-db --with-ndbcluster --with-archive-storage-engine --with-federated-storage-engine --with-blackhole-storage-engine --with-csv-storage-engine --with-openssl --with-embedded-server --with-big-tables" max_configs="$base_max_configs --with-embedded-server" path=`dirname $0` diff --git a/sql/handler.cc b/sql/handler.cc index 34ce7e60eba..5f8fa33fecc 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -511,7 +511,7 @@ int ha_init() break; #endif #ifdef HAVE_CSV_DB - case DB_TYPE_CSV_DB,: + case DB_TYPE_CSV_DB: types->ht= &tina_hton; break; #endif From 21a62eb1c6a281b72c24bb9a7d5af702a5b3d8d5 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 21 Sep 2005 08:29:47 +0300 Subject: [PATCH 7/7] postmerge fixes libmysqld/lib_sql.cc: struct st_security_context nad to class Security_context sql/item_func.cc: fixed method call, name and contence to be compatible with new code sql/item_func.h: fixed method to be compatible wit new code sql/sql_parse.cc: fixed typo removed compiler warnings --- libmysqld/lib_sql.cc | 2 +- sql/item_func.cc | 70 ++++++++++++++++++-------------------------- sql/item_func.h | 3 +- sql/sql_parse.cc | 10 +++---- 4 files changed, 36 insertions(+), 49 deletions(-) diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index d6f41fda5f6..99761ceb8c7 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -532,7 +532,7 @@ err: int check_embedded_connection(MYSQL *mysql) { THD *thd= (THD*)mysql->thd; - st_security_context *sctx= thd->security_ctx; + Security_context *sctx= thd->security_ctx; sctx->host_or_ip= sctx->host= (char*)my_localhost; sctx->priv_user= sctx->user= my_strdup(mysql->user, MYF(0)); return check_user(thd, COM_CONNECT, NULL, 0, thd->db, true); diff --git a/sql/item_func.cc b/sql/item_func.cc index 4fbc60014f3..265eb28bba8 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -4711,21 +4711,11 @@ Item_func_sp::execute(Item **itp) THD *thd= current_thd; int res= -1; Sub_statement_state statement_state; - -#ifndef NO_EMBEDDED_ACCESS_CHECKS Security_context *save_ctx; -#endif - if (! m_sp && ! (m_sp= sp_find_function(thd, m_name, TRUE))) - { - my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str); + if (find_and_check_access(thd, EXECUTE_ACL, &save_ctx)) goto error; - } -#ifndef NO_EMBEDDED_ACCESS_CHECKS - if (check_access(EXECUTE_ACL, 0, &save_ctx)) - goto error; -#endif /* Disable the binlogging if this is not a SELECT statement. If this is a SELECT, leave binlogging on, so execute_function() code writes the @@ -4734,7 +4724,7 @@ Item_func_sp::execute(Item **itp) thd->reset_sub_statement_state(&statement_state, SUB_STMT_FUNCTION); res= m_sp->execute_function(thd, args, arg_count, itp); thd->restore_sub_statement_state(&statement_state); - + if (res && mysql_bin_log.is_open() && (m_sp->m_chistics->daccess == SP_CONTAINS_SQL || m_sp->m_chistics->daccess == SP_MODIFIES_SQL_DATA)) @@ -4851,71 +4841,67 @@ Item_func_sp::tmp_table_field(TABLE *t_arg) DBUG_RETURN(res); } + /* - Check access rigths to function + Find the function and chack access rigths to the function SYNOPSIS - check_access() + find_and_check_access() + thd thread handler want_access requested access - report_error whether to set error to thd->net.report_error - sp_ctx sp security context for switching + backup backup of security context or 0 RETURN - 0 Access granted - 1 Requested access can't be granted or function doesn't exists + FALSE Access granted + TRUE Requested access can't be granted or function doesn't exists NOTES Checks if requested access to function can be granted to user. If function isn't found yet, it searches function first. If function can't be found or user don't have requested access - and report_error is true error is raised. + error is raised. If security context sp_ctx is provided and access can be granted then switch back to previous context isn't performed. - In case of access error or if context is not provided then check_access() - switches back to previous security context. + In case of access error or if context is not provided then + find_and_check_access() switches back to previous security context. */ + bool -Item_func_sp::check_access(ulong want_access, bool report_error, st_sp_security_context *sp_ctx) +Item_func_sp::find_and_check_access(THD *thd, ulong want_access, + Security_context **backup) { bool res; -#ifndef NO_EMBEDDED_ACCESS_CHECKS - THD *thd= current_thd; - st_sp_security_context save_ctx, *curr_ctx= sp_ctx?sp_ctx:&save_ctx; - bool ctx_switched= 0; - res= 1; + Security_context *local_save, + **save= (backup ? backup : &local_save); + res= TRUE; if (! m_sp && ! (m_sp= sp_find_function(thd, m_name, TRUE))) { my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str); - if (report_error) - thd->net.report_error= 1; goto error; } +#ifndef NO_EMBEDDED_ACCESS_CHECKS if (check_routine_access(thd, want_access, - m_sp->m_db.str, m_sp->m_name.str, 0, 0)) + m_sp->m_db.str, m_sp->m_name.str, 0, FALSE)) { - if (report_error) - thd->net.report_error= 1; goto error; } - sp_change_security_context(thd, m_sp, curr_ctx); - ctx_switched= curr_ctx->changed; - if (curr_ctx->changed && + sp_change_security_context(thd, m_sp, save); + if (*save && check_routine_access(thd, want_access, - m_sp->m_db.str, m_sp->m_name.str, 0, 0)) + m_sp->m_db.str, m_sp->m_name.str, 0, FALSE)) { - if (report_error) - thd->net.report_error= 1; goto error_check_ctx; } - res= 0; + res= FALSE; error_check_ctx: - if (ctx_switched && (res || !sp_ctx)) - sp_restore_security_context(thd, m_sp, curr_ctx); + if (*save && (res || !backup)) + sp_restore_security_context(thd, local_save); error: #else res= 0; +error: #endif return res; }; @@ -4926,7 +4912,7 @@ Item_func_sp::fix_fields(THD *thd, Item **ref) bool res; DBUG_ASSERT(fixed == 0); res= Item_func::fix_fields(thd, ref); - if (!res && check_access(EXECUTE_ACL, 1, NULL)) + if (!res && find_and_check_access(thd, EXECUTE_ACL, NULL)) res= 1; return res; } diff --git a/sql/item_func.h b/sql/item_func.h index adc1dd1b1be..de4d60e9cbb 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1435,7 +1435,8 @@ public: { context= (Name_resolution_context *)cntx; return FALSE; } void fix_length_and_dec(); - bool check_access(ulong want_access, bool report_error, st_sp_security_context *sp_ctx); + bool find_and_check_access(THD * thd, ulong want_access, + Security_context **backup); virtual enum Functype functype() const { return FUNC_SP; } bool fix_fields(THD *thd, Item **ref); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 8f259b21919..d361b9343f1 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -273,7 +273,7 @@ int check_user(THD *thd, enum enum_server_command command, DBUG_ENTER("check_user"); #ifdef NO_EMBEDDED_ACCESS_CHECKS - thd->ain_security_ctx.master_access= GLOBAL_ACLS; // Full rights + thd->main_security_ctx.master_access= GLOBAL_ACLS; // Full rights /* Change database if necessary */ if (db && db[0]) { @@ -4490,10 +4490,10 @@ end_with_restore_list: mysql_bin_log.is_open()) { String buff; - LEX_STRING command[3]= - {{STRING_WITH_LEN("CREATE ")}, - {STRING_WITH_LEN("ALTER ")}, - {STRING_WITH_LEN("CREATE OR REPLACE ")}}; + const LEX_STRING command[3]= + {{(char *)STRING_WITH_LEN("CREATE ")}, + {(char *)STRING_WITH_LEN("ALTER ")}, + {(char *)STRING_WITH_LEN("CREATE OR REPLACE ")}}; thd->clear_error(); buff.append(command[thd->lex->create_view_mode].str,