diff options
Diffstat (limited to 'libmariadb')
49 files changed, 1367 insertions, 195 deletions
diff --git a/libmariadb/.travis.yml b/libmariadb/.travis.yml index aab4dfec..02d0d29c 100644 --- a/libmariadb/.travis.yml +++ b/libmariadb/.travis.yml @@ -24,5 +24,7 @@ jobs: name: "CS 10.11 Server unit testing" - env: server_branch=11.3 TEST_OPTION=--ps-protocol name: "11.3 Server unit testing with ps-protocol" + - env: server_branch=11.4 + name: "11.4 Server unit testing" script: ./travis.sh diff --git a/libmariadb/CMakeLists.txt b/libmariadb/CMakeLists.txt index b987bc7f..ed9572cb 100644 --- a/libmariadb/CMakeLists.txt +++ b/libmariadb/CMakeLists.txt @@ -25,7 +25,8 @@ get_directory_property(IS_SUBPROJECT PARENT_DIRECTORY) SET_PROPERTY(DIRECTORY PROPERTY INCLUDE_DIRECTORIES) FOREACH(V WITH_MYSQLCOMPAT WITH_MSI WITH_SIGNCODE WITH_RTC WITH_UNIT_TESTS WITH_DYNCOL WITH_EXTERNAL_ZLIB WITH_CURL WITH_SQLITE WITH_SSL WITH_ICONV - DEFAULT_CHARSET INSTALL_LAYOUT WITH_TEST_SRCPKG) + DEFAULT_CHARSET INSTALL_LAYOUT WITH_TEST_SRCPKG + DEFAULT_SSL_VERIFY_SERVER_CERT) SET(${V} ${${OPT}${V}}) ENDFOREACH() @@ -35,8 +36,8 @@ SET(CC_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) SET(CC_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) SET(CPACK_PACKAGE_VERSION_MAJOR 3) -SET(CPACK_PACKAGE_VERSION_MINOR 3) -SET(CPACK_PACKAGE_VERSION_PATCH 10) +SET(CPACK_PACKAGE_VERSION_MINOR 4) +SET(CPACK_PACKAGE_VERSION_PATCH 0) SET(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}") MATH(EXPR MARIADB_PACKAGE_VERSION_ID "${CPACK_PACKAGE_VERSION_MAJOR} * 10000 + ${CPACK_PACKAGE_VERSION_MINOR} * 100 + @@ -65,6 +66,7 @@ ADD_OPTION(WITH_DYNCOL "Enables support of dynamic columns" ON) ADD_OPTION(WITH_EXTERNAL_ZLIB "Enables use of external zlib" OFF) ADD_OPTION(WITH_CURL "Enables use of curl" ON) ADD_OPTION(WITH_SSL "Enables use of TLS/SSL library" ON) +ADD_OPTION(DEFAULT_SSL_VERIFY_SERVER_CERT "Default value for MYSQL_OPT_SSL_VERIFY_SERVER_CERT" ON) ############### INCLUDE(${CC_SOURCE_DIR}/cmake/misc.cmake) @@ -305,7 +307,8 @@ IF(NOT WITH_SSL STREQUAL "OFF") ENDIF() IF(OPENSSL_FOUND) ADD_DEFINITIONS(-DHAVE_OPENSSL -DHAVE_TLS) - SET(SSL_SOURCES "${CC_SOURCE_DIR}/libmariadb/secure/openssl.c") + SET(SSL_SOURCES "${CC_SOURCE_DIR}/libmariadb/secure/openssl.c" + "${CC_SOURCE_DIR}/libmariadb/secure/openssl_crypt.c") SET(SSL_LIBRARIES ${OPENSSL_SSL_LIBRARY} ${OPENSSL_CRYPTO_LIBRARY}) IF(WIN32) CHECK_INCLUDE_FILES (${OPENSSL_INCLUDE_DIR}/openssl/applink.c HAVE_OPENSSL_APPLINK_C) @@ -332,7 +335,8 @@ IF(NOT WITH_SSL STREQUAL "OFF") FIND_PACKAGE(GnuTLS "3.3.24" REQUIRED) IF(GNUTLS_FOUND) ADD_DEFINITIONS(-DHAVE_GNUTLS -DHAVE_TLS) - SET(SSL_SOURCES "${CC_SOURCE_DIR}/libmariadb/secure/gnutls.c") + SET(SSL_SOURCES "${CC_SOURCE_DIR}/libmariadb/secure/gnutls.c" + "${CC_SOURCE_DIR}/libmariadb/secure/gnutls_crypt.c") SET(SSL_LIBRARIES ${GNUTLS_LIBRARY}) SET(TLS_LIBRARY_VERSION "GnuTLS ${GNUTLS_VERSION_STRING}") INCLUDE_DIRECTORIES(${GNUTLS_INCLUDE_DIR}) @@ -342,12 +346,13 @@ IF(NOT WITH_SSL STREQUAL "OFF") ENDIF() IF(WIN32) IF(WITH_SSL STREQUAL "SCHANNEL") - ADD_DEFINITIONS(-DHAVE_SCHANNEL -DHAVE_TLS) + ADD_DEFINITIONS(-DHAVE_SCHANNEL -DHAVE_TLS -DHAVE_WINCRYPT) SET(SSL_SOURCES "${CC_SOURCE_DIR}/libmariadb/secure/schannel.c" + "${CC_SOURCE_DIR}/libmariadb/secure/win_crypt.c" "${CC_SOURCE_DIR}/libmariadb/secure/ma_schannel.c" "${CC_SOURCE_DIR}/libmariadb/secure/schannel_certs.c") INCLUDE_DIRECTORIES("${CC_SOURCE_DIR}/plugins/pvio/") - SET(SSL_LIBRARIES secur32) + SET(SSL_LIBRARIES secur32 crypt32 bcrypt) SET(TLS_LIBRARY_VERSION "Schannel ${CMAKE_SYSTEM_VERSION}") ENDIF() ENDIF() @@ -382,7 +387,7 @@ CONFIGURE_FILE(${CC_SOURCE_DIR}/include/mariadb_version.h.in INCLUDE_DIRECTORIES(${CC_BINARY_DIR}/include) IF(WIN32) - SET(SYSTEM_LIBS ws2_32 advapi32 kernel32 shlwapi crypt32 ${LIBZ}) + SET(SYSTEM_LIBS ws2_32 advapi32 kernel32 shlwapi crypt32 bcrypt ${LIBZ}) ELSE() SET(SYSTEM_LIBS ${SYSTEM_LIBS} ${LIBPTHREAD} ${CMAKE_DL_LIBS} ${LIBM}) IF(ICONV_EXTERNAL) @@ -542,6 +547,7 @@ ENDIF() MESSAGE1(STATUS "MariaDB Connector/c configuration: -- Static PLUGINS ${PLUGINS_STATIC} -- Dynamic PLUGINS ${PLUGINS_DYNAMIC} +-- Disabled PLUGINS ${PLUGINS_DISABLED} -- CPack generation: ${CPACK_GENERATOR} -- SSL support: ${WITH_SSL} Libs: ${SSL_LIBRARIES} -- Zlib support: ${zlib_status} diff --git a/libmariadb/cmake/plugins.cmake b/libmariadb/cmake/plugins.cmake index 1f321b14..de5c12c1 100644 --- a/libmariadb/cmake/plugins.cmake +++ b/libmariadb/cmake/plugins.cmake @@ -12,7 +12,7 @@ include(${CC_SOURCE_DIR}/cmake/sign.cmake) FUNCTION(REGISTER_PLUGIN) - SET(one_value_keywords TARGET DEFAULT TYPE) + SET(one_value_keywords TARGET DISABLED TYPE DEFAULT) SET(multi_value_keywords CONFIGURATIONS SOURCES LIBRARIES INCLUDES COMPILE_OPTIONS) cmake_parse_arguments(CC_PLUGIN @@ -43,12 +43,19 @@ FUNCTION(REGISTER_PLUGIN) message(FATAL_ERROR "Invalid plugin type ${CC_PLUGIN_DEFAULT}. Allowed plugin types are ${CC_PLUGIN_CONFIGURATIONS}") endif() +# check if plugin is disabled + string(TOUPPER "${CC_PLUGIN_DISABLED}" CC_PLUGIN_DISABLED) + if("${CC_PLUGIN_DISABLED}" STREQUAL "YES") + set(PLUGINS_DISABLED ${PLUGINS_DISABLED} ${CC_PLUGIN_TARGET} PARENT_SCOPE) + endif() + if(NOT ${CC_PLUGIN_DEFAULT} STREQUAL "OFF") set(PLUGIN_${CC_PLUGIN_TARGET}_TYPE ${CC_PLUGIN_TYPE}) - if(${CC_PLUGIN_DEFAULT} STREQUAL "DYNAMIC") + if(${CC_PLUGIN_DEFAULT} MATCHES "DYNAMIC") set(PLUGINS_DYNAMIC ${PLUGINS_DYNAMIC} ${CC_PLUGIN_TARGET} PARENT_SCOPE) + add_library(${CC_PLUGIN_TARGET} MODULE ${CC_PLUGIN_SOURCES}) if(WIN32) set(target ${CC_PLUGIN_TARGET}) set(FILE_TYPE "VFT_DLL") @@ -58,9 +65,9 @@ FUNCTION(REGISTER_PLUGIN) configure_file(${CC_SOURCE_DIR}/win/resource.rc.in ${CC_BINARY_DIR}/win/${target}.rc @ONLY) - set(CC_PLUGIN_SOURCES ${CC_PLUGIN_SOURCES} ${CC_BINARY_DIR}/win/${target}.rc ${CC_SOURCE_DIR}/plugins/plugin.def) + target_sources(${CC_PLUGIN_TARGET} PRIVATE + ${CC_BINARY_DIR}/win/${target}.rc ${CC_SOURCE_DIR}/plugins/plugin.def) endif() - add_library(${CC_PLUGIN_TARGET} MODULE ${CC_PLUGIN_SOURCES}) target_link_libraries(${CC_PLUGIN_TARGET} ${CC_PLUGIN_LIBRARIES}) set_target_properties(${CC_PLUGIN_TARGET} PROPERTIES PREFIX "") set_target_properties(${CC_PLUGIN_TARGET} @@ -81,7 +88,8 @@ FUNCTION(REGISTER_PLUGIN) SIGN_TARGET(${target}) endif() INSTALL_PLUGIN(${CC_PLUGIN_TARGET} ${CMAKE_CURRENT_BINARY_DIR}) - elseif(${CC_PLUGIN_DEFAULT} STREQUAL "STATIC") + endif() + if(${CC_PLUGIN_DEFAULT} MATCHES "STATIC") set(PLUGINS_STATIC ${PLUGINS_STATIC} ${CC_PLUGIN_TARGET} PARENT_SCOPE) set(LIBMARIADB_PLUGIN_CFLAGS ${LIBMARIADB_PLUGIN_CFLAGS} ${CC_PLUGIN_COMPILE_OPTIONS} PARENT_SCOPE) set(LIBMARIADB_PLUGIN_INCLUDES ${LIBMARIADB_PLUGIN_INCLUDES} ${CC_PLUGIN_INCLUDES} PARENT_SCOPE) diff --git a/libmariadb/include/errmsg.h b/libmariadb/include/errmsg.h index f22db164..0e6d24e0 100644 --- a/libmariadb/include/errmsg.h +++ b/libmariadb/include/errmsg.h @@ -115,10 +115,11 @@ extern const char *mariadb_client_errors[]; /* Error messages */ #define CR_BINLOG_INVALID_FILE 5022 #define CR_BINLOG_SEMI_SYNC_ERROR 5023 #define CR_INVALID_CLIENT_FLAG 5024 +#define CR_STMT_NO_RESULT 5025 /* Always last, if you add new error codes please update the value for CR_MARIADB_LAST_ERROR */ -#define CR_MARIADB_LAST_ERROR CR_INVALID_CLIENT_FLAG +#define CR_MARIADB_LAST_ERROR CR_STMT_NO_RESULT #endif diff --git a/libmariadb/include/ma_common.h b/libmariadb/include/ma_common.h index 1ac0cb68..dfa96621 100644 --- a/libmariadb/include/ma_common.h +++ b/libmariadb/include/ma_common.h @@ -73,6 +73,7 @@ struct st_mysql_options_extension { unsigned int tls_cipher_strength; char *tls_version; my_bool read_only; + my_bool bulk_unit_results; char *connection_handler; my_bool (*set_option)(MYSQL *mysql, const char *config_option, const char *config_value); MA_HASHTBL userdata; @@ -86,7 +87,7 @@ struct st_mysql_options_extension { unsigned short rpl_port; void (*status_callback)(void *ptr, enum enum_mariadb_status_info type, ...); void *status_data; - my_bool tls_verify_server_cert; + my_bool tls_allow_invalid_server_cert; }; typedef struct st_connection_handler @@ -129,3 +130,16 @@ typedef struct st_mariadb_field_extension { MARIADB_CONST_STRING metadata[MARIADB_FIELD_ATTR_LAST+1]; /* 10.5 */ } MA_FIELD_EXTENSION; + +#if defined(HAVE_SCHANNEL) || defined(HAVE_GNUTLS) +#define reset_tls_self_signed_error(mysql) \ + do { \ + free((char*)mysql->net.tls_self_signed_error); \ + mysql->net.tls_self_signed_error= 0; \ + } while(0) +#else +#define reset_tls_self_signed_error(mysql) \ + do { \ + mysql->net.tls_self_signed_error= 0; \ + } while(0) +#endif diff --git a/libmariadb/include/ma_config.h.in b/libmariadb/include/ma_config.h.in index c5c758dc..4cabfef3 100644 --- a/libmariadb/include/ma_config.h.in +++ b/libmariadb/include/ma_config.h.in @@ -148,3 +148,4 @@ #define MARIADB_DEFAULT_CHARSET "@DEFAULT_CHARSET@" +#cmakedefine DEFAULT_SSL_VERIFY_SERVER_CERT 1 diff --git a/libmariadb/include/ma_crypt.h b/libmariadb/include/ma_crypt.h index 367488fa..b4d2a09f 100644 --- a/libmariadb/include/ma_crypt.h +++ b/libmariadb/include/ma_crypt.h @@ -17,34 +17,20 @@ 51 Franklin St., Fifth Floor, Boston, MA 02110, USA */ -#ifndef _ma_hash_h_ -#define _ma_hash_h_ +#ifndef _ma_crypt_h_ +#define _ma_crypt_h_ +#include <ma_hash.h> #include <stddef.h> #include <stdarg.h> /*! Hash algorithms */ -#define MA_HASH_MD5 1 -#define MA_HASH_SHA1 2 -#define MA_HASH_SHA224 3 -#define MA_HASH_SHA256 4 -#define MA_HASH_SHA384 5 -#define MA_HASH_SHA512 6 #define MA_HASH_RIPEMD160 7 #define MA_HASH_MAX 8 /*! Hash digest sizes */ -#define MA_MD5_HASH_SIZE 16 -#define MA_SHA1_HASH_SIZE 20 -#define MA_SHA224_HASH_SIZE 28 -#define MA_SHA256_HASH_SIZE 32 -#define MA_SHA384_HASH_SIZE 48 -#define MA_SHA512_HASH_SIZE 64 #define MA_RIPEMD160_HASH_SIZE 20 -#define MA_MAX_HASH_SIZE 64 -/** \typedef MRL hash context */ - #if defined(HAVE_WINCRYPT) typedef void MA_HASH_CTX; #elif defined(HAVE_OPENSSL) @@ -123,8 +109,6 @@ static inline size_t ma_hash_digest_size(unsigned int hash_alg) return MA_SHA384_HASH_SIZE; case MA_HASH_SHA512: return MA_SHA512_HASH_SIZE; - case MA_HASH_RIPEMD160: - return MA_RIPEMD160_HASH_SIZE; default: return 0; } @@ -152,4 +136,4 @@ static inline void ma_hash(unsigned int algorithm, ma_hash_free(ctx); } -#endif /* _ma_hash_h_ */ +#endif /* _ma_crypt_h_ */ diff --git a/libmariadb/include/ma_tls.h b/libmariadb/include/ma_tls.h index ec8bc239..6601f896 100644 --- a/libmariadb/include/ma_tls.h +++ b/libmariadb/include/ma_tls.h @@ -1,6 +1,8 @@ #ifndef _ma_tls_h_ #define _ma_tls_h_ +#include <ma_hash.h> + enum enum_pvio_tls_type { SSL_TYPE_DEFAULT=0, #ifdef _WIN32 @@ -25,6 +27,7 @@ typedef struct st_ma_pvio_tls { void *data; MARIADB_PVIO *pvio; void *ssl; + MARIADB_X509_INFO cert_info; } MARIADB_TLS; /* Function prototypes */ @@ -128,12 +131,14 @@ const char *ma_tls_get_cipher(MARIADB_TLS *ssl); returns SHA1 finger print of server certificate Parameter: MARIADB_TLS MariaDB SSL container + hash_type hash_type as defined in ma_hash.h fp buffer for fingerprint fp_len buffer length + Returns: actual size of finger print */ -unsigned int ma_tls_get_finger_print(MARIADB_TLS *ctls, char *fp, unsigned int fp_len); +unsigned int ma_tls_get_finger_print(MARIADB_TLS *ctls, uint hash_type, char *fp, unsigned int fp_len); /* ma_tls_get_protocol_version returns protocol version number in use diff --git a/libmariadb/include/mariadb_com.h b/libmariadb/include/mariadb_com.h index 01a13dab..6e7164a3 100644 --- a/libmariadb/include/mariadb_com.h +++ b/libmariadb/include/mariadb_com.h @@ -177,6 +177,8 @@ enum enum_server_command #define MARIADB_CLIENT_EXTENDED_METADATA (1ULL << 35) /* Do not resend metadata for prepared statements, since 10.6*/ #define MARIADB_CLIENT_CACHE_METADATA (1ULL << 36) +/* permit sending unit result-set for BULK commands */ +#define MARIADB_CLIENT_BULK_UNIT_RESULTS (1ULL << 37) #define IS_MARIADB_EXTENDED_SERVER(mysql)\ (!(mysql->server_capabilities & CLIENT_MYSQL)) @@ -184,7 +186,8 @@ enum enum_server_command #define MARIADB_CLIENT_SUPPORTED_FLAGS (MARIADB_CLIENT_PROGRESS |\ MARIADB_CLIENT_STMT_BULK_OPERATIONS|\ MARIADB_CLIENT_EXTENDED_METADATA|\ - MARIADB_CLIENT_CACHE_METADATA) + MARIADB_CLIENT_CACHE_METADATA|\ + MARIADB_CLIENT_BULK_UNIT_RESULTS) #define CLIENT_SUPPORTED_FLAGS (CLIENT_MYSQL |\ CLIENT_FOUND_ROWS |\ @@ -231,6 +234,9 @@ enum enum_server_command #define CLIENT_DEFAULT_FLAGS ((CLIENT_SUPPORTED_FLAGS & ~CLIENT_COMPRESS)\ & ~CLIENT_SSL) +#define CLIENT_DEFAULT_EXTENDED_FLAGS (MARIADB_CLIENT_SUPPORTED_FLAGS &\ + ~MARIADB_CLIENT_BULK_UNIT_RESULTS) + #define SERVER_STATUS_IN_TRANS 1 /* Transaction has started */ #define SERVER_STATUS_AUTOCOMMIT 2 /* Server in auto_commit mode */ #define SERVER_MORE_RESULTS_EXIST 8 @@ -294,7 +300,7 @@ typedef struct st_net { my_bool unused_2; my_bool compress; my_bool unused_3; - void *unused_4; + const char *tls_self_signed_error; unsigned int last_errno; unsigned char error; my_bool unused_5; diff --git a/libmariadb/include/mariadb_rpl.h b/libmariadb/include/mariadb_rpl.h index ea0ca4db..f12fdfa1 100644 --- a/libmariadb/include/mariadb_rpl.h +++ b/libmariadb/include/mariadb_rpl.h @@ -501,10 +501,7 @@ struct st_mariadb_rpl_rows_event { }; struct st_mariadb_rpl_heartbeat_event { - uint32_t timestamp; - uint32_t next_position; - uint8_t type; - uint16_t flags; + MARIADB_STRING filename; }; struct st_mariadb_rpl_xa_prepare_log_event { diff --git a/libmariadb/include/mariadb_stmt.h b/libmariadb/include/mariadb_stmt.h index 531c2181..87ad4fa5 100644 --- a/libmariadb/include/mariadb_stmt.h +++ b/libmariadb/include/mariadb_stmt.h @@ -34,6 +34,12 @@ ((stmt)->mysql->extension->mariadb_server_capabilities & \ (MARIADB_CLIENT_STMT_BULK_OPERATIONS >> 32)))) +#define MARIADB_STMT_BULK_UNIT_RESULTS_SUPPORTED(stmt)\ + ((stmt)->mysql && \ + (!((stmt)->mysql->server_capabilities & CLIENT_MYSQL) &&\ + ((stmt)->mysql->extension->mariadb_client_flag & \ + (MARIADB_CLIENT_BULK_UNIT_RESULTS >> 32)))) + #define CLEAR_CLIENT_STMT_ERROR(a) \ do { \ (a)->last_errno= 0;\ @@ -88,7 +94,7 @@ enum enum_indicator_type bulk PS flags */ #define STMT_BULK_FLAG_CLIENT_SEND_TYPES 128 -#define STMT_BULK_FLAG_INSERT_ID_REQUEST 64 +#define STMT_BULK_FLAG_SEND_UNIT_RESULTS 64 typedef enum mysql_stmt_state { diff --git a/libmariadb/include/mysql.h b/libmariadb/include/mysql.h index 76b16830..1d30486a 100644 --- a/libmariadb/include/mysql.h +++ b/libmariadb/include/mysql.h @@ -33,6 +33,7 @@ extern "C" { #endif #include <stdarg.h> +#include <time.h> #if !defined (_global_h) && !defined (MY_GLOBAL_INCLUDED) /* If not standard header */ #include <sys/types.h> @@ -257,7 +258,8 @@ extern const char *SQLSTATE_UNKNOWN; MARIADB_OPT_RESTRICTED_AUTH, MARIADB_OPT_RPL_REGISTER_REPLICA, MARIADB_OPT_STATUS_CALLBACK, - MARIADB_OPT_SERVER_PLUGINS + MARIADB_OPT_SERVER_PLUGINS, + MARIADB_OPT_BULK_UNIT_RESULTS }; enum mariadb_value { @@ -296,7 +298,8 @@ extern const char *SQLSTATE_UNKNOWN; MARIADB_CONNECTION_EXTENDED_SERVER_CAPABILITIES, MARIADB_CONNECTION_CLIENT_CAPABILITIES, MARIADB_CONNECTION_BYTES_READ, - MARIADB_CONNECTION_BYTES_SENT + MARIADB_CONNECTION_BYTES_SENT, + MARIADB_TLS_PEER_CERT_INFO, }; enum mysql_status { MYSQL_STATUS_READY, @@ -336,7 +339,7 @@ struct st_mysql_options { enum mysql_option methods_to_use; char *bind_address; my_bool secure_auth; - my_bool report_data_truncation; + my_bool report_data_truncation; /* function pointers for local infile support */ int (*local_infile_init)(void **, const char *, void *); int (*local_infile_read)(void *, char *, unsigned int); @@ -480,6 +483,27 @@ struct st_mysql_client_plugin MYSQL_CLIENT_PLUGIN_HEADER }; +enum mariadb_tls_verification { + MARIADB_VERIFY_NONE = 0, + MARIADB_VERIFY_PIPE, + MARIADB_VERIFY_UNIXSOCKET, + MARIADB_VERIFY_LOCALHOST, + MARIADB_VERIFY_FINGERPRINT, + MARIADB_VERIFY_PEER_CERT +}; + +typedef struct +{ + int version; + char *issuer; + char *subject; + char fingerprint[65]; + struct tm not_before; + struct tm not_after; + enum mariadb_tls_verification verify_mode; +} MARIADB_X509_INFO; + + struct st_mysql_client_plugin * mysql_load_plugin(struct st_mysql *mysql, const char *name, int type, int argc, ...); diff --git a/libmariadb/include/mysql/client_plugin.h b/libmariadb/include/mysql/client_plugin.h index 667074ce..aa7e5363 100644 --- a/libmariadb/include/mysql/client_plugin.h +++ b/libmariadb/include/mysql/client_plugin.h @@ -43,7 +43,7 @@ #define MYSQL_CLIENT_PLUGIN_RESERVED2 1 #define MYSQL_CLIENT_AUTHENTICATION_PLUGIN 2 /* authentication */ -#define MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION 0x0100 +#define MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION 0x0101 #define MYSQL_CLIENT_MAX_PLUGINS 3 /* Connector/C specific plugin types */ @@ -128,6 +128,7 @@ struct st_mysql_client_plugin_AUTHENTICATION { MYSQL_CLIENT_PLUGIN_HEADER int (*authenticate_user)(MYSQL_PLUGIN_VIO *vio, struct st_mysql *mysql); + int (*hash_password_bin)(struct st_mysql *mysql, unsigned char *hash, size_t *hash_length); }; /******** trace plugin *******/ diff --git a/libmariadb/libmariadb/CMakeLists.txt b/libmariadb/libmariadb/CMakeLists.txt index 43ed67b4..852be8dc 100644 --- a/libmariadb/libmariadb/CMakeLists.txt +++ b/libmariadb/libmariadb/CMakeLists.txt @@ -344,6 +344,10 @@ IF(WIN32) ${CC_SOURCE_DIR}/win-iconv/win_iconv.c win32_errmsg.c win32_errmsg.h) + IF(WITH_SSL STREQUAL "SCHANNEL") + SET(LIBMARIADB_SOURCES ${LIBMARIADB_SOURCES} + secure/win_crypt.c) + ENDIF() ELSE() IF(ICONV_INCLUDE_DIR) INCLUDE_DIRECTORIES(BEFORE ${ICONV_INCLUDE_DIR}) diff --git a/libmariadb/libmariadb/ma_charset.c b/libmariadb/libmariadb/ma_charset.c index f6ed6f80..10c191cd 100644 --- a/libmariadb/libmariadb/ma_charset.c +++ b/libmariadb/libmariadb/ma_charset.c @@ -830,9 +830,11 @@ const MARIADB_CHARSET_INFO mariadb_compiled_charsets[] = { 576, 1, UTF8_MB3, UTF8_MB3"_croatian_ci", "", 65001, "UTF-8", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid}, /*MDB*/ { 577, 1, UTF8_MB3, UTF8_MB3"_myanmar_ci", "", 65001, "UTF-8", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid}, /*MDB*/ { 578, 1, UTF8_MB3, UTF8_MB3"_thai_520_w2", "", 65001, "UTF-8", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid}, /*MDB*/ + { 579, 1, UTF8_MB3, UTF8_MB3"_general1400_as_ci", "", 65001, "UTF-8", 1, 3, mysql_mbcharlen_utf8mb3, check_mb_utf8mb3_valid}, /*MDB*/ { 608, 1, UTF8_MB4, UTF8_MB4"_croatian_ci", "", 65001, "UTF-8", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid}, { 609, 1, UTF8_MB4, UTF8_MB4"_myanmar_ci", "", 65001, "UTF-8", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid}, { 610, 1, UTF8_MB4, UTF8_MB4"_thai_520_w2", "", 65001, "UTF-8", 1, 4, mysql_mbcharlen_utf8, check_mb_utf8_valid}, + { 611, 1, UTF8_MB4, UTF8_MB4"_general1400_as_ci", "", 65001, "UTF-8", 1, 3, mysql_mbcharlen_utf8, check_mb_utf8_valid}, { 640, 1, "ucs2", "ucs2_croatian_ci", "", 1200, "UCS2-BE", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2}, { 641, 1, "ucs2", "ucs2_myanmar_ci", "", 1200, "UCS2-BE", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2}, { 642, 1, "ucs2", "ucs2_thai_520_w2", "", 1200, "UCS2-BE", 2, 2, mysql_mbcharlen_ucs2, check_mb_ucs2}, diff --git a/libmariadb/libmariadb/ma_client_plugin.c.in b/libmariadb/libmariadb/ma_client_plugin.c.in index 6e0433b3..a402d082 100644 --- a/libmariadb/libmariadb/ma_client_plugin.c.in +++ b/libmariadb/libmariadb/ma_client_plugin.c.in @@ -46,6 +46,8 @@ #include <dlfcn.h> #endif +const char *disabled_plugins= "@PLUGINS_DISABLED@"; + struct st_client_plugin_int { struct st_client_plugin_int *next; void *dlhandle; @@ -111,8 +113,7 @@ static int get_plugin_nr(uint type) static const char *check_plugin_version(struct st_mysql_client_plugin *plugin, unsigned int version) { - if (plugin->interface_version < version || - (plugin->interface_version >> 8) > (version >> 8)) + if (plugin->interface_version >> 8 != version >> 8) return "Incompatible client plugin interface"; return 0; } diff --git a/libmariadb/libmariadb/ma_errmsg.c b/libmariadb/libmariadb/ma_errmsg.c index 90218573..53890f87 100644 --- a/libmariadb/libmariadb/ma_errmsg.c +++ b/libmariadb/libmariadb/ma_errmsg.c @@ -119,6 +119,7 @@ const char *mariadb_client_errors[] = /* 5022 */ "File '%s' is not a binary log file", /* 5023 */ "Semi sync request error: %s", /* 5024 */ "Invalid client flags (%lu) specified. Supported flags: %lu", + /* 5025 */ "Statement has no result set", "" }; diff --git a/libmariadb/libmariadb/ma_pvio.c b/libmariadb/libmariadb/ma_pvio.c index a8a653b6..e18af51e 100644 --- a/libmariadb/libmariadb/ma_pvio.c +++ b/libmariadb/libmariadb/ma_pvio.c @@ -522,6 +522,55 @@ my_bool ma_pvio_has_data(MARIADB_PVIO *pvio, ssize_t *data_len) /* }}} */ #ifdef HAVE_TLS +/** + Checks if self-signed certificate error should be ignored. +*/ +static my_bool ignore_self_signed_cert_error(MARIADB_PVIO *pvio) +{ + const char *hostname= pvio->mysql->host; + const char *local_host_names[]= { +#ifdef _WIN32 + /* + On Unix, we consider TCP connections with "localhost" + an insecure transport, for the single reason to run tests for + insecure transport on CI.This is artificial, but should be ok. + Default client connections use unix sockets anyway, so it + would not hurt much. + + On Windows, the situation is quite different. + Default connections type is TCP, default host name is "localhost", + non-password plugin gssapi is common (every installation) + In this environment, there would be a lot of faux/disruptive + "self-signed certificates" errors there. Thus, "localhost" TCP + needs to be considered secure transport. + */ + "localhost", +#endif + "127.0.0.1", "::1", NULL}; + int i; + if (pvio->type != PVIO_TYPE_SOCKET) + { + pvio->ctls->cert_info.verify_mode= +#ifdef WIN32 + MARIADB_VERIFY_PIPE; +#else + MARIADB_VERIFY_UNIXSOCKET; +#endif + return TRUE; + } + if (!hostname) + return FALSE; + for (i= 0; local_host_names[i]; i++) + { + if (strcmp(hostname, local_host_names[i]) == 0) + { + pvio->ctls->cert_info.verify_mode= MARIADB_VERIFY_LOCALHOST; + return TRUE; + } + } + return FALSE; +} + /* {{{ my_bool ma_pvio_start_ssl */ my_bool ma_pvio_start_ssl(MARIADB_PVIO *pvio) { @@ -544,20 +593,28 @@ my_bool ma_pvio_start_ssl(MARIADB_PVIO *pvio) 2. verify CN (requires option ssl_verify_check) 3. verrify finger print */ - if (pvio->mysql->options.extension->tls_verify_server_cert && + if (!pvio->mysql->options.extension->tls_allow_invalid_server_cert && + !pvio->mysql->net.tls_self_signed_error && ma_pvio_tls_verify_server_cert(pvio->ctls)) return 1; + else + pvio->ctls->cert_info.verify_mode= MARIADB_VERIFY_PEER_CERT; if (pvio->mysql->options.extension && ((pvio->mysql->options.extension->tls_fp && pvio->mysql->options.extension->tls_fp[0]) || (pvio->mysql->options.extension->tls_fp_list && pvio->mysql->options.extension->tls_fp_list[0]))) { if (ma_pvio_tls_check_fp(pvio->ctls, - pvio->mysql->options.extension->tls_fp, - pvio->mysql->options.extension->tls_fp_list)) + pvio->mysql->options.extension->tls_fp, + pvio->mysql->options.extension->tls_fp_list)) return 1; + pvio->ctls->cert_info.verify_mode= MARIADB_VERIFY_FINGERPRINT; + reset_tls_self_signed_error(pvio->mysql); // validated } + if (pvio->mysql->net.tls_self_signed_error && ignore_self_signed_cert_error(pvio)) + reset_tls_self_signed_error(pvio->mysql); + return 0; } /* }}} */ diff --git a/libmariadb/libmariadb/ma_tls.c b/libmariadb/libmariadb/ma_tls.c index 3f48ad8b..432a0f4a 100644 --- a/libmariadb/libmariadb/ma_tls.c +++ b/libmariadb/libmariadb/ma_tls.c @@ -41,12 +41,15 @@ #include <ma_tls.h> #include <mysql/client_plugin.h> #include <mariadb/ma_io.h> +#include <ma_hash.h> #ifdef HAVE_NONBLOCK #include <mariadb_async.h> #include <ma_context.h> #endif +#define MAX_FINGERPRINT_LEN 128; + /* Errors should be handled via pvio callback function */ my_bool ma_tls_initialized= FALSE; unsigned int mariadb_deinitialize_ssl= 1; @@ -141,62 +144,96 @@ static signed char ma_hex2int(char c) return -1; } -static my_bool ma_pvio_tls_compare_fp(const char *cert_fp, - unsigned int cert_fp_len, - const char *fp, unsigned int fp_len) +#ifndef EVP_MAX_MD_SIZE +#define EVP_MAX_MD_SIZE 64 +#endif + +static my_bool ma_pvio_tls_compare_fp(MARIADB_TLS *ctls, + const char *cert_fp, + unsigned int cert_fp_len +) { - char *p= (char *)fp, - *c; + const char fp[EVP_MAX_MD_SIZE]; + unsigned int fp_len= EVP_MAX_MD_SIZE; + unsigned int hash_type; + + char *p, *c; + uint hash_len; + + /* check length without colons */ + if (strchr(cert_fp, ':')) + hash_len= (uint)((strlen(cert_fp) + 1) / 3) * 2; + else + hash_len= (uint)strlen(cert_fp); + + /* check hash size */ + switch (hash_len) { +#ifndef DISABLE_WEAK_HASH + case MA_SHA1_HASH_SIZE * 2: + hash_type = MA_HASH_SHA1; + break; +#endif + case MA_SHA224_HASH_SIZE * 2: + hash_type = MA_HASH_SHA224; + break; + case MA_SHA256_HASH_SIZE * 2: + hash_type = MA_HASH_SHA256; + break; + case MA_SHA384_HASH_SIZE * 2: + hash_type = MA_HASH_SHA384; + break; + case MA_SHA512_HASH_SIZE * 2: + hash_type = MA_HASH_SHA512; + break; + default: + { + MYSQL* mysql = ctls->pvio->mysql; + my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, + ER(CR_SSL_CONNECTION_ERROR), + "Unknown or invalid fingerprint hash size detected"); + return 1; + } + } - /* check length */ - if (cert_fp_len != 20) + if (!ma_tls_get_finger_print(ctls, hash_type, (char *)fp, fp_len)) return 1; - /* We support two formats: - 2 digits hex numbers, separated by colons (length=59) - 20 * 2 digits hex numbers without separators (length = 40) - */ - if (fp_len != (strchr(fp, ':') ? 59 : 40)) - return 1; + p= (char *)cert_fp; + c = (char *)fp; - for(c= (char *)cert_fp; c < cert_fp + cert_fp_len; c++) + for (p = (char*)cert_fp; p < cert_fp + cert_fp_len; c++, p += 2) { signed char d1, d2; if (*p == ':') p++; - if (p - fp > (int)fp_len -1) + if (p - cert_fp > (int)fp_len - 1) return 1; - if ((d1 = ma_hex2int(*p)) == - 1 || - (d2 = ma_hex2int(*(p+1))) == -1 || - (char)(d1 * 16 + d2) != *c) + if ((d1 = ma_hex2int(*p)) == -1 || + (d2 = ma_hex2int(*(p + 1))) == -1 || + (char)(d1 * 16 + d2) != *c) return 1; - p+= 2; } return 0; } my_bool ma_pvio_tls_check_fp(MARIADB_TLS *ctls, const char *fp, const char *fp_list) { - unsigned int cert_fp_len= 64; - char *cert_fp= NULL; my_bool rc=1; MYSQL *mysql= ctls->pvio->mysql; - cert_fp= (char *)malloc(cert_fp_len); - - if ((cert_fp_len= ma_tls_get_finger_print(ctls, cert_fp, cert_fp_len)) < 1) - goto end; if (fp) - rc= ma_pvio_tls_compare_fp(cert_fp, cert_fp_len, fp, (unsigned int)strlen(fp)); + { + rc = ma_pvio_tls_compare_fp(ctls, fp, (uint)strlen(fp)); + } else if (fp_list) { - MA_FILE *fp; + MA_FILE *f; char buff[255]; - if (!(fp = ma_open(fp_list, "r", mysql))) + if (!(f = ma_open(fp_list, "r", mysql))) goto end; - while (ma_gets(buff, sizeof(buff)-1, fp)) + while (ma_gets(buff, sizeof(buff)-1, f)) { /* remove trailing new line character */ char *pos= strchr(buff, '\r'); @@ -205,22 +242,20 @@ my_bool ma_pvio_tls_check_fp(MARIADB_TLS *ctls, const char *fp, const char *fp_l if (pos) *pos= '\0'; - if (!ma_pvio_tls_compare_fp(cert_fp, cert_fp_len, buff, (unsigned int)strlen(buff))) + if (!ma_pvio_tls_compare_fp(ctls, buff, (uint)strlen(buff))) { /* finger print is valid: close file and exit */ - ma_close(fp); + ma_close(f); rc= 0; goto end; } } /* No finger print matched - close file and return error */ - ma_close(fp); + ma_close(f); } end: - if (cert_fp) - free(cert_fp); if (rc) { my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, diff --git a/libmariadb/libmariadb/mariadb_lib.c b/libmariadb/libmariadb/mariadb_lib.c index c48ccdad..b4a36585 100644 --- a/libmariadb/libmariadb/mariadb_lib.c +++ b/libmariadb/libmariadb/mariadb_lib.c @@ -693,6 +693,7 @@ struct st_default_options mariadb_defaults[] = {{MYSQL_OPT_SSL_ENFORCE}, MARIADB_OPTION_BOOL, "ssl-enforce"}, {{MARIADB_OPT_RESTRICTED_AUTH}, MARIADB_OPTION_STR, "restricted-auth"}, {{.option_func=parse_connection_string}, MARIADB_OPTION_FUNC, "connection"}, + {{MARIADB_OPT_BULK_UNIT_RESULTS}, MARIADB_OPTION_BOOL, "bulk-unit-results"}, /* Aliases */ {{MARIADB_OPT_SCHEMA}, MARIADB_OPTION_STR, "db"}, {{MARIADB_OPT_UNIXSOCKET}, MARIADB_OPTION_STR, "unix_socket"}, @@ -714,10 +715,19 @@ struct st_default_options mariadb_defaults[] = {{0}, 0, NULL} }; +#ifdef DEFAULT_SSL_VERIFY_SERVER_CERT +#define FIX_SSL_VERIFY_SERVER_CERT(OPTS) +#else +#define FIX_SSL_VERIFY_SERVER_CERT(OPTS) (OPTS)->extension->tls_allow_invalid_server_cert=1 +#endif + #define CHECK_OPT_EXTENSION_SET(OPTS)\ if (!(OPTS)->extension) \ + { \ (OPTS)->extension= (struct st_mysql_options_extension *) \ - calloc(1, sizeof(struct st_mysql_options_extension)); + calloc(1, sizeof(struct st_mysql_options_extension)); \ + FIX_SSL_VERIFY_SERVER_CERT(OPTS); \ + } #define OPT_SET_EXTENDED_VALUE_BIN(OPTS, KEY, KEY_LEN, VAL, LEN)\ CHECK_OPT_EXTENSION_SET(OPTS) \ @@ -1449,6 +1459,8 @@ mysql_real_connect(MYSQL *mysql, const char *host, const char *user, if (!mysql->options.extension || !mysql->options.extension->status_callback) mysql_optionsv(mysql, MARIADB_OPT_STATUS_CALLBACK, NULL, NULL); + reset_tls_self_signed_error(mysql); + /* if host contains a semicolon, we need to parse connection string */ if (host && strchr(host, ';')) { @@ -2453,6 +2465,7 @@ mysql_close(MYSQL *mysql) mysql_close_memory(mysql); mysql_close_options(mysql); ma_clear_session_state(mysql); + reset_tls_self_signed_error(mysql); if (mysql->net.extension) { @@ -3300,10 +3313,17 @@ mysql_refresh(MYSQL *mysql,uint options) int STDCALL mysql_kill(MYSQL *mysql,ulong pid) { - char buff[12]; - int4store(buff,pid); - /* if we kill our own thread, reading the response packet will fail */ - return(ma_simple_command(mysql, COM_PROCESS_KILL,buff,4,0,0)); + char buff[16]; + + /* process id can't be larger than 4-bytes */ + if (pid & (~0xFFFFFFFFUL)) + { + my_set_error(mysql, CR_CONNECTION_ERROR, SQLSTATE_UNKNOWN, 0); + return 1; + } + + snprintf(buff, sizeof buff, "KILL %lu", pid); + return mysql_real_query(mysql, (char *)buff, (ulong)strlen(buff)); } @@ -3528,6 +3548,7 @@ mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...) goto end; } if (!mysql->options.extension) + { if(!(mysql->options.extension= (struct st_mysql_options_extension *) calloc(1, sizeof(struct st_mysql_options_extension)))) { @@ -3535,6 +3556,8 @@ mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...) SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); goto end; } + FIX_SSL_VERIFY_SERVER_CERT(&mysql->options); + } mysql->options.extension->async_context= ctxt; break; case MYSQL_OPT_MAX_ALLOWED_PACKET: @@ -3556,7 +3579,7 @@ mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...) mysql->options.use_ssl= (*(my_bool *)arg1); break; case MYSQL_OPT_SSL_VERIFY_SERVER_CERT: - OPT_SET_EXTENDED_VALUE(&mysql->options, tls_verify_server_cert, *(my_bool *)arg1); + OPT_SET_EXTENDED_VALUE(&mysql->options, tls_allow_invalid_server_cert, !*(my_bool *)arg1); break; case MYSQL_OPT_SSL_KEY: OPT_SET_VALUE_STR(&mysql->options, ssl_key, (char *)arg1); @@ -3824,6 +3847,9 @@ mysql_optionsv(MYSQL *mysql,enum mysql_option option, ...) } } break; + case MARIADB_OPT_BULK_UNIT_RESULTS: + OPT_SET_EXTENDED_VALUE_INT(&mysql->options, bulk_unit_results, *(my_bool *)arg1); + break; default: va_end(ap); SET_CLIENT_ERROR(mysql, CR_NOT_IMPLEMENTED, SQLSTATE_UNKNOWN, 0); @@ -3922,7 +3948,7 @@ mysql_get_optionv(MYSQL *mysql, enum mysql_option option, void *arg, ...) *((my_bool *)arg)= mysql->options.use_ssl; break; case MYSQL_OPT_SSL_VERIFY_SERVER_CERT: - *((my_bool*)arg) = mysql->options.extension ? mysql->options.extension->tls_verify_server_cert : 0; + *((my_bool*)arg) = mysql->options.extension ? !mysql->options.extension->tls_allow_invalid_server_cert: 1; break; case MYSQL_OPT_SSL_KEY: *((char **)arg)= mysql->options.ssl_key; @@ -4046,6 +4072,9 @@ mysql_get_optionv(MYSQL *mysql, enum mysql_option option, void *arg, ...) case MARIADB_OPT_SKIP_READ_RESPONSE: *((my_bool*)arg)= mysql->options.extension ? mysql->options.extension->skip_read_response : 0; break; + case MARIADB_OPT_BULK_UNIT_RESULTS: + *((my_bool *)arg)= mysql->options.extension ? mysql->options.extension->bulk_unit_results : 0; + break; default: va_end(ap); SET_CLIENT_ERROR(mysql, CR_NOT_IMPLEMENTED, SQLSTATE_UNKNOWN, 0); @@ -4506,6 +4535,11 @@ my_bool mariadb_get_infov(MYSQL *mysql, enum mariadb_value value, void *arg, ... va_start(ap, arg); switch(value) { +#ifdef HAVE_TLS + case MARIADB_TLS_PEER_CERT_INFO: + *((MARIADB_X509_INFO **)arg)= mysql->net.pvio->ctls ? (MARIADB_X509_INFO *)&mysql->net.pvio->ctls->cert_info : NULL; + break; +#endif case MARIADB_MAX_ALLOWED_PACKET: *((size_t *)arg)= (size_t)max_allowed_packet; break; diff --git a/libmariadb/libmariadb/mariadb_rpl.c b/libmariadb/libmariadb/mariadb_rpl.c index 0019f246..cfaf228d 100644 --- a/libmariadb/libmariadb/mariadb_rpl.c +++ b/libmariadb/libmariadb/mariadb_rpl.c @@ -1165,20 +1165,15 @@ MARIADB_RPL_EVENT * STDCALL mariadb_rpl_fetch(MARIADB_RPL *rpl, MARIADB_RPL_EVEN switch(rpl_event->event_type) { case UNKNOWN_EVENT: case SLAVE_EVENT: - return rpl_event; - break; + return rpl_event; + break; + case HEARTBEAT_LOG_EVENT: - /* no post header size */ - RPL_CHECK_POS(ev, ev_end, 11); - rpl_event->event.heartbeat.timestamp= uint4korr(ev); - ev+= 4; - rpl_event->event.heartbeat.next_position= uint4korr(ev); - ev+= 4; - rpl_event->event.heartbeat.type= (uint8_t)*ev; - ev+= 1; - rpl_event->event.heartbeat.flags= uint2korr(ev); - ev+= 2; - + len= rpl_event->event_length - (ev - ev_start) - (rpl->use_checksum ? 4 : 0) - (EVENT_HEADER_OFS - 1); + RPL_CHECK_POS(ev, ev_end, len); + rpl_event->event.heartbeat.filename.length= len; + rpl_event->event.heartbeat.filename.str= (char *)ev; + ev+= len; break; case BEGIN_LOAD_QUERY_EVENT: @@ -1835,7 +1830,7 @@ MARIADB_RPL_EVENT * STDCALL mariadb_rpl_fetch(MARIADB_RPL *rpl, MARIADB_RPL_EVEN if (rpl_event->event.rows.extra_data_size - 2 > 0) { rpl_alloc_set_string_and_len(rpl_event, rpl_event->event.rows.extra_data, ev, rpl_event->event.rows.extra_data_size - 2); - ev+= rpl_event->event.rows.extra_data_size; + ev+= (rpl_event->event.rows.extra_data_size -2); } } /* END_ROWS_EVENT_V2 */ diff --git a/libmariadb/libmariadb/mariadb_stmt.c b/libmariadb/libmariadb/mariadb_stmt.c index 5bcecfde..cb37359e 100644 --- a/libmariadb/libmariadb/mariadb_stmt.c +++ b/libmariadb/libmariadb/mariadb_stmt.c @@ -123,6 +123,26 @@ void stmt_set_error(MYSQL_STMT *stmt, return; } +/* checks if there are any other statements which have a + pending result set */ +static my_bool madb_have_pending_results(MYSQL_STMT *stmt) +{ + LIST *li_stmt; + + if (!stmt->mysql) + return 0; + + li_stmt= stmt->mysql->stmts; + for (;li_stmt;li_stmt= li_stmt->next) + { + MYSQL_STMT *s= (MYSQL_STMT *)li_stmt->data; + if (s != stmt && s->state == MYSQL_STMT_WAITING_USE_OR_STORE && + !(s->flags & CURSOR_TYPE_READ_ONLY)) + return 1; + } + return 0; +} + my_bool mthd_supported_buffer_type(enum enum_field_types type) { switch (type) { @@ -911,7 +931,7 @@ unsigned char* ma_stmt_execute_generate_bulk_request(MYSQL_STMT *stmt, size_t *r 0 4 Statement id 4 2 Flags (cursor type): STMT_BULK_FLAG_CLIENT_SEND_TYPES = 128 - STMT_BULK_FLAG_INSERT_ID_REQUEST = 64 + STMT_BULK_FLAG_SEND_UNIT_RESULTS = 64 ----------------------------------------- if (stmt->send_types_to_server): for (i=0; i < param_count; i++) @@ -964,6 +984,9 @@ unsigned char* ma_stmt_execute_generate_bulk_request(MYSQL_STMT *stmt, size_t *r /* todo: request to return auto generated ids */ if (stmt->send_types_to_server) flags|= STMT_BULK_FLAG_CLIENT_SEND_TYPES; + if (MARIADB_STMT_BULK_UNIT_RESULTS_SUPPORTED(stmt)) + flags|= STMT_BULK_FLAG_SEND_UNIT_RESULTS; + int2store(p, flags); p+=2; @@ -1486,6 +1509,12 @@ my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt) { my_bool rc= 1; + if (madb_have_pending_results(stmt)) + { + stmt_set_error(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + return 1; + } + if (stmt) { if (stmt->mysql && stmt->mysql->net.pvio) @@ -1610,6 +1639,12 @@ unsigned int STDCALL mysql_stmt_field_count(MYSQL_STMT *stmt) my_bool STDCALL mysql_stmt_free_result(MYSQL_STMT *stmt) { + if (stmt->state < MYSQL_STMT_EXECUTED || !stmt->field_count) + { + stmt_set_error(stmt, CR_STMT_NO_RESULT, SQLSTATE_UNKNOWN, 0); + return 1; + } + return madb_reset_stmt(stmt, MADB_RESET_LONGDATA | MADB_RESET_STORED | MADB_RESET_BUFFER | MADB_RESET_ERROR); } @@ -2196,6 +2231,14 @@ static my_bool madb_reset_stmt(MYSQL_STMT *stmt, unsigned int flags) MYSQL *mysql= stmt->mysql; my_bool ret= 0; + /* CONC-667: If an other statement has a pending result set, we + need to return an error */ + if (madb_have_pending_results(stmt)) + { + stmt_set_error(stmt, CR_COMMANDS_OUT_OF_SYNC, SQLSTATE_UNKNOWN, 0); + return 1; + } + if (!stmt->mysql) { stmt_set_error(stmt, CR_SERVER_LOST, SQLSTATE_UNKNOWN, 0); @@ -2294,7 +2337,8 @@ static my_bool mysql_stmt_internal_reset(MYSQL_STMT *stmt, my_bool is_close) stmt->fetch_row_func == stmt_unbuffered_fetch) flags|= MADB_RESET_BUFFER; - ret= madb_reset_stmt(stmt, flags); + if ((ret= madb_reset_stmt(stmt, flags))) + return ret; if (stmt->stmt_id) { diff --git a/libmariadb/libmariadb/secure/gnutls.c b/libmariadb/libmariadb/secure/gnutls.c index 4782be62..0d40746e 100644 --- a/libmariadb/libmariadb/secure/gnutls.c +++ b/libmariadb/libmariadb/secure/gnutls.c @@ -995,9 +995,6 @@ static size_t ma_gnutls_get_protocol_version(const char *tls_version_option, if (!tls_version_option || !tls_version_option[0]) goto end; - - if (strstr(tls_version_option, "TLSv1.0")) - strcat(tls_versions, ":+VERS-TLS1.0"); if (strstr(tls_version_option, "TLSv1.1")) strcat(tls_versions, ":+VERS-TLS1.1"); if (strstr(tls_version_option, "TLSv1.2")) @@ -1010,7 +1007,7 @@ end: if (tls_versions[0]) snprintf(priority_string, prio_len - 1, "-VERS-TLS-ALL%s:NORMAL", tls_versions); else - strncpy(priority_string, "NORMAL:+VERS-ALL", prio_len - 1); + strncpy(priority_string, "NORMAL:+VERS-ALL+!VERS-TLS1.0", prio_len - 1); return strlen(priority_string); } @@ -1176,6 +1173,8 @@ my_bool ma_tls_connect(MARIADB_TLS *ctls) MYSQL *mysql= (MYSQL *)gnutls_session_get_ptr(ssl); MARIADB_PVIO *pvio; int ret; + const gnutls_datum_t *cert_list; + unsigned int list_size= 0; if (!mysql) return 1; @@ -1217,6 +1216,42 @@ my_bool ma_tls_connect(MARIADB_TLS *ctls) return 1; } ctls->ssl= (void *)ssl; + + /* retrieve peer certificate information */ + if ((cert_list= gnutls_certificate_get_peers(ssl, &list_size))) + { + gnutls_x509_crt_t cert; + + gnutls_x509_crt_init(&cert); + memset(&ctls->cert_info, 0, sizeof(MARIADB_X509_INFO)); + + if (!gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER)) + { + size_t len= 0; + char fp[33]; + time_t notBefore, notAfter; + + ctls->cert_info.version= gnutls_x509_crt_get_version(cert); + + gnutls_x509_crt_get_issuer_dn(cert, NULL, &len); + if ((ctls->cert_info.issuer= (char *)malloc(len))) + gnutls_x509_crt_get_issuer_dn(cert, ctls->cert_info.issuer, &len); + + gnutls_x509_crt_get_dn(cert, NULL, &len); + if ((ctls->cert_info.subject= (char *)malloc(len))) + gnutls_x509_crt_get_dn(cert, ctls->cert_info.subject, &len); + + notBefore= gnutls_x509_crt_get_activation_time(cert); + memcpy(&ctls->cert_info.not_before, gmtime(¬Before), sizeof(struct tm)); + + notAfter= gnutls_x509_crt_get_expiration_time(cert); + memcpy(&ctls->cert_info.not_after, gmtime(¬After), sizeof(struct tm)); + + ma_tls_get_finger_print(ctls, MA_HASH_SHA256, fp, sizeof(fp)); + mysql_hex_string(ctls->cert_info.fingerprint, fp, 32); + } + gnutls_x509_crt_deinit(cert); + } return 0; } @@ -1324,6 +1359,8 @@ my_bool ma_tls_close(MARIADB_TLS *ctls) gnutls_certificate_free_ca_names(ctx); gnutls_certificate_free_credentials(ctx); gnutls_deinit((gnutls_session_t )ctls->ssl); + free(ctls->cert_info.issuer); + free(ctls->cert_info.subject); ctls->ssl= NULL; } return 0; @@ -1357,7 +1394,7 @@ static int my_verify_callback(gnutls_session_t ssl) CLEAR_CLIENT_ERROR(mysql); - if ((mysql->options.extension->tls_verify_server_cert)) + if (!mysql->options.extension->tls_allow_invalid_server_cert) { const char *hostname= mysql->host; @@ -1371,10 +1408,22 @@ static int my_verify_callback(gnutls_session_t ssl) { gnutls_datum_t out; int type; - /* accept self signed certificates if we don't have to verify server cert */ - if (!(mysql->options.extension->tls_verify_server_cert) && - (status & GNUTLS_CERT_SIGNER_NOT_FOUND)) - return 0; + + if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) + { + /* accept self signed certificates if we don't have to verify server cert */ + if (mysql->options.extension->tls_allow_invalid_server_cert) + return 0; + + /* postpone the error for self signed certificates if CA isn't set */ + if (!mysql->options.ssl_ca && !mysql->options.ssl_capath) + { + type= gnutls_certificate_type_get(ssl); + gnutls_certificate_verification_status_print(status, type, &out, 0); + mysql->net.tls_self_signed_error= (char*)out.data; + return 0; + } + } /* gnutls default error message "certificate validation failed" isn't very descriptive, so we provide more information about the error here */ @@ -1391,18 +1440,43 @@ static int my_verify_callback(gnutls_session_t ssl) return 0; } -unsigned int ma_tls_get_finger_print(MARIADB_TLS *ctls, char *fp, unsigned int len) +unsigned int ma_tls_get_finger_print(MARIADB_TLS *ctls, uint hash_type, char *fp, unsigned int len) { MYSQL *mysql; size_t fp_len= len; const gnutls_datum_t *cert_list; unsigned int cert_list_size; + gnutls_digest_algorithm_t hash_alg; if (!ctls || !ctls->ssl) return 0; mysql= (MYSQL *)gnutls_session_get_ptr(ctls->ssl); + switch (hash_type) + { + case MA_HASH_SHA1: + hash_alg = GNUTLS_DIG_SHA1; + break; + case MA_HASH_SHA224: + hash_alg = GNUTLS_DIG_SHA224; + break; + case MA_HASH_SHA256: + hash_alg = GNUTLS_DIG_SHA256; + break; + case MA_HASH_SHA384: + hash_alg = GNUTLS_DIG_SHA384; + break; + case MA_HASH_SHA512: + hash_alg = GNUTLS_DIG_SHA512; + break; + default: + my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, + ER(CR_SSL_CONNECTION_ERROR), + "Cannot detect hash algorithm for fingerprint verification"); + return 0; + } + cert_list = gnutls_certificate_get_peers (ctls->ssl, &cert_list_size); if (cert_list == NULL) { @@ -1412,7 +1486,7 @@ unsigned int ma_tls_get_finger_print(MARIADB_TLS *ctls, char *fp, unsigned int l return 0; } - if (gnutls_fingerprint(GNUTLS_DIG_SHA1, &cert_list[0], fp, &fp_len) == 0) + if (gnutls_fingerprint(hash_alg, &cert_list[0], fp, &fp_len) == 0) return fp_len; else { diff --git a/libmariadb/libmariadb/secure/gnutls_crypt.c b/libmariadb/libmariadb/secure/gnutls_crypt.c index a669e88e..222e5585 100644 --- a/libmariadb/libmariadb/secure/gnutls_crypt.c +++ b/libmariadb/libmariadb/secure/gnutls_crypt.c @@ -34,8 +34,6 @@ static gnutls_digest_algorithm_t ma_hash_get_algorithm(unsigned int alg) return GNUTLS_DIG_SHA384; case MA_HASH_SHA512: return GNUTLS_DIG_SHA512; - case MA_HASH_RIPEMD160: - return GNUTLS_DIG_RMD160; default: return GNUTLS_DIG_UNKNOWN; } diff --git a/libmariadb/libmariadb/secure/ma_schannel.c b/libmariadb/libmariadb/secure/ma_schannel.c index be4148c7..10ea3318 100644 --- a/libmariadb/libmariadb/secure/ma_schannel.c +++ b/libmariadb/libmariadb/secure/ma_schannel.c @@ -526,6 +526,13 @@ my_bool ma_schannel_verify_certs(MARIADB_TLS *ctls, BOOL verify_server_name) end: if (!ret) { + /* postpone the error for self signed certificates if CA isn't set */ + if (status == CERT_E_UNTRUSTEDROOT && !ca_file && !ca_path) + { + mysql->net.tls_self_signed_error= strdup(errmsg); + ret= 1; + } + else pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, 0, errmsg); } if (pServerCert) diff --git a/libmariadb/libmariadb/secure/ma_schannel.h b/libmariadb/libmariadb/secure/ma_schannel.h index af7fc602..562dae1f 100644 --- a/libmariadb/libmariadb/secure/ma_schannel.h +++ b/libmariadb/libmariadb/secure/ma_schannel.h @@ -28,6 +28,7 @@ #include <ma_common.h> #include <ma_pvio.h> #include <errmsg.h> +#include <ma_hash.h> #include <wincrypt.h> @@ -35,6 +36,7 @@ #include <security.h> +#include <ma_crypt.h> #include <schnlsp.h> #undef SECURITY_WIN32 @@ -57,7 +59,7 @@ struct st_schannel { DWORD IoBufferSize; SecPkgContext_StreamSizes Sizes; CtxtHandle hCtxt; - + BCRYPT_ALG_HANDLE HashProv[MA_MAX_HASH_SIZE]; /* Cached data from the last read/decrypt call.*/ SecBuffer extraBuf; /* encrypted data read from server. */ SecBuffer dataBuf; /* decrypted but still unread data from server.*/ diff --git a/libmariadb/libmariadb/secure/openssl.c b/libmariadb/libmariadb/secure/openssl.c index edc90a3b..828c3121 100644 --- a/libmariadb/libmariadb/secure/openssl.c +++ b/libmariadb/libmariadb/secure/openssl.c @@ -29,6 +29,10 @@ #include <openssl/err.h> /* error reporting */ #include <openssl/conf.h> #include <openssl/md4.h> +#include <ma_tls.h> +#if OPENSSL_VERSION_NUMBER < 0x10100000L +#include <time.h> +#endif #if defined(_WIN32) && !defined(_OPENSSL_Applink) && defined(HAVE_OPENSSL_APPLINK_C) #include <openssl/applink.c> @@ -103,8 +107,6 @@ static long ma_tls_version_options(const char *version) if (!version) return 0; - if (strstr(version, "TLSv1.0")) - protocol_options&= ~SSL_OP_NO_TLSv1; if (strstr(version, "TLSv1.1")) protocol_options&= ~SSL_OP_NO_TLSv1_1; if (strstr(version, "TLSv1.2")) @@ -420,7 +422,8 @@ void *ma_tls_init(MYSQL *mysql) SSL_CTX *ctx= NULL; long default_options= SSL_OP_ALL | SSL_OP_NO_SSLv2 | - SSL_OP_NO_SSLv3; + SSL_OP_NO_SSLv3 | + SSL_OP_NO_TLSv1; long options= 0; pthread_mutex_lock(&LOCK_openssl_config); @@ -463,6 +466,7 @@ my_bool ma_tls_connect(MARIADB_TLS *ctls) MYSQL *mysql; MARIADB_PVIO *pvio; int rc; + X509 *cert; #ifdef OPENSSL_USE_BIOMETHOD BIO_METHOD *bio_method= NULL; BIO *bio; @@ -505,13 +509,17 @@ my_bool ma_tls_connect(MARIADB_TLS *ctls) /* In case handshake failed or if a root certificate (ca) was specified, we need to check the result code of X509 verification. A detailed check of the peer certificate (hostname checking will follow later) */ - if (rc != 1 || mysql->options.extension->tls_verify_server_cert || + if (rc != 1 || !mysql->options.extension->tls_allow_invalid_server_cert || mysql->options.ssl_ca || mysql->options.ssl_capath) { long x509_err= SSL_get_verify_result(ssl); - if (x509_err != X509_V_OK) + if ((x509_err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT || + x509_err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) && rc == 1 && + !mysql->options.ssl_ca && !mysql->options.ssl_capath) + mysql->net.tls_self_signed_error= X509_verify_cert_error_string(x509_err); + else if (x509_err != X509_V_OK) { - my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, + my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, ER(CR_SSL_CONNECTION_ERROR), X509_verify_cert_error_string(x509_err)); /* restore blocking mode */ if (!blocking) @@ -525,6 +533,40 @@ my_bool ma_tls_connect(MARIADB_TLS *ctls) } pvio->ctls->ssl= ctls->ssl= (void *)ssl; + /* Store peer certificate information */ + if ((cert= SSL_get_peer_certificate(ssl))) + { + char fp[33]; +#if OPENSSL_VERSION_NUMBER >= 0x10101000L + const ASN1_TIME *not_before= X509_get0_notBefore(cert), + *not_after= X509_get0_notAfter(cert); + ASN1_TIME_to_tm(not_before, (struct tm *)&ctls->cert_info.not_before); + ASN1_TIME_to_tm(not_after, (struct tm *)&ctls->cert_info.not_after); +#else + const ASN1_TIME *not_before= X509_get_notBefore(cert), + *not_after= X509_get_notAfter(cert); + time_t now, from, to; + int pday, psec; + /* ANS1_TIME_diff returns days and seconds between now and the + specified ASN1_TIME */ + time(&now); + ASN1_TIME_diff(&pday, &psec, not_before, NULL); + from= now - (pday * 86400 + psec); + gmtime_r(&from, &ctls->cert_info.not_before); + ASN1_TIME_diff(&pday, &psec, NULL, not_after); + to= now + (pday * 86400 + psec); + gmtime_r(&to, &ctls->cert_info.not_after); +#endif + ctls->cert_info.subject= X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0); + ctls->cert_info.issuer= X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0); + ctls->cert_info.version= X509_get_version(cert) + 1; + + ma_tls_get_finger_print(ctls, MA_HASH_SHA256, fp, 33); + mysql_hex_string(ctls->cert_info.fingerprint, fp, 32); + + X509_free(cert); + } + return 0; } @@ -650,6 +692,9 @@ my_bool ma_tls_close(MARIADB_TLS *ctls) SSL_free(ssl); ctls->ssl= NULL; + OPENSSL_free(ctls->cert_info.issuer); + OPENSSL_free(ctls->cert_info.subject); + return rc; } @@ -729,33 +774,64 @@ const char *ma_tls_get_cipher(MARIADB_TLS *ctls) return SSL_get_cipher_name(ctls->ssl); } -unsigned int ma_tls_get_finger_print(MARIADB_TLS *ctls, char *fp, unsigned int len) +unsigned int ma_tls_get_finger_print(MARIADB_TLS *ctls, uint hash_type, char *fp, unsigned int len) { X509 *cert= NULL; MYSQL *mysql; unsigned int fp_len; + const EVP_MD *hash_alg; + unsigned int max_len= EVP_MAX_MD_SIZE; if (!ctls || !ctls->ssl) return 0; - mysql= SSL_get_app_data(ctls->ssl); + mysql = SSL_get_app_data(ctls->ssl); - if (!(cert= SSL_get_peer_certificate(ctls->ssl))) + switch (hash_type) { + case MA_HASH_SHA1: + hash_alg = EVP_sha1(); + max_len= 20; + break; + case MA_HASH_SHA224: + hash_alg = EVP_sha224(); + max_len= 28; + break; + case MA_HASH_SHA256: + hash_alg = EVP_sha256(); + max_len= 32; + break; + case MA_HASH_SHA384: + hash_alg = EVP_sha384(); + max_len= 48; + break; + case MA_HASH_SHA512: + hash_alg = EVP_sha512(); + break; + default: my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, - ER(CR_SSL_CONNECTION_ERROR), - "Unable to get server certificate"); - goto end; + ER(CR_SSL_CONNECTION_ERROR), + "Cannot detect hash algorithm for fingerprint verification"); + return 0; } - if (len < EVP_MAX_MD_SIZE) + if (len < max_len) { my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, ER(CR_SSL_CONNECTION_ERROR), "Finger print buffer too small"); + return 0; + } + + if (!(cert= SSL_get_peer_certificate(ctls->ssl))) + { + my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, + ER(CR_SSL_CONNECTION_ERROR), + "Unable to get server certificate"); goto end; } - if (!X509_digest(cert, EVP_sha1(), (unsigned char *)fp, &fp_len)) + + if (!X509_digest(cert, hash_alg, (unsigned char *)fp, &fp_len)) { my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, ER(CR_SSL_CONNECTION_ERROR), diff --git a/libmariadb/libmariadb/secure/openssl_crypt.c b/libmariadb/libmariadb/secure/openssl_crypt.c index faf755c9..fd3538ba 100644 --- a/libmariadb/libmariadb/secure/openssl_crypt.c +++ b/libmariadb/libmariadb/secure/openssl_crypt.c @@ -36,8 +36,6 @@ static const EVP_MD *ma_hash_get_algorithm(unsigned int alg) return EVP_sha384(); case MA_HASH_SHA512: return EVP_sha512(); - case MA_HASH_RIPEMD160: - return EVP_ripemd160(); default: return NULL; } diff --git a/libmariadb/libmariadb/secure/schannel.c b/libmariadb/libmariadb/secure/schannel.c index 8069af53..a6617d2e 100644 --- a/libmariadb/libmariadb/secure/schannel.c +++ b/libmariadb/libmariadb/secure/schannel.c @@ -20,6 +20,9 @@ #include "ma_schannel.h" #include "schannel_certs.h" #include <string.h> +#include <ma_crypt.h> +#include <wincrypt.h> +#include <bcrypt.h> extern my_bool ma_tls_initialized; char tls_library_version[] = "Schannel"; @@ -29,6 +32,8 @@ char tls_library_version[] = "Schannel"; #define PROT_TLS1_2 4 #define PROT_TLS1_3 8 +unsigned int ma_set_tls_x509_info(MARIADB_TLS *ctls); + static struct { DWORD cipher_id; @@ -418,15 +423,13 @@ my_bool ma_tls_connect(MARIADB_TLS *ctls) if (mysql->options.extension && mysql->options.extension->tls_version) { - if (strstr(mysql->options.extension->tls_version, "TLSv1.0")) - Cred.grbitEnabledProtocols|= SP_PROT_TLS1_0_CLIENT; if (strstr(mysql->options.extension->tls_version, "TLSv1.1")) Cred.grbitEnabledProtocols|= SP_PROT_TLS1_1_CLIENT; if (strstr(mysql->options.extension->tls_version, "TLSv1.2")) Cred.grbitEnabledProtocols|= SP_PROT_TLS1_2_CLIENT; } if (!Cred.grbitEnabledProtocols) - Cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_2_CLIENT; + Cred.grbitEnabledProtocols = SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_2_CLIENT; if (ma_tls_set_client_certs(ctls, &cert_context)) @@ -448,14 +451,15 @@ my_bool ma_tls_connect(MARIADB_TLS *ctls) goto end; verify_certs = mysql->options.ssl_ca || mysql->options.ssl_capath || - (mysql->options.extension->tls_verify_server_cert); + !mysql->options.extension->tls_allow_invalid_server_cert; if (verify_certs) { - if (!ma_schannel_verify_certs(ctls, mysql->options.extension->tls_verify_server_cert)) + if (!ma_schannel_verify_certs(ctls, !mysql->options.extension->tls_allow_invalid_server_cert)) goto end; } + ma_set_tls_x509_info(ctls); rc = 0; end: @@ -510,6 +514,8 @@ my_bool ma_tls_close(MARIADB_TLS *ctls) DeleteSecurityContext(&sctx->hCtxt); } LocalFree(sctx); + LocalFree(ctls->cert_info.issuer); + LocalFree(ctls->cert_info.subject); return 0; } /* }}} */ @@ -550,15 +556,87 @@ const char *ma_tls_get_cipher(MARIADB_TLS *ctls) return cipher_name(&CipherInfo); } -unsigned int ma_tls_get_finger_print(MARIADB_TLS *ctls, char *fp, unsigned int len) +unsigned char *ma_cert_blob_to_str(PCERT_NAME_BLOB cnblob) +{ + DWORD type= CERT_X500_NAME_STR; + DWORD size= CertNameToStrA(X509_ASN_ENCODING, cnblob, type, NULL, 0); + char *str= NULL; + + if (!size) + return NULL; + + str= (char *)LocalAlloc(LMEM_ZEROINIT,size); + CertNameToStrA(X509_ASN_ENCODING, cnblob, type, str, size); + return str; +} + +static void ma_systime_to_tm(SYSTEMTIME sys_tm, struct tm *tm) { + memset(tm, 0, sizeof(struct tm)); + tm->tm_year= sys_tm.wYear - 1900; + tm->tm_mon= sys_tm.wMonth - 1; + tm->tm_mday= sys_tm.wDay; + tm->tm_hour = sys_tm.wHour; + tm->tm_min = sys_tm.wMinute; +} + +unsigned int ma_set_tls_x509_info(MARIADB_TLS *ctls) +{ + PCCERT_CONTEXT pCertCtx= NULL; + SC_CTX *sctx= (SC_CTX *)ctls->ssl; + PCERT_INFO pci= NULL; + DWORD size´= 0; + SYSTEMTIME tm; + char fp[33]; + + if (QueryContextAttributes(&sctx->hCtxt, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (PVOID)&pCertCtx) != SEC_E_OK) + return 1; + + pci= pCertCtx->pCertInfo; + + ctls->cert_info.version= pci->dwVersion; + ctls->cert_info.subject = ma_cert_blob_to_str(&pci->Subject); + ctls->cert_info.issuer = ma_cert_blob_to_str(&pci->Issuer); + + FileTimeToSystemTime(&pci->NotBefore, &tm); + ma_systime_to_tm(tm, &ctls->cert_info.not_before); + FileTimeToSystemTime(&pci->NotAfter, &tm); + ma_systime_to_tm(tm, &ctls->cert_info.not_after); + + ma_tls_get_finger_print(ctls, MA_HASH_SHA256, fp, 33); + mysql_hex_string(ctls->cert_info.fingerprint, fp, 32); + + return 0; +} + + +unsigned int ma_tls_get_finger_print(MARIADB_TLS *ctls, uint hash_type, char *fp, unsigned int len) +{ + MA_HASH_CTX* hash_ctx; + SC_CTX *sctx= (SC_CTX *)ctls->ssl; PCCERT_CONTEXT pRemoteCertContext = NULL; + int rc= 0; + + if (hash_type == MA_HASH_SHA224) + { + MYSQL *mysql = ctls->pvio->mysql; + my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, + ER(CR_SSL_CONNECTION_ERROR), + "SHA224 hash for fingerprint verification is not supported in Schannel"); + return 0; + } + if (QueryContextAttributes(&sctx->hCtxt, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (PVOID)&pRemoteCertContext) != SEC_E_OK) return 0; - CertGetCertificateContextProperty(pRemoteCertContext, CERT_HASH_PROP_ID, fp, (DWORD *)&len); + + hash_ctx = ma_hash_new(hash_type); + ma_hash_input(hash_ctx, pRemoteCertContext->pbCertEncoded, pRemoteCertContext->cbCertEncoded); + ma_hash_result(hash_ctx, fp); + ma_hash_free(hash_ctx); + CertFreeCertificateContext(pRemoteCertContext); - return len; + return (uint)ma_hash_digest_size(hash_type); } void ma_tls_set_connection(MYSQL *mysql __attribute__((unused))) diff --git a/libmariadb/plugins/auth/CMakeLists.txt b/libmariadb/plugins/auth/CMakeLists.txt index 83e324b9..d04fc7f1 100644 --- a/libmariadb/plugins/auth/CMakeLists.txt +++ b/libmariadb/plugins/auth/CMakeLists.txt @@ -108,12 +108,12 @@ IF(NOT WIN32) ELSE() SET(GSSAPI_LIBS secur32) SET(GSSAPI_SOURCES ${AUTH_DIR}/auth_gssapi_client.c ${AUTH_DIR}/sspi_client.c ${AUTH_DIR}/sspi_errmsg.c) - SET(AUTH_GSSAPI_DEFAULT_CONFIG STATIC) + SET(AUTH_GSSAPI_DEFAULT_CONFIG DYNAMIC_AND_STATIC) ENDIF() IF(GSSAPI_SOURCES) REGISTER_PLUGIN(TARGET auth_gssapi_client TYPE MARIADB_CLIENT_PLUGIN_AUTH - CONFIGURATIONS DYNAMIC STATIC OFF + CONFIGURATIONS DYNAMIC STATIC OFF DYNAMIC_AND_STATIC DEFAULT ${AUTH_GSSAPI_DEFAULT_CONFIG} SOURCES ${GSSAPI_SOURCES} INCLUDES ${CC_SOURCE_DIR}/plugins/auth ${GSSAPI_INCS} @@ -131,6 +131,7 @@ REGISTER_PLUGIN(TARGET mysql_old_password TYPE MARIADB_CLIENT_PLUGIN_AUTH CONFIGURATIONS STATIC DYNAMIC OFF DEFAULT STATIC + DISABLED YES SOURCES ${AUTH_DIR}/old_password.c) # Cleartext diff --git a/libmariadb/plugins/auth/auth_gssapi_client.c b/libmariadb/plugins/auth/auth_gssapi_client.c index 6f6c6ceb..19cdf246 100644 --- a/libmariadb/plugins/auth/auth_gssapi_client.c +++ b/libmariadb/plugins/auth/auth_gssapi_client.c @@ -117,5 +117,6 @@ struct st_mysql_client_plugin_AUTHENTICATION _mysql_client_plugin_declaration_ = NULL, NULL, NULL, - gssapi_auth_client + gssapi_auth_client, + NULL }; diff --git a/libmariadb/plugins/auth/caching_sha2_pw.c b/libmariadb/plugins/auth/caching_sha2_pw.c index b442e477..14abb0c8 100644 --- a/libmariadb/plugins/auth/caching_sha2_pw.c +++ b/libmariadb/plugins/auth/caching_sha2_pw.c @@ -145,7 +145,8 @@ struct st_mysql_client_plugin_AUTHENTICATION _mysql_client_plugin_declaration_ = auth_caching_sha2_init, auth_caching_sha2_deinit, NULL, - auth_caching_sha2_client + auth_caching_sha2_client, + NULL }; #ifdef HAVE_WINCRYPT diff --git a/libmariadb/plugins/auth/dialog.c b/libmariadb/plugins/auth/dialog.c index 31d7b7d8..8513e9ac 100644 --- a/libmariadb/plugins/auth/dialog.c +++ b/libmariadb/plugins/auth/dialog.c @@ -58,7 +58,8 @@ struct st_mysql_client_plugin_AUTHENTICATION _mysql_client_plugin_declaration_ = auth_dialog_init, NULL, NULL, - auth_dialog_open + auth_dialog_open, + NULL }; diff --git a/libmariadb/plugins/auth/ed25519.c b/libmariadb/plugins/auth/ed25519.c index 38b896f8..ff2f39a5 100644 --- a/libmariadb/plugins/auth/ed25519.c +++ b/libmariadb/plugins/auth/ed25519.c @@ -64,6 +64,7 @@ static int auth_ed25519_init(char *unused1, size_t unused2, int unused3, va_list); +static int auth_ed25519_hash(MYSQL *, unsigned char *out, size_t *outlen); #ifndef PLUGIN_DYNAMIC @@ -77,21 +78,25 @@ struct st_mysql_client_plugin_AUTHENTICATION _mysql_client_plugin_declaration_ = "client_ed25519", "Sergei Golubchik, Georg Richter", "Ed25519 Authentication Plugin", - {0,1,0}, + {0,1,1}, "LGPL", NULL, auth_ed25519_init, auth_ed25519_deinit, NULL, - auth_ed25519_client + auth_ed25519_client, + auth_ed25519_hash }; static int auth_ed25519_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) { unsigned char *packet, - signature[CRYPTO_BYTES + NONCE_BYTES]; - int pkt_len; + signature[CRYPTO_BYTES + NONCE_BYTES], + pk[CRYPTO_PUBLICKEYBYTES]; + unsigned long long pkt_len; + size_t pwlen= strlen(mysql->passwd); + char *newpw; /* Step 1: Server sends nonce @@ -106,16 +111,36 @@ static int auth_ed25519_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) return CR_SERVER_HANDSHAKE_ERR; /* Sign nonce: the crypto_sign function is part of ref10 */ - ma_crypto_sign(signature, packet, NONCE_BYTES, (unsigned char*)mysql->passwd, strlen(mysql->passwd)); + ma_crypto_sign(signature, pk, packet, NONCE_BYTES, (unsigned char*)mysql->passwd, pwlen); /* send signature to server */ if (vio->write_packet(vio, signature, CRYPTO_BYTES)) return CR_ERROR; + /* save pk for the future auth_ed25519_hash() call */ + if ((newpw= realloc(mysql->passwd, pwlen + 1 + sizeof(pk)))) + { + memcpy(newpw + pwlen + 1, pk, sizeof(pk)); + mysql->passwd= newpw; + } + return CR_OK; } /* }}} */ +/* {{{ static int auth_ed25519_hash */ +static int auth_ed25519_hash(MYSQL *mysql, unsigned char *out, size_t *outlen) +{ + if (*outlen < CRYPTO_PUBLICKEYBYTES) + return 1; + *outlen= CRYPTO_PUBLICKEYBYTES; + + /* use the cached value */ + memcpy(out, mysql->passwd + strlen(mysql->passwd) + 1, CRYPTO_PUBLICKEYBYTES); + return 0; +} +/* }}} */ + /* {{{ static int auth_ed25519_init */ static int auth_ed25519_init(char *unused1 __attribute__((unused)), size_t unused2 __attribute__((unused)), diff --git a/libmariadb/plugins/auth/mariadb_cleartext.c b/libmariadb/plugins/auth/mariadb_cleartext.c index b63c1d3b..92e56547 100644 --- a/libmariadb/plugins/auth/mariadb_cleartext.c +++ b/libmariadb/plugins/auth/mariadb_cleartext.c @@ -70,7 +70,8 @@ struct st_mysql_client_plugin_AUTHENTICATION _mysql_client_plugin_declaration_ = NULL, NULL, NULL, - clear_password_auth_client + clear_password_auth_client, + NULL }; diff --git a/libmariadb/plugins/auth/my_auth.c b/libmariadb/plugins/auth/my_auth.c index 72773079..faea968c 100644 --- a/libmariadb/plugins/auth/my_auth.c +++ b/libmariadb/plugins/auth/my_auth.c @@ -3,16 +3,29 @@ #include <errmsg.h> #include <string.h> #include <ma_common.h> +#include <ma_crypt.h> #include <mysql/client_plugin.h> typedef struct st_mysql_client_plugin_AUTHENTICATION auth_plugin_t; static int client_mpvio_write_packet(struct st_plugin_vio*, const uchar*, size_t); static int native_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql); +static int native_password_hash(MYSQL *mysql, unsigned char *out, size_t *outlen); static int dummy_fallback_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql __attribute__((unused))); extern void read_user_name(char *name); extern char *ma_send_connect_attr(MYSQL *mysql, unsigned char *buffer); extern int ma_read_ok_packet(MYSQL *mysql, uchar *pos, ulong length); extern unsigned char *mysql_net_store_length(unsigned char *packet, ulonglong length); +extern const char *disabled_plugins; + +#define hashing(p) (p->interface_version >= 0x0101 && p->hash_password_bin) + +static int set_error_from_tls_self_signed_error(MYSQL *mysql) +{ + my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, + ER(CR_SSL_CONNECTION_ERROR), mysql->net.tls_self_signed_error); + reset_tls_self_signed_error(mysql); + return 1; +} typedef struct { int (*read_packet)(struct st_plugin_vio *vio, uchar **buf); @@ -44,13 +57,14 @@ auth_plugin_t mysql_native_password_client_plugin= native_password_plugin_name, "R.J.Silk, Sergei Golubchik", "Native MySQL authentication", - {1, 0, 0}, + {1, 0, 1}, "LGPL", NULL, NULL, NULL, NULL, - native_password_auth_client + native_password_auth_client, + native_password_hash }; @@ -97,6 +111,22 @@ static int native_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) return CR_OK; } +static int native_password_hash(MYSQL *mysql, unsigned char *out, size_t *out_length) +{ + unsigned char digest[MA_SHA1_HASH_SIZE]; + + if (*out_length < MA_SHA1_HASH_SIZE) + return 1; + *out_length= MA_SHA1_HASH_SIZE; + + /* would it be better to reuse instead of recalculating here? see ed25519 */ + ma_hash(MA_HASH_SHA1, (unsigned char*)mysql->passwd, strlen(mysql->passwd), + digest); + ma_hash(MA_HASH_SHA1, digest, sizeof(digest), out); + + return 0; +} + auth_plugin_t dummy_fallback_client_plugin= { MYSQL_CLIENT_AUTHENTICATION_PLUGIN, @@ -110,7 +140,8 @@ auth_plugin_t dummy_fallback_client_plugin= NULL, NULL, NULL, - dummy_fallback_auth_client + dummy_fallback_auth_client, + NULL }; @@ -223,7 +254,7 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio, if (mysql->options.ssl_key || mysql->options.ssl_cert || mysql->options.ssl_ca || mysql->options.ssl_capath || mysql->options.ssl_cipher || mysql->options.use_ssl || - mysql->options.extension->tls_verify_server_cert) + !mysql->options.extension->tls_allow_invalid_server_cert) mysql->options.use_ssl= 1; if (mysql->options.use_ssl) mysql->client_flag|= CLIENT_SSL; @@ -243,15 +274,16 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio, mysql->net.pvio->type == PVIO_TYPE_SHAREDMEM)) { mysql->server_capabilities &= ~(CLIENT_SSL); + mysql->options.extension->tls_allow_invalid_server_cert= 1; } /* if server doesn't support SSL and verification of server certificate was set to mandatory, we need to return an error */ if (mysql->options.use_ssl && !(mysql->server_capabilities & CLIENT_SSL)) { - if (mysql->options.extension->tls_verify_server_cert || - (mysql->options.extension && (mysql->options.extension->tls_fp || - mysql->options.extension->tls_fp_list))) + if (!mysql->options.extension->tls_allow_invalid_server_cert || + mysql->options.extension->tls_fp || + mysql->options.extension->tls_fp_list) { my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, ER(CR_SSL_CONNECTION_ERROR), @@ -307,9 +339,11 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio, if (!(mysql->server_capabilities & CLIENT_MYSQL)) { uint server_extended_cap= mysql->extension->mariadb_server_capabilities; - uint client_extended_cap= (uint)(MARIADB_CLIENT_SUPPORTED_FLAGS >> 32); + ulonglong client_extended_flag = CLIENT_DEFAULT_EXTENDED_FLAGS; + if (mysql->options.extension && mysql->options.extension->bulk_unit_results) + client_extended_flag|= MARIADB_CLIENT_BULK_UNIT_RESULTS; mysql->extension->mariadb_client_flag= - server_extended_cap & client_extended_cap; + server_extended_cap & (long)(client_extended_flag >> 32); int4store(buff + 28, mysql->extension->mariadb_client_flag); } end= buff+32; @@ -350,6 +384,13 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio, } if (ma_pvio_start_ssl(mysql->net.pvio)) goto error; + if (mysql->net.tls_self_signed_error && + (!mysql->passwd || !mysql->passwd[0] || !hashing(mpvio->plugin))) + { + /* cannot use auth to validate the cert */ + set_error_from_tls_self_signed_error(mysql); + goto error; + } } #endif /* HAVE_TLS */ @@ -658,13 +699,13 @@ int run_plugin_auth(MYSQL *mysql, char *data, uint data_len, retry: mpvio.plugin= auth_plugin; - if (auth_plugin_name && - mysql->options.extension && - mysql->options.extension->restricted_auth) + if (auth_plugin_name) { - if (!strstr(mysql->options.extension->restricted_auth, auth_plugin_name)) + if ((mysql->options.extension && mysql->options.extension->restricted_auth) + ? !strstr(mysql->options.extension->restricted_auth, auth_plugin_name) + : strstr(disabled_plugins, auth_plugin_name) != NULL) { - my_set_error(mysql, CR_PLUGIN_NOT_ALLOWED, SQLSTATE_UNKNOWN, 0, data_plugin); + my_set_error(mysql, CR_PLUGIN_NOT_ALLOWED, SQLSTATE_UNKNOWN, 0, auth_plugin_name); return 1; } } @@ -727,15 +768,62 @@ retry: auth_plugin_name, MYSQL_CLIENT_AUTHENTICATION_PLUGIN))) auth_plugin= &dummy_fallback_client_plugin; + /* can we use this plugin with this tls server cert ? */ + if (mysql->net.tls_self_signed_error && !hashing(auth_plugin)) + return set_error_from_tls_self_signed_error(mysql); goto retry; - } /* net->read_pos[0] should always be 0 here if the server implements the protocol correctly */ - if (mysql->net.read_pos[0] == 0) - return ma_read_ok_packet(mysql, mysql->net.read_pos + 1, pkt_length); - return 1; + if (mysql->net.read_pos[0] != 0) + return 1; + if (ma_read_ok_packet(mysql, mysql->net.read_pos + 1, pkt_length)) + return -1; + + if (!mysql->net.tls_self_signed_error) + return 0; + + assert(mysql->options.use_ssl); + assert(!mysql->options.extension->tls_allow_invalid_server_cert); + assert(!mysql->options.ssl_ca); + assert(!mysql->options.ssl_capath); + assert(!mysql->options.extension->tls_fp); + assert(!mysql->options.extension->tls_fp_list); + assert(hashing(auth_plugin)); + assert(mysql->passwd[0]); + if (mysql->info && mysql->info[0] == '\1') + { + MA_HASH_CTX *ctx = NULL; + unsigned char buf[1024], digest[MA_SHA256_HASH_SIZE]; + char fp[128], hexdigest[sizeof(digest)*2+1], *hexsig= mysql->info + 1; + size_t buflen= sizeof(buf) - 1, fplen; + + mysql->info= NULL; /* no need to confuse the client with binary info */ + + if (!(fplen= ma_tls_get_finger_print(mysql->net.pvio->ctls, MA_HASH_SHA256, + fp, sizeof(fp)))) + return 1; /* error is already set */ + + if (auth_plugin->hash_password_bin(mysql, buf, &buflen) || + !(ctx= ma_hash_new(MA_HASH_SHA256))) + { + SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); + return 1; + } + + ma_hash_input(ctx, (unsigned char*)buf, buflen); + ma_hash_input(ctx, (unsigned char*)mysql->scramble_buff, SCRAMBLE_LENGTH); + ma_hash_input(ctx, (unsigned char*)fp, fplen); + ma_hash_result(ctx, digest); + ma_hash_free(ctx); + + mysql_hex_string(hexdigest, (char*)digest, sizeof(digest)); + if (strcmp(hexdigest, hexsig) == 0) + return 0; /* phew. self-signed certificate is validated! */ + } + + return set_error_from_tls_self_signed_error(mysql); } diff --git a/libmariadb/plugins/auth/old_password.c b/libmariadb/plugins/auth/old_password.c index 07756e92..3f7d533c 100644 --- a/libmariadb/plugins/auth/old_password.c +++ b/libmariadb/plugins/auth/old_password.c @@ -63,7 +63,8 @@ struct st_mysql_client_plugin_AUTHENTICATION _mysql_client_plugin_declaration_ = NULL, NULL, NULL, - auth_old_password + auth_old_password, + NULL }; /** diff --git a/libmariadb/plugins/auth/ref10/crypto_sign.h b/libmariadb/plugins/auth/ref10/crypto_sign.h index 5f9b3437..3c676885 100644 --- a/libmariadb/plugins/auth/ref10/crypto_sign.h +++ b/libmariadb/plugins/auth/ref10/crypto_sign.h @@ -3,7 +3,7 @@ int crypto_sign_keypair( unsigned char *pw, unsigned long long pwlen ); int ma_crypto_sign( - unsigned char *sm, + unsigned char *sm, unsigned char *pk, const unsigned char *m, unsigned long long mlen, const unsigned char *pw, unsigned long long pwlen ); diff --git a/libmariadb/plugins/auth/ref10/sign.c b/libmariadb/plugins/auth/ref10/sign.c index b4153201..421a0aed 100644 --- a/libmariadb/plugins/auth/ref10/sign.c +++ b/libmariadb/plugins/auth/ref10/sign.c @@ -5,7 +5,7 @@ #include "sc.h" int ma_crypto_sign( - unsigned char *sm, + unsigned char *sm, unsigned char *pk, const unsigned char *m,unsigned long long mlen, const unsigned char *pw,unsigned long long pwlen ) @@ -26,6 +26,7 @@ int ma_crypto_sign( ge_scalarmult_base(&A,az); ge_p3_tobytes(sm + 32,&A); + memmove(pk, sm + 32, 32); sc_reduce(nonce); ge_scalarmult_base(&R,nonce); diff --git a/libmariadb/plugins/auth/sha256_pw.c b/libmariadb/plugins/auth/sha256_pw.c index 79febf1a..66fb1071 100644 --- a/libmariadb/plugins/auth/sha256_pw.c +++ b/libmariadb/plugins/auth/sha256_pw.c @@ -76,7 +76,8 @@ struct st_mysql_client_plugin_AUTHENTICATION _mysql_client_plugin_declaration_ = auth_sha256_init, NULL, NULL, - auth_sha256_client + auth_sha256_client, + NULL }; #ifdef HAVE_WINCRYPT diff --git a/libmariadb/travis.sh b/libmariadb/travis.sh index c316dec2..d918b010 100755 --- a/libmariadb/travis.sh +++ b/libmariadb/travis.sh @@ -62,9 +62,10 @@ else mkdir bld cd bld - cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCERT_PATH=${SSLCERT} - if [ "$TRAVIS_OS_NAME" = "windows" ] ; then + export WIX="c:/Program Files (x86)/WiX Toolset v3.14" + cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCERT_PATH=${SSLCERT} -DDEFAULT_SSL_VERIFY_SERVER_CERT=OFF -DWITH_MSI=ON -DWITH_CURL=ON + echo "build from windows" set MARIADB_CC_TEST=1 set MYSQL_TEST_DB=testc @@ -77,6 +78,7 @@ else cmake --build . --config RelWithDebInfo else echo "build from linux" + cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCERT_PATH=${SSLCERT} -DDEFAULT_SSL_VERIFY_SERVER_CERT=OFF -DWITH_CURL=ON export MARIADB_CC_TEST=1 export MYSQL_TEST_USER=$TEST_DB_USER export MYSQL_TEST_HOST=$TEST_DB_HOST diff --git a/libmariadb/unittest/libmariadb/CMakeLists.txt b/libmariadb/unittest/libmariadb/CMakeLists.txt index 876e5cfc..d5b93716 100644 --- a/libmariadb/unittest/libmariadb/CMakeLists.txt +++ b/libmariadb/unittest/libmariadb/CMakeLists.txt @@ -31,7 +31,9 @@ IF(WITH_DYNCOL) SET(API_TESTS ${API_TESTS} "dyncol") ENDIF() -SET(API_TESTS ${API_TESTS} "async") +IF(NOT WIN32) + SET(API_TESTS ${API_TESTS} "async") +ENDIF() #exclude following tests from ctests, since we need to run them manually with different credentials SET(MANUAL_TESTS "t_conc173" "rpl_api") diff --git a/libmariadb/unittest/libmariadb/bulk1.c b/libmariadb/unittest/libmariadb/bulk1.c index 62267cd7..56ae20d8 100644 --- a/libmariadb/unittest/libmariadb/bulk1.c +++ b/libmariadb/unittest/libmariadb/bulk1.c @@ -21,6 +21,12 @@ static my_bool bulk_enabled= 0; +#define SERVER_SUPPORT_BULK_UNIT_RESULTS(mysql)\ + (!(mysql->server_capabilities & CLIENT_MYSQL) &&\ + (mysql->extension->mariadb_server_capabilities & \ + (MARIADB_CLIENT_BULK_UNIT_RESULTS >> 32))) + + char *rand_str(size_t length) { const char charset[] = "0123456789" "abcdefghijklmnopqrstuvwxyz" @@ -57,11 +63,14 @@ static int bulk1(MYSQL *mysql) MYSQL_RES *res; MYSQL_ROW row; unsigned int intval; + my_bool bool_val; if (!bulk_enabled) return SKIP; rc= mysql_select_db(mysql, "testc"); + mysql_get_option(mysql, MARIADB_OPT_BULK_UNIT_RESULTS, &bool_val); + FAIL_IF(bool_val, "bool_val == true"); rc= mysql_query(mysql, "DROP TABLE IF EXISTS bulk1"); check_mysql_rc(rc, mysql); @@ -1067,6 +1076,344 @@ static int test_mdev16593(MYSQL *mysql) return OK; } +static int bulk_with_unit_result_insert(MYSQL *my) +{ + my_bool unique_result= 1; + my_bool bool_val; + MYSQL *mysql; + MYSQL_STMT *stmt; + unsigned int array_size= TEST_ARRAY_SIZE; + int rc, rowcount= 0; + unsigned int i; + char **buffer; + unsigned long *lengths; + MYSQL_BIND bind[1]; + MYSQL_RES *res; + MYSQL_ROW row; + MYSQL_BIND bind_out[2]; + int id, affected_rows = 0; + int expectedId = 1; + unsigned int intval; + + SKIP_MAXSCALE; + if (!SERVER_SUPPORT_BULK_UNIT_RESULTS(my)) + { + diag("Server doesn't support bulk unit results"); + return SKIP; + } + + mysql= mysql_init(NULL); + stmt= mysql_stmt_init(mysql); + mysql_options(mysql, MARIADB_OPT_BULK_UNIT_RESULTS, &unique_result); + FAIL_IF(!my_test_connect(mysql, hostname, username, password, schema, + port, socketname, 0), mysql_error(mysql)); + mysql_get_option(mysql, MARIADB_OPT_BULK_UNIT_RESULTS, &bool_val); + FAIL_UNLESS(bool_val, "bool_val != true"); + + if (!bulk_enabled) + return SKIP; + + rc= mysql_select_db(mysql, "testc"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS bulk_with_unit_result_insert"); + check_mysql_rc(rc, mysql); + + rc= mysql_query(mysql, "CREATE TABLE bulk_with_unit_result_insert (a int NOT NULL AUTO_INCREMENT, b VARCHAR(255), PRIMARY KEY (a)) engine=MyISAM"); + check_mysql_rc(rc, mysql); + + rc= mysql_stmt_prepare(stmt, SL("INSERT INTO bulk_with_unit_result_insert(b) VALUES (?)")); + check_stmt_rc(rc, stmt); + + /* allocate memory */ + buffer= calloc(TEST_ARRAY_SIZE, sizeof(char *)); + lengths= (unsigned long *)calloc(sizeof(long), TEST_ARRAY_SIZE); + + for (i=0; i < TEST_ARRAY_SIZE; i++) + { + buffer[i]= rand_str(254); + lengths[i]= -1; + } + + memset(bind, 0, sizeof(MYSQL_BIND) * 1); + memset(bind_out, '\0', sizeof(bind_out)); + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= (void *)buffer; + bind[0].length= (unsigned long *)lengths; + + bind_out[0].buffer_type= MYSQL_TYPE_LONG; + bind_out[0].buffer= (void*) &id; + bind_out[1].buffer_type= MYSQL_TYPE_LONG; + bind_out[1].buffer= (void*) &affected_rows; + + rc= mysql_stmt_attr_set(stmt, STMT_ATTR_ARRAY_SIZE, &array_size); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_bind_param(stmt, bind); + check_stmt_rc(rc, stmt); + + for (i=0; i < 100; i++) + { + rc= mysql_stmt_execute(stmt); + check_stmt_rc(rc, stmt); + rc= mysql_stmt_bind_result(stmt, bind_out); + check_stmt_rc(rc, stmt); + rowcount= 0; + while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA) + { + rowcount++; + // diag("id:%llu expected %llu", id, expectedId); + FAIL_UNLESS(id == expectedId, "id != expectedId"); + expectedId++; + // diag("affected_rows:%llu", affected_rows); + FAIL_UNLESS(affected_rows == 1, "affected_rows != 1"); + } + // test can be improved depending on auto_increment_increment/auto_increment_offset... + FAIL_IF(rowcount != TEST_ARRAY_SIZE, "rowcount != TEST_ARRAY_SIZE"); + } + + for (i=0; i < array_size; i++) + free(buffer[i]); + + free(buffer); + free(lengths); + + rc= mysql_stmt_close(stmt); + check_mysql_rc(rc, mysql); + + rc= mysql_query(mysql, "SELECT COUNT(*) FROM bulk_with_unit_result_insert"); + check_mysql_rc(rc, mysql); + + res= mysql_store_result(mysql); + row= mysql_fetch_row(res); + intval= atoi(row[0]); + mysql_free_result(res); + FAIL_IF(intval != array_size * 100, "Expected 102400 rows"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS bulk_with_unit_result_insert"); + check_mysql_rc(rc, mysql); + mysql_close(mysql); + check_mysql_rc(rc, my); + return OK; +} + +static int bulk_with_unit_result_delete(MYSQL *my) +{ + my_bool unique_result= 1; + unsigned int array_size= 5; + int rc, rowcount= 0; + unsigned int i, j; + MYSQL_BIND bind[1]; + MYSQL_RES *res; + MYSQL_ROW row; + MYSQL_BIND bind_out[2]; + unsigned int *vals; + int id, affected_rows = 0; + unsigned int intval; + MYSQL *mysql; + MYSQL_STMT *stmt; + + SKIP_MAXSCALE; + if (!SERVER_SUPPORT_BULK_UNIT_RESULTS(my)) + { + diag("Server doesn't support bulk unit results"); + return SKIP; + } + + mysql= mysql_init(NULL); + stmt= mysql_stmt_init(mysql); + mysql_options(mysql, MARIADB_OPT_BULK_UNIT_RESULTS, &unique_result); + FAIL_IF(!my_test_connect(mysql, hostname, username, password, schema, + port, socketname, 0), mysql_error(mysql)); + + if (!bulk_enabled) + return SKIP; + + rc= mysql_select_db(mysql, "testc"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS bulk_with_unit_result_delete"); + check_mysql_rc(rc, mysql); + + rc= mysql_query(mysql, "CREATE TABLE bulk_with_unit_result_delete (a int NOT NULL AUTO_INCREMENT, b VARCHAR(255), PRIMARY KEY (a))"); + check_mysql_rc(rc, mysql); + + rc= mysql_query(mysql, "INSERT INTO bulk_with_unit_result_delete(b) with recursive cte (seq) as (select 1 union all select seq+1 from cte where seq < 100) select concat(seq, 'test') from cte"); + check_mysql_rc(rc, mysql); + + rc= mysql_stmt_prepare(stmt, SL("DELETE FROM bulk_with_unit_result_delete WHERE a = ?")); + check_stmt_rc(rc, stmt); + + memset(bind_out, '\0', sizeof(bind_out)); + bind_out[0].buffer_type= MYSQL_TYPE_LONG; + bind_out[0].buffer= (void*) &id; + bind_out[1].buffer_type= MYSQL_TYPE_LONG; + bind_out[1].buffer= (void*) &affected_rows; + + rc= mysql_stmt_attr_set(stmt, STMT_ATTR_ARRAY_SIZE, &array_size); + check_stmt_rc(rc, stmt); + + vals= (unsigned int *)calloc(sizeof(int), 5); + memset(bind, 0, sizeof(MYSQL_BIND) * 1); + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= vals; + + for (i=0; i < 10; i++) + { + for (j=0; j < 5; j++) + vals[j]= 1 + j * 2 + i * 10; + + rc= mysql_stmt_bind_param(stmt, bind); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_execute(stmt); + check_stmt_rc(rc, stmt); + rc= mysql_stmt_bind_result(stmt, bind_out); + check_stmt_rc(rc, stmt); + rowcount= 0; + while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA) + { + rowcount++; + FAIL_UNLESS(id == 0, "id != 0"); + FAIL_UNLESS(affected_rows == 1, "affected_rows != 1"); + } + // test can be improved depending on auto_increment_increment/auto_increment_offset... + FAIL_UNLESS(rowcount == 5, "rowcount != 5"); + } + + rc= mysql_stmt_close(stmt); + check_mysql_rc(rc, mysql); + free(vals); + rc= mysql_query(mysql, "SELECT a FROM bulk_with_unit_result_delete"); + check_mysql_rc(rc, mysql); + + res= mysql_store_result(mysql); + rowcount= 0; + for (i=1; i < 51; i++) + { + row=mysql_fetch_row(res); + intval = atoi(row[0]); + FAIL_UNLESS(intval == i * 2, "intval != i * 2"); + } + mysql_free_result(res); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS bulk_with_unit_result_delete"); + check_mysql_rc(rc, mysql); + mysql_close(mysql); + check_mysql_rc(rc, my); + return OK; +} + + +static int bulk_with_unit_result_update(MYSQL *my) +{ + my_bool unique_result= 1; + unsigned int array_size= 5; + int rc, rowcount= 0; + unsigned int i, j; + MYSQL_BIND bind[1]; + MYSQL_RES *res; + MYSQL_ROW row; + MYSQL_BIND bind_out[2]; + unsigned int *vals; + int id, affected_rows = 0; + char str[50]; + MYSQL *mysql; + MYSQL_STMT *stmt; + + SKIP_MAXSCALE; + if (!SERVER_SUPPORT_BULK_UNIT_RESULTS(my)) + { + diag("Server doesn't support bulk unit results"); + return SKIP; + } + + mysql= mysql_init(NULL); + stmt= mysql_stmt_init(mysql); + + mysql_options(mysql, MARIADB_OPT_BULK_UNIT_RESULTS, &unique_result); + FAIL_IF(!my_test_connect(mysql, hostname, username, password, schema, + port, socketname, 0), mysql_error(mysql)); + + if (!bulk_enabled) + return SKIP; + + rc= mysql_select_db(mysql, "testc"); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS bulk_with_unit_result_update"); + check_mysql_rc(rc, mysql); + + rc= mysql_query(mysql, "CREATE TABLE bulk_with_unit_result_update (a int NOT NULL AUTO_INCREMENT, b VARCHAR(255), PRIMARY KEY (a))"); + check_mysql_rc(rc, mysql); + + rc= mysql_query(mysql, "INSERT INTO bulk_with_unit_result_update(b) with recursive cte (seq) as (select 1 union all select seq+1 from cte where seq < 100) select concat(seq, 'test') from cte"); + check_mysql_rc(rc, mysql); + + rc= mysql_stmt_prepare(stmt, SL("UPDATE bulk_with_unit_result_update SET b=CONCAT(b,'added') WHERE a = ?")); + check_stmt_rc(rc, stmt); + + memset(bind_out, '\0', sizeof(bind_out)); + bind_out[0].buffer_type= MYSQL_TYPE_LONG; + bind_out[0].buffer= (void*) &id; + bind_out[1].buffer_type= MYSQL_TYPE_LONG; + bind_out[1].buffer= (void*) &affected_rows; + + rc= mysql_stmt_attr_set(stmt, STMT_ATTR_ARRAY_SIZE, &array_size); + check_stmt_rc(rc, stmt); + + vals= (unsigned int *)calloc(sizeof(int), 5); + memset(bind, 0, sizeof(MYSQL_BIND) * 1); + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= vals; + + for (i=0; i < 10; i++) + { + for (j=0; j < 5; j++) + vals[j]= 1 + j * 2 + i * 10; + + rc= mysql_stmt_bind_param(stmt, bind); + check_stmt_rc(rc, stmt); + + rc= mysql_stmt_execute(stmt); + check_stmt_rc(rc, stmt); + rc= mysql_stmt_bind_result(stmt, bind_out); + check_stmt_rc(rc, stmt); + rowcount= 0; + while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA) + { + rowcount++; + FAIL_UNLESS(id == 0, "id != 0"); + FAIL_UNLESS(affected_rows == 1, "affected_rows != 1"); + } + // test can be improved depending on auto_increment_increment/auto_increment_offset... + FAIL_UNLESS(rowcount == 5, "rowcount != 5"); + } + + rc= mysql_stmt_close(stmt); + check_mysql_rc(rc, mysql); + free(vals); + rc= mysql_query(mysql, "SELECT b FROM bulk_with_unit_result_update"); + check_mysql_rc(rc, mysql); + + res= mysql_store_result(mysql); + rowcount= 0; + for (i=1; i < 101; i++) + { + row=mysql_fetch_row(res); + if (i % 2 == 0) { + sprintf(str, "%dtest", i); + } else { + sprintf(str, "%dtestadded", i); + } + FAIL_IF(strcmp(row[0], str) != 0, "strcmp(row[0], str) != 0"); + } + mysql_free_result(res); + + rc= mysql_query(mysql, "DROP TABLE IF EXISTS bulk_with_unit_result_update"); + check_mysql_rc(rc, mysql); + mysql_close(mysql); + check_mysql_rc(rc, my); + return OK; +} + struct my_tests_st my_tests[] = { {"check_bulk", check_bulk, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_mdev16593", test_mdev16593, TEST_CONNECTION_NEW, 0, NULL, NULL}, @@ -1083,6 +1430,9 @@ struct my_tests_st my_tests[] = { {"bulk4", bulk4, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"bulk_null", bulk_null, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"bulk_skip_row", bulk_skip_row, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, + {"bulk_with_unit_result_insert", bulk_with_unit_result_insert, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, + {"bulk_with_unit_result_delete", bulk_with_unit_result_delete, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, + {"bulk_with_unit_result_update", bulk_with_unit_result_update, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {NULL, NULL, 0, 0, NULL, NULL} }; diff --git a/libmariadb/unittest/libmariadb/charset.c b/libmariadb/unittest/libmariadb/charset.c index 4d17731f..35ae716f 100644 --- a/libmariadb/unittest/libmariadb/charset.c +++ b/libmariadb/unittest/libmariadb/charset.c @@ -794,6 +794,10 @@ static int test_conc223(MYSQL *mysql) MYSQL_ROW row; int found= 0; int mdev27266= 0; + int unsupported[]= { + 579, /* utf8mb3_general1400_as_ci added in 11.5 */ + 611, /* utf8mb4_general1400_as_ci added in 11.5 */ + 0}; SKIP_MYSQL(mysql); @@ -839,8 +843,11 @@ static int test_conc223(MYSQL *mysql) id= atoi(row[0]); if (!mariadb_get_charset_by_nr(id)) { - diag("%04d %s %s", id, row[1], row[2]); + int j=0; found++; + for (j=0; unsupported[j]; j++) + if (unsupported[j] == id) + found--; } } } diff --git a/libmariadb/unittest/libmariadb/connection.c b/libmariadb/unittest/libmariadb/connection.c index a10e01bd..bd4e0e0a 100644 --- a/libmariadb/unittest/libmariadb/connection.c +++ b/libmariadb/unittest/libmariadb/connection.c @@ -686,6 +686,7 @@ int test_connection_timeout2(MYSQL *unused __attribute__((unused))) unsigned int timeout= 5; time_t start, elapsed; MYSQL *mysql; + my_bool no= 0; SKIP_SKYSQL; SKIP_MAXSCALE; @@ -694,6 +695,7 @@ int test_connection_timeout2(MYSQL *unused __attribute__((unused))) mysql= mysql_init(NULL); mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, (unsigned int *)&timeout); mysql_options(mysql, MYSQL_INIT_COMMAND, "set @a:=SLEEP(7)"); + mysql_options(mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, &no); start= time(NULL); if (my_test_connect(mysql, hostname, username, password, schema, port, socketname, CLIENT_REMEMBER_OPTIONS)) { @@ -1378,7 +1380,6 @@ static int test_conc276(MYSQL *unused __attribute__((unused))) return FAIL; } diag("Cipher in use: %s", mysql_get_ssl_cipher(mysql)); - rc= mariadb_reconnect(mysql); check_mysql_rc(rc, mysql); @@ -2307,6 +2308,49 @@ static int test_conc632(MYSQL *my __attribute__((unused))) return OK; } +static int test_x509(MYSQL *my __attribute__((unused))) +{ + MYSQL *mysql1, *mysql2; + my_bool val= 1; + my_bool verify= 0; + char fp[65]; + MARIADB_X509_INFO *info; + + SKIP_MAXSCALE; + + mysql1= mysql_init(NULL); + mysql2= mysql_init(NULL); + + mysql_options(mysql1, MYSQL_OPT_SSL_ENFORCE, &val); + mysql_options(mysql2, MYSQL_OPT_SSL_ENFORCE, &val); + + mysql_options(mysql1, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, &verify); + if (!(my_test_connect(mysql1, hostname, username, + password, schema, port, + socketname, 0))) + { + diag("connection failed"); + return FAIL; + } + mariadb_get_infov(mysql1, MARIADB_TLS_PEER_CERT_INFO, &info); + memset(fp, 0, 65); + diag("fingerprint: %s", info->fingerprint); + mysql_options(mysql2, MARIADB_OPT_TLS_PEER_FP, info->fingerprint); + if (!(my_test_connect(mysql2, hostname, username, + password, schema, port, + socketname, 0))) + { + diag("connection failed"); + return FAIL; + } + mariadb_get_infov(mysql2, MARIADB_TLS_PEER_CERT_INFO, &info); + FAIL_IF(info->verify_mode != MARIADB_VERIFY_FINGERPRINT, "Fingerprint verification expected"); + + mysql_close(mysql1); + mysql_close(mysql2); + return OK; +} + static int test_conc505(MYSQL *my __attribute__((unused))) { MYSQL *mysql= mysql_init(NULL); @@ -2333,6 +2377,7 @@ static int test_conc505(MYSQL *my __attribute__((unused))) } struct my_tests_st my_tests[] = { + {"test_x509", test_x509, TEST_CONNECTION_NONE, 0, NULL, NULL}, {"test_conc505", test_conc505, TEST_CONNECTION_NONE, 0, NULL, NULL}, {"test_conc632", test_conc632, TEST_CONNECTION_NONE, 0, NULL, NULL}, {"test_status_callback", test_status_callback, TEST_CONNECTION_NONE, 0, NULL, NULL}, diff --git a/libmariadb/unittest/libmariadb/misc.c b/libmariadb/unittest/libmariadb/misc.c index f67d1366..47f2f523 100644 --- a/libmariadb/unittest/libmariadb/misc.c +++ b/libmariadb/unittest/libmariadb/misc.c @@ -1628,7 +1628,37 @@ static int test_ext_field_attr(MYSQL *mysql) return OK; } +static int test_disable_tls1_0(MYSQL *my __attribute__((unused))) +{ + MYSQL *mysql= mysql_init(NULL); + const char *disabled_version= "TLSv1.0"; + MYSQL_RES *result; + MYSQL_ROW row; + int rc; + + mysql_ssl_set(mysql, NULL, NULL, NULL, NULL, NULL); + mysql_optionsv(mysql, MARIADB_OPT_TLS_VERSION, disabled_version); + + FAIL_IF(!mysql_real_connect(mysql, hostname, username, password, schema, + port, socketname, 0), mysql_error(mysql)); + + rc= mysql_query(mysql, "SHOW STATUS LIKE 'ssl_version'"); + check_mysql_rc(rc, mysql); + + result = mysql_store_result(mysql); + row= mysql_fetch_row(result); + + FAIL_IF(!strcmp(row[1], "TLSv1.0"), "TLS 1.0 should be disabled!"); + + mysql_free_result(result); + + mysql_close(mysql); + return OK; +} + + struct my_tests_st my_tests[] = { + {"test_disable_tls1_0", test_disable_tls1_0, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_ext_field_attr", test_ext_field_attr, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc533", test_conc533, TEST_CONNECTION_NEW, 0, NULL, NULL}, {"test_conc458", test_conc458, TEST_CONNECTION_NONE, 0, NULL, NULL}, diff --git a/libmariadb/unittest/libmariadb/my_test.h b/libmariadb/unittest/libmariadb/my_test.h index 9f75d67a..3184b80d 100644 --- a/libmariadb/unittest/libmariadb/my_test.h +++ b/libmariadb/unittest/libmariadb/my_test.h @@ -76,7 +76,7 @@ if (IS_SKYSQL(hostname)) \ #endif #define SKIP_TLS \ -if (force_tls)\ +if (force_tls || fingerprint[0])\ {\ diag("Test doesn't work with TLS");\ return SKIP;\ @@ -224,6 +224,7 @@ MYSQL *my_test_connect(MYSQL *mysql, static const char *schema = 0; static char *hostname = 0; static char *password = 0; +static char fingerprint[65]; static unsigned int port = 0; static unsigned int ssl_port = 0; static char *socketname = 0; @@ -656,7 +657,9 @@ MYSQL *my_test_connect(MYSQL *mysql, unsigned long clientflag) { if (force_tls) - mysql_options(mysql, MYSQL_OPT_SSL_ENFORCE, &force_tls); + mysql_options(mysql, MYSQL_OPT_SSL_ENFORCE, &force_tls); + if (fingerprint[0]) + mysql_options(mysql, MARIADB_OPT_SSL_FP, fingerprint); if (!mysql_real_connect(mysql, host, user, passwd, db, port, unix_socket, clientflag)) { diag("error: %s", mysql_error(mysql)); @@ -677,6 +680,8 @@ MYSQL *my_test_connect(MYSQL *mysql, void run_tests(struct my_tests_st *test) { int i, rc, total=0; MYSQL *mysql; + my_bool verify= 0; + MARIADB_X509_INFO *info= NULL; while (test[total].function) total++; @@ -684,13 +689,15 @@ void run_tests(struct my_tests_st *test) { /* display TLS stats */ mysql= mysql_init(NULL); + mysql_options(mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, &verify); mysql_ssl_set(mysql, NULL, NULL, NULL, NULL, NULL); if (!mysql_real_connect(mysql, hostname, username, password, schema, port, socketname, 0)) { + diag("Error: %s", mysql_error(mysql)); BAIL_OUT("Can't establish TLS connection to server."); } - + fingerprint[0]= 0; if (!mysql_query(mysql, "SHOW VARIABLES LIKE '%ssl%'")) { MYSQL_RES *res; @@ -703,8 +710,15 @@ void run_tests(struct my_tests_st *test) { while ((row= mysql_fetch_row(res))) diag("%s: %s", row[0], row[1]); mysql_free_result(res); - diag("Cipher in use: %s", mysql_get_ssl_cipher(mysql)); - diag("--------------------"); + if (mysql_get_ssl_cipher(mysql)) + diag("Cipher in use: %s", mysql_get_ssl_cipher(mysql)); + mariadb_get_infov(mysql, MARIADB_TLS_PEER_CERT_INFO, &info); + if (info) + { + strcpy(fingerprint, info->fingerprint); + diag("Peer certificate fingerprint: %s", fingerprint); + diag("--------------------"); + } } mysql_close(mysql); diff --git a/libmariadb/unittest/libmariadb/ps_bugs.c b/libmariadb/unittest/libmariadb/ps_bugs.c index 72af30b4..7a581ad8 100644 --- a/libmariadb/unittest/libmariadb/ps_bugs.c +++ b/libmariadb/unittest/libmariadb/ps_bugs.c @@ -5741,7 +5741,77 @@ end: return ret; } +static int test_conc667(MYSQL *mysql) +{ + MYSQL_STMT *stmt1, *stmt2; + int rc; + + stmt1= mysql_stmt_init(mysql); + stmt2= mysql_stmt_init(mysql); + + rc= mysql_stmt_prepare(stmt1, "SELECT 1", -1); + check_stmt_rc(rc, stmt1); + + rc= mysql_stmt_prepare(stmt2, "SELECT 2", -1); + check_stmt_rc(rc, stmt2); + + rc= mysql_stmt_execute(stmt1); + check_stmt_rc(rc, stmt1); + + rc= mysql_stmt_free_result(stmt2); + FAIL_IF(!rc || mysql_stmt_errno(stmt2) != CR_STMT_NO_RESULT, + "Expected CR_STMT_NO_RESULT"); + diag("Error (expected) %s", mysql_stmt_error(stmt2)); + + rc= mysql_stmt_reset(stmt2); + FAIL_IF(!rc || mysql_stmt_errno(stmt2) != CR_COMMANDS_OUT_OF_SYNC, + "Expected commands out of sync error"); + + rc= mysql_stmt_fetch(stmt1); + check_stmt_rc(rc, stmt1); + + mysql_stmt_free_result(stmt1); + + rc= mysql_stmt_close(stmt1); + check_stmt_rc(rc, stmt1); + rc= mysql_stmt_close(stmt2); + check_stmt_rc(rc, stmt2); + + return OK; +} + +static int test_conc683(MYSQL *mysql) +{ + MYSQL_STMT *stmt1, *stmt2; + int rc; + + stmt1= mysql_stmt_init(mysql); + stmt2= mysql_stmt_init(mysql); + + rc= mysql_stmt_prepare(stmt1, "SELECT 1 UNION SELECT 2", -1); + check_stmt_rc(rc, stmt1); + + rc= mysql_stmt_prepare(stmt2, "SELECT 1", -1); + check_stmt_rc(rc, stmt2); + + rc= mysql_stmt_execute(stmt1); + check_stmt_rc(rc, stmt1); + + rc= mysql_stmt_close(stmt2); + FAIL_IF(!rc || mysql_stmt_errno(stmt2) != CR_COMMANDS_OUT_OF_SYNC, + "Expected commands out of sync error"); + + rc= mysql_stmt_close(stmt1); + check_stmt_rc(rc, stmt1); + rc= mysql_stmt_close(stmt2); + check_stmt_rc(rc, stmt2); + + return OK; +} + struct my_tests_st my_tests[] = { + {"test_conc683", test_conc683, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, + {"test_conc667", test_conc667, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc633", test_conc633, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc623", test_conc623, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, {"test_conc627", test_conc627, TEST_CONNECTION_DEFAULT, 0, NULL, NULL}, diff --git a/libmariadb/unittest/libmariadb/rpl_api.c b/libmariadb/unittest/libmariadb/rpl_api.c index f65a2915..b502eec8 100644 --- a/libmariadb/unittest/libmariadb/rpl_api.c +++ b/libmariadb/unittest/libmariadb/rpl_api.c @@ -72,6 +72,7 @@ static int test_rpl_async(MYSQL *my __attribute__((unused))) mysql_query(mysql, "SET @mariadb_slave_capability=4"); mysql_query(mysql, "SET NAMES latin1"); mysql_query(mysql, "SET @slave_gtid_strict_mode=1"); + mysql_query(mysql, "SET @master_heartbeat_period=10"); mysql_query(mysql, "SET @slave_gtid_ignore_duplicates=1"); mysql_query(mysql, "SET NAMES utf8"); mysql_query(mysql, "SET @master_binlog_checksum= @@global.binlog_checksum"); @@ -85,7 +86,7 @@ static int test_rpl_async(MYSQL *my __attribute__((unused))) /* We run rpl_api as very last test, too make sure binary log contains > 10000 events. */ - while((event= mariadb_rpl_fetch(rpl, event)) && events < 10000) + while((event= mariadb_rpl_fetch(rpl, event)) && event->event_type != HEARTBEAT_LOG_EVENT) { events++; } @@ -142,6 +143,7 @@ static int test_rpl_semisync(MYSQL *my __attribute__((unused))) mysql_query(mysql, "SET NAMES latin1"); mysql_query(mysql, "SET @slave_gtid_strict_mode=1"); mysql_query(mysql, "SET @slave_gtid_ignore_duplicates=1"); + mysql_query(mysql, "SET @master_heartbeat_period=10"); mysql_query(mysql, "SET NAMES utf8"); mysql_query(mysql, "SET @master_binlog_checksum= @@global.binlog_checksum"); rpl->server_id= 12; @@ -161,10 +163,7 @@ static int test_rpl_semisync(MYSQL *my __attribute__((unused))) if (mariadb_rpl_open(rpl)) return FAIL; - /* We run rpl_api as very last test, too make sure - binary log contains > 10000 events. - */ - while((event= mariadb_rpl_fetch(rpl, event)) && events < 10000) + while((event= mariadb_rpl_fetch(rpl, event)) && event->event_type != HEARTBEAT_LOG_EVENT) { events++; } @@ -341,7 +340,78 @@ static int test_conc592(MYSQL *my __attribute__((unused))) return OK; } +static int test_conc689(MYSQL *my __attribute__((unused))) +{ + MYSQL *mysql= mysql_init(NULL); + MYSQL_RES *result; + MYSQL_ROW row; + MARIADB_RPL_EVENT *event= NULL; + MARIADB_RPL *rpl; + int events= 0, rc; + + SKIP_SKYSQL; + SKIP_MAXSCALE; + + if (!is_mariadb) + return SKIP; + + if (!my_test_connect(mysql, hostname, username, + password, schema, port, socketname, 0)) + { + diag("Error: %s", mysql_error(mysql)); + mysql_close(mysql); + return FAIL; + } + + rc= mysql_query(mysql, "SELECT @@log_bin"); + check_mysql_rc(rc, mysql); + + result= mysql_store_result(mysql); + row= mysql_fetch_row(result); + if (!atoi(row[0])) + rc= SKIP; + mysql_free_result(result); + + if (rc == SKIP) + { + diag("binary log disabled -> skip"); + mysql_close(mysql); + return SKIP; + } + + rpl = mariadb_rpl_init(mysql); + + mysql_query(mysql, "SET @mariadb_slave_capability=4"); + mysql_query(mysql, "SET NAMES latin1"); + mysql_query(mysql, "SET @slave_gtid_strict_mode=1"); + mysql_query(mysql, "SET @master_heartbeat_period=10"); + mysql_query(mysql, "SET @slave_gtid_ignore_duplicates=1"); + mysql_query(mysql, "SET NAMES utf8"); + mysql_query(mysql, "SET @master_binlog_checksum= @@global.binlog_checksum"); + rpl->server_id= 12; + rpl->start_position= 4; + rpl->flags= MARIADB_RPL_BINLOG_SEND_ANNOTATE_ROWS; + + if (mariadb_rpl_open(rpl)) + return FAIL; + + /* We run rpl_api as very last test, too make sure + binary log contains > 10000 events. + */ + while((event= mariadb_rpl_fetch(rpl, event)) && event->event_type != HEARTBEAT_LOG_EVENT) + { + events++; + } + FAIL_IF(event->event.heartbeat.filename.length == 0, "Invalid filename"); + mariadb_free_rpl_event(event); + mariadb_rpl_close(rpl); + mysql_close(mysql); + return OK; +} + + struct my_tests_st my_tests[] = { + {"test_conc689", test_conc689, TEST_CONNECTION_NEW, 0, NULL, NULL}, {"test_conc592", test_conc592, TEST_CONNECTION_NEW, 0, NULL, NULL}, {"test_rpl_async", test_rpl_async, TEST_CONNECTION_NEW, 0, NULL, NULL}, {"test_rpl_semisync", test_rpl_semisync, TEST_CONNECTION_NEW, 0, NULL, NULL}, |