From 853bdf576fab92a8cfc9205a60154c6848aa7133 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 15 Sep 2023 12:33:52 +0200 Subject: [PATCH] auto-disable --ssl-verify-server-cert in clients, if * --ssl-verify-server-cert was not enabled explicitly, and * CA was not specified, and * fingerprint was not specified, and * protocol is TCP, and * no password was provided insecure passwordless logins are common in test environment, let's not break them. practically, it hardly makes sense to have strong MitM protection if an attacker can simply login without a password. Covers mariadb, mariadb-admin, mariadb-binlog, mariadb-dump --- client/mysql.cc | 5 +++-- client/mysqladmin.cc | 12 ++++++------ client/mysqlbinlog.cc | 22 ++++++++++----------- client/mysqldump.cc | 2 +- include/sslopt-longopts.h | 2 +- include/sslopt-vars.h | 25 +++++++++++++++++++++++- mysql-test/main/mysql.result | 2 +- mysql-test/main/ssl_autoverify,win.rdiff | 12 ++++++------ mysql-test/main/ssl_autoverify.result | 4 ++++ mysql-test/main/ssl_autoverify.test | 8 +++++++- 10 files changed, 64 insertions(+), 30 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index 37a63e2d912..e9eada2d8cc 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -1292,6 +1292,7 @@ int main(int argc,char *argv[]) glob_buffer.realloc(512); completion_hash_init(&ht, 128); init_alloc_root(PSI_NOT_INSTRUMENTED, &hash_mem_root, 16384, 0, MYF(0)); + if (sql_connect(current_host,current_db,current_user,opt_password, opt_silent)) { @@ -1496,7 +1497,7 @@ static bool do_connect(MYSQL *mysql, const char *host, const char *user, { if (opt_secure_auth) mysql_options(mysql, MYSQL_SECURE_AUTH, (char *) &opt_secure_auth); - SET_SSL_OPTS(mysql); + SET_SSL_OPTS_WITH_CHECK(mysql); if (opt_protocol) mysql_options(mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol); if (opt_plugin_dir && *opt_plugin_dir) @@ -1967,7 +1968,7 @@ get_one_option(const struct my_option *opt, const char *argument, MySQL might still have this option in their commands, and it will not work in MariaDB unless it is handled. Therefore output a warning and continue. */ - printf("WARNING: option '--enable-cleartext-plugin' is obsolete.\n"); + printf("WARNING: option --enable-cleartext-plugin is obsolete.\n"); break; case 'A': opt_rehash= 0; diff --git a/client/mysqladmin.cc b/client/mysqladmin.cc index 789ce1a0ce3..c0b58807e9e 100644 --- a/client/mysqladmin.cc +++ b/client/mysqladmin.cc @@ -40,7 +40,7 @@ static my_bool option_force=0,interrupted=0,new_line=0, opt_compress= 0, opt_local= 0, opt_relative= 0, tty_password= 0, opt_nobeep, opt_shutdown_wait_for_slaves= 0, opt_not_used; static my_bool debug_info_flag= 0, debug_check_flag= 0; -static uint tcp_port = 0, option_wait = 0, option_silent=0, nr_iterations; +static uint opt_mysql_port = 0, option_wait = 0, option_silent=0, nr_iterations; static uint opt_count_iterations= 0, my_end_arg, opt_verbose= 0; static ulong opt_connect_timeout, opt_shutdown_timeout; static char * unix_port=0; @@ -166,7 +166,7 @@ static struct my_option my_long_options[] = "/etc/services, " #endif "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").", - &tcp_port, &tcp_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + &opt_mysql_port, &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"protocol", OPT_MYSQL_PROTOCOL, "The protocol to use for connection (tcp, socket, pipe).", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"relative", 'r', @@ -371,7 +371,7 @@ int main(int argc,char *argv[]) mysql_options(&mysql,MYSQL_OPT_CONNECT_TIMEOUT, (char*) &tmp); } - SET_SSL_OPTS(&mysql); + SET_SSL_OPTS_WITH_CHECK(&mysql); if (opt_protocol) mysql_options(&mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol); @@ -533,7 +533,7 @@ static my_bool sql_connect(MYSQL *mysql, uint wait) for (;;) { - if (mysql_real_connect(mysql,host,user,opt_password,NullS,tcp_port, + if (mysql_real_connect(mysql,host,user,opt_password,NullS,opt_mysql_port, unix_port, CLIENT_REMEMBER_OPTIONS)) { my_bool reconnect= 1; @@ -565,9 +565,9 @@ static my_bool sql_connect(MYSQL *mysql, uint wait) { fprintf(stderr,"Check that mariadbd is running on %s",host); fprintf(stderr," and that the port is %d.\n", - tcp_port ? tcp_port: mysql_port); + opt_mysql_port ? opt_mysql_port: mysql_port); fprintf(stderr,"You can check this by doing 'telnet %s %d'\n", - host, tcp_port ? tcp_port: mysql_port); + host, opt_mysql_port ? opt_mysql_port: mysql_port); } } return 1; diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index d8a28b7ef65..c79392988c1 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -134,13 +134,13 @@ static ulong opt_stop_never_slave_server_id= 0; static my_bool opt_verify_binlog_checksum= 1; static ulonglong offset = 0; static char* host = 0; -static int port= 0; +static int opt_mysql_port= 0; static uint my_end_arg; static const char* sock= 0; static char *opt_plugindir= 0, *opt_default_auth= 0; static char* user = 0; -static char* pass = 0; +static char* opt_password = 0; static char *charset= 0; static uint verbose= 0; @@ -1196,8 +1196,8 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, int tmp_sql_offset; conn = mysql_init(NULL); - if (!mysql_real_connect(conn, host, user, pass, - map->get_db_name(), port, sock, 0)) + if (!mysql_real_connect(conn, host, user, opt_password, + map->get_db_name(), opt_mysql_port, sock, 0)) { fprintf(stderr, "%s\n", mysql_error(conn)); exit(1); @@ -1502,7 +1502,7 @@ static struct my_option my_options[] = "/etc/services, " #endif "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").", - &port, &port, 0, GET_INT, REQUIRED_ARG, + &opt_mysql_port, &opt_mysql_port, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"protocol", OPT_MYSQL_PROTOCOL, "The protocol to use for connection (tcp, socket, pipe).", @@ -1769,7 +1769,7 @@ static void warning(const char *format,...) static void cleanup() { DBUG_ENTER("cleanup"); - my_free(pass); + my_free(opt_password); my_free(database); my_free(table); my_free(host); @@ -2090,9 +2090,9 @@ get_one_option(const struct my_option *opt, const char *argument, One should not really change the argument, but we make an exception for passwords */ - my_free(pass); + my_free(opt_password); char *start= (char*) argument; - pass= my_strdup(PSI_NOT_INSTRUMENTED, argument,MYF(MY_FAE)); + opt_password= my_strdup(PSI_NOT_INSTRUMENTED, argument,MYF(MY_FAE)); while (*argument) *(char*)argument++= 'x'; /* Destroy argument */ if (*start) @@ -2261,7 +2261,7 @@ get_one_option(const struct my_option *opt, const char *argument, break; } if (tty_password) - pass= my_get_tty_password(NullS); + opt_password= my_get_tty_password(NullS); return 0; } @@ -2351,7 +2351,7 @@ static Exit_status safe_connect() return ERROR_STOP; } - SET_SSL_OPTS(mysql); + SET_SSL_OPTS_WITH_CHECK(mysql); if (opt_plugindir && *opt_plugindir) mysql_options(mysql, MYSQL_PLUGIN_DIR, opt_plugindir); @@ -2364,7 +2364,7 @@ static Exit_status safe_connect() mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_RESET, 0); mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "program_name", "mysqlbinlog"); - if (!mysql_real_connect(mysql, host, user, pass, 0, port, sock, 0)) + if (!mysql_real_connect(mysql, host, user, opt_password, 0, opt_mysql_port, sock, 0)) { error("Failed on connect: %s", mysql_error(mysql)); return ERROR_STOP; diff --git a/client/mysqldump.cc b/client/mysqldump.cc index b8f892f54d2..1b05e45f478 100644 --- a/client/mysqldump.cc +++ b/client/mysqldump.cc @@ -1992,7 +1992,7 @@ static MYSQL* connect_to_db(char *host, char *user,char *passwd) MYSQL* con = mysql_init(NULL); if (opt_compress) mysql_options(con,MYSQL_OPT_COMPRESS,NullS); - SET_SSL_OPTS(con); + SET_SSL_OPTS_WITH_CHECK(con); if (opt_protocol) mysql_options(con,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol); mysql_options(con, MYSQL_SET_CHARSET_NAME, default_charset); diff --git a/include/sslopt-longopts.h b/include/sslopt-longopts.h index 33e51cae87d..586440bad11 100644 --- a/include/sslopt-longopts.h +++ b/include/sslopt-longopts.h @@ -60,7 +60,7 @@ {"ssl-verify-server-cert", OPT_SSL_VERIFY_SERVER_CERT, "Verify server's certificate to prevent man-in-the-middle attacks", &opt_ssl_verify_server_cert, &opt_ssl_verify_server_cert, - 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0}, + 0, GET_BOOL, OPT_ARG, 2, 0, 0, 0, 0, 0}, #endif #endif /* HAVE_OPENSSL */ #endif /* SSLOPT_LONGOPTS_INCLUDED */ diff --git a/include/sslopt-vars.h b/include/sslopt-vars.h index 44c98ae26da..bad28db41d2 100644 --- a/include/sslopt-vars.h +++ b/include/sslopt-vars.h @@ -34,7 +34,7 @@ SSL_STATIC char *opt_tls_version = 0; #ifdef MYSQL_CLIENT SSL_STATIC char *opt_ssl_fp = 0; SSL_STATIC char *opt_ssl_fplist = 0; -SSL_STATIC my_bool opt_ssl_verify_server_cert= 1; +SSL_STATIC my_bool opt_ssl_verify_server_cert= 2; #define SET_SSL_OPTS(M) \ do { \ @@ -51,8 +51,31 @@ SSL_STATIC my_bool opt_ssl_verify_server_cert= 1; mysql_options((M),MYSQL_OPT_SSL_VERIFY_SERVER_CERT, \ &opt_ssl_verify_server_cert); \ } while(0) + +/* + let's disable opt_ssl_verify_server_cert if neither CA nor FP and + nor password were specified and the protocol is TCP. +*/ +#define SET_SSL_OPTS_WITH_CHECK(M) \ + do { \ + if (opt_ssl_verify_server_cert==2 && \ + !(opt_ssl_ca && opt_ssl_ca[0]) && \ + !(opt_ssl_capath && opt_ssl_capath[0]) && \ + !(opt_ssl_fp && opt_ssl_fp[0]) && \ + !(opt_ssl_fplist && opt_ssl_fplist[0]) && \ + !(opt_password && opt_password[0]) && \ + opt_protocol == MYSQL_PROTOCOL_TCP) \ + { \ + fprintf(stderr, "WARNING: option --ssl-verify-server-cert is " \ + "disabled, because of an insecure passwordless login.\n");\ + opt_ssl_verify_server_cert= 0; \ + } \ + SET_SSL_OPTS(M); \ + } while (0) + #endif #else #define SET_SSL_OPTS(M) do { } while(0) +#define SET_SSL_OPTS_WITH_CHECK(M) do { } while(0) #endif #endif /* SSLOPT_VARS_INCLUDED */ diff --git a/mysql-test/main/mysql.result b/mysql-test/main/mysql.result index 1792f09d3ac..ecc052d9ee2 100644 --- a/mysql-test/main/mysql.result +++ b/mysql-test/main/mysql.result @@ -634,7 +634,7 @@ drop table t1; # MDEV-15538 '-N' Produce html output wrong #
1
-WARNING: option '--enable-cleartext-plugin' is obsolete. +WARNING: option --enable-cleartext-plugin is obsolete. 1 1 # diff --git a/mysql-test/main/ssl_autoverify,win.rdiff b/mysql-test/main/ssl_autoverify,win.rdiff index a2e3f26ecb5..541870f117f 100644 --- a/mysql-test/main/ssl_autoverify,win.rdiff +++ b/mysql-test/main/ssl_autoverify,win.rdiff @@ -1,9 +1,9 @@ ---- main/ssl_autoverify.reject -+++ main/ssl_autoverify.result -@@ -18,9 +18,9 @@ +--- a/mysql-test/main/ssl_autoverify.result ++++ b/mysql-test/main/ssl_autoverify.result +@@ -22,9 +22,9 @@ ERROR 2026 (HY000): TLS/SSL error: Failed to verify the server certificate + WARNING: option --ssl-verify-server-cert is disabled, because of an insecure passwordless login. + test.have_ssl() yes - # mysql -uroot --ssl-verify-server-cert -e "select test.have_ssl()" - ERROR 2026 (HY000): TLS/SSL error: Failed to verify the server certificate -# mysql --protocol socket -uroot --ssl-verify-server-cert -e "select test.have_ssl()" +# mysql --protocol pipe -uroot --ssl-verify-server-cert -e "select test.have_ssl()" test.have_ssl() @@ -12,7 +12,7 @@ # mysql -unative -pfoo --ssl-verify-server-cert -e "select test.have_ssl()" test.have_ssl() yes -@@ -38,16 +38,6 @@ +@@ -42,16 +42,6 @@ yes # mysql -umulti -ppw2 --ssl-verify-server-cert -e "select test.have_ssl()" test.have_ssl() yes diff --git a/mysql-test/main/ssl_autoverify.result b/mysql-test/main/ssl_autoverify.result index 0e7a3dc9b94..551e817819f 100644 --- a/mysql-test/main/ssl_autoverify.result +++ b/mysql-test/main/ssl_autoverify.result @@ -18,6 +18,10 @@ test.have_ssl() yes # mysql -uroot --ssl-verify-server-cert -e "select test.have_ssl()" ERROR 2026 (HY000): TLS/SSL error: Failed to verify the server certificate +# mysql -uroot -e "select test.have_ssl()" +WARNING: option --ssl-verify-server-cert is disabled, because of an insecure passwordless login. +test.have_ssl() +yes # mysql --protocol socket -uroot --ssl-verify-server-cert -e "select test.have_ssl()" test.have_ssl() yes diff --git a/mysql-test/main/ssl_autoverify.test b/mysql-test/main/ssl_autoverify.test index 907817d677d..e042e42855b 100644 --- a/mysql-test/main/ssl_autoverify.test +++ b/mysql-test/main/ssl_autoverify.test @@ -35,7 +35,13 @@ create function have_ssl() returns char(3) --error 1 --exec $MYSQL --protocol tcp -uroot --ssl-verify-server-cert -e "select test.have_ssl()" 2>&1 # -# unless using a secure transport, like unix_socket or named pipes +# except if ssl-verify-server-cert is left on default (not explicitly enabled) +# +--let $csd=`select @@character_sets_dir` +--echo # mysql -uroot -e "select test.have_ssl()" +--exec $EXE_MYSQL --no-defaults --character-sets-dir=$csd --protocol tcp --port $MASTER_MYPORT -uroot -e "select test.have_ssl()" 2>&1 +# +# or unless using a secure transport, like unix_socket or named pipes # # note that SSL works over unix_socket, and it doesn't work over named pipes # but the connection is allowed either way, as the transport is secure