trilogy 2.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of trilogy might be problematic. Click here for more details.

Files changed (37) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +22 -0
  3. data/README.md +74 -0
  4. data/Rakefile +18 -0
  5. data/ext/trilogy-ruby/cast.c +272 -0
  6. data/ext/trilogy-ruby/cext.c +933 -0
  7. data/ext/trilogy-ruby/extconf.rb +16 -0
  8. data/ext/trilogy-ruby/inc/trilogy/blocking.h +163 -0
  9. data/ext/trilogy-ruby/inc/trilogy/buffer.h +64 -0
  10. data/ext/trilogy-ruby/inc/trilogy/builder.h +161 -0
  11. data/ext/trilogy-ruby/inc/trilogy/charset.h +277 -0
  12. data/ext/trilogy-ruby/inc/trilogy/client.h +546 -0
  13. data/ext/trilogy-ruby/inc/trilogy/error.h +43 -0
  14. data/ext/trilogy-ruby/inc/trilogy/packet_parser.h +34 -0
  15. data/ext/trilogy-ruby/inc/trilogy/protocol.h +756 -0
  16. data/ext/trilogy-ruby/inc/trilogy/reader.h +212 -0
  17. data/ext/trilogy-ruby/inc/trilogy/socket.h +111 -0
  18. data/ext/trilogy-ruby/inc/trilogy/vendor/curl_hostcheck.h +29 -0
  19. data/ext/trilogy-ruby/inc/trilogy/vendor/openssl_hostname_validation.h +51 -0
  20. data/ext/trilogy-ruby/inc/trilogy.h +8 -0
  21. data/ext/trilogy-ruby/src/blocking.c +241 -0
  22. data/ext/trilogy-ruby/src/buffer.c +60 -0
  23. data/ext/trilogy-ruby/src/builder.c +198 -0
  24. data/ext/trilogy-ruby/src/charset.c +212 -0
  25. data/ext/trilogy-ruby/src/client.c +728 -0
  26. data/ext/trilogy-ruby/src/error.c +17 -0
  27. data/ext/trilogy-ruby/src/packet_parser.c +140 -0
  28. data/ext/trilogy-ruby/src/protocol.c +676 -0
  29. data/ext/trilogy-ruby/src/reader.c +244 -0
  30. data/ext/trilogy-ruby/src/socket.c +623 -0
  31. data/ext/trilogy-ruby/src/vendor/curl_hostcheck.c +206 -0
  32. data/ext/trilogy-ruby/src/vendor/openssl_hostname_validation.c +175 -0
  33. data/ext/trilogy-ruby/trilogy-ruby.h +36 -0
  34. data/lib/trilogy/version.rb +3 -0
  35. data/lib/trilogy.rb +61 -0
  36. data/trilogy.gemspec +27 -0
  37. metadata +106 -0
@@ -0,0 +1,676 @@
1
+ #include <openssl/evp.h>
2
+
3
+ #include "trilogy/builder.h"
4
+ #include "trilogy/error.h"
5
+ #include "trilogy/packet_parser.h"
6
+ #include "trilogy/protocol.h"
7
+ #include "trilogy/reader.h"
8
+
9
+ #define TRILOGY_CMD_QUIT 0x01
10
+ #define TRILOGY_CMD_CHANGE_DB 0x02
11
+ #define TRILOGY_CMD_QUERY 0x03
12
+ #define TRILOGY_CMD_PING 0x0e
13
+
14
+ #define SCRAMBLE_LEN 20
15
+
16
+ static size_t min(size_t a, size_t b)
17
+ {
18
+ if (a < b) {
19
+ return a;
20
+ } else {
21
+ return b;
22
+ }
23
+ }
24
+
25
+ #define CHECKED(expr) \
26
+ if ((rc = (expr)) < 0) { \
27
+ goto fail; \
28
+ }
29
+
30
+ int trilogy_parse_ok_packet(const uint8_t *buff, size_t len, uint32_t capabilities, trilogy_ok_packet_t *out_packet)
31
+ {
32
+ int rc;
33
+
34
+ trilogy_reader_t reader = TRILOGY_READER(buff, len);
35
+
36
+ // skip packet type
37
+ CHECKED(trilogy_reader_get_uint8(&reader, NULL));
38
+
39
+ CHECKED(trilogy_reader_get_lenenc(&reader, &out_packet->affected_rows));
40
+
41
+ CHECKED(trilogy_reader_get_lenenc(&reader, &out_packet->last_insert_id));
42
+
43
+ out_packet->status_flags = 0;
44
+ out_packet->warning_count = 0;
45
+ out_packet->txn_status_flags = 0;
46
+ out_packet->session_status = NULL;
47
+ out_packet->session_status_len = 0;
48
+ out_packet->session_state_changes = NULL;
49
+ out_packet->session_state_changes_len = 0;
50
+ out_packet->info = NULL;
51
+ out_packet->info_len = 0;
52
+ out_packet->last_gtid_len = 0;
53
+
54
+ if (capabilities & TRILOGY_CAPABILITIES_PROTOCOL_41) {
55
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_packet->status_flags));
56
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_packet->warning_count));
57
+ } else if (capabilities & TRILOGY_CAPABILITIES_TRANSACTIONS) {
58
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_packet->txn_status_flags));
59
+ }
60
+
61
+ if (capabilities & TRILOGY_CAPABILITIES_SESSION_TRACK && !trilogy_reader_eof(&reader)) {
62
+ CHECKED(trilogy_reader_get_lenenc_buffer(&reader, &out_packet->session_status_len,
63
+ (const void **)&out_packet->session_status));
64
+
65
+ if (out_packet->status_flags & TRILOGY_SERVER_STATUS_SESSION_STATE_CHANGED) {
66
+ CHECKED(trilogy_reader_get_lenenc_buffer(&reader, &out_packet->session_state_changes_len,
67
+ (const void **)&out_packet->session_state_changes));
68
+
69
+ TRILOGY_SESSION_TRACK_TYPE_t type = 0;
70
+ const char *state_info = NULL;
71
+ size_t state_info_len = 0;
72
+
73
+ trilogy_reader_t state_reader = TRILOGY_READER((const uint8_t *)out_packet->session_state_changes,
74
+ out_packet->session_state_changes_len);
75
+
76
+ while (!trilogy_reader_eof(&state_reader)) {
77
+ CHECKED(trilogy_reader_get_uint8(&state_reader, (uint8_t *)&type));
78
+ CHECKED(trilogy_reader_get_lenenc_buffer(&state_reader, &state_info_len, (const void **)&state_info));
79
+
80
+ switch (type) {
81
+ case TRILOGY_SESSION_TRACK_GTIDS: {
82
+ trilogy_reader_t gtid_reader = TRILOGY_READER((const uint8_t *)state_info, state_info_len);
83
+ // There's a type with value TRILOGY_SESSION_TRACK_GTIDS tag
84
+ // at the beginning here we can ignore since we already had
85
+ // the type one level higher as well.
86
+ CHECKED(trilogy_reader_get_uint8(&gtid_reader, NULL));
87
+ CHECKED(trilogy_reader_get_lenenc_buffer(&gtid_reader, &out_packet->last_gtid_len,
88
+ (const void **)&out_packet->last_gtid));
89
+ if (out_packet->last_gtid_len > TRILOGY_MAX_LAST_GTID_LEN) {
90
+ return TRILOGY_PROTOCOL_VIOLATION;
91
+ }
92
+ break;
93
+ }
94
+ default:
95
+ break;
96
+ }
97
+ }
98
+ }
99
+ } else {
100
+ CHECKED(trilogy_reader_get_eof_buffer(&reader, &out_packet->info_len, (const void **)&out_packet->info));
101
+ }
102
+
103
+ return trilogy_reader_finish(&reader);
104
+
105
+ fail:
106
+ return rc;
107
+ }
108
+
109
+ int trilogy_parse_eof_packet(const uint8_t *buff, size_t len, uint32_t capabilities, trilogy_eof_packet_t *out_packet)
110
+ {
111
+ int rc;
112
+
113
+ trilogy_reader_t reader = TRILOGY_READER(buff, len);
114
+
115
+ // skip packet type
116
+ CHECKED(trilogy_reader_get_uint8(&reader, NULL));
117
+
118
+ if (capabilities & TRILOGY_CAPABILITIES_PROTOCOL_41) {
119
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_packet->warning_count));
120
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_packet->status_flags));
121
+ } else {
122
+ out_packet->status_flags = 0;
123
+ out_packet->warning_count = 0;
124
+ }
125
+
126
+ return trilogy_reader_finish(&reader);
127
+
128
+ fail:
129
+ return rc;
130
+ }
131
+
132
+ int trilogy_parse_err_packet(const uint8_t *buff, size_t len, uint32_t capabilities, trilogy_err_packet_t *out_packet)
133
+ {
134
+ int rc;
135
+
136
+ trilogy_reader_t reader = TRILOGY_READER(buff, len);
137
+
138
+ // skip packet type
139
+ CHECKED(trilogy_reader_get_uint8(&reader, NULL));
140
+
141
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_packet->error_code));
142
+
143
+ if (capabilities & TRILOGY_CAPABILITIES_PROTOCOL_41) {
144
+ CHECKED(trilogy_reader_get_uint8(&reader, out_packet->sql_state_marker));
145
+ CHECKED(trilogy_reader_copy_buffer(&reader, 5, out_packet->sql_state));
146
+ } else {
147
+ memset(out_packet->sql_state_marker, 0, sizeof out_packet->sql_state_marker);
148
+ memset(out_packet->sql_state, 0, sizeof out_packet->sql_state);
149
+ }
150
+
151
+ CHECKED(trilogy_reader_get_eof_buffer(&reader, &out_packet->error_message_len,
152
+ (const void **)&out_packet->error_message));
153
+
154
+ return trilogy_reader_finish(&reader);
155
+
156
+ fail:
157
+ return rc;
158
+ }
159
+
160
+ int trilogy_parse_auth_switch_request_packet(const uint8_t *buff, size_t len, uint32_t capabilities,
161
+ trilogy_auth_switch_request_packet_t *out_packet)
162
+ {
163
+ int rc;
164
+
165
+ trilogy_reader_t reader = TRILOGY_READER(buff, len);
166
+
167
+ // skip packet type
168
+ CHECKED(trilogy_reader_get_uint8(&reader, NULL));
169
+
170
+ if (capabilities & TRILOGY_CAPABILITIES_PLUGIN_AUTH) {
171
+ const char *auth_plugin;
172
+ size_t auth_plugin_len;
173
+
174
+ CHECKED(trilogy_reader_get_string(&reader, &auth_plugin, &auth_plugin_len));
175
+ if (auth_plugin_len > sizeof(out_packet->auth_plugin) - 1) {
176
+ return TRILOGY_AUTH_PLUGIN_TOO_LONG;
177
+ }
178
+ memcpy(out_packet->auth_plugin, auth_plugin, auth_plugin_len + 1);
179
+
180
+ const char *auth_data;
181
+ size_t auth_data_len;
182
+ CHECKED(trilogy_reader_get_eof_buffer(&reader, &auth_data_len, (const void **)&auth_data));
183
+ if (auth_data_len > 21) {
184
+ auth_data_len = 21;
185
+ }
186
+ memcpy(out_packet->scramble, auth_data, auth_data_len);
187
+ } else {
188
+ return TRILOGY_PROTOCOL_VIOLATION;
189
+ }
190
+
191
+ return trilogy_reader_finish(&reader);
192
+
193
+ fail:
194
+ return rc;
195
+ }
196
+
197
+ int trilogy_parse_handshake_packet(const uint8_t *buff, size_t len, trilogy_handshake_t *out_packet)
198
+ {
199
+ int rc;
200
+
201
+ trilogy_reader_t reader = TRILOGY_READER(buff, len);
202
+
203
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_packet->proto_version));
204
+ if (out_packet->proto_version != 0xa) {
205
+ // incompatible protocol version
206
+ return TRILOGY_PROTOCOL_VIOLATION;
207
+ }
208
+
209
+ const char *server_version;
210
+ size_t server_version_len;
211
+
212
+ CHECKED(trilogy_reader_get_string(&reader, &server_version, &server_version_len));
213
+ server_version_len = min(server_version_len, sizeof(out_packet->server_version) - 1);
214
+ memcpy(out_packet->server_version, server_version, server_version_len);
215
+ out_packet->server_version[server_version_len] = '\0';
216
+
217
+ CHECKED(trilogy_reader_get_uint32(&reader, &out_packet->conn_id));
218
+
219
+ CHECKED(trilogy_reader_copy_buffer(&reader, 8, out_packet->scramble));
220
+
221
+ // this should be a NULL filler
222
+ uint8_t filler = 0;
223
+ CHECKED(trilogy_reader_get_uint8(&reader, &filler));
224
+ if (filler != '\0') {
225
+ // corrupt handshake packet
226
+ return TRILOGY_PROTOCOL_VIOLATION;
227
+ }
228
+
229
+ // lower two bytes of capabilities flags
230
+ uint16_t caps_part = 0;
231
+ CHECKED(trilogy_reader_get_uint16(&reader, &caps_part));
232
+ out_packet->capabilities = caps_part;
233
+
234
+ if (!(out_packet->capabilities & TRILOGY_CAPABILITIES_PROTOCOL_41)) {
235
+ // incompatible protocol version
236
+ return TRILOGY_PROTOCOL_VIOLATION;
237
+ }
238
+
239
+ uint8_t server_charset;
240
+ CHECKED(trilogy_reader_get_uint8(&reader, &server_charset));
241
+
242
+ out_packet->server_charset = server_charset;
243
+
244
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_packet->server_status));
245
+
246
+ // upper 16 bits of capabilities flags
247
+
248
+ CHECKED(trilogy_reader_get_uint16(&reader, &caps_part));
249
+ out_packet->capabilities |= ((uint32_t)caps_part << 16);
250
+
251
+ uint8_t auth_data_len = 0;
252
+ CHECKED(trilogy_reader_get_uint8(&reader, &auth_data_len));
253
+ if (!(out_packet->capabilities & TRILOGY_CAPABILITIES_PLUGIN_AUTH)) {
254
+ // this should be a NULL filler
255
+ if (auth_data_len != '\0') {
256
+ // corrupt handshake packet
257
+ return TRILOGY_PROTOCOL_VIOLATION;
258
+ }
259
+ }
260
+
261
+ // This space is reserved. It should be all NULL bytes but some tools or
262
+ // future versions of MySQL-compatible clients may use it. This library
263
+ // opts to skip the validation as some servers don't respect the protocol.
264
+ //
265
+ static const uint8_t null_filler[10] = {0};
266
+
267
+ const void *str;
268
+ CHECKED(trilogy_reader_get_buffer(&reader, 10, &str));
269
+
270
+ if (memcmp(str, null_filler, 10) != 0) {
271
+ // corrupt handshake packet
272
+ return TRILOGY_PROTOCOL_VIOLATION;
273
+ }
274
+
275
+ if (out_packet->capabilities & TRILOGY_CAPABILITIES_SECURE_CONNECTION && auth_data_len > 8) {
276
+ uint8_t remaining_auth_data_len = auth_data_len - 8;
277
+
278
+ if (remaining_auth_data_len > 13) {
279
+ remaining_auth_data_len = 13;
280
+ }
281
+
282
+ CHECKED(trilogy_reader_copy_buffer(&reader, remaining_auth_data_len, out_packet->scramble + 8));
283
+ } else {
284
+ // only support 4.1 protocol or newer with secure connection
285
+ return TRILOGY_PROTOCOL_VIOLATION;
286
+ }
287
+
288
+ if (out_packet->capabilities & TRILOGY_CAPABILITIES_PLUGIN_AUTH) {
289
+ const char *auth_plugin;
290
+ size_t auth_plugin_len;
291
+
292
+ CHECKED(trilogy_reader_get_string(&reader, &auth_plugin, &auth_plugin_len));
293
+ if (auth_plugin_len > sizeof(out_packet->auth_plugin) - 1) {
294
+ return TRILOGY_AUTH_PLUGIN_TOO_LONG;
295
+ }
296
+
297
+ memcpy(out_packet->auth_plugin, auth_plugin, auth_plugin_len + 1);
298
+ }
299
+
300
+ return trilogy_reader_finish(&reader);
301
+
302
+ fail:
303
+ return rc;
304
+ }
305
+
306
+ int trilogy_parse_result_packet(const uint8_t *buff, size_t len, trilogy_result_packet_t *out_packet)
307
+ {
308
+ int rc = 0;
309
+
310
+ trilogy_reader_t reader = TRILOGY_READER(buff, len);
311
+
312
+ CHECKED(trilogy_reader_get_lenenc(&reader, &out_packet->column_count));
313
+
314
+ return trilogy_reader_finish(&reader);
315
+
316
+ fail:
317
+ return rc;
318
+ }
319
+
320
+ int trilogy_parse_row_packet(const uint8_t *buff, size_t len, uint64_t column_count, trilogy_value_t *out_values)
321
+ {
322
+ trilogy_reader_t reader = TRILOGY_READER(buff, len);
323
+
324
+ for (uint64_t i = 0; i < column_count; i++) {
325
+ void *data = NULL;
326
+ size_t data_len = 0;
327
+
328
+ int rc = trilogy_reader_get_lenenc_buffer(&reader, &data_len, (const void **)&data);
329
+
330
+ switch (rc) {
331
+ case TRILOGY_OK:
332
+ out_values[i].is_null = false;
333
+ out_values[i].data = data;
334
+ out_values[i].data_len = data_len;
335
+ break;
336
+
337
+ case TRILOGY_NULL_VALUE:
338
+ out_values[i].is_null = true;
339
+ out_values[i].data_len = 0;
340
+ break;
341
+
342
+ default:
343
+ return rc;
344
+ }
345
+ }
346
+
347
+ return trilogy_reader_finish(&reader);
348
+ }
349
+
350
+ int trilogy_parse_column_packet(const uint8_t *buff, size_t len, bool field_list, trilogy_column_packet_t *out_packet)
351
+ {
352
+ int rc;
353
+
354
+ trilogy_reader_t reader = TRILOGY_READER(buff, len);
355
+
356
+ CHECKED(trilogy_reader_get_lenenc_buffer(&reader, &out_packet->catalog_len, (const void **)&out_packet->catalog));
357
+
358
+ CHECKED(trilogy_reader_get_lenenc_buffer(&reader, &out_packet->schema_len, (const void **)&out_packet->schema));
359
+
360
+ CHECKED(trilogy_reader_get_lenenc_buffer(&reader, &out_packet->table_len, (const void **)&out_packet->table));
361
+
362
+ CHECKED(trilogy_reader_get_lenenc_buffer(&reader, &out_packet->original_table_len,
363
+ (const void **)&out_packet->original_table));
364
+
365
+ CHECKED(trilogy_reader_get_lenenc_buffer(&reader, &out_packet->name_len, (const void **)&out_packet->name));
366
+
367
+ CHECKED(trilogy_reader_get_lenenc_buffer(&reader, &out_packet->original_name_len,
368
+ (const void **)&out_packet->original_name));
369
+
370
+ // skip length of fixed length field until we have something to use it for
371
+ CHECKED(trilogy_reader_get_lenenc(&reader, NULL));
372
+
373
+ uint16_t charset;
374
+ CHECKED(trilogy_reader_get_uint16(&reader, &charset));
375
+
376
+ out_packet->charset = charset;
377
+
378
+ CHECKED(trilogy_reader_get_uint32(&reader, &out_packet->len));
379
+
380
+ uint8_t type;
381
+ CHECKED(trilogy_reader_get_uint8(&reader, &type));
382
+ out_packet->type = type;
383
+
384
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_packet->flags));
385
+
386
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_packet->decimals));
387
+
388
+ // skip NULL filler
389
+ CHECKED(trilogy_reader_get_uint16(&reader, NULL));
390
+
391
+ out_packet->default_value_len = 0;
392
+
393
+ if (field_list) {
394
+ CHECKED(trilogy_reader_get_lenenc_buffer(&reader, &out_packet->default_value_len,
395
+ (const void **)&out_packet->default_value));
396
+ }
397
+
398
+ return trilogy_reader_finish(&reader);
399
+
400
+ fail:
401
+ return rc;
402
+ }
403
+
404
+ static void trilogy_pack_scramble_native_hash(const char *scramble, const char *password, size_t password_len,
405
+ uint8_t *buffer, unsigned int *buffer_len)
406
+ {
407
+ EVP_MD_CTX *ctx;
408
+ const EVP_MD *alg;
409
+ unsigned int hash_size_tmp1;
410
+ unsigned int hash_size_tmp2;
411
+ unsigned int x;
412
+
413
+ #if OPENSSL_VERSION_NUMBER >= 0x1010000fL
414
+ ctx = EVP_MD_CTX_new();
415
+ #else
416
+ ctx = EVP_MD_CTX_create();
417
+ EVP_MD_CTX_init(ctx);
418
+ #endif
419
+ alg = EVP_sha1();
420
+ hash_size_tmp1 = 0;
421
+ hash_size_tmp2 = 0;
422
+ uint8_t hash_tmp1[EVP_MAX_MD_SIZE];
423
+ uint8_t hash_tmp2[EVP_MAX_MD_SIZE];
424
+
425
+ /* First hash the password. */
426
+ EVP_DigestInit_ex(ctx, alg, NULL);
427
+ EVP_DigestUpdate(ctx, (unsigned char *)(password), password_len);
428
+ EVP_DigestFinal_ex(ctx, hash_tmp1, &hash_size_tmp1);
429
+
430
+ /* Second, hash the password hash. */
431
+ EVP_DigestInit_ex(ctx, alg, NULL);
432
+ EVP_DigestUpdate(ctx, hash_tmp1, (size_t)hash_size_tmp1);
433
+ EVP_DigestFinal_ex(ctx, hash_tmp2, &hash_size_tmp2);
434
+
435
+ /* Third, hash the scramble and the double password hash. */
436
+ EVP_DigestInit_ex(ctx, alg, NULL);
437
+ EVP_DigestUpdate(ctx, (unsigned char *)scramble, SCRAMBLE_LEN);
438
+ EVP_DigestUpdate(ctx, hash_tmp2, (size_t)hash_size_tmp2);
439
+ EVP_DigestFinal_ex(ctx, buffer, buffer_len);
440
+
441
+ #if OPENSSL_VERSION_NUMBER >= 0x1010000fL
442
+ EVP_MD_CTX_free(ctx);
443
+ #else
444
+ EVP_MD_CTX_destroy(ctx);
445
+ #endif
446
+
447
+ /* Fourth, xor the last hash against the first password hash. */
448
+ for (x = 0; x < *buffer_len; x++) {
449
+ buffer[x] = buffer[x] ^ hash_tmp1[x];
450
+ }
451
+ }
452
+
453
+ static void trilogy_pack_scramble_sha2_hash(const char *scramble, const char *password, size_t password_len,
454
+ uint8_t *buffer, unsigned int *buffer_len)
455
+ {
456
+ EVP_MD_CTX *ctx;
457
+ const EVP_MD *alg;
458
+ unsigned int hash_size_tmp1;
459
+ unsigned int hash_size_tmp2;
460
+ unsigned int x;
461
+
462
+ #if OPENSSL_VERSION_NUMBER >= 0x1010000fL
463
+ ctx = EVP_MD_CTX_new();
464
+ #else
465
+ ctx = EVP_MD_CTX_create();
466
+ EVP_MD_CTX_init(ctx);
467
+ #endif
468
+ alg = EVP_sha256();
469
+ hash_size_tmp1 = 0;
470
+ hash_size_tmp2 = 0;
471
+ uint8_t hash_tmp1[EVP_MAX_MD_SIZE];
472
+ uint8_t hash_tmp2[EVP_MAX_MD_SIZE];
473
+
474
+ /* First hash the password. */
475
+ EVP_DigestInit_ex(ctx, alg, NULL);
476
+ EVP_DigestUpdate(ctx, (unsigned char *)(password), password_len);
477
+ EVP_DigestFinal_ex(ctx, hash_tmp1, &hash_size_tmp1);
478
+
479
+ /* Second, hash the password hash. */
480
+ EVP_DigestInit_ex(ctx, alg, NULL);
481
+ EVP_DigestUpdate(ctx, hash_tmp1, (size_t)hash_size_tmp1);
482
+ EVP_DigestFinal_ex(ctx, hash_tmp2, &hash_size_tmp2);
483
+
484
+ /* Third, hash the scramble and the double password hash. */
485
+ EVP_DigestInit_ex(ctx, alg, NULL);
486
+ EVP_DigestUpdate(ctx, hash_tmp2, (size_t)hash_size_tmp2);
487
+ EVP_DigestUpdate(ctx, (unsigned char *)scramble, SCRAMBLE_LEN);
488
+ EVP_DigestFinal_ex(ctx, buffer, buffer_len);
489
+
490
+ #if OPENSSL_VERSION_NUMBER >= 0x1010000fL
491
+ EVP_MD_CTX_free(ctx);
492
+ #else
493
+ EVP_MD_CTX_destroy(ctx);
494
+ #endif
495
+
496
+ /* Fourth, xor the first and last hash. */
497
+ for (x = 0; x < *buffer_len; x++) {
498
+ buffer[x] = hash_tmp1[x] ^ buffer[x];
499
+ }
500
+ }
501
+
502
+ int trilogy_build_auth_packet(trilogy_builder_t *builder, const char *user, const char *pass, size_t pass_len,
503
+ const char *database, const char *auth_plugin, const char *scramble,
504
+ TRILOGY_CAPABILITIES_t flags)
505
+ {
506
+ int rc = TRILOGY_OK;
507
+
508
+ const char *default_auth_plugin = "mysql_native_password";
509
+
510
+ uint32_t capabilities = flags;
511
+ // Add the default set of capabilities for this client
512
+ capabilities |= TRILOGY_CAPABILITIES_CLIENT;
513
+
514
+ uint32_t max_packet_len = TRILOGY_MAX_PACKET_LEN;
515
+
516
+ uint8_t client_encoding = TRILOGY_CHARSET_UTF8_GENERAL_CI;
517
+
518
+ unsigned int auth_response_len = 0;
519
+ uint8_t auth_response[EVP_MAX_MD_SIZE];
520
+
521
+ if (database) {
522
+ capabilities |= TRILOGY_CAPABILITIES_CONNECT_WITH_DB;
523
+ }
524
+
525
+ CHECKED(trilogy_builder_write_uint32(builder, capabilities));
526
+
527
+ CHECKED(trilogy_builder_write_uint32(builder, max_packet_len));
528
+
529
+ CHECKED(trilogy_builder_write_uint8(builder, client_encoding));
530
+
531
+ static const char zeroes[23] = {0};
532
+ CHECKED(trilogy_builder_write_buffer(builder, zeroes, 23));
533
+
534
+ if (user) {
535
+ CHECKED(trilogy_builder_write_string(builder, user));
536
+ } else {
537
+ CHECKED(trilogy_builder_write_string(builder, "root"));
538
+ }
539
+
540
+ if (pass_len > 0) {
541
+ // Fallback to te default unless we have SHA2 requested
542
+ if (!strcmp("caching_sha2_password", auth_plugin)) {
543
+ trilogy_pack_scramble_sha2_hash(scramble, pass, pass_len, auth_response, &auth_response_len);
544
+ } else {
545
+ trilogy_pack_scramble_native_hash(scramble, pass, pass_len, auth_response, &auth_response_len);
546
+ auth_plugin = default_auth_plugin;
547
+ }
548
+ }
549
+
550
+ // auth data len
551
+ CHECKED(trilogy_builder_write_uint8(builder, (uint8_t)auth_response_len));
552
+
553
+ if (auth_response_len > 0) {
554
+ CHECKED(trilogy_builder_write_buffer(builder, auth_response, auth_response_len));
555
+ }
556
+
557
+ if (database) {
558
+ CHECKED(trilogy_builder_write_string(builder, database));
559
+ }
560
+
561
+ if (capabilities & TRILOGY_CAPABILITIES_PLUGIN_AUTH) {
562
+ CHECKED(trilogy_builder_write_string(builder, auth_plugin));
563
+ }
564
+
565
+ trilogy_builder_finalize(builder);
566
+
567
+ return TRILOGY_OK;
568
+
569
+ fail:
570
+ return rc;
571
+ }
572
+
573
+ int trilogy_build_auth_switch_response_packet(trilogy_builder_t *builder, const char *pass, size_t pass_len,
574
+ const char *auth_plugin, const char *scramble)
575
+ {
576
+ int rc = TRILOGY_OK;
577
+ unsigned int auth_response_len = 0;
578
+ uint8_t auth_response[EVP_MAX_MD_SIZE];
579
+
580
+ if (!strcmp("caching_sha2_password", auth_plugin)) {
581
+ trilogy_pack_scramble_sha2_hash(scramble, pass, pass_len, auth_response, &auth_response_len);
582
+ } else {
583
+ trilogy_pack_scramble_native_hash(scramble, pass, pass_len, auth_response, &auth_response_len);
584
+ }
585
+
586
+ CHECKED(trilogy_builder_write_buffer(builder, auth_response, auth_response_len));
587
+ trilogy_builder_finalize(builder);
588
+
589
+ return TRILOGY_OK;
590
+ fail:
591
+ return rc;
592
+ }
593
+
594
+ int trilogy_build_ping_packet(trilogy_builder_t *builder)
595
+ {
596
+ int rc = TRILOGY_OK;
597
+
598
+ CHECKED(trilogy_builder_write_uint8(builder, TRILOGY_CMD_PING));
599
+
600
+ trilogy_builder_finalize(builder);
601
+
602
+ return TRILOGY_OK;
603
+
604
+ fail:
605
+ return rc;
606
+ }
607
+
608
+ int trilogy_build_query_packet(trilogy_builder_t *builder, const char *sql, size_t sql_len)
609
+ {
610
+ int rc = TRILOGY_OK;
611
+
612
+ CHECKED(trilogy_builder_write_uint8(builder, TRILOGY_CMD_QUERY));
613
+
614
+ CHECKED(trilogy_builder_write_buffer(builder, sql, sql_len));
615
+
616
+ trilogy_builder_finalize(builder);
617
+
618
+ return TRILOGY_OK;
619
+
620
+ fail:
621
+ return rc;
622
+ }
623
+
624
+ int trilogy_build_change_db_packet(trilogy_builder_t *builder, const char *name, size_t name_len)
625
+ {
626
+ int rc = TRILOGY_OK;
627
+
628
+ CHECKED(trilogy_builder_write_uint8(builder, TRILOGY_CMD_CHANGE_DB));
629
+
630
+ CHECKED(trilogy_builder_write_buffer(builder, name, name_len));
631
+
632
+ trilogy_builder_finalize(builder);
633
+
634
+ return TRILOGY_OK;
635
+
636
+ fail:
637
+ return rc;
638
+ }
639
+
640
+ int trilogy_build_quit_packet(trilogy_builder_t *builder)
641
+ {
642
+ int rc = TRILOGY_OK;
643
+
644
+ CHECKED(trilogy_builder_write_uint8(builder, TRILOGY_CMD_QUIT));
645
+
646
+ trilogy_builder_finalize(builder);
647
+
648
+ return TRILOGY_OK;
649
+
650
+ fail:
651
+ return rc;
652
+ }
653
+
654
+ int trilogy_build_ssl_request_packet(trilogy_builder_t *builder, TRILOGY_CAPABILITIES_t flags)
655
+ {
656
+ static const char zeroes[23] = {0};
657
+
658
+ const uint32_t max_packet_len = TRILOGY_MAX_PACKET_LEN;
659
+ const uint8_t client_encoding = TRILOGY_CHARSET_UTF8_GENERAL_CI;
660
+ const uint32_t capabilities = flags | TRILOGY_CAPABILITIES_CLIENT | TRILOGY_CAPABILITIES_SSL;
661
+
662
+ int rc = TRILOGY_OK;
663
+
664
+ CHECKED(trilogy_builder_write_uint32(builder, capabilities));
665
+ CHECKED(trilogy_builder_write_uint32(builder, max_packet_len));
666
+ CHECKED(trilogy_builder_write_uint8(builder, client_encoding));
667
+ CHECKED(trilogy_builder_write_buffer(builder, zeroes, 23));
668
+ trilogy_builder_finalize(builder);
669
+
670
+ return TRILOGY_OK;
671
+
672
+ fail:
673
+ return rc;
674
+ }
675
+
676
+ #undef CHECKED