~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to libdrizzle/handshake.c

  • Committer: Monty Taylor
  • Date: 2010-08-12 20:27:32 UTC
  • mto: (1720.1.5 build)
  • mto: This revision was merged to the branch mainline in revision 1722.
  • Revision ID: mordred@inaugust.com-20100812202732-9kzchbkvkyki4n3u
Merged libdrizzle directly into tree.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
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
}