~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to libdrizzle/handshake.c

  • Committer: Monty Taylor
  • Date: 2008-08-01 23:59:59 UTC
  • mto: (236.1.42 codestyle)
  • mto: This revision was merged to the branch mainline in revision 261.
  • Revision ID: monty@inaugust.com-20080801235959-n8ypy9r5aohown77
Gettext error compiles and passes test!

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
 
}