From d79eabf6d04ec2a0df0ad0184e2fb3fd36858f35 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Thu, 8 Feb 2024 22:46:15 +0900 Subject: [PATCH 1/2] Support ssl=True MySQL use ssl by default but MariaDB don't. Until mysqlclient<=2.2.1, `ssl=True` unintentionally allowed and it called `mysql_ssl_set(mysql, NULL, NULL, NULL, NULL, NULL)`. Although it is no-op in MySQL Connector, MariaDB Connector silently set MYSQL_OPT_SSL_ENFORCE when the API is called. (See #698) In case of PyMySQL, ssl is not used by default but `ssl=True` behave like `sslmode="PREFERRED"`. For better backward compatibility and compatibility with PyMySQL and security, I decided to allow ssl=True and it means sslmode="REQUIRED". --- src/MySQLdb/_mysql.c | 30 +++++++++++++++++++++--------- src/MySQLdb/connections.py | 2 ++ 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/MySQLdb/_mysql.c b/src/MySQLdb/_mysql.c index c334db6..d82b473 100644 --- a/src/MySQLdb/_mysql.c +++ b/src/MySQLdb/_mysql.c @@ -414,7 +414,7 @@ _mysql_ConnectionObject_Initialize( MYSQL *conn = NULL; PyObject *conv = NULL; PyObject *ssl = NULL; - char *ssl_mode = NULL; + const char *ssl_mode = NULL; const char *key = NULL, *cert = NULL, *ca = NULL, *capath = NULL, *cipher = NULL; PyObject *ssl_keepref[5] = {NULL}; @@ -437,7 +437,7 @@ _mysql_ConnectionObject_Initialize( int read_timeout = 0; int write_timeout = 0; int compress = -1, named_pipe = -1, local_infile = -1; - int ssl_mode_num = SSLMODE_DISABLED; + int ssl_mode_num = SSLMODE_PREFERRED; char *init_command=NULL, *read_default_file=NULL, *read_default_group=NULL, @@ -470,19 +470,31 @@ _mysql_ConnectionObject_Initialize( if(t){d=PyUnicode_AsUTF8(t);ssl_keepref[n_ssl_keepref++]=t;}\ PyErr_Clear();} + char ssl_mode_set = 0; if (ssl) { - PyObject *value = NULL; - _stringsuck(ca, value, ssl); - _stringsuck(capath, value, ssl); - _stringsuck(cert, value, ssl); - _stringsuck(key, value, ssl); - _stringsuck(cipher, value, ssl); + if (PyMapping_Check(ssl)) { + PyObject *value = NULL; + _stringsuck(ca, value, ssl); + _stringsuck(capath, value, ssl); + _stringsuck(cert, value, ssl); + _stringsuck(key, value, ssl); + _stringsuck(cipher, value, ssl); + } else if (PyObject_IsTrue(ssl)) { + // Support ssl=True from mysqlclient 2.2.4. + // for compatibility with PyMySQL and mysqlclient==2.2.1&libmariadb. + ssl_mode_num = SSLMODE_REQUIRED; + ssl_mode_set = 1; + } else { + ssl_mode_num = SSLMODE_DISABLED; + ssl_mode_set = 1; + } } if (ssl_mode) { if ((ssl_mode_num = _get_ssl_mode_num(ssl_mode)) <= 0) { PyErr_SetString(_mysql_NotSupportedError, "Unknown ssl_mode specification"); return -1; } + ssl_mode_set = 1; } conn = mysql_init(&(self->connection)); @@ -531,7 +543,7 @@ _mysql_ConnectionObject_Initialize( mysql_options(&(self->connection), MYSQL_OPT_SSL_CIPHER, cipher); } - if (ssl_mode) { + if (ssl_mode_set) { #ifdef HAVE_ENUM_MYSQL_OPT_SSL_MODE mysql_options(&(self->connection), MYSQL_OPT_SSL_MODE, &ssl_mode_num); #else diff --git a/src/MySQLdb/connections.py b/src/MySQLdb/connections.py index 4fa762d..c713229 100644 --- a/src/MySQLdb/connections.py +++ b/src/MySQLdb/connections.py @@ -134,6 +134,8 @@ class object, used to create cursors (keyword only) see the MySQL documentation for more details (mysql_ssl_set()). If this is set, and the client does not support SSL, NotSupportedError will be raised. + Since mysqlclient 2.2.4, ssl=True is alias of ssl_mode=REQUIRED + for better compatibility with PyMySQL and MariaDB. :param bool local_infile: enables LOAD LOCAL INFILE; zero disables From 93fbaf941f7aebd9ebb10a02caac701a0e068af7 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Thu, 8 Feb 2024 23:14:47 +0900 Subject: [PATCH 2/2] fix warning --- src/MySQLdb/_mysql.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/MySQLdb/_mysql.c b/src/MySQLdb/_mysql.c index d82b473..b9ec1c1 100644 --- a/src/MySQLdb/_mysql.c +++ b/src/MySQLdb/_mysql.c @@ -391,10 +391,10 @@ enum { }; static int -_get_ssl_mode_num(char *ssl_mode) +_get_ssl_mode_num(const char *ssl_mode) { - static char *ssl_mode_list[] = { "DISABLED", "PREFERRED", - "REQUIRED", "VERIFY_CA", "VERIFY_IDENTITY" }; + static const char *ssl_mode_list[] = { + "DISABLED", "PREFERRED", "REQUIRED", "VERIFY_CA", "VERIFY_IDENTITY" }; unsigned int i; for (i=0; i < sizeof(ssl_mode_list)/sizeof(ssl_mode_list[0]); i++) { if (strcmp(ssl_mode, ssl_mode_list[i]) == 0) {