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