trilogy 2.7.0 → 2.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f36747c1d61f440a5ff6b5d37981b0a11ad26a1b973ebeb9bab84e832b2841a3
4
- data.tar.gz: b654bac6dbc4d3451c5101e9f8574de4aee4044d6aa280c0736e3e18ad09c723
3
+ metadata.gz: dc0ed0331bd27abe2cf82b8c1e334dbd0d68ac93ae2bbd73fac5fe12874ee324
4
+ data.tar.gz: 457d93059c16e539c9b79f901269476f9380b0141e13edfd0624a0de6b5e06d1
5
5
  SHA512:
6
- metadata.gz: 81aefe81cfe750d70a42915c6a16f6d7211455b255a6588088c8ac6c682240636df5c2269b7090e78ba2ce6f991e3266f1c2b57711130e84fde85a8d38b22a1c
7
- data.tar.gz: 3df0441086b141c6c0ebb0d3a216d14205547bd340c06cf0884e1985ac6550023ea8960200c5afe31821160883a3cd96a07a942efb05a9d335153dcdafa83976
6
+ metadata.gz: d77b2c84b0fec65762a591e3685ac50f8a031cb74a7fee90ca4b1bf02173a8abd2d6c7b9be410c0bab7b71b6e85c5c13de8db21bddb93eb265aeeda395184f46
7
+ data.tar.gz: 668737a977f8d831fbb1509e4e9695e0d3ca83e7a60859a485d3ae7bed0d4c2659994fd0d33ac12cf73a74b09400a3ef7ee631e9c7bc3cccfcfb70b19dff745b
@@ -18,12 +18,12 @@
18
18
  VALUE Trilogy_CastError;
19
19
  static VALUE Trilogy_BaseConnectionError, Trilogy_ProtocolError, Trilogy_SSLError, Trilogy_QueryError,
20
20
  Trilogy_ConnectionClosedError,
21
- Trilogy_TimeoutError, Trilogy_SyscallError, Trilogy_Result, Trilogy_EOFError;
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
 
@@ -156,6 +156,14 @@ static void handle_trilogy_error(struct trilogy_ctx *ctx, int rc, const char *ms
156
156
  rb_raise(Trilogy_EOFError, "%" PRIsVALUE ": TRILOGY_CLOSED_CONNECTION", rbmsg);
157
157
  }
158
158
 
159
+ case TRILOGY_AUTH_PLUGIN_ERROR: {
160
+ rb_raise(Trilogy_AuthPluginError, "%" PRIsVALUE ": TRILOGY_AUTH_PLUGIN_ERROR", rbmsg);
161
+ }
162
+
163
+ case TRILOGY_UNSUPPORTED: {
164
+ rb_raise(Trilogy_BaseConnectionError, "%" PRIsVALUE ": TRILOGY_UNSUPPORTED", rbmsg);
165
+ }
166
+
159
167
  default:
160
168
  rb_raise(Trilogy_QueryError, "%" PRIsVALUE ": %s", rbmsg, trilogy_error(rc));
161
169
  }
@@ -239,7 +247,18 @@ static int _cb_ruby_wait(trilogy_sock_t *sock, trilogy_wait_t wait)
239
247
  wait_flag = RB_WAITFD_OUT;
240
248
  break;
241
249
 
250
+ case TRILOGY_WAIT_CONNECT:
251
+ // wait for connection to be writable
252
+ timeout = &sock->opts.connect_timeout;
253
+ if (timeout->tv_sec == 0 && timeout->tv_usec == 0) {
254
+ // We used to use the write timeout for this, so if a connect timeout isn't configured, default to that.
255
+ timeout = &sock->opts.write_timeout;
256
+ }
257
+ wait_flag = RB_WAITFD_OUT;
258
+ break;
259
+
242
260
  case TRILOGY_WAIT_HANDSHAKE:
261
+ // wait for handshake packet on initial connection
243
262
  timeout = &sock->opts.connect_timeout;
244
263
  wait_flag = RB_WAITFD_IN;
245
264
  break;
@@ -408,7 +427,12 @@ static void authenticate(struct trilogy_ctx *ctx, trilogy_handshake_t *handshake
408
427
  }
409
428
 
410
429
  if (rc != TRILOGY_AGAIN) {
411
- handle_trilogy_error(ctx, rc, "trilogy_auth_recv");
430
+ if (rc == TRILOGY_UNSUPPORTED) {
431
+ handle_trilogy_error(ctx, rc, "trilogy_auth_recv: caching_sha2_password requires either TCP with TLS or a unix socket");
432
+ }
433
+ else {
434
+ handle_trilogy_error(ctx, rc, "trilogy_auth_recv");
435
+ }
412
436
  }
413
437
 
414
438
  rc = trilogy_sock_wait_read(ctx->conn.socket);
@@ -511,6 +535,10 @@ static VALUE rb_trilogy_connect(VALUE self, VALUE encoding, VALUE charset, VALUE
511
535
  connopt.flags |= TRILOGY_CAPABILITIES_CONNECT_WITH_DB;
512
536
  }
513
537
 
538
+ if (RTEST(rb_hash_aref(opts, ID2SYM(id_enable_cleartext_plugin)))) {
539
+ connopt.enable_cleartext_plugin = true;
540
+ }
541
+
514
542
  if (RTEST(rb_hash_aref(opts, ID2SYM(id_found_rows)))) {
515
543
  connopt.flags |= TRILOGY_CAPABILITIES_FOUND_ROWS;
516
544
  }
@@ -1014,6 +1042,17 @@ static VALUE rb_trilogy_closed(VALUE self)
1014
1042
  }
1015
1043
  }
1016
1044
 
1045
+ static VALUE rb_trilogy_check(VALUE self)
1046
+ {
1047
+ struct trilogy_ctx *ctx = get_open_ctx(self);
1048
+
1049
+ int rc = trilogy_sock_check(ctx->conn.socket);
1050
+ if (rc != TRILOGY_OK && rc != TRILOGY_AGAIN) {
1051
+ handle_trilogy_error(ctx, rc, "trilogy_sock_check");
1052
+ }
1053
+ return Qtrue;
1054
+ }
1055
+
1017
1056
  static VALUE rb_trilogy_discard(VALUE self)
1018
1057
  {
1019
1058
  struct trilogy_ctx *ctx = get_ctx(self);
@@ -1092,7 +1131,7 @@ static VALUE rb_trilogy_server_status(VALUE self) { return LONG2FIX(get_open_ctx
1092
1131
 
1093
1132
  static VALUE rb_trilogy_server_version(VALUE self) { return rb_str_new_cstr(get_open_ctx(self)->server_version); }
1094
1133
 
1095
- RUBY_FUNC_EXPORTED void Init_cext()
1134
+ RUBY_FUNC_EXPORTED void Init_cext(void)
1096
1135
  {
1097
1136
  VALUE Trilogy = rb_const_get(rb_cObject, rb_intern("Trilogy"));
1098
1137
  rb_define_alloc_func(Trilogy, allocate_trilogy);
@@ -1105,6 +1144,7 @@ RUBY_FUNC_EXPORTED void Init_cext()
1105
1144
  rb_define_method(Trilogy, "escape", rb_trilogy_escape, 1);
1106
1145
  rb_define_method(Trilogy, "close", rb_trilogy_close, 0);
1107
1146
  rb_define_method(Trilogy, "closed?", rb_trilogy_closed, 0);
1147
+ rb_define_method(Trilogy, "check", rb_trilogy_check, 0);
1108
1148
  rb_define_method(Trilogy, "discard!", rb_trilogy_discard, 0);
1109
1149
  rb_define_method(Trilogy, "last_insert_id", rb_trilogy_last_insert_id, 0);
1110
1150
  rb_define_method(Trilogy, "affected_rows", rb_trilogy_affected_rows, 0);
@@ -1170,6 +1210,9 @@ RUBY_FUNC_EXPORTED void Init_cext()
1170
1210
  Trilogy_EOFError = rb_const_get(Trilogy, rb_intern("EOFError"));
1171
1211
  rb_global_variable(&Trilogy_EOFError);
1172
1212
 
1213
+ rb_global_variable(&Trilogy_AuthPluginError);
1214
+ Trilogy_AuthPluginError = rb_const_get(Trilogy, rb_intern("AuthPluginError"));
1215
+
1173
1216
  id_socket = rb_intern("socket");
1174
1217
  id_host = rb_intern("host");
1175
1218
  id_port = rb_intern("port");
@@ -1185,6 +1228,7 @@ RUBY_FUNC_EXPORTED void Init_cext()
1185
1228
  id_keepalive_count = rb_intern("keepalive_count");
1186
1229
  id_keepalive_interval = rb_intern("keepalive_interval");
1187
1230
  id_database = rb_intern("database");
1231
+ id_enable_cleartext_plugin = rb_intern("enable_cleartext_plugin");
1188
1232
  id_ssl_ca = rb_intern("ssl_ca");
1189
1233
  id_ssl_capath = rb_intern("ssl_capath");
1190
1234
  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,
@@ -367,6 +367,7 @@ typedef enum {
367
367
  // Typical response packet types
368
368
  typedef enum {
369
369
  TRILOGY_PACKET_OK = 0x0,
370
+ TRILOGY_PACKET_AUTH_MORE_DATA = 0x01,
370
371
  TRILOGY_PACKET_EOF = 0xfe,
371
372
  TRILOGY_PACKET_ERR = 0xff,
372
373
  TRILOGY_PACKET_UNKNOWN
@@ -442,14 +443,16 @@ int trilogy_build_auth_packet(trilogy_builder_t *builder, const char *user, cons
442
443
  * pass_len - The length of password in bytes.
443
444
  * auth_plugin - Plugin authentication mechanism that the server requested.
444
445
  * scramble - The scramble value received from the server.
446
+ * enable_cleartext_plugin - Send cleartext password if requested by server.
445
447
  *
446
448
  * Return values:
447
449
  * TRILOGY_OK - The packet was successfully built and written to the
448
450
  * builder's internal buffer.
449
451
  * TRILOGY_SYSERR - A system error occurred, check errno.
452
+ * TRILOGY_AUTH_PLUGIN_ERROR - The server requested auth plugin is not supported.
450
453
  */
451
454
  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);
455
+ const char *auth_plugin, const char *scramble, const bool enable_cleartext_plugin);
453
456
 
454
457
  /* trilogy_build_change_db_packet - Build a change database command packet. This
455
458
  * command will change the default database for the connection.
@@ -1035,4 +1038,6 @@ int trilogy_parse_stmt_ok_packet(const uint8_t *buff, size_t len, trilogy_stmt_o
1035
1038
  int trilogy_parse_stmt_row_packet(const uint8_t *buff, size_t len, trilogy_column_packet_t *columns,
1036
1039
  uint64_t column_count, trilogy_binary_value_t *out_values);
1037
1040
 
1041
+ int trilogy_build_auth_clear_password(trilogy_builder_t *builder, const char *pass, size_t pass_len);
1042
+
1038
1043
  #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
@@ -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
- // Only support native password & caching sha2 password here.
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 read_generic_response(trilogy_conn_t *conn)
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);
@@ -336,9 +341,8 @@ int trilogy_connect_recv(trilogy_conn_t *conn, trilogy_handshake_t *handshake_ou
336
341
  int trilogy_auth_send(trilogy_conn_t *conn, const trilogy_handshake_t *handshake)
337
342
  {
338
343
  trilogy_builder_t builder;
339
- bool use_ssl = (conn->socket->opts.flags & TRILOGY_CAPABILITIES_SSL) != 0;
340
344
 
341
- int rc = begin_command_phase(&builder, conn, use_ssl ? 2 : 1);
345
+ int rc = begin_command_phase(&builder, conn, conn->packet_parser.sequence_number);
342
346
 
343
347
  if (rc < 0) {
344
348
  return rc;
@@ -360,7 +364,7 @@ int trilogy_ssl_request_send(trilogy_conn_t *conn)
360
364
  {
361
365
  trilogy_builder_t builder;
362
366
 
363
- int rc = begin_command_phase(&builder, conn, 1);
367
+ int rc = begin_command_phase(&builder, conn, conn->packet_parser.sequence_number);
364
368
 
365
369
  if (rc < 0) {
366
370
  return rc;
@@ -380,8 +384,7 @@ int trilogy_auth_switch_send(trilogy_conn_t *conn, const trilogy_handshake_t *ha
380
384
  {
381
385
  trilogy_builder_t builder;
382
386
 
383
- bool use_ssl = (conn->socket->opts.flags & TRILOGY_CAPABILITIES_SSL) != 0;
384
- int rc = begin_command_phase(&builder, conn, use_ssl ? 4 : 3);
387
+ int rc = begin_command_phase(&builder, conn, conn->packet_parser.sequence_number);
385
388
 
386
389
  if (rc < 0) {
387
390
  return rc;
@@ -389,7 +392,7 @@ int trilogy_auth_switch_send(trilogy_conn_t *conn, const trilogy_handshake_t *ha
389
392
 
390
393
  rc = trilogy_build_auth_switch_response_packet(&builder, conn->socket->opts.password,
391
394
  conn->socket->opts.password_len, handshake->auth_plugin,
392
- handshake->scramble);
395
+ handshake->scramble, conn->socket->opts.enable_cleartext_plugin);
393
396
 
394
397
  if (rc < 0) {
395
398
  return rc;
@@ -405,6 +408,9 @@ void trilogy_auth_clear_password(trilogy_conn_t *conn)
405
408
  }
406
409
  }
407
410
 
411
+ #define FAST_AUTH_OK 3
412
+ #define FAST_AUTH_FAIL 4
413
+
408
414
  int trilogy_auth_recv(trilogy_conn_t *conn, trilogy_handshake_t *handshake)
409
415
  {
410
416
  int rc = read_packet(conn);
@@ -414,13 +420,69 @@ int trilogy_auth_recv(trilogy_conn_t *conn, trilogy_handshake_t *handshake)
414
420
  }
415
421
 
416
422
  switch (current_packet_type(conn)) {
417
- case TRILOGY_PACKET_OK:
418
- trilogy_auth_clear_password(conn);
419
- return read_ok_packet(conn);
423
+ case TRILOGY_PACKET_AUTH_MORE_DATA: {
424
+ bool use_ssl = (conn->socket->opts.flags & TRILOGY_CAPABILITIES_SSL) != 0;
425
+ bool has_unix_socket = (conn->socket->opts.path != NULL);
420
426
 
421
- case TRILOGY_PACKET_ERR:
427
+ if (!use_ssl && !has_unix_socket) {
428
+ return TRILOGY_UNSUPPORTED;
429
+ }
430
+
431
+ uint8_t byte = conn->packet_buffer.buff[1];
432
+ switch (byte) {
433
+ case FAST_AUTH_OK:
434
+ break;
435
+ case FAST_AUTH_FAIL:
436
+ {
437
+ trilogy_builder_t builder;
438
+ int err = begin_command_phase(&builder, conn, conn->packet_parser.sequence_number);
439
+
440
+ if (err < 0) {
441
+ return err;
442
+ }
443
+
444
+ err = trilogy_build_auth_clear_password(&builder, conn->socket->opts.password, conn->socket->opts.password_len);
445
+
446
+ if (err < 0) {
447
+ return err;
448
+ }
449
+
450
+ int rc = begin_write(conn);
451
+
452
+ while (rc == TRILOGY_AGAIN) {
453
+ rc = trilogy_sock_wait_write(conn->socket);
454
+ if (rc != TRILOGY_OK) {
455
+ return rc;
456
+ }
457
+
458
+ rc = trilogy_flush_writes(conn);
459
+ }
460
+ if (rc != TRILOGY_OK) {
461
+ return rc;
462
+ }
463
+
464
+ break;
465
+ }
466
+ default:
467
+ return TRILOGY_UNEXPECTED_PACKET;
468
+ }
469
+ while (1) {
470
+ rc = read_packet(conn);
471
+
472
+ if (rc == TRILOGY_OK) {
473
+ break;
474
+ }
475
+ else if (rc == TRILOGY_AGAIN) {
476
+ rc = trilogy_sock_wait_read(conn->socket);
477
+ }
478
+
479
+ if (rc != TRILOGY_OK) {
480
+ return rc;
481
+ }
482
+ }
422
483
  trilogy_auth_clear_password(conn);
423
- return read_err_packet(conn);
484
+ return handle_generic_response(conn);
485
+ }
424
486
 
425
487
  case TRILOGY_PACKET_EOF:
426
488
  // EOF is returned here if an auth switch is requested.
@@ -428,9 +490,11 @@ int trilogy_auth_recv(trilogy_conn_t *conn, trilogy_handshake_t *handshake)
428
490
  // in a follow up call to this function after the switch.
429
491
  return read_auth_switch_packet(conn, handshake);
430
492
 
493
+ case TRILOGY_PACKET_OK:
494
+ case TRILOGY_PACKET_ERR:
431
495
  default:
432
496
  trilogy_auth_clear_password(conn);
433
- return TRILOGY_UNEXPECTED_PACKET;
497
+ return handle_generic_response(conn);
434
498
  }
435
499
 
436
500
  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
- return TRILOGY_OK;
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("caching_sha2_password", auth_plugin)) {
611
- trilogy_pack_scramble_sha2_hash(scramble, pass, pass_len, auth_response, &auth_response_len);
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
- trilogy_pack_scramble_native_hash(scramble, pass, pass_len, auth_response, &auth_response_len);
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;
@@ -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 = trilogy_sock_wait_write((trilogy_sock_t *)sock)) < 0) {
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
@@ -115,4 +115,9 @@ class Trilogy
115
115
  # attempted on a socket which previously encountered an error.
116
116
  class EOFError < BaseConnectionError
117
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
118
123
  end
@@ -1,3 +1,3 @@
1
1
  class Trilogy
2
- VERSION = "2.7.0"
2
+ VERSION = "2.8.0"
3
3
  end
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.7.0
4
+ version: 2.8.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-01-23 00:00:00.000000000 Z
11
+ date: 2024-04-09 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.4.7
105
+ rubygems_version: 3.5.3
106
106
  signing_key:
107
107
  specification_version: 4
108
108
  summary: A friendly MySQL-compatible library for Ruby, binding to libtrilogy