Skip to content

Commit

Permalink
Support ssl=True (#700)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
methane committed Feb 8, 2024
1 parent 1fa31fd commit a7e3887
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 12 deletions.
36 changes: 24 additions & 12 deletions src/MySQLdb/_mysql.c
Expand Up @@ -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) {
Expand All @@ -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};
Expand All @@ -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,
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions src/MySQLdb/connections.py
Expand Up @@ -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
Expand Down

0 comments on commit a7e3887

Please sign in to comment.