libdrizzle Developer Documentation

handshake.c
Go to the documentation of this file.
1/*
2 * Drizzle Client & Protocol Library
3 *
4 * Copyright (C) 2008 Eric Day (eday@oddments.org)
5 * All rights reserved.
6 *
7 * Use and distribution licensed under the BSD license. See
8 * the COPYING file in this directory for full text.
9 */
10
16#include "common.h"
17
18/*
19 * Client Definitions
20 */
21
32
43
44/*
45 * Server Definitions
46 */
47
58
69
70/*
71 * State Definitions
72 */
73
75{
76 uint8_t *ptr;
77
78 drizzle_log_debug(con->drizzle, "drizzle_state_handshake_server_read");
79
80 /* Assume the entire handshake packet will fit in the buffer. */
81 if (con->buffer_size < con->packet_size)
82 {
84 return DRIZZLE_RETURN_OK;
85 }
86
87 if (con->packet_size < 46)
88 {
89 drizzle_set_error(con->drizzle, "drizzle_state_handshake_server_read",
90 "bad packet size:>=46:%zu", con->packet_size);
92 }
93
94 con->protocol_version= con->buffer_ptr[0];
95 con->buffer_ptr++;
96
97 if (con->protocol_version != 10)
98 {
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)
102 {
103 drizzle_set_error(con->drizzle, "drizzle_state_handshake_server_read",
104 "%.*s", (int32_t)con->packet_size - 3,
105 con->buffer_ptr + 2);
107 }
108
109 drizzle_set_error(con->drizzle, "drizzle_state_handshake_server_read",
110 "protocol version not supported:%d",
111 con->protocol_version);
113 }
114
115 /* Look for null-terminated server version string. */
116 ptr= memchr(con->buffer_ptr, 0, con->buffer_size - 1);
117 if (ptr == NULL)
118 {
119 drizzle_set_error(con->drizzle, "drizzle_state_handshake_server_read",
120 "server version string not found");
122 }
123
124 if (con->packet_size != (46 + (size_t)(ptr - con->buffer_ptr)))
125 {
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);
130 }
131
132 strncpy(con->server_version, (char *)con->buffer_ptr,
135 con->buffer_ptr+= ((ptr - con->buffer_ptr) + 1);
136
137 con->thread_id= (uint32_t)drizzle_get_byte4(con->buffer_ptr);
138 con->buffer_ptr+= 4;
139
140 con->scramble= con->scramble_buffer;
141 memcpy(con->scramble, con->buffer_ptr, 8);
142 /* Skip scramble and filler. */
143 con->buffer_ptr+= 9;
144
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. */
149 con->buffer_ptr+= 2;
150
151 if (con->options & DRIZZLE_CON_MYSQL &&
153 {
154 drizzle_set_error(con->drizzle, "drizzle_state_handshake_server_read",
155 "protocol version not supported, must be MySQL 4.1+");
157 }
158
159 con->charset= con->buffer_ptr[0];
160 con->buffer_ptr+= 1;
161
163 /* Skip status and filler. */
164 con->buffer_ptr+= 15;
165
166 memcpy(con->scramble + 8, con->buffer_ptr, 12);
167 con->buffer_ptr+= 13;
168
169 con->buffer_size-= con->packet_size;
170 if (con->buffer_size != 0)
171 {
172 drizzle_set_error(con->drizzle, "drizzle_state_handshake_server_read",
173 "unexpected data after packet:%zu", con->buffer_size);
175 }
176
177 con->buffer_ptr= con->buffer;
178
180
181 if (!(con->options & DRIZZLE_CON_RAW_PACKET))
182 {
187 }
188
189 return DRIZZLE_RETURN_OK;
190}
191
193{
194 uint8_t *ptr;
195
196 drizzle_log_debug(con->drizzle, "drizzle_state_handshake_server_write");
197
198 /* Calculate max packet size. */
199 con->packet_size= 1 /* Protocol version */
200 + strlen(con->server_version) + 1
201 + 4 /* Thread ID */
202 + 8 /* Scramble */
203 + 1 /* NULL */
204 + 2 /* Capabilities */
205 + 1 /* Language */
206 + 2 /* Status */
207 + 13 /* Unused */
208 + 12 /* Scramble */
209 + 1; /* NULL */
210
211 /* Assume the entire handshake packet will fit in the buffer. */
212 if ((con->packet_size + 4) > DRIZZLE_MAX_BUFFER_SIZE)
213 {
214 drizzle_set_error(con->drizzle, "drizzle_state_handshake_server_write",
215 "buffer too small:%zu", con->packet_size + 4);
217 }
218
219 ptr= con->buffer_ptr;
220
221 /* Store packet size and packet number first. */
223 ptr[3]= 0;
224 con->packet_number= 1;
225 ptr+= 4;
226
227 ptr[0]= con->protocol_version;
228 ptr++;
229
230 memcpy(ptr, con->server_version, strlen(con->server_version));
231 ptr+= strlen(con->server_version);
232
233 ptr[0]= 0;
234 ptr++;
235
236 drizzle_set_byte4(ptr, con->thread_id);
237 ptr+= 4;
238
239 if (con->scramble == NULL)
240 memset(ptr, 0, 8);
241 else
242 memcpy(ptr, con->scramble, 8);
243 ptr+= 8;
244
245 ptr[0]= 0;
246 ptr++;
247
248 if (con->options & DRIZZLE_CON_MYSQL)
250
251 /* We can only send two bytes worth, this is a protocol limitation. */
253 ptr+= 2;
254
255 ptr[0]= con->charset;
256 ptr++;
257
258 drizzle_set_byte2(ptr, con->status);
259 ptr+= 2;
260
261 memset(ptr, 0, 13);
262 ptr+= 13;
263
264 if (con->scramble == NULL)
265 memset(ptr, 0, 12);
266 else
267 memcpy(ptr, con->scramble + 8, 12);
268 ptr+= 12;
269
270 ptr[0]= 0;
271 ptr++;
272
273 con->buffer_size+= (4 + con->packet_size);
274
275 /* Make sure we packed it correctly. */
276 if ((size_t)(ptr - con->buffer_ptr) != (4 + con->packet_size))
277 {
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);
282 }
283
285 return DRIZZLE_RETURN_OK;
286}
287
289{
290 size_t real_size;
291 uint8_t *ptr;
292 uint8_t scramble_size;
293
294 drizzle_log_debug(con->drizzle, "drizzle_state_handshake_client_read");
295
296 /* Assume the entire handshake packet will fit in the buffer. */
297 if (con->buffer_size < con->packet_size)
298 {
300 return DRIZZLE_RETURN_OK;
301 }
302
303 /* This is the minimum packet size. */
304 if (con->packet_size < 34)
305 {
306 drizzle_set_error(con->drizzle, "drizzle_state_handshake_client_read",
307 "bad packet size:>=34:%zu", con->packet_size);
309 }
310
311 real_size= 34;
312
314 con->buffer_ptr+= 4;
315
316 if (con->options & DRIZZLE_CON_MYSQL &&
318 {
319 drizzle_set_error(con->drizzle, "drizzle_state_handshake_client_read",
320 "protocol version not supported, must be MySQL 4.1+");
322 }
323
324 con->max_packet_size= (uint32_t)drizzle_get_byte4(con->buffer_ptr);
325 con->buffer_ptr+= 4;
326
327 con->charset= con->buffer_ptr[0];
328 con->buffer_ptr+= 1;
329
330 /* Skip unused. */
331 con->buffer_ptr+= 23;
332
333 /* Look for null-terminated user string. */
334 ptr= memchr(con->buffer_ptr, 0, con->buffer_size - 32);
335 if (ptr == NULL)
336 {
337 drizzle_set_error(con->drizzle, "drizzle_state_handshake_client_read",
338 "user string not found");
340 }
341
342 if (con->buffer_ptr == ptr)
343 {
344 con->user[0]= 0;
345 con->buffer_ptr++;
346 }
347 else
348 {
349 real_size+= (size_t)(ptr - con->buffer_ptr);
350 if (con->packet_size < real_size)
351 {
352 drizzle_set_error(con->drizzle, "drizzle_state_handshake_client_read",
353 "bad packet size:>=%zu:%zu", real_size,
354 con->packet_size);
356 }
357
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);
361 }
362
363 scramble_size= con->buffer_ptr[0];
364 con->buffer_ptr+= 1;
365
366 if (scramble_size == 0)
367 con->scramble= NULL;
368 else
369 {
370 if (scramble_size != DRIZZLE_MAX_SCRAMBLE_SIZE)
371 {
372 drizzle_set_error(con->drizzle, "drizzle_state_handshake_client_read",
373 "wrong scramble size");
375 }
376
377 real_size+= scramble_size;
378 con->scramble= con->scramble_buffer;
380
382 }
383
384 /* Look for null-terminated db string. */
385 if ((34 + strlen(con->user) + scramble_size) == con->packet_size)
386 con->db[0]= 0;
387 else
388 {
389 ptr= memchr(con->buffer_ptr, 0, con->buffer_size -
390 (34 + strlen(con->user) + scramble_size));
391 if (ptr == NULL)
392 {
393 drizzle_set_error(con->drizzle, "drizzle_state_handshake_client_read",
394 "db string not found");
396 }
397
398 real_size+= ((size_t)(ptr - con->buffer_ptr) + 1);
399 if (con->packet_size != real_size)
400 {
401 drizzle_set_error(con->drizzle, "drizzle_state_handshake_client_read",
402 "bad packet size:%zu:%zu", real_size, con->packet_size);
404 }
405
406 if (con->buffer_ptr == ptr)
407 {
408 con->db[0]= 0;
409 con->buffer_ptr++;
410 }
411 else
412 {
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);
416 }
417 }
418
419 con->buffer_size-= con->packet_size;
420 if (con->buffer_size != 0)
421 {
422 drizzle_set_error(con->drizzle, "drizzle_state_handshake_client_read",
423 "unexpected data after packet:%zu", con->buffer_size);
425 }
426
427 con->buffer_ptr= con->buffer;
428
430 return DRIZZLE_RETURN_OK;
431}
432
434{
435 uint8_t *ptr;
436 drizzle_capabilities_t capabilities;
438
439 drizzle_log_debug(con->drizzle, "drizzle_state_handshake_client_write");
440
441 /* Calculate max packet size. */
442 con->packet_size= 4 /* Capabilities */
443 + 4 /* Max packet size */
444 + 1 /* Charset */
445 + 23 /* Unused */
446 + strlen(con->user) + 1
447 + 1 /* Scramble size */
449 + strlen(con->db) + 1;
450
451 /* Assume the entire handshake packet will fit in the buffer. */
452 if ((con->packet_size + 4) > DRIZZLE_MAX_BUFFER_SIZE)
453 {
454 drizzle_set_error(con->drizzle, "drizzle_state_handshake_client_write",
455 "buffer too small:%zu", con->packet_size + 4);
457 }
458
459 ptr= con->buffer_ptr;
460
461 /* Store packet size at the end since it may change. */
462 ptr[3]= con->packet_number;
463 con->packet_number++;
464 ptr+= 4;
465
466 if (con->options & DRIZZLE_CON_MYSQL)
468
469 capabilities= con->capabilities & DRIZZLE_CAPABILITIES_CLIENT;
471 if (con->db[0] == 0)
472 capabilities&= ~DRIZZLE_CAPABILITIES_CONNECT_WITH_DB;
473
474 drizzle_set_byte4(ptr, capabilities);
475 ptr+= 4;
476
478 ptr+= 4;
479
480 ptr[0]= con->charset;
481 ptr++;
482
483 memset(ptr, 0, 23);
484 ptr+= 23;
485
486 ptr= drizzle_pack_auth(con, ptr, &ret);
487 if (ret != DRIZZLE_RETURN_OK)
488 return ret;
489
490 con->buffer_size+= (4 + con->packet_size);
491
492 /* Make sure we packed it correctly. */
493 if ((size_t)(ptr - con->buffer_ptr) != (4 + con->packet_size))
494 {
495 drizzle_set_error(con->drizzle, "drizzle_state_handshake_client_write",
496 "error packing client handshake:%zu:%zu",
497 (size_t)(ptr - con->buffer_ptr), 4 + con->packet_size);
499 }
500
501 /* Store packet size now. */
503
505 return DRIZZLE_RETURN_OK;
506}
507
509{
511 drizzle_result_st result;
512
513 drizzle_log_debug(con->drizzle, "drizzle_state_handshake_result_read");
514
515 if (drizzle_result_create(con, &result) == NULL)
517
518 con->result= &result;
519
521 if (drizzle_state_none(con))
522 {
523 if (ret == DRIZZLE_RETURN_OK)
524 {
525 if (drizzle_result_eof(&result))
526 {
527 drizzle_set_error(con->drizzle, "drizzle_state_handshake_result_read",
528 "old insecure authentication mechanism not supported");
530 }
531 else
533 }
534 }
535
536 drizzle_result_free(&result);
537
538 if (ret == DRIZZLE_RETURN_ERROR_CODE)
540
541 return ret;
542}
System Include Files.
static void drizzle_state_pop(drizzle_con_st *con)
Definition conn_local.h:73
static void drizzle_state_push(drizzle_con_st *con, drizzle_state_fn *function)
Definition conn_local.h:57
static bool drizzle_state_none(drizzle_con_st *con)
Definition conn_local.h:45
drizzle_capabilities_t
Definition constants.h:179
@ DRIZZLE_CAPABILITIES_SSL
Definition constants.h:192
@ DRIZZLE_CAPABILITIES_CLIENT
Definition constants.h:201
@ DRIZZLE_CAPABILITIES_COMPRESS
Definition constants.h:186
@ DRIZZLE_CAPABILITIES_PROTOCOL_41
Definition constants.h:190
@ DRIZZLE_CON_MYSQL
Definition constants.h:135
@ DRIZZLE_CON_READY
Definition constants.h:138
@ DRIZZLE_CON_RAW_PACKET
Definition constants.h:136
#define DRIZZLE_MAX_USER_SIZE
Definition constants.h:45
#define DRIZZLE_MAX_BUFFER_SIZE
Definition constants.h:55
#define DRIZZLE_MAX_SCRAMBLE_SIZE
Definition constants.h:58
drizzle_return_t
Definition constants.h:69
#define DRIZZLE_MAX_DB_SIZE
Definition constants.h:47
#define DRIZZLE_MAX_SERVER_VERSION_SIZE
Definition constants.h:57
@ DRIZZLE_RETURN_HANDSHAKE_FAILED
Definition constants.h:93
@ DRIZZLE_RETURN_ERROR_CODE
Definition constants.h:87
@ DRIZZLE_RETURN_OK
Definition constants.h:70
@ DRIZZLE_RETURN_INTERNAL_ERROR
Definition constants.h:76
@ DRIZZLE_RETURN_AUTH_FAILED
Definition constants.h:85
@ DRIZZLE_RETURN_UNEXPECTED_DATA
Definition constants.h:83
@ DRIZZLE_RETURN_BAD_HANDSHAKE_PACKET
Definition constants.h:80
@ DRIZZLE_RETURN_PROTOCOL_NOT_SUPPORTED
Definition constants.h:82
@ DRIZZLE_RETURN_MEMORY
Definition constants.h:74
drizzle_return_t drizzle_handshake_server_read(drizzle_con_st *con)
Definition handshake.c:22
drizzle_return_t drizzle_handshake_client_write(drizzle_con_st *con)
Definition handshake.c:33
drizzle_return_t drizzle_handshake_client_read(drizzle_con_st *con)
Definition handshake.c:59
drizzle_return_t drizzle_handshake_server_write(drizzle_con_st *con)
Definition handshake.c:48
static void drizzle_log_debug(drizzle_st *drizzle, const char *format,...)
void drizzle_set_error(drizzle_st *drizzle, const char *function, const char *format,...)
Definition drizzle.c:633
#define drizzle_set_byte3(__buffer, __int)
Definition constants.h:478
#define drizzle_set_byte4(__buffer, __int)
Definition constants.h:482
#define drizzle_get_byte2(__buffer)
Definition constants.h:452
#define drizzle_get_byte4(__buffer)
Definition constants.h:459
#define drizzle_set_byte2(__buffer, __int)
Definition constants.h:475
uint8_t * drizzle_pack_auth(drizzle_con_st *con, uint8_t *ptr, drizzle_return_t *ret_ptr)
Definition pack.c:172
drizzle_result_st * drizzle_result_create(drizzle_con_st *con, drizzle_result_st *result)
Definition result.c:22
bool drizzle_result_eof(drizzle_result_st *result)
Definition result.c:118
void drizzle_result_free(drizzle_result_st *result)
Definition result.c:75
drizzle_return_t drizzle_state_packet_read(drizzle_con_st *con)
Definition state.c:40
drizzle_return_t drizzle_state_write(drizzle_con_st *con)
Definition conn.c:975
drizzle_return_t drizzle_state_handshake_server_write(drizzle_con_st *con)
Definition handshake.c:192
drizzle_return_t drizzle_state_read(drizzle_con_st *con)
Definition conn.c:897
drizzle_return_t drizzle_state_handshake_result_read(drizzle_con_st *con)
Definition handshake.c:508
drizzle_return_t drizzle_state_handshake_server_read(drizzle_con_st *con)
Definition handshake.c:74
drizzle_return_t drizzle_state_handshake_client_write(drizzle_con_st *con)
Definition handshake.c:433
drizzle_return_t drizzle_state_loop(drizzle_con_st *con)
Definition state.c:18
drizzle_return_t drizzle_state_handshake_client_read(drizzle_con_st *con)
Definition handshake.c:288
drizzle_return_t drizzle_state_result_read(drizzle_con_st *con)
Definition result.c:384
uint8_t packet_number
Definition structs.h:76
uint8_t buffer[DRIZZLE_MAX_BUFFER_SIZE]
Definition structs.h:115
drizzle_capabilities_t capabilities
Definition structs.h:81
drizzle_st * drizzle
Definition structs.h:103
drizzle_result_st * result
Definition structs.h:107
drizzle_charset_t charset
Definition structs.h:82
uint32_t thread_id
Definition structs.h:89
drizzle_con_options_t options
Definition structs.h:84
drizzle_con_status_t status
Definition structs.h:86
uint8_t * scramble
Definition structs.h:109
char server_version[DRIZZLE_MAX_SERVER_VERSION_SIZE]
Definition structs.h:119
size_t packet_size
Definition structs.h:96
uint8_t * buffer_ptr
Definition structs.h:98
uint32_t max_packet_size
Definition structs.h:87
char db[DRIZZLE_MAX_DB_SIZE]
Definition structs.h:116
size_t buffer_size
Definition structs.h:92
uint8_t protocol_version
Definition structs.h:77
char user[DRIZZLE_MAX_USER_SIZE]
Definition structs.h:121
uint8_t scramble_buffer[DRIZZLE_MAX_SCRAMBLE_SIZE]
Definition structs.h:118