github.com/letsencrypt/boulder@v0.20251208.0/sa/sysvars.go (about) 1 package sa 2 3 import ( 4 "fmt" 5 "regexp" 6 ) 7 8 var ( 9 checkStringQuoteRE = regexp.MustCompile(`^'[0-9A-Za-z_\-=:]+'$`) 10 checkIntRE = regexp.MustCompile(`^\d+$`) 11 checkImproperIntRE = regexp.MustCompile(`^'\d+'$`) 12 checkNumericRE = regexp.MustCompile(`^\d+(\.\d+)?$`) 13 checkBooleanRE = regexp.MustCompile(`^([0-1])|(?i)(true|false)|(?i)(on|off)`) 14 ) 15 16 // checkMariaDBSystemVariables validates a MariaDB config passed in via SA 17 // setDefault or DSN. This manually curated list of system variables was 18 // partially generated by a tool in issue #6687. An overview of the validations 19 // performed are: 20 // 21 // - Correct quoting for strings and string enums prevent future 22 // problems such as PR #6683 from occurring. 23 // 24 // - Regex validation is performed for the various booleans, floats, integers, and strings. 25 // 26 // Only session scoped variables should be included. A session variable is one 27 // that affects the current session only. Passing a session variable that only 28 // works in the global scope causes database connection error 1045. 29 // https://mariadb.com/kb/en/set/#global-session 30 func checkMariaDBSystemVariables(name string, value string) error { 31 // System variable names will be indexed into the appropriate hash sets 32 // below and can possibly exist in several sets. 33 34 // Check the list of currently known MariaDB string type system variables 35 // and determine if the value is a properly formatted string e.g. 36 // sql_mode='STRICT_TABLES' 37 mariaDBStringTypes := map[string]struct{}{ 38 "character_set_client": {}, 39 "character_set_connection": {}, 40 "character_set_database": {}, 41 "character_set_filesystem": {}, 42 "character_set_results": {}, 43 "character_set_server": {}, 44 "collation_connection": {}, 45 "collation_database": {}, 46 "collation_server": {}, 47 "debug/debug_dbug": {}, 48 "debug_sync": {}, 49 "enforce_storage_engine": {}, 50 "external_user": {}, 51 "lc_messages": {}, 52 "lc_time_names": {}, 53 "old_alter_table": {}, 54 "old_mode": {}, 55 "optimizer_switch": {}, 56 "proxy_user": {}, 57 "session_track_system_variables": {}, 58 "sql_mode": {}, 59 "time_zone": {}, 60 } 61 62 if _, found := mariaDBStringTypes[name]; found { 63 if checkStringQuoteRE.FindString(value) != value { 64 return fmt.Errorf("%s=%s string is not properly quoted", name, value) 65 } 66 return nil 67 } 68 69 // MariaDB numerics which may either be integers or floats. 70 // https://mariadb.com/kb/en/numeric-data-type-overview/ 71 mariaDBNumericTypes := map[string]struct{}{ 72 "bulk_insert_buffer_size": {}, 73 "default_week_format": {}, 74 "eq_range_index_dive_limit": {}, 75 "error_count": {}, 76 "expensive_subquery_limit": {}, 77 "group_concat_max_len": {}, 78 "histogram_size": {}, 79 "idle_readonly_transaction_timeout": {}, 80 "idle_transaction_timeout": {}, 81 "idle_write_transaction_timeout": {}, 82 "in_predicate_conversion_threshold": {}, 83 "insert_id": {}, 84 "interactive_timeout": {}, 85 "join_buffer_size": {}, 86 "join_buffer_space_limit": {}, 87 "join_cache_level": {}, 88 "last_insert_id": {}, 89 "lock_wait_timeout": {}, 90 "log_slow_min_examined_row_limit": {}, 91 "log_slow_query_time": {}, 92 "log_slow_rate_limit": {}, 93 "long_query_time": {}, 94 "max_allowed_packet": {}, 95 "max_delayed_threads": {}, 96 "max_digest_length": {}, 97 "max_error_count": {}, 98 "max_heap_table_size": {}, 99 "max_join_size": {}, 100 "max_length_for_sort_data": {}, 101 "max_recursive_iterations": {}, 102 "max_rowid_filter_size": {}, 103 "max_seeks_for_key": {}, 104 "max_session_mem_used": {}, 105 "max_sort_length": {}, 106 "max_sp_recursion_depth": {}, 107 "max_statement_time": {}, 108 "max_user_connections": {}, 109 "min_examined_row_limit": {}, 110 "mrr_buffer_size": {}, 111 "net_buffer_length": {}, 112 "net_read_timeout": {}, 113 "net_retry_count": {}, 114 "net_write_timeout": {}, 115 "optimizer_extra_pruning_depth": {}, 116 "optimizer_max_sel_arg_weight": {}, 117 "optimizer_prune_level": {}, 118 "optimizer_search_depth": {}, 119 "optimizer_selectivity_sampling_limit": {}, 120 "optimizer_trace_max_mem_size": {}, 121 "optimizer_use_condition_selectivity": {}, 122 "preload_buffer_size": {}, 123 "profiling_history_size": {}, 124 "progress_report_time": {}, 125 "pseudo_slave_mode": {}, 126 "pseudo_thread_id": {}, 127 "query_alloc_block_size": {}, 128 "query_prealloc_size": {}, 129 "rand_seed1": {}, 130 "range_alloc_block_size": {}, 131 "read_rnd_buffer_size": {}, 132 "rowid_merge_buff_size": {}, 133 "sql_select_limit": {}, 134 "tmp_disk_table_size": {}, 135 "tmp_table_size": {}, 136 "transaction_alloc_block_size": {}, 137 "transaction_prealloc_size": {}, 138 "wait_timeout": {}, 139 "warning_count": {}, 140 } 141 142 if _, found := mariaDBNumericTypes[name]; found { 143 if checkNumericRE.FindString(value) != value { 144 return fmt.Errorf("%s=%s requires a numeric value, but is not formatted like a number", name, value) 145 } 146 return nil 147 } 148 149 // Certain MariaDB enums can have both string and integer values. 150 mariaDBIntEnumTypes := map[string]struct{}{ 151 "completion_type": {}, 152 "query_cache_type": {}, 153 } 154 155 mariaDBStringEnumTypes := map[string]struct{}{ 156 "completion_type": {}, 157 "default_regex_flags": {}, 158 "default_storage_engine": {}, 159 "default_tmp_storage_engine": {}, 160 "histogram_type": {}, 161 "log_slow_filter": {}, 162 "log_slow_verbosity": {}, 163 "optimizer_trace": {}, 164 "query_cache_type": {}, 165 "session_track_transaction_info": {}, 166 "transaction_isolation": {}, 167 "tx_isolation": {}, 168 "use_stat_tables": {}, 169 } 170 171 // Check the list of currently known MariaDB enumeration type system 172 // variables and determine if the value is either: 173 // 1) A properly formatted integer e.g. completion_type=1 174 if _, found := mariaDBIntEnumTypes[name]; found { 175 if checkIntRE.FindString(value) == value { 176 return nil 177 } 178 if checkImproperIntRE.FindString(value) == value { 179 return fmt.Errorf("%s=%s integer enum is quoted, but should not be", name, value) 180 } 181 } 182 183 // 2) A properly formatted string e.g. completion_type='CHAIN' 184 if _, found := mariaDBStringEnumTypes[name]; found { 185 if checkStringQuoteRE.FindString(value) != value { 186 return fmt.Errorf("%s=%s string enum is not properly quoted", name, value) 187 } 188 return nil 189 } 190 191 // MariaDB booleans can be (0, false) or (1, true). 192 // https://mariadb.com/kb/en/boolean/ 193 mariaDBBooleanTypes := map[string]struct{}{ 194 "autocommit": {}, 195 "big_tables": {}, 196 "check_constraint_checks": {}, 197 "foreign_key_checks": {}, 198 "in_transaction": {}, 199 "keep_files_on_create": {}, 200 "log_slow_query": {}, 201 "low_priority_updates": {}, 202 "old": {}, 203 "old_passwords": {}, 204 "profiling": {}, 205 "query_cache_strip_comments": {}, 206 "query_cache_wlock_invalidate": {}, 207 "session_track_schema": {}, 208 "session_track_state_change": {}, 209 "slow_query_log": {}, 210 "sql_auto_is_null": {}, 211 "sql_big_selects": {}, 212 "sql_buffer_result": {}, 213 "sql_if_exists": {}, 214 "sql_log_off": {}, 215 "sql_notes": {}, 216 "sql_quote_show_create": {}, 217 "sql_safe_updates": {}, 218 "sql_warnings": {}, 219 "standard_compliant_cte": {}, 220 "tcp_nodelay": {}, 221 "transaction_read_only": {}, 222 "tx_read_only": {}, 223 "unique_checks": {}, 224 "updatable_views_with_limit": {}, 225 } 226 227 if _, found := mariaDBBooleanTypes[name]; found { 228 if checkBooleanRE.FindString(value) != value { 229 return fmt.Errorf("%s=%s expected boolean value", name, value) 230 } 231 return nil 232 } 233 234 return fmt.Errorf("%s=%s was unexpected", name, value) 235 }