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.
- checksums.yaml +7 -0
- data/LICENSE +22 -0
- data/README.md +74 -0
- data/Rakefile +18 -0
- data/ext/trilogy-ruby/cast.c +272 -0
- data/ext/trilogy-ruby/cext.c +933 -0
- data/ext/trilogy-ruby/extconf.rb +16 -0
- data/ext/trilogy-ruby/inc/trilogy/blocking.h +163 -0
- data/ext/trilogy-ruby/inc/trilogy/buffer.h +64 -0
- data/ext/trilogy-ruby/inc/trilogy/builder.h +161 -0
- data/ext/trilogy-ruby/inc/trilogy/charset.h +277 -0
- data/ext/trilogy-ruby/inc/trilogy/client.h +546 -0
- data/ext/trilogy-ruby/inc/trilogy/error.h +43 -0
- data/ext/trilogy-ruby/inc/trilogy/packet_parser.h +34 -0
- data/ext/trilogy-ruby/inc/trilogy/protocol.h +756 -0
- data/ext/trilogy-ruby/inc/trilogy/reader.h +212 -0
- data/ext/trilogy-ruby/inc/trilogy/socket.h +111 -0
- data/ext/trilogy-ruby/inc/trilogy/vendor/curl_hostcheck.h +29 -0
- data/ext/trilogy-ruby/inc/trilogy/vendor/openssl_hostname_validation.h +51 -0
- data/ext/trilogy-ruby/inc/trilogy.h +8 -0
- data/ext/trilogy-ruby/src/blocking.c +241 -0
- data/ext/trilogy-ruby/src/buffer.c +60 -0
- data/ext/trilogy-ruby/src/builder.c +198 -0
- data/ext/trilogy-ruby/src/charset.c +212 -0
- data/ext/trilogy-ruby/src/client.c +728 -0
- data/ext/trilogy-ruby/src/error.c +17 -0
- data/ext/trilogy-ruby/src/packet_parser.c +140 -0
- data/ext/trilogy-ruby/src/protocol.c +676 -0
- data/ext/trilogy-ruby/src/reader.c +244 -0
- data/ext/trilogy-ruby/src/socket.c +623 -0
- data/ext/trilogy-ruby/src/vendor/curl_hostcheck.c +206 -0
- data/ext/trilogy-ruby/src/vendor/openssl_hostname_validation.c +175 -0
- data/ext/trilogy-ruby/trilogy-ruby.h +36 -0
- data/lib/trilogy/version.rb +3 -0
- data/lib/trilogy.rb +61 -0
- data/trilogy.gemspec +27 -0
- 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(>id_reader, NULL));
|
87
|
+
CHECKED(trilogy_reader_get_lenenc_buffer(>id_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
|