Skip to content

Commit a7e3887

Browse files
authored
Support ssl=True (#700)
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" on MySQL Connector and set MYSQL_OPT_SSL_ENFORCE on MariaDB Connector. Fix #699
1 parent 1fa31fd commit a7e3887

File tree

2 files changed

+26
-12
lines changed

2 files changed

+26
-12
lines changed

Diff for: src/MySQLdb/_mysql.c

+24-12
Original file line numberDiff line numberDiff line change
@@ -391,10 +391,10 @@ enum {
391391
};
392392

393393
static int
394-
_get_ssl_mode_num(char *ssl_mode)
394+
_get_ssl_mode_num(const char *ssl_mode)
395395
{
396-
static char *ssl_mode_list[] = { "DISABLED", "PREFERRED",
397-
"REQUIRED", "VERIFY_CA", "VERIFY_IDENTITY" };
396+
static const char *ssl_mode_list[] = {
397+
"DISABLED", "PREFERRED", "REQUIRED", "VERIFY_CA", "VERIFY_IDENTITY" };
398398
unsigned int i;
399399
for (i=0; i < sizeof(ssl_mode_list)/sizeof(ssl_mode_list[0]); i++) {
400400
if (strcmp(ssl_mode, ssl_mode_list[i]) == 0) {
@@ -414,7 +414,7 @@ _mysql_ConnectionObject_Initialize(
414414
MYSQL *conn = NULL;
415415
PyObject *conv = NULL;
416416
PyObject *ssl = NULL;
417-
char *ssl_mode = NULL;
417+
const char *ssl_mode = NULL;
418418
const char *key = NULL, *cert = NULL, *ca = NULL,
419419
*capath = NULL, *cipher = NULL;
420420
PyObject *ssl_keepref[5] = {NULL};
@@ -437,7 +437,7 @@ _mysql_ConnectionObject_Initialize(
437437
int read_timeout = 0;
438438
int write_timeout = 0;
439439
int compress = -1, named_pipe = -1, local_infile = -1;
440-
int ssl_mode_num = SSLMODE_DISABLED;
440+
int ssl_mode_num = SSLMODE_PREFERRED;
441441
char *init_command=NULL,
442442
*read_default_file=NULL,
443443
*read_default_group=NULL,
@@ -470,19 +470,31 @@ _mysql_ConnectionObject_Initialize(
470470
if(t){d=PyUnicode_AsUTF8(t);ssl_keepref[n_ssl_keepref++]=t;}\
471471
PyErr_Clear();}
472472

473+
char ssl_mode_set = 0;
473474
if (ssl) {
474-
PyObject *value = NULL;
475-
_stringsuck(ca, value, ssl);
476-
_stringsuck(capath, value, ssl);
477-
_stringsuck(cert, value, ssl);
478-
_stringsuck(key, value, ssl);
479-
_stringsuck(cipher, value, ssl);
475+
if (PyMapping_Check(ssl)) {
476+
PyObject *value = NULL;
477+
_stringsuck(ca, value, ssl);
478+
_stringsuck(capath, value, ssl);
479+
_stringsuck(cert, value, ssl);
480+
_stringsuck(key, value, ssl);
481+
_stringsuck(cipher, value, ssl);
482+
} else if (PyObject_IsTrue(ssl)) {
483+
// Support ssl=True from mysqlclient 2.2.4.
484+
// for compatibility with PyMySQL and mysqlclient==2.2.1&libmariadb.
485+
ssl_mode_num = SSLMODE_REQUIRED;
486+
ssl_mode_set = 1;
487+
} else {
488+
ssl_mode_num = SSLMODE_DISABLED;
489+
ssl_mode_set = 1;
490+
}
480491
}
481492
if (ssl_mode) {
482493
if ((ssl_mode_num = _get_ssl_mode_num(ssl_mode)) <= 0) {
483494
PyErr_SetString(_mysql_NotSupportedError, "Unknown ssl_mode specification");
484495
return -1;
485496
}
497+
ssl_mode_set = 1;
486498
}
487499

488500
conn = mysql_init(&(self->connection));
@@ -531,7 +543,7 @@ _mysql_ConnectionObject_Initialize(
531543
mysql_options(&(self->connection), MYSQL_OPT_SSL_CIPHER, cipher);
532544
}
533545

534-
if (ssl_mode) {
546+
if (ssl_mode_set) {
535547
#ifdef HAVE_ENUM_MYSQL_OPT_SSL_MODE
536548
mysql_options(&(self->connection), MYSQL_OPT_SSL_MODE, &ssl_mode_num);
537549
#else

Diff for: src/MySQLdb/connections.py

+2
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@ class object, used to create cursors (keyword only)
134134
see the MySQL documentation for more details
135135
(mysql_ssl_set()). If this is set, and the client does not
136136
support SSL, NotSupportedError will be raised.
137+
Since mysqlclient 2.2.4, ssl=True is alias of ssl_mode=REQUIRED
138+
for better compatibility with PyMySQL and MariaDB.
137139
138140
:param bool local_infile:
139141
enables LOAD LOCAL INFILE; zero disables

0 commit comments

Comments
 (0)