diff options
author | Georgi Kodinov <Georgi.Kodinov@Oracle.com> | 2012-04-12 14:04:12 +0300 |
---|---|---|
committer | Georgi Kodinov <Georgi.Kodinov@Oracle.com> | 2012-04-12 14:04:12 +0300 |
commit | a84ca722247a2aa118c42d8c55d80196660d6795 (patch) | |
tree | 670cea5ced9a811e020dff96778fa05250fc9e39 /sql/handler.cc | |
parent | 12421762616f217a98002df50538c46f6966b4d9 (diff) | |
parent | 64e74d484fcbf6d348397b3ce4f32438754dc8bd (diff) | |
download | mariadb-git-a84ca722247a2aa118c42d8c55d80196660d6795.tar.gz |
merge mysql-5.5->mysql-5.5-security
Diffstat (limited to 'sql/handler.cc')
-rw-r--r-- | sql/handler.cc | 307 |
1 files changed, 307 insertions, 0 deletions
diff --git a/sql/handler.cc b/sql/handler.cc index 8ce20c19d2d..b2cb7f1cf9a 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -45,6 +45,7 @@ #include "ha_partition.h" #endif + /* While we have legacy_db_type, we have this array to check for dups and to find handlerton from legacy_db_type. @@ -90,6 +91,83 @@ TYPELIB tx_isolation_typelib= {array_elements(tx_isolation_names)-1,"", static TYPELIB known_extensions= {0,"known_exts", NULL, NULL}; uint known_extensions_id= 0; +/** + Database name that hold most of mysqld system tables. + Current code assumes that, there exists only some + specific "database name" designated as system database. +*/ +const char* mysqld_system_database= "mysql"; + +// System tables that belong to mysqld_system_database. +st_system_tablename mysqld_system_tables[]= { + {mysqld_system_database, "db"}, + {mysqld_system_database, "user"}, + {mysqld_system_database, "host"}, + {mysqld_system_database, "func"}, + {mysqld_system_database, "proc"}, + {mysqld_system_database, "event"}, + {mysqld_system_database, "plugin"}, + {mysqld_system_database, "servers"}, + {mysqld_system_database, "procs_priv"}, + {mysqld_system_database, "tables_priv"}, + {mysqld_system_database, "proxies_priv"}, + {mysqld_system_database, "columns_priv"}, + {mysqld_system_database, "time_zone"}, + {mysqld_system_database, "time_zone_name"}, + {mysqld_system_database, "time_zone_leap_second"}, + {mysqld_system_database, "time_zone_transition"}, + {mysqld_system_database, "time_zone_transition_type"}, + {mysqld_system_database, "help_category"}, + {mysqld_system_database, "help_keyword"}, + {mysqld_system_database, "help_relation"}, + {mysqld_system_database, "help_topic"}, + {(const char *)NULL, (const char *)NULL} /* This must be at the end */ +}; + +/** + This static pointer holds list of system databases from SQL layer and + various SE's. The required memory is allocated once, and never freed. +*/ +static const char **known_system_databases= NULL; +static const char **ha_known_system_databases(); + +// Called for each SE to get SE specific system database. +static my_bool system_databases_handlerton(THD *unused, plugin_ref plugin, + void *arg); + +// Called for each SE to check if given db.table_name is a system table. +static my_bool check_engine_system_table_handlerton(THD *unused, + plugin_ref plugin, + void *arg); + +/** + Structure used by SE during check for system table. + This structure is passed to each SE handlerton and the status (OUT param) + is collected. +*/ +struct st_sys_tbl_chk_params +{ + const char *db; // IN param + const char *table_name; // IN param + bool is_sql_layer_system_table; // IN param + legacy_db_type db_type; // IN param + + enum enum_sys_tbl_chk_status + { + // db.table_name is not a supported system table. + NOT_KNOWN_SYSTEM_TABLE, + /* + db.table_name is a system table, + but may not be supported by SE. + */ + KNOWN_SYSTEM_TABLE, + /* + db.table_name is a system table, + and is supported by SE. + */ + SUPPORTED_SYSTEM_TABLE + }status; // OUT param +}; static plugin_ref ha_default_plugin(THD *thd) @@ -588,6 +666,14 @@ int ha_init() */ opt_using_transactions= total_ha>(ulong)opt_bin_log; savepoint_alloc_size+= sizeof(SAVEPOINT); + + /* + Initialize system database name cache. + This cache is used to do a quick check if a given + db.tablename is a system table. + */ + known_system_databases= ha_known_system_databases(); + DBUG_RETURN(error); } @@ -3788,6 +3874,227 @@ ha_check_if_table_exists(THD* thd, const char *db, const char *name, DBUG_RETURN(FALSE); } +/** + @brief Check if a given table is a system table. + + @details The primary purpose of introducing this function is to stop system + tables to be created or being moved to undesired storage engines. + + @todo There is another function called is_system_table_name() used by + get_table_category(), which is used to set TABLE_SHARE table_category. + It checks only a subset of table name like proc, event and time*. + We cannot use below function in get_table_category(), + as that affects locking mechanism. If we need to + unify these functions, we need to fix locking issues generated. + + @param hton Handlerton of new engine. + @param db Database name. + @param table_name Table name to be checked. + + @return Operation status + @retval true If the table name is a valid system table + or if its a valid user table. + + @retval false If the table name is a system table name + and does not belong to engine specified + in the command. +*/ +bool ha_check_if_supported_system_table(handlerton *hton, const char *db, + const char *table_name) +{ + DBUG_ENTER("ha_check_if_supported_system_table"); + st_sys_tbl_chk_params check_params; + bool is_system_database= false; + const char **names; + st_system_tablename *systab; + + // Check if we have a system database name in the command. + DBUG_ASSERT(known_system_databases != NULL); + names= known_system_databases; + while (names && *names) + { + if (strcmp(*names, db) == 0) + { + /* Used to compare later, will be faster */ + check_params.db= *names; + is_system_database= true; + break; + } + names++; + } + if (!is_system_database) + DBUG_RETURN(true); // It's a user table name. + + // Check if this is SQL layer system tables. + systab= mysqld_system_tables; + check_params.is_sql_layer_system_table= false; + while (systab && systab->db) + { + if (systab->db == check_params.db && + strcmp(systab->tablename, table_name) == 0) + { + check_params.is_sql_layer_system_table= true; + break; + } + systab++; + } + + // Check if this is a system table and if some engine supports it. + check_params.status= check_params.is_sql_layer_system_table ? + st_sys_tbl_chk_params::KNOWN_SYSTEM_TABLE : + st_sys_tbl_chk_params::NOT_KNOWN_SYSTEM_TABLE; + check_params.db_type= hton->db_type; + check_params.table_name= table_name; + plugin_foreach(NULL, check_engine_system_table_handlerton, + MYSQL_STORAGE_ENGINE_PLUGIN, &check_params); + + // SE does not support this system table. + if (check_params.status == st_sys_tbl_chk_params::KNOWN_SYSTEM_TABLE) + DBUG_RETURN(false); + + // It's a system table or a valid user table. + DBUG_RETURN(true); +} + +/** + @brief Called for each SE to check if given db, tablename is a system table. + + @details The primary purpose of introducing this function is to stop system + tables to be created or being moved to undesired storage engines. + + @param unused unused THD* + @param plugin Points to specific SE. + @param arg Is of type struct st_sys_tbl_chk_params. + + @note + args->status Indicates OUT param, + see struct st_sys_tbl_chk_params definition for more info. + + @return Operation status + @retval true There was a match found. + This will stop doing checks with other SE's. + + @retval false There was no match found. + Other SE's will be checked to find a match. +*/ +static my_bool check_engine_system_table_handlerton(THD *unused, + plugin_ref plugin, + void *arg) +{ + st_sys_tbl_chk_params *check_params= (st_sys_tbl_chk_params*) arg; + handlerton *hton= plugin_data(plugin, handlerton *); + + // Do we already know that the table is a system table? + if (check_params->status == st_sys_tbl_chk_params::KNOWN_SYSTEM_TABLE) + { + /* + If this is the same SE specified in the command, we can + simply ask the SE if it supports it stop the search regardless. + */ + if (hton->db_type == check_params->db_type) + { + if (hton->is_supported_system_table && + hton->is_supported_system_table(check_params->db, + check_params->table_name, + check_params->is_sql_layer_system_table)) + check_params->status= st_sys_tbl_chk_params::SUPPORTED_SYSTEM_TABLE; + return TRUE; + } + /* + If this is a different SE, there is no point in asking the SE + since we already know it's a system table and we don't care + if it is supported or not. + */ + return FALSE; + } + + /* + We don't yet know if the table is a system table or not. + We therefore must always ask the SE. + */ + if (hton->is_supported_system_table && + hton->is_supported_system_table(check_params->db, + check_params->table_name, + check_params->is_sql_layer_system_table)) + { + /* + If this is the same SE specified in the command, we know it's a + supported system table and can stop the search. + */ + if (hton->db_type == check_params->db_type) + { + check_params->status= st_sys_tbl_chk_params::SUPPORTED_SYSTEM_TABLE; + return TRUE; + } + else + check_params->status= st_sys_tbl_chk_params::KNOWN_SYSTEM_TABLE; + } + + return FALSE; +} + +/* + Prepare list of all known system database names + current we just have 'mysql' as system database name. + + Later ndbcluster, innodb SE's can define some new database + name which can store system tables specific to SE. +*/ +const char** ha_known_system_databases(void) +{ + I_List<i_string> found_databases; + const char **databases, **database; + + // Get mysqld system database name. + found_databases.push_back(new i_string(mysqld_system_database)); + + // Get system database names from every specific storage engine. + plugin_foreach(NULL, system_databases_handlerton, + MYSQL_STORAGE_ENGINE_PLUGIN, &found_databases); + + int element_count= 0; + I_List_iterator<i_string> iter(found_databases); + while (iter++) element_count++; + databases= (const char **) my_once_alloc(sizeof(char *)* + (element_count+1), + MYF(MY_WME | MY_FAE)); + DBUG_ASSERT(databases != NULL); + + database= databases; + i_string *tmp; + while ((tmp= found_databases.get())) + { + *database++= tmp->ptr; + delete tmp; + } + *database= NULL; // Last element. + + return databases; +} + +/** + @brief Fetch system database name specific to SE. + + @details This function is invoked by plugin_foreach() from + ha_known_system_databases(), for each storage engine. +*/ +static my_bool system_databases_handlerton(THD *unused, plugin_ref plugin, + void *arg) +{ + I_List<i_string> *found_databases= (I_List<i_string> *) arg; + const char *db; + + handlerton *hton= plugin_data(plugin, handlerton *); + if (hton->system_database) + { + db= hton->system_database(); + if (db) + found_databases->push_back(new i_string(db)); + } + + return FALSE; +} + void st_ha_check_opt::init() { |