libdrizzle Developer Documentation
Main Page
Related Pages
Modules
Data Structures
Files
File List
Globals
libdrizzle
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
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
capabilities&= ~(
DRIZZLE_CAPABILITIES_COMPRESS
|
DRIZZLE_CAPABILITIES_SSL
);
471
if
(con->
db
[0] == 0)
472
capabilities&= ~
DRIZZLE_CAPABILITIES_CONNECT_WITH_DB
;
473
474
drizzle_set_byte4
(ptr, capabilities);
475
ptr+= 4;
476
477
drizzle_set_byte4
(ptr, con->
max_packet_size
);
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
);
498
return
DRIZZLE_RETURN_INTERNAL_ERROR
;
499
}
500
501
/* Store packet size now. */
502
drizzle_set_byte3
(con->
buffer_ptr
, con->
packet_size
);
503
504
drizzle_state_pop
(con);
505
return
DRIZZLE_RETURN_OK
;
506
}
507
508
drizzle_return_t
drizzle_state_handshake_result_read
(
drizzle_con_st
*con)
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"
);
529
ret=
DRIZZLE_RETURN_AUTH_FAILED
;
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
)
539
return
DRIZZLE_RETURN_HANDSHAKE_FAILED
;
540
541
return
ret;
542
}
Generated by
1.8.1.1