Skip to content

Commit deda0c7

Browse files
Adam Palmbladsodabrew
authored andcommitted
Add ability to set ssl_mode. (brianmario#793)
This PR adds support for the new MySQL 5.7.3 ssl_mode option and additional ssl_mode options in MySQL 5.7.11 and higher. See the MySQL docs for details: http://dev.mysql.com/doc/refman/5.7/en/mysql-options.html
1 parent 079860b commit deda0c7

File tree

4 files changed

+94
-0
lines changed

4 files changed

+94
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ Mysql2::Client.new(
203203
:reconnect = true/false,
204204
:local_infile = true/false,
205205
:secure_auth = true/false,
206+
:ssl_mode = :disabled / :preferred / :required / :verify_ca / :verify_identity,
206207
:default_file = '/path/to/my.cfg',
207208
:default_group = 'my.cfg section',
208209
:init_command => sql

ext/mysql2/client.c

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,43 @@ struct nogvl_select_db_args {
8383
char *db;
8484
};
8585

86+
static VALUE rb_set_ssl_mode_option(VALUE self, VALUE setting) {
87+
unsigned long version = mysql_get_client_version();
88+
89+
if (version < 50703) {
90+
rb_warn( "Your mysql client library does not support setting ssl_mode; full support comes with 5.7.11." );
91+
return Qnil;
92+
}
93+
#ifdef HAVE_CONST_MYSQL_OPT_SSL_ENFORCE
94+
GET_CLIENT(self);
95+
int val = NUM2INT( setting );
96+
if (version >= 50703 && version < 50711) {
97+
if (val == SSL_MODE_DISABLED || val == SSL_MODE_REQUIRED) {
98+
bool b = ( val == SSL_MODE_REQUIRED );
99+
int result = mysql_options( wrapper->client, MYSQL_OPT_SSL_ENFORCE, &b );
100+
return INT2NUM(result);
101+
102+
} else {
103+
rb_warn( "MySQL client libraries between 5.7.3 and 5.7.10 only support SSL_MODE_DISABLED and SSL_MODE_REQUIRED" );
104+
return Qnil;
105+
}
106+
}
107+
#endif
108+
#ifdef FULL_SSL_MODE_SUPPORT
109+
GET_CLIENT(self);
110+
int val = NUM2INT( setting );
111+
112+
if (val != SSL_MODE_DISABLED && val != SSL_MODE_PREFERRED && val != SSL_MODE_REQUIRED && val != SSL_MODE_VERIFY_CA && val != SSL_MODE_VERIFY_IDENTITY) {
113+
rb_raise(cMysql2Error, "ssl_mode= takes DISABLED, PREFERRED, REQUIRED, VERIFY_CA, VERIFY_IDENTITY, you passed: %d", val );
114+
}
115+
int result = mysql_options( wrapper->client, MYSQL_OPT_SSL_MODE, &val );
116+
117+
return INT2NUM(result);
118+
#endif
119+
#ifdef NO_SSL_MODE_SUPPORT
120+
return Qnil;
121+
#endif
122+
}
86123
/*
87124
* non-blocking mysql_*() functions that we won't be wrapping since
88125
* they do not appear to hit the network nor issue any interruptible
@@ -1337,6 +1374,7 @@ void init_mysql2_client() {
13371374
rb_define_private_method(cMysql2Client, "default_group=", set_read_default_group, 1);
13381375
rb_define_private_method(cMysql2Client, "init_command=", set_init_command, 1);
13391376
rb_define_private_method(cMysql2Client, "ssl_set", set_ssl_options, 5);
1377+
rb_define_private_method(cMysql2Client, "ssl_mode=", rb_set_ssl_mode_option, 1);
13401378
rb_define_private_method(cMysql2Client, "initialize_ext", initialize_ext, 0);
13411379
rb_define_private_method(cMysql2Client, "connect", rb_connect, 7);
13421380
rb_define_private_method(cMysql2Client, "_query", rb_query, 2);
@@ -1464,4 +1502,35 @@ void init_mysql2_client() {
14641502
rb_const_set(cMysql2Client, rb_intern("BASIC_FLAGS"),
14651503
LONG2NUM(CLIENT_BASIC_FLAGS));
14661504
#endif
1505+
#ifdef FULL_SSL_MODE_SUPPORT
1506+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_DISABLED"), INT2NUM(SSL_MODE_DISABLED));
1507+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_PREFERRED"), INT2NUM(SSL_MODE_PREFERRED));
1508+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_REQUIRED"), INT2NUM(SSL_MODE_REQUIRED));
1509+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_VERIFY_CA"), INT2NUM(SSL_MODE_VERIFY_CA));
1510+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_VERIFY_IDENTITY"), INT2NUM(SSL_MODE_VERIFY_IDENTITY));
1511+
#endif
1512+
#ifdef HAVE_CONST_MYSQL_OPT_SSL_ENFORCE
1513+
#define SSL_MODE_DISABLED 1
1514+
#define SSL_MODE_REQUIRED 3
1515+
#define HAVE_CONST_SSL_MODE_DISABLED
1516+
#define HAVE_CONST_SSL_MODE_REQUIRED
1517+
1518+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_DISABLED"), INT2NUM(SSL_MODE_DISABLED));
1519+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_REQUIRED"), INT2NUM(SSL_MODE_REQUIRED));
1520+
#endif
1521+
#ifndef HAVE_CONST_SSL_MODE_DISABLED
1522+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_DISABLED"), INT2NUM(0));
1523+
#endif
1524+
#ifndef HAVE_CONST_SSL_MODE_PREFERRED
1525+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_PREFERRED"), INT2NUM(0));
1526+
#endif
1527+
#ifndef HAVE_CONST_SSL_MODE_REQUIRED
1528+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_REQUIRED"), INT2NUM(0));
1529+
#endif
1530+
#ifndef HAVE_CONST_SSL_MODE_VERIFY_CA
1531+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_VERIFY_CA"), INT2NUM(0));
1532+
#endif
1533+
#ifndef HAVE_CONST_SSL_MODE_VERIFY_IDENTITY
1534+
rb_const_set(cMysql2Client, rb_intern("SSL_MODE_VERIFY_IDENTITY"), INT2NUM(0));
1535+
#endif
14671536
}

ext/mysql2/extconf.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,16 @@ def asplode(lib)
1212
end
1313
end
1414

15+
def add_ssl_defines(header)
16+
all_modes_found = %w(SSL_MODE_DISABLED SSL_MODE_PREFERRED SSL_MODE_REQUIRED SSL_MODE_VERIFY_CA SSL_MODE_VERIFY_IDENTITY).inject(true) do |m, ssl_mode|
17+
m && have_const(ssl_mode, header)
18+
end
19+
$CFLAGS << ' -DFULL_SSL_MODE_SUPPORT' if all_modes_found
20+
# if we only have ssl toggle (--ssl,--disable-ssl) from 5.7.3 to 5.7.10
21+
has_no_support = all_modes_found ? false : !have_const('MYSQL_OPT_SSL_ENFORCE', header)
22+
$CFLAGS << ' -DNO_SSL_MODE_SUPPORT' if has_no_support
23+
end
24+
1525
# 2.0-only
1626
have_header('ruby/thread.h') && have_func('rb_thread_call_without_gvl', 'ruby/thread.h')
1727

@@ -87,6 +97,8 @@ def asplode(lib)
8797
asplode 'mysql.h'
8898
end
8999

100+
add_ssl_defines([prefix, 'mysql.h'].compact.join('/'))
101+
90102
%w(errmsg.h mysqld_error.h).each do |h|
91103
header = [prefix, h].compact.join '/'
92104
asplode h unless have_header header

lib/mysql2/client.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ def initialize(opts = {})
4747

4848
ssl_options = opts.values_at(:sslkey, :sslcert, :sslca, :sslcapath, :sslcipher)
4949
ssl_set(*ssl_options) if ssl_options.any?
50+
self.ssl_mode = parse_ssl_mode(opts[:ssl_mode]) if opts[:ssl_mode]
5051

5152
case opts[:flags]
5253
when Array
@@ -87,6 +88,17 @@ def initialize(opts = {})
8788
connect user, pass, host, port, database, socket, flags
8889
end
8990

91+
def parse_ssl_mode(mode)
92+
m = mode.to_s.upcase
93+
if m.start_with?('SSL_MODE_')
94+
return Mysql2::Client.const_get(m) if Mysql2::Client.const_defined?(m)
95+
else
96+
x = 'SSL_MODE_' + m
97+
return Mysql2::Client.const_get(x) if Mysql2::Client.const_defined?(x)
98+
end
99+
warn "Unknown MySQL ssl_mode flag: #{mode}"
100+
end
101+
90102
def parse_flags_array(flags, initial = 0)
91103
flags.reduce(initial) do |memo, f|
92104
fneg = f.start_with?('-') ? f[1..-1] : nil

0 commit comments

Comments
 (0)