~drizzle-trunk/drizzle/development

1712.1.1 by Monty Taylor
Merged libdrizzle directly into tree.
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
1799.2.3 by Monty Taylor
Reference root BSD copying file.
8
 * the COPYING.BSD file in the root source directory for full text.
1712.1.1 by Monty Taylor
Merged libdrizzle directly into tree.
9
 */
10
11
/**
12
 * @file
13
 * @brief Handshake Definitions
14
 */
15
16
#include "common.h"
17
18
/*
19
 * Client Definitions
20
 */
21
22
drizzle_return_t drizzle_handshake_server_read(drizzle_con_st *con)
23
{
24
  if (drizzle_state_none(con))
25
  {
26
    drizzle_state_push(con, drizzle_state_handshake_server_read);
27
    drizzle_state_push(con, drizzle_state_packet_read);
28
  }
29
30
  return drizzle_state_loop(con);
31
}
32
33
drizzle_return_t drizzle_handshake_client_write(drizzle_con_st *con)
34
{
35
  if (drizzle_state_none(con))
36
  {
37
    drizzle_state_push(con, drizzle_state_write);
38
    drizzle_state_push(con, drizzle_state_handshake_client_write);
39
  }
40
41
  return drizzle_state_loop(con);
42
}
43
44
/*
45
 * Server Definitions
46
 */
47
48
drizzle_return_t drizzle_handshake_server_write(drizzle_con_st *con)
49
{
50
  if (drizzle_state_none(con))
51
  {
52
    drizzle_state_push(con, drizzle_state_write);
53
    drizzle_state_push(con, drizzle_state_handshake_server_write);
54
  }
55
56
  return drizzle_state_loop(con);
57
}
58
59
drizzle_return_t drizzle_handshake_client_read(drizzle_con_st *con)
60
{
61
  if (drizzle_state_none(con))
62
  {
63
    drizzle_state_push(con, drizzle_state_handshake_client_read);
64
    drizzle_state_push(con, drizzle_state_packet_read);
65
  }
66
67
  return drizzle_state_loop(con);
68
}
69
70
/*
71
 * State Definitions
72
 */
73
74
drizzle_return_t drizzle_state_handshake_server_read(drizzle_con_st *con)
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
  {
83
    drizzle_state_push(con, drizzle_state_read);
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);
91
    return DRIZZLE_RETURN_BAD_HANDSHAKE_PACKET;
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);
106
      return DRIZZLE_RETURN_AUTH_FAILED;
107
    }
108
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;
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");
121
    return DRIZZLE_RETURN_BAD_HANDSHAKE_PACKET;
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);
129
    return DRIZZLE_RETURN_BAD_HANDSHAKE_PACKET;
130
  }
131
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);
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. */
148
  con->capabilities= (drizzle_capabilities_t)drizzle_get_byte2(con->buffer_ptr);
149
  con->buffer_ptr+= 2;
150
151
  if (con->options & DRIZZLE_CON_MYSQL &&
152
      !(con->capabilities & DRIZZLE_CAPABILITIES_PROTOCOL_41))
153
  {
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;
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);
174
    return DRIZZLE_RETURN_UNEXPECTED_DATA;
175
  }
176
177
  con->buffer_ptr= con->buffer;
178
179
  drizzle_state_pop(con);
180
181
  if (!(con->options & DRIZZLE_CON_RAW_PACKET))
182
  {
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);
187
  }
188
189
  return DRIZZLE_RETURN_OK;
190
}
191
192
drizzle_return_t drizzle_state_handshake_server_write(drizzle_con_st *con)
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);
216
    return DRIZZLE_RETURN_INTERNAL_ERROR;
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)
249
    con->capabilities|= DRIZZLE_CAPABILITIES_PROTOCOL_41;
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);
281
    return DRIZZLE_RETURN_INTERNAL_ERROR;
282
  }
283
284
  drizzle_state_pop(con);
285
  return DRIZZLE_RETURN_OK;
286
}
287
288
drizzle_return_t drizzle_state_handshake_client_read(drizzle_con_st *con)
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
  {
299
    drizzle_state_push(con, drizzle_state_read);
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);
308
    return DRIZZLE_RETURN_BAD_HANDSHAKE_PACKET;
309
  }
310
311
  real_size= 34;
312
313
  con->capabilities= drizzle_get_byte4(con->buffer_ptr);
314
  con->buffer_ptr+= 4;
315
316
  if (con->options & DRIZZLE_CON_MYSQL &&
317
      !(con->capabilities & DRIZZLE_CAPABILITIES_PROTOCOL_41))
318
  {
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;
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");
339
    return DRIZZLE_RETURN_BAD_HANDSHAKE_PACKET;
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);
355
      return DRIZZLE_RETURN_BAD_HANDSHAKE_PACKET;
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");
374
      return DRIZZLE_RETURN_BAD_HANDSHAKE_PACKET;
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
381
    con->buffer_ptr+= DRIZZLE_MAX_SCRAMBLE_SIZE;
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");
395
      return DRIZZLE_RETURN_BAD_HANDSHAKE_PACKET;
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);
403
      return DRIZZLE_RETURN_BAD_HANDSHAKE_PACKET;
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);
424
    return DRIZZLE_RETURN_UNEXPECTED_DATA;
425
  }
426
427
  con->buffer_ptr= con->buffer;
428
429
  drizzle_state_pop(con);
430
  return DRIZZLE_RETURN_OK;
431
}
432
433
drizzle_return_t drizzle_state_handshake_client_write(drizzle_con_st *con)
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 */
448
                  + DRIZZLE_MAX_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);
456
    return DRIZZLE_RETURN_INTERNAL_ERROR;
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)
467
    con->capabilities|= DRIZZLE_CAPABILITIES_PROTOCOL_41;
468
469
  capabilities= con->capabilities & DRIZZLE_CAPABILITIES_CLIENT;
470
  if (!(con->options & DRIZZLE_CON_FOUND_ROWS))
471
    capabilities&= ~DRIZZLE_CAPABILITIES_FOUND_ROWS;
472
473
  capabilities&= ~(DRIZZLE_CAPABILITIES_COMPRESS | DRIZZLE_CAPABILITIES_SSL);
474
  if (con->db[0] == 0)
475
    capabilities&= ~DRIZZLE_CAPABILITIES_CONNECT_WITH_DB;
476
477
  drizzle_set_byte4(ptr, capabilities);
478
  ptr+= 4;
479
480
  drizzle_set_byte4(ptr, con->max_packet_size);
481
  ptr+= 4;
482
483
  ptr[0]= con->charset;
484
  ptr++;
485
486
  memset(ptr, 0, 23);
487
  ptr+= 23;
488
489
  ptr= drizzle_pack_auth(con, ptr, &ret);
490
  if (ret != DRIZZLE_RETURN_OK)
491
    return ret;
492
493
  con->buffer_size+= (4 + con->packet_size);
494
495
  /* Make sure we packed it correctly. */
496
  if ((size_t)(ptr - con->buffer_ptr) != (4 + con->packet_size))
497
  {
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;
502
  }
503
504
  /* Store packet size now. */
505
  drizzle_set_byte3(con->buffer_ptr, con->packet_size);
506
507
  drizzle_state_pop(con);
508
  return DRIZZLE_RETURN_OK;
509
}
510
511
drizzle_return_t drizzle_state_handshake_result_read(drizzle_con_st *con)
512
{
513
  drizzle_return_t ret;
514
  drizzle_result_st result;
515
516
  drizzle_log_debug(con->drizzle, "drizzle_state_handshake_result_read");
517
518
  if (drizzle_result_create(con, &result) == NULL)
519
    return DRIZZLE_RETURN_MEMORY;
520
521
  con->result= &result;
522
523
  ret= drizzle_state_result_read(con);
524
  if (drizzle_state_none(con))
525
  {
526
    if (ret == DRIZZLE_RETURN_OK)
527
    {
528
      if (drizzle_result_eof(&result))
529
      {
530
        drizzle_set_error(con->drizzle, "drizzle_state_handshake_result_read",
531
                         "old insecure authentication mechanism not supported");
532
        ret= DRIZZLE_RETURN_AUTH_FAILED;
533
      }
534
      else
535
        con->options|= DRIZZLE_CON_READY;
536
    }
537
  }
538
539
  drizzle_result_free(&result);
540
541
  if (ret == DRIZZLE_RETURN_ERROR_CODE)
542
    return DRIZZLE_RETURN_HANDSHAKE_FAILED;
543
544
  return ret;
545
}