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 
23 {
24  if (drizzle_state_none(con))
25  {
28  }
29 
30  return drizzle_state_loop(con);
31 }
32 
34 {
35  if (drizzle_state_none(con))
36  {
39  }
40 
41  return drizzle_state_loop(con);
42 }
43 
44 /*
45  * Server Definitions
46  */
47 
49 {
50  if (drizzle_state_none(con))
51  {
54  }
55 
56  return drizzle_state_loop(con);
57 }
58 
60 {
61  if (drizzle_state_none(con))
62  {
65  }
66 
67  return drizzle_state_loop(con);
68 }
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 
162  con->status= drizzle_get_byte2(con->buffer_ptr);
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 
179  drizzle_state_pop(con);
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. */
222  drizzle_set_byte3(ptr, con->packet_size);
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. */
252  drizzle_set_byte2(ptr, con->capabilities);
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 
284  drizzle_state_pop(con);
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;
379  memcpy(con->scramble, con->buffer_ptr, DRIZZLE_MAX_SCRAMBLE_SIZE);
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 
429  drizzle_state_pop(con);
430  return DRIZZLE_RETURN_OK;
431 }
432 
434 {
435  uint8_t *ptr;
436  drizzle_capabilities_t capabilities;
437  drizzle_return_t ret;
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 
504  drizzle_state_pop(con);
505  return DRIZZLE_RETURN_OK;
506 }
507 
509 {
510  drizzle_return_t ret;
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)
516  return DRIZZLE_RETURN_MEMORY;
517 
518  con->result= &result;
519 
520  ret= drizzle_state_result_read(con);
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
532  con->options|= DRIZZLE_CON_READY;
533  }
534  }
535 
536  drizzle_result_free(&result);
537 
538  if (ret == DRIZZLE_RETURN_ERROR_CODE)
540 
541  return ret;
542 }