trilogy_w_prepared_statements 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +22 -0
  3. data/README.md +80 -0
  4. data/Rakefile +22 -0
  5. data/ext/trilogy-ruby/cast.c +277 -0
  6. data/ext/trilogy-ruby/cext.c +1048 -0
  7. data/ext/trilogy-ruby/extconf.rb +17 -0
  8. data/ext/trilogy-ruby/inc/trilogy/blocking.h +281 -0
  9. data/ext/trilogy-ruby/inc/trilogy/buffer.h +64 -0
  10. data/ext/trilogy-ruby/inc/trilogy/builder.h +165 -0
  11. data/ext/trilogy-ruby/inc/trilogy/charset.h +277 -0
  12. data/ext/trilogy-ruby/inc/trilogy/client.h +760 -0
  13. data/ext/trilogy-ruby/inc/trilogy/error.h +44 -0
  14. data/ext/trilogy-ruby/inc/trilogy/packet_parser.h +34 -0
  15. data/ext/trilogy-ruby/inc/trilogy/protocol.h +1014 -0
  16. data/ext/trilogy-ruby/inc/trilogy/reader.h +216 -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 +358 -0
  22. data/ext/trilogy-ruby/src/buffer.c +60 -0
  23. data/ext/trilogy-ruby/src/builder.c +236 -0
  24. data/ext/trilogy-ruby/src/charset.c +212 -0
  25. data/ext/trilogy-ruby/src/client.c +903 -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 +1175 -0
  29. data/ext/trilogy-ruby/src/reader.c +282 -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 +37 -0
  34. data/lib/trilogy/version.rb +3 -0
  35. data/lib/trilogy.rb +61 -0
  36. data/trilogy.gemspec +27 -0
  37. metadata +107 -0
@@ -0,0 +1,1175 @@
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 TRILOGY_CMD_STMT_PREPARE 0x16
15
+ #define TRILOGY_CMD_STMT_EXECUTE 0x17
16
+ #define TRILOGY_CMD_STMT_SEND_LONG_DATA 0x18
17
+ #define TRILOGY_CMD_STMT_CLOSE 0x19
18
+ #define TRILOGY_CMD_STMT_RESET 0x1a
19
+
20
+ #define SCRAMBLE_LEN 20
21
+
22
+ static size_t min(size_t a, size_t b)
23
+ {
24
+ if (a < b) {
25
+ return a;
26
+ } else {
27
+ return b;
28
+ }
29
+ }
30
+
31
+ #define CHECKED(expr) \
32
+ if ((rc = (expr)) < 0) { \
33
+ goto fail; \
34
+ }
35
+
36
+ int trilogy_parse_ok_packet(const uint8_t *buff, size_t len, uint32_t capabilities, trilogy_ok_packet_t *out_packet)
37
+ {
38
+ int rc;
39
+
40
+ trilogy_reader_t reader = TRILOGY_READER(buff, len);
41
+
42
+ // skip packet type
43
+ CHECKED(trilogy_reader_get_uint8(&reader, NULL));
44
+
45
+ CHECKED(trilogy_reader_get_lenenc(&reader, &out_packet->affected_rows));
46
+
47
+ CHECKED(trilogy_reader_get_lenenc(&reader, &out_packet->last_insert_id));
48
+
49
+ out_packet->status_flags = 0;
50
+ out_packet->warning_count = 0;
51
+ out_packet->txn_status_flags = 0;
52
+ out_packet->session_status = NULL;
53
+ out_packet->session_status_len = 0;
54
+ out_packet->session_state_changes = NULL;
55
+ out_packet->session_state_changes_len = 0;
56
+ out_packet->info = NULL;
57
+ out_packet->info_len = 0;
58
+ out_packet->last_gtid_len = 0;
59
+
60
+ if (capabilities & TRILOGY_CAPABILITIES_PROTOCOL_41) {
61
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_packet->status_flags));
62
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_packet->warning_count));
63
+ } else if (capabilities & TRILOGY_CAPABILITIES_TRANSACTIONS) {
64
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_packet->txn_status_flags));
65
+ }
66
+
67
+ if (capabilities & TRILOGY_CAPABILITIES_SESSION_TRACK && !trilogy_reader_eof(&reader)) {
68
+ CHECKED(trilogy_reader_get_lenenc_buffer(&reader, &out_packet->session_status_len,
69
+ (const void **)&out_packet->session_status));
70
+
71
+ if (out_packet->status_flags & TRILOGY_SERVER_STATUS_SESSION_STATE_CHANGED) {
72
+ CHECKED(trilogy_reader_get_lenenc_buffer(&reader, &out_packet->session_state_changes_len,
73
+ (const void **)&out_packet->session_state_changes));
74
+
75
+ TRILOGY_SESSION_TRACK_TYPE_t type = 0;
76
+ const char *state_info = NULL;
77
+ size_t state_info_len = 0;
78
+
79
+ trilogy_reader_t state_reader = TRILOGY_READER((const uint8_t *)out_packet->session_state_changes,
80
+ out_packet->session_state_changes_len);
81
+
82
+ while (!trilogy_reader_eof(&state_reader)) {
83
+ CHECKED(trilogy_reader_get_uint8(&state_reader, (uint8_t *)&type));
84
+ CHECKED(trilogy_reader_get_lenenc_buffer(&state_reader, &state_info_len, (const void **)&state_info));
85
+
86
+ switch (type) {
87
+ case TRILOGY_SESSION_TRACK_GTIDS: {
88
+ trilogy_reader_t gtid_reader = TRILOGY_READER((const uint8_t *)state_info, state_info_len);
89
+ // There's a type with value TRILOGY_SESSION_TRACK_GTIDS tag
90
+ // at the beginning here we can ignore since we already had
91
+ // the type one level higher as well.
92
+ CHECKED(trilogy_reader_get_uint8(&gtid_reader, NULL));
93
+ CHECKED(trilogy_reader_get_lenenc_buffer(&gtid_reader, &out_packet->last_gtid_len,
94
+ (const void **)&out_packet->last_gtid));
95
+ if (out_packet->last_gtid_len > TRILOGY_MAX_LAST_GTID_LEN) {
96
+ return TRILOGY_PROTOCOL_VIOLATION;
97
+ }
98
+ break;
99
+ }
100
+ default:
101
+ break;
102
+ }
103
+ }
104
+ }
105
+ } else {
106
+ CHECKED(trilogy_reader_get_eof_buffer(&reader, &out_packet->info_len, (const void **)&out_packet->info));
107
+ }
108
+
109
+ return trilogy_reader_finish(&reader);
110
+
111
+ fail:
112
+ return rc;
113
+ }
114
+
115
+ int trilogy_parse_eof_packet(const uint8_t *buff, size_t len, uint32_t capabilities, trilogy_eof_packet_t *out_packet)
116
+ {
117
+ int rc;
118
+
119
+ trilogy_reader_t reader = TRILOGY_READER(buff, len);
120
+
121
+ // skip packet type
122
+ CHECKED(trilogy_reader_get_uint8(&reader, NULL));
123
+
124
+ if (capabilities & TRILOGY_CAPABILITIES_PROTOCOL_41) {
125
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_packet->warning_count));
126
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_packet->status_flags));
127
+ } else {
128
+ out_packet->status_flags = 0;
129
+ out_packet->warning_count = 0;
130
+ }
131
+
132
+ return trilogy_reader_finish(&reader);
133
+
134
+ fail:
135
+ return rc;
136
+ }
137
+
138
+ int trilogy_parse_err_packet(const uint8_t *buff, size_t len, uint32_t capabilities, trilogy_err_packet_t *out_packet)
139
+ {
140
+ int rc;
141
+
142
+ trilogy_reader_t reader = TRILOGY_READER(buff, len);
143
+
144
+ // skip packet type
145
+ CHECKED(trilogy_reader_get_uint8(&reader, NULL));
146
+
147
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_packet->error_code));
148
+
149
+ if (capabilities & TRILOGY_CAPABILITIES_PROTOCOL_41) {
150
+ CHECKED(trilogy_reader_get_uint8(&reader, out_packet->sql_state_marker));
151
+ CHECKED(trilogy_reader_copy_buffer(&reader, 5, out_packet->sql_state));
152
+ } else {
153
+ memset(out_packet->sql_state_marker, 0, sizeof out_packet->sql_state_marker);
154
+ memset(out_packet->sql_state, 0, sizeof out_packet->sql_state);
155
+ }
156
+
157
+ CHECKED(trilogy_reader_get_eof_buffer(&reader, &out_packet->error_message_len,
158
+ (const void **)&out_packet->error_message));
159
+
160
+ return trilogy_reader_finish(&reader);
161
+
162
+ fail:
163
+ return rc;
164
+ }
165
+
166
+ int trilogy_parse_auth_switch_request_packet(const uint8_t *buff, size_t len, uint32_t capabilities,
167
+ trilogy_auth_switch_request_packet_t *out_packet)
168
+ {
169
+ int rc;
170
+
171
+ trilogy_reader_t reader = TRILOGY_READER(buff, len);
172
+
173
+ // skip packet type
174
+ CHECKED(trilogy_reader_get_uint8(&reader, NULL));
175
+
176
+ if (capabilities & TRILOGY_CAPABILITIES_PLUGIN_AUTH) {
177
+ const char *auth_plugin;
178
+ size_t auth_plugin_len;
179
+
180
+ CHECKED(trilogy_reader_get_string(&reader, &auth_plugin, &auth_plugin_len));
181
+ if (auth_plugin_len > sizeof(out_packet->auth_plugin) - 1) {
182
+ return TRILOGY_AUTH_PLUGIN_TOO_LONG;
183
+ }
184
+ memcpy(out_packet->auth_plugin, auth_plugin, auth_plugin_len + 1);
185
+
186
+ const char *auth_data;
187
+ size_t auth_data_len;
188
+ CHECKED(trilogy_reader_get_eof_buffer(&reader, &auth_data_len, (const void **)&auth_data));
189
+ if (auth_data_len > 21) {
190
+ auth_data_len = 21;
191
+ }
192
+ memcpy(out_packet->scramble, auth_data, auth_data_len);
193
+ } else {
194
+ return TRILOGY_PROTOCOL_VIOLATION;
195
+ }
196
+
197
+ return trilogy_reader_finish(&reader);
198
+
199
+ fail:
200
+ return rc;
201
+ }
202
+
203
+ int trilogy_parse_handshake_packet(const uint8_t *buff, size_t len, trilogy_handshake_t *out_packet)
204
+ {
205
+ int rc;
206
+
207
+ trilogy_reader_t reader = TRILOGY_READER(buff, len);
208
+
209
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_packet->proto_version));
210
+ if (out_packet->proto_version != 0xa) {
211
+ // incompatible protocol version
212
+ return TRILOGY_PROTOCOL_VIOLATION;
213
+ }
214
+
215
+ const char *server_version;
216
+ size_t server_version_len;
217
+
218
+ CHECKED(trilogy_reader_get_string(&reader, &server_version, &server_version_len));
219
+ server_version_len = min(server_version_len, sizeof(out_packet->server_version) - 1);
220
+ memcpy(out_packet->server_version, server_version, server_version_len);
221
+ out_packet->server_version[server_version_len] = '\0';
222
+
223
+ CHECKED(trilogy_reader_get_uint32(&reader, &out_packet->conn_id));
224
+
225
+ CHECKED(trilogy_reader_copy_buffer(&reader, 8, out_packet->scramble));
226
+
227
+ // this should be a NULL filler
228
+ uint8_t filler = 0;
229
+ CHECKED(trilogy_reader_get_uint8(&reader, &filler));
230
+ if (filler != '\0') {
231
+ // corrupt handshake packet
232
+ return TRILOGY_PROTOCOL_VIOLATION;
233
+ }
234
+
235
+ // lower two bytes of capabilities flags
236
+ uint16_t caps_part = 0;
237
+ CHECKED(trilogy_reader_get_uint16(&reader, &caps_part));
238
+ out_packet->capabilities = caps_part;
239
+
240
+ if (!(out_packet->capabilities & TRILOGY_CAPABILITIES_PROTOCOL_41)) {
241
+ // incompatible protocol version
242
+ return TRILOGY_PROTOCOL_VIOLATION;
243
+ }
244
+
245
+ uint8_t server_charset;
246
+ CHECKED(trilogy_reader_get_uint8(&reader, &server_charset));
247
+
248
+ out_packet->server_charset = server_charset;
249
+
250
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_packet->server_status));
251
+
252
+ // upper 16 bits of capabilities flags
253
+
254
+ CHECKED(trilogy_reader_get_uint16(&reader, &caps_part));
255
+ out_packet->capabilities |= ((uint32_t)caps_part << 16);
256
+
257
+ uint8_t auth_data_len = 0;
258
+ CHECKED(trilogy_reader_get_uint8(&reader, &auth_data_len));
259
+ if (!(out_packet->capabilities & TRILOGY_CAPABILITIES_PLUGIN_AUTH)) {
260
+ // this should be a NULL filler
261
+ if (auth_data_len != '\0') {
262
+ // corrupt handshake packet
263
+ return TRILOGY_PROTOCOL_VIOLATION;
264
+ }
265
+ }
266
+
267
+ // This space is reserved. It should be all NULL bytes but some tools or
268
+ // future versions of MySQL-compatible clients may use it. This library
269
+ // opts to skip the validation as some servers don't respect the protocol.
270
+ CHECKED(trilogy_reader_get_buffer(&reader, 10, NULL));
271
+
272
+ if (out_packet->capabilities & TRILOGY_CAPABILITIES_SECURE_CONNECTION && auth_data_len > 8) {
273
+ uint8_t remaining_auth_data_len = auth_data_len - 8;
274
+
275
+ // The auth plugins we support all provide exactly 21 bytes of
276
+ // auth_data. Reject any other values for auth_data_len.
277
+ if (SCRAMBLE_LEN + 1 != auth_data_len) {
278
+ return TRILOGY_PROTOCOL_VIOLATION;
279
+ }
280
+
281
+ CHECKED(trilogy_reader_copy_buffer(&reader, remaining_auth_data_len, out_packet->scramble + 8));
282
+ } else {
283
+ // only support 4.1 protocol or newer with secure connection
284
+ return TRILOGY_PROTOCOL_VIOLATION;
285
+ }
286
+
287
+ if (out_packet->capabilities & TRILOGY_CAPABILITIES_PLUGIN_AUTH) {
288
+ const char *auth_plugin;
289
+ size_t auth_plugin_len;
290
+
291
+ CHECKED(trilogy_reader_get_string(&reader, &auth_plugin, &auth_plugin_len));
292
+ if (auth_plugin_len > sizeof(out_packet->auth_plugin) - 1) {
293
+ return TRILOGY_AUTH_PLUGIN_TOO_LONG;
294
+ }
295
+
296
+ memcpy(out_packet->auth_plugin, auth_plugin, auth_plugin_len + 1);
297
+ }
298
+
299
+ return trilogy_reader_finish(&reader);
300
+
301
+ fail:
302
+ return rc;
303
+ }
304
+
305
+ int trilogy_parse_result_packet(const uint8_t *buff, size_t len, trilogy_result_packet_t *out_packet)
306
+ {
307
+ int rc = 0;
308
+
309
+ trilogy_reader_t reader = TRILOGY_READER(buff, len);
310
+
311
+ CHECKED(trilogy_reader_get_lenenc(&reader, &out_packet->column_count));
312
+
313
+ return trilogy_reader_finish(&reader);
314
+
315
+ fail:
316
+ return rc;
317
+ }
318
+
319
+ int trilogy_parse_row_packet(const uint8_t *buff, size_t len, uint64_t column_count, trilogy_value_t *out_values)
320
+ {
321
+ trilogy_reader_t reader = TRILOGY_READER(buff, len);
322
+
323
+ for (uint64_t i = 0; i < column_count; i++) {
324
+ void *data = NULL;
325
+ size_t data_len = 0;
326
+
327
+ int rc = trilogy_reader_get_lenenc_buffer(&reader, &data_len, (const void **)&data);
328
+
329
+ switch (rc) {
330
+ case TRILOGY_OK:
331
+ out_values[i].is_null = false;
332
+ out_values[i].data = data;
333
+ out_values[i].data_len = data_len;
334
+ break;
335
+
336
+ case TRILOGY_NULL_VALUE:
337
+ out_values[i].is_null = true;
338
+ out_values[i].data_len = 0;
339
+ break;
340
+
341
+ default:
342
+ return rc;
343
+ }
344
+ }
345
+
346
+ return trilogy_reader_finish(&reader);
347
+ }
348
+
349
+ int trilogy_parse_column_packet(const uint8_t *buff, size_t len, bool field_list, trilogy_column_packet_t *out_packet)
350
+ {
351
+ int rc;
352
+
353
+ trilogy_reader_t reader = TRILOGY_READER(buff, len);
354
+
355
+ CHECKED(trilogy_reader_get_lenenc_buffer(&reader, &out_packet->catalog_len, (const void **)&out_packet->catalog));
356
+
357
+ CHECKED(trilogy_reader_get_lenenc_buffer(&reader, &out_packet->schema_len, (const void **)&out_packet->schema));
358
+
359
+ CHECKED(trilogy_reader_get_lenenc_buffer(&reader, &out_packet->table_len, (const void **)&out_packet->table));
360
+
361
+ CHECKED(trilogy_reader_get_lenenc_buffer(&reader, &out_packet->original_table_len,
362
+ (const void **)&out_packet->original_table));
363
+
364
+ CHECKED(trilogy_reader_get_lenenc_buffer(&reader, &out_packet->name_len, (const void **)&out_packet->name));
365
+
366
+ CHECKED(trilogy_reader_get_lenenc_buffer(&reader, &out_packet->original_name_len,
367
+ (const void **)&out_packet->original_name));
368
+
369
+ // skip length of fixed length field until we have something to use it for
370
+ CHECKED(trilogy_reader_get_lenenc(&reader, NULL));
371
+
372
+ uint16_t charset;
373
+ CHECKED(trilogy_reader_get_uint16(&reader, &charset));
374
+
375
+ out_packet->charset = charset;
376
+
377
+ CHECKED(trilogy_reader_get_uint32(&reader, &out_packet->len));
378
+
379
+ uint8_t type;
380
+ CHECKED(trilogy_reader_get_uint8(&reader, &type));
381
+ out_packet->type = type;
382
+
383
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_packet->flags));
384
+
385
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_packet->decimals));
386
+
387
+ // skip NULL filler
388
+ CHECKED(trilogy_reader_get_uint16(&reader, NULL));
389
+
390
+ out_packet->default_value_len = 0;
391
+
392
+ if (field_list) {
393
+ CHECKED(trilogy_reader_get_lenenc_buffer(&reader, &out_packet->default_value_len,
394
+ (const void **)&out_packet->default_value));
395
+ }
396
+
397
+ return trilogy_reader_finish(&reader);
398
+
399
+ fail:
400
+ return rc;
401
+ }
402
+
403
+ int trilogy_parse_stmt_ok_packet(const uint8_t *buff, size_t len, trilogy_stmt_ok_packet_t *out_packet)
404
+ {
405
+ int rc;
406
+
407
+ trilogy_reader_t reader = TRILOGY_READER(buff, len);
408
+
409
+ // skip packet type
410
+ CHECKED(trilogy_reader_get_uint8(&reader, NULL));
411
+
412
+ CHECKED(trilogy_reader_get_uint32(&reader, &out_packet->id));
413
+
414
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_packet->column_count));
415
+
416
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_packet->parameter_count));
417
+
418
+ uint8_t filler;
419
+
420
+ CHECKED(trilogy_reader_get_uint8(&reader, &filler));
421
+
422
+ if (filler != 0) {
423
+ return TRILOGY_PROTOCOL_VIOLATION;
424
+ }
425
+
426
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_packet->warning_count));
427
+
428
+ return trilogy_reader_finish(&reader);
429
+
430
+ fail:
431
+ return rc;
432
+ }
433
+
434
+ static void trilogy_pack_scramble_native_hash(const char *scramble, const char *password, size_t password_len,
435
+ uint8_t *buffer, unsigned int *buffer_len)
436
+ {
437
+ EVP_MD_CTX *ctx;
438
+ const EVP_MD *alg;
439
+ unsigned int hash_size_tmp1;
440
+ unsigned int hash_size_tmp2;
441
+ unsigned int x;
442
+
443
+ #if OPENSSL_VERSION_NUMBER >= 0x1010000fL
444
+ ctx = EVP_MD_CTX_new();
445
+ #else
446
+ ctx = EVP_MD_CTX_create();
447
+ EVP_MD_CTX_init(ctx);
448
+ #endif
449
+ alg = EVP_sha1();
450
+ hash_size_tmp1 = 0;
451
+ hash_size_tmp2 = 0;
452
+ uint8_t hash_tmp1[EVP_MAX_MD_SIZE];
453
+ uint8_t hash_tmp2[EVP_MAX_MD_SIZE];
454
+
455
+ /* First hash the password. */
456
+ EVP_DigestInit_ex(ctx, alg, NULL);
457
+ EVP_DigestUpdate(ctx, (unsigned char *)(password), password_len);
458
+ EVP_DigestFinal_ex(ctx, hash_tmp1, &hash_size_tmp1);
459
+
460
+ /* Second, hash the password hash. */
461
+ EVP_DigestInit_ex(ctx, alg, NULL);
462
+ EVP_DigestUpdate(ctx, hash_tmp1, (size_t)hash_size_tmp1);
463
+ EVP_DigestFinal_ex(ctx, hash_tmp2, &hash_size_tmp2);
464
+
465
+ /* Third, hash the scramble and the double password hash. */
466
+ EVP_DigestInit_ex(ctx, alg, NULL);
467
+ EVP_DigestUpdate(ctx, (unsigned char *)scramble, SCRAMBLE_LEN);
468
+ EVP_DigestUpdate(ctx, hash_tmp2, (size_t)hash_size_tmp2);
469
+ EVP_DigestFinal_ex(ctx, buffer, buffer_len);
470
+
471
+ #if OPENSSL_VERSION_NUMBER >= 0x1010000fL
472
+ EVP_MD_CTX_free(ctx);
473
+ #else
474
+ EVP_MD_CTX_destroy(ctx);
475
+ #endif
476
+
477
+ /* Fourth, xor the last hash against the first password hash. */
478
+ for (x = 0; x < *buffer_len; x++) {
479
+ buffer[x] = buffer[x] ^ hash_tmp1[x];
480
+ }
481
+ }
482
+
483
+ static void trilogy_pack_scramble_sha2_hash(const char *scramble, const char *password, size_t password_len,
484
+ uint8_t *buffer, unsigned int *buffer_len)
485
+ {
486
+ EVP_MD_CTX *ctx;
487
+ const EVP_MD *alg;
488
+ unsigned int hash_size_tmp1;
489
+ unsigned int hash_size_tmp2;
490
+ unsigned int x;
491
+
492
+ #if OPENSSL_VERSION_NUMBER >= 0x1010000fL
493
+ ctx = EVP_MD_CTX_new();
494
+ #else
495
+ ctx = EVP_MD_CTX_create();
496
+ EVP_MD_CTX_init(ctx);
497
+ #endif
498
+ alg = EVP_sha256();
499
+ hash_size_tmp1 = 0;
500
+ hash_size_tmp2 = 0;
501
+ uint8_t hash_tmp1[EVP_MAX_MD_SIZE];
502
+ uint8_t hash_tmp2[EVP_MAX_MD_SIZE];
503
+
504
+ /* First hash the password. */
505
+ EVP_DigestInit_ex(ctx, alg, NULL);
506
+ EVP_DigestUpdate(ctx, (unsigned char *)(password), password_len);
507
+ EVP_DigestFinal_ex(ctx, hash_tmp1, &hash_size_tmp1);
508
+
509
+ /* Second, hash the password hash. */
510
+ EVP_DigestInit_ex(ctx, alg, NULL);
511
+ EVP_DigestUpdate(ctx, hash_tmp1, (size_t)hash_size_tmp1);
512
+ EVP_DigestFinal_ex(ctx, hash_tmp2, &hash_size_tmp2);
513
+
514
+ /* Third, hash the scramble and the double password hash. */
515
+ EVP_DigestInit_ex(ctx, alg, NULL);
516
+ EVP_DigestUpdate(ctx, hash_tmp2, (size_t)hash_size_tmp2);
517
+ EVP_DigestUpdate(ctx, (unsigned char *)scramble, SCRAMBLE_LEN);
518
+ EVP_DigestFinal_ex(ctx, buffer, buffer_len);
519
+
520
+ #if OPENSSL_VERSION_NUMBER >= 0x1010000fL
521
+ EVP_MD_CTX_free(ctx);
522
+ #else
523
+ EVP_MD_CTX_destroy(ctx);
524
+ #endif
525
+
526
+ /* Fourth, xor the first and last hash. */
527
+ for (x = 0; x < *buffer_len; x++) {
528
+ buffer[x] = hash_tmp1[x] ^ buffer[x];
529
+ }
530
+ }
531
+
532
+ int trilogy_build_auth_packet(trilogy_builder_t *builder, const char *user, const char *pass, size_t pass_len,
533
+ const char *database, const char *auth_plugin, const char *scramble,
534
+ TRILOGY_CAPABILITIES_t flags)
535
+ {
536
+ int rc = TRILOGY_OK;
537
+
538
+ const char *default_auth_plugin = "mysql_native_password";
539
+
540
+ uint32_t capabilities = flags;
541
+ // Add the default set of capabilities for this client
542
+ capabilities |= TRILOGY_CAPABILITIES_CLIENT;
543
+
544
+ uint32_t max_packet_len = TRILOGY_MAX_PACKET_LEN;
545
+
546
+ uint8_t client_encoding = TRILOGY_CHARSET_UTF8_GENERAL_CI;
547
+
548
+ unsigned int auth_response_len = 0;
549
+ uint8_t auth_response[EVP_MAX_MD_SIZE];
550
+
551
+ if (database) {
552
+ capabilities |= TRILOGY_CAPABILITIES_CONNECT_WITH_DB;
553
+ }
554
+
555
+ CHECKED(trilogy_builder_write_uint32(builder, capabilities));
556
+
557
+ CHECKED(trilogy_builder_write_uint32(builder, max_packet_len));
558
+
559
+ CHECKED(trilogy_builder_write_uint8(builder, client_encoding));
560
+
561
+ static const char zeroes[23] = {0};
562
+ CHECKED(trilogy_builder_write_buffer(builder, zeroes, 23));
563
+
564
+ if (user) {
565
+ CHECKED(trilogy_builder_write_string(builder, user));
566
+ } else {
567
+ CHECKED(trilogy_builder_write_string(builder, "root"));
568
+ }
569
+
570
+ if (pass_len > 0) {
571
+ // Fallback to te default unless we have SHA2 requested
572
+ if (!strcmp("caching_sha2_password", auth_plugin)) {
573
+ trilogy_pack_scramble_sha2_hash(scramble, pass, pass_len, auth_response, &auth_response_len);
574
+ } else {
575
+ trilogy_pack_scramble_native_hash(scramble, pass, pass_len, auth_response, &auth_response_len);
576
+ auth_plugin = default_auth_plugin;
577
+ }
578
+ }
579
+
580
+ // auth data len
581
+ CHECKED(trilogy_builder_write_uint8(builder, (uint8_t)auth_response_len));
582
+
583
+ if (auth_response_len > 0) {
584
+ CHECKED(trilogy_builder_write_buffer(builder, auth_response, auth_response_len));
585
+ }
586
+
587
+ if (database) {
588
+ CHECKED(trilogy_builder_write_string(builder, database));
589
+ }
590
+
591
+ if (capabilities & TRILOGY_CAPABILITIES_PLUGIN_AUTH) {
592
+ CHECKED(trilogy_builder_write_string(builder, auth_plugin));
593
+ }
594
+
595
+ trilogy_builder_finalize(builder);
596
+
597
+ return TRILOGY_OK;
598
+
599
+ fail:
600
+ return rc;
601
+ }
602
+
603
+ int trilogy_build_auth_switch_response_packet(trilogy_builder_t *builder, const char *pass, size_t pass_len,
604
+ const char *auth_plugin, const char *scramble)
605
+ {
606
+ int rc = TRILOGY_OK;
607
+ unsigned int auth_response_len = 0;
608
+ uint8_t auth_response[EVP_MAX_MD_SIZE];
609
+
610
+ if (pass_len > 0) {
611
+ if (!strcmp("caching_sha2_password", auth_plugin)) {
612
+ trilogy_pack_scramble_sha2_hash(scramble, pass, pass_len, auth_response, &auth_response_len);
613
+ } else {
614
+ trilogy_pack_scramble_native_hash(scramble, pass, pass_len, auth_response, &auth_response_len);
615
+ }
616
+ }
617
+
618
+ CHECKED(trilogy_builder_write_buffer(builder, auth_response, auth_response_len));
619
+ trilogy_builder_finalize(builder);
620
+
621
+ return TRILOGY_OK;
622
+ fail:
623
+ return rc;
624
+ }
625
+
626
+ int trilogy_build_ping_packet(trilogy_builder_t *builder)
627
+ {
628
+ int rc = TRILOGY_OK;
629
+
630
+ CHECKED(trilogy_builder_write_uint8(builder, TRILOGY_CMD_PING));
631
+
632
+ trilogy_builder_finalize(builder);
633
+
634
+ return TRILOGY_OK;
635
+
636
+ fail:
637
+ return rc;
638
+ }
639
+
640
+ int trilogy_build_query_packet(trilogy_builder_t *builder, const char *sql, size_t sql_len)
641
+ {
642
+ int rc = TRILOGY_OK;
643
+
644
+ CHECKED(trilogy_builder_write_uint8(builder, TRILOGY_CMD_QUERY));
645
+
646
+ CHECKED(trilogy_builder_write_buffer(builder, sql, sql_len));
647
+
648
+ trilogy_builder_finalize(builder);
649
+
650
+ return TRILOGY_OK;
651
+
652
+ fail:
653
+ return rc;
654
+ }
655
+
656
+ int trilogy_build_change_db_packet(trilogy_builder_t *builder, const char *name, size_t name_len)
657
+ {
658
+ int rc = TRILOGY_OK;
659
+
660
+ CHECKED(trilogy_builder_write_uint8(builder, TRILOGY_CMD_CHANGE_DB));
661
+
662
+ CHECKED(trilogy_builder_write_buffer(builder, name, name_len));
663
+
664
+ trilogy_builder_finalize(builder);
665
+
666
+ return TRILOGY_OK;
667
+
668
+ fail:
669
+ return rc;
670
+ }
671
+
672
+ int trilogy_build_quit_packet(trilogy_builder_t *builder)
673
+ {
674
+ int rc = TRILOGY_OK;
675
+
676
+ CHECKED(trilogy_builder_write_uint8(builder, TRILOGY_CMD_QUIT));
677
+
678
+ trilogy_builder_finalize(builder);
679
+
680
+ return TRILOGY_OK;
681
+
682
+ fail:
683
+ return rc;
684
+ }
685
+
686
+ int trilogy_build_ssl_request_packet(trilogy_builder_t *builder, TRILOGY_CAPABILITIES_t flags)
687
+ {
688
+ static const char zeroes[23] = {0};
689
+
690
+ const uint32_t max_packet_len = TRILOGY_MAX_PACKET_LEN;
691
+ const uint8_t client_encoding = TRILOGY_CHARSET_UTF8_GENERAL_CI;
692
+ const uint32_t capabilities = flags | TRILOGY_CAPABILITIES_CLIENT | TRILOGY_CAPABILITIES_SSL;
693
+
694
+ int rc = TRILOGY_OK;
695
+
696
+ CHECKED(trilogy_builder_write_uint32(builder, capabilities));
697
+ CHECKED(trilogy_builder_write_uint32(builder, max_packet_len));
698
+ CHECKED(trilogy_builder_write_uint8(builder, client_encoding));
699
+ CHECKED(trilogy_builder_write_buffer(builder, zeroes, 23));
700
+ trilogy_builder_finalize(builder);
701
+
702
+ return TRILOGY_OK;
703
+
704
+ fail:
705
+ return rc;
706
+ }
707
+
708
+ int trilogy_build_stmt_prepare_packet(trilogy_builder_t *builder, const char *sql, size_t sql_len)
709
+ {
710
+ int rc = TRILOGY_OK;
711
+
712
+ CHECKED(trilogy_builder_write_uint8(builder, TRILOGY_CMD_STMT_PREPARE));
713
+
714
+ CHECKED(trilogy_builder_write_buffer(builder, sql, sql_len));
715
+
716
+ trilogy_builder_finalize(builder);
717
+
718
+ return TRILOGY_OK;
719
+
720
+ fail:
721
+ return rc;
722
+ }
723
+
724
+ int trilogy_build_stmt_execute_packet(trilogy_builder_t *builder, uint32_t stmt_id, uint8_t flags,
725
+ trilogy_binary_value_t *binds, uint16_t num_binds)
726
+ {
727
+ int rc = TRILOGY_OK;
728
+
729
+ CHECKED(trilogy_builder_write_uint8(builder, TRILOGY_CMD_STMT_EXECUTE));
730
+
731
+ CHECKED(trilogy_builder_write_uint32(builder, stmt_id));
732
+
733
+ CHECKED(trilogy_builder_write_uint8(builder, flags));
734
+
735
+ // apparently, iteration-count is always 1
736
+ CHECKED(trilogy_builder_write_uint32(builder, 1));
737
+
738
+ int i;
739
+
740
+ if (num_binds > 0) {
741
+ if (binds == NULL) {
742
+ return TRILOGY_PROTOCOL_VIOLATION;
743
+ }
744
+
745
+ uint8_t current_bits = 0;
746
+
747
+ for (i = 0; i < num_binds; i++) {
748
+ if (binds[i].is_null) {
749
+ current_bits |= 1 << (i % 8);
750
+ }
751
+
752
+ // If we hit a byte boundary, write the bits we have so far and continue
753
+ if ((i % 8) == 7) {
754
+ CHECKED(trilogy_builder_write_uint8(builder, current_bits))
755
+
756
+ current_bits = 0;
757
+ }
758
+ }
759
+
760
+ // If there would have been any remainder bits, finally write those as well
761
+ if (num_binds % 8) {
762
+ CHECKED(trilogy_builder_write_uint8(builder, current_bits))
763
+ }
764
+
765
+ // new params bound flag
766
+ CHECKED(trilogy_builder_write_uint8(builder, 0x1));
767
+
768
+ for (i = 0; i < num_binds; i++) {
769
+ CHECKED(trilogy_builder_write_uint8(builder, binds[i].type));
770
+
771
+ if (binds[i].is_unsigned) {
772
+ CHECKED(trilogy_builder_write_uint8(builder, 0x80));
773
+ } else {
774
+ CHECKED(trilogy_builder_write_uint8(builder, 0x00));
775
+ }
776
+ }
777
+
778
+ for (i = 0; i < num_binds; i++) {
779
+ trilogy_binary_value_t val = binds[i];
780
+
781
+ switch (val.type) {
782
+ case TRILOGY_TYPE_TINY:
783
+ CHECKED(trilogy_builder_write_uint8(builder, val.as.uint8));
784
+
785
+ break;
786
+ case TRILOGY_TYPE_SHORT:
787
+ CHECKED(trilogy_builder_write_uint16(builder, val.as.uint16));
788
+
789
+ break;
790
+ case TRILOGY_TYPE_INT24:
791
+ case TRILOGY_TYPE_LONG:
792
+ CHECKED(trilogy_builder_write_uint32(builder, val.as.uint32));
793
+
794
+ break;
795
+ case TRILOGY_TYPE_LONGLONG:
796
+ CHECKED(trilogy_builder_write_uint64(builder, val.as.uint64));
797
+
798
+ break;
799
+ case TRILOGY_TYPE_FLOAT:
800
+ CHECKED(trilogy_builder_write_float(builder, val.as.flt));
801
+
802
+ break;
803
+ case TRILOGY_TYPE_DOUBLE:
804
+ CHECKED(trilogy_builder_write_double(builder, val.as.dbl));
805
+
806
+ break;
807
+ case TRILOGY_TYPE_YEAR:
808
+ CHECKED(trilogy_builder_write_uint16(builder, val.as.year));
809
+
810
+ break;
811
+ case TRILOGY_TYPE_TIME: {
812
+ uint8_t field_len = 0;
813
+
814
+ if (val.as.time.micro_seconds) {
815
+ field_len = 12;
816
+ } else if (val.as.time.hour || val.as.time.minute || val.as.time.second) {
817
+ field_len = 8;
818
+ } else {
819
+ field_len = 0;
820
+ }
821
+
822
+ CHECKED(trilogy_builder_write_uint8(builder, field_len));
823
+
824
+ if (field_len > 0) {
825
+ CHECKED(trilogy_builder_write_uint8(builder, val.as.time.is_negative));
826
+
827
+ CHECKED(trilogy_builder_write_uint32(builder, val.as.time.days));
828
+
829
+ CHECKED(trilogy_builder_write_uint8(builder, val.as.time.hour));
830
+
831
+ CHECKED(trilogy_builder_write_uint8(builder, val.as.time.minute));
832
+
833
+ CHECKED(trilogy_builder_write_uint8(builder, val.as.time.second));
834
+
835
+ if (field_len > 8) {
836
+ CHECKED(trilogy_builder_write_uint32(builder, val.as.time.micro_seconds));
837
+ }
838
+ }
839
+
840
+ break;
841
+ }
842
+ case TRILOGY_TYPE_DATE:
843
+ case TRILOGY_TYPE_DATETIME:
844
+ case TRILOGY_TYPE_TIMESTAMP: {
845
+ uint8_t field_len = 0;
846
+
847
+ if (val.as.date.datetime.micro_seconds) {
848
+ field_len = 11;
849
+ } else if (val.as.date.datetime.hour || val.as.date.datetime.minute || val.as.date.datetime.second) {
850
+ field_len = 7;
851
+ } else if (val.as.date.year || val.as.date.month || val.as.date.day) {
852
+ field_len = 4;
853
+ } else {
854
+ field_len = 0;
855
+ }
856
+
857
+ CHECKED(trilogy_builder_write_uint8(builder, field_len));
858
+
859
+ if (field_len > 0) {
860
+ CHECKED(trilogy_builder_write_uint16(builder, val.as.date.year));
861
+
862
+ CHECKED(trilogy_builder_write_uint8(builder, val.as.date.month));
863
+
864
+ CHECKED(trilogy_builder_write_uint8(builder, val.as.date.day));
865
+
866
+ if (field_len > 4) {
867
+ CHECKED(trilogy_builder_write_uint8(builder, val.as.date.datetime.hour));
868
+
869
+ CHECKED(trilogy_builder_write_uint8(builder, val.as.date.datetime.minute));
870
+
871
+ CHECKED(trilogy_builder_write_uint8(builder, val.as.date.datetime.second));
872
+
873
+ if (field_len > 7) {
874
+ CHECKED(trilogy_builder_write_uint32(builder, val.as.date.datetime.micro_seconds));
875
+ }
876
+ }
877
+ }
878
+
879
+ break;
880
+ }
881
+ case TRILOGY_TYPE_DECIMAL:
882
+ case TRILOGY_TYPE_VARCHAR:
883
+ case TRILOGY_TYPE_BIT:
884
+ case TRILOGY_TYPE_NEWDECIMAL:
885
+ case TRILOGY_TYPE_ENUM:
886
+ case TRILOGY_TYPE_SET:
887
+ case TRILOGY_TYPE_TINY_BLOB:
888
+ case TRILOGY_TYPE_BLOB:
889
+ case TRILOGY_TYPE_MEDIUM_BLOB:
890
+ case TRILOGY_TYPE_LONG_BLOB:
891
+ case TRILOGY_TYPE_VAR_STRING:
892
+ case TRILOGY_TYPE_STRING:
893
+ case TRILOGY_TYPE_GEOMETRY:
894
+ CHECKED(trilogy_builder_write_lenenc_buffer(builder, val.as.str.data, val.as.str.len));
895
+
896
+ break;
897
+ case TRILOGY_TYPE_NULL:
898
+ // already handled by the null bitmap
899
+ break;
900
+ default:
901
+ return TRILOGY_UNKNOWN_TYPE;
902
+ }
903
+ }
904
+ }
905
+
906
+ trilogy_builder_finalize(builder);
907
+
908
+ return TRILOGY_OK;
909
+
910
+ fail:
911
+ return rc;
912
+ }
913
+
914
+ int trilogy_build_stmt_bind_data_packet(trilogy_builder_t *builder, uint32_t stmt_id, uint16_t param_id, uint8_t *data,
915
+ size_t data_len)
916
+ {
917
+ int rc = TRILOGY_OK;
918
+
919
+ CHECKED(trilogy_builder_write_uint8(builder, TRILOGY_CMD_STMT_SEND_LONG_DATA));
920
+
921
+ CHECKED(trilogy_builder_write_uint32(builder, stmt_id));
922
+
923
+ CHECKED(trilogy_builder_write_uint16(builder, param_id));
924
+
925
+ CHECKED(trilogy_builder_write_buffer(builder, data, data_len));
926
+
927
+ trilogy_builder_finalize(builder);
928
+
929
+ return TRILOGY_OK;
930
+
931
+ fail:
932
+ return rc;
933
+ }
934
+
935
+ int trilogy_build_stmt_reset_packet(trilogy_builder_t *builder, uint32_t stmt_id)
936
+ {
937
+ int rc = TRILOGY_OK;
938
+
939
+ CHECKED(trilogy_builder_write_uint8(builder, TRILOGY_CMD_STMT_RESET));
940
+
941
+ CHECKED(trilogy_builder_write_uint32(builder, stmt_id));
942
+
943
+ trilogy_builder_finalize(builder);
944
+
945
+ return TRILOGY_OK;
946
+
947
+ fail:
948
+ return rc;
949
+ }
950
+
951
+ int trilogy_build_stmt_close_packet(trilogy_builder_t *builder, uint32_t stmt_id)
952
+ {
953
+ int rc = TRILOGY_OK;
954
+
955
+ CHECKED(trilogy_builder_write_uint8(builder, TRILOGY_CMD_STMT_CLOSE));
956
+
957
+ CHECKED(trilogy_builder_write_uint32(builder, stmt_id));
958
+
959
+ trilogy_builder_finalize(builder);
960
+
961
+ return TRILOGY_OK;
962
+
963
+ fail:
964
+ return rc;
965
+ }
966
+
967
+ static inline int is_null(uint8_t *null_bitmap, uint64_t bitmap_len, uint64_t column_offset, bool *col_is_null)
968
+ {
969
+ if (column_offset > (bitmap_len * 8) - 1) {
970
+ return TRILOGY_PROTOCOL_VIOLATION;
971
+ }
972
+
973
+ column_offset += 2;
974
+
975
+ uint64_t byte_offset = column_offset / 8;
976
+
977
+ // for the binary protocol result row packet, we need to offset the bit check
978
+ // by 2
979
+ *col_is_null = (null_bitmap[byte_offset] & (1 << (column_offset % 8))) != 0;
980
+
981
+ return TRILOGY_OK;
982
+ }
983
+
984
+ int trilogy_parse_stmt_row_packet(const uint8_t *buff, size_t len, trilogy_column_packet_t *columns,
985
+ uint64_t column_count, trilogy_binary_value_t *out_values)
986
+ {
987
+ int rc;
988
+
989
+ trilogy_reader_t reader = TRILOGY_READER(buff, len);
990
+
991
+ // skip packet header
992
+ CHECKED(trilogy_reader_get_uint8(&reader, NULL));
993
+
994
+ uint8_t *null_bitmap = NULL;
995
+ uint64_t bitmap_len = (column_count + 7 + 2) / 8;
996
+
997
+ CHECKED(trilogy_reader_get_buffer(&reader, bitmap_len, (const void **)&null_bitmap));
998
+
999
+ for (uint64_t i = 0; i < column_count; i++) {
1000
+ CHECKED(is_null(null_bitmap, bitmap_len, i, &out_values[i].is_null));
1001
+ if (out_values[i].is_null) {
1002
+ out_values[i].type = TRILOGY_TYPE_NULL;
1003
+ } else {
1004
+ out_values[i].is_null = false;
1005
+
1006
+ out_values[i].type = columns[i].type;
1007
+
1008
+ if (columns[i].flags & TRILOGY_COLUMN_FLAG_UNSIGNED) {
1009
+ out_values[i].is_unsigned = true;
1010
+ }
1011
+
1012
+ switch (columns[i].type) {
1013
+ case TRILOGY_TYPE_STRING:
1014
+ case TRILOGY_TYPE_VARCHAR:
1015
+ case TRILOGY_TYPE_VAR_STRING:
1016
+ case TRILOGY_TYPE_ENUM:
1017
+ case TRILOGY_TYPE_SET:
1018
+ case TRILOGY_TYPE_LONG_BLOB:
1019
+ case TRILOGY_TYPE_MEDIUM_BLOB:
1020
+ case TRILOGY_TYPE_BLOB:
1021
+ case TRILOGY_TYPE_TINY_BLOB:
1022
+ case TRILOGY_TYPE_GEOMETRY:
1023
+ case TRILOGY_TYPE_BIT:
1024
+ case TRILOGY_TYPE_DECIMAL:
1025
+ case TRILOGY_TYPE_NEWDECIMAL:
1026
+ case TRILOGY_TYPE_JSON:
1027
+ CHECKED(trilogy_reader_get_lenenc_buffer(&reader, &out_values[i].as.str.len,
1028
+ (const void **)&out_values[i].as.str.data));
1029
+
1030
+ break;
1031
+ case TRILOGY_TYPE_LONGLONG:
1032
+ CHECKED(trilogy_reader_get_uint64(&reader, &out_values[i].as.uint64));
1033
+
1034
+ break;
1035
+ case TRILOGY_TYPE_DOUBLE:
1036
+ CHECKED(trilogy_reader_get_double(&reader, &out_values[i].as.dbl));
1037
+
1038
+ break;
1039
+ case TRILOGY_TYPE_LONG:
1040
+ case TRILOGY_TYPE_INT24:
1041
+ CHECKED(trilogy_reader_get_uint32(&reader, &out_values[i].as.uint32));
1042
+
1043
+ break;
1044
+ case TRILOGY_TYPE_FLOAT:
1045
+ CHECKED(trilogy_reader_get_float(&reader, &out_values[i].as.flt));
1046
+
1047
+ break;
1048
+ case TRILOGY_TYPE_SHORT:
1049
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_values[i].as.uint16));
1050
+
1051
+ break;
1052
+ case TRILOGY_TYPE_YEAR:
1053
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_values[i].as.year));
1054
+
1055
+ break;
1056
+ case TRILOGY_TYPE_TINY:
1057
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.uint8));
1058
+
1059
+ break;
1060
+ case TRILOGY_TYPE_DATE:
1061
+ case TRILOGY_TYPE_DATETIME:
1062
+ case TRILOGY_TYPE_TIMESTAMP: {
1063
+ uint8_t time_len;
1064
+
1065
+ CHECKED(trilogy_reader_get_uint8(&reader, &time_len));
1066
+
1067
+ out_values[i].as.date.year = 0;
1068
+ out_values[i].as.date.month = 0;
1069
+ out_values[i].as.date.day = 0;
1070
+ out_values[i].as.date.datetime.hour = 0;
1071
+ out_values[i].as.date.datetime.minute = 0;
1072
+ out_values[i].as.date.datetime.second = 0;
1073
+ out_values[i].as.date.datetime.micro_seconds = 0;
1074
+
1075
+ switch (time_len) {
1076
+ case 0:
1077
+ break;
1078
+ case 4:
1079
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_values[i].as.date.year));
1080
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.date.month));
1081
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.date.day));
1082
+
1083
+ break;
1084
+ case 7:
1085
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_values[i].as.date.year));
1086
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.date.month));
1087
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.date.day));
1088
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.date.datetime.hour));
1089
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.date.datetime.minute));
1090
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.date.datetime.second));
1091
+
1092
+ break;
1093
+ case 11:
1094
+ CHECKED(trilogy_reader_get_uint16(&reader, &out_values[i].as.date.year));
1095
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.date.month));
1096
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.date.day));
1097
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.date.datetime.hour));
1098
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.date.datetime.minute));
1099
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.date.datetime.second));
1100
+ CHECKED(trilogy_reader_get_uint32(&reader, &out_values[i].as.date.datetime.micro_seconds));
1101
+
1102
+ break;
1103
+ default:
1104
+ return TRILOGY_PROTOCOL_VIOLATION;
1105
+ }
1106
+
1107
+ break;
1108
+ }
1109
+ case TRILOGY_TYPE_TIME: {
1110
+ uint8_t time_len;
1111
+
1112
+ CHECKED(trilogy_reader_get_uint8(&reader, &time_len));
1113
+
1114
+ out_values[i].as.time.is_negative = false;
1115
+ out_values[i].as.time.days = 0;
1116
+ out_values[i].as.time.hour = 0;
1117
+ out_values[i].as.time.minute = 0;
1118
+ out_values[i].as.time.second = 0;
1119
+ out_values[i].as.time.micro_seconds = 0;
1120
+
1121
+ switch (time_len) {
1122
+ case 0:
1123
+ break;
1124
+ case 8: {
1125
+ uint8_t is_negative;
1126
+
1127
+ CHECKED(trilogy_reader_get_uint8(&reader, &is_negative));
1128
+
1129
+ out_values[i].as.time.is_negative = is_negative == 1;
1130
+
1131
+ CHECKED(trilogy_reader_get_uint32(&reader, &out_values[i].as.time.days));
1132
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.time.hour));
1133
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.time.minute));
1134
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.time.second));
1135
+ CHECKED(trilogy_reader_get_uint32(&reader, &out_values[i].as.time.micro_seconds));
1136
+
1137
+ break;
1138
+ }
1139
+ case 12: {
1140
+ uint8_t is_negative;
1141
+
1142
+ CHECKED(trilogy_reader_get_uint8(&reader, &is_negative));
1143
+
1144
+ out_values[i].as.time.is_negative = is_negative == 1;
1145
+
1146
+ CHECKED(trilogy_reader_get_uint32(&reader, &out_values[i].as.time.days));
1147
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.time.hour));
1148
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.time.minute));
1149
+ CHECKED(trilogy_reader_get_uint8(&reader, &out_values[i].as.time.second));
1150
+ CHECKED(trilogy_reader_get_uint32(&reader, &out_values[i].as.time.micro_seconds));
1151
+
1152
+ break;
1153
+ }
1154
+ default:
1155
+ return TRILOGY_PROTOCOL_VIOLATION;
1156
+ }
1157
+
1158
+ break;
1159
+ }
1160
+ case TRILOGY_TYPE_NULL:
1161
+ default:
1162
+ // we cover TRILOGY_TYPE_NULL here because we should never hit this case
1163
+ // explicitly as it should be covered in the null bitmap
1164
+ return TRILOGY_UNKNOWN_TYPE;
1165
+ }
1166
+ }
1167
+ }
1168
+
1169
+ return trilogy_reader_finish(&reader);
1170
+
1171
+ fail:
1172
+ return rc;
1173
+ }
1174
+
1175
+ #undef CHECKED