~drizzle-trunk/drizzle/development

2244.1.1 by Monty Taylor
Split libdrizzle into 1.0 and 2.0. Applied the C++ changes to 2.0 branch.
1
/*
2
 * Drizzle Client & Protocol Library
3
 *
4
 * Copyright (C) 2008 Eric Day (eday@oddments.org)
5
 * All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions are
9
 * met:
10
 *
11
 *     * Redistributions of source code must retain the above copyright
12
 * notice, this list of conditions and the following disclaimer.
13
 *
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
17
 * distribution.
18
 *
19
 *     * The names of its contributors may not be used to endorse or
20
 * promote products derived from this software without specific prior
21
 * written permission.
22
 *
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.
34
 *
35
 */
36
37
/**
38
 * @file
39
 * @brief Handshake Definitions
40
 */
41
42
#include "common.h"
43
44
/*
45
 * Client Definitions
46
 */
47
48
drizzle_return_t drizzle_handshake_server_read(drizzle_con_st *con)
49
{
50
  if (drizzle_state_none(con))
51
  {
52
    drizzle_state_push(con, drizzle_state_handshake_server_read);
53
    drizzle_state_push(con, drizzle_state_packet_read);
54
  }
55
56
  return drizzle_state_loop(con);
57
}
58
59
drizzle_return_t drizzle_handshake_client_write(drizzle_con_st *con)
60
{
61
  if (drizzle_state_none(con))
62
  {
63
    drizzle_state_push(con, drizzle_state_write);
64
    drizzle_state_push(con, drizzle_state_handshake_client_write);
65
  }
66
67
  return drizzle_state_loop(con);
68
}
69
70
/*
71
 * Server Definitions
72
 */
73
74
drizzle_return_t drizzle_handshake_server_write(drizzle_con_st *con)
75
{
76
  if (drizzle_state_none(con))
77
  {
78
    drizzle_state_push(con, drizzle_state_write);
79
    drizzle_state_push(con, drizzle_state_handshake_server_write);
80
  }
81
82
  return drizzle_state_loop(con);
83
}
84
85
drizzle_return_t drizzle_handshake_client_read(drizzle_con_st *con)
86
{
87
  if (drizzle_state_none(con))
88
  {
89
    drizzle_state_push(con, drizzle_state_handshake_client_read);
90
    drizzle_state_push(con, drizzle_state_packet_read);
91
  }
92
93
  return drizzle_state_loop(con);
94
}
95
96
/*
97
 * State Definitions
98
 */
99
100
drizzle_return_t drizzle_state_handshake_server_read(drizzle_con_st *con)
101
{
102
  uint8_t *ptr;
103
  int extra_length;
104
  unsigned char* packet_end;
105
106
  drizzle_log_debug(con->drizzle, "drizzle_state_handshake_server_read");
107
108
  /* Assume the entire handshake packet will fit in the buffer. */
109
  if (con->buffer_size < con->packet_size)
110
  {
111
    drizzle_state_push(con, drizzle_state_read);
112
    return DRIZZLE_RETURN_OK;
113
  }
114
115
  if (con->packet_size < 46)
116
  {
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;
120
  }
121
122
  packet_end= con->buffer_ptr + con->packet_size;
123
  con->protocol_version= con->buffer_ptr[0];
124
  con->buffer_ptr++;
125
126
  if (con->protocol_version != 10)
127
  {
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)
131
    {
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;
136
    }
137
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;
142
  }
143
144
  /* Look for null-terminated server version string. */
145
  ptr= (uint8_t *)memchr(con->buffer_ptr, 0, con->buffer_size - 1);
146
  if (ptr == NULL)
147
  {
148
    drizzle_set_error(con->drizzle, "drizzle_state_handshake_server_read",
149
                      "server version string not found");
150
    return DRIZZLE_RETURN_BAD_HANDSHAKE_PACKET;
151
  }
152
153
  if (con->packet_size < (46 + (size_t)(ptr - con->buffer_ptr)))
154
  {
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;
159
  }
160
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);
165
166
  con->thread_id= (uint32_t)drizzle_get_byte4(con->buffer_ptr);
167
  con->buffer_ptr+= 4;
168
169
  con->scramble= con->scramble_buffer;
170
  memcpy(con->scramble, con->buffer_ptr, 8);
171
  /* Skip scramble and filler. */
172
  con->buffer_ptr+= 9;
173
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);
178
  con->buffer_ptr+= 2;
179
180
  if (con->options & DRIZZLE_CON_MYSQL &&
181
      !(con->capabilities & DRIZZLE_CAPABILITIES_PROTOCOL_41))
182
  {
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;
186
  }
187
188
  con->charset= con->buffer_ptr[0];
189
  con->buffer_ptr+= 1;
190
191
  con->status= (drizzle_con_status_t)drizzle_get_byte2(con->buffer_ptr);
192
  /* Skip status and filler. */
193
  con->buffer_ptr+= 15;
194
195
  memcpy(con->scramble + 8, con->buffer_ptr, 12);
196
  con->buffer_ptr+= 13;
197
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;
205
206
  con->buffer_size-= con->packet_size;
207
  if (con->buffer_size != 0)
208
  {
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;
212
  }
213
214
  con->buffer_ptr= con->buffer;
215
216
  drizzle_state_pop(con);
217
218
  if (!(con->options & DRIZZLE_CON_RAW_PACKET))
219
  {
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);
224
  }
225
226
  return DRIZZLE_RETURN_OK;
227
}
228
229
drizzle_return_t drizzle_state_handshake_server_write(drizzle_con_st *con)
230
{
231
  uint8_t *ptr;
232
233
  drizzle_log_debug(con->drizzle, "drizzle_state_handshake_server_write");
234
235
  /* Calculate max packet size. */
236
  con->packet_size= 1   /* Protocol version */
237
                  + strlen(con->server_version) + 1
238
                  + 4   /* Thread ID */
239
                  + 8   /* Scramble */
240
                  + 1   /* NULL */
241
                  + 2   /* Capabilities */
242
                  + 1   /* Language */
243
                  + 2   /* Status */
244
                  + 13  /* Unused */
245
                  + 12  /* Scramble */
246
                  + 1;  /* NULL */
247
248
  /* Assume the entire handshake packet will fit in the buffer. */
249
  if ((con->packet_size + 4) > DRIZZLE_MAX_BUFFER_SIZE)
250
  {
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;
254
  }
255
256
  ptr= con->buffer_ptr;
257
258
  /* Store packet size and packet number first. */
259
  drizzle_set_byte3(ptr, con->packet_size);
260
  ptr[3]= 0;
261
  con->packet_number= 1;
262
  ptr+= 4;
263
264
  ptr[0]= con->protocol_version;
265
  ptr++;
266
267
  memcpy(ptr, con->server_version, strlen(con->server_version));
268
  ptr+= strlen(con->server_version);
269
270
  ptr[0]= 0;
271
  ptr++;
272
273
  drizzle_set_byte4(ptr, con->thread_id);
274
  ptr+= 4;
275
276
  if (con->scramble == NULL)
277
    memset(ptr, 0, 8);
278
  else
279
    memcpy(ptr, con->scramble, 8);
280
  ptr+= 8;
281
282
  ptr[0]= 0;
283
  ptr++;
284
285
  if (con->options & DRIZZLE_CON_MYSQL)
286
    con->capabilities|= DRIZZLE_CAPABILITIES_PROTOCOL_41;
287
288
  /* We can only send two bytes worth, this is a protocol limitation. */
289
  drizzle_set_byte2(ptr, con->capabilities);
290
  ptr+= 2;
291
292
  ptr[0]= con->charset;
293
  ptr++;
294
295
  drizzle_set_byte2(ptr, con->status);
296
  ptr+= 2;
297
298
  memset(ptr, 0, 13);
299
  ptr+= 13;
300
301
  if (con->scramble == NULL)
302
    memset(ptr, 0, 12);
303
  else
304
    memcpy(ptr, con->scramble + 8, 12);
305
  ptr+= 12;
306
307
  ptr[0]= 0;
308
  ptr++;
309
310
  con->buffer_size+= (4 + con->packet_size);
311
312
  /* Make sure we packed it correctly. */
313
  if ((size_t)(ptr - con->buffer_ptr) != (4 + con->packet_size))
314
  {
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;
319
  }
320
321
  drizzle_state_pop(con);
322
  return DRIZZLE_RETURN_OK;
323
}
324
325
drizzle_return_t drizzle_state_handshake_client_read(drizzle_con_st *con)
326
{
327
  size_t real_size;
328
  uint8_t *ptr;
329
  uint8_t scramble_size;
330
331
  drizzle_log_debug(con->drizzle, "drizzle_state_handshake_client_read");
332
333
  /* Assume the entire handshake packet will fit in the buffer. */
334
  if (con->buffer_size < con->packet_size)
335
  {
336
    drizzle_state_push(con, drizzle_state_read);
337
    return DRIZZLE_RETURN_OK;
338
  }
339
340
  /* This is the minimum packet size. */
341
  if (con->packet_size < 34)
342
  {
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;
346
  }
347
348
  real_size= 34;
349
350
  con->capabilities= drizzle_get_byte4(con->buffer_ptr);
351
  con->buffer_ptr+= 4;
352
353
  if (con->options & DRIZZLE_CON_MYSQL &&
354
      !(con->capabilities & DRIZZLE_CAPABILITIES_PROTOCOL_41))
355
  {
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;
359
  }
360
361
  con->max_packet_size= (uint32_t)drizzle_get_byte4(con->buffer_ptr);
362
  con->buffer_ptr+= 4;
363
364
  con->charset= con->buffer_ptr[0];
365
  con->buffer_ptr+= 1;
366
367
  /* Skip unused. */
368
  con->buffer_ptr+= 23;
369
370
  /* Look for null-terminated user string. */
371
  ptr= (uint8_t *)memchr(con->buffer_ptr, 0, con->buffer_size - 32);
372
  if (ptr == NULL)
373
  {
374
    drizzle_set_error(con->drizzle, "drizzle_state_handshake_client_read",
375
                      "user string not found");
376
    return DRIZZLE_RETURN_BAD_HANDSHAKE_PACKET;
377
  }
378
379
  if (con->buffer_ptr == ptr)
380
  {
381
    con->user[0]= 0;
382
    con->buffer_ptr++;
383
  }
384
  else
385
  {
386
    real_size+= (size_t)(ptr - con->buffer_ptr);
387
    if (con->packet_size < real_size)
388
    {
389
      drizzle_set_error(con->drizzle, "drizzle_state_handshake_client_read",
390
                        "bad packet size:>=%zu:%zu", real_size,
391
                        con->packet_size);
392
      return DRIZZLE_RETURN_BAD_HANDSHAKE_PACKET;
393
    }
394
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);
398
  }
399
400
  scramble_size= con->buffer_ptr[0];
401
  con->buffer_ptr+= 1;
402
403
  if (scramble_size == 0)
404
    con->scramble= NULL;
405
  else
406
  {
407
    if (scramble_size != DRIZZLE_MAX_SCRAMBLE_SIZE)
408
    {
409
      drizzle_set_error(con->drizzle, "drizzle_state_handshake_client_read",
410
                        "wrong scramble size");
411
      return DRIZZLE_RETURN_BAD_HANDSHAKE_PACKET;
412
    }
413
414
    real_size+= scramble_size;
415
    con->scramble= con->scramble_buffer;
416
    memcpy(con->scramble, con->buffer_ptr, DRIZZLE_MAX_SCRAMBLE_SIZE);
417
418
    con->buffer_ptr+= DRIZZLE_MAX_SCRAMBLE_SIZE;
419
  }
420
421
  /* Look for null-terminated db string. */
422
  if ((34 + strlen(con->user) + scramble_size) == con->packet_size)
423
    con->db[0]= 0;
424
  else
425
  {
426
    ptr= (uint8_t *)memchr(con->buffer_ptr, 0, con->buffer_size -
427
                           (34 + strlen(con->user) + scramble_size));
428
    if (ptr == NULL)
429
    {
430
      drizzle_set_error(con->drizzle, "drizzle_state_handshake_client_read",
431
                        "db string not found");
432
      return DRIZZLE_RETURN_BAD_HANDSHAKE_PACKET;
433
    }
434
435
    real_size+= ((size_t)(ptr - con->buffer_ptr) + 1);
436
    if (con->packet_size != real_size)
437
    {
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;
441
    }
442
443
    if (con->buffer_ptr == ptr)
444
    {
445
      con->db[0]= 0;
446
      con->buffer_ptr++;
447
    }
448
    else
449
    {
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);
453
    }
454
  }
455
456
  con->buffer_size-= con->packet_size;
457
  if (con->buffer_size != 0)
458
  {
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;
462
  }
463
464
  con->buffer_ptr= con->buffer;
465
466
  drizzle_state_pop(con);
467
  return DRIZZLE_RETURN_OK;
468
}
469
470
drizzle_return_t drizzle_state_handshake_client_write(drizzle_con_st *con)
471
{
472
  uint8_t *ptr;
473
  int capabilities;
474
  drizzle_return_t ret;
475
476
  drizzle_log_debug(con->drizzle, "drizzle_state_handshake_client_write");
477
478
  /* Calculate max packet size. */
479
  con->packet_size= 4   /* Capabilities */
480
                  + 4   /* Max packet size */
481
                  + 1   /* Charset */
482
                  + 23  /* Unused */
483
                  + strlen(con->user) + 1
484
                  + 1   /* Scramble size */
485
                  + DRIZZLE_MAX_SCRAMBLE_SIZE
486
                  + strlen(con->db) + 1;
487
488
  /* Assume the entire handshake packet will fit in the buffer. */
489
  if ((con->packet_size + 4) > DRIZZLE_MAX_BUFFER_SIZE)
490
  {
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;
494
  }
495
496
  ptr= con->buffer_ptr;
497
498
  /* Store packet size at the end since it may change. */
499
  ptr[3]= con->packet_number;
500
  con->packet_number++;
501
  ptr+= 4;
502
503
  if (con->options & DRIZZLE_CON_MYSQL)
504
    con->capabilities|= DRIZZLE_CAPABILITIES_PROTOCOL_41;
505
506
  capabilities= con->capabilities & DRIZZLE_CAPABILITIES_CLIENT;
507
  if (!(con->options & DRIZZLE_CON_FOUND_ROWS))
508
    capabilities&= ~DRIZZLE_CAPABILITIES_FOUND_ROWS;
509
510
  if (con->options & DRIZZLE_CON_INTERACTIVE)
511
  {
512
    capabilities|= DRIZZLE_CAPABILITIES_INTERACTIVE;
513
  }
514
515
  if (con->options & DRIZZLE_CON_MULTI_STATEMENTS)
516
  {
517
    capabilities|= DRIZZLE_CAPABILITIES_MULTI_STATEMENTS;
518
  }
519
520
  if (con->options & DRIZZLE_CON_AUTH_PLUGIN)
521
  {
522
    capabilities|= DRIZZLE_CAPABILITIES_PLUGIN_AUTH;
523
  }
524
525
  capabilities&= ~(DRIZZLE_CAPABILITIES_COMPRESS | DRIZZLE_CAPABILITIES_SSL);
526
  if (con->db[0] == 0)
527
    capabilities&= ~DRIZZLE_CAPABILITIES_CONNECT_WITH_DB;
528
529
  drizzle_set_byte4(ptr, capabilities);
530
  ptr+= 4;
531
532
  drizzle_set_byte4(ptr, con->max_packet_size);
533
  ptr+= 4;
534
535
  ptr[0]= con->charset;
536
  ptr++;
537
538
  memset(ptr, 0, 23);
539
  ptr+= 23;
540
541
  ptr= drizzle_pack_auth(con, ptr, &ret);
542
  if (ret != DRIZZLE_RETURN_OK)
543
    return ret;
544
545
  con->buffer_size+= (4 + con->packet_size);
546
547
  /* Make sure we packed it correctly. */
548
  if ((size_t)(ptr - con->buffer_ptr) != (4 + con->packet_size))
549
  {
550
    drizzle_set_error(con->drizzle, "drizzle_state_handshake_client_write",
551
                      "error packing client handshake:%zu:%zu",
552
                      (size_t)(ptr - con->buffer_ptr), 4 + con->packet_size);
553
    return DRIZZLE_RETURN_INTERNAL_ERROR;
554
  }
555
556
  /* Store packet size now. */
557
  drizzle_set_byte3(con->buffer_ptr, con->packet_size);
558
559
  drizzle_state_pop(con);
560
  return DRIZZLE_RETURN_OK;
561
}
562
563
drizzle_return_t drizzle_state_handshake_result_read(drizzle_con_st *con)
564
{
565
  drizzle_return_t ret;
566
  drizzle_result_st result;
567
568
  drizzle_log_debug(con->drizzle, "drizzle_state_handshake_result_read");
569
570
  if (drizzle_result_create(con, &result) == NULL)
571
    return DRIZZLE_RETURN_MEMORY;
572
573
  con->result= &result;
574
575
  ret= drizzle_state_result_read(con);
576
  if (drizzle_state_none(con))
577
  {
578
    if (ret == DRIZZLE_RETURN_OK)
579
    {
580
      if (drizzle_result_eof(&result))
581
      {
582
        drizzle_set_error(con->drizzle, "drizzle_state_handshake_result_read",
583
                         "old insecure authentication mechanism not supported");
584
        ret= DRIZZLE_RETURN_AUTH_FAILED;
585
      }
586
      else
587
        con->options|= DRIZZLE_CON_READY;
588
    }
589
  }
590
591
  drizzle_result_free(&result);
592
593
  if (ret == DRIZZLE_RETURN_ERROR_CODE)
594
    return DRIZZLE_RETURN_HANDSHAKE_FAILED;
595
596
  return ret;
597
}