1 | #include <ma_global.h> |
2 | #include <ma_sys.h> |
3 | #include <errmsg.h> |
4 | #include <string.h> |
5 | #include <ma_common.h> |
6 | #include <mysql/client_plugin.h> |
7 | |
8 | typedef struct st_mysql_client_plugin_AUTHENTICATION auth_plugin_t; |
9 | static int client_mpvio_write_packet(struct st_plugin_vio*, const uchar*, size_t); |
10 | static int native_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql); |
11 | extern void read_user_name(char *name); |
12 | extern char *ma_send_connect_attr(MYSQL *mysql, unsigned char *buffer); |
13 | |
14 | typedef struct { |
15 | int (*read_packet)(struct st_plugin_vio *vio, uchar **buf); |
16 | int (*write_packet)(struct st_plugin_vio *vio, const uchar *pkt, size_t pkt_len); |
17 | void (*info)(struct st_plugin_vio *vio, struct st_plugin_vio_info *info); |
18 | /* -= end of MYSQL_PLUGIN_VIO =- */ |
19 | MYSQL *mysql; |
20 | auth_plugin_t *plugin; /**< what plugin we're under */ |
21 | const char *db; |
22 | struct { |
23 | uchar *pkt; /**< pointer into NET::buff */ |
24 | uint pkt_len; |
25 | } cached_server_reply; |
26 | uint packets_read, packets_written; /**< counters for send/received packets */ |
27 | my_bool mysql_change_user; /**< if it's mysql_change_user() */ |
28 | int last_read_packet_len; /**< the length of the last *read* packet */ |
29 | } MCPVIO_EXT; |
30 | /* |
31 | #define compile_time_assert(A) \ |
32 | do {\ |
33 | typedef char constraint[(A) ? 1 : -1];\ |
34 | } while (0); |
35 | */ |
36 | |
37 | auth_plugin_t mysql_native_password_client_plugin= |
38 | { |
39 | MYSQL_CLIENT_AUTHENTICATION_PLUGIN, |
40 | MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION, |
41 | native_password_plugin_name, |
42 | "R.J.Silk, Sergei Golubchik" , |
43 | "Native MySQL authentication" , |
44 | {1, 0, 0}, |
45 | "LGPL" , |
46 | NULL, |
47 | NULL, |
48 | NULL, |
49 | NULL, |
50 | native_password_auth_client |
51 | }; |
52 | |
53 | |
54 | static int native_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql) |
55 | { |
56 | int pkt_len; |
57 | uchar *pkt; |
58 | |
59 | if (((MCPVIO_EXT *)vio)->mysql_change_user) |
60 | { |
61 | /* |
62 | in mysql_change_user() the client sends the first packet. |
63 | we use the old scramble. |
64 | */ |
65 | pkt= (uchar*)mysql->scramble_buff; |
66 | pkt_len= SCRAMBLE_LENGTH + 1; |
67 | } |
68 | else |
69 | { |
70 | /* read the scramble */ |
71 | if ((pkt_len= vio->read_packet(vio, &pkt)) < 0) |
72 | return CR_ERROR; |
73 | |
74 | if (pkt_len != SCRAMBLE_LENGTH + 1) |
75 | return CR_SERVER_HANDSHAKE_ERR; |
76 | |
77 | /* save it in MYSQL */ |
78 | memmove(mysql->scramble_buff, pkt, SCRAMBLE_LENGTH); |
79 | mysql->scramble_buff[SCRAMBLE_LENGTH] = 0; |
80 | } |
81 | |
82 | if (mysql && mysql->passwd[0]) |
83 | { |
84 | char scrambled[SCRAMBLE_LENGTH + 1]; |
85 | ma_scramble_41((uchar *)scrambled, (char*)pkt, mysql->passwd); |
86 | if (vio->write_packet(vio, (uchar*)scrambled, SCRAMBLE_LENGTH)) |
87 | return CR_ERROR; |
88 | } |
89 | else |
90 | if (vio->write_packet(vio, 0, 0)) /* no password */ |
91 | return CR_ERROR; |
92 | |
93 | return CR_OK; |
94 | } |
95 | |
96 | static int send_change_user_packet(MCPVIO_EXT *mpvio, |
97 | const uchar *data, int data_len) |
98 | { |
99 | MYSQL *mysql= mpvio->mysql; |
100 | char *buff, *end; |
101 | int res= 1; |
102 | size_t conn_attr_len= (mysql->options.extension) ? |
103 | mysql->options.extension->connect_attrs_len : 0; |
104 | |
105 | buff= malloc(USERNAME_LENGTH+1 + data_len+1 + NAME_LEN+1 + 2 + NAME_LEN+1 + 9 + conn_attr_len); |
106 | |
107 | end= ma_strmake(buff, mysql->user, USERNAME_LENGTH) + 1; |
108 | |
109 | if (!data_len) |
110 | *end++= 0; |
111 | else |
112 | { |
113 | if (mysql->client_flag & CLIENT_SECURE_CONNECTION) |
114 | { |
115 | DBUG_ASSERT(data_len <= 255); |
116 | if (data_len > 255) |
117 | { |
118 | my_set_error(mysql, CR_MALFORMED_PACKET, SQLSTATE_UNKNOWN, 0); |
119 | goto error; |
120 | } |
121 | *end++= data_len; |
122 | } |
123 | else |
124 | { |
125 | DBUG_ASSERT(data_len == SCRAMBLE_LENGTH_323 + 1); |
126 | DBUG_ASSERT(data[SCRAMBLE_LENGTH_323] == 0); |
127 | } |
128 | memcpy(end, data, data_len); |
129 | end+= data_len; |
130 | } |
131 | end= ma_strmake(end, mpvio->db ? mpvio->db : "" , NAME_LEN) + 1; |
132 | |
133 | if (mysql->server_capabilities & CLIENT_PROTOCOL_41) |
134 | { |
135 | int2store(end, (ushort) mysql->charset->nr); |
136 | end+= 2; |
137 | } |
138 | |
139 | if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH) |
140 | end= ma_strmake(end, mpvio->plugin->name, NAME_LEN) + 1; |
141 | |
142 | end= ma_send_connect_attr(mysql, (unsigned char *)end); |
143 | |
144 | res= ma_simple_command(mysql, COM_CHANGE_USER, |
145 | buff, (ulong)(end-buff), 1, NULL); |
146 | |
147 | error: |
148 | free(buff); |
149 | return res; |
150 | } |
151 | |
152 | |
153 | |
154 | static int send_client_reply_packet(MCPVIO_EXT *mpvio, |
155 | const uchar *data, int data_len) |
156 | { |
157 | MYSQL *mysql= mpvio->mysql; |
158 | NET *net= &mysql->net; |
159 | char *buff, *end; |
160 | size_t conn_attr_len= (mysql->options.extension) ? |
161 | mysql->options.extension->connect_attrs_len : 0; |
162 | |
163 | /* see end= buff+32 below, fixed size of the packet is 32 bytes */ |
164 | buff= malloc(33 + USERNAME_LENGTH + data_len + NAME_LEN + NAME_LEN + conn_attr_len + 9); |
165 | end= buff; |
166 | |
167 | mysql->client_flag|= mysql->options.client_flag; |
168 | mysql->client_flag|= CLIENT_CAPABILITIES; |
169 | |
170 | if (mysql->client_flag & CLIENT_MULTI_STATEMENTS) |
171 | mysql->client_flag|= CLIENT_MULTI_RESULTS; |
172 | |
173 | #if defined(HAVE_TLS) && !defined(EMBEDDED_LIBRARY) |
174 | if (mysql->options.ssl_key || mysql->options.ssl_cert || |
175 | mysql->options.ssl_ca || mysql->options.ssl_capath || |
176 | mysql->options.ssl_cipher || mysql->options.use_ssl || |
177 | (mysql->options.client_flag & CLIENT_SSL_VERIFY_SERVER_CERT)) |
178 | mysql->options.use_ssl= 1; |
179 | if (mysql->options.use_ssl) |
180 | mysql->client_flag|= CLIENT_SSL; |
181 | #endif /* HAVE_TLS && !EMBEDDED_LIBRARY*/ |
182 | if (mpvio->db) |
183 | mysql->client_flag|= CLIENT_CONNECT_WITH_DB; |
184 | |
185 | /* if server doesn't support SSL and verification of server certificate |
186 | was set to mandatory, we need to return an error */ |
187 | if (mysql->options.use_ssl && !(mysql->server_capabilities & CLIENT_SSL)) |
188 | { |
189 | if ((mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT) || |
190 | (mysql->options.extension && (mysql->options.extension->tls_fp || |
191 | mysql->options.extension->tls_fp_list))) |
192 | { |
193 | my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, |
194 | ER(CR_SSL_CONNECTION_ERROR), |
195 | "SSL is required, but the server does not support it" ); |
196 | goto error; |
197 | } |
198 | } |
199 | |
200 | |
201 | /* Remove options that server doesn't support */ |
202 | mysql->client_flag= mysql->client_flag & |
203 | (~(CLIENT_COMPRESS | CLIENT_SSL | CLIENT_PROTOCOL_41) |
204 | | mysql->server_capabilities); |
205 | |
206 | #ifndef HAVE_COMPRESS |
207 | mysql->client_flag&= ~CLIENT_COMPRESS; |
208 | #endif |
209 | |
210 | if (mysql->client_flag & CLIENT_PROTOCOL_41) |
211 | { |
212 | /* 4.1 server and 4.1 client has a 32 byte option flag */ |
213 | if (!(mysql->server_capabilities & CLIENT_MYSQL)) |
214 | mysql->client_flag&= ~CLIENT_MYSQL; |
215 | int4store(buff,mysql->client_flag); |
216 | int4store(buff+4, net->max_packet_size); |
217 | buff[8]= (char) mysql->charset->nr; |
218 | memset(buff + 9, 0, 32-9); |
219 | if (!(mysql->server_capabilities & CLIENT_MYSQL)) |
220 | { |
221 | mysql->extension->mariadb_client_flag = MARIADB_CLIENT_SUPPORTED_FLAGS >> 32; |
222 | int4store(buff + 28, mysql->extension->mariadb_client_flag); |
223 | } |
224 | end= buff+32; |
225 | } |
226 | else |
227 | { |
228 | int2store(buff, mysql->client_flag); |
229 | int3store(buff+2, net->max_packet_size); |
230 | end= buff+5; |
231 | } |
232 | #ifdef HAVE_TLS |
233 | if (mysql->options.ssl_key || |
234 | mysql->options.ssl_cert || |
235 | mysql->options.ssl_ca || |
236 | mysql->options.ssl_capath || |
237 | mysql->options.ssl_cipher |
238 | #ifdef CRL_IMPLEMENTED |
239 | || (mysql->options.extension && |
240 | (mysql->options.extension->ssl_crl || |
241 | mysql->options.extension->ssl_crlpath)) |
242 | #endif |
243 | ) |
244 | mysql->options.use_ssl= 1; |
245 | if (mysql->options.use_ssl && |
246 | (mysql->client_flag & CLIENT_SSL)) |
247 | { |
248 | /* |
249 | Send mysql->client_flag, max_packet_size - unencrypted otherwise |
250 | the server does not know we want to do SSL |
251 | */ |
252 | if (ma_net_write(net, (unsigned char *)buff, (size_t) (end-buff)) || ma_net_flush(net)) |
253 | { |
254 | my_set_error(mysql, CR_SERVER_LOST, SQLSTATE_UNKNOWN, |
255 | ER(CR_SERVER_LOST_EXTENDED), |
256 | "sending connection information to server" , |
257 | errno); |
258 | goto error; |
259 | } |
260 | if (ma_pvio_start_ssl(mysql->net.pvio)) |
261 | goto error; |
262 | } |
263 | #endif /* HAVE_TLS */ |
264 | |
265 | /* This needs to be changed as it's not useful with big packets */ |
266 | if (mysql->user && mysql->user[0]) |
267 | ma_strmake(end, mysql->user, USERNAME_LENGTH); |
268 | else |
269 | read_user_name(end); |
270 | |
271 | /* We have to handle different version of handshake here */ |
272 | end+= strlen(end) + 1; |
273 | if (data_len) |
274 | { |
275 | if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION) |
276 | { |
277 | *end++= data_len; |
278 | memcpy(end, data, data_len); |
279 | end+= data_len; |
280 | } |
281 | else |
282 | { |
283 | DBUG_ASSERT(data_len == SCRAMBLE_LENGTH_323 + 1); /* incl. \0 at the end */ |
284 | memcpy(end, data, data_len); |
285 | end+= data_len; |
286 | } |
287 | } |
288 | else |
289 | *end++= 0; |
290 | |
291 | /* Add database if needed */ |
292 | if (mpvio->db && (mysql->server_capabilities & CLIENT_CONNECT_WITH_DB)) |
293 | { |
294 | end= ma_strmake(end, mpvio->db, NAME_LEN) + 1; |
295 | mysql->db= strdup(mpvio->db); |
296 | } |
297 | |
298 | if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH) |
299 | end= ma_strmake(end, mpvio->plugin->name, NAME_LEN) + 1; |
300 | |
301 | end= ma_send_connect_attr(mysql, (unsigned char *)end); |
302 | |
303 | /* Write authentication package */ |
304 | if (ma_net_write(net, (unsigned char *)buff, (size_t) (end-buff)) || ma_net_flush(net)) |
305 | { |
306 | my_set_error(mysql, CR_SERVER_LOST, SQLSTATE_UNKNOWN, |
307 | ER(CR_SERVER_LOST_EXTENDED), |
308 | "sending authentication information" , |
309 | errno); |
310 | goto error; |
311 | } |
312 | free(buff); |
313 | return 0; |
314 | |
315 | error: |
316 | free(buff); |
317 | return 1; |
318 | } |
319 | |
320 | /** |
321 | vio->read_packet() callback method for client authentication plugins |
322 | |
323 | This function is called by a client authentication plugin, when it wants |
324 | to read data from the server. |
325 | */ |
326 | |
327 | static int client_mpvio_read_packet(struct st_plugin_vio *mpv, uchar **buf) |
328 | { |
329 | MCPVIO_EXT *mpvio= (MCPVIO_EXT*)mpv; |
330 | MYSQL *mysql= mpvio->mysql; |
331 | ulong pkt_len; |
332 | |
333 | /* there are cached data left, feed it to a plugin */ |
334 | if (mpvio->cached_server_reply.pkt) |
335 | { |
336 | *buf= mpvio->cached_server_reply.pkt; |
337 | mpvio->cached_server_reply.pkt= 0; |
338 | mpvio->packets_read++; |
339 | return mpvio->cached_server_reply.pkt_len; |
340 | } |
341 | |
342 | if (mpvio->packets_read == 0) |
343 | { |
344 | /* |
345 | the server handshake packet came from the wrong plugin, |
346 | or it's mysql_change_user(). Either way, there is no data |
347 | for a plugin to read. send a dummy packet to the server |
348 | to initiate a dialog. |
349 | */ |
350 | if (client_mpvio_write_packet(mpv, 0, 0)) |
351 | return (int)packet_error; |
352 | } |
353 | |
354 | /* otherwise read the data */ |
355 | pkt_len= ma_net_safe_read(mysql); |
356 | mpvio->last_read_packet_len= pkt_len; |
357 | *buf= mysql->net.read_pos; |
358 | |
359 | /* was it a request to change plugins ? */ |
360 | if (**buf == 254) |
361 | return (int)packet_error; /* if yes, this plugin shan't continue */ |
362 | |
363 | /* |
364 | the server sends \1\255 or \1\254 instead of just \255 or \254 - |
365 | for us to not confuse it with an error or "change plugin" packets. |
366 | We remove this escaping \1 here. |
367 | |
368 | See also server_mpvio_write_packet() where the escaping is done. |
369 | */ |
370 | if (pkt_len && **buf == 1) |
371 | { |
372 | (*buf)++; |
373 | pkt_len--; |
374 | } |
375 | mpvio->packets_read++; |
376 | return pkt_len; |
377 | } |
378 | |
379 | /** |
380 | vio->write_packet() callback method for client authentication plugins |
381 | |
382 | This function is called by a client authentication plugin, when it wants |
383 | to send data to the server. |
384 | |
385 | It transparently wraps the data into a change user or authentication |
386 | handshake packet, if necessary. |
387 | */ |
388 | |
389 | static int client_mpvio_write_packet(struct st_plugin_vio *mpv, |
390 | const uchar *pkt, size_t pkt_len) |
391 | { |
392 | int res; |
393 | MCPVIO_EXT *mpvio= (MCPVIO_EXT*)mpv; |
394 | |
395 | if (mpvio->packets_written == 0) |
396 | { |
397 | if (mpvio->mysql_change_user) |
398 | res= send_change_user_packet(mpvio, pkt, (int)pkt_len); |
399 | else |
400 | res= send_client_reply_packet(mpvio, pkt, (int)pkt_len); |
401 | } |
402 | else |
403 | { |
404 | NET *net= &mpvio->mysql->net; |
405 | if (mpvio->mysql->thd) |
406 | res= 1; /* no chit-chat in embedded */ |
407 | else |
408 | res= ma_net_write(net, (unsigned char *)pkt, pkt_len) || ma_net_flush(net); |
409 | } |
410 | |
411 | if (res) |
412 | { |
413 | /* don't overwrite errors */ |
414 | if (!mysql_errno(mpvio->mysql)) |
415 | my_set_error(mpvio->mysql, CR_SERVER_LOST, SQLSTATE_UNKNOWN, |
416 | ER(CR_SERVER_LOST_EXTENDED), |
417 | "sending authentication information" , |
418 | errno); |
419 | } |
420 | mpvio->packets_written++; |
421 | return res; |
422 | } |
423 | |
424 | /** |
425 | fills MYSQL_PLUGIN_VIO_INFO structure with the information about the |
426 | connection |
427 | */ |
428 | |
429 | void mpvio_info(MARIADB_PVIO *pvio, MYSQL_PLUGIN_VIO_INFO *info) |
430 | { |
431 | memset(info, 0, sizeof(*info)); |
432 | switch (pvio->type) { |
433 | case PVIO_TYPE_SOCKET: |
434 | info->protocol= MYSQL_VIO_TCP; |
435 | ma_pvio_get_handle(pvio, &info->socket); |
436 | return; |
437 | case PVIO_TYPE_UNIXSOCKET: |
438 | info->protocol= MYSQL_VIO_SOCKET; |
439 | ma_pvio_get_handle(pvio, &info->socket); |
440 | return; |
441 | /* |
442 | case VIO_TYPE_SSL: |
443 | { |
444 | struct sockaddr addr; |
445 | SOCKET_SIZE_TYPE addrlen= sizeof(addr); |
446 | if (getsockname(vio->sd, &addr, &addrlen)) |
447 | return; |
448 | info->protocol= addr.sa_family == AF_UNIX ? |
449 | MYSQL_VIO_SOCKET : MYSQL_VIO_TCP; |
450 | info->socket= vio->sd; |
451 | return; |
452 | } |
453 | */ |
454 | #ifdef _WIN32 |
455 | /* |
456 | case VIO_TYPE_NAMEDPIPE: |
457 | info->protocol= MYSQL_VIO_PIPE; |
458 | info->handle= vio->hPipe; |
459 | return; |
460 | */ |
461 | /* not supported yet |
462 | case VIO_TYPE_SHARED_MEMORY: |
463 | info->protocol= MYSQL_VIO_MEMORY; |
464 | info->handle= vio->handle_file_map; |
465 | return; |
466 | */ |
467 | #endif |
468 | default: DBUG_ASSERT(0); |
469 | } |
470 | } |
471 | |
472 | static void client_mpvio_info(MYSQL_PLUGIN_VIO *vio, |
473 | MYSQL_PLUGIN_VIO_INFO *info) |
474 | { |
475 | MCPVIO_EXT *mpvio= (MCPVIO_EXT*)vio; |
476 | mpvio_info(mpvio->mysql->net.pvio, info); |
477 | } |
478 | |
479 | /** |
480 | Client side of the plugin driver authentication. |
481 | |
482 | @note this is used by both the mysql_real_connect and mysql_change_user |
483 | |
484 | @param mysql mysql |
485 | @param data pointer to the plugin auth data (scramble) in the |
486 | handshake packet |
487 | @param data_len the length of the data |
488 | @param data_plugin a plugin that data were prepared for |
489 | or 0 if it's mysql_change_user() |
490 | @param db initial db to use, can be 0 |
491 | |
492 | @retval 0 ok |
493 | @retval 1 error |
494 | */ |
495 | |
496 | int run_plugin_auth(MYSQL *mysql, char *data, uint data_len, |
497 | const char *data_plugin, const char *db) |
498 | { |
499 | const char *auth_plugin_name; |
500 | auth_plugin_t *auth_plugin; |
501 | MCPVIO_EXT mpvio; |
502 | ulong pkt_length; |
503 | int res; |
504 | |
505 | /* determine the default/initial plugin to use */ |
506 | if (mysql->options.extension && mysql->options.extension->default_auth && |
507 | mysql->server_capabilities & CLIENT_PLUGIN_AUTH) |
508 | { |
509 | auth_plugin_name= mysql->options.extension->default_auth; |
510 | if (!(auth_plugin= (auth_plugin_t*) mysql_client_find_plugin(mysql, |
511 | auth_plugin_name, MYSQL_CLIENT_AUTHENTICATION_PLUGIN))) |
512 | return 1; /* oops, not found */ |
513 | } |
514 | else |
515 | { |
516 | if (mysql->server_capabilities & CLIENT_PROTOCOL_41) |
517 | auth_plugin= &mysql_native_password_client_plugin; |
518 | else |
519 | { |
520 | if (!(auth_plugin= (auth_plugin_t*)mysql_client_find_plugin(mysql, |
521 | "mysql_old_password" , MYSQL_CLIENT_AUTHENTICATION_PLUGIN))) |
522 | return 1; /* not found */ |
523 | } |
524 | auth_plugin_name= auth_plugin->name; |
525 | } |
526 | |
527 | mysql->net.last_errno= 0; /* just in case */ |
528 | |
529 | if (data_plugin && strcmp(data_plugin, auth_plugin_name)) |
530 | { |
531 | /* data was prepared for a different plugin, don't show it to this one */ |
532 | data= 0; |
533 | data_len= 0; |
534 | } |
535 | |
536 | mpvio.mysql_change_user= data_plugin == 0; |
537 | mpvio.cached_server_reply.pkt= (uchar*)data; |
538 | mpvio.cached_server_reply.pkt_len= data_len; |
539 | mpvio.read_packet= client_mpvio_read_packet; |
540 | mpvio.write_packet= client_mpvio_write_packet; |
541 | mpvio.info= client_mpvio_info; |
542 | mpvio.mysql= mysql; |
543 | mpvio.packets_read= mpvio.packets_written= 0; |
544 | mpvio.db= db; |
545 | mpvio.plugin= auth_plugin; |
546 | |
547 | res= auth_plugin->authenticate_user((struct st_plugin_vio *)&mpvio, mysql); |
548 | |
549 | if (res > CR_OK && mysql->net.read_pos[0] != 254) |
550 | { |
551 | /* |
552 | the plugin returned an error. write it down in mysql, |
553 | unless the error code is CR_ERROR and mysql->net.last_errno |
554 | is already set (the plugin has done it) |
555 | */ |
556 | if (res > CR_ERROR) |
557 | my_set_error(mysql, res, SQLSTATE_UNKNOWN, 0); |
558 | else |
559 | if (!mysql->net.last_errno) { |
560 | my_set_error(mysql, CR_UNKNOWN_ERROR, SQLSTATE_UNKNOWN, 0); |
561 | } |
562 | return 1; |
563 | } |
564 | |
565 | /* read the OK packet (or use the cached value in mysql->net.read_pos */ |
566 | if (res == CR_OK) |
567 | pkt_length= ma_net_safe_read(mysql); |
568 | else /* res == CR_OK_HANDSHAKE_COMPLETE */ |
569 | pkt_length= mpvio.last_read_packet_len; |
570 | |
571 | if (pkt_length == packet_error) |
572 | { |
573 | if (mysql->net.last_errno == CR_SERVER_LOST) |
574 | my_set_error(mysql, CR_SERVER_LOST, SQLSTATE_UNKNOWN, |
575 | ER(CR_SERVER_LOST_EXTENDED), |
576 | "reading authorization packet" , |
577 | errno); |
578 | return 1; |
579 | } |
580 | |
581 | if (mysql->net.read_pos[0] == 254) |
582 | { |
583 | /* The server asked to use a different authentication plugin */ |
584 | if (pkt_length == 1) |
585 | { |
586 | /* old "use short scramble" packet */ |
587 | auth_plugin_name= old_password_plugin_name; |
588 | mpvio.cached_server_reply.pkt= (uchar*)mysql->scramble_buff; |
589 | mpvio.cached_server_reply.pkt_len= SCRAMBLE_LENGTH + 1; |
590 | } |
591 | else |
592 | { |
593 | /* new "use different plugin" packet */ |
594 | uint len; |
595 | auth_plugin_name= (char*)mysql->net.read_pos + 1; |
596 | len= (uint)strlen(auth_plugin_name); /* safe as ma_net_read always appends \0 */ |
597 | mpvio.cached_server_reply.pkt_len= pkt_length - len - 2; |
598 | mpvio.cached_server_reply.pkt= mysql->net.read_pos + len + 2; |
599 | } |
600 | if (!(auth_plugin= (auth_plugin_t *) mysql_client_find_plugin(mysql, |
601 | auth_plugin_name, MYSQL_CLIENT_AUTHENTICATION_PLUGIN))) |
602 | return 1; |
603 | |
604 | mpvio.plugin= auth_plugin; |
605 | res= auth_plugin->authenticate_user((struct st_plugin_vio *)&mpvio, mysql); |
606 | |
607 | if (res > CR_OK) |
608 | { |
609 | if (res > CR_ERROR) |
610 | my_set_error(mysql, res, SQLSTATE_UNKNOWN, 0); |
611 | else |
612 | if (!mysql->net.last_errno) |
613 | my_set_error(mysql, CR_UNKNOWN_ERROR, SQLSTATE_UNKNOWN, 0); |
614 | return 1; |
615 | } |
616 | |
617 | if (res != CR_OK_HANDSHAKE_COMPLETE) |
618 | { |
619 | /* Read what server thinks about out new auth message report */ |
620 | if (ma_net_safe_read(mysql) == packet_error) |
621 | { |
622 | if (mysql->net.last_errno == CR_SERVER_LOST) |
623 | my_set_error(mysql, CR_SERVER_LOST, SQLSTATE_UNKNOWN, |
624 | ER(CR_SERVER_LOST_EXTENDED), |
625 | "reading final connect information" , |
626 | errno); |
627 | return 1; |
628 | } |
629 | } |
630 | } |
631 | /* |
632 | net->read_pos[0] should always be 0 here if the server implements |
633 | the protocol correctly |
634 | */ |
635 | return mysql->net.read_pos[0] != 0; |
636 | } |
637 | |
638 | |