66
* extract the type of the object that is placed where a length-encoded string is expected
68
* reads a byte from the packet and checks if it either a:
74
int network_mysqld_proto_peek_lenenc_type(network_packet *packet, network_mysqld_lenenc_type *type) {
75
guint off = packet->offset;
76
unsigned char *bytestream = (unsigned char *)packet->data->str;
78
g_return_val_if_fail(off < packet->data->len, -1);
80
if (bytestream[off] < 251) { /* */
81
*type = NETWORK_MYSQLD_LENENC_TYPE_INT;
82
} else if (bytestream[off] == 251) { /* NULL */
83
*type = NETWORK_MYSQLD_LENENC_TYPE_NULL;
84
} else if (bytestream[off] == 252) { /* 2 byte length*/
85
*type = NETWORK_MYSQLD_LENENC_TYPE_INT;
86
} else if (bytestream[off] == 253) { /* 3 byte */
87
*type = NETWORK_MYSQLD_LENENC_TYPE_INT;
88
} else if (bytestream[off] == 254) { /* 8 byte OR EOF */
90
packet->data->len - packet->offset < 8) {
91
*type = NETWORK_MYSQLD_LENENC_TYPE_EOF;
93
*type = NETWORK_MYSQLD_LENENC_TYPE_INT;
96
*type = NETWORK_MYSQLD_LENENC_TYPE_ERR;
103
55
* decode a length-encoded integer from a network packet
105
57
* _off is incremented on success
107
59
* @param packet the MySQL-packet to decode
108
* @param v destination of the integer
109
* @return 0 on success, non-0 on error
60
* @param _off offset in into the packet
61
* @return the decoded number
112
int network_mysqld_proto_get_lenenc_int(network_packet *packet, guint64 *v) {
113
guint off = packet->offset;
64
guint64 network_mysqld_proto_get_lenenc_int(GString *packet, guint *_off) {
115
unsigned char *bytestream = (unsigned char *)packet->data->str;
67
unsigned char *bytestream = (unsigned char *)packet->str;
117
if (off >= packet->data->len) return -1;
69
g_assert(off < packet->len);
119
71
if (bytestream[off] < 251) { /* */
120
72
ret = bytestream[off];
73
} else if (bytestream[off] == 251) { /* NULL in row-data */
74
ret = bytestream[off];
121
75
} else if (bytestream[off] == 252) { /* 2 byte length*/
122
if (off + 2 >= packet->data->len) return -1;
76
g_assert(off + 2 < packet->len);
123
77
ret = (bytestream[off + 1] << 0) |
124
78
(bytestream[off + 2] << 8) ;
126
80
} else if (bytestream[off] == 253) { /* 3 byte */
127
if (off + 3 >= packet->data->len) return -1;
81
g_assert(off + 3 < packet->len);
128
82
ret = (bytestream[off + 1] << 0) |
129
83
(bytestream[off + 2] << 8) |
130
84
(bytestream[off + 3] << 16);
133
87
} else if (bytestream[off] == 254) { /* 8 byte */
134
if (off + 8 >= packet->data->len) return -1;
88
g_assert(off + 8 < packet->len);
135
89
ret = (bytestream[off + 5] << 0) |
136
90
(bytestream[off + 6] << 8) |
137
91
(bytestream[off + 7] << 16) |
149
/* if we hit this place we complete have no idea about the protocol */
150
g_critical("%s: bytestream[%d] is %d",
103
g_error("%s.%d: bytestream[%d] is %d",
152
105
off, bytestream[off]);
154
/* either ERR (255) or NULL (251) */
160
packet->offset = off;
115
* decode a OK packet from the network packet
117
int network_mysqld_proto_get_ok_packet(GString *packet, guint64 *affected, guint64 *insert_id, int *server_status, int *warning_count, char **msg) {
122
field_count = network_mysqld_proto_get_int8(packet, &off);
123
g_assert(field_count == 0);
125
dest = network_mysqld_proto_get_lenenc_int(packet, &off); if (affected) *affected = dest;
126
dest = network_mysqld_proto_get_lenenc_int(packet, &off); if (insert_id) *insert_id = dest;
128
dest = network_mysqld_proto_get_int16(packet, &off); if (server_status) *server_status = dest;
129
dest = network_mysqld_proto_get_int16(packet, &off); if (warning_count) *warning_count = dest;
131
if (msg) *msg = NULL;
136
int network_mysqld_proto_append_ok_packet(GString *packet, guint64 affected_rows, guint64 insert_id, guint16 server_status, guint16 warnings) {
137
network_mysqld_proto_append_int8(packet, 0); /* no fields */
138
network_mysqld_proto_append_lenenc_int(packet, affected_rows);
139
network_mysqld_proto_append_lenenc_int(packet, insert_id);
140
network_mysqld_proto_append_int16(packet, server_status); /* autocommit */
141
network_mysqld_proto_append_int16(packet, warnings); /* no warnings */
147
* create a ERR packet
149
* @note the sqlstate has to match the SQL standard. If no matching SQL state is known, leave it at NULL
151
* @param packet network packet
152
* @param errmsg the error message
153
* @param errmsg_len byte-len of the error-message
154
* @param errorcode mysql error-code we want to send
155
* @param sqlstate if none-NULL, 5-char SQL state to send, if NULL, default SQL state is used
157
* @return 0 on success
159
int network_mysqld_proto_append_error_packet(GString *packet, const char *errmsg, gsize errmsg_len, guint errorcode, const gchar *sqlstate) {
160
network_mysqld_proto_append_int8(packet, 0xff); /* ERR */
161
network_mysqld_proto_append_int16(packet, errorcode); /* errorcode */
162
g_string_append_c(packet, '#');
164
g_string_append_len(packet, C("07000"));
166
g_string_append_len(packet, sqlstate, 5);
169
if (errmsg_len < 512) {
170
g_string_append_len(packet, errmsg, errmsg_len);
172
/* truncate the err-msg */
173
g_string_append_len(packet, errmsg, 512);
168
181
* skip bytes in the network packet
170
183
* a assertion makes sure that we can't skip over the end of the packet
172
185
* @param packet the MySQL network packet
186
* @param _off offset into the packet
173
187
* @param size bytes to skip
176
int network_mysqld_proto_skip(network_packet *packet, gsize size) {
177
if (packet->offset + size > packet->data->len) return -1;
190
void network_mysqld_proto_skip(GString *packet, guint *_off, gsize size) {
191
g_assert(*_off + size <= packet->len);
179
packet->offset += size;
185
197
* get a fixed-length integer from the network packet
187
199
* @param packet the MySQL network packet
188
* @param v destination of the integer
200
* @param _off offset into the packet
189
201
* @param size byte-len of the integer to decode
190
202
* @return a the decoded integer
192
int network_mysqld_proto_peek_int_len(network_packet *packet, guint64 *v, gsize size) {
204
guint64 network_mysqld_proto_get_int_len(GString *packet, guint *_off, gsize size) {
195
guint32 r_l = 0, r_h = 0;
196
guchar *bytes = (guchar *)packet->data->str + packet->offset;
198
if (packet->offset > packet->data->len) {
201
if (packet->offset + size > packet->data->len) {
206
* for some reason left-shift > 32 leads to negative numbers
208
for (i = 0, shift = 0;
210
i++, shift += 8, bytes++) {
211
r_l |= ((*bytes) << shift);
216
i++, shift += 8, bytes++) {
217
r_h |= ((*bytes) << shift);
220
*v = (((guint64)r_h << 32) | r_l);
225
int network_mysqld_proto_get_int_len(network_packet *packet, guint64 *v, gsize size) {
228
err = err || network_mysqld_proto_peek_int_len(packet, v, size);
232
packet->offset += size;
237
* get a 8-bit integer from the network packet
239
* @param packet the MySQL network packet
240
* @param v dest for the number
241
* @return 0 on success, non-0 on error
242
* @see network_mysqld_proto_get_int_len()
244
int network_mysqld_proto_get_int8(network_packet *packet, guint8 *v) {
247
if (network_mysqld_proto_get_int_len(packet, &v64, 1)) return -1;
249
g_assert_cmpint(v64 & 0xff, ==, v64); /* check that we really only got one byte back */
257
* get a 8-bit integer from the network packet
259
* @param packet the MySQL network packet
260
* @param v dest for the number
261
* @return 0 on success, non-0 on error
262
* @see network_mysqld_proto_get_int_len()
264
int network_mysqld_proto_peek_int8(network_packet *packet, guint8 *v) {
267
if (network_mysqld_proto_peek_int_len(packet, &v64, 1)) return -1;
269
g_assert_cmpint(v64 & 0xff, ==, v64); /* check that we really only got one byte back */
278
* get a 16-bit integer from the network packet
280
* @param packet the MySQL network packet
281
* @param v dest for the number
282
* @return 0 on success, non-0 on error
283
* @see network_mysqld_proto_get_int_len()
285
int network_mysqld_proto_get_int16(network_packet *packet, guint16 *v) {
288
if (network_mysqld_proto_get_int_len(packet, &v64, 2)) return -1;
290
g_assert_cmpint(v64 & 0xffff, ==, v64); /* check that we really only got two byte back */
298
* get a 16-bit integer from the network packet
300
* @param packet the MySQL network packet
301
* @param v dest for the number
302
* @return 0 on success, non-0 on error
303
* @see network_mysqld_proto_get_int_len()
305
int network_mysqld_proto_peek_int16(network_packet *packet, guint16 *v) {
308
if (network_mysqld_proto_peek_int_len(packet, &v64, 2)) return -1;
310
g_assert_cmpint(v64 & 0xffff, ==, v64); /* check that we really only got two byte back */
319
* get a 24-bit integer from the network packet
321
* @param packet the MySQL network packet
322
* @param v dest for the number
323
* @return 0 on success, non-0 on error
324
* @see network_mysqld_proto_get_int_len()
326
int network_mysqld_proto_get_int24(network_packet *packet, guint32 *v) {
329
if (network_mysqld_proto_get_int_len(packet, &v64, 3)) return -1;
331
g_assert_cmpint(v64 & 0x00ffffff, ==, v64); /* check that we really only got two byte back */
333
*v = v64 & 0x00ffffff;
210
g_assert(*_off < packet->len);
211
if (*_off + size > packet->len) {
214
g_assert(*_off + size <= packet->len);
216
for (i = 0, shift = 0; i < size; i++, shift += 8) {
217
r += (unsigned char)(packet->str[off + i]) << shift;
226
* get a 8-bit integer from the network packet
228
* @param packet the MySQL network packet
229
* @param _off offset into the packet
230
* @return a the decoded integer
231
* @see network_mysqld_proto_get_int_len()
233
guint8 network_mysqld_proto_get_int8(GString *packet, guint *_off) {
234
return network_mysqld_proto_get_int_len(packet, _off, 1);
238
* get a 16-bit integer from the network packet
240
* @param packet the MySQL network packet
241
* @param _off offset into the packet
242
* @return a the decoded integer
243
* @see network_mysqld_proto_get_int_len()
245
guint16 network_mysqld_proto_get_int16(GString *packet, guint *_off) {
246
return network_mysqld_proto_get_int_len(packet, _off, 2);
340
250
* get a 32-bit integer from the network packet
342
252
* @param packet the MySQL network packet
343
* @param v dest for the number
344
* @return 0 on success, non-0 on error
345
* @see network_mysqld_proto_get_int_len()
347
int network_mysqld_proto_get_int32(network_packet *packet, guint32 *v) {
350
if (network_mysqld_proto_get_int_len(packet, &v64, 4)) return -1;
352
*v = v64 & 0xffffffff;
358
* get a 6-byte integer from the network packet
360
* @param packet the MySQL network packet
361
* @param v dest for the number
362
* @return 0 on success, non-0 on error
363
* @see network_mysqld_proto_get_int_len()
365
int network_mysqld_proto_get_int48(network_packet *packet, guint64 *v) {
368
if (network_mysqld_proto_get_int_len(packet, &v64, 6)) return -1;
376
* get a 8-byte integer from the network packet
378
* @param packet the MySQL network packet
379
* @param v dest for the number
380
* @return 0 on success, non-0 on error
381
* @see network_mysqld_proto_get_int_len()
383
int network_mysqld_proto_get_int64(network_packet *packet, guint64 *v) {
384
return network_mysqld_proto_get_int_len(packet, v, 8);
388
* find a 8-bit integer in the network packet
390
* @param packet the MySQL network packet
391
* @param c character to find
392
* @param pos offset into the packet the 'c' was found
253
* @param _off offset into the packet
393
254
* @return a the decoded integer
394
255
* @see network_mysqld_proto_get_int_len()
396
int network_mysqld_proto_find_int8(network_packet *packet, guint8 c, guint *pos) {
398
guint off = packet->offset;
403
err = err || network_mysqld_proto_get_int8(packet, &_c);
406
*pos = packet->offset - off;
412
packet->offset = off;
257
guint32 network_mysqld_proto_get_int32(GString *packet, guint *_off) {
258
return network_mysqld_proto_get_int_len(packet, _off, 4);
419
262
* get a string from the network packet
421
264
* @param packet the MySQL network packet
422
* @param s dest of the string
265
* @param _off offset into the packet
423
266
* @param len length of the string
424
* @return 0 on success, non-0 otherwise
425
267
* @return the string (allocated) or NULL of len is 0
427
int network_mysqld_proto_get_string_len(network_packet *packet, gchar **s, gsize len) {
269
gchar *network_mysqld_proto_get_string_len(GString *packet, guint *_off, gsize len) {
435
if (packet->offset > packet->data->len) {
438
if (packet->offset + len > packet->data->len) {
439
g_critical("%s: packet-offset out of range: %u + "F_SIZE_T" > "F_SIZE_T,
441
packet->offset, len, packet->data->len);
447
str = g_malloc(len + 1);
448
memcpy(str, packet->data->str + packet->offset, len);
454
packet->offset += len;
272
g_assert(*_off < packet->len);
273
if (*_off + len > packet->len) {
274
g_error("packet-offset out of range: %u + "F_SIZE_T" > "F_SIZE_T, *_off, len, packet->len);
277
str = len ? g_strndup(packet->str + *_off, len) : NULL;
464
287
* variable length strings are prefixed with variable-length integer defining the length of the string
466
289
* @param packet the MySQL network packet
467
* @param s destination of the decoded string
468
* @param _len destination of the length of the decoded string, if len is non-NULL
469
* @return 0 on success, non-0 on error
290
* @param _off offset into the packet
470
292
* @see network_mysqld_proto_get_string_len(), network_mysqld_proto_get_lenenc_int()
472
int network_mysqld_proto_get_lenenc_string(network_packet *packet, gchar **s, guint64 *_len) {
294
gchar *network_mysqld_proto_get_lenenc_string(GString *packet, guint *_off) {
475
if (packet->offset >= packet->data->len) {
476
g_debug_hexdump(G_STRLOC, S(packet->data));
479
if (packet->offset >= packet->data->len) {
483
if (network_mysqld_proto_get_lenenc_int(packet, &len)) return -1;
485
if (packet->offset + len > packet->data->len) return -1;
487
if (_len) *_len = len;
489
return network_mysqld_proto_get_string_len(packet, s, len);
297
len = network_mysqld_proto_get_lenenc_int(packet, _off);
299
g_assert(*_off < packet->len);
300
g_assert(*_off + len <= packet->len);
302
return network_mysqld_proto_get_string_len(packet, _off, len);
493
306
* get a NUL-terminated string from the network packet
495
308
* @param packet the MySQL network packet
496
* @param s dest of the string
497
* @return 0 on success, non-0 otherwise
309
* @param _off offset into the packet
498
311
* @see network_mysqld_proto_get_string_len()
500
int network_mysqld_proto_get_string(network_packet *packet, gchar **s) {
504
for (len = 0; packet->offset + len < packet->data->len && *(packet->data->str + packet->offset + len); len++);
506
if (*(packet->data->str + packet->offset + len) != '\0') {
507
/* this has to be a \0 */
313
gchar *network_mysqld_proto_get_string(GString *packet, guint *_off) {
317
for (len = 0; *_off + len < packet->len && *(packet->str + *_off + len); len++);
319
g_assert(*(packet->str + *_off + len) == '\0'); /* this has to be a \0 */
512
if (packet->offset >= packet->data->len) {
515
if (packet->offset + len > packet->data->len) {
322
g_assert(*_off < packet->len);
323
g_assert(*_off + len <= packet->len);
520
326
* copy the string w/o the NUL byte
522
err = err || network_mysqld_proto_get_string_len(packet, s, len);
328
r = network_mysqld_proto_get_string_len(packet, _off, len);
525
err = err || network_mysqld_proto_skip(packet, 1);
532
338
* get a GString from the network packet
534
340
* @param packet the MySQL network packet
341
* @param _off offset into the packet
535
342
* @param len bytes to copy
536
343
* @param out a GString which carries the string
537
* @return 0 on success, -1 on error
344
* @return a pointer to the string in out
539
int network_mysqld_proto_get_gstring_len(network_packet *packet, gsize len, GString *out) {
346
gchar *network_mysqld_proto_get_gstring_len(GString *packet, guint *_off, gsize len, GString *out) {
544
347
g_string_truncate(out, 0);
546
if (!len) return 0; /* nothing to copy */
548
err = err || (packet->offset >= packet->data->len); /* the offset is already too large */
549
err = err || (packet->offset + len > packet->data->len); /* offset would get too large */
552
g_string_append_len(out, packet->data->str + packet->offset, len);
553
packet->offset += len;
350
g_assert(*_off < packet->len);
351
if (*_off + len > packet->len) {
352
g_error("packet-offset out of range: %u + "F_SIZE_T" > "F_SIZE_T, *_off, len, packet->len);
355
g_string_append_len(out, packet->str + *_off, len);
560
363
* get a NUL-terminated GString from the network packet
562
365
* @param packet the MySQL network packet
366
* @param _off offset into the packet
563
367
* @param out a GString which carries the string
564
368
* @return a pointer to the string in out
566
370
* @see network_mysqld_proto_get_gstring_len()
568
int network_mysqld_proto_get_gstring(network_packet *packet, GString *out) {
572
for (len = 0; packet->offset + len < packet->data->len && *(packet->data->str + packet->offset + len) != '\0'; len++);
574
if (packet->offset + len == packet->data->len) { /* havn't found a trailing \0 */
372
gchar *network_mysqld_proto_get_gstring(GString *packet, guint *_off, GString *out) {
376
for (len = 0; *_off + len < packet->len && *(packet->str + *_off + len); len++);
378
g_assert(*(packet->str + *_off + len) == '\0'); /* this has to be a \0 */
579
g_assert(packet->offset < packet->data->len);
580
g_assert(packet->offset + len <= packet->data->len);
381
g_assert(*_off < packet->len);
382
g_assert(*_off + len <= packet->len);
582
err = err || network_mysqld_proto_get_gstring_len(packet, len, out);
384
r = network_mysqld_proto_get_gstring_len(packet, _off, len, out);
585
387
/* skip the \0 */
586
err = err || network_mysqld_proto_skip(packet, 1);
592
394
* get a variable-length GString from the network packet
594
396
* @param packet the MySQL network packet
397
* @param _off offset into the packet
595
398
* @param out a GString which carries the string
596
* @return 0 on success, non-0 on error
399
* @return a pointer to the string in out
598
401
* @see network_mysqld_proto_get_gstring_len(), network_mysqld_proto_get_lenenc_int()
600
int network_mysqld_proto_get_lenenc_gstring(network_packet *packet, GString *out) {
403
gchar *network_mysqld_proto_get_lenenc_gstring(GString *packet, guint *_off, GString *out) {
604
err = err || network_mysqld_proto_get_lenenc_int(packet, &len);
605
err = err || network_mysqld_proto_get_gstring_len(packet, len, out);
406
len = network_mysqld_proto_get_lenenc_int(packet, _off);
408
return network_mysqld_proto_get_gstring_len(packet, _off, len, out);
871
626
* @see network_mysqld_proto_append_int_len()
873
628
int network_mysqld_proto_append_int32(GString *packet, guint32 num) {
874
return network_mysqld_proto_append_int_len(packet, num, 4);
878
* encode 48-bit integer in to a network packet
880
* @param packet the MySQL network packet
881
* @param num integer to encode
883
* @see network_mysqld_proto_append_int_len()
885
int network_mysqld_proto_append_int48(GString *packet, guint64 num) {
886
return network_mysqld_proto_append_int_len(packet, num, 6);
891
* encode 64-bit integer in to a network packet
893
* @param packet the MySQL network packet
894
* @param num integer to encode
896
* @see network_mysqld_proto_append_int_len()
898
int network_mysqld_proto_append_int64(GString *packet, guint64 num) {
899
return network_mysqld_proto_append_int_len(packet, num, 8);
904
* hash the password as MySQL 4.1 and later assume
908
* @see network_mysqld_proto_scramble
910
int network_mysqld_proto_password_hash(GString *response, const char *password, gsize password_len) {
913
/* first round: SHA1(password) */
914
cs = g_checksum_new(G_CHECKSUM_SHA1);
916
g_checksum_update(cs, (guchar *)password, password_len);
918
g_string_set_size(response, g_checksum_type_get_length(G_CHECKSUM_SHA1));
919
response->len = response->allocated_len; /* will be overwritten with the right value in the next step */
920
g_checksum_get_digest(cs, (guchar *)response->str, &(response->len));
928
* scramble the hashed password with the challenge
930
* @param response dest
931
* @param challenge the challenge string as sent by the mysql-server
932
* @param challenge_len length of the challenge
933
* @param hashed_password hashed password
934
* @param hashed_password_len length of the hashed password
936
* @see network_mysqld_proto_password_hash
938
int network_mysqld_proto_password_scramble(GString *response,
939
const char *challenge, gsize challenge_len,
940
const char *hashed_password, gsize hashed_password_len) {
945
g_return_val_if_fail(NULL != challenge, -1);
946
g_return_val_if_fail(20 == challenge_len, -1);
947
g_return_val_if_fail(NULL != hashed_password, -1);
948
g_return_val_if_fail(20 == hashed_password_len, -1);
953
* XOR( SHA1(password), SHA1(challenge + SHA1(SHA1(password)))
955
* where SHA1(password) is the hashed_password and
956
* challenge is ... challenge
958
* XOR( hashed_password, SHA1(challenge + SHA1(hashed_password)))
962
/* 1. SHA1(hashed_password) */
963
step2 = g_string_new(NULL);
964
network_mysqld_proto_password_hash(step2, hashed_password, hashed_password_len);
966
/* 2. SHA1(challenge + SHA1(hashed_password) */
967
cs = g_checksum_new(G_CHECKSUM_SHA1);
968
g_checksum_update(cs, (guchar *)challenge, challenge_len);
969
g_checksum_update(cs, (guchar *)step2->str, step2->len);
971
g_string_set_size(response, g_checksum_type_get_length(G_CHECKSUM_SHA1));
972
response->len = response->allocated_len;
973
g_checksum_get_digest(cs, (guchar *)response->str, &(response->len));
977
/* XOR the hashed_password with SHA1(challenge + SHA1(hashed_password)) */
978
for (i = 0; i < 20; i++) {
979
response->str[i] = (guchar)response->str[i] ^ (guchar)hashed_password[i];
982
g_string_free(step2, TRUE);
988
* unscramble the auth-response and get the hashed-password
990
* @param hashed_password dest of the hashed password
991
* @param challenge the challenge string as sent by the mysql-server
992
* @param challenge_len length of the challenge
993
* @param response auth response as sent by the client
994
* @param response_len length of response
995
* @param double_hashed the double hashed password as stored in the mysql.server table (without * and unhexed)
996
* @param double_hashed_len length of double_hashed
998
* @see network_mysqld_proto_scramble
1000
int network_mysqld_proto_password_unscramble(
1001
GString *hashed_password,
1002
const char *challenge, gsize challenge_len,
1003
const char *response, gsize response_len,
1004
const char *double_hashed, gsize double_hashed_len) {
1008
g_return_val_if_fail(NULL != response, FALSE);
1009
g_return_val_if_fail(20 == response_len, FALSE);
1010
g_return_val_if_fail(NULL != challenge, FALSE);
1011
g_return_val_if_fail(20 == challenge_len, FALSE);
1012
g_return_val_if_fail(NULL != double_hashed, FALSE);
1013
g_return_val_if_fail(20 == double_hashed_len, FALSE);
1016
* to check we have to:
1018
* hashed_password = XOR( response, SHA1(challenge + double_hashed))
1019
* double_hashed == SHA1(hashed_password)
1021
* where SHA1(password) is the hashed_password and
1022
* challenge is ... challenge
1023
* response is the response of the client
1025
* XOR( hashed_password, SHA1(challenge + SHA1(hashed_password)))
1030
/* 1. SHA1(challenge + double_hashed) */
1031
cs = g_checksum_new(G_CHECKSUM_SHA1);
1032
g_checksum_update(cs, (guchar *)challenge, challenge_len);
1033
g_checksum_update(cs, (guchar *)double_hashed, double_hashed_len);
1035
g_string_set_size(hashed_password, g_checksum_type_get_length(G_CHECKSUM_SHA1));
1036
hashed_password->len = hashed_password->allocated_len;
1037
g_checksum_get_digest(cs, (guchar *)hashed_password->str, &(hashed_password->len));
1039
g_checksum_free(cs);
1041
/* 2. XOR the response with SHA1(challenge + SHA1(hashed_password)) */
1042
for (i = 0; i < 20; i++) {
1043
hashed_password->str[i] = (guchar)response[i] ^ (guchar)hashed_password->str[i];
1050
* check if response and challenge match a double-hashed password
1052
* @param challenge the challenge string as sent by the mysql-server
1053
* @param challenge_len length of the challenge
1054
* @param response auth response as sent by the client
1055
* @param response_len length of response
1056
* @param double_hashed the double hashed password as stored in the mysql.server table (without * and unhexed)
1057
* @param double_hashed_len length of double_hashed
1059
* @see network_mysqld_proto_scramble
1061
gboolean network_mysqld_proto_password_check(
1062
const char *challenge, gsize challenge_len,
1063
const char *response, gsize response_len,
1064
const char *double_hashed, gsize double_hashed_len) {
1066
GString *hashed_password, *step2;
1069
g_return_val_if_fail(NULL != response, FALSE);
1070
g_return_val_if_fail(20 == response_len, FALSE);
1071
g_return_val_if_fail(NULL != challenge, FALSE);
1072
g_return_val_if_fail(20 == challenge_len, FALSE);
1073
g_return_val_if_fail(NULL != double_hashed, FALSE);
1074
g_return_val_if_fail(20 == double_hashed_len, FALSE);
1076
hashed_password = g_string_new(NULL);
1078
network_mysqld_proto_password_unscramble(hashed_password,
1079
challenge, challenge_len,
1080
response, response_len,
1081
double_hashed, double_hashed_len);
1083
/* 3. SHA1(hashed_password) */
1084
step2 = g_string_new(NULL);
1085
network_mysqld_proto_password_hash(step2, S(hashed_password));
1087
/* 4. the result of 3 should be the same what we got from the mysql.user table */
1088
is_same = strleq(S(step2), double_hashed, double_hashed_len);
1090
g_string_free(step2, TRUE);
1091
g_string_free(hashed_password, TRUE);
1097
network_packet *network_packet_new(void) {
1098
network_packet *packet;
1100
packet = g_new0(network_packet, 1);
1105
void network_packet_free(network_packet *packet) {
1106
if (!packet) return;
1111
int network_mysqld_proto_skip_network_header(network_packet *packet) {
1112
return network_mysqld_proto_skip(packet, NET_HEADER_SIZE);
629
return network_mysqld_proto_append_int_len(packet, num, sizeof(num));