summaryrefslogtreecommitdiffstats
path: root/sql-common
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-07-01 18:15:00 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-07-01 18:15:00 +0000
commita2a2e32c02643a0cec111511220227703fda1cd5 (patch)
tree69cc2b631234c2a8e026b9cd4d72676c61c594df /sql-common
parentReleasing progress-linux version 1:10.11.8-1~progress7.99u1. (diff)
downloadmariadb-a2a2e32c02643a0cec111511220227703fda1cd5.tar.xz
mariadb-a2a2e32c02643a0cec111511220227703fda1cd5.zip
Merging upstream version 1:11.4.2.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sql-common')
-rw-r--r--sql-common/client.c313
-rw-r--r--sql-common/client_plugin.c4
2 files changed, 194 insertions, 123 deletions
diff --git a/sql-common/client.c b/sql-common/client.c
index db52a42c..9b88855f 100644
--- a/sql-common/client.c
+++ b/sql-common/client.c
@@ -167,6 +167,7 @@ static void mysql_close_free_options(MYSQL *mysql);
static void mysql_close_free(MYSQL *mysql);
static void mysql_prune_stmt_list(MYSQL *mysql);
static int cli_report_progress(MYSQL *mysql, char *packet, uint length);
+static my_bool parse_ok_packet(MYSQL *mysql, ulong length);
CHARSET_INFO *default_client_charset_info = &my_charset_latin1;
@@ -723,6 +724,12 @@ void end_server(MYSQL *mysql)
DBUG_ENTER("end_server");
if (mysql->net.vio != 0)
{
+ struct st_VioSSLFd *ssl_fd= (struct st_VioSSLFd*) mysql->connector_fd;
+ if (ssl_fd)
+ SSL_CTX_free(ssl_fd->ssl_context);
+ my_free(ssl_fd);
+ mysql->connector_fd = 0;
+
DBUG_PRINT("info",("Net: %s", vio_description(mysql->net.vio)));
#ifdef MYSQL_SERVER
slave_io_thread_detach_vio();
@@ -1432,6 +1439,7 @@ mysql_init(MYSQL *mysql)
bzero((char*) (mysql), sizeof(*(mysql)));
mysql->options.connect_timeout= CONNECT_TIMEOUT;
mysql->charset=default_client_charset_info;
+ mysql->options.use_ssl= 1;
strmov(mysql->net.sqlstate, not_error_sqlstate);
/*
@@ -1509,7 +1517,6 @@ mysql_ssl_set(MYSQL *mysql __attribute__((unused)) ,
static void
mysql_ssl_free(MYSQL *mysql __attribute__((unused)))
{
- struct st_VioSSLFd *ssl_fd= (struct st_VioSSLFd*) mysql->connector_fd;
DBUG_ENTER("mysql_ssl_free");
my_free(mysql->options.ssl_key);
@@ -1522,9 +1529,6 @@ mysql_ssl_free(MYSQL *mysql __attribute__((unused)))
my_free(mysql->options.extension->ssl_crl);
my_free(mysql->options.extension->ssl_crlpath);
}
- if (ssl_fd)
- SSL_CTX_free(ssl_fd->ssl_context);
- my_free(mysql->connector_fd);
mysql->options.ssl_key = 0;
mysql->options.ssl_cert = 0;
mysql->options.ssl_ca = 0;
@@ -1536,7 +1540,6 @@ mysql_ssl_free(MYSQL *mysql __attribute__((unused)))
mysql->options.extension->ssl_crlpath = 0;
}
mysql->options.use_ssl = FALSE;
- mysql->connector_fd = 0;
DBUG_VOID_RETURN;
}
@@ -1570,8 +1573,7 @@ mysql_get_ssl_cipher(MYSQL *mysql __attribute__((unused)))
SYNOPSIS
ssl_verify_server_cert()
- vio pointer to a SSL connected vio
- server_hostname name of the server that we connected to
+ MYSQL mysql
errptr if we fail, we'll return (a pointer to a string
describing) the reason here
@@ -1583,33 +1585,24 @@ mysql_get_ssl_cipher(MYSQL *mysql __attribute__((unused)))
#if defined(HAVE_OPENSSL)
-#ifdef HAVE_X509_check_host
#include <openssl/x509v3.h>
-#endif
-static int ssl_verify_server_cert(Vio *vio, const char* server_hostname, const char **errptr)
+static int ssl_verify_server_cert(MYSQL *mysql, const char **errptr)
{
SSL *ssl;
X509 *server_cert= NULL;
-#ifndef HAVE_X509_check_host
- char *cn= NULL;
- int cn_loc= -1;
- ASN1_STRING *cn_asn1= NULL;
- X509_NAME_ENTRY *cn_entry= NULL;
- X509_NAME *subject= NULL;
-#endif
int ret_validation= 1;
DBUG_ENTER("ssl_verify_server_cert");
- DBUG_PRINT("enter", ("server_hostname: %s", server_hostname));
+ DBUG_PRINT("enter", ("server_hostname: %s", mysql->host));
- if (!(ssl= (SSL*)vio->ssl_arg))
+ if (!(ssl= (SSL*)mysql->net.vio->ssl_arg))
{
*errptr= "No SSL pointer found";
goto error;
}
- if (!server_hostname)
+ if (!mysql->host)
{
*errptr= "No server hostname supplied";
goto error;
@@ -1621,70 +1614,32 @@ static int ssl_verify_server_cert(Vio *vio, const char* server_hostname, const c
goto error;
}
- if (X509_V_OK != SSL_get_verify_result(ssl))
+ switch (SSL_get_verify_result(ssl))
{
+ case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: /* OpenSSL */
+ case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: /* OpenSSL */
+ case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: /* wolfSSL */
+ /*
+ If the caller have specified CA - it'll define whether the
+ cert is good. Otherwise we'll do more checks.
+ */
+ ret_validation= (mysql->options.ssl_ca && mysql->options.ssl_ca[0]) ||
+ (mysql->options.ssl_capath && mysql->options.ssl_capath[0]);
+ mysql->tls_self_signed_error= *errptr= "SSL certificate is self-signed";
+ break;
+ case X509_V_OK:
+ ret_validation= X509_check_host(server_cert, mysql->host,
+ strlen(mysql->host), 0, 0) != 1 &&
+ X509_check_ip_asc(server_cert, mysql->host, 0) != 1;
+ *errptr= "SSL certificate validation failure";
+ break;
+ default:
*errptr= "Failed to verify the server certificate";
- goto error;
- }
- /*
- We already know that the certificate exchanged was valid; the SSL library
- handled that. Now we need to verify that the contents of the certificate
- are what we expect.
- */
-
-#ifdef HAVE_X509_check_host
- ret_validation=
- X509_check_host(server_cert, server_hostname,
- strlen(server_hostname), 0, 0) != 1;
-#ifndef HAVE_WOLFSSL
- if (ret_validation)
- {
- ret_validation=
- X509_check_ip_asc(server_cert, server_hostname, 0) != 1;
- }
-#endif
-#else
- subject= X509_get_subject_name(server_cert);
- cn_loc= X509_NAME_get_index_by_NID(subject, NID_commonName, -1);
- if (cn_loc < 0)
- {
- *errptr= "Failed to get CN location in the certificate subject";
- goto error;
- }
- cn_entry= X509_NAME_get_entry(subject, cn_loc);
- if (cn_entry == NULL)
- {
- *errptr= "Failed to get CN entry using CN location";
- goto error;
- }
-
- cn_asn1 = X509_NAME_ENTRY_get_data(cn_entry);
- if (cn_asn1 == NULL)
- {
- *errptr= "Failed to get CN from CN entry";
- goto error;
- }
-
- cn= (char *) ASN1_STRING_get0_data(cn_asn1);
-
- if ((size_t)ASN1_STRING_length(cn_asn1) != strlen(cn))
- {
- *errptr= "NULL embedded in the certificate CN";
- goto error;
+ break;
}
- DBUG_PRINT("info", ("Server hostname in cert: %s", cn));
- if (!strcmp(cn, server_hostname))
- {
- /* Success */
- ret_validation= 0;
- }
-#endif
- *errptr= "SSL certificate validation failure";
-
error:
- if (server_cert != NULL)
- X509_free (server_cert);
+ X509_free(server_cert);
DBUG_RETURN(ret_validation);
}
@@ -1813,6 +1768,7 @@ C_MODE_END
typedef struct st_mysql_client_plugin_AUTHENTICATION auth_plugin_t;
static int client_mpvio_write_packet(struct st_plugin_vio*, const uchar*, int);
static int native_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql);
+static int native_password_auth_hash(MYSQL *mysql, uchar *out, size_t *outlen);
static int old_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql);
static auth_plugin_t native_password_client_plugin=
@@ -1822,13 +1778,14 @@ static auth_plugin_t native_password_client_plugin=
native_password_plugin_name,
"R.J.Silk, Sergei Golubchik",
"Native MySQL authentication",
- {1, 0, 0},
+ {1, 0, 1},
"GPL",
NULL,
NULL,
NULL,
NULL,
- native_password_auth_client
+ native_password_auth_client,
+ native_password_auth_hash
};
static auth_plugin_t old_password_client_plugin=
@@ -1844,7 +1801,8 @@ static auth_plugin_t old_password_client_plugin=
NULL,
NULL,
NULL,
- old_password_auth_client
+ old_password_auth_client,
+ NULL
};
@@ -2072,6 +2030,7 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio,
{
MYSQL *mysql= mpvio->mysql;
NET *net= &mysql->net;
+ enum enum_vio_type vio_type= net->vio->type;
char *buff, *end;
size_t buff_size;
size_t connect_attrs_len=
@@ -2106,6 +2065,12 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio,
if (mpvio->db)
mysql->client_flag|= CLIENT_CONNECT_WITH_DB;
+ if (vio_type == VIO_TYPE_NAMEDPIPE)
+ {
+ mysql->server_capabilities&= ~CLIENT_SSL;
+ mysql->options.use_ssl= 0;
+ }
+
/* Remove options that server doesn't support */
mysql->client_flag= mysql->client_flag &
(~(CLIENT_COMPRESS | CLIENT_SSL | CLIENT_PROTOCOL_41)
@@ -2136,9 +2101,9 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio,
certificate, a ssl connection is required.
If the server does not support ssl, we abort the connection.
*/
- if (mysql->options.use_ssl &&
- (mysql->options.extension && mysql->options.extension->tls_verify_server_cert) &&
- !(mysql->server_capabilities & CLIENT_SSL))
+ if (mysql->options.use_ssl && !(mysql->server_capabilities & CLIENT_SSL) &&
+ (!mysql->options.extension ||
+ !mysql->options.extension->tls_allow_invalid_server_cert))
{
set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
ER(CR_SSL_CONNECTION_ERROR),
@@ -2156,9 +2121,6 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio,
enum enum_ssl_init_error ssl_init_error;
const char *cert_error;
unsigned long ssl_error;
-#ifdef EMBEDDED_LIBRARY
- DBUG_ASSERT(0); // embedded should not do SSL connect
-#endif
/*
Send mysql->client_flag, max_packet_size - unencrypted otherwise
@@ -2189,7 +2151,7 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio,
ER(CR_SSL_CONNECTION_ERROR), sslGetErrString(ssl_init_error));
goto error;
}
- mysql->connector_fd= (unsigned char *) ssl_fd;
+ mysql->connector_fd= (uchar *) ssl_fd;
/* Connect to the server */
DBUG_PRINT("info", ("IO layer change in progress..."));
@@ -2207,13 +2169,34 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio,
DBUG_PRINT("info", ("IO layer change done!"));
/* Verify server cert */
- if ((mysql->options.extension && mysql->options.extension->tls_verify_server_cert) &&
- ssl_verify_server_cert(net->vio, mysql->host, &cert_error))
+ if ((!mysql->options.extension ||
+ !mysql->options.extension->tls_allow_invalid_server_cert) &&
+ ssl_verify_server_cert(mysql, &cert_error))
{
set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
ER(CR_SSL_CONNECTION_ERROR), cert_error);
goto error;
}
+ if (mysql->tls_self_signed_error)
+ {
+ /*
+ If the transport is secure (see opt_require_secure_transport) we
+ allow a self-signed cert as we know it came from the server.
+
+ If no password or plugin uses insecure protocol - refuse the cert.
+
+ Otherwise one last cert check after auth.
+ */
+ if (vio_type == VIO_TYPE_SOCKET)
+ mysql->tls_self_signed_error= 0;
+ else if (!mysql->passwd || !mysql->passwd[0] ||
+ !mpvio->plugin->hash_password_bin)
+ {
+ set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
+ ER(CR_SSL_CONNECTION_ERROR), mysql->tls_self_signed_error);
+ goto error;
+ }
+ }
}
#endif /* HAVE_OPENSSL */
@@ -2568,6 +2551,14 @@ int run_plugin_auth(MYSQL *mysql, char *data, uint data_len,
auth_plugin_name, MYSQL_CLIENT_AUTHENTICATION_PLUGIN)))
DBUG_RETURN (1);
+ /* refuse insecure plugin if TLS is in doubt */
+ if (mysql->tls_self_signed_error && !auth_plugin->hash_password_bin)
+ {
+ set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
+ ER(CR_SSL_CONNECTION_ERROR), mysql->tls_self_signed_error);
+ DBUG_RETURN (1);
+ }
+
mpvio.plugin= auth_plugin;
res= auth_plugin->authenticate_user((struct st_plugin_vio *)&mpvio, mysql);
@@ -2589,7 +2580,7 @@ int run_plugin_auth(MYSQL *mysql, char *data, uint data_len,
if (res != CR_OK_HANDSHAKE_COMPLETE)
{
/* Read what server thinks about out new auth message report */
- if (cli_safe_read(mysql) == packet_error)
+ if ((pkt_length= cli_safe_read(mysql)) == packet_error)
{
if (mysql->net.last_errno == CR_SERVER_LOST)
set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
@@ -2604,7 +2595,44 @@ int run_plugin_auth(MYSQL *mysql, char *data, uint data_len,
net->read_pos[0] should always be 0 here if the server implements
the protocol correctly
*/
- DBUG_RETURN (mysql->net.read_pos[0] != 0);
+ if (mysql->net.read_pos[0] != 0)
+ DBUG_RETURN(1);
+ if (!mysql->tls_self_signed_error)
+ DBUG_RETURN(0);
+
+ /* Last attempt to validate the cert: compare cert info packet */
+ DBUG_ASSERT(mysql->options.use_ssl);
+ DBUG_ASSERT(mysql->net.vio->ssl_arg);
+ DBUG_ASSERT(!mysql->options.extension ||
+ !mysql->options.extension->tls_allow_invalid_server_cert);
+ DBUG_ASSERT(!mysql->options.ssl_ca || !mysql->options.ssl_ca[0]);
+ DBUG_ASSERT(!mysql->options.ssl_capath || !mysql->options.ssl_capath[0]);
+ DBUG_ASSERT(auth_plugin->hash_password_bin);
+ DBUG_ASSERT(mysql->passwd[0]);
+
+ parse_ok_packet(mysql, pkt_length); /* set mysql->info */
+ if (mysql->info && mysql->info[0] == '\1')
+ {
+ uchar fp[128], buf[1024], digest[256/8];
+ size_t buflen= sizeof(buf);
+ uint fplen= sizeof(fp);
+ char *hexsig= mysql->info + 1, hexdigest[sizeof(digest)*2+1];
+ X509 *cert= SSL_get_peer_certificate((SSL*)mysql->net.vio->ssl_arg);
+ X509_digest(cert, EVP_sha256(), fp, &fplen);
+ X509_free(cert);
+ auth_plugin->hash_password_bin(mysql, buf, &buflen);
+ my_sha256_multi(digest, buf, buflen, mysql->scramble, SCRAMBLE_LENGTH,
+ fp, fplen, NULL);
+ mysql->info= NULL; /* no need to confuse the client with binary info */
+
+ octet2hex(hexdigest, digest, sizeof(digest));
+ if (strcmp(hexdigest, hexsig) == 0)
+ DBUG_RETURN(0); /* phew. self-signed certificate is validated! */
+ }
+
+ set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
+ ER(CR_SSL_CONNECTION_ERROR), mysql->tls_self_signed_error);
+ DBUG_RETURN(1);
}
@@ -2695,6 +2723,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
mysql->methods= &client_methods;
mysql->client_flag=0; /* For handshake */
+ mysql->tls_self_signed_error= 0;
/* use default options */
if (mysql->options.my_cnf_file || mysql->options.my_cnf_group)
@@ -3070,9 +3099,10 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
mysql->port=port;
/*
- remove the rpl hack from the version string,
- see RPL_VERSION_HACK comment
+ remove the rpl hack from the version string, in case we're connecting
+ to a pre-11.0 server
*/
+#define RPL_VERSION_HACK "5.5.5-"
if ((mysql->server_capabilities & CLIENT_PLUGIN_AUTH) &&
strncmp(mysql->server_version, RPL_VERSION_HACK,
sizeof(RPL_VERSION_HACK) - 1) == 0)
@@ -3448,6 +3478,29 @@ void STDCALL mysql_close(MYSQL *mysql)
}
+static my_bool parse_ok_packet(MYSQL *mysql, ulong length)
+{
+ uchar *pos= mysql->net.read_pos + 1;
+ DBUG_ASSERT(pos[-1] == 0);
+
+ mysql->affected_rows= net_field_length_ll(&pos);
+ mysql->insert_id= net_field_length_ll(&pos);
+ if (protocol_41(mysql))
+ {
+ mysql->server_status=uint2korr(pos); pos+=2;
+ mysql->warning_count=uint2korr(pos); pos+=2;
+ }
+ else if (mysql->server_capabilities & CLIENT_TRANSACTIONS)
+ {
+ mysql->server_status=uint2korr(pos); pos+=2;
+ mysql->warning_count= 0;
+ }
+ if (pos < mysql->net.read_pos + length && net_field_length(&pos))
+ mysql->info=(char*) pos;
+ return 0;
+}
+
+
static my_bool cli_read_query_result(MYSQL *mysql)
{
uchar *pos;
@@ -3468,31 +3521,10 @@ static my_bool cli_read_query_result(MYSQL *mysql)
#ifdef MYSQL_CLIENT /* Avoid warn of unused labels*/
get_info:
#endif
- pos=(uchar*) mysql->net.read_pos;
+ pos= mysql->net.read_pos;
if ((field_count= net_field_length(&pos)) == 0)
- {
- mysql->affected_rows= net_field_length_ll(&pos);
- mysql->insert_id= net_field_length_ll(&pos);
- DBUG_PRINT("info",("affected_rows: %lu insert_id: %lu",
- (ulong) mysql->affected_rows,
- (ulong) mysql->insert_id));
- if (protocol_41(mysql))
- {
- mysql->server_status=uint2korr(pos); pos+=2;
- mysql->warning_count=uint2korr(pos); pos+=2;
- }
- else if (mysql->server_capabilities & CLIENT_TRANSACTIONS)
- {
- /* MySQL 4.0 protocol */
- mysql->server_status=uint2korr(pos); pos+=2;
- mysql->warning_count= 0;
- }
- DBUG_PRINT("info",("status: %u warning_count: %u",
- mysql->server_status, mysql->warning_count));
- if (pos < mysql->net.read_pos+length && net_field_length(&pos))
- mysql->info=(char*) pos;
- DBUG_RETURN(0);
- }
+ DBUG_RETURN(parse_ok_packet(mysql, length));
+
#ifdef MYSQL_CLIENT
if (field_count == NULL_LENGTH) /* LOAD DATA LOCAL INFILE */
{
@@ -3817,7 +3849,7 @@ mysql_options(MYSQL *mysql,enum mysql_option option, const void *arg)
sizeof(struct st_mysql_options_extention),
MYF(MY_WME | MY_ZEROFILL));
if (mysql->options.extension)
- mysql->options.extension->tls_verify_server_cert= *(my_bool*) arg;
+ mysql->options.extension->tls_allow_invalid_server_cert= !*(my_bool*) arg;
break;
case MYSQL_PLUGIN_DIR:
EXTENSION_SET_STRING(&mysql->options, plugin_dir, arg);
@@ -4170,6 +4202,22 @@ static int native_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
DBUG_RETURN(CR_OK);
}
+
+static int native_password_auth_hash(MYSQL *mysql, uchar *out, size_t *out_length)
+{
+ uchar hash_stage1[MY_SHA1_HASH_SIZE];
+
+ if (*out_length < MY_SHA1_HASH_SIZE)
+ return 1;
+ *out_length= MY_SHA1_HASH_SIZE;
+
+ my_sha1(hash_stage1, mysql->passwd, strlen(mysql->passwd));
+ my_sha1(out, (char*)hash_stage1, MY_SHA1_HASH_SIZE);
+
+ return 0;
+}
+
+
/**
client authentication plugin that does old MySQL authentication
using an 8-byte (4.0-) scramble
@@ -4235,3 +4283,28 @@ int STDCALL mysql_cancel(MYSQL *mysql)
return vio_shutdown(mysql->net.vio, SHUT_RDWR);
return -1;
}
+
+
+MYSQL_RES *STDCALL mysql_use_result(MYSQL *mysql)
+{
+ return (*mysql->methods->use_result)(mysql);
+}
+
+
+MYSQL_FIELD *STDCALL mysql_fetch_fields(MYSQL_RES *res)
+{
+ return (res)->fields;
+}
+
+
+ulong STDCALL
+mysql_real_escape_string(MYSQL *mysql, char *to,const char *from,
+ ulong length)
+{
+ my_bool overflow;
+ if (mysql->server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES)
+ return (ulong) escape_quotes_for_mysql(mysql->charset, to, 0, from, length,
+ &overflow);
+ return (ulong) escape_string_for_mysql(mysql->charset, to, 0, from, length,
+ &overflow);
+}
diff --git a/sql-common/client_plugin.c b/sql-common/client_plugin.c
index 0a2e39f7..38444648 100644
--- a/sql-common/client_plugin.c
+++ b/sql-common/client_plugin.c
@@ -171,9 +171,7 @@ add_plugin(MYSQL *mysql, struct st_mysql_client_plugin *plugin, void *dlhandle,
goto err1;
}
- if (plugin->interface_version < plugin_version[plugin->type] ||
- (plugin->interface_version >> 8) >
- (plugin_version[plugin->type] >> 8))
+ if (plugin->interface_version >> 8 != plugin_version[plugin->type] >> 8)
{
errmsg= "Incompatible client plugin interface";
goto err1;