2
* Drizzle Client & Protocol Library
4
* Copyright (C) 2008 Eric Day (eday@oddments.org)
7
* Use and distribution licensed under the BSD license. See
8
* the COPYING file in this directory for full text.
13
* @brief Handshake Definitions
22
drizzle_return_t drizzle_handshake_server_read(drizzle_con_st *con)
24
if (drizzle_state_none(con))
26
drizzle_state_push(con, drizzle_state_handshake_server_read);
27
drizzle_state_push(con, drizzle_state_packet_read);
30
return drizzle_state_loop(con);
33
drizzle_return_t drizzle_handshake_client_write(drizzle_con_st *con)
35
if (drizzle_state_none(con))
37
drizzle_state_push(con, drizzle_state_write);
38
drizzle_state_push(con, drizzle_state_handshake_client_write);
41
return drizzle_state_loop(con);
48
drizzle_return_t drizzle_handshake_server_write(drizzle_con_st *con)
50
if (drizzle_state_none(con))
52
drizzle_state_push(con, drizzle_state_write);
53
drizzle_state_push(con, drizzle_state_handshake_server_write);
56
return drizzle_state_loop(con);
59
drizzle_return_t drizzle_handshake_client_read(drizzle_con_st *con)
61
if (drizzle_state_none(con))
63
drizzle_state_push(con, drizzle_state_handshake_client_read);
64
drizzle_state_push(con, drizzle_state_packet_read);
67
return drizzle_state_loop(con);
74
drizzle_return_t drizzle_state_handshake_server_read(drizzle_con_st *con)
78
drizzle_log_debug(con->drizzle, "drizzle_state_handshake_server_read");
80
/* Assume the entire handshake packet will fit in the buffer. */
81
if (con->buffer_size < con->packet_size)
83
drizzle_state_push(con, drizzle_state_read);
84
return DRIZZLE_RETURN_OK;
87
if (con->packet_size < 46)
89
drizzle_set_error(con->drizzle, "drizzle_state_handshake_server_read",
90
"bad packet size:>=46:%zu", con->packet_size);
91
return DRIZZLE_RETURN_BAD_HANDSHAKE_PACKET;
94
con->protocol_version= con->buffer_ptr[0];
97
if (con->protocol_version != 10)
99
/* This is a special case where the server determines that authentication
100
will be impossible and denies any attempt right away. */
101
if (con->protocol_version == 255)
103
drizzle_set_error(con->drizzle, "drizzle_state_handshake_server_read",
104
"%.*s", (int32_t)con->packet_size - 3,
105
con->buffer_ptr + 2);
106
return DRIZZLE_RETURN_AUTH_FAILED;
109
drizzle_set_error(con->drizzle, "drizzle_state_handshake_server_read",
110
"protocol version not supported:%d",
111
con->protocol_version);
112
return DRIZZLE_RETURN_PROTOCOL_NOT_SUPPORTED;
115
/* Look for null-terminated server version string. */
116
ptr= memchr(con->buffer_ptr, 0, con->buffer_size - 1);
119
drizzle_set_error(con->drizzle, "drizzle_state_handshake_server_read",
120
"server version string not found");
121
return DRIZZLE_RETURN_BAD_HANDSHAKE_PACKET;
124
if (con->packet_size != (46 + (size_t)(ptr - con->buffer_ptr)))
126
drizzle_set_error(con->drizzle, "drizzle_state_handshake_server_read",
127
"bad packet size:%zu:%zu",
128
(46 + (size_t)(ptr - con->buffer_ptr)), con->packet_size);
129
return DRIZZLE_RETURN_BAD_HANDSHAKE_PACKET;
132
strncpy(con->server_version, (char *)con->buffer_ptr,
133
DRIZZLE_MAX_SERVER_VERSION_SIZE);
134
con->server_version[DRIZZLE_MAX_SERVER_VERSION_SIZE - 1]= 0;
135
con->buffer_ptr+= ((ptr - con->buffer_ptr) + 1);
137
con->thread_id= (uint32_t)drizzle_get_byte4(con->buffer_ptr);
140
con->scramble= con->scramble_buffer;
141
memcpy(con->scramble, con->buffer_ptr, 8);
142
/* Skip scramble and filler. */
145
/* Even though drizzle_capabilities is more than 2 bytes, the protocol only
146
allows for 2. This means some capabilities are not possible during this
147
handshake step. The options beyond 2 bytes are for client response only. */
148
con->capabilities= (drizzle_capabilities_t)drizzle_get_byte2(con->buffer_ptr);
151
if (con->options & DRIZZLE_CON_MYSQL &&
152
!(con->capabilities & DRIZZLE_CAPABILITIES_PROTOCOL_41))
154
drizzle_set_error(con->drizzle, "drizzle_state_handshake_server_read",
155
"protocol version not supported, must be MySQL 4.1+");
156
return DRIZZLE_RETURN_PROTOCOL_NOT_SUPPORTED;
159
con->charset= con->buffer_ptr[0];
162
con->status= drizzle_get_byte2(con->buffer_ptr);
163
/* Skip status and filler. */
164
con->buffer_ptr+= 15;
166
memcpy(con->scramble + 8, con->buffer_ptr, 12);
167
con->buffer_ptr+= 13;
169
con->buffer_size-= con->packet_size;
170
if (con->buffer_size != 0)
172
drizzle_set_error(con->drizzle, "drizzle_state_handshake_server_read",
173
"unexpected data after packet:%zu", con->buffer_size);
174
return DRIZZLE_RETURN_UNEXPECTED_DATA;
177
con->buffer_ptr= con->buffer;
179
drizzle_state_pop(con);
181
if (!(con->options & DRIZZLE_CON_RAW_PACKET))
183
drizzle_state_push(con, drizzle_state_handshake_result_read);
184
drizzle_state_push(con, drizzle_state_packet_read);
185
drizzle_state_push(con, drizzle_state_write);
186
drizzle_state_push(con, drizzle_state_handshake_client_write);
189
return DRIZZLE_RETURN_OK;
192
drizzle_return_t drizzle_state_handshake_server_write(drizzle_con_st *con)
196
drizzle_log_debug(con->drizzle, "drizzle_state_handshake_server_write");
198
/* Calculate max packet size. */
199
con->packet_size= 1 /* Protocol version */
200
+ strlen(con->server_version) + 1
204
+ 2 /* Capabilities */
211
/* Assume the entire handshake packet will fit in the buffer. */
212
if ((con->packet_size + 4) > DRIZZLE_MAX_BUFFER_SIZE)
214
drizzle_set_error(con->drizzle, "drizzle_state_handshake_server_write",
215
"buffer too small:%zu", con->packet_size + 4);
216
return DRIZZLE_RETURN_INTERNAL_ERROR;
219
ptr= con->buffer_ptr;
221
/* Store packet size and packet number first. */
222
drizzle_set_byte3(ptr, con->packet_size);
224
con->packet_number= 1;
227
ptr[0]= con->protocol_version;
230
memcpy(ptr, con->server_version, strlen(con->server_version));
231
ptr+= strlen(con->server_version);
236
drizzle_set_byte4(ptr, con->thread_id);
239
if (con->scramble == NULL)
242
memcpy(ptr, con->scramble, 8);
248
if (con->options & DRIZZLE_CON_MYSQL)
249
con->capabilities|= DRIZZLE_CAPABILITIES_PROTOCOL_41;
251
/* We can only send two bytes worth, this is a protocol limitation. */
252
drizzle_set_byte2(ptr, con->capabilities);
255
ptr[0]= con->charset;
258
drizzle_set_byte2(ptr, con->status);
264
if (con->scramble == NULL)
267
memcpy(ptr, con->scramble + 8, 12);
273
con->buffer_size+= (4 + con->packet_size);
275
/* Make sure we packed it correctly. */
276
if ((size_t)(ptr - con->buffer_ptr) != (4 + con->packet_size))
278
drizzle_set_error(con->drizzle, "drizzle_state_handshake_server_write",
279
"error packing server handshake:%zu:%zu",
280
(size_t)(ptr - con->buffer_ptr), 4 + con->packet_size);
281
return DRIZZLE_RETURN_INTERNAL_ERROR;
284
drizzle_state_pop(con);
285
return DRIZZLE_RETURN_OK;
288
drizzle_return_t drizzle_state_handshake_client_read(drizzle_con_st *con)
292
uint8_t scramble_size;
294
drizzle_log_debug(con->drizzle, "drizzle_state_handshake_client_read");
296
/* Assume the entire handshake packet will fit in the buffer. */
297
if (con->buffer_size < con->packet_size)
299
drizzle_state_push(con, drizzle_state_read);
300
return DRIZZLE_RETURN_OK;
303
/* This is the minimum packet size. */
304
if (con->packet_size < 34)
306
drizzle_set_error(con->drizzle, "drizzle_state_handshake_client_read",
307
"bad packet size:>=34:%zu", con->packet_size);
308
return DRIZZLE_RETURN_BAD_HANDSHAKE_PACKET;
313
con->capabilities= drizzle_get_byte4(con->buffer_ptr);
316
if (con->options & DRIZZLE_CON_MYSQL &&
317
!(con->capabilities & DRIZZLE_CAPABILITIES_PROTOCOL_41))
319
drizzle_set_error(con->drizzle, "drizzle_state_handshake_client_read",
320
"protocol version not supported, must be MySQL 4.1+");
321
return DRIZZLE_RETURN_PROTOCOL_NOT_SUPPORTED;
324
con->max_packet_size= (uint32_t)drizzle_get_byte4(con->buffer_ptr);
327
con->charset= con->buffer_ptr[0];
331
con->buffer_ptr+= 23;
333
/* Look for null-terminated user string. */
334
ptr= memchr(con->buffer_ptr, 0, con->buffer_size - 32);
337
drizzle_set_error(con->drizzle, "drizzle_state_handshake_client_read",
338
"user string not found");
339
return DRIZZLE_RETURN_BAD_HANDSHAKE_PACKET;
342
if (con->buffer_ptr == ptr)
349
real_size+= (size_t)(ptr - con->buffer_ptr);
350
if (con->packet_size < real_size)
352
drizzle_set_error(con->drizzle, "drizzle_state_handshake_client_read",
353
"bad packet size:>=%zu:%zu", real_size,
355
return DRIZZLE_RETURN_BAD_HANDSHAKE_PACKET;
358
strncpy(con->user, (char *)con->buffer_ptr, DRIZZLE_MAX_USER_SIZE);
359
con->user[DRIZZLE_MAX_USER_SIZE - 1]= 0;
360
con->buffer_ptr+= ((ptr - con->buffer_ptr) + 1);
363
scramble_size= con->buffer_ptr[0];
366
if (scramble_size == 0)
370
if (scramble_size != DRIZZLE_MAX_SCRAMBLE_SIZE)
372
drizzle_set_error(con->drizzle, "drizzle_state_handshake_client_read",
373
"wrong scramble size");
374
return DRIZZLE_RETURN_BAD_HANDSHAKE_PACKET;
377
real_size+= scramble_size;
378
con->scramble= con->scramble_buffer;
379
memcpy(con->scramble, con->buffer_ptr, DRIZZLE_MAX_SCRAMBLE_SIZE);
381
con->buffer_ptr+= DRIZZLE_MAX_SCRAMBLE_SIZE;
384
/* Look for null-terminated db string. */
385
if ((34 + strlen(con->user) + scramble_size) == con->packet_size)
389
ptr= memchr(con->buffer_ptr, 0, con->buffer_size -
390
(34 + strlen(con->user) + scramble_size));
393
drizzle_set_error(con->drizzle, "drizzle_state_handshake_client_read",
394
"db string not found");
395
return DRIZZLE_RETURN_BAD_HANDSHAKE_PACKET;
398
real_size+= ((size_t)(ptr - con->buffer_ptr) + 1);
399
if (con->packet_size != real_size)
401
drizzle_set_error(con->drizzle, "drizzle_state_handshake_client_read",
402
"bad packet size:%zu:%zu", real_size, con->packet_size);
403
return DRIZZLE_RETURN_BAD_HANDSHAKE_PACKET;
406
if (con->buffer_ptr == ptr)
413
strncpy(con->db, (char *)con->buffer_ptr, DRIZZLE_MAX_DB_SIZE);
414
con->db[DRIZZLE_MAX_DB_SIZE - 1]= 0;
415
con->buffer_ptr+= ((ptr - con->buffer_ptr) + 1);
419
con->buffer_size-= con->packet_size;
420
if (con->buffer_size != 0)
422
drizzle_set_error(con->drizzle, "drizzle_state_handshake_client_read",
423
"unexpected data after packet:%zu", con->buffer_size);
424
return DRIZZLE_RETURN_UNEXPECTED_DATA;
427
con->buffer_ptr= con->buffer;
429
drizzle_state_pop(con);
430
return DRIZZLE_RETURN_OK;
433
drizzle_return_t drizzle_state_handshake_client_write(drizzle_con_st *con)
436
drizzle_capabilities_t capabilities;
437
drizzle_return_t ret;
439
drizzle_log_debug(con->drizzle, "drizzle_state_handshake_client_write");
441
/* Calculate max packet size. */
442
con->packet_size= 4 /* Capabilities */
443
+ 4 /* Max packet size */
446
+ strlen(con->user) + 1
447
+ 1 /* Scramble size */
448
+ DRIZZLE_MAX_SCRAMBLE_SIZE
449
+ strlen(con->db) + 1;
451
/* Assume the entire handshake packet will fit in the buffer. */
452
if ((con->packet_size + 4) > DRIZZLE_MAX_BUFFER_SIZE)
454
drizzle_set_error(con->drizzle, "drizzle_state_handshake_client_write",
455
"buffer too small:%zu", con->packet_size + 4);
456
return DRIZZLE_RETURN_INTERNAL_ERROR;
459
ptr= con->buffer_ptr;
461
/* Store packet size at the end since it may change. */
462
ptr[3]= con->packet_number;
463
con->packet_number++;
466
if (con->options & DRIZZLE_CON_MYSQL)
467
con->capabilities|= DRIZZLE_CAPABILITIES_PROTOCOL_41;
469
capabilities= con->capabilities & DRIZZLE_CAPABILITIES_CLIENT;
470
if (!(con->options & DRIZZLE_CON_FOUND_ROWS))
471
capabilities&= ~DRIZZLE_CAPABILITIES_FOUND_ROWS;
473
capabilities&= ~(DRIZZLE_CAPABILITIES_COMPRESS | DRIZZLE_CAPABILITIES_SSL);
475
capabilities&= ~DRIZZLE_CAPABILITIES_CONNECT_WITH_DB;
477
drizzle_set_byte4(ptr, capabilities);
480
drizzle_set_byte4(ptr, con->max_packet_size);
483
ptr[0]= con->charset;
489
ptr= drizzle_pack_auth(con, ptr, &ret);
490
if (ret != DRIZZLE_RETURN_OK)
493
con->buffer_size+= (4 + con->packet_size);
495
/* Make sure we packed it correctly. */
496
if ((size_t)(ptr - con->buffer_ptr) != (4 + con->packet_size))
498
drizzle_set_error(con->drizzle, "drizzle_state_handshake_client_write",
499
"error packing client handshake:%zu:%zu",
500
(size_t)(ptr - con->buffer_ptr), 4 + con->packet_size);
501
return DRIZZLE_RETURN_INTERNAL_ERROR;
504
/* Store packet size now. */
505
drizzle_set_byte3(con->buffer_ptr, con->packet_size);
507
drizzle_state_pop(con);
508
return DRIZZLE_RETURN_OK;
511
drizzle_return_t drizzle_state_handshake_result_read(drizzle_con_st *con)
513
drizzle_return_t ret;
514
drizzle_result_st result;
516
drizzle_log_debug(con->drizzle, "drizzle_state_handshake_result_read");
518
if (drizzle_result_create(con, &result) == NULL)
519
return DRIZZLE_RETURN_MEMORY;
521
con->result= &result;
523
ret= drizzle_state_result_read(con);
524
if (drizzle_state_none(con))
526
if (ret == DRIZZLE_RETURN_OK)
528
if (drizzle_result_eof(&result))
530
drizzle_set_error(con->drizzle, "drizzle_state_handshake_result_read",
531
"old insecure authentication mechanism not supported");
532
ret= DRIZZLE_RETURN_AUTH_FAILED;
535
con->options|= DRIZZLE_CON_READY;
539
drizzle_result_free(&result);
541
if (ret == DRIZZLE_RETURN_ERROR_CODE)
542
return DRIZZLE_RETURN_HANDSHAKE_FAILED;