trilogy 2.6.1 → 2.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ext/trilogy-ruby/cext.c +57 -18
- data/ext/trilogy-ruby/inc/trilogy/error.h +2 -1
- data/ext/trilogy-ruby/inc/trilogy/protocol.h +7 -1
- data/ext/trilogy-ruby/inc/trilogy/socket.h +19 -0
- data/ext/trilogy-ruby/src/builder.c +1 -1
- data/ext/trilogy-ruby/src/client.c +88 -25
- data/ext/trilogy-ruby/src/protocol.c +29 -6
- data/ext/trilogy-ruby/src/socket.c +24 -1
- data/lib/trilogy/error.rb +16 -17
- data/lib/trilogy/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 998b06e77dcb78b2f30307834490a7c9c7d61422dea586f646cead7b74467058
|
4
|
+
data.tar.gz: e5bf1ecf9e8b2b675db0d3c3ee7531db4ab022aa725c4ed0c16db088884c6075
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bd2acff1c38bbed9bea64f3fbb9ad474e4d42198dccbcdca0aa1b8ba3b52e35711f1c9e2e1a6859c15a71c38ed08ba06b5adcb5fbb5054b1b4264fd51ae0933f
|
7
|
+
data.tar.gz: e032a04cfb901d48a4e1e711cd576c380562f2b7f871724d06568dff8bd3b599fd3ea86360b3bcbe2f8f9471f986d6b1cc8f8d8e69309877778d1ce442dd65f3
|
data/ext/trilogy-ruby/cext.c
CHANGED
@@ -17,13 +17,13 @@
|
|
17
17
|
|
18
18
|
VALUE Trilogy_CastError;
|
19
19
|
static VALUE Trilogy_BaseConnectionError, Trilogy_ProtocolError, Trilogy_SSLError, Trilogy_QueryError,
|
20
|
-
Trilogy_ConnectionClosedError,
|
21
|
-
Trilogy_TimeoutError, Trilogy_SyscallError, Trilogy_Result, Trilogy_EOFError;
|
20
|
+
Trilogy_ConnectionClosedError,
|
21
|
+
Trilogy_TimeoutError, Trilogy_SyscallError, Trilogy_Result, Trilogy_EOFError, Trilogy_AuthPluginError;
|
22
22
|
|
23
23
|
static ID id_socket, id_host, id_port, id_username, id_password, id_found_rows, id_connect_timeout, id_read_timeout,
|
24
24
|
id_write_timeout, id_keepalive_enabled, id_keepalive_idle, id_keepalive_interval, id_keepalive_count,
|
25
25
|
id_ivar_affected_rows, id_ivar_fields, id_ivar_last_insert_id, id_ivar_rows, id_ivar_query_time, id_password,
|
26
|
-
id_database, id_ssl_ca, id_ssl_capath, id_ssl_cert, id_ssl_cipher, id_ssl_crl, id_ssl_crlpath, id_ssl_key,
|
26
|
+
id_database, id_enable_cleartext_plugin, id_ssl_ca, id_ssl_capath, id_ssl_cert, id_ssl_cipher, id_ssl_crl, id_ssl_crlpath, id_ssl_key,
|
27
27
|
id_ssl_mode, id_tls_ciphersuites, id_tls_min_version, id_tls_max_version, id_multi_statement, id_multi_result,
|
28
28
|
id_from_code, id_from_errno, id_connection_options, id_max_allowed_packet;
|
29
29
|
|
@@ -88,12 +88,8 @@ static struct trilogy_ctx *get_open_ctx(VALUE obj)
|
|
88
88
|
NORETURN(static void trilogy_syserr_fail_str(int, VALUE));
|
89
89
|
static void trilogy_syserr_fail_str(int e, VALUE msg)
|
90
90
|
{
|
91
|
-
if (e ==
|
92
|
-
|
93
|
-
} else if (e == ECONNRESET) {
|
94
|
-
rb_raise(Trilogy_ConnectionResetError, "%" PRIsVALUE, msg);
|
95
|
-
} else if (e == EPIPE) {
|
96
|
-
// Backwards compatibility: This error class makes no sense, but matches legacy behavior
|
91
|
+
if (e == EPIPE) {
|
92
|
+
// Backwards compatibility: This error message is a bit odd, but includes "TRILOGY_CLOSED_CONNECTION" to match legacy string matching
|
97
93
|
rb_raise(Trilogy_EOFError, "%" PRIsVALUE ": TRILOGY_CLOSED_CONNECTION: EPIPE", msg);
|
98
94
|
} else {
|
99
95
|
VALUE exc = rb_funcall(Trilogy_SyscallError, id_from_errno, 2, INT2NUM(e), msg);
|
@@ -137,7 +133,8 @@ static void handle_trilogy_error(struct trilogy_ctx *ctx, int rc, const char *ms
|
|
137
133
|
rb_raise(Trilogy_TimeoutError, "%" PRIsVALUE, rbmsg);
|
138
134
|
|
139
135
|
case TRILOGY_ERR: {
|
140
|
-
VALUE
|
136
|
+
VALUE conn_message = rb_str_new(ctx->conn.error_message, ctx->conn.error_message_len);
|
137
|
+
VALUE message = rb_sprintf("%" PRIsVALUE " (%" PRIsVALUE ")", conn_message, rbmsg);
|
141
138
|
VALUE exc = rb_funcall(Trilogy_ProtocolError, id_from_code, 2, message, INT2NUM(ctx->conn.error_code));
|
142
139
|
rb_exc_raise(exc);
|
143
140
|
}
|
@@ -160,6 +157,14 @@ static void handle_trilogy_error(struct trilogy_ctx *ctx, int rc, const char *ms
|
|
160
157
|
rb_raise(Trilogy_EOFError, "%" PRIsVALUE ": TRILOGY_CLOSED_CONNECTION", rbmsg);
|
161
158
|
}
|
162
159
|
|
160
|
+
case TRILOGY_AUTH_PLUGIN_ERROR: {
|
161
|
+
rb_raise(Trilogy_AuthPluginError, "%" PRIsVALUE ": TRILOGY_AUTH_PLUGIN_ERROR", rbmsg);
|
162
|
+
}
|
163
|
+
|
164
|
+
case TRILOGY_UNSUPPORTED: {
|
165
|
+
rb_raise(Trilogy_BaseConnectionError, "%" PRIsVALUE ": TRILOGY_UNSUPPORTED", rbmsg);
|
166
|
+
}
|
167
|
+
|
163
168
|
default:
|
164
169
|
rb_raise(Trilogy_QueryError, "%" PRIsVALUE ": %s", rbmsg, trilogy_error(rc));
|
165
170
|
}
|
@@ -243,7 +248,18 @@ static int _cb_ruby_wait(trilogy_sock_t *sock, trilogy_wait_t wait)
|
|
243
248
|
wait_flag = RB_WAITFD_OUT;
|
244
249
|
break;
|
245
250
|
|
251
|
+
case TRILOGY_WAIT_CONNECT:
|
252
|
+
// wait for connection to be writable
|
253
|
+
timeout = &sock->opts.connect_timeout;
|
254
|
+
if (timeout->tv_sec == 0 && timeout->tv_usec == 0) {
|
255
|
+
// We used to use the write timeout for this, so if a connect timeout isn't configured, default to that.
|
256
|
+
timeout = &sock->opts.write_timeout;
|
257
|
+
}
|
258
|
+
wait_flag = RB_WAITFD_OUT;
|
259
|
+
break;
|
260
|
+
|
246
261
|
case TRILOGY_WAIT_HANDSHAKE:
|
262
|
+
// wait for handshake packet on initial connection
|
247
263
|
timeout = &sock->opts.connect_timeout;
|
248
264
|
wait_flag = RB_WAITFD_IN;
|
249
265
|
break;
|
@@ -412,7 +428,12 @@ static void authenticate(struct trilogy_ctx *ctx, trilogy_handshake_t *handshake
|
|
412
428
|
}
|
413
429
|
|
414
430
|
if (rc != TRILOGY_AGAIN) {
|
415
|
-
|
431
|
+
if (rc == TRILOGY_UNSUPPORTED) {
|
432
|
+
handle_trilogy_error(ctx, rc, "trilogy_auth_recv: caching_sha2_password requires either TCP with TLS or a unix socket");
|
433
|
+
}
|
434
|
+
else {
|
435
|
+
handle_trilogy_error(ctx, rc, "trilogy_auth_recv");
|
436
|
+
}
|
416
437
|
}
|
417
438
|
|
418
439
|
rc = trilogy_sock_wait_read(ctx->conn.socket);
|
@@ -515,6 +536,10 @@ static VALUE rb_trilogy_connect(VALUE self, VALUE encoding, VALUE charset, VALUE
|
|
515
536
|
connopt.flags |= TRILOGY_CAPABILITIES_CONNECT_WITH_DB;
|
516
537
|
}
|
517
538
|
|
539
|
+
if (RTEST(rb_hash_aref(opts, ID2SYM(id_enable_cleartext_plugin)))) {
|
540
|
+
connopt.enable_cleartext_plugin = true;
|
541
|
+
}
|
542
|
+
|
518
543
|
if (RTEST(rb_hash_aref(opts, ID2SYM(id_found_rows)))) {
|
519
544
|
connopt.flags |= TRILOGY_CAPABILITIES_FOUND_ROWS;
|
520
545
|
}
|
@@ -1018,6 +1043,17 @@ static VALUE rb_trilogy_closed(VALUE self)
|
|
1018
1043
|
}
|
1019
1044
|
}
|
1020
1045
|
|
1046
|
+
static VALUE rb_trilogy_check(VALUE self)
|
1047
|
+
{
|
1048
|
+
struct trilogy_ctx *ctx = get_open_ctx(self);
|
1049
|
+
|
1050
|
+
int rc = trilogy_sock_check(ctx->conn.socket);
|
1051
|
+
if (rc != TRILOGY_OK && rc != TRILOGY_AGAIN) {
|
1052
|
+
handle_trilogy_error(ctx, rc, "trilogy_sock_check");
|
1053
|
+
}
|
1054
|
+
return Qtrue;
|
1055
|
+
}
|
1056
|
+
|
1021
1057
|
static VALUE rb_trilogy_discard(VALUE self)
|
1022
1058
|
{
|
1023
1059
|
struct trilogy_ctx *ctx = get_ctx(self);
|
@@ -1096,8 +1132,12 @@ static VALUE rb_trilogy_server_status(VALUE self) { return LONG2FIX(get_open_ctx
|
|
1096
1132
|
|
1097
1133
|
static VALUE rb_trilogy_server_version(VALUE self) { return rb_str_new_cstr(get_open_ctx(self)->server_version); }
|
1098
1134
|
|
1099
|
-
RUBY_FUNC_EXPORTED void Init_cext()
|
1135
|
+
RUBY_FUNC_EXPORTED void Init_cext(void)
|
1100
1136
|
{
|
1137
|
+
#ifdef HAVE_RB_EXT_RACTOR_SAFE
|
1138
|
+
rb_ext_ractor_safe(true);
|
1139
|
+
#endif
|
1140
|
+
|
1101
1141
|
VALUE Trilogy = rb_const_get(rb_cObject, rb_intern("Trilogy"));
|
1102
1142
|
rb_define_alloc_func(Trilogy, allocate_trilogy);
|
1103
1143
|
|
@@ -1109,6 +1149,7 @@ RUBY_FUNC_EXPORTED void Init_cext()
|
|
1109
1149
|
rb_define_method(Trilogy, "escape", rb_trilogy_escape, 1);
|
1110
1150
|
rb_define_method(Trilogy, "close", rb_trilogy_close, 0);
|
1111
1151
|
rb_define_method(Trilogy, "closed?", rb_trilogy_closed, 0);
|
1152
|
+
rb_define_method(Trilogy, "check", rb_trilogy_check, 0);
|
1112
1153
|
rb_define_method(Trilogy, "discard!", rb_trilogy_discard, 0);
|
1113
1154
|
rb_define_method(Trilogy, "last_insert_id", rb_trilogy_last_insert_id, 0);
|
1114
1155
|
rb_define_method(Trilogy, "affected_rows", rb_trilogy_affected_rows, 0);
|
@@ -1156,12 +1197,6 @@ RUBY_FUNC_EXPORTED void Init_cext()
|
|
1156
1197
|
Trilogy_TimeoutError = rb_const_get(Trilogy, rb_intern("TimeoutError"));
|
1157
1198
|
rb_global_variable(&Trilogy_TimeoutError);
|
1158
1199
|
|
1159
|
-
Trilogy_ConnectionRefusedError = rb_const_get(Trilogy, rb_intern("ConnectionRefusedError"));
|
1160
|
-
rb_global_variable(&Trilogy_ConnectionRefusedError);
|
1161
|
-
|
1162
|
-
Trilogy_ConnectionResetError = rb_const_get(Trilogy, rb_intern("ConnectionResetError"));
|
1163
|
-
rb_global_variable(&Trilogy_ConnectionResetError);
|
1164
|
-
|
1165
1200
|
Trilogy_BaseConnectionError = rb_const_get(Trilogy, rb_intern("BaseConnectionError"));
|
1166
1201
|
rb_global_variable(&Trilogy_BaseConnectionError);
|
1167
1202
|
|
@@ -1180,6 +1215,9 @@ RUBY_FUNC_EXPORTED void Init_cext()
|
|
1180
1215
|
Trilogy_EOFError = rb_const_get(Trilogy, rb_intern("EOFError"));
|
1181
1216
|
rb_global_variable(&Trilogy_EOFError);
|
1182
1217
|
|
1218
|
+
rb_global_variable(&Trilogy_AuthPluginError);
|
1219
|
+
Trilogy_AuthPluginError = rb_const_get(Trilogy, rb_intern("AuthPluginError"));
|
1220
|
+
|
1183
1221
|
id_socket = rb_intern("socket");
|
1184
1222
|
id_host = rb_intern("host");
|
1185
1223
|
id_port = rb_intern("port");
|
@@ -1195,6 +1233,7 @@ RUBY_FUNC_EXPORTED void Init_cext()
|
|
1195
1233
|
id_keepalive_count = rb_intern("keepalive_count");
|
1196
1234
|
id_keepalive_interval = rb_intern("keepalive_interval");
|
1197
1235
|
id_database = rb_intern("database");
|
1236
|
+
id_enable_cleartext_plugin = rb_intern("enable_cleartext_plugin");
|
1198
1237
|
id_ssl_ca = rb_intern("ssl_ca");
|
1199
1238
|
id_ssl_capath = rb_intern("ssl_capath");
|
1200
1239
|
id_ssl_cert = rb_intern("ssl_cert");
|
@@ -24,7 +24,8 @@
|
|
24
24
|
XX(TRILOGY_AUTH_SWITCH, -19) \
|
25
25
|
XX(TRILOGY_MAX_PACKET_EXCEEDED, -20) \
|
26
26
|
XX(TRILOGY_UNKNOWN_TYPE, -21) \
|
27
|
-
XX(TRILOGY_TIMEOUT, -22)
|
27
|
+
XX(TRILOGY_TIMEOUT, -22) \
|
28
|
+
XX(TRILOGY_AUTH_PLUGIN_ERROR, -23)
|
28
29
|
|
29
30
|
enum {
|
30
31
|
#define XX(name, code) name = code,
|
@@ -289,6 +289,7 @@ typedef enum {
|
|
289
289
|
XX(TRILOGY_TYPE_YEAR, 0x0d) \
|
290
290
|
XX(TRILOGY_TYPE_VARCHAR, 0x0f) \
|
291
291
|
XX(TRILOGY_TYPE_BIT, 0x10) \
|
292
|
+
XX(TRILOGY_TYPE_VECTOR, 0xf2) \
|
292
293
|
XX(TRILOGY_TYPE_JSON, 0xf5) \
|
293
294
|
XX(TRILOGY_TYPE_NEWDECIMAL, 0xf6) \
|
294
295
|
XX(TRILOGY_TYPE_ENUM, 0xf7) \
|
@@ -367,6 +368,7 @@ typedef enum {
|
|
367
368
|
// Typical response packet types
|
368
369
|
typedef enum {
|
369
370
|
TRILOGY_PACKET_OK = 0x0,
|
371
|
+
TRILOGY_PACKET_AUTH_MORE_DATA = 0x01,
|
370
372
|
TRILOGY_PACKET_EOF = 0xfe,
|
371
373
|
TRILOGY_PACKET_ERR = 0xff,
|
372
374
|
TRILOGY_PACKET_UNKNOWN
|
@@ -442,14 +444,16 @@ int trilogy_build_auth_packet(trilogy_builder_t *builder, const char *user, cons
|
|
442
444
|
* pass_len - The length of password in bytes.
|
443
445
|
* auth_plugin - Plugin authentication mechanism that the server requested.
|
444
446
|
* scramble - The scramble value received from the server.
|
447
|
+
* enable_cleartext_plugin - Send cleartext password if requested by server.
|
445
448
|
*
|
446
449
|
* Return values:
|
447
450
|
* TRILOGY_OK - The packet was successfully built and written to the
|
448
451
|
* builder's internal buffer.
|
449
452
|
* TRILOGY_SYSERR - A system error occurred, check errno.
|
453
|
+
* TRILOGY_AUTH_PLUGIN_ERROR - The server requested auth plugin is not supported.
|
450
454
|
*/
|
451
455
|
int trilogy_build_auth_switch_response_packet(trilogy_builder_t *builder, const char *pass, size_t pass_len,
|
452
|
-
const char *auth_plugin, const char *scramble);
|
456
|
+
const char *auth_plugin, const char *scramble, const bool enable_cleartext_plugin);
|
453
457
|
|
454
458
|
/* trilogy_build_change_db_packet - Build a change database command packet. This
|
455
459
|
* command will change the default database for the connection.
|
@@ -1035,4 +1039,6 @@ int trilogy_parse_stmt_ok_packet(const uint8_t *buff, size_t len, trilogy_stmt_o
|
|
1035
1039
|
int trilogy_parse_stmt_row_packet(const uint8_t *buff, size_t len, trilogy_column_packet_t *columns,
|
1036
1040
|
uint64_t column_count, trilogy_binary_value_t *out_values);
|
1037
1041
|
|
1042
|
+
int trilogy_build_auth_clear_password(trilogy_builder_t *builder, const char *pass, size_t pass_len);
|
1043
|
+
|
1038
1044
|
#endif
|
@@ -13,6 +13,7 @@ typedef enum {
|
|
13
13
|
TRILOGY_WAIT_READ = 0,
|
14
14
|
TRILOGY_WAIT_WRITE = 1,
|
15
15
|
TRILOGY_WAIT_HANDSHAKE = 2,
|
16
|
+
TRILOGY_WAIT_CONNECT = 3,
|
16
17
|
} trilogy_wait_t;
|
17
18
|
|
18
19
|
// We use the most strict mode as value 1 so if anyone ever
|
@@ -66,6 +67,8 @@ typedef struct {
|
|
66
67
|
uint16_t keepalive_count;
|
67
68
|
uint16_t keepalive_interval;
|
68
69
|
|
70
|
+
bool enable_cleartext_plugin;
|
71
|
+
|
69
72
|
TRILOGY_CAPABILITIES_t flags;
|
70
73
|
|
71
74
|
size_t max_allowed_packet;
|
@@ -111,4 +114,20 @@ trilogy_sock_t *trilogy_sock_new(const trilogy_sockopt_t *opts);
|
|
111
114
|
int trilogy_sock_resolve(trilogy_sock_t *raw);
|
112
115
|
int trilogy_sock_upgrade_ssl(trilogy_sock_t *raw);
|
113
116
|
|
117
|
+
/* trilogy_sock_check - Verify if the socket is still alive and not disconnected.
|
118
|
+
*
|
119
|
+
* This check is very cheap to do and reduces the number of errors when for
|
120
|
+
* example the server has restarted since the connection was opened. In connection
|
121
|
+
* pooling implementations, this check can be done before the connection is
|
122
|
+
* returned.
|
123
|
+
*
|
124
|
+
* raw - A connected trilogy_sock_t pointer. Using a disconnected trilogy_sock_t is undefined.
|
125
|
+
*
|
126
|
+
* Return values:
|
127
|
+
* TRILOGY_OK - The connection is alive on the client side and can be.
|
128
|
+
* TRILOGY_CLOSED_CONNECTION - The connection is closed.
|
129
|
+
* TRILOGY_SYSERR - A system error occurred, check errno.
|
130
|
+
*/
|
131
|
+
int trilogy_sock_check(trilogy_sock_t *raw);
|
132
|
+
|
114
133
|
#endif
|
@@ -182,7 +182,7 @@ int trilogy_builder_write_buffer(trilogy_builder_t *builder, const void *data, s
|
|
182
182
|
|
183
183
|
size_t fragment_remaining = TRILOGY_MAX_PACKET_LEN - builder->fragment_length;
|
184
184
|
|
185
|
-
if (builder->packet_length >= builder->packet_max_length
|
185
|
+
if (builder->packet_length + len >= builder->packet_max_length) {
|
186
186
|
return TRILOGY_MAX_PACKET_EXCEEDED;
|
187
187
|
}
|
188
188
|
|
@@ -248,8 +248,9 @@ static int read_auth_switch_packet(trilogy_conn_t *conn, trilogy_handshake_t *ha
|
|
248
248
|
}
|
249
249
|
|
250
250
|
if (strcmp("mysql_native_password", auth_switch_packet.auth_plugin) &&
|
251
|
-
strcmp("caching_sha2_password", auth_switch_packet.auth_plugin)
|
252
|
-
|
251
|
+
strcmp("caching_sha2_password", auth_switch_packet.auth_plugin) &&
|
252
|
+
strcmp("mysql_clear_password", auth_switch_packet.auth_plugin)) {
|
253
|
+
// Only support native password, caching sha2 and cleartext password here.
|
253
254
|
return TRILOGY_PROTOCOL_VIOLATION;
|
254
255
|
}
|
255
256
|
|
@@ -258,14 +259,7 @@ static int read_auth_switch_packet(trilogy_conn_t *conn, trilogy_handshake_t *ha
|
|
258
259
|
return TRILOGY_AUTH_SWITCH;
|
259
260
|
}
|
260
261
|
|
261
|
-
static int
|
262
|
-
{
|
263
|
-
int rc = read_packet(conn);
|
264
|
-
|
265
|
-
if (rc < 0) {
|
266
|
-
return rc;
|
267
|
-
}
|
268
|
-
|
262
|
+
static int handle_generic_response(trilogy_conn_t *conn) {
|
269
263
|
switch (current_packet_type(conn)) {
|
270
264
|
case TRILOGY_PACKET_OK:
|
271
265
|
return read_ok_packet(conn);
|
@@ -278,6 +272,17 @@ static int read_generic_response(trilogy_conn_t *conn)
|
|
278
272
|
}
|
279
273
|
}
|
280
274
|
|
275
|
+
static int read_generic_response(trilogy_conn_t *conn)
|
276
|
+
{
|
277
|
+
int rc = read_packet(conn);
|
278
|
+
|
279
|
+
if (rc < 0) {
|
280
|
+
return rc;
|
281
|
+
}
|
282
|
+
|
283
|
+
return handle_generic_response(conn);
|
284
|
+
}
|
285
|
+
|
281
286
|
int trilogy_connect_send(trilogy_conn_t *conn, const trilogy_sockopt_t *opts)
|
282
287
|
{
|
283
288
|
trilogy_sock_t *sock = trilogy_sock_new(opts);
|
@@ -300,14 +305,13 @@ int trilogy_connect_send_socket(trilogy_conn_t *conn, trilogy_sock_t *sock)
|
|
300
305
|
return rc;
|
301
306
|
|
302
307
|
conn->socket = sock;
|
308
|
+
conn->packet_parser.sequence_number = 0;
|
309
|
+
|
303
310
|
return TRILOGY_OK;
|
304
311
|
}
|
305
312
|
|
306
313
|
int trilogy_connect_recv(trilogy_conn_t *conn, trilogy_handshake_t *handshake_out)
|
307
314
|
{
|
308
|
-
// reset the sequence number with each connect recv attempt
|
309
|
-
conn->packet_parser.sequence_number = 0;
|
310
|
-
|
311
315
|
int rc = read_packet(conn);
|
312
316
|
|
313
317
|
if (rc < 0) {
|
@@ -336,9 +340,8 @@ int trilogy_connect_recv(trilogy_conn_t *conn, trilogy_handshake_t *handshake_ou
|
|
336
340
|
int trilogy_auth_send(trilogy_conn_t *conn, const trilogy_handshake_t *handshake)
|
337
341
|
{
|
338
342
|
trilogy_builder_t builder;
|
339
|
-
bool use_ssl = (conn->socket->opts.flags & TRILOGY_CAPABILITIES_SSL) != 0;
|
340
343
|
|
341
|
-
int rc = begin_command_phase(&builder, conn,
|
344
|
+
int rc = begin_command_phase(&builder, conn, conn->packet_parser.sequence_number);
|
342
345
|
|
343
346
|
if (rc < 0) {
|
344
347
|
return rc;
|
@@ -360,7 +363,7 @@ int trilogy_ssl_request_send(trilogy_conn_t *conn)
|
|
360
363
|
{
|
361
364
|
trilogy_builder_t builder;
|
362
365
|
|
363
|
-
int rc = begin_command_phase(&builder, conn,
|
366
|
+
int rc = begin_command_phase(&builder, conn, conn->packet_parser.sequence_number);
|
364
367
|
|
365
368
|
if (rc < 0) {
|
366
369
|
return rc;
|
@@ -380,8 +383,7 @@ int trilogy_auth_switch_send(trilogy_conn_t *conn, const trilogy_handshake_t *ha
|
|
380
383
|
{
|
381
384
|
trilogy_builder_t builder;
|
382
385
|
|
383
|
-
|
384
|
-
int rc = begin_command_phase(&builder, conn, use_ssl ? 4 : 3);
|
386
|
+
int rc = begin_command_phase(&builder, conn, conn->packet_parser.sequence_number);
|
385
387
|
|
386
388
|
if (rc < 0) {
|
387
389
|
return rc;
|
@@ -389,7 +391,7 @@ int trilogy_auth_switch_send(trilogy_conn_t *conn, const trilogy_handshake_t *ha
|
|
389
391
|
|
390
392
|
rc = trilogy_build_auth_switch_response_packet(&builder, conn->socket->opts.password,
|
391
393
|
conn->socket->opts.password_len, handshake->auth_plugin,
|
392
|
-
handshake->scramble);
|
394
|
+
handshake->scramble, conn->socket->opts.enable_cleartext_plugin);
|
393
395
|
|
394
396
|
if (rc < 0) {
|
395
397
|
return rc;
|
@@ -405,6 +407,9 @@ void trilogy_auth_clear_password(trilogy_conn_t *conn)
|
|
405
407
|
}
|
406
408
|
}
|
407
409
|
|
410
|
+
#define FAST_AUTH_OK 3
|
411
|
+
#define FAST_AUTH_FAIL 4
|
412
|
+
|
408
413
|
int trilogy_auth_recv(trilogy_conn_t *conn, trilogy_handshake_t *handshake)
|
409
414
|
{
|
410
415
|
int rc = read_packet(conn);
|
@@ -414,13 +419,69 @@ int trilogy_auth_recv(trilogy_conn_t *conn, trilogy_handshake_t *handshake)
|
|
414
419
|
}
|
415
420
|
|
416
421
|
switch (current_packet_type(conn)) {
|
417
|
-
case
|
418
|
-
|
419
|
-
|
422
|
+
case TRILOGY_PACKET_AUTH_MORE_DATA: {
|
423
|
+
bool use_ssl = (conn->socket->opts.flags & TRILOGY_CAPABILITIES_SSL) != 0;
|
424
|
+
bool has_unix_socket = (conn->socket->opts.path != NULL);
|
420
425
|
|
421
|
-
|
426
|
+
if (!use_ssl && !has_unix_socket) {
|
427
|
+
return TRILOGY_UNSUPPORTED;
|
428
|
+
}
|
429
|
+
|
430
|
+
uint8_t byte = conn->packet_buffer.buff[1];
|
431
|
+
switch (byte) {
|
432
|
+
case FAST_AUTH_OK:
|
433
|
+
break;
|
434
|
+
case FAST_AUTH_FAIL:
|
435
|
+
{
|
436
|
+
trilogy_builder_t builder;
|
437
|
+
int err = begin_command_phase(&builder, conn, conn->packet_parser.sequence_number);
|
438
|
+
|
439
|
+
if (err < 0) {
|
440
|
+
return err;
|
441
|
+
}
|
442
|
+
|
443
|
+
err = trilogy_build_auth_clear_password(&builder, conn->socket->opts.password, conn->socket->opts.password_len);
|
444
|
+
|
445
|
+
if (err < 0) {
|
446
|
+
return err;
|
447
|
+
}
|
448
|
+
|
449
|
+
int rc = begin_write(conn);
|
450
|
+
|
451
|
+
while (rc == TRILOGY_AGAIN) {
|
452
|
+
rc = trilogy_sock_wait_write(conn->socket);
|
453
|
+
if (rc != TRILOGY_OK) {
|
454
|
+
return rc;
|
455
|
+
}
|
456
|
+
|
457
|
+
rc = trilogy_flush_writes(conn);
|
458
|
+
}
|
459
|
+
if (rc != TRILOGY_OK) {
|
460
|
+
return rc;
|
461
|
+
}
|
462
|
+
|
463
|
+
break;
|
464
|
+
}
|
465
|
+
default:
|
466
|
+
return TRILOGY_UNEXPECTED_PACKET;
|
467
|
+
}
|
468
|
+
while (1) {
|
469
|
+
rc = read_packet(conn);
|
470
|
+
|
471
|
+
if (rc == TRILOGY_OK) {
|
472
|
+
break;
|
473
|
+
}
|
474
|
+
else if (rc == TRILOGY_AGAIN) {
|
475
|
+
rc = trilogy_sock_wait_read(conn->socket);
|
476
|
+
}
|
477
|
+
|
478
|
+
if (rc != TRILOGY_OK) {
|
479
|
+
return rc;
|
480
|
+
}
|
481
|
+
}
|
422
482
|
trilogy_auth_clear_password(conn);
|
423
|
-
return
|
483
|
+
return handle_generic_response(conn);
|
484
|
+
}
|
424
485
|
|
425
486
|
case TRILOGY_PACKET_EOF:
|
426
487
|
// EOF is returned here if an auth switch is requested.
|
@@ -428,9 +489,11 @@ int trilogy_auth_recv(trilogy_conn_t *conn, trilogy_handshake_t *handshake)
|
|
428
489
|
// in a follow up call to this function after the switch.
|
429
490
|
return read_auth_switch_packet(conn, handshake);
|
430
491
|
|
492
|
+
case TRILOGY_PACKET_OK:
|
493
|
+
case TRILOGY_PACKET_ERR:
|
431
494
|
default:
|
432
495
|
trilogy_auth_clear_password(conn);
|
433
|
-
return
|
496
|
+
return handle_generic_response(conn);
|
434
497
|
}
|
435
498
|
|
436
499
|
return read_generic_response(conn);
|
@@ -593,28 +593,48 @@ int trilogy_build_auth_packet(trilogy_builder_t *builder, const char *user, cons
|
|
593
593
|
|
594
594
|
trilogy_builder_finalize(builder);
|
595
595
|
|
596
|
-
|
596
|
+
fail:
|
597
|
+
return rc;
|
598
|
+
}
|
599
|
+
|
600
|
+
int trilogy_build_auth_clear_password(trilogy_builder_t *builder, const char *pass, size_t pass_len) {
|
601
|
+
int rc = TRILOGY_OK;
|
602
|
+
|
603
|
+
CHECKED(trilogy_builder_write_buffer(builder, pass, pass_len));
|
604
|
+
CHECKED(trilogy_builder_write_uint8(builder, 0));
|
605
|
+
trilogy_builder_finalize(builder);
|
597
606
|
|
598
607
|
fail:
|
599
608
|
return rc;
|
600
609
|
}
|
601
610
|
|
602
611
|
int trilogy_build_auth_switch_response_packet(trilogy_builder_t *builder, const char *pass, size_t pass_len,
|
603
|
-
const char *auth_plugin, const char *scramble)
|
612
|
+
const char *auth_plugin, const char *scramble, const bool enable_cleartext_plugin)
|
604
613
|
{
|
605
614
|
int rc = TRILOGY_OK;
|
606
615
|
unsigned int auth_response_len = 0;
|
607
616
|
uint8_t auth_response[EVP_MAX_MD_SIZE];
|
608
617
|
|
609
618
|
if (pass_len > 0) {
|
610
|
-
if (!strcmp("
|
611
|
-
|
619
|
+
if (!strcmp("mysql_clear_password", auth_plugin)) {
|
620
|
+
if (enable_cleartext_plugin) {
|
621
|
+
CHECKED(trilogy_builder_write_buffer(builder, pass, pass_len));
|
622
|
+
} else {
|
623
|
+
return TRILOGY_AUTH_PLUGIN_ERROR;
|
624
|
+
}
|
612
625
|
} else {
|
613
|
-
|
626
|
+
if (!strcmp("caching_sha2_password", auth_plugin)) {
|
627
|
+
trilogy_pack_scramble_sha2_hash(scramble, pass, pass_len, auth_response, &auth_response_len);
|
628
|
+
} else if (!strcmp("mysql_native_password", auth_plugin)) {
|
629
|
+
trilogy_pack_scramble_native_hash(scramble, pass, pass_len, auth_response, &auth_response_len);
|
630
|
+
} else {
|
631
|
+
return TRILOGY_AUTH_PLUGIN_ERROR;
|
632
|
+
}
|
633
|
+
|
634
|
+
CHECKED(trilogy_builder_write_buffer(builder, auth_response, auth_response_len));
|
614
635
|
}
|
615
636
|
}
|
616
637
|
|
617
|
-
CHECKED(trilogy_builder_write_buffer(builder, auth_response, auth_response_len));
|
618
638
|
trilogy_builder_finalize(builder);
|
619
639
|
|
620
640
|
return TRILOGY_OK;
|
@@ -906,6 +926,8 @@ int trilogy_build_stmt_execute_packet(trilogy_builder_t *builder, uint32_t stmt_
|
|
906
926
|
case TRILOGY_TYPE_VAR_STRING:
|
907
927
|
case TRILOGY_TYPE_STRING:
|
908
928
|
case TRILOGY_TYPE_GEOMETRY:
|
929
|
+
case TRILOGY_TYPE_JSON:
|
930
|
+
case TRILOGY_TYPE_VECTOR:
|
909
931
|
CHECKED(trilogy_builder_write_lenenc_buffer(builder, val.as.str.data, val.as.str.len));
|
910
932
|
|
911
933
|
break;
|
@@ -1039,6 +1061,7 @@ int trilogy_parse_stmt_row_packet(const uint8_t *buff, size_t len, trilogy_colum
|
|
1039
1061
|
case TRILOGY_TYPE_DECIMAL:
|
1040
1062
|
case TRILOGY_TYPE_NEWDECIMAL:
|
1041
1063
|
case TRILOGY_TYPE_JSON:
|
1064
|
+
case TRILOGY_TYPE_VECTOR:
|
1042
1065
|
CHECKED(trilogy_reader_get_lenenc_buffer(&reader, &out_values[i].as.str.len,
|
1043
1066
|
(const void **)&out_values[i].as.str.data));
|
1044
1067
|
|
@@ -40,6 +40,7 @@ static int _cb_wait(trilogy_sock_t *_sock, trilogy_wait_t wait)
|
|
40
40
|
case TRILOGY_WAIT_READ:
|
41
41
|
pfd.events = POLLIN;
|
42
42
|
break;
|
43
|
+
case TRILOGY_WAIT_CONNECT:
|
43
44
|
case TRILOGY_WAIT_WRITE:
|
44
45
|
pfd.events = POLLOUT;
|
45
46
|
break;
|
@@ -252,7 +253,7 @@ static int raw_connect_internal(struct trilogy_sock *sock, const struct addrinfo
|
|
252
253
|
}
|
253
254
|
}
|
254
255
|
|
255
|
-
if ((rc =
|
256
|
+
if ((rc = trilogy_sock_wait((trilogy_sock_t *)sock, TRILOGY_WAIT_CONNECT)) < 0) {
|
256
257
|
goto failrc;
|
257
258
|
}
|
258
259
|
|
@@ -724,3 +725,25 @@ fail:
|
|
724
725
|
sock->ssl = NULL;
|
725
726
|
return TRILOGY_OPENSSL_ERR;
|
726
727
|
}
|
728
|
+
|
729
|
+
int trilogy_sock_check(trilogy_sock_t *_sock)
|
730
|
+
{
|
731
|
+
struct trilogy_sock *sock = (struct trilogy_sock *)_sock;
|
732
|
+
char buf[1];
|
733
|
+
while (1) {
|
734
|
+
ssize_t data_read = recv(sock->fd, buf, 1, MSG_PEEK);
|
735
|
+
if (data_read > 0) {
|
736
|
+
return TRILOGY_OK;
|
737
|
+
}
|
738
|
+
if (data_read == 0) {
|
739
|
+
return TRILOGY_CLOSED_CONNECTION;
|
740
|
+
}
|
741
|
+
if (errno == EINTR) {
|
742
|
+
continue;
|
743
|
+
}
|
744
|
+
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
745
|
+
return TRILOGY_OK;
|
746
|
+
}
|
747
|
+
return TRILOGY_SYSERR;
|
748
|
+
}
|
749
|
+
}
|
data/lib/trilogy/error.rb
CHANGED
@@ -12,7 +12,7 @@ class Trilogy
|
|
12
12
|
end
|
13
13
|
|
14
14
|
# Trilogy may raise various syscall errors, which we treat as Trilogy::Errors.
|
15
|
-
|
15
|
+
module SyscallError
|
16
16
|
ERRORS = {}
|
17
17
|
|
18
18
|
Errno.constants
|
@@ -20,7 +20,10 @@ class Trilogy
|
|
20
20
|
.select { |c| c.is_a?(Class) && c < SystemCallError }
|
21
21
|
.each do |c|
|
22
22
|
errno_name = c.to_s.split('::').last
|
23
|
-
ERRORS[c::Errno] = const_set(errno_name, Class.new(c) {
|
23
|
+
ERRORS[c::Errno] = const_set(errno_name, Class.new(c) {
|
24
|
+
include Trilogy::ConnectionError
|
25
|
+
singleton_class.define_method(:===, Module.instance_method(:===))
|
26
|
+
})
|
24
27
|
end
|
25
28
|
|
26
29
|
ERRORS.freeze
|
@@ -32,6 +35,11 @@ class Trilogy
|
|
32
35
|
end
|
33
36
|
end
|
34
37
|
|
38
|
+
ConnectionRefusedError = SyscallError::ECONNREFUSED
|
39
|
+
deprecate_constant :ConnectionRefusedError
|
40
|
+
ConnectionResetError = SyscallError::ECONNRESET
|
41
|
+
deprecate_constant :ConnectionResetError
|
42
|
+
|
35
43
|
class BaseError < StandardError
|
36
44
|
include Error
|
37
45
|
|
@@ -58,21 +66,7 @@ class Trilogy
|
|
58
66
|
class CastError < ClientError
|
59
67
|
end
|
60
68
|
|
61
|
-
class TimeoutError <
|
62
|
-
include ConnectionError
|
63
|
-
|
64
|
-
def initialize(error_message = nil, error_code = nil)
|
65
|
-
super
|
66
|
-
@error_code = error_code
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
class ConnectionRefusedError < Errno::ECONNREFUSED
|
71
|
-
include ConnectionError
|
72
|
-
end
|
73
|
-
|
74
|
-
class ConnectionResetError < Errno::ECONNRESET
|
75
|
-
include ConnectionError
|
69
|
+
class TimeoutError < BaseConnectionError
|
76
70
|
end
|
77
71
|
|
78
72
|
# DatabaseError was replaced by ProtocolError, but we'll keep it around as an
|
@@ -121,4 +115,9 @@ class Trilogy
|
|
121
115
|
# attempted on a socket which previously encountered an error.
|
122
116
|
class EOFError < BaseConnectionError
|
123
117
|
end
|
118
|
+
|
119
|
+
# Occurs when the server request an auth switch to an incompatible
|
120
|
+
# authentication plugin
|
121
|
+
class AuthPluginError < Trilogy::BaseConnectionError
|
122
|
+
end
|
124
123
|
end
|
data/lib/trilogy/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: trilogy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- GitHub Engineering
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-10-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|
@@ -102,7 +102,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
102
102
|
- !ruby/object:Gem::Version
|
103
103
|
version: '0'
|
104
104
|
requirements: []
|
105
|
-
rubygems_version: 3.
|
105
|
+
rubygems_version: 3.5.11
|
106
106
|
signing_key:
|
107
107
|
specification_version: 4
|
108
108
|
summary: A friendly MySQL-compatible library for Ruby, binding to libtrilogy
|