...

Source file src/github.com/letsencrypt/boulder/sa/sysvars.go

Documentation: github.com/letsencrypt/boulder/sa

     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  }
   236  

View as plain text