boulder/sa/sysvars.go

236 lines
8.9 KiB
Go

package sa
import (
"fmt"
"regexp"
)
var (
checkStringQuoteRE = regexp.MustCompile(`^'[0-9A-Za-z_\-=:]+'$`)
checkIntRE = regexp.MustCompile(`^\d+$`)
checkImproperIntRE = regexp.MustCompile(`^'\d+'$`)
checkNumericRE = regexp.MustCompile(`^\d+(\.\d+)?$`)
checkBooleanRE = regexp.MustCompile(`^([0-1])|(?i)(true|false)|(?i)(on|off)`)
)
// checkMariaDBSystemVariables validates a MariaDB config passed in via SA
// setDefault or DSN. This manually curated list of system variables was
// partially generated by a tool in issue #6687. An overview of the validations
// performed are:
//
// - Correct quoting for strings and string enums prevent future
// problems such as PR #6683 from occurring.
//
// - Regex validation is performed for the various booleans, floats, integers, and strings.
//
// Only session scoped variables should be included. A session variable is one
// that affects the current session only. Passing a session variable that only
// works in the global scope causes database connection error 1045.
// https://mariadb.com/kb/en/set/#global-session
func checkMariaDBSystemVariables(name string, value string) error {
// System variable names will be indexed into the appropriate hash sets
// below and can possibly exist in several sets.
// Check the list of currently known MariaDB string type system variables
// and determine if the value is a properly formatted string e.g.
// sql_mode='STRICT_TABLES'
mariaDBStringTypes := map[string]struct{}{
"character_set_client": {},
"character_set_connection": {},
"character_set_database": {},
"character_set_filesystem": {},
"character_set_results": {},
"character_set_server": {},
"collation_connection": {},
"collation_database": {},
"collation_server": {},
"debug/debug_dbug": {},
"debug_sync": {},
"enforce_storage_engine": {},
"external_user": {},
"lc_messages": {},
"lc_time_names": {},
"old_alter_table": {},
"old_mode": {},
"optimizer_switch": {},
"proxy_user": {},
"session_track_system_variables": {},
"sql_mode": {},
"time_zone": {},
}
if _, found := mariaDBStringTypes[name]; found {
if checkStringQuoteRE.FindString(value) != value {
return fmt.Errorf("%s=%s string is not properly quoted", name, value)
}
return nil
}
// MariaDB numerics which may either be integers or floats.
// https://mariadb.com/kb/en/numeric-data-type-overview/
mariaDBNumericTypes := map[string]struct{}{
"bulk_insert_buffer_size": {},
"default_week_format": {},
"eq_range_index_dive_limit": {},
"error_count": {},
"expensive_subquery_limit": {},
"group_concat_max_len": {},
"histogram_size": {},
"idle_readonly_transaction_timeout": {},
"idle_transaction_timeout": {},
"idle_write_transaction_timeout": {},
"in_predicate_conversion_threshold": {},
"insert_id": {},
"interactive_timeout": {},
"join_buffer_size": {},
"join_buffer_space_limit": {},
"join_cache_level": {},
"last_insert_id": {},
"lock_wait_timeout": {},
"log_slow_min_examined_row_limit": {},
"log_slow_query_time": {},
"log_slow_rate_limit": {},
"long_query_time": {},
"max_allowed_packet": {},
"max_delayed_threads": {},
"max_digest_length": {},
"max_error_count": {},
"max_heap_table_size": {},
"max_join_size": {},
"max_length_for_sort_data": {},
"max_recursive_iterations": {},
"max_rowid_filter_size": {},
"max_seeks_for_key": {},
"max_session_mem_used": {},
"max_sort_length": {},
"max_sp_recursion_depth": {},
"max_statement_time": {},
"max_user_connections": {},
"min_examined_row_limit": {},
"mrr_buffer_size": {},
"net_buffer_length": {},
"net_read_timeout": {},
"net_retry_count": {},
"net_write_timeout": {},
"optimizer_extra_pruning_depth": {},
"optimizer_max_sel_arg_weight": {},
"optimizer_prune_level": {},
"optimizer_search_depth": {},
"optimizer_selectivity_sampling_limit": {},
"optimizer_trace_max_mem_size": {},
"optimizer_use_condition_selectivity": {},
"preload_buffer_size": {},
"profiling_history_size": {},
"progress_report_time": {},
"pseudo_slave_mode": {},
"pseudo_thread_id": {},
"query_alloc_block_size": {},
"query_prealloc_size": {},
"rand_seed1": {},
"range_alloc_block_size": {},
"read_rnd_buffer_size": {},
"rowid_merge_buff_size": {},
"sql_select_limit": {},
"tmp_disk_table_size": {},
"tmp_table_size": {},
"transaction_alloc_block_size": {},
"transaction_prealloc_size": {},
"wait_timeout": {},
"warning_count": {},
}
if _, found := mariaDBNumericTypes[name]; found {
if checkNumericRE.FindString(value) != value {
return fmt.Errorf("%s=%s requires a numeric value, but is not formatted like a number", name, value)
}
return nil
}
// Certain MariaDB enums can have both string and integer values.
mariaDBIntEnumTypes := map[string]struct{}{
"completion_type": {},
"query_cache_type": {},
}
mariaDBStringEnumTypes := map[string]struct{}{
"completion_type": {},
"default_regex_flags": {},
"default_storage_engine": {},
"default_tmp_storage_engine": {},
"histogram_type": {},
"log_slow_filter": {},
"log_slow_verbosity": {},
"optimizer_trace": {},
"query_cache_type": {},
"session_track_transaction_info": {},
"transaction_isolation": {},
"tx_isolation": {},
"use_stat_tables": {},
}
// Check the list of currently known MariaDB enumeration type system
// variables and determine if the value is either:
// 1) A properly formatted integer e.g. completion_type=1
if _, found := mariaDBIntEnumTypes[name]; found {
if checkIntRE.FindString(value) == value {
return nil
}
if checkImproperIntRE.FindString(value) == value {
return fmt.Errorf("%s=%s integer enum is quoted, but should not be", name, value)
}
}
// 2) A properly formatted string e.g. completion_type='CHAIN'
if _, found := mariaDBStringEnumTypes[name]; found {
if checkStringQuoteRE.FindString(value) != value {
return fmt.Errorf("%s=%s string enum is not properly quoted", name, value)
}
return nil
}
// MariaDB booleans can be (0, false) or (1, true).
// https://mariadb.com/kb/en/boolean/
mariaDBBooleanTypes := map[string]struct{}{
"autocommit": {},
"big_tables": {},
"check_constraint_checks": {},
"foreign_key_checks": {},
"in_transaction": {},
"keep_files_on_create": {},
"log_slow_query": {},
"low_priority_updates": {},
"old": {},
"old_passwords": {},
"profiling": {},
"query_cache_strip_comments": {},
"query_cache_wlock_invalidate": {},
"session_track_schema": {},
"session_track_state_change": {},
"slow_query_log": {},
"sql_auto_is_null": {},
"sql_big_selects": {},
"sql_buffer_result": {},
"sql_if_exists": {},
"sql_log_off": {},
"sql_notes": {},
"sql_quote_show_create": {},
"sql_safe_updates": {},
"sql_warnings": {},
"standard_compliant_cte": {},
"tcp_nodelay": {},
"transaction_read_only": {},
"tx_read_only": {},
"unique_checks": {},
"updatable_views_with_limit": {},
}
if _, found := mariaDBBooleanTypes[name]; found {
if checkBooleanRE.FindString(value) != value {
return fmt.Errorf("%s=%s expected boolean value", name, value)
}
return nil
}
return fmt.Errorf("%s=%s was unexpected", name, value)
}