2
* Drizzle Client & Protocol Library
4
* Copyright (C) 2008 Eric Day (eday@oddments.org)
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions are
11
* * Redistributions of source code must retain the above copyright
12
* notice, this list of conditions and the following disclaimer.
14
* * Redistributions in binary form must reproduce the above
15
* copyright notice, this list of conditions and the following disclaimer
16
* in the documentation and/or other materials provided with the
19
* * The names of its contributors may not be used to endorse or
20
* promote products derived from this software without specific prior
23
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39
* @brief Handshake Definitions
48
drizzle_return_t drizzle_handshake_server_read(drizzle_con_st *con)
50
if (drizzle_state_none(con))
52
drizzle_state_push(con, drizzle_state_handshake_server_read);
53
drizzle_state_push(con, drizzle_state_packet_read);
56
return drizzle_state_loop(con);
59
drizzle_return_t drizzle_handshake_client_write(drizzle_con_st *con)
61
if (drizzle_state_none(con))
63
drizzle_state_push(con, drizzle_state_write);
64
drizzle_state_push(con, drizzle_state_handshake_client_write);
67
return drizzle_state_loop(con);
74
drizzle_return_t drizzle_handshake_server_write(drizzle_con_st *con)
76
if (drizzle_state_none(con))
78
drizzle_state_push(con, drizzle_state_write);
79
drizzle_state_push(con, drizzle_state_handshake_server_write);
82
return drizzle_state_loop(con);
85
drizzle_return_t drizzle_handshake_client_read(drizzle_con_st *con)
87
if (drizzle_state_none(con))
89
drizzle_state_push(con, drizzle_state_handshake_client_read);
90
drizzle_state_push(con, drizzle_state_packet_read);
93
return drizzle_state_loop(con);
100
drizzle_return_t drizzle_state_handshake_server_read(drizzle_con_st *con)
104
unsigned char* packet_end;
106
drizzle_log_debug(con->drizzle, "drizzle_state_handshake_server_read");
108
/* Assume the entire handshake packet will fit in the buffer. */
109
if (con->buffer_size < con->packet_size)
111
drizzle_state_push(con, drizzle_state_read);
112
return DRIZZLE_RETURN_OK;
115
if (con->packet_size < 46)
117
drizzle_set_error(con->drizzle, "drizzle_state_handshake_server_read",
118
"bad packet size:>=46:%zu", con->packet_size);
119
return DRIZZLE_RETURN_BAD_HANDSHAKE_PACKET;
122
packet_end= con->buffer_ptr + con->packet_size;
123
con->protocol_version= con->buffer_ptr[0];
126
if (con->protocol_version != 10)
128
/* This is a special case where the server determines that authentication
129
will be impossible and denies any attempt right away. */
130
if (con->protocol_version == 255)
132
drizzle_set_error(con->drizzle, "drizzle_state_handshake_server_read",
133
"%.*s", (int32_t)con->packet_size - 3,
134
con->buffer_ptr + 2);
135
return DRIZZLE_RETURN_AUTH_FAILED;
138
drizzle_set_error(con->drizzle, "drizzle_state_handshake_server_read",
139
"protocol version not supported:%d",
140
con->protocol_version);
141
return DRIZZLE_RETURN_PROTOCOL_NOT_SUPPORTED;
144
/* Look for null-terminated server version string. */
145
ptr= memchr(con->buffer_ptr, 0, con->buffer_size - 1);
148
drizzle_set_error(con->drizzle, "drizzle_state_handshake_server_read",
149
"server version string not found");
150
return DRIZZLE_RETURN_BAD_HANDSHAKE_PACKET;
153
if (con->packet_size < (46 + (size_t)(ptr - con->buffer_ptr)))
155
drizzle_set_error(con->drizzle, "drizzle_state_handshake_server_read",
156
"bad packet size:%zu:%zu",
157
(46 + (size_t)(ptr - con->buffer_ptr)), con->packet_size);
158
return DRIZZLE_RETURN_BAD_HANDSHAKE_PACKET;
161
strncpy(con->server_version, (char *)con->buffer_ptr,
162
DRIZZLE_MAX_SERVER_VERSION_SIZE);
163
con->server_version[DRIZZLE_MAX_SERVER_VERSION_SIZE - 1]= 0;
164
con->buffer_ptr+= ((ptr - con->buffer_ptr) + 1);
166
con->thread_id= (uint32_t)drizzle_get_byte4(con->buffer_ptr);
169
con->scramble= con->scramble_buffer;
170
memcpy(con->scramble, con->buffer_ptr, 8);
171
/* Skip scramble and filler. */
174
/* Even though drizzle_capabilities is more than 2 bytes, the protocol only
175
allows for 2. This means some capabilities are not possible during this
176
handshake step. The options beyond 2 bytes are for client response only. */
177
con->capabilities= (drizzle_capabilities_t)drizzle_get_byte2(con->buffer_ptr);
180
if (con->options & DRIZZLE_CON_MYSQL &&
181
!(con->capabilities & DRIZZLE_CAPABILITIES_PROTOCOL_41))
183
drizzle_set_error(con->drizzle, "drizzle_state_handshake_server_read",
184
"protocol version not supported, must be MySQL 4.1+");
185
return DRIZZLE_RETURN_PROTOCOL_NOT_SUPPORTED;
188
con->charset= con->buffer_ptr[0];
191
con->status= drizzle_get_byte2(con->buffer_ptr);
192
/* Skip status and filler. */
193
con->buffer_ptr+= 15;
195
memcpy(con->scramble + 8, con->buffer_ptr, 12);
196
con->buffer_ptr+= 13;
198
/* MySQL 5.5 adds "mysql_native_password" after the server greeting. */
199
extra_length= packet_end - con->buffer_ptr;
200
assert(extra_length >= 0);
201
if (extra_length > DRIZZLE_MAX_SERVER_EXTRA_SIZE - 1)
202
extra_length= DRIZZLE_MAX_SERVER_EXTRA_SIZE - 1;
203
memcpy(con->server_extra, (char *)con->buffer_ptr, extra_length);
204
con->server_extra[extra_length]= 0;
206
con->buffer_size-= con->packet_size;
207
if (con->buffer_size != 0)
209
drizzle_set_error(con->drizzle, "drizzle_state_handshake_server_read",
210
"unexpected data after packet:%zu", con->buffer_size);
211
return DRIZZLE_RETURN_UNEXPECTED_DATA;
214
con->buffer_ptr= con->buffer;
216
drizzle_state_pop(con);
218
if (!(con->options & DRIZZLE_CON_RAW_PACKET))
220
drizzle_state_push(con, drizzle_state_handshake_result_read);
221
drizzle_state_push(con, drizzle_state_packet_read);
222
drizzle_state_push(con, drizzle_state_write);
223
drizzle_state_push(con, drizzle_state_handshake_client_write);
226
return DRIZZLE_RETURN_OK;
229
drizzle_return_t drizzle_state_handshake_server_write(drizzle_con_st *con)
233
drizzle_log_debug(con->drizzle, "drizzle_state_handshake_server_write");
235
/* Calculate max packet size. */
236
con->packet_size= 1 /* Protocol version */
237
+ strlen(con->server_version) + 1
241
+ 2 /* Capabilities */
248
/* Assume the entire handshake packet will fit in the buffer. */
249
if ((con->packet_size + 4) > DRIZZLE_MAX_BUFFER_SIZE)
251
drizzle_set_error(con->drizzle, "drizzle_state_handshake_server_write",
252
"buffer too small:%zu", con->packet_size + 4);
253
return DRIZZLE_RETURN_INTERNAL_ERROR;
256
ptr= con->buffer_ptr;
258
/* Store packet size and packet number first. */
259
drizzle_set_byte3(ptr, con->packet_size);
261
con->packet_number= 1;
264
ptr[0]= con->protocol_version;
267
memcpy(ptr, con->server_version, strlen(con->server_version));
268
ptr+= strlen(con->server_version);
273
drizzle_set_byte4(ptr, con->thread_id);
276
if (con->scramble == NULL)
279
memcpy(ptr, con->scramble, 8);
285
if (con->options & DRIZZLE_CON_MYSQL)
286
con->capabilities|= DRIZZLE_CAPABILITIES_PROTOCOL_41;
288
/* We can only send two bytes worth, this is a protocol limitation. */
289
drizzle_set_byte2(ptr, con->capabilities);
292
ptr[0]= con->charset;
295
drizzle_set_byte2(ptr, con->status);
301
if (con->scramble == NULL)
304
memcpy(ptr, con->scramble + 8, 12);
310
con->buffer_size+= (4 + con->packet_size);
312
/* Make sure we packed it correctly. */
313
if ((size_t)(ptr - con->buffer_ptr) != (4 + con->packet_size))
315
drizzle_set_error(con->drizzle, "drizzle_state_handshake_server_write",
316
"error packing server handshake:%zu:%zu",
317
(size_t)(ptr - con->buffer_ptr), 4 + con->packet_size);
318
return DRIZZLE_RETURN_INTERNAL_ERROR;
321
drizzle_state_pop(con);
322
return DRIZZLE_RETURN_OK;
325
drizzle_return_t drizzle_state_handshake_client_read(drizzle_con_st *con)
329
uint8_t scramble_size;
331
drizzle_log_debug(con->drizzle, "drizzle_state_handshake_client_read");
333
/* Assume the entire handshake packet will fit in the buffer. */
334
if (con->buffer_size < con->packet_size)
336
drizzle_state_push(con, drizzle_state_read);
337
return DRIZZLE_RETURN_OK;
340
/* This is the minimum packet size. */
341
if (con->packet_size < 34)
343
drizzle_set_error(con->drizzle, "drizzle_state_handshake_client_read",
344
"bad packet size:>=34:%zu", con->packet_size);
345
return DRIZZLE_RETURN_BAD_HANDSHAKE_PACKET;
350
con->capabilities= drizzle_get_byte4(con->buffer_ptr);
353
if (con->options & DRIZZLE_CON_MYSQL &&
354
!(con->capabilities & DRIZZLE_CAPABILITIES_PROTOCOL_41))
356
drizzle_set_error(con->drizzle, "drizzle_state_handshake_client_read",
357
"protocol version not supported, must be MySQL 4.1+");
358
return DRIZZLE_RETURN_PROTOCOL_NOT_SUPPORTED;
361
con->max_packet_size= (uint32_t)drizzle_get_byte4(con->buffer_ptr);
364
con->charset= con->buffer_ptr[0];
368
con->buffer_ptr+= 23;
370
/* Look for null-terminated user string. */
371
ptr= memchr(con->buffer_ptr, 0, con->buffer_size - 32);
374
drizzle_set_error(con->drizzle, "drizzle_state_handshake_client_read",
375
"user string not found");
376
return DRIZZLE_RETURN_BAD_HANDSHAKE_PACKET;
379
if (con->buffer_ptr == ptr)
386
real_size+= (size_t)(ptr - con->buffer_ptr);
387
if (con->packet_size < real_size)
389
drizzle_set_error(con->drizzle, "drizzle_state_handshake_client_read",
390
"bad packet size:>=%zu:%zu", real_size,
392
return DRIZZLE_RETURN_BAD_HANDSHAKE_PACKET;
395
strncpy(con->user, (char *)con->buffer_ptr, DRIZZLE_MAX_USER_SIZE);
396
con->user[DRIZZLE_MAX_USER_SIZE - 1]= 0;
397
con->buffer_ptr+= ((ptr - con->buffer_ptr) + 1);
400
scramble_size= con->buffer_ptr[0];
403
if (scramble_size == 0)
407
if (scramble_size != DRIZZLE_MAX_SCRAMBLE_SIZE)
409
drizzle_set_error(con->drizzle, "drizzle_state_handshake_client_read",
410
"wrong scramble size");
411
return DRIZZLE_RETURN_BAD_HANDSHAKE_PACKET;
414
real_size+= scramble_size;
415
con->scramble= con->scramble_buffer;
416
memcpy(con->scramble, con->buffer_ptr, DRIZZLE_MAX_SCRAMBLE_SIZE);
418
con->buffer_ptr+= DRIZZLE_MAX_SCRAMBLE_SIZE;
421
/* Look for null-terminated db string. */
422
if ((34 + strlen(con->user) + scramble_size) == con->packet_size)
426
ptr= memchr(con->buffer_ptr, 0, con->buffer_size -
427
(34 + strlen(con->user) + scramble_size));
430
drizzle_set_error(con->drizzle, "drizzle_state_handshake_client_read",
431
"db string not found");
432
return DRIZZLE_RETURN_BAD_HANDSHAKE_PACKET;
435
real_size+= ((size_t)(ptr - con->buffer_ptr) + 1);
436
if (con->packet_size != real_size)
438
drizzle_set_error(con->drizzle, "drizzle_state_handshake_client_read",
439
"bad packet size:%zu:%zu", real_size, con->packet_size);
440
return DRIZZLE_RETURN_BAD_HANDSHAKE_PACKET;
443
if (con->buffer_ptr == ptr)
450
strncpy(con->db, (char *)con->buffer_ptr, DRIZZLE_MAX_DB_SIZE);
451
con->db[DRIZZLE_MAX_DB_SIZE - 1]= 0;
452
con->buffer_ptr+= ((ptr - con->buffer_ptr) + 1);
456
con->buffer_size-= con->packet_size;
457
if (con->buffer_size != 0)
459
drizzle_set_error(con->drizzle, "drizzle_state_handshake_client_read",
460
"unexpected data after packet:%zu", con->buffer_size);
461
return DRIZZLE_RETURN_UNEXPECTED_DATA;
464
con->buffer_ptr= con->buffer;
466
drizzle_state_pop(con);
467
return DRIZZLE_RETURN_OK;
470
drizzle_return_t drizzle_state_handshake_client_write(drizzle_con_st *con)
473
drizzle_capabilities_t capabilities;
474
drizzle_return_t ret;
476
drizzle_log_debug(con->drizzle, "drizzle_state_handshake_client_write");
478
/* Calculate max packet size. */
479
con->packet_size= 4 /* Capabilities */
480
+ 4 /* Max packet size */
483
+ strlen(con->user) + 1
484
+ 1 /* Scramble size */
485
+ DRIZZLE_MAX_SCRAMBLE_SIZE
486
+ strlen(con->db) + 1;
488
/* Assume the entire handshake packet will fit in the buffer. */
489
if ((con->packet_size + 4) > DRIZZLE_MAX_BUFFER_SIZE)
491
drizzle_set_error(con->drizzle, "drizzle_state_handshake_client_write",
492
"buffer too small:%zu", con->packet_size + 4);
493
return DRIZZLE_RETURN_INTERNAL_ERROR;
496
ptr= con->buffer_ptr;
498
/* Store packet size at the end since it may change. */
499
ptr[3]= con->packet_number;
500
con->packet_number++;
503
if (con->options & DRIZZLE_CON_MYSQL)
504
con->capabilities|= DRIZZLE_CAPABILITIES_PROTOCOL_41;
506
capabilities= con->capabilities & DRIZZLE_CAPABILITIES_CLIENT;
507
if (!(con->options & DRIZZLE_CON_FOUND_ROWS))
508
capabilities&= ~DRIZZLE_CAPABILITIES_FOUND_ROWS;
510
if (con->options & DRIZZLE_CON_ADMIN)
511
capabilities|= DRIZZLE_CAPABILITIES_ADMIN;
513
capabilities&= ~(DRIZZLE_CAPABILITIES_COMPRESS | DRIZZLE_CAPABILITIES_SSL);
515
capabilities&= ~DRIZZLE_CAPABILITIES_CONNECT_WITH_DB;
517
drizzle_set_byte4(ptr, capabilities);
520
drizzle_set_byte4(ptr, con->max_packet_size);
523
ptr[0]= con->charset;
529
ptr= drizzle_pack_auth(con, ptr, &ret);
530
if (ret != DRIZZLE_RETURN_OK)
533
con->buffer_size+= (4 + con->packet_size);
535
/* Make sure we packed it correctly. */
536
if ((size_t)(ptr - con->buffer_ptr) != (4 + con->packet_size))
538
drizzle_set_error(con->drizzle, "drizzle_state_handshake_client_write",
539
"error packing client handshake:%zu:%zu",
540
(size_t)(ptr - con->buffer_ptr), 4 + con->packet_size);
541
return DRIZZLE_RETURN_INTERNAL_ERROR;
544
/* Store packet size now. */
545
drizzle_set_byte3(con->buffer_ptr, con->packet_size);
547
drizzle_state_pop(con);
548
return DRIZZLE_RETURN_OK;
551
drizzle_return_t drizzle_state_handshake_result_read(drizzle_con_st *con)
553
drizzle_return_t ret;
554
drizzle_result_st result;
556
drizzle_log_debug(con->drizzle, "drizzle_state_handshake_result_read");
558
if (drizzle_result_create(con, &result) == NULL)
559
return DRIZZLE_RETURN_MEMORY;
561
con->result= &result;
563
ret= drizzle_state_result_read(con);
564
if (drizzle_state_none(con))
566
if (ret == DRIZZLE_RETURN_OK)
568
if (drizzle_result_eof(&result))
570
drizzle_set_error(con->drizzle, "drizzle_state_handshake_result_read",
571
"old insecure authentication mechanism not supported");
572
ret= DRIZZLE_RETURN_AUTH_FAILED;
575
con->options|= DRIZZLE_CON_READY;
579
drizzle_result_free(&result);
581
if (ret == DRIZZLE_RETURN_ERROR_CODE)
582
return DRIZZLE_RETURN_HANDSHAKE_FAILED;