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