1 /* Copyright (c) 2003, 2016, Oracle and/or its affiliates.
2    Copyright (c) 2009, 2020, MariaDB
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; version 2 of the License.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 
13    You should have received a copy of the GNU General Public License
14    along with this program; if not, write to the Free Software
15    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1335  USA */
16 
17 /*
18   This file is included by both libmysql.c (the MySQL client C API)
19   and the mysqld server to connect to another MYSQL server.
20 
21   The differences for the two cases are:
22 
23   - Things that only works for the client:
24   - Trying to automaticly determinate user name if not supplied to
25     mysql_real_connect()
26   - Support for reading local file with LOAD DATA LOCAL
27   - SHARED memory handling
28   - Prepared statements
29 
30   - Things that only works for the server
31   - Alarm handling on connect
32 
33   In all other cases, the code should be idential for the client and
34   server.
35 */
36 
37 #include <my_global.h>
38 #include <my_default.h>
39 #include "mysql.h"
40 #include "hash.h"
41 
42 /* Remove client convenience wrappers */
43 #undef max_allowed_packet
44 #undef net_buffer_length
45 
46 #ifdef EMBEDDED_LIBRARY
47 
48 #undef MYSQL_SERVER
49 
50 #ifndef MYSQL_CLIENT
51 #define MYSQL_CLIENT
52 #endif
53 
54 #define CLI_MYSQL_REAL_CONNECT STDCALL cli_mysql_real_connect
55 
56 #undef net_flush
57 my_bool	net_flush(NET *net);
58 
59 #else  /*EMBEDDED_LIBRARY*/
60 #define CLI_MYSQL_REAL_CONNECT STDCALL mysql_real_connect
61 #endif /*EMBEDDED_LIBRARY*/
62 
63 #include <my_sys.h>
64 #include <mysys_err.h>
65 #include <m_string.h>
66 #include <m_ctype.h>
67 #include "mysql_version.h"
68 #include "mysqld_error.h"
69 #include "errmsg.h"
70 #include <violite.h>
71 
72 #if !defined(__WIN__)
73 #include <my_pthread.h>				/* because of signal()	*/
74 #endif /* !defined(__WIN__) */
75 
76 #include <sys/stat.h>
77 #include <signal.h>
78 #include <time.h>
79 
80 #ifdef	 HAVE_PWD_H
81 #include <pwd.h>
82 #endif
83 
84 #if !defined(__WIN__)
85 #ifdef HAVE_SELECT_H
86 #  include <select.h>
87 #endif
88 #ifdef HAVE_SYS_SELECT_H
89 #include <sys/select.h>
90 #endif
91 #endif /* !defined(__WIN__) */
92 #ifdef HAVE_SYS_UN_H
93 #  include <sys/un.h>
94 #endif
95 
96 #ifndef _WIN32
97 #include <errno.h>
98 #define SOCKET_ERROR -1
99 #define INVALID_SOCKET -1
100 #endif
101 
102 #ifdef __WIN__
103 #define CONNECT_TIMEOUT 20
104 #else
105 #define CONNECT_TIMEOUT 0
106 #endif
107 
108 #include "client_settings.h"
109 #include <ssl_compat.h>
110 #include <sql_common.h>
111 #include <mysql/client_plugin.h>
112 #include <my_context.h>
113 #include <mysql_async.h>
114 
115 typedef enum {
116   ALWAYS_ACCEPT,       /* heuristics is disabled, use CLIENT_LOCAL_FILES */
117   WAIT_FOR_QUERY,      /* heuristics is enabled, not sending files */
118   ACCEPT_FILE_REQUEST  /* heuristics is enabled, ready to send a file */
119 } auto_local_infile_state;
120 
121 #define native_password_plugin_name "mysql_native_password"
122 #define old_password_plugin_name    "mysql_old_password"
123 
124 uint            mariadb_deinitialize_ssl= 1;
125 uint		mysql_port=0;
126 char		*mysql_unix_port= 0;
127 const char	*unknown_sqlstate= "HY000";
128 const char	*not_error_sqlstate= "00000";
129 const char	*cant_connect_sqlstate= "08001";
130 #ifdef HAVE_SMEM
131 char		 *shared_memory_base_name= 0;
132 const char 	*def_shared_memory_base_name= default_shared_memory_base_name;
133 #endif
134 
135 static void mysql_close_free_options(MYSQL *mysql);
136 static void mysql_close_free(MYSQL *mysql);
137 static void mysql_prune_stmt_list(MYSQL *mysql);
138 static int cli_report_progress(MYSQL *mysql, char *packet, uint length);
139 
140 CHARSET_INFO *default_client_charset_info = &my_charset_latin1;
141 
142 /* Server error code and message */
143 unsigned int mysql_server_last_errno;
144 char mysql_server_last_error[MYSQL_ERRMSG_SIZE];
145 
146 /**
147   Convert the connect timeout option to a timeout value for VIO
148   functions (vio_socket_connect() and vio_io_wait()).
149 
150   @param mysql  Connection handle (client side).
151 
152   @return The timeout value in milliseconds, or -1 if no timeout.
153 */
154 
get_vio_connect_timeout(MYSQL * mysql)155 static int get_vio_connect_timeout(MYSQL *mysql)
156 {
157   int timeout_ms;
158   uint timeout_sec;
159 
160   /*
161     A timeout of 0 means no timeout. Also, the connect_timeout
162     option value is in seconds, while VIO timeouts are measured
163     in milliseconds. Hence, check for a possible overflow. In
164     case of overflow, set to no timeout.
165   */
166   timeout_sec= mysql->options.connect_timeout;
167 
168   if (!timeout_sec || (timeout_sec > INT_MAX/1000))
169     timeout_ms= -1;
170   else
171     timeout_ms= (int) (timeout_sec * 1000);
172 
173   return timeout_ms;
174 }
175 
176 
177 /**
178   Set the internal error message to mysql handler
179 
180   @param mysql    connection handle (client side)
181   @param errcode  CR_ error code, passed to ER macro to get
182                   error text
183   @parma sqlstate SQL standard sqlstate
184 */
185 
set_mysql_error(MYSQL * mysql,int errcode,const char * sqlstate)186 void set_mysql_error(MYSQL *mysql, int errcode, const char *sqlstate)
187 {
188   NET *net;
189   DBUG_ENTER("set_mysql_error");
190   DBUG_PRINT("enter", ("error :%d '%s'", errcode, ER(errcode)));
191   DBUG_ASSERT(mysql != 0);
192 
193   if (mysql)
194   {
195     net= &mysql->net;
196     net->last_errno= errcode;
197     strmov(net->last_error, ER(errcode));
198     strmov(net->sqlstate, sqlstate);
199   }
200   else
201   {
202     mysql_server_last_errno= errcode;
203     strmov(mysql_server_last_error, ER(errcode));
204   }
205   DBUG_VOID_RETURN;
206 }
207 
208 /**
209   Clear possible error state of struct NET
210 
211   @param net  clear the state of the argument
212 */
213 
net_clear_error(NET * net)214 void net_clear_error(NET *net)
215 {
216   net->last_errno= 0;
217   net->last_error[0]= '\0';
218   strmov(net->sqlstate, not_error_sqlstate);
219 }
220 
221 /**
222   Set an error message on the client.
223 
224   @param mysql     connection handle
225   @param errcode   CR_* errcode, for client errors
226   @param sqlstate  SQL standard sql state, unknown_sqlstate for the
227                    majority of client errors.
228   @param format    error message template, in sprintf format
229   @param ...       variable number of arguments
230 */
231 
set_mysql_extended_error(MYSQL * mysql,int errcode,const char * sqlstate,const char * format,...)232 void set_mysql_extended_error(MYSQL *mysql, int errcode,
233                                      const char *sqlstate,
234                                      const char *format, ...)
235 {
236   NET *net;
237   va_list args;
238   DBUG_ENTER("set_mysql_extended_error");
239   DBUG_PRINT("enter", ("error :%d '%s'", errcode, format));
240   DBUG_ASSERT(mysql != 0);
241 
242   net= &mysql->net;
243   net->last_errno= errcode;
244   va_start(args, format);
245   my_vsnprintf(net->last_error, sizeof(net->last_error)-1,
246                format, args);
247   va_end(args);
248   strmov(net->sqlstate, sqlstate);
249 
250   DBUG_VOID_RETURN;
251 }
252 
253 
254 
255 /*
256   Create a named pipe connection
257 */
258 
259 #ifdef __WIN__
260 
create_named_pipe(MYSQL * mysql,uint connect_timeout,char ** arg_host,char ** arg_unix_socket)261 HANDLE create_named_pipe(MYSQL *mysql, uint connect_timeout, char **arg_host,
262 			 char **arg_unix_socket)
263 {
264   HANDLE hPipe=INVALID_HANDLE_VALUE;
265   char pipe_name[1024];
266   DWORD dwMode;
267   int i;
268   char *host= *arg_host, *unix_socket= *arg_unix_socket;
269 
270   if ( ! unix_socket || (unix_socket)[0] == 0x00)
271     unix_socket = mysql_unix_port;
272   if (!host || !strcmp(host,LOCAL_HOST))
273     host=LOCAL_HOST_NAMEDPIPE;
274 
275 
276   pipe_name[sizeof(pipe_name)-1]= 0;		/* Safety if too long string */
277   strxnmov(pipe_name, sizeof(pipe_name)-1, "\\\\", host, "\\pipe\\",
278 	   unix_socket, NullS);
279   DBUG_PRINT("info",("Server name: '%s'.  Named Pipe: %s", host, unix_socket));
280 
281   for (i=0 ; i < 100 ; i++)			/* Don't retry forever */
282   {
283     if ((hPipe = CreateFile(pipe_name,
284 			    GENERIC_READ | GENERIC_WRITE,
285 			    0,
286 			    NULL,
287 			    OPEN_EXISTING,
288 			    FILE_FLAG_OVERLAPPED,
289 			    NULL )) != INVALID_HANDLE_VALUE)
290       break;
291     if (GetLastError() != ERROR_PIPE_BUSY)
292     {
293       set_mysql_extended_error(mysql, CR_NAMEDPIPEOPEN_ERROR,
294                                unknown_sqlstate, ER(CR_NAMEDPIPEOPEN_ERROR),
295                                host, unix_socket, (ulong) GetLastError());
296       return INVALID_HANDLE_VALUE;
297     }
298     /* wait for for an other instance */
299     if (! WaitNamedPipe(pipe_name, connect_timeout*1000) )
300     {
301       set_mysql_extended_error(mysql, CR_NAMEDPIPEWAIT_ERROR, unknown_sqlstate,
302                                ER(CR_NAMEDPIPEWAIT_ERROR),
303                                host, unix_socket, (ulong) GetLastError());
304       return INVALID_HANDLE_VALUE;
305     }
306   }
307   if (hPipe == INVALID_HANDLE_VALUE)
308   {
309     set_mysql_extended_error(mysql, CR_NAMEDPIPEOPEN_ERROR, unknown_sqlstate,
310                              ER(CR_NAMEDPIPEOPEN_ERROR), host, unix_socket,
311                              (ulong) GetLastError());
312     return INVALID_HANDLE_VALUE;
313   }
314   dwMode = PIPE_READMODE_BYTE | PIPE_WAIT;
315   if ( !SetNamedPipeHandleState(hPipe, &dwMode, NULL, NULL) )
316   {
317     CloseHandle( hPipe );
318     set_mysql_extended_error(mysql, CR_NAMEDPIPESETSTATE_ERROR,
319                              unknown_sqlstate, ER(CR_NAMEDPIPESETSTATE_ERROR),
320                              host, unix_socket, (ulong) GetLastError());
321     return INVALID_HANDLE_VALUE;
322   }
323   *arg_host=host ; *arg_unix_socket=unix_socket;	/* connect arg */
324   return (hPipe);
325 }
326 #endif
327 
328 
329 /*
330   Create new shared memory connection, return handler of connection
331 
332   SYNOPSIS
333     create_shared_memory()
334     mysql		Pointer of mysql structure
335     net			Pointer of net structure
336     connect_timeout	Timeout of connection
337 */
338 
339 #ifdef HAVE_SMEM
create_shared_memory(MYSQL * mysql,NET * net,uint connect_timeout)340 HANDLE create_shared_memory(MYSQL *mysql,NET *net, uint connect_timeout)
341 {
342   ulong smem_buffer_length = shared_memory_buffer_length + 4;
343   /*
344     event_connect_request is event object for start connection actions
345     event_connect_answer is event object for confirm, that server put data
346     handle_connect_file_map is file-mapping object, use for create shared
347     memory
348     handle_connect_map is pointer on shared memory
349     handle_map is pointer on shared memory for client
350     event_server_wrote,
351     event_server_read,
352     event_client_wrote,
353     event_client_read are events for transfer data between server and client
354     handle_file_map is file-mapping object, use for create shared memory
355   */
356   HANDLE event_connect_request = NULL;
357   HANDLE event_connect_answer = NULL;
358   HANDLE handle_connect_file_map = NULL;
359   char *handle_connect_map = NULL;
360 
361   char *handle_map = NULL;
362   HANDLE event_server_wrote = NULL;
363   HANDLE event_server_read = NULL;
364   HANDLE event_client_wrote = NULL;
365   HANDLE event_client_read = NULL;
366   HANDLE event_conn_closed = NULL;
367   HANDLE handle_file_map = NULL;
368   ulong connect_number;
369   char connect_number_char[22], *p;
370   char *tmp= NULL;
371   char *suffix_pos;
372   DWORD error_allow = 0;
373   DWORD error_code = 0;
374   DWORD event_access_rights= SYNCHRONIZE | EVENT_MODIFY_STATE;
375   char *shared_memory_base_name = mysql->options.shared_memory_base_name;
376   static const char *name_prefixes[] = {"","Global\\"};
377   const char *prefix;
378   uint i;
379 
380   /*
381     If this is NULL, somebody freed the MYSQL* options.  mysql_close()
382     is a good candidate.  We don't just silently (re)set it to
383     def_shared_memory_base_name as that would create really confusing/buggy
384     behavior if the user passed in a different name on the command-line or
385     in a my.cnf.
386   */
387   DBUG_ASSERT(shared_memory_base_name != NULL);
388 
389   /*
390      get enough space base-name + '_' + longest suffix we might ever send
391    */
392   if (!(tmp= (char *)my_malloc(strlen(shared_memory_base_name) + 32L, MYF(MY_FAE))))
393     goto err;
394 
395   /*
396     The name of event and file-mapping events create agree next rule:
397     shared_memory_base_name+unique_part
398     Where:
399     shared_memory_base_name is unique value for each server
400     unique_part is uniquel value for each object (events and file-mapping)
401   */
402   for (i = 0; i< array_elements(name_prefixes); i++)
403   {
404     prefix= name_prefixes[i];
405     suffix_pos = strxmov(tmp, prefix , shared_memory_base_name, "_", NullS);
406     strmov(suffix_pos, "CONNECT_REQUEST");
407     event_connect_request= OpenEvent(event_access_rights, FALSE, tmp);
408     if (event_connect_request)
409     {
410       break;
411     }
412   }
413   if (!event_connect_request)
414   {
415     error_allow = CR_SHARED_MEMORY_CONNECT_REQUEST_ERROR;
416     goto err;
417   }
418   strmov(suffix_pos, "CONNECT_ANSWER");
419   if (!(event_connect_answer= OpenEvent(event_access_rights,FALSE,tmp)))
420   {
421     error_allow = CR_SHARED_MEMORY_CONNECT_ANSWER_ERROR;
422     goto err;
423   }
424   strmov(suffix_pos, "CONNECT_DATA");
425   if (!(handle_connect_file_map= OpenFileMapping(FILE_MAP_WRITE,FALSE,tmp)))
426   {
427     error_allow = CR_SHARED_MEMORY_CONNECT_FILE_MAP_ERROR;
428     goto err;
429   }
430   if (!(handle_connect_map= MapViewOfFile(handle_connect_file_map,
431 					  FILE_MAP_WRITE,0,0,sizeof(DWORD))))
432   {
433     error_allow = CR_SHARED_MEMORY_CONNECT_MAP_ERROR;
434     goto err;
435   }
436 
437   /* Send to server request of connection */
438   if (!SetEvent(event_connect_request))
439   {
440     error_allow = CR_SHARED_MEMORY_CONNECT_SET_ERROR;
441     goto err;
442   }
443 
444   /* Wait of answer from server */
445   if (WaitForSingleObject(event_connect_answer,connect_timeout*1000) !=
446       WAIT_OBJECT_0)
447   {
448     error_allow = CR_SHARED_MEMORY_CONNECT_ABANDONED_ERROR;
449     goto err;
450   }
451 
452   /* Get number of connection */
453   connect_number = uint4korr(handle_connect_map);/*WAX2*/
454   p= int10_to_str(connect_number, connect_number_char, 10);
455 
456   /*
457     The name of event and file-mapping events create agree next rule:
458     shared_memory_base_name+unique_part+number_of_connection
459 
460     Where:
461     shared_memory_base_name is uniquel value for each server
462     unique_part is uniquel value for each object (events and file-mapping)
463     number_of_connection is number of connection between server and client
464   */
465   suffix_pos = strxmov(tmp, prefix , shared_memory_base_name, "_", connect_number_char,
466 		       "_", NullS);
467   strmov(suffix_pos, "DATA");
468   if ((handle_file_map = OpenFileMapping(FILE_MAP_WRITE,FALSE,tmp)) == NULL)
469   {
470     error_allow = CR_SHARED_MEMORY_FILE_MAP_ERROR;
471     goto err2;
472   }
473   if ((handle_map = MapViewOfFile(handle_file_map,FILE_MAP_WRITE,0,0,
474 				  smem_buffer_length)) == NULL)
475   {
476     error_allow = CR_SHARED_MEMORY_MAP_ERROR;
477     goto err2;
478   }
479 
480   strmov(suffix_pos, "SERVER_WROTE");
481   if ((event_server_wrote = OpenEvent(event_access_rights,FALSE,tmp)) == NULL)
482   {
483     error_allow = CR_SHARED_MEMORY_EVENT_ERROR;
484     goto err2;
485   }
486 
487   strmov(suffix_pos, "SERVER_READ");
488   if ((event_server_read = OpenEvent(event_access_rights,FALSE,tmp)) == NULL)
489   {
490     error_allow = CR_SHARED_MEMORY_EVENT_ERROR;
491     goto err2;
492   }
493 
494   strmov(suffix_pos, "CLIENT_WROTE");
495   if ((event_client_wrote = OpenEvent(event_access_rights,FALSE,tmp)) == NULL)
496   {
497     error_allow = CR_SHARED_MEMORY_EVENT_ERROR;
498     goto err2;
499   }
500 
501   strmov(suffix_pos, "CLIENT_READ");
502   if ((event_client_read = OpenEvent(event_access_rights,FALSE,tmp)) == NULL)
503   {
504     error_allow = CR_SHARED_MEMORY_EVENT_ERROR;
505     goto err2;
506   }
507 
508   strmov(suffix_pos, "CONNECTION_CLOSED");
509   if ((event_conn_closed = OpenEvent(event_access_rights,FALSE,tmp)) == NULL)
510   {
511     error_allow = CR_SHARED_MEMORY_EVENT_ERROR;
512     goto err2;
513   }
514   /*
515     Set event that server should send data
516   */
517   SetEvent(event_server_read);
518 
519 err2:
520   if (error_allow == 0)
521   {
522     net->vio= vio_new_win32shared_memory(handle_file_map,handle_map,
523                                          event_server_wrote,
524                                          event_server_read,event_client_wrote,
525                                          event_client_read,event_conn_closed);
526   }
527   else
528   {
529     error_code = GetLastError();
530     if (event_server_read)
531       CloseHandle(event_server_read);
532     if (event_server_wrote)
533       CloseHandle(event_server_wrote);
534     if (event_client_read)
535       CloseHandle(event_client_read);
536     if (event_client_wrote)
537       CloseHandle(event_client_wrote);
538     if (event_conn_closed)
539       CloseHandle(event_conn_closed);
540     if (handle_map)
541       UnmapViewOfFile(handle_map);
542     if (handle_file_map)
543       CloseHandle(handle_file_map);
544   }
545 err:
546   my_free(tmp);
547   if (error_allow)
548     error_code = GetLastError();
549   if (event_connect_request)
550     CloseHandle(event_connect_request);
551   if (event_connect_answer)
552     CloseHandle(event_connect_answer);
553   if (handle_connect_map)
554     UnmapViewOfFile(handle_connect_map);
555   if (handle_connect_file_map)
556     CloseHandle(handle_connect_file_map);
557   if (error_allow)
558   {
559     if (error_allow == CR_SHARED_MEMORY_EVENT_ERROR)
560       set_mysql_extended_error(mysql, error_allow, unknown_sqlstate,
561                                ER(error_allow), suffix_pos, error_code);
562     else
563       set_mysql_extended_error(mysql, error_allow, unknown_sqlstate,
564                                ER(error_allow), error_code);
565     return(INVALID_HANDLE_VALUE);
566   }
567   return(handle_map);
568 }
569 #endif
570 
571 /**
572   Read a packet from server. Give error message if socket was down
573   or packet is an error message
574 
575   @retval  packet_error    An error occurred during reading.
576                            Error message is set.
577   @retval
578 */
579 ulong
cli_safe_read(MYSQL * mysql)580 cli_safe_read(MYSQL *mysql)
581 {
582   ulong reallen = 0;
583   return cli_safe_read_reallen(mysql, &reallen);
584 }
585 
586 ulong
cli_safe_read_reallen(MYSQL * mysql,ulong * reallen)587 cli_safe_read_reallen(MYSQL *mysql, ulong* reallen)
588 {
589   NET *net= &mysql->net;
590   ulong len=0;
591 
592 restart:
593   if (net->vio != 0)
594     len= my_net_read_packet_reallen(net, 0, reallen);
595 
596   if (len == packet_error || len == 0)
597   {
598     DBUG_PRINT("error",("Wrong connection or packet. fd: %s  len: %lu",
599 			net->vio ? vio_description(net->vio) : NULL, len));
600 #ifdef MYSQL_SERVER
601     if (net->vio && (net->last_errno == ER_NET_READ_INTERRUPTED))
602       return (packet_error);
603 #endif /*MYSQL_SERVER*/
604     end_server(mysql);
605     set_mysql_error(mysql, net->last_errno == ER_NET_PACKET_TOO_LARGE ?
606                     CR_NET_PACKET_TOO_LARGE: CR_SERVER_LOST, unknown_sqlstate);
607     return (packet_error);
608   }
609   if (net->read_pos[0] == 255)
610   {
611     if (len > 3)
612     {
613       char *pos= (char*) net->read_pos+1;
614       uint last_errno=uint2korr(pos);
615 
616       if (last_errno == 65535 &&
617           (mysql->server_capabilities & CLIENT_PROGRESS_OBSOLETE))
618       {
619         if (cli_report_progress(mysql, pos+2, (uint) (len-3)))
620         {
621           /* Wrong packet */
622           set_mysql_error(mysql,  CR_MALFORMED_PACKET, unknown_sqlstate);
623           return (packet_error);
624         }
625         goto restart;
626       }
627       net->last_errno= last_errno;
628 
629       pos+=2;
630       len-=2;
631       if (protocol_41(mysql) && pos[0] == '#')
632       {
633 	strmake_buf(net->sqlstate, pos+1);
634 	pos+= SQLSTATE_LENGTH+1;
635       }
636       else
637       {
638         /*
639           The SQL state hasn't been received -- it should be reset to HY000
640           (unknown error sql state).
641         */
642 
643         strmov(net->sqlstate, unknown_sqlstate);
644       }
645 
646       (void) strmake(net->last_error,(char*) pos,
647 		     MY_MIN((uint) len,(uint) sizeof(net->last_error)-1));
648     }
649     else
650       set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate);
651     /*
652       Cover a protocol design error: error packet does not
653       contain the server status. Therefore, the client has no way
654       to find out whether there are more result sets of
655       a multiple-result-set statement pending. Luckily, in 5.0 an
656       error always aborts execution of a statement, wherever it is
657       a multi-statement or a stored procedure, so it should be
658       safe to unconditionally turn off the flag here.
659     */
660     mysql->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
661 
662     DBUG_PRINT("error",("Got error: %d/%s (%s)",
663                         net->last_errno,
664                         net->sqlstate,
665                         net->last_error));
666     return(packet_error);
667   }
668   return len;
669 }
670 
free_rows(MYSQL_DATA * cur)671 void free_rows(MYSQL_DATA *cur)
672 {
673   if (cur)
674   {
675     free_root(&cur->alloc,MYF(0));
676     my_free(cur);
677   }
678 }
679 
680 my_bool
cli_advanced_command(MYSQL * mysql,enum enum_server_command command,const uchar * header,ulong header_length,const uchar * arg,ulong arg_length,my_bool skip_check,MYSQL_STMT * stmt)681 cli_advanced_command(MYSQL *mysql, enum enum_server_command command,
682 		     const uchar *header, ulong header_length,
683 		     const uchar *arg, ulong arg_length, my_bool skip_check,
684                      MYSQL_STMT *stmt)
685 {
686   NET *net= &mysql->net;
687   my_bool result= 1;
688   my_bool stmt_skip= stmt ? stmt->state != MYSQL_STMT_INIT_DONE : FALSE;
689   DBUG_ENTER("cli_advanced_command");
690 
691   if (mysql->net.vio == 0)
692   {						/* Do reconnect if possible */
693     if (mysql_reconnect(mysql) || stmt_skip)
694       DBUG_RETURN(1);
695   }
696   if (mysql->status != MYSQL_STATUS_READY ||
697       mysql->server_status & SERVER_MORE_RESULTS_EXISTS)
698   {
699     DBUG_PRINT("error",("state: %d", mysql->status));
700     set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
701     DBUG_RETURN(1);
702   }
703 
704   net_clear_error(net);
705   mysql->info=0;
706   mysql->affected_rows= ~(my_ulonglong) 0;
707   /*
708     We don't want to clear the protocol buffer on COM_QUIT, because if
709     the previous command was a shutdown command, we may have the
710     response for the COM_QUIT already in the communication buffer
711   */
712   net_clear(&mysql->net, (command != COM_QUIT));
713 
714   if (net_write_command(net,(uchar) command, header, header_length,
715 			arg, arg_length))
716   {
717     DBUG_PRINT("error",("Can't send command to server. Error: %d",
718 			socket_errno));
719     if (net->last_errno == ER_NET_PACKET_TOO_LARGE)
720     {
721       set_mysql_error(mysql, CR_NET_PACKET_TOO_LARGE, unknown_sqlstate);
722       goto end;
723     }
724     if (net->last_errno == ER_NET_ERROR_ON_WRITE && command == COM_BINLOG_DUMP)
725       goto end;
726     end_server(mysql);
727     if (mysql_reconnect(mysql) || stmt_skip)
728       goto end;
729     if (net_write_command(net,(uchar) command, header, header_length,
730 			  arg, arg_length))
731     {
732       set_mysql_error(mysql, CR_SERVER_GONE_ERROR, unknown_sqlstate);
733       goto end;
734     }
735   }
736   result=0;
737   if (!skip_check)
738     result= ((mysql->packet_length=cli_safe_read(mysql)) == packet_error ?
739 	     1 : 0);
740 end:
741   DBUG_PRINT("exit",("result: %d", result));
742   DBUG_RETURN(result);
743 }
744 
free_old_query(MYSQL * mysql)745 void free_old_query(MYSQL *mysql)
746 {
747   DBUG_ENTER("free_old_query");
748   if (mysql->fields)
749     free_root(&mysql->field_alloc,MYF(0));
750  /* Assume rowlength < 8192 */
751   init_alloc_root(&mysql->field_alloc, "fields", 8192, 0,
752                   MYF(mysql->options.use_thread_specific_memory ?
753                       MY_THREAD_SPECIFIC : 0));
754   mysql->fields= 0;
755   mysql->field_count= 0;			/* For API */
756   mysql->warning_count= 0;
757   mysql->info= 0;
758   DBUG_VOID_RETURN;
759 }
760 
761 
762 /**
763   Finish reading of a partial result set from the server.
764   Get the EOF packet, and update mysql->status
765   and mysql->warning_count.
766 
767   @return  TRUE if a communication or protocol error, an error
768            is set in this case, FALSE otherwise.
769 */
770 
flush_one_result(MYSQL * mysql)771 my_bool flush_one_result(MYSQL *mysql)
772 {
773   ulong packet_length;
774 
775   DBUG_ASSERT(mysql->status != MYSQL_STATUS_READY);
776 
777   do
778   {
779     packet_length= cli_safe_read(mysql);
780     /*
781       There is an error reading from the connection,
782       or (sic!) there were no error and no
783       data in the stream, i.e. no more data from the server.
784       Since we know our position in the stream (somewhere in
785       the middle of a result set), this latter case is an error too
786       -- each result set must end with a EOF packet.
787       cli_safe_read() has set an error for us, just return.
788     */
789     if (packet_length == packet_error)
790       return TRUE;
791   }
792   while (packet_length > 8 || mysql->net.read_pos[0] != 254);
793 
794   /* Analyze EOF packet of the result set. */
795 
796   if (protocol_41(mysql))
797   {
798     char *pos= (char*) mysql->net.read_pos + 1;
799     mysql->warning_count=uint2korr(pos);
800     pos+=2;
801     mysql->server_status=uint2korr(pos);
802     pos+=2;
803   }
804   return FALSE;
805 }
806 
807 
808 /**
809   Read a packet from network. If it's an OK packet, flush it.
810 
811   @return  TRUE if error, FALSE otherwise. In case of
812            success, is_ok_packet is set to TRUE or FALSE,
813            based on what we got from network.
814 */
815 
opt_flush_ok_packet(MYSQL * mysql,my_bool * is_ok_packet)816 my_bool opt_flush_ok_packet(MYSQL *mysql, my_bool *is_ok_packet)
817 {
818   ulong packet_length= cli_safe_read(mysql);
819 
820   if (packet_length == packet_error)
821     return TRUE;
822 
823   /* cli_safe_read always reads a non-empty packet. */
824   DBUG_ASSERT(packet_length);
825 
826   *is_ok_packet= mysql->net.read_pos[0] == 0;
827   if (*is_ok_packet)
828   {
829     uchar *pos= mysql->net.read_pos + 1;
830 
831     net_field_length_ll(&pos); /* affected rows */
832     net_field_length_ll(&pos); /* insert id */
833 
834     mysql->server_status=uint2korr(pos);
835     pos+=2;
836 
837     if (protocol_41(mysql))
838     {
839       mysql->warning_count=uint2korr(pos);
840       pos+=2;
841     }
842   }
843   return FALSE;
844 }
845 
846 
847 /*
848   Flush result set sent from server
849 */
850 
cli_flush_use_result(MYSQL * mysql,my_bool flush_all_results)851 static void cli_flush_use_result(MYSQL *mysql, my_bool flush_all_results)
852 {
853   /* Clear the current execution status */
854   DBUG_ENTER("cli_flush_use_result");
855   DBUG_PRINT("warning",("Not all packets read, clearing them"));
856 
857   if (flush_one_result(mysql))
858     DBUG_VOID_RETURN;                           /* An error occurred */
859 
860   if (! flush_all_results)
861     DBUG_VOID_RETURN;
862 
863   while (mysql->server_status & SERVER_MORE_RESULTS_EXISTS)
864   {
865     my_bool is_ok_packet;
866     if (opt_flush_ok_packet(mysql, &is_ok_packet))
867       DBUG_VOID_RETURN;                         /* An error occurred. */
868     if (is_ok_packet)
869     {
870       /*
871         Indeed what we got from network was an OK packet, and we
872         know that OK is the last one in a multi-result-set, so
873         just return.
874       */
875       DBUG_VOID_RETURN;
876     }
877     /*
878       It's a result set, not an OK packet. A result set contains
879       of two result set subsequences: field metadata, terminated
880       with EOF packet, and result set data, again terminated with
881       EOF packet. Read and flush them.
882     */
883     if (flush_one_result(mysql) || flush_one_result(mysql))
884       DBUG_VOID_RETURN;                         /* An error occurred. */
885   }
886 
887   DBUG_VOID_RETURN;
888 }
889 
890 
891 /*
892   Report progress to the client
893 
894   RETURN VALUES
895     0  ok
896     1  error
897 */
898 
cli_report_progress(MYSQL * mysql,char * pkt,uint length)899 static int cli_report_progress(MYSQL *mysql, char *pkt, uint length)
900 {
901   uint stage, max_stage, proc_length;
902   double progress;
903   uchar *packet= (uchar*)pkt;
904   uchar *start= packet;
905 
906   if (length < 5)
907     return 1;                         /* Wrong packet */
908 
909   if (!(mysql->options.extension && mysql->options.extension->report_progress))
910     return 0;                         /* No callback, ignore packet */
911 
912   packet++;                           /* Ignore number of strings */
913   stage= (uint) *packet++;
914   max_stage= (uint) *packet++;
915   progress= uint3korr(packet)/1000.0;
916   packet+= 3;
917   proc_length= net_field_length(&packet);
918   if (packet + proc_length > start + length)
919     return 1;                         /* Wrong packet */
920   (*mysql->options.extension->report_progress)(mysql, stage, max_stage,
921                                                progress, (char*) packet,
922                                                proc_length);
923   return 0;
924 }
925 
926 
927 /**************************************************************************
928   Shut down connection
929 **************************************************************************/
930 
end_server(MYSQL * mysql)931 void end_server(MYSQL *mysql)
932 {
933   int save_errno= errno;
934   DBUG_ENTER("end_server");
935   if (mysql->net.vio != 0)
936   {
937     DBUG_PRINT("info",("Net: %s", vio_description(mysql->net.vio)));
938 #ifdef MYSQL_SERVER
939     slave_io_thread_detach_vio();
940 #endif
941     vio_delete(mysql->net.vio);
942     mysql->net.vio= 0;          /* Marker */
943     mysql_prune_stmt_list(mysql);
944   }
945   net_end(&mysql->net);
946   free_old_query(mysql);
947   errno= save_errno;
948   DBUG_VOID_RETURN;
949 }
950 
951 
952 void STDCALL
mysql_free_result(MYSQL_RES * result)953 mysql_free_result(MYSQL_RES *result)
954 {
955   DBUG_ENTER("mysql_free_result");
956   DBUG_PRINT("enter",("mysql_res: %p", result));
957   if (result)
958   {
959     MYSQL *mysql= result->handle;
960     if (mysql)
961     {
962       if (mysql->unbuffered_fetch_owner == &result->unbuffered_fetch_cancelled)
963         mysql->unbuffered_fetch_owner= 0;
964       if (mysql->status == MYSQL_STATUS_USE_RESULT)
965       {
966         (*mysql->methods->flush_use_result)(mysql, FALSE);
967         mysql->status=MYSQL_STATUS_READY;
968         if (mysql->unbuffered_fetch_owner)
969           *mysql->unbuffered_fetch_owner= TRUE;
970       }
971     }
972     free_rows(result->data);
973     if (result->fields)
974       free_root(&result->field_alloc,MYF(0));
975     my_free(result->row);
976     my_free(result);
977   }
978   DBUG_VOID_RETURN;
979 }
980 
981 /****************************************************************************
982   Get options from my.cnf
983 ****************************************************************************/
984 
985 static const char *default_options[]=
986 {
987   "port","socket","compress","password","pipe", "timeout", "user",
988   "init-command", "host", "database", "debug", "return-found-rows",
989   "ssl-key" ,"ssl-cert" ,"ssl-ca" ,"ssl-capath",
990   "character-sets-dir", "default-character-set", "interactive-timeout",
991   "connect-timeout", "local-infile", "disable-local-infile",
992   "ssl-cipher", "max-allowed-packet", "protocol", "shared-memory-base-name",
993   "multi-results", "multi-statements", "multi-queries", "secure-auth",
994   "report-data-truncation", "plugin-dir", "default-auth",
995   "bind-address", "ssl-crl", "ssl-crlpath",
996   "enable-cleartext-plugin",
997   NullS
998 };
999 enum option_id {
1000   OPT_port=1, OPT_socket, OPT_compress, OPT_password, OPT_pipe, OPT_timeout, OPT_user,
1001   OPT_init_command, OPT_host, OPT_database, OPT_debug, OPT_return_found_rows,
1002   OPT_ssl_key, OPT_ssl_cert, OPT_ssl_ca, OPT_ssl_capath,
1003   OPT_character_sets_dir, OPT_default_character_set, OPT_interactive_timeout,
1004   OPT_connect_timeout, OPT_local_infile, OPT_disable_local_infile,
1005   OPT_ssl_cipher, OPT_max_allowed_packet, OPT_protocol, OPT_shared_memory_base_name,
1006   OPT_multi_results, OPT_multi_statements, OPT_multi_queries, OPT_secure_auth,
1007   OPT_report_data_truncation, OPT_plugin_dir, OPT_default_auth,
1008   OPT_bind_address, OPT_ssl_crl, OPT_ssl_crlpath,
1009   OPT_enable_cleartext_plugin,
1010   OPT_keep_this_one_last
1011 };
1012 
1013 static TYPELIB option_types={array_elements(default_options)-1,
1014 			     "options",default_options, NULL};
1015 
add_init_command(struct st_mysql_options * options,const char * cmd)1016 static int add_init_command(struct st_mysql_options *options, const char *cmd)
1017 {
1018   char *tmp;
1019 
1020   if (!options->init_commands)
1021   {
1022     options->init_commands= (DYNAMIC_ARRAY*)my_malloc(sizeof(DYNAMIC_ARRAY),
1023 						      MYF(MY_WME));
1024     my_init_dynamic_array(options->init_commands,sizeof(char*),5, 5, MYF(0));
1025   }
1026 
1027   if (!(tmp= my_strdup(cmd,MYF(MY_WME))) ||
1028       insert_dynamic(options->init_commands, &tmp))
1029   {
1030     my_free(tmp);
1031     return 1;
1032   }
1033 
1034   return 0;
1035 }
1036 
1037 
1038 #define ALLOCATE_EXTENSIONS(OPTS)                                \
1039       (OPTS)->extension= (struct st_mysql_options_extention *)   \
1040         my_malloc(sizeof(struct st_mysql_options_extention),     \
1041                   MYF(MY_WME | MY_ZEROFILL))                     \
1042 
1043 
1044 #define ENSURE_EXTENSIONS_PRESENT(OPTS)                          \
1045     do {                                                         \
1046       if (!(OPTS)->extension)                                    \
1047         ALLOCATE_EXTENSIONS(OPTS);                               \
1048     } while (0)
1049 
1050 
1051 #define EXTENSION_SET_STRING_X(OPTS, X, STR, dup)                \
1052     do {                                                         \
1053       if ((OPTS)->extension)                                     \
1054         my_free((OPTS)->extension->X);                           \
1055       else                                                       \
1056         ALLOCATE_EXTENSIONS(OPTS);                               \
1057       (OPTS)->extension->X= ((STR) != NULL) ?                    \
1058         dup((STR), MYF(MY_WME)) : NULL;                          \
1059     } while (0)
1060 
1061 #define EXTENSION_SET_STRING(OPTS, X, STR)      \
1062   EXTENSION_SET_STRING_X(OPTS, X, STR, my_strdup)
1063 
1064 
1065 #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
1066 #define SET_SSL_OPTION_X(OPTS, opt_var, arg, dup)                \
1067   my_free((OPTS)->opt_var);                                      \
1068   (OPTS)->opt_var= arg ? dup(arg, MYF(MY_WME)) : NULL;
1069 #define EXTENSION_SET_SSL_STRING_X(OPTS, X, STR, dup)            \
1070   EXTENSION_SET_STRING_X((OPTS), X, (STR), dup);
1071 
set_ssl_option_unpack_path(const char * arg,myf flags)1072 static char *set_ssl_option_unpack_path(const char *arg, myf flags)
1073 {
1074   char buff[FN_REFLEN + 1];
1075   unpack_filename(buff, (char *)arg);
1076   return my_strdup(buff, flags);
1077 }
1078 
1079 #else
1080 #define SET_SSL_OPTION_X(OPTS, opt_var,arg, dup) do { } while(0)
1081 #define EXTENSION_SET_SSL_STRING_X(OPTS, X, STR, dup) do { } while(0)
1082 #endif /* defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) */
1083 
1084 #define SET_SSL_OPTION(OPTS, opt_var,arg) SET_SSL_OPTION_X(OPTS, opt_var, arg, my_strdup)
1085 #define EXTENSION_SET_SSL_STRING(OPTS, X, STR) EXTENSION_SET_SSL_STRING_X(OPTS, X, STR, my_strdup)
1086 #define SET_SSL_PATH_OPTION(OPTS, opt_var,arg) SET_SSL_OPTION_X(OPTS, opt_var, arg, set_ssl_option_unpack_path)
1087 #define EXTENSION_SET_SSL_PATH_STRING(OPTS, X, STR) EXTENSION_SET_SSL_STRING_X(OPTS, X, STR, set_ssl_option_unpack_path)
1088 
mysql_read_default_options(struct st_mysql_options * options,const char * filename,const char * group)1089 void mysql_read_default_options(struct st_mysql_options *options,
1090 				const char *filename,const char *group)
1091 {
1092   int argc;
1093   char *argv_buff[1],**argv;
1094   const char *groups[5];
1095   DBUG_ENTER("mysql_read_default_options");
1096   DBUG_PRINT("enter",("file: %s  group: %s",filename,group ? group :"NULL"));
1097 
1098   compile_time_assert(OPT_keep_this_one_last ==
1099                       array_elements(default_options));
1100 
1101   argc=1; argv=argv_buff; argv_buff[0]= (char*) "client";
1102   groups[0]= (char*) "client";
1103   groups[1]= (char*) "client-server";
1104   groups[2]= (char*) "client-mariadb";
1105   groups[3]= (char*) group;
1106   groups[4]=0;
1107 
1108   my_load_defaults(filename, groups, &argc, &argv, NULL);
1109   if (argc != 1)				/* If some default option */
1110   {
1111     char **option=argv;
1112     while (*++option)
1113     {
1114       if (my_getopt_is_args_separator(option[0]))          /* skip arguments separator */
1115         continue;
1116       /* DBUG_PRINT("info",("option: %s",option[0])); */
1117       if (option[0][0] == '-' && option[0][1] == '-')
1118       {
1119 	char *end=strcend(*option,'=');
1120 	char *opt_arg=0;
1121 	if (*end)
1122 	{
1123 	  opt_arg=end+1;
1124 	  *end=0;				/* Remove '=' */
1125 	}
1126 	/* Change all '_' in variable name to '-' */
1127 	for (end= *option ; *(end= strcend(end,'_')) ; )
1128 	  *end= '-';
1129 	switch (find_type(*option + 2, &option_types, FIND_TYPE_BASIC)) {
1130 	case OPT_port:
1131 	  if (opt_arg)
1132 	    options->port=atoi(opt_arg);
1133 	  break;
1134 	case OPT_socket:
1135 	  if (opt_arg)
1136 	  {
1137 	    my_free(options->unix_socket);
1138 	    options->unix_socket=my_strdup(opt_arg,MYF(MY_WME));
1139 	  }
1140 	  break;
1141 	case OPT_compress:
1142 	  options->compress=1;
1143 	  options->client_flag|= CLIENT_COMPRESS;
1144 	  break;
1145         case OPT_password:
1146 	  if (opt_arg)
1147 	  {
1148 	    my_free(options->password);
1149 	    options->password=my_strdup(opt_arg,MYF(MY_WME));
1150 	  }
1151 	  break;
1152         case OPT_pipe:
1153           options->protocol = MYSQL_PROTOCOL_PIPE;
1154           break;
1155         case OPT_connect_timeout:
1156 	case OPT_timeout:
1157 	  if (opt_arg)
1158 	    options->connect_timeout=atoi(opt_arg);
1159 	  break;
1160 	case OPT_user:
1161 	  if (opt_arg)
1162 	  {
1163 	    my_free(options->user);
1164 	    options->user=my_strdup(opt_arg,MYF(MY_WME));
1165 	  }
1166 	  break;
1167 	case OPT_init_command:
1168 	  add_init_command(options,opt_arg);
1169 	  break;
1170 	case OPT_host:
1171 	  if (opt_arg)
1172 	  {
1173 	    my_free(options->host);
1174 	    options->host=my_strdup(opt_arg,MYF(MY_WME));
1175 	  }
1176 	  break;
1177         case OPT_database:
1178 	  if (opt_arg)
1179 	  {
1180 	    my_free(options->db);
1181 	    options->db=my_strdup(opt_arg,MYF(MY_WME));
1182 	  }
1183 	  break;
1184 	case OPT_debug:
1185 #ifdef MYSQL_CLIENT
1186 	  mysql_debug(opt_arg ? opt_arg : "d:t:o,/tmp/client.trace");
1187 	  break;
1188 #endif
1189 	case OPT_return_found_rows:
1190 	  options->client_flag|=CLIENT_FOUND_ROWS;
1191 	  break;
1192 	case OPT_ssl_key:
1193           SET_SSL_OPTION(options, ssl_key, opt_arg);
1194           break;
1195 	case OPT_ssl_cert:
1196           SET_SSL_OPTION(options, ssl_cert, opt_arg);
1197           break;
1198 	case OPT_ssl_ca:
1199           SET_SSL_OPTION(options, ssl_ca, opt_arg);
1200           break;
1201 	case OPT_ssl_capath:
1202           SET_SSL_OPTION(options, ssl_capath, opt_arg);
1203           break;
1204         case OPT_ssl_cipher:
1205           SET_SSL_OPTION(options, ssl_cipher, opt_arg);
1206           break;
1207 	case OPT_ssl_crl:
1208           EXTENSION_SET_SSL_STRING(options, ssl_crl, opt_arg);
1209           break;
1210 	case OPT_ssl_crlpath:
1211           EXTENSION_SET_SSL_STRING(options, ssl_crlpath, opt_arg);
1212           break;
1213 	case OPT_character_sets_dir:
1214 	  my_free(options->charset_dir);
1215           options->charset_dir = my_strdup(opt_arg, MYF(MY_WME));
1216 	  break;
1217 	case OPT_default_character_set:
1218 	  my_free(options->charset_name);
1219           options->charset_name = my_strdup(opt_arg, MYF(MY_WME));
1220 	  break;
1221         case OPT_interactive_timeout:
1222 	  options->client_flag|= CLIENT_INTERACTIVE;
1223 	  break;
1224         case OPT_local_infile:
1225 	  if (!opt_arg || atoi(opt_arg) != 0)
1226 	    options->client_flag|= CLIENT_LOCAL_FILES;
1227 	  else
1228 	    options->client_flag&= ~CLIENT_LOCAL_FILES;
1229 	  break;
1230         case OPT_disable_local_infile:
1231 	  options->client_flag&= ~CLIENT_LOCAL_FILES;
1232           break;
1233 	case OPT_max_allowed_packet:
1234           if (opt_arg)
1235 	    options->max_allowed_packet= atoi(opt_arg);
1236 	  break;
1237         case OPT_protocol:
1238           if (options->protocol != UINT_MAX32 &&
1239               (options->protocol= find_type(opt_arg, &sql_protocol_typelib,
1240                                             FIND_TYPE_BASIC)) <= 0)
1241           {
1242             fprintf(stderr, "Unknown option to protocol: %s\n", opt_arg);
1243             options->protocol= UINT_MAX32;
1244           }
1245           break;
1246         case OPT_shared_memory_base_name:
1247 #ifdef HAVE_SMEM
1248           if (options->shared_memory_base_name != def_shared_memory_base_name)
1249             my_free(options->shared_memory_base_name);
1250           options->shared_memory_base_name=my_strdup(opt_arg,MYF(MY_WME));
1251 #endif
1252           break;
1253         case OPT_multi_results:
1254 	  options->client_flag|= CLIENT_MULTI_RESULTS;
1255 	  break;
1256         case OPT_multi_statements:
1257         case OPT_multi_queries:
1258 	  options->client_flag|= CLIENT_MULTI_STATEMENTS | CLIENT_MULTI_RESULTS;
1259 	  break;
1260         case OPT_secure_auth:
1261           options->secure_auth= TRUE;
1262           break;
1263         case OPT_report_data_truncation:
1264           options->report_data_truncation= opt_arg ? MY_TEST(atoi(opt_arg)) : 1;
1265           break;
1266         case OPT_plugin_dir:
1267           {
1268             char buff[FN_REFLEN], buff2[FN_REFLEN], *buff2_ptr= buff2;
1269             if (strlen(opt_arg) >= FN_REFLEN)
1270               opt_arg[FN_REFLEN]= '\0';
1271             if (my_realpath(buff, opt_arg, 0))
1272             {
1273               DBUG_PRINT("warning",("failed to normalize the plugin path: %s",
1274                                     opt_arg));
1275               break;
1276             }
1277             convert_dirname(buff2, buff, NULL);
1278             EXTENSION_SET_STRING(options, plugin_dir, buff2_ptr);
1279           }
1280           break;
1281         case OPT_default_auth:
1282           EXTENSION_SET_STRING(options, default_auth, opt_arg);
1283           break;
1284         case OPT_enable_cleartext_plugin:
1285           break;
1286 	default:
1287 	  DBUG_PRINT("warning",("unknown option: %s",option[0]));
1288 	}
1289       }
1290     }
1291   }
1292   free_defaults(argv);
1293   DBUG_VOID_RETURN;
1294 }
1295 
1296 
1297 /**************************************************************************
1298   Get column lengths of the current row
1299   If one uses mysql_use_result, res->lengths contains the length information,
1300   else the lengths are calculated from the offset between pointers.
1301 **************************************************************************/
1302 
cli_fetch_lengths(ulong * to,MYSQL_ROW column,unsigned int field_count)1303 static void cli_fetch_lengths(ulong *to, MYSQL_ROW column,
1304 			      unsigned int field_count)
1305 {
1306   ulong *prev_length;
1307   char *start=0;
1308   MYSQL_ROW end;
1309 
1310   prev_length=0;				/* Keep gcc happy */
1311   for (end=column + field_count + 1 ; column != end ; column++, to++)
1312   {
1313     if (!*column)
1314     {
1315       *to= 0;					/* Null */
1316       continue;
1317     }
1318     if (start)					/* Found end of prev string */
1319       *prev_length= (ulong) (*column-start-1);
1320     start= *column;
1321     prev_length= to;
1322   }
1323 }
1324 
1325 /***************************************************************************
1326   Change field rows to field structs
1327 ***************************************************************************/
1328 
1329 MYSQL_FIELD *
unpack_fields(MYSQL * mysql,MYSQL_DATA * data,MEM_ROOT * alloc,uint fields,my_bool default_value,uint server_capabilities)1330 unpack_fields(MYSQL *mysql, MYSQL_DATA *data,MEM_ROOT *alloc,uint fields,
1331 	      my_bool default_value, uint server_capabilities)
1332 {
1333   MYSQL_ROWS	*row;
1334   MYSQL_FIELD	*field,*result;
1335   ulong lengths[9];				/* Max of fields */
1336   DBUG_ENTER("unpack_fields");
1337 
1338   field= result= (MYSQL_FIELD*) alloc_root(alloc,
1339 					   (uint) sizeof(*field)*fields);
1340   if (!result)
1341   {
1342     free_rows(data);				/* Free old data */
1343     set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
1344     DBUG_RETURN(0);
1345   }
1346   bzero((char*) field, (uint) sizeof(MYSQL_FIELD)*fields);
1347   if (server_capabilities & CLIENT_PROTOCOL_41)
1348   {
1349     /* server is 4.1, and returns the new field result format */
1350     for (row=data->data; row ; row = row->next,field++)
1351     {
1352       uchar *pos;
1353       /* fields count may be wrong */
1354       if (field >= result + fields)
1355         goto err;
1356 
1357       cli_fetch_lengths(&lengths[0], row->data, default_value ? 8 : 7);
1358       field->catalog=   strmake_root(alloc,(char*) row->data[0], lengths[0]);
1359       field->db=        strmake_root(alloc,(char*) row->data[1], lengths[1]);
1360       field->table=     strmake_root(alloc,(char*) row->data[2], lengths[2]);
1361       field->org_table= strmake_root(alloc,(char*) row->data[3], lengths[3]);
1362       field->name=      strmake_root(alloc,(char*) row->data[4], lengths[4]);
1363       field->org_name=  strmake_root(alloc,(char*) row->data[5], lengths[5]);
1364 
1365       field->catalog_length=	lengths[0];
1366       field->db_length=		lengths[1];
1367       field->table_length=	lengths[2];
1368       field->org_table_length=	lengths[3];
1369       field->name_length=	lengths[4];
1370       field->org_name_length=	lengths[5];
1371 
1372       /* Unpack fixed length parts */
1373       if (lengths[6] != 12)
1374         goto err;
1375 
1376       pos= (uchar*) row->data[6];
1377       field->charsetnr= uint2korr(pos);
1378       field->length=	(uint) uint4korr(pos+2);
1379       field->type=	(enum enum_field_types) pos[6];
1380       field->flags=	uint2korr(pos+7);
1381       field->decimals=  (uint) pos[9];
1382 
1383       if (IS_NUM(field->type))
1384         field->flags|= NUM_FLAG;
1385       if (default_value && row->data[7])
1386       {
1387         field->def=strmake_root(alloc,(char*) row->data[7], lengths[7]);
1388 	field->def_length= lengths[7];
1389       }
1390       else
1391         field->def=0;
1392       field->max_length= 0;
1393     }
1394   }
1395 #ifndef DELETE_SUPPORT_OF_4_0_PROTOCOL
1396   else
1397   {
1398     /* old protocol, for backward compatibility */
1399     for (row=data->data; row ; row = row->next,field++)
1400     {
1401       if (field >= result + fields)
1402         goto err;
1403 
1404       /*
1405        If any of the row->data[] below is NULL, it can result in a
1406        crash. Error out early as it indicates a malformed packet.
1407        For data[0], data[1] and data[5], strmake_root will handle
1408        NULL values.
1409       */
1410       if (!row->data[2] || !row->data[3] || !row->data[4])
1411       {
1412         free_rows(data);
1413         set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
1414         DBUG_RETURN(0);
1415       }
1416 
1417       cli_fetch_lengths(&lengths[0], row->data, default_value ? 6 : 5);
1418       field->org_table= field->table=  strmake_root(alloc,(char*) row->data[0], lengths[0]);
1419       field->name=   strmake_root(alloc,(char*) row->data[1], lengths[1]);
1420       field->length= (uint) uint3korr(row->data[2]);
1421       field->type=   (enum enum_field_types) (uchar) row->data[3][0];
1422 
1423       field->catalog=(char*)  "";
1424       field->db=     (char*)  "";
1425       field->catalog_length= 0;
1426       field->db_length= 0;
1427       field->org_table_length=	field->table_length=	lengths[0];
1428       field->name_length=	lengths[1];
1429 
1430       if (server_capabilities & CLIENT_LONG_FLAG)
1431       {
1432         field->flags=   uint2korr(row->data[4]);
1433         field->decimals=(uint) (uchar) row->data[4][2];
1434       }
1435       else
1436       {
1437         field->flags=   (uint) (uchar) row->data[4][0];
1438         field->decimals=(uint) (uchar) row->data[4][1];
1439       }
1440       if (IS_NUM(field->type))
1441         field->flags|= NUM_FLAG;
1442       if (default_value && row->data[5])
1443       {
1444         field->def= strmake_root(alloc,(char*) row->data[5], lengths[5]);
1445 	field->def_length= lengths[5];
1446       }
1447       else
1448         field->def=0;
1449       field->max_length= 0;
1450     }
1451   }
1452 #endif /* DELETE_SUPPORT_OF_4_0_PROTOCOL */
1453   if (field < result + fields)
1454     goto err;
1455   free_rows(data);				/* Free old data */
1456   DBUG_RETURN(result);
1457 
1458 err:
1459   /* malformed packet. signal an error. */
1460   free_rows(data);
1461   free_root(alloc, MYF(0));
1462   set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
1463   DBUG_RETURN(0);
1464 }
1465 
1466 /* Read all rows (fields or data) from server */
1467 
cli_read_rows(MYSQL * mysql,MYSQL_FIELD * mysql_fields,unsigned int fields)1468 MYSQL_DATA *cli_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
1469 			  unsigned int fields)
1470 {
1471   uint	field;
1472   ulong pkt_len;
1473   ulong len;
1474   uchar *cp;
1475   char	*to, *end_to;
1476   MYSQL_DATA *result;
1477   MYSQL_ROWS **prev_ptr,*cur;
1478   NET *net = &mysql->net;
1479   DBUG_ENTER("cli_read_rows");
1480 
1481   if ((pkt_len= cli_safe_read(mysql)) == packet_error)
1482     DBUG_RETURN(0);
1483   if (pkt_len == 0) DBUG_RETURN(0);
1484   if (!(result=(MYSQL_DATA*) my_malloc(sizeof(MYSQL_DATA),
1485 				       MYF(MY_WME | MY_ZEROFILL))))
1486   {
1487     set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
1488     DBUG_RETURN(0);
1489   }
1490   /* Assume rowlength < 8192 */
1491   init_alloc_root(&result->alloc, "result", 8192, 0,
1492                   MYF(mysql->options.use_thread_specific_memory ?
1493                       MY_THREAD_SPECIFIC : 0));
1494   result->alloc.min_malloc=sizeof(MYSQL_ROWS);
1495   prev_ptr= &result->data;
1496   result->rows=0;
1497   result->fields=fields;
1498 
1499   /*
1500     The last EOF packet is either a single 254 character or (in MySQL 4.1)
1501     254 followed by 1-7 status bytes.
1502 
1503     This doesn't conflict with normal usage of 254 which stands for a
1504     string where the length of the string is 8 bytes. (see net_field_length())
1505   */
1506 
1507   while (*(cp=net->read_pos) != 254 || pkt_len >= 8)
1508   {
1509     result->rows++;
1510     if (!(cur= (MYSQL_ROWS*) alloc_root(&result->alloc,
1511 					sizeof(MYSQL_ROWS))) ||
1512 	!(cur->data= ((MYSQL_ROW)
1513 		      alloc_root(&result->alloc,
1514 				 (fields+1)*sizeof(char *)+pkt_len))))
1515     {
1516       free_rows(result);
1517       set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
1518       DBUG_RETURN(0);
1519     }
1520     *prev_ptr=cur;
1521     prev_ptr= &cur->next;
1522     to= (char*) (cur->data+fields+1);
1523     end_to=to+pkt_len-1;
1524     for (field=0 ; field < fields ; field++)
1525     {
1526       if ((len=(ulong) net_field_length(&cp)) == NULL_LENGTH)
1527       {						/* null field */
1528 	cur->data[field] = 0;
1529       }
1530       else
1531       {
1532 	cur->data[field] = to;
1533         if (unlikely(len > (ulong)(end_to-to) || to > end_to))
1534         {
1535           free_rows(result);
1536           set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
1537           DBUG_RETURN(0);
1538         }
1539 	memcpy(to,(char*) cp,len); to[len]=0;
1540 	to+=len+1;
1541 	cp+=len;
1542 	if (mysql_fields)
1543 	{
1544 	  if (mysql_fields[field].max_length < len)
1545 	    mysql_fields[field].max_length=len;
1546 	}
1547       }
1548     }
1549     cur->data[field]=to;			/* End of last field */
1550     if ((pkt_len=cli_safe_read(mysql)) == packet_error)
1551     {
1552       free_rows(result);
1553       DBUG_RETURN(0);
1554     }
1555   }
1556   *prev_ptr=0;					/* last pointer is null */
1557   if (pkt_len > 1)				/* MySQL 4.1 protocol */
1558   {
1559     mysql->warning_count= uint2korr(cp+1);
1560     mysql->server_status= uint2korr(cp+3);
1561     DBUG_PRINT("info",("status: %u  warning_count:  %u",
1562 		       mysql->server_status, mysql->warning_count));
1563   }
1564   DBUG_PRINT("exit", ("Got %lu rows", (ulong) result->rows));
1565   DBUG_RETURN(result);
1566 }
1567 
1568 /*
1569   Read one row. Uses packet buffer as storage for fields.
1570   When next packet is read, the previous field values are destroyed
1571 */
1572 
1573 
1574 static int
read_one_row(MYSQL * mysql,uint fields,MYSQL_ROW row,ulong * lengths)1575 read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, ulong *lengths)
1576 {
1577   uint field;
1578   ulong pkt_len,len;
1579   uchar *pos, *prev_pos, *end_pos;
1580   NET *net= &mysql->net;
1581 
1582   if ((pkt_len=cli_safe_read(mysql)) == packet_error)
1583     return -1;
1584   if (pkt_len <= 8 && net->read_pos[0] == 254)
1585   {
1586     if (pkt_len > 1)				/* MySQL 4.1 protocol */
1587     {
1588       mysql->warning_count= uint2korr(net->read_pos+1);
1589       mysql->server_status= uint2korr(net->read_pos+3);
1590     }
1591     return 1;				/* End of data */
1592   }
1593   prev_pos= 0;				/* allowed to write at packet[-1] */
1594   pos=net->read_pos;
1595   end_pos=pos+pkt_len;
1596   for (field=0 ; field < fields ; field++)
1597   {
1598     if ((len=(ulong) net_field_length(&pos)) == NULL_LENGTH)
1599     {						/* null field */
1600       row[field] = 0;
1601       *lengths++=0;
1602     }
1603     else
1604     {
1605       if (unlikely(len > (ulong)(end_pos - pos) || pos > end_pos))
1606       {
1607         set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate);
1608         return -1;
1609       }
1610       row[field] = (char*) pos;
1611       pos+=len;
1612       *lengths++=len;
1613     }
1614     if (prev_pos)
1615       *prev_pos=0;				/* Terminate prev field */
1616     prev_pos=pos;
1617   }
1618   row[field]=(char*) prev_pos+1;		/* End of last field */
1619   *prev_pos=0;					/* Terminate last field */
1620   return 0;
1621 }
1622 
1623 
1624 /****************************************************************************
1625   Init MySQL structure or allocate one
1626 ****************************************************************************/
1627 
1628 MYSQL * STDCALL
mysql_init(MYSQL * mysql)1629 mysql_init(MYSQL *mysql)
1630 {
1631   if (mysql_server_init(0, NULL, NULL))
1632     return 0;
1633   if (!mysql)
1634   {
1635     if (!(mysql=(MYSQL*) my_malloc(sizeof(*mysql),MYF(MY_WME | MY_ZEROFILL))))
1636     {
1637       set_mysql_error(NULL, CR_OUT_OF_MEMORY, unknown_sqlstate);
1638       return 0;
1639     }
1640     mysql->free_me=1;
1641   }
1642   else
1643     bzero((char*) (mysql), sizeof(*(mysql)));
1644   mysql->options.connect_timeout= CONNECT_TIMEOUT;
1645   mysql->charset=default_client_charset_info;
1646   strmov(mysql->net.sqlstate, not_error_sqlstate);
1647 
1648   /*
1649     Only enable LOAD DATA INFILE by default if configured with
1650     --enable-local-infile
1651   */
1652 
1653 #if ENABLED_LOCAL_INFILE && !defined(MYSQL_SERVER)
1654   mysql->options.client_flag|= CLIENT_LOCAL_FILES;
1655   mysql->auto_local_infile= ENABLED_LOCAL_INFILE == LOCAL_INFILE_MODE_AUTO
1656                             ? WAIT_FOR_QUERY : ALWAYS_ACCEPT;
1657 #endif
1658 
1659 #ifdef HAVE_SMEM
1660   mysql->options.shared_memory_base_name= (char*) def_shared_memory_base_name;
1661 #endif
1662 
1663   mysql->options.methods_to_use= MYSQL_OPT_GUESS_CONNECTION;
1664   mysql->options.report_data_truncation= TRUE;  /* default */
1665 
1666   /*
1667     By default we don't reconnect because it could silently corrupt data (after
1668     reconnection you potentially lose table locks, user variables, session
1669     variables (transactions but they are specifically dealt with in
1670     mysql_reconnect()).
1671     This is a change: < 5.0.3 mysql->reconnect was set to 1 by default.
1672     How this change impacts existing apps:
1673     - existing apps which relyed on the default will see a behaviour change;
1674     they will have to set reconnect=1 after mysql_real_connect().
1675     - existing apps which explicitly asked for reconnection (the only way they
1676     could do it was by setting mysql.reconnect to 1 after mysql_real_connect())
1677     will not see a behaviour change.
1678     - existing apps which explicitly asked for no reconnection
1679     (mysql.reconnect=0) will not see a behaviour change.
1680   */
1681   mysql->reconnect= 0;
1682 
1683   DBUG_PRINT("mysql",("mysql: %p", mysql));
1684   return mysql;
1685 }
1686 
1687 
1688 /*
1689   Fill in SSL part of MYSQL structure.
1690   NB! Errors are not reported until you do mysql_real_connect.
1691   use_ssl is set in send_client_reply_packet if any ssl option is set.
1692 */
1693 
1694 my_bool STDCALL
mysql_ssl_set(MYSQL * mysql,const char * key,const char * cert,const char * ca,const char * capath,const char * cipher)1695 mysql_ssl_set(MYSQL *mysql __attribute__((unused)) ,
1696 	      const char *key __attribute__((unused)),
1697 	      const char *cert __attribute__((unused)),
1698 	      const char *ca __attribute__((unused)),
1699 	      const char *capath __attribute__((unused)),
1700 	      const char *cipher __attribute__((unused)))
1701 {
1702   my_bool result= 0;
1703   DBUG_ENTER("mysql_ssl_set");
1704 #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
1705   result= (mysql_options(mysql, MYSQL_OPT_SSL_KEY, key) |
1706            mysql_options(mysql, MYSQL_OPT_SSL_CERT,   cert) |
1707            mysql_options(mysql, MYSQL_OPT_SSL_CA,     ca) |
1708            mysql_options(mysql, MYSQL_OPT_SSL_CAPATH, capath) |
1709            mysql_options(mysql, MYSQL_OPT_SSL_CIPHER, cipher) ?
1710            1 : 0);
1711 #endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */
1712   mysql->options.use_ssl= TRUE;
1713   DBUG_RETURN(result);
1714 }
1715 
1716 
1717 /*
1718   Free strings in the SSL structure and clear 'use_ssl' flag.
1719   NB! Errors are not reported until you do mysql_real_connect.
1720 */
1721 
1722 #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
1723 
1724 static void
mysql_ssl_free(MYSQL * mysql)1725 mysql_ssl_free(MYSQL *mysql __attribute__((unused)))
1726 {
1727   struct st_VioSSLFd *ssl_fd= (struct st_VioSSLFd*) mysql->connector_fd;
1728   DBUG_ENTER("mysql_ssl_free");
1729 
1730   my_free(mysql->options.ssl_key);
1731   my_free(mysql->options.ssl_cert);
1732   my_free(mysql->options.ssl_ca);
1733   my_free(mysql->options.ssl_capath);
1734   my_free(mysql->options.ssl_cipher);
1735   if (mysql->options.extension)
1736   {
1737     my_free(mysql->options.extension->ssl_crl);
1738     my_free(mysql->options.extension->ssl_crlpath);
1739   }
1740   if (ssl_fd)
1741     SSL_CTX_free(ssl_fd->ssl_context);
1742   my_free(mysql->connector_fd);
1743   mysql->options.ssl_key = 0;
1744   mysql->options.ssl_cert = 0;
1745   mysql->options.ssl_ca = 0;
1746   mysql->options.ssl_capath = 0;
1747   mysql->options.ssl_cipher= 0;
1748   if (mysql->options.extension)
1749   {
1750     mysql->options.extension->ssl_crl = 0;
1751     mysql->options.extension->ssl_crlpath = 0;
1752   }
1753   mysql->options.use_ssl = FALSE;
1754   mysql->connector_fd = 0;
1755   DBUG_VOID_RETURN;
1756 }
1757 
1758 #endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */
1759 
1760 /*
1761   Return the SSL cipher (if any) used for current
1762   connection to the server.
1763 
1764   SYNOPSYS
1765     mysql_get_ssl_cipher()
1766       mysql pointer to the mysql connection
1767 
1768 */
1769 
1770 const char * STDCALL
mysql_get_ssl_cipher(MYSQL * mysql)1771 mysql_get_ssl_cipher(MYSQL *mysql __attribute__((unused)))
1772 {
1773   DBUG_ENTER("mysql_get_ssl_cipher");
1774 #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
1775   if (mysql->net.vio && mysql->net.vio->ssl_arg)
1776     DBUG_RETURN(SSL_get_cipher_name((SSL*)mysql->net.vio->ssl_arg));
1777 #endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */
1778   DBUG_RETURN(NULL);
1779 }
1780 
1781 
1782 /*
1783   Check the server's (subject) Common Name against the
1784   hostname we connected to
1785 
1786   SYNOPSIS
1787   ssl_verify_server_cert()
1788     vio              pointer to a SSL connected vio
1789     server_hostname  name of the server that we connected to
1790     errptr           if we fail, we'll return (a pointer to a string
1791                      describing) the reason here
1792 
1793   RETURN VALUES
1794    0 Success
1795    1 Failed to validate server
1796 
1797  */
1798 
1799 #if defined(HAVE_OPENSSL)
1800 
1801 #ifdef HAVE_X509_check_host
1802 #include <openssl/x509v3.h>
1803 #endif
1804 
ssl_verify_server_cert(Vio * vio,const char * server_hostname,const char ** errptr)1805 static int ssl_verify_server_cert(Vio *vio, const char* server_hostname, const char **errptr)
1806 {
1807   SSL *ssl;
1808   X509 *server_cert= NULL;
1809 #ifndef HAVE_X509_check_host
1810   char *cn= NULL;
1811   int cn_loc= -1;
1812   ASN1_STRING *cn_asn1= NULL;
1813   X509_NAME_ENTRY *cn_entry= NULL;
1814   X509_NAME *subject= NULL;
1815 #endif
1816   int ret_validation= 1;
1817 
1818   DBUG_ENTER("ssl_verify_server_cert");
1819   DBUG_PRINT("enter", ("server_hostname: %s", server_hostname));
1820 
1821   if (!(ssl= (SSL*)vio->ssl_arg))
1822   {
1823     *errptr= "No SSL pointer found";
1824     goto error;
1825   }
1826 
1827   if (!server_hostname)
1828   {
1829     *errptr= "No server hostname supplied";
1830     goto error;
1831   }
1832 
1833   if (!(server_cert= SSL_get_peer_certificate(ssl)))
1834   {
1835     *errptr= "Could not get server certificate";
1836     goto error;
1837   }
1838 
1839   if (X509_V_OK != SSL_get_verify_result(ssl))
1840   {
1841     *errptr= "Failed to verify the server certificate";
1842     goto error;
1843   }
1844   /*
1845     We already know that the certificate exchanged was valid; the SSL library
1846     handled that. Now we need to verify that the contents of the certificate
1847     are what we expect.
1848   */
1849 
1850 #ifdef HAVE_X509_check_host
1851   ret_validation=
1852    (X509_check_host(server_cert, server_hostname,
1853        strlen(server_hostname), 0, 0) != 1) &&
1854    (X509_check_ip_asc(server_cert, server_hostname, 0) != 1);
1855 #else
1856   subject= X509_get_subject_name(server_cert);
1857   cn_loc= X509_NAME_get_index_by_NID(subject, NID_commonName, -1);
1858   if (cn_loc < 0)
1859   {
1860     *errptr= "Failed to get CN location in the certificate subject";
1861     goto error;
1862   }
1863   cn_entry= X509_NAME_get_entry(subject, cn_loc);
1864   if (cn_entry == NULL)
1865   {
1866     *errptr= "Failed to get CN entry using CN location";
1867     goto error;
1868   }
1869 
1870   cn_asn1 = X509_NAME_ENTRY_get_data(cn_entry);
1871   if (cn_asn1 == NULL)
1872   {
1873     *errptr= "Failed to get CN from CN entry";
1874     goto error;
1875   }
1876 
1877   cn= (char *) ASN1_STRING_get0_data(cn_asn1);
1878 
1879   if ((size_t)ASN1_STRING_length(cn_asn1) != strlen(cn))
1880   {
1881     *errptr= "NULL embedded in the certificate CN";
1882     goto error;
1883   }
1884 
1885   DBUG_PRINT("info", ("Server hostname in cert: %s", cn));
1886   if (!strcmp(cn, server_hostname))
1887   {
1888     /* Success */
1889     ret_validation= 0;
1890   }
1891 #endif
1892   *errptr= "SSL certificate validation failure";
1893 
1894 error:
1895   if (server_cert != NULL)
1896     X509_free (server_cert);
1897   DBUG_RETURN(ret_validation);
1898 }
1899 
1900 #endif /* HAVE_OPENSSL */
1901 
1902 
1903 /*
1904   Note that the mysql argument must be initialized with mysql_init()
1905   before calling mysql_real_connect !
1906 */
1907 
1908 static my_bool cli_read_query_result(MYSQL *mysql);
1909 static MYSQL_RES *cli_use_result(MYSQL *mysql);
1910 
cli_read_change_user_result(MYSQL * mysql)1911 int cli_read_change_user_result(MYSQL *mysql)
1912 {
1913   return cli_safe_read(mysql);
1914 }
1915 
1916 static MYSQL_METHODS client_methods=
1917 {
1918   cli_read_query_result,                       /* read_query_result */
1919   cli_advanced_command,                        /* advanced_command */
1920   cli_read_rows,                               /* read_rows */
1921   cli_use_result,                              /* use_result */
1922   cli_fetch_lengths,                           /* fetch_lengths */
1923   cli_flush_use_result,                        /* flush_use_result */
1924   cli_read_change_user_result                  /* read_change_user_result */
1925 #ifndef MYSQL_SERVER
1926   ,cli_list_fields,                            /* list_fields */
1927   cli_read_prepare_result,                     /* read_prepare_result */
1928   cli_stmt_execute,                            /* stmt_execute */
1929   cli_read_binary_rows,                        /* read_binary_rows */
1930   cli_unbuffered_fetch,                        /* unbuffered_fetch */
1931   NULL,                                        /* free_embedded_thd */
1932   cli_read_statistics,                         /* read_statistics */
1933   cli_read_query_result,                       /* next_result */
1934   cli_read_binary_rows                         /* read_rows_from_cursor */
1935 #endif
1936 };
1937 
1938 
1939 #include <my_sys.h>
1940 static int
mysql_autodetect_character_set(MYSQL * mysql)1941 mysql_autodetect_character_set(MYSQL *mysql)
1942 {
1943   if (mysql->options.charset_name)
1944     my_free(mysql->options.charset_name);
1945   if (!(mysql->options.charset_name= my_strdup(my_default_csname(),MYF(MY_WME))))
1946     return 1;
1947   return 0;
1948 }
1949 
1950 
1951 static void
mysql_set_character_set_with_default_collation(MYSQL * mysql)1952 mysql_set_character_set_with_default_collation(MYSQL *mysql)
1953 {
1954   const char *save= charsets_dir;
1955   if (mysql->options.charset_dir)
1956     charsets_dir=mysql->options.charset_dir;
1957 
1958   if ((mysql->charset= get_charset_by_csname(mysql->options.charset_name,
1959                                              MY_CS_PRIMARY, MYF(MY_WME))))
1960   {
1961     /* Try to set compiled default collation when it's possible. */
1962     CHARSET_INFO *collation;
1963     if ((collation=
1964          get_charset_by_name(MYSQL_DEFAULT_COLLATION_NAME, MYF(MY_WME))) &&
1965                              my_charset_same(mysql->charset, collation))
1966     {
1967       mysql->charset= collation;
1968     }
1969     else
1970     {
1971       /*
1972         Default compiled collation not found, or is not applicable
1973         to the requested character set.
1974         Continue with the default collation of the character set.
1975       */
1976     }
1977   }
1978   charsets_dir= save;
1979 }
1980 
1981 
1982 C_MODE_START
mysql_init_character_set(MYSQL * mysql)1983 int mysql_init_character_set(MYSQL *mysql)
1984 {
1985   /* Set character set */
1986   if (!mysql->options.charset_name ||
1987       !strcmp(mysql->options.charset_name,
1988               MYSQL_AUTODETECT_CHARSET_NAME))
1989   {
1990     if (mysql_autodetect_character_set(mysql))
1991       return 1;
1992   }
1993 
1994   mysql_set_character_set_with_default_collation(mysql);
1995 
1996   if (!mysql->charset)
1997   {
1998     if (mysql->options.charset_dir)
1999       set_mysql_extended_error(mysql, CR_CANT_READ_CHARSET, unknown_sqlstate,
2000                                ER(CR_CANT_READ_CHARSET),
2001                                mysql->options.charset_name,
2002                                mysql->options.charset_dir);
2003     else
2004     {
2005       char cs_dir_name[FN_REFLEN];
2006       get_charsets_dir(cs_dir_name);
2007       set_mysql_extended_error(mysql, CR_CANT_READ_CHARSET, unknown_sqlstate,
2008                                ER(CR_CANT_READ_CHARSET),
2009                                mysql->options.charset_name,
2010                                cs_dir_name);
2011     }
2012     return 1;
2013   }
2014   return 0;
2015 }
2016 C_MODE_END
2017 
2018 /*********** client side authentication support **************************/
2019 
2020 typedef struct st_mysql_client_plugin_AUTHENTICATION auth_plugin_t;
2021 static int client_mpvio_write_packet(struct st_plugin_vio*, const uchar*, int);
2022 static int native_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql);
2023 static int old_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql);
2024 
2025 static auth_plugin_t native_password_client_plugin=
2026 {
2027   MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
2028   MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION,
2029   native_password_plugin_name,
2030   "R.J.Silk, Sergei Golubchik",
2031   "Native MySQL authentication",
2032   {1, 0, 0},
2033   "GPL",
2034   NULL,
2035   NULL,
2036   NULL,
2037   NULL,
2038   native_password_auth_client
2039 };
2040 
2041 static auth_plugin_t old_password_client_plugin=
2042 {
2043   MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
2044   MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION,
2045   old_password_plugin_name,
2046   "R.J.Silk, Sergei Golubchik",
2047   "Old MySQL-3.23 authentication",
2048   {1, 0, 0},
2049   "GPL",
2050   NULL,
2051   NULL,
2052   NULL,
2053   NULL,
2054   old_password_auth_client
2055 };
2056 
2057 
2058 struct st_mysql_client_plugin *mysql_client_builtins[]=
2059 {
2060   (struct st_mysql_client_plugin *)&native_password_client_plugin,
2061   (struct st_mysql_client_plugin *)&old_password_client_plugin,
2062   0
2063 };
2064 
2065 
2066 static uchar *
write_length_encoded_string3(uchar * buf,char * string,size_t length)2067 write_length_encoded_string3(uchar *buf, char *string, size_t length)
2068 {
2069   buf= net_store_length(buf, length);
2070   memcpy(buf, string, length);
2071   buf+= length;
2072   return buf;
2073 }
2074 
2075 
2076 uchar *
send_client_connect_attrs(MYSQL * mysql,uchar * buf)2077 send_client_connect_attrs(MYSQL *mysql, uchar *buf)
2078 {
2079   /* check if the server supports connection attributes */
2080   if (mysql->server_capabilities & CLIENT_CONNECT_ATTRS)
2081   {
2082 
2083     /* Always store the length if the client supports it */
2084     buf= net_store_length(buf,
2085                           mysql->options.extension ?
2086                           mysql->options.extension->connection_attributes_length :
2087                           0);
2088 
2089     /* check if we have connection attributes */
2090     if (mysql->options.extension &&
2091         my_hash_inited(&mysql->options.extension->connection_attributes))
2092     {
2093       HASH *attrs= &mysql->options.extension->connection_attributes;
2094       ulong idx;
2095 
2096       /* loop over and dump the connection attributes */
2097       for (idx= 0; idx < attrs->records; idx++)
2098       {
2099         LEX_STRING *attr= (LEX_STRING *) my_hash_element(attrs, idx);
2100         LEX_STRING *key= attr, *value= attr + 1;
2101 
2102         /* we can't have zero length keys */
2103         DBUG_ASSERT(key->length);
2104 
2105         buf= write_length_encoded_string3(buf, key->str, key->length);
2106         buf= write_length_encoded_string3(buf, value->str, value->length);
2107       }
2108     }
2109   }
2110   return buf;
2111 }
2112 
2113 
get_length_store_length(size_t length)2114 static size_t get_length_store_length(size_t length)
2115 {
2116   /* as defined in net_store_length */
2117   #define MAX_VARIABLE_STRING_LENGTH 9
2118   uchar length_buffer[MAX_VARIABLE_STRING_LENGTH], *ptr;
2119 
2120   ptr= net_store_length(length_buffer, length);
2121 
2122   return ptr - &length_buffer[0];
2123 }
2124 
2125 
2126 /* this is a "superset" of MYSQL_PLUGIN_VIO, in C++ I use inheritance */
2127 typedef struct {
2128   int (*read_packet)(struct st_plugin_vio *vio, uchar **buf);
2129   int (*write_packet)(struct st_plugin_vio *vio, const uchar *pkt, int pkt_len);
2130   void (*info)(struct st_plugin_vio *vio, struct st_plugin_vio_info *info);
2131   /* -= end of MYSQL_PLUGIN_VIO =- */
2132   MYSQL *mysql;
2133   auth_plugin_t *plugin;            /**< what plugin we're under */
2134   const char *db;
2135   struct {
2136     uchar *pkt;                     /**< pointer into NET::buff */
2137     uint pkt_len;
2138   } cached_server_reply;
2139   int packets_read, packets_written; /**< counters for send/received packets */
2140   int mysql_change_user;            /**< if it's mysql_change_user() */
2141   int last_read_packet_len;         /**< the length of the last *read* packet */
2142 } MCPVIO_EXT;
2143 
2144 
2145 /*
2146   Write 1-8 bytes of string length header infromation to dest depending on
2147   value of src_len, then copy src_len bytes from src to dest.
2148 
2149  @param dest Destination buffer of size src_len+8
2150  @param dest_end One byte past the end of the dest buffer
2151  @param src Source buff of size src_len
2152  @param src_end One byte past the end of the src buffer
2153 
2154  @return pointer dest+src_len+header size or NULL if
2155 */
2156 
write_length_encoded_string4(uchar * dst,size_t dst_len,const uchar * src,size_t src_len)2157 static uchar *write_length_encoded_string4(uchar *dst, size_t dst_len,
2158                                            const uchar *src, size_t src_len)
2159 {
2160   uchar *to= safe_net_store_length(dst, dst_len, src_len);
2161   if (to == NULL)
2162     return NULL;
2163   memcpy(to, src, src_len);
2164   return to + src_len;
2165 }
2166 
2167 /**
2168   sends a COM_CHANGE_USER command with a caller provided payload
2169 
2170   Packet format:
2171 
2172     Bytes       Content
2173     -----       ----
2174     n           user name - \0-terminated string
2175     n           password
2176                   3.23 scramble - \0-terminated string (9 bytes)
2177                   otherwise - length (1 byte) coded
2178     n           database name - \0-terminated string
2179     2           character set number (if the server >= 4.1.x)
2180     n           client auth plugin name - \0-terminated string,
2181                   (if the server supports plugin auth)
2182 
2183   @retval 0 ok
2184   @retval 1 error
2185 */
send_change_user_packet(MCPVIO_EXT * mpvio,const uchar * data,int data_len)2186 static int send_change_user_packet(MCPVIO_EXT *mpvio,
2187                                    const uchar *data, int data_len)
2188 {
2189   MYSQL *mysql= mpvio->mysql;
2190   char *buff, *end;
2191   int res= 1;
2192   size_t connect_attrs_len=
2193     (mysql->server_capabilities & CLIENT_CONNECT_ATTRS &&
2194      mysql->options.extension) ?
2195     mysql->options.extension->connection_attributes_length : 0;
2196 
2197   buff= my_alloca(USERNAME_LENGTH + data_len + 1 + NAME_LEN + 2 + NAME_LEN +
2198                   connect_attrs_len + 9 /* for the length of the attrs */);
2199 
2200   end= strmake(buff, mysql->user, USERNAME_LENGTH) + 1;
2201 
2202   if (!data_len)
2203     *end++= 0;
2204   else
2205   {
2206     if (mysql->client_flag & CLIENT_SECURE_CONNECTION)
2207     {
2208       DBUG_ASSERT(data_len <= 255);
2209       if (data_len > 255)
2210       {
2211         set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
2212         goto error;
2213       }
2214       *end++= data_len;
2215     }
2216     else
2217     {
2218       DBUG_ASSERT(data_len == SCRAMBLE_LENGTH_323 + 1);
2219       DBUG_ASSERT(data[SCRAMBLE_LENGTH_323] == 0);
2220     }
2221     memcpy(end, data, data_len);
2222     end+= data_len;
2223   }
2224   end= strmake(end, mpvio->db ? mpvio->db : "", NAME_LEN) + 1;
2225 
2226   if (mysql->server_capabilities & CLIENT_PROTOCOL_41)
2227   {
2228     int2store(end, (ushort) mysql->charset->number);
2229     end+= 2;
2230   }
2231 
2232   if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH)
2233     end= strmake(end, mpvio->plugin->name, NAME_LEN) + 1;
2234 
2235   end= (char *) send_client_connect_attrs(mysql, (uchar *) end);
2236 
2237   res= simple_command(mysql, COM_CHANGE_USER,
2238                       (uchar*)buff, (ulong)(end-buff), 1);
2239 
2240 error:
2241   my_afree(buff);
2242   return res;
2243 }
2244 
2245 #define MAX_CONNECTION_ATTR_STORAGE_LENGTH 65536
2246 
2247 /**
2248   sends a client authentication packet (second packet in the 3-way handshake)
2249 
2250   Packet format (when the server is 4.0 or earlier):
2251 
2252     Bytes       Content
2253     -----       ----
2254     2           client capabilities
2255     3           max packet size
2256     n           user name, \0-terminated
2257     9           scramble_323, \0-terminated
2258 
2259   Packet format (when the server is 4.1 or newer):
2260 
2261     Bytes       Content
2262     -----       ----
2263     4           client capabilities
2264     4           max packet size
2265     1           charset number
2266     23          reserved (always 0)
2267     n           user name, \0-terminated
2268     n           plugin auth data (e.g. scramble), length encoded
2269     n           database name, \0-terminated
2270                 (if CLIENT_CONNECT_WITH_DB is set in the capabilities)
2271     n           client auth plugin name - \0-terminated string,
2272                 (if CLIENT_PLUGIN_AUTH is set in the capabilities)
2273 
2274   @retval 0 ok
2275   @retval 1 error
2276 */
send_client_reply_packet(MCPVIO_EXT * mpvio,const uchar * data,int data_len)2277 static int send_client_reply_packet(MCPVIO_EXT *mpvio,
2278                                     const uchar *data, int data_len)
2279 {
2280   MYSQL *mysql= mpvio->mysql;
2281   NET *net= &mysql->net;
2282   char *buff, *end;
2283   size_t buff_size;
2284   size_t connect_attrs_len=
2285     (mysql->server_capabilities & CLIENT_CONNECT_ATTRS &&
2286      mysql->options.extension) ?
2287     mysql->options.extension->connection_attributes_length : 0;
2288 
2289   DBUG_ASSERT(connect_attrs_len < MAX_CONNECTION_ATTR_STORAGE_LENGTH);
2290 
2291   /*
2292     see end= buff+32 below, fixed size of the packet is 32 bytes.
2293      +9 because data is a length encoded binary where meta data size is max 9.
2294   */
2295   buff_size= 33 + USERNAME_LENGTH + data_len + 9 + NAME_LEN + NAME_LEN + connect_attrs_len + 9;
2296   buff= my_alloca(buff_size);
2297 
2298   mysql->client_flag|= mysql->options.client_flag;
2299   mysql->client_flag|= CLIENT_CAPABILITIES;
2300 
2301   if (mysql->client_flag & CLIENT_MULTI_STATEMENTS)
2302     mysql->client_flag|= CLIENT_MULTI_RESULTS;
2303 
2304 #ifdef HAVE_OPENSSL
2305   if (mysql->options.ssl_key || mysql->options.ssl_cert ||
2306       mysql->options.ssl_ca || mysql->options.ssl_capath ||
2307       mysql->options.ssl_cipher)
2308     mysql->options.use_ssl = 1;
2309   if (mysql->options.use_ssl)
2310     mysql->client_flag|= CLIENT_SSL;
2311 #endif /* HAVE_OPENSSL */
2312 
2313   if (mpvio->db)
2314     mysql->client_flag|= CLIENT_CONNECT_WITH_DB;
2315 
2316   /* Remove options that server doesn't support */
2317   mysql->client_flag= mysql->client_flag &
2318                        (~(CLIENT_COMPRESS | CLIENT_SSL | CLIENT_PROTOCOL_41)
2319                        | mysql->server_capabilities);
2320 
2321 #ifndef HAVE_COMPRESS
2322   mysql->client_flag&= ~CLIENT_COMPRESS;
2323 #endif
2324 
2325   if (mysql->client_flag & CLIENT_PROTOCOL_41)
2326   {
2327     /* 4.1 server and 4.1 client has a 32 byte option flag */
2328     int4store(buff,mysql->client_flag);
2329     int4store(buff+4, net->max_packet_size);
2330     buff[8]= (char) mysql->charset->number;
2331     bzero(buff+9, 32-9);
2332     end= buff+32;
2333   }
2334   else
2335   {
2336     int2store(buff, mysql->client_flag);
2337     int3store(buff+2, net->max_packet_size);
2338     end= buff+5;
2339   }
2340 
2341   /*
2342      If client uses ssl and client also has to verify the server
2343      certificate, a ssl connection is required.
2344      If the server does not support ssl, we abort the connection.
2345   */
2346   if (mysql->options.use_ssl &&
2347       (mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT) &&
2348       !(mysql->server_capabilities & CLIENT_SSL))
2349   {
2350     set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
2351                              ER(CR_SSL_CONNECTION_ERROR),
2352                              "SSL is required, but the server does not "
2353                              "support it");
2354     goto error;
2355   }
2356 
2357 #ifdef HAVE_OPENSSL
2358   if (mysql->client_flag & CLIENT_SSL)
2359   {
2360     /* Do the SSL layering. */
2361     struct st_mysql_options *options= &mysql->options;
2362     struct st_VioSSLFd *ssl_fd;
2363     enum enum_ssl_init_error ssl_init_error;
2364     const char *cert_error;
2365     unsigned long ssl_error;
2366 #ifdef EMBEDDED_LIBRARY
2367     DBUG_ASSERT(0); // embedded should not do SSL connect
2368 #endif
2369 
2370     /*
2371       Send mysql->client_flag, max_packet_size - unencrypted otherwise
2372       the server does not know we want to do SSL
2373     */
2374     if (my_net_write(net, (uchar*)buff, (size_t) (end-buff)) || net_flush(net))
2375     {
2376       set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
2377                                ER(CR_SERVER_LOST_EXTENDED),
2378                                "sending connection information to server",
2379                                errno);
2380       goto error;
2381     }
2382 
2383     /* Create the VioSSLConnectorFd - init SSL and load certs */
2384     if (!(ssl_fd= new_VioSSLConnectorFd(options->ssl_key,
2385                                         options->ssl_cert,
2386                                         options->ssl_ca,
2387                                         options->ssl_capath,
2388                                         options->ssl_cipher,
2389                                         &ssl_init_error,
2390                                         options->extension ?
2391                                         options->extension->ssl_crl : NULL,
2392                                         options->extension ?
2393                                         options->extension->ssl_crlpath : NULL)))
2394     {
2395       set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
2396                                ER(CR_SSL_CONNECTION_ERROR), sslGetErrString(ssl_init_error));
2397       goto error;
2398     }
2399     mysql->connector_fd= (unsigned char *) ssl_fd;
2400 
2401     /* Connect to the server */
2402     DBUG_PRINT("info", ("IO layer change in progress..."));
2403     if (sslconnect(ssl_fd, net->vio,
2404                    (long) (mysql->options.connect_timeout), &ssl_error))
2405     {
2406       char buf[512];
2407       ERR_error_string_n(ssl_error, buf, 512);
2408       buf[511]= 0;
2409       set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
2410                                ER(CR_SSL_CONNECTION_ERROR),
2411                                buf);
2412       goto error;
2413     }
2414     DBUG_PRINT("info", ("IO layer change done!"));
2415 
2416     /* Verify server cert */
2417     if ((mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT) &&
2418         ssl_verify_server_cert(net->vio, mysql->host, &cert_error))
2419     {
2420       set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate,
2421                                ER(CR_SSL_CONNECTION_ERROR), cert_error);
2422       goto error;
2423     }
2424   }
2425 #endif /* HAVE_OPENSSL */
2426 
2427   DBUG_PRINT("info",("Server version = '%s'  capabilites: %lu  status: %u  client_flag: %lu",
2428 		     mysql->server_version, mysql->server_capabilities,
2429 		     mysql->server_status, mysql->client_flag));
2430 
2431   /* This needs to be changed as it's not useful with big packets */
2432   if (mysql->user[0])
2433     strmake(end, mysql->user, USERNAME_LENGTH);
2434   else
2435     read_user_name(end);
2436 
2437   /* We have to handle different version of handshake here */
2438   DBUG_PRINT("info",("user: %s",end));
2439   end= strend(end) + 1;
2440   if (data_len)
2441   {
2442     if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
2443     {
2444       if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA)
2445         end= (char*)write_length_encoded_string4((uchar*)end,
2446                                                  buff_size, data, data_len);
2447       else
2448       {
2449         if (data_len > 255)
2450           goto error;
2451         *end++= data_len;
2452         memcpy(end, data, data_len);
2453         end+= data_len;
2454       }
2455       if (end == NULL)
2456         goto error;
2457     }
2458     else
2459     {
2460       DBUG_ASSERT(data_len == SCRAMBLE_LENGTH_323 + 1); /* incl. \0 at the end */
2461       memcpy(end, data, data_len);
2462       end+= data_len;
2463     }
2464   }
2465   else
2466     *end++= 0;
2467 
2468   /* Add database if needed */
2469   if (mpvio->db && (mysql->server_capabilities & CLIENT_CONNECT_WITH_DB))
2470   {
2471     end= strmake(end, mpvio->db, NAME_LEN) + 1;
2472     mysql->db= my_strdup(mpvio->db, MYF(MY_WME));
2473   }
2474 
2475   if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH)
2476     end= strmake(end, mpvio->plugin->name, NAME_LEN) + 1;
2477 
2478   end= (char *) send_client_connect_attrs(mysql, (uchar *) end);
2479 
2480   /* Write authentication package */
2481   if (my_net_write(net, (uchar*) buff, (size_t) (end-buff)) || net_flush(net))
2482   {
2483     set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
2484                              ER(CR_SERVER_LOST_EXTENDED),
2485                              "sending authentication information",
2486                              errno);
2487     goto error;
2488   }
2489   my_afree(buff);
2490   return 0;
2491 
2492 error:
2493   my_afree(buff);
2494   return 1;
2495 }
2496 
2497 
2498 /**
2499   vio->read_packet() callback method for client authentication plugins
2500 
2501   This function is called by a client authentication plugin, when it wants
2502   to read data from the server.
2503 */
client_mpvio_read_packet(struct st_plugin_vio * mpv,uchar ** buf)2504 static int client_mpvio_read_packet(struct st_plugin_vio *mpv, uchar **buf)
2505 {
2506   MCPVIO_EXT *mpvio= (MCPVIO_EXT*)mpv;
2507   MYSQL *mysql= mpvio->mysql;
2508   ulong  pkt_len;
2509 
2510   /* there are cached data left, feed it to a plugin */
2511   if (mpvio->cached_server_reply.pkt)
2512   {
2513     *buf= mpvio->cached_server_reply.pkt;
2514     mpvio->cached_server_reply.pkt= 0;
2515     mpvio->packets_read++;
2516     return mpvio->cached_server_reply.pkt_len;
2517   }
2518 
2519   if (mpvio->packets_read == 0)
2520   {
2521     /*
2522       the server handshake packet came from the wrong plugin,
2523       or it's mysql_change_user(). Either way, there is no data
2524       for a plugin to read. send a dummy packet to the server
2525       to initiate a dialog.
2526     */
2527     if (client_mpvio_write_packet(mpv, 0, 0))
2528       return (int)packet_error;
2529   }
2530 
2531   /* otherwise read the data */
2532   pkt_len= (*mysql->methods->read_change_user_result)(mysql);
2533   mpvio->last_read_packet_len= pkt_len;
2534   *buf= mysql->net.read_pos;
2535 
2536   /* was it a request to change plugins ? */
2537   if (pkt_len == packet_error || **buf == 254)
2538     return (int)packet_error; /* if yes, this plugin shan't continue */
2539 
2540   /*
2541     the server sends \1\255 or \1\254 instead of just \255 or \254 -
2542     for us to not confuse it with an error or "change plugin" packets.
2543     We remove this escaping \1 here.
2544 
2545     See also server_mpvio_write_packet() where the escaping is done.
2546   */
2547   if (pkt_len && **buf == 1)
2548   {
2549     (*buf)++;
2550     pkt_len--;
2551   }
2552   mpvio->packets_read++;
2553   return pkt_len;
2554 }
2555 
2556 
2557 /**
2558   vio->write_packet() callback method for client authentication plugins
2559 
2560   This function is called by a client authentication plugin, when it wants
2561   to send data to the server.
2562 
2563   It transparently wraps the data into a change user or authentication
2564   handshake packet, if neccessary.
2565 */
client_mpvio_write_packet(struct st_plugin_vio * mpv,const uchar * pkt,int pkt_len)2566 static int client_mpvio_write_packet(struct st_plugin_vio *mpv,
2567                                      const uchar *pkt, int pkt_len)
2568 {
2569   int res;
2570   MCPVIO_EXT *mpvio= (MCPVIO_EXT*)mpv;
2571 
2572   if (mpvio->packets_written == 0)
2573   {
2574     if (mpvio->mysql_change_user)
2575       res= send_change_user_packet(mpvio, pkt, pkt_len);
2576     else
2577       res= send_client_reply_packet(mpvio, pkt, pkt_len);
2578   }
2579   else
2580   {
2581     NET *net= &mpvio->mysql->net;
2582     if (mpvio->mysql->thd)
2583       res= 1; /* no chit-chat in embedded */
2584     else
2585       res= my_net_write(net, pkt, pkt_len) || net_flush(net);
2586     if (res)
2587       set_mysql_extended_error(mpvio->mysql, CR_SERVER_LOST, unknown_sqlstate,
2588                                ER(CR_SERVER_LOST_EXTENDED),
2589                                "sending authentication information",
2590                                errno);
2591   }
2592   mpvio->packets_written++;
2593   return res;
2594 }
2595 
2596 
2597 /**
2598   fills MYSQL_PLUGIN_VIO_INFO structure with the information about the
2599   connection
2600 */
mpvio_info(Vio * vio,MYSQL_PLUGIN_VIO_INFO * info)2601 void mpvio_info(Vio *vio, MYSQL_PLUGIN_VIO_INFO *info)
2602 {
2603   bzero(info, sizeof(*info));
2604   switch (vio->type) {
2605   case VIO_TYPE_TCPIP:
2606     info->protocol= MYSQL_VIO_TCP;
2607     info->socket= (int)vio_fd(vio);
2608     return;
2609   case VIO_TYPE_SOCKET:
2610     info->protocol= MYSQL_VIO_SOCKET;
2611     info->socket= (int)vio_fd(vio);
2612     return;
2613   case VIO_TYPE_SSL:
2614     {
2615       struct sockaddr addr;
2616       SOCKET_SIZE_TYPE addrlen= sizeof(addr);
2617       if (getsockname(vio_fd(vio), &addr, &addrlen))
2618         return;
2619       info->protocol= addr.sa_family == AF_UNIX ?
2620         MYSQL_VIO_SOCKET : MYSQL_VIO_TCP;
2621       info->socket= (int)vio_fd(vio);
2622       return;
2623     }
2624 #ifdef _WIN32
2625   case VIO_TYPE_NAMEDPIPE:
2626     info->protocol= MYSQL_VIO_PIPE;
2627     info->handle= vio->hPipe;
2628     return;
2629   case VIO_TYPE_SHARED_MEMORY:
2630     info->protocol= MYSQL_VIO_MEMORY;
2631 #ifdef HAVE_SMEM
2632     info->handle= vio->handle_file_map; /* or what ? */
2633 #endif
2634     return;
2635 #endif
2636   default: DBUG_ASSERT(0);
2637   }
2638 }
2639 
2640 
client_mpvio_info(MYSQL_PLUGIN_VIO * vio,MYSQL_PLUGIN_VIO_INFO * info)2641 static void client_mpvio_info(MYSQL_PLUGIN_VIO *vio,
2642                               MYSQL_PLUGIN_VIO_INFO *info)
2643 {
2644   MCPVIO_EXT *mpvio= (MCPVIO_EXT*)vio;
2645   mpvio_info(mpvio->mysql->net.vio, info);
2646 }
2647 
2648 
2649 /**
2650   Client side of the plugin driver authentication.
2651 
2652   @note this is used by both the mysql_real_connect and mysql_change_user
2653 
2654   @param mysql       mysql
2655   @param data        pointer to the plugin auth data (scramble) in the
2656                      handshake packet
2657   @param data_len    the length of the data
2658   @param data_plugin a plugin that data were prepared for
2659                      or 0 if it's mysql_change_user()
2660   @param db          initial db to use, can be 0
2661 
2662   @retval 0 ok
2663   @retval 1 error
2664 */
run_plugin_auth(MYSQL * mysql,char * data,uint data_len,const char * data_plugin,const char * db)2665 int run_plugin_auth(MYSQL *mysql, char *data, uint data_len,
2666                     const char *data_plugin, const char *db)
2667 {
2668   const char    *auth_plugin_name;
2669   auth_plugin_t *auth_plugin;
2670   MCPVIO_EXT    mpvio;
2671   ulong		pkt_length;
2672   int           res;
2673 
2674   DBUG_ENTER ("run_plugin_auth");
2675   /* determine the default/initial plugin to use */
2676   if (mysql->options.extension && mysql->options.extension->default_auth &&
2677       mysql->server_capabilities & CLIENT_PLUGIN_AUTH)
2678   {
2679     auth_plugin_name= mysql->options.extension->default_auth;
2680     if (!(auth_plugin= (auth_plugin_t*) mysql_client_find_plugin(mysql,
2681                        auth_plugin_name, MYSQL_CLIENT_AUTHENTICATION_PLUGIN)))
2682       DBUG_RETURN (1); /* oops, not found */
2683   }
2684   else
2685   {
2686     auth_plugin= mysql->server_capabilities & CLIENT_PROTOCOL_41 ?
2687       &native_password_client_plugin : &old_password_client_plugin;
2688     auth_plugin_name= auth_plugin->name;
2689   }
2690 
2691   DBUG_PRINT ("info", ("using plugin %s", auth_plugin_name));
2692 
2693   mysql->net.last_errno= 0; /* just in case */
2694 
2695   if (data_plugin && strcmp(data_plugin, auth_plugin_name))
2696   {
2697     /* data was prepared for a different plugin, don't show it to this one */
2698     data= 0;
2699     data_len= 0;
2700   }
2701 
2702   mpvio.mysql_change_user= data_plugin == 0;
2703   mpvio.cached_server_reply.pkt= (uchar*)data;
2704   mpvio.cached_server_reply.pkt_len= data_len;
2705   mpvio.read_packet= client_mpvio_read_packet;
2706   mpvio.write_packet= client_mpvio_write_packet;
2707   mpvio.info= client_mpvio_info;
2708   mpvio.mysql= mysql;
2709   mpvio.packets_read= mpvio.packets_written= 0;
2710   mpvio.db= db;
2711   mpvio.plugin= auth_plugin;
2712 
2713   res= auth_plugin->authenticate_user((struct st_plugin_vio *)&mpvio, mysql);
2714   DBUG_PRINT ("info", ("authenticate_user returned %s",
2715                        res == CR_OK ? "CR_OK" :
2716                        res == CR_ERROR ? "CR_ERROR" :
2717                        res == CR_OK_HANDSHAKE_COMPLETE ?
2718                          "CR_OK_HANDSHAKE_COMPLETE" : "error"));
2719 
2720   compile_time_assert(CR_OK == -1);
2721   compile_time_assert(CR_ERROR == 0);
2722   if (res > CR_OK && (mysql->net.last_errno || mysql->net.read_pos[0] != 254))
2723   {
2724     /*
2725       the plugin returned an error. write it down in mysql,
2726       unless the error code is CR_ERROR and mysql->net.last_errno
2727       is already set (the plugin has done it)
2728     */
2729     DBUG_PRINT ("info", ("res=%d", res));
2730     if (res > CR_ERROR)
2731       set_mysql_error(mysql, res, unknown_sqlstate);
2732     else
2733       if (!mysql->net.last_errno)
2734         set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate);
2735     DBUG_RETURN (1);
2736   }
2737 
2738   /* read the OK packet (or use the cached value in mysql->net.read_pos */
2739   if (res == CR_OK)
2740     pkt_length= (*mysql->methods->read_change_user_result)(mysql);
2741   else /* res == CR_OK_HANDSHAKE_COMPLETE */
2742     pkt_length= mpvio.last_read_packet_len;
2743 
2744   DBUG_PRINT ("info", ("OK packet length=%lu", pkt_length));
2745   if (pkt_length == packet_error)
2746   {
2747     if (mysql->net.last_errno == CR_SERVER_LOST)
2748       set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
2749                                ER(CR_SERVER_LOST_EXTENDED),
2750                                "reading authorization packet",
2751                                errno);
2752     DBUG_RETURN (1);
2753   }
2754 
2755   if (mysql->net.read_pos[0] == 254)
2756   {
2757     /* The server asked to use a different authentication plugin */
2758     if (pkt_length == 1)
2759     {
2760       /* old "use short scramble" packet */
2761       DBUG_PRINT ("info", ("old use short scramble packet from server"));
2762       auth_plugin_name= old_password_plugin_name;
2763       mpvio.cached_server_reply.pkt= (uchar*)mysql->scramble;
2764       mpvio.cached_server_reply.pkt_len= SCRAMBLE_LENGTH + 1;
2765     }
2766     else
2767     {
2768       /* new "use different plugin" packet */
2769       uint len;
2770       auth_plugin_name= (char*)mysql->net.read_pos + 1;
2771       len= (uint)strlen(auth_plugin_name); /* safe as my_net_read always appends \0 */
2772       mpvio.cached_server_reply.pkt_len= pkt_length - len - 2;
2773       mpvio.cached_server_reply.pkt= mysql->net.read_pos + len + 2;
2774       DBUG_PRINT ("info", ("change plugin packet from server for plugin %s",
2775                            auth_plugin_name));
2776     }
2777 
2778     if (!(auth_plugin= (auth_plugin_t *) mysql_client_find_plugin(mysql,
2779                          auth_plugin_name, MYSQL_CLIENT_AUTHENTICATION_PLUGIN)))
2780       DBUG_RETURN (1);
2781 
2782     mpvio.plugin= auth_plugin;
2783     res= auth_plugin->authenticate_user((struct st_plugin_vio *)&mpvio, mysql);
2784 
2785     DBUG_PRINT ("info", ("second authenticate_user returned %s",
2786                          res == CR_OK ? "CR_OK" :
2787                          res == CR_ERROR ? "CR_ERROR" :
2788                          res == CR_OK_HANDSHAKE_COMPLETE ?
2789                          "CR_OK_HANDSHAKE_COMPLETE" : "error"));
2790     if (res > CR_OK)
2791     {
2792       if (res > CR_ERROR)
2793         set_mysql_error(mysql, res, unknown_sqlstate);
2794       else
2795         if (!mysql->net.last_errno)
2796           set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate);
2797       DBUG_RETURN (1);
2798     }
2799 
2800     if (res != CR_OK_HANDSHAKE_COMPLETE)
2801     {
2802       /* Read what server thinks about out new auth message report */
2803       if (cli_safe_read(mysql) == packet_error)
2804       {
2805         if (mysql->net.last_errno == CR_SERVER_LOST)
2806           set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
2807                                    ER(CR_SERVER_LOST_EXTENDED),
2808                                    "reading final connect information",
2809                                    errno);
2810         DBUG_RETURN (1);
2811       }
2812     }
2813   }
2814   /*
2815     net->read_pos[0] should always be 0 here if the server implements
2816     the protocol correctly
2817   */
2818   DBUG_RETURN (mysql->net.read_pos[0] != 0);
2819 }
2820 
2821 
2822 static int
connect_sync_or_async(MYSQL * mysql,NET * net,my_socket fd,struct sockaddr * name,uint namelen)2823 connect_sync_or_async(MYSQL *mysql, NET *net, my_socket fd,
2824                       struct sockaddr *name, uint namelen)
2825 {
2826   int vio_timeout = get_vio_connect_timeout(mysql);
2827 
2828   if (mysql->options.extension && mysql->options.extension->async_context &&
2829       mysql->options.extension->async_context->active)
2830   {
2831     my_bool old_mode;
2832     vio_blocking(net->vio, FALSE, &old_mode);
2833     return my_connect_async(mysql->options.extension->async_context, fd,
2834                             name, namelen, vio_timeout);
2835   }
2836 
2837   return vio_socket_connect(net->vio, name, namelen, vio_timeout);
2838 }
2839 
2840 
2841 /** set some default attributes */
2842 static int
set_connect_attributes(MYSQL * mysql,char * buff,size_t buf_len)2843 set_connect_attributes(MYSQL *mysql, char *buff, size_t buf_len)
2844 {
2845   int rc= 0;
2846 
2847   /*
2848     Clean up any values set by the client code. We want these options as
2849     consistent as possible
2850   */
2851   rc+= mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_client_name");
2852   rc+= mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_os");
2853   rc+= mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_platform");
2854   rc+= mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_server_host");
2855   rc+= mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_pid");
2856   rc+= mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_thread");
2857   rc+= mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_client_version");
2858 
2859   /*
2860    Now let's set up some values
2861   */
2862   rc+= mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
2863                      "_client_name", "libmysql");
2864   rc+= mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
2865                       "_client_version", PACKAGE_VERSION);
2866   rc+= mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
2867                       "_os", SYSTEM_TYPE);
2868   rc+= mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
2869                       "_platform", MACHINE_TYPE);
2870   rc+= mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
2871                       "_server_host", mysql->host);
2872 #ifdef __WIN__
2873   snprintf(buff, buf_len, "%lu", (ulong) GetCurrentProcessId());
2874 #else
2875   snprintf(buff, buf_len, "%lu", (ulong) getpid());
2876 #endif
2877   rc+= mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_pid", buff);
2878 
2879 #ifdef __WIN__
2880   snprintf(buff, buf_len, "%lu", (ulong) GetCurrentThreadId());
2881   rc+= mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_thread", buff);
2882 #endif
2883 
2884   return rc > 0 ? 1 : 0;
2885 }
2886 
2887 
2888 MYSQL * STDCALL
CLI_MYSQL_REAL_CONNECT(MYSQL * mysql,const char * host,const char * user,const char * passwd,const char * db,uint port,const char * unix_socket,ulong client_flag)2889 CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
2890 		       const char *passwd, const char *db,
2891 		       uint port, const char *unix_socket,ulong client_flag)
2892 {
2893   char		buff[NAME_LEN+USERNAME_LENGTH+100];
2894   int           scramble_data_len, UNINIT_VAR(pkt_scramble_len);
2895   char          *end,*host_info= 0, *server_version_end, *pkt_end;
2896   char          *scramble_data;
2897   const char    *scramble_plugin;
2898   ulong		pkt_length;
2899   NET		*net= &mysql->net;
2900 #ifdef __WIN__
2901   HANDLE	hPipe=INVALID_HANDLE_VALUE;
2902 #endif
2903 #ifdef HAVE_SYS_UN_H
2904   struct	sockaddr_un UNIXaddr;
2905 #endif
2906   DBUG_ENTER("mysql_real_connect");
2907 
2908   DBUG_PRINT("enter",("host: %s  db: %s  user: %s (client)",
2909 		      host ? host : "(Null)",
2910 		      db ? db : "(Null)",
2911 		      user ? user : "(Null)"));
2912 
2913   /* Test whether we're already connected */
2914   if (net->vio)
2915   {
2916     set_mysql_error(mysql, CR_ALREADY_CONNECTED, unknown_sqlstate);
2917     DBUG_RETURN(0);
2918   }
2919 
2920   mysql->methods= &client_methods;
2921   mysql->client_flag=0;			/* For handshake */
2922 
2923   /* use default options */
2924   if (mysql->options.my_cnf_file || mysql->options.my_cnf_group)
2925   {
2926     mysql_read_default_options(&mysql->options,
2927 			       (mysql->options.my_cnf_file ?
2928 				mysql->options.my_cnf_file : "my"),
2929 			       mysql->options.my_cnf_group);
2930     my_free(mysql->options.my_cnf_file);
2931     my_free(mysql->options.my_cnf_group);
2932     mysql->options.my_cnf_file=mysql->options.my_cnf_group=0;
2933     if (mysql->options.protocol == UINT_MAX32)
2934       goto error;
2935   }
2936 
2937   /* Some empty-string-tests are done because of ODBC */
2938   if (!host || !host[0])
2939     host=mysql->options.host;
2940   if (!user || !user[0])
2941   {
2942     user=mysql->options.user;
2943     if (!user)
2944       user= "";
2945   }
2946   if (!passwd)
2947   {
2948     passwd=mysql->options.password;
2949 #if !defined(DONT_USE_MYSQL_PWD) && !defined(MYSQL_SERVER)
2950     if (!passwd)
2951       passwd=getenv("MYSQL_PWD");		/* get it from environment */
2952 #endif
2953     if (!passwd)
2954       passwd= "";
2955   }
2956   if (!db || !db[0])
2957     db=mysql->options.db;
2958   if (!port)
2959     port=mysql->options.port;
2960   if (!unix_socket)
2961     unix_socket=mysql->options.unix_socket;
2962 
2963   mysql->server_status=SERVER_STATUS_AUTOCOMMIT;
2964   DBUG_PRINT("info", ("Connecting"));
2965 
2966   /*
2967     Part 0: Grab a socket and connect it to the server
2968   */
2969 #if defined(HAVE_SMEM)
2970   if ((!mysql->options.protocol ||
2971        mysql->options.protocol == MYSQL_PROTOCOL_MEMORY) &&
2972       (!host || !strcmp(host,LOCAL_HOST)) &&
2973       mysql->options.shared_memory_base_name)
2974   {
2975     DBUG_PRINT("info", ("Using shared memory"));
2976     if ((create_shared_memory(mysql,net, mysql->options.connect_timeout)) ==
2977 	INVALID_HANDLE_VALUE)
2978     {
2979       DBUG_PRINT("error",
2980 		 ("host: '%s'  socket: '%s'  shared memory: %s  have_tcpip: %d",
2981 		  host ? host : "<null>",
2982 		  unix_socket ? unix_socket : "<null>",
2983 		  mysql->options.shared_memory_base_name,
2984 		  (int) have_tcpip));
2985       if (mysql->options.protocol == MYSQL_PROTOCOL_MEMORY)
2986 	goto error;
2987 
2988       /*
2989         Try also with PIPE or TCP/IP. Clear the error from
2990         create_shared_memory().
2991       */
2992 
2993       net_clear_error(net);
2994     }
2995     else
2996     {
2997       mysql->options.protocol=MYSQL_PROTOCOL_MEMORY;
2998       unix_socket = 0;
2999       host=mysql->options.shared_memory_base_name;
3000       my_snprintf(host_info=buff, sizeof(buff)-1,
3001                   ER(CR_SHARED_MEMORY_CONNECTION), host);
3002     }
3003   }
3004 #endif /* HAVE_SMEM */
3005 #if defined(HAVE_SYS_UN_H)
3006   if (!net->vio &&
3007       (!mysql->options.protocol ||
3008        mysql->options.protocol == MYSQL_PROTOCOL_SOCKET) &&
3009       (unix_socket || mysql_unix_port) &&
3010       (!host || !strcmp(host,LOCAL_HOST)))
3011   {
3012     my_socket sock= socket(AF_UNIX, SOCK_STREAM, 0);
3013     DBUG_PRINT("info", ("Using socket"));
3014     if (sock == INVALID_SOCKET)
3015     {
3016       set_mysql_extended_error(mysql, CR_SOCKET_CREATE_ERROR,
3017                                unknown_sqlstate,
3018                                ER(CR_SOCKET_CREATE_ERROR),
3019                                socket_errno);
3020       goto error;
3021     }
3022 
3023     net->vio= vio_new(sock, VIO_TYPE_SOCKET,
3024                       VIO_LOCALHOST | VIO_BUFFERED_READ);
3025     if (!net->vio)
3026     {
3027       DBUG_PRINT("error",("Unknow protocol %d ", mysql->options.protocol));
3028       set_mysql_error(mysql, CR_CONN_UNKNOW_PROTOCOL, unknown_sqlstate);
3029       closesocket(sock);
3030       goto error;
3031     }
3032 
3033     host= LOCAL_HOST;
3034     if (!unix_socket)
3035       unix_socket= mysql_unix_port;
3036     host_info= (char*) ER(CR_LOCALHOST_CONNECTION);
3037     DBUG_PRINT("info", ("Using UNIX sock '%s'", unix_socket));
3038 
3039     bzero((char*) &UNIXaddr, sizeof(UNIXaddr));
3040     UNIXaddr.sun_family= AF_UNIX;
3041     strmake_buf(UNIXaddr.sun_path, unix_socket);
3042     if (connect_sync_or_async(mysql, net, sock,
3043                               (struct sockaddr *) &UNIXaddr, sizeof(UNIXaddr)))
3044     {
3045       DBUG_PRINT("error",("Got error %d on connect to local server",
3046 			  socket_errno));
3047       set_mysql_extended_error(mysql, CR_CONNECTION_ERROR,
3048                                unknown_sqlstate,
3049                                ER(CR_CONNECTION_ERROR),
3050                                unix_socket, socket_errno);
3051       vio_delete(net->vio);
3052       net->vio= 0;
3053       goto error;
3054     }
3055     mysql->options.protocol=MYSQL_PROTOCOL_SOCKET;
3056   }
3057 #elif defined(__WIN__)
3058   if (!net->vio &&
3059       (mysql->options.protocol == MYSQL_PROTOCOL_PIPE ||
3060        (host && !strcmp(host,LOCAL_HOST_NAMEDPIPE)) ||
3061        (! have_tcpip && (unix_socket || !host ))))
3062   {
3063     if ((hPipe= create_named_pipe(mysql, mysql->options.connect_timeout,
3064                                   (char**) &host, (char**) &unix_socket)) ==
3065 	INVALID_HANDLE_VALUE)
3066     {
3067       DBUG_PRINT("error",
3068 		 ("host: '%s'  socket: '%s'  have_tcpip: %d",
3069 		  host ? host : "<null>",
3070 		  unix_socket ? unix_socket : "<null>",
3071 		  (int) have_tcpip));
3072       if (mysql->options.protocol == MYSQL_PROTOCOL_PIPE ||
3073 	  (host && !strcmp(host,LOCAL_HOST_NAMEDPIPE)) ||
3074 	  (unix_socket && !strcmp(unix_socket,MYSQL_NAMEDPIPE)))
3075 	goto error;
3076       /* Try also with TCP/IP */
3077     }
3078     else
3079     {
3080       net->vio= vio_new_win32pipe(hPipe);
3081       my_snprintf(host_info=buff, sizeof(buff)-1,
3082                   ER(CR_NAMEDPIPE_CONNECTION), unix_socket);
3083     }
3084   }
3085 #endif
3086   DBUG_PRINT("info", ("net->vio: %p  protocol: %d",
3087                       net->vio, mysql->options.protocol));
3088   if (!net->vio &&
3089       (!mysql->options.protocol ||
3090        mysql->options.protocol == MYSQL_PROTOCOL_TCP))
3091   {
3092     struct addrinfo *res_lst, hints, *t_res;
3093     int gai_errno;
3094     char port_buf[NI_MAXSERV];
3095     my_socket sock= INVALID_SOCKET;
3096     int saved_error= 0, status= -1;
3097 
3098     unix_socket=0;				/* This is not used */
3099 
3100     if (!port)
3101       port= mysql_port;
3102 
3103     if (!host)
3104       host= LOCAL_HOST;
3105 
3106     my_snprintf(host_info=buff, sizeof(buff)-1, ER(CR_TCP_CONNECTION), host);
3107     DBUG_PRINT("info",("Server name: '%s'.  TCP sock: %d", host, port));
3108     DBUG_PRINT("info",("IP '%s'", "client"));
3109 
3110     memset(&hints, 0, sizeof(hints));
3111     hints.ai_socktype= SOCK_STREAM;
3112     hints.ai_protocol= IPPROTO_TCP;
3113     hints.ai_family= AF_UNSPEC;
3114 
3115     DBUG_PRINT("info",("IPV6 getaddrinfo %s", host));
3116     my_snprintf(port_buf, NI_MAXSERV, "%d", port);
3117     gai_errno= getaddrinfo(host, port_buf, &hints, &res_lst);
3118 
3119     if (gai_errno != 0)
3120     {
3121       /*
3122         For DBUG we are keeping the right message but for client we default to
3123         historical error message.
3124       */
3125       DBUG_PRINT("info",("IPV6 getaddrinfo error %d", gai_errno));
3126       set_mysql_extended_error(mysql, CR_UNKNOWN_HOST, unknown_sqlstate,
3127                                ER(CR_UNKNOWN_HOST), host, gai_errno);
3128 
3129       goto error;
3130     }
3131 
3132     /*
3133       A hostname might map to multiple IP addresses (IPv4/IPv6). Go over the
3134       list of IP addresses until a successful connection can be established.
3135     */
3136     DBUG_PRINT("info", ("Try connect on all addresses for host."));
3137     for (t_res= res_lst; t_res; t_res= t_res->ai_next)
3138     {
3139       DBUG_PRINT("info", ("Create socket, family: %d  type: %d  proto: %d",
3140                           t_res->ai_family, t_res->ai_socktype,
3141                           t_res->ai_protocol));
3142       sock= socket(t_res->ai_family, t_res->ai_socktype, t_res->ai_protocol);
3143       if (sock == INVALID_SOCKET)
3144       {
3145         saved_error= socket_errno;
3146         continue;
3147       }
3148 
3149       net->vio= vio_new(sock, VIO_TYPE_TCPIP, VIO_BUFFERED_READ);
3150       if (!net->vio)
3151       {
3152         set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
3153         closesocket(sock);
3154         freeaddrinfo(res_lst);
3155         goto error;
3156       }
3157 
3158       DBUG_PRINT("info", ("Connect socket"));
3159       status= connect_sync_or_async(mysql, net, sock,
3160                                     t_res->ai_addr, (uint)t_res->ai_addrlen);
3161       /*
3162         Here we rely on my_connect() to return success only if the
3163         connect attempt was really successful. Otherwise we would stop
3164         trying another address, believing we were successful.
3165       */
3166       if (!status)
3167         break;
3168 
3169       /*
3170         Save value as socket errno might be overwritten due to
3171         calling a socket function below.
3172       */
3173       saved_error= socket_errno;
3174 
3175       DBUG_PRINT("info", ("No success, close socket, try next address."));
3176       vio_delete(mysql->net.vio);
3177       mysql->net.vio= 0;
3178     }
3179     DBUG_PRINT("info",
3180                ("End of connect attempts, sock: %d  status: %d  error: %d",
3181                 (int)sock, status, saved_error));
3182 
3183     freeaddrinfo(res_lst);
3184 
3185     if (sock == INVALID_SOCKET)
3186     {
3187       set_mysql_extended_error(mysql, CR_IPSOCK_ERROR, unknown_sqlstate,
3188                                 ER(CR_IPSOCK_ERROR), saved_error);
3189       goto error;
3190     }
3191 
3192     if (status)
3193     {
3194       DBUG_PRINT("error",("Got error %d on connect to '%s'", saved_error, host));
3195       set_mysql_extended_error(mysql, CR_CONN_HOST_ERROR, unknown_sqlstate,
3196                                 ER(CR_CONN_HOST_ERROR), host, saved_error);
3197       goto error;
3198     }
3199   }
3200 
3201   DBUG_PRINT("info", ("net->vio: %p", net->vio));
3202   if (!net->vio)
3203   {
3204     DBUG_PRINT("error",("Unknow protocol %d ",mysql->options.protocol));
3205     set_mysql_error(mysql, CR_CONN_UNKNOW_PROTOCOL, unknown_sqlstate);
3206     goto error;
3207   }
3208 
3209   if (mysql->options.extension && mysql->options.extension->async_context)
3210     net->vio->async_context= mysql->options.extension->async_context;
3211 
3212   if (my_net_init(net, net->vio, _current_thd(), MYF(0)))
3213   {
3214     vio_delete(net->vio);
3215     net->vio = 0;
3216     set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
3217     goto error;
3218   }
3219   vio_keepalive(net->vio,TRUE);
3220 
3221   /* If user set read_timeout, let it override the default */
3222   if (mysql->options.read_timeout)
3223     my_net_set_read_timeout(net, mysql->options.read_timeout);
3224 
3225   /* If user set write_timeout, let it override the default */
3226   if (mysql->options.write_timeout)
3227     my_net_set_write_timeout(net, mysql->options.write_timeout);
3228 
3229   if (mysql->options.max_allowed_packet)
3230     net->max_packet_size= mysql->options.max_allowed_packet;
3231 
3232   /* Get version info */
3233   mysql->protocol_version= PROTOCOL_VERSION;	/* Assume this */
3234   if (mysql->options.connect_timeout &&
3235       (vio_io_wait(net->vio, VIO_IO_EVENT_READ,
3236                    get_vio_connect_timeout(mysql)) < 1))
3237   {
3238     set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
3239                              ER(CR_SERVER_LOST_EXTENDED),
3240                              "waiting for initial communication packet",
3241                              errno);
3242     goto error;
3243   }
3244 
3245   /*
3246     Part 1: Connection established, read and parse first packet
3247   */
3248   DBUG_PRINT("info", ("Read first packet."));
3249 
3250   if ((pkt_length=cli_safe_read(mysql)) == packet_error)
3251   {
3252     if (mysql->net.last_errno == CR_SERVER_LOST)
3253       set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
3254                                ER(CR_SERVER_LOST_EXTENDED),
3255                                "reading initial communication packet",
3256                                errno);
3257     goto error;
3258   }
3259   pkt_end= (char*)net->read_pos + pkt_length;
3260   /* Check if version of protocol matches current one */
3261   mysql->protocol_version= net->read_pos[0];
3262   DBUG_DUMP("packet",(uchar*) net->read_pos,10);
3263   DBUG_PRINT("info",("mysql protocol version %d, server=%d",
3264 		     PROTOCOL_VERSION, mysql->protocol_version));
3265   if (mysql->protocol_version != PROTOCOL_VERSION)
3266   {
3267     set_mysql_extended_error(mysql, CR_VERSION_ERROR, unknown_sqlstate,
3268                              ER(CR_VERSION_ERROR), mysql->protocol_version,
3269                              PROTOCOL_VERSION);
3270     goto error;
3271   }
3272   server_version_end= end= strend((char*) net->read_pos+1);
3273   mysql->thread_id=uint4korr(end+1);
3274   end+=5;
3275   /*
3276     Scramble is split into two parts because old clients do not understand
3277     long scrambles; here goes the first part.
3278   */
3279   scramble_data= end;
3280   scramble_data_len= SCRAMBLE_LENGTH_323 + 1;
3281   scramble_plugin= old_password_plugin_name;
3282   end+= scramble_data_len;
3283 
3284   if (pkt_end >= end + 1)
3285     mysql->server_capabilities=uint2korr(end);
3286   if (pkt_end >= end + 18)
3287   {
3288     /* New protocol with 16 bytes to describe server characteristics */
3289     mysql->server_language=end[2];
3290     mysql->server_status=uint2korr(end+3);
3291     mysql->server_capabilities|= ((unsigned) uint2korr(end+5)) << 16;
3292     pkt_scramble_len= end[7];
3293     if (pkt_scramble_len < 0)
3294     {
3295       set_mysql_error(mysql, CR_MALFORMED_PACKET,
3296                       unknown_sqlstate);        /* purecov: inspected */
3297       goto error;
3298     }
3299   }
3300   end+= 18;
3301 
3302   if (mysql->options.secure_auth && passwd[0] &&
3303       !(mysql->server_capabilities & CLIENT_SECURE_CONNECTION))
3304   {
3305     set_mysql_error(mysql, CR_SECURE_AUTH, unknown_sqlstate);
3306     goto error;
3307   }
3308 
3309   if (mysql_init_character_set(mysql))
3310     goto error;
3311 
3312   /* Save connection information */
3313   if (!my_multi_malloc(MYF(0),
3314 		       &mysql->host_info, (uint) strlen(host_info)+1,
3315 		       &mysql->host,      (uint) strlen(host)+1,
3316 		       &mysql->unix_socket,unix_socket ?
3317 		       (uint) strlen(unix_socket)+1 : (uint) 1,
3318 		       &mysql->server_version,
3319 		       (uint) (server_version_end - (char*) net->read_pos + 1),
3320 		       NullS) ||
3321       !(mysql->user=my_strdup(user,MYF(0))) ||
3322       !(mysql->passwd=my_strdup(passwd,MYF(0))))
3323   {
3324     set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
3325     goto error;
3326   }
3327   strmov(mysql->host_info,host_info);
3328   strmov(mysql->host,host);
3329   if (unix_socket)
3330     strmov(mysql->unix_socket,unix_socket);
3331   else
3332     mysql->unix_socket=0;
3333   strmov(mysql->server_version,(char*) net->read_pos+1);
3334   mysql->port=port;
3335 
3336   /*
3337     remove the rpl hack from the version string,
3338     see RPL_VERSION_HACK comment
3339   */
3340   if ((mysql->server_capabilities & CLIENT_PLUGIN_AUTH) &&
3341       strncmp(mysql->server_version, RPL_VERSION_HACK,
3342               sizeof(RPL_VERSION_HACK) - 1) == 0)
3343     mysql->server_version+= sizeof(RPL_VERSION_HACK) - 1;
3344 
3345   if (pkt_end >= end + SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323 + 1)
3346   {
3347     /*
3348      move the first scramble part - directly in the NET buffer -
3349      to get a full continuous scramble. We've read all the header,
3350      and can overwrite it now.
3351     */
3352     memmove(end - SCRAMBLE_LENGTH_323, scramble_data,
3353             SCRAMBLE_LENGTH_323);
3354     scramble_data= end - SCRAMBLE_LENGTH_323;
3355     if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH)
3356     {
3357       scramble_data_len= pkt_scramble_len;
3358       scramble_plugin= scramble_data + scramble_data_len;
3359       if (scramble_data + scramble_data_len > pkt_end)
3360       {
3361         set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
3362         goto error;
3363       }
3364     }
3365     else
3366     {
3367       scramble_data_len= (int)(pkt_end - scramble_data);
3368       scramble_plugin= native_password_plugin_name;
3369     }
3370   }
3371   else
3372     mysql->server_capabilities&= ~CLIENT_SECURE_CONNECTION;
3373 
3374   mysql->client_flag= client_flag;
3375 
3376   set_connect_attributes(mysql, buff, sizeof(buff));
3377 
3378   /*
3379     Part 2: invoke the plugin to send the authentication data to the server
3380   */
3381 
3382   if (run_plugin_auth(mysql, scramble_data, scramble_data_len,
3383                       scramble_plugin, db))
3384     goto error;
3385 
3386   /*
3387     Part 3: authenticated, finish the initialization of the connection
3388   */
3389 
3390   if (mysql->client_flag & CLIENT_COMPRESS)      /* We will use compression */
3391     net->compress=1;
3392 
3393   if (db && !mysql->db && mysql_select_db(mysql, db))
3394   {
3395     if (mysql->net.last_errno == CR_SERVER_LOST)
3396         set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
3397                                  ER(CR_SERVER_LOST_EXTENDED),
3398                                  "Setting intital database",
3399                                  errno);
3400     goto error;
3401   }
3402 
3403   /*
3404      Using init_commands is not supported when connecting from within the
3405      server.
3406   */
3407 #ifndef MYSQL_SERVER
3408   if (mysql->options.init_commands)
3409   {
3410     DYNAMIC_ARRAY *init_commands= mysql->options.init_commands;
3411     char **ptr= (char**)init_commands->buffer;
3412     char **end_command= ptr + init_commands->elements;
3413 
3414     my_bool reconnect=mysql->reconnect;
3415     mysql->reconnect=0;
3416 
3417     for (; ptr < end_command; ptr++)
3418     {
3419       int status;
3420 
3421       if (mysql_real_query(mysql,*ptr, (ulong) strlen(*ptr)))
3422 	goto error;
3423 
3424       do {
3425         if (mysql->fields)
3426         {
3427           MYSQL_RES *res;
3428           if (!(res= cli_use_result(mysql)))
3429             goto error;
3430           mysql_free_result(res);
3431         }
3432         if ((status= mysql_next_result(mysql)) > 0)
3433           goto error;
3434       } while (status == 0);
3435     }
3436     mysql->reconnect=reconnect;
3437   }
3438 #endif
3439 
3440   DBUG_PRINT("exit", ("Mysql handler: %p",mysql));
3441   DBUG_RETURN(mysql);
3442 
3443 error:
3444   DBUG_PRINT("error",("message: %u/%s (%s)",
3445                       net->last_errno,
3446                       net->sqlstate,
3447                       net->last_error));
3448   {
3449     /* Free alloced memory */
3450     end_server(mysql);
3451     mysql_close_free(mysql);
3452     if (!(client_flag & CLIENT_REMEMBER_OPTIONS) &&
3453         !(mysql->options.extension && mysql->options.extension->async_context))
3454       mysql_close_free_options(mysql);
3455   }
3456   DBUG_RETURN(0);
3457 }
3458 
3459 
3460 struct my_hook_data {
3461   MYSQL *orig_mysql;
3462   MYSQL *new_mysql;
3463   /* This is always NULL currently, but restoring does not hurt just in case. */
3464   Vio *orig_vio;
3465 };
3466 /*
3467   Callback hook to make the new VIO accessible via the old MYSQL to calling
3468   application when suspending a non-blocking call during automatic reconnect.
3469 */
3470 static void
my_suspend_hook(my_bool suspend,void * data)3471 my_suspend_hook(my_bool suspend, void *data)
3472 {
3473   struct my_hook_data *hook_data= (struct my_hook_data *)data;
3474   if (suspend)
3475   {
3476     hook_data->orig_vio= hook_data->orig_mysql->net.vio;
3477     hook_data->orig_mysql->net.vio= hook_data->new_mysql->net.vio;
3478   }
3479   else
3480     hook_data->orig_mysql->net.vio= hook_data->orig_vio;
3481 }
3482 
mysql_reconnect(MYSQL * mysql)3483 my_bool mysql_reconnect(MYSQL *mysql)
3484 {
3485   MYSQL tmp_mysql;
3486   struct my_hook_data hook_data;
3487   struct mysql_async_context *ctxt= NULL;
3488   DBUG_ENTER("mysql_reconnect");
3489   DBUG_ASSERT(mysql);
3490   DBUG_PRINT("enter", ("mysql->reconnect: %d", mysql->reconnect));
3491 
3492   if (!mysql->reconnect ||
3493       (mysql->server_status & SERVER_STATUS_IN_TRANS) || !mysql->host_info)
3494   {
3495     /* Allow reconnect next time */
3496     mysql->server_status&= ~SERVER_STATUS_IN_TRANS;
3497     set_mysql_error(mysql, CR_SERVER_GONE_ERROR, unknown_sqlstate);
3498     DBUG_RETURN(1);
3499   }
3500   mysql_init(&tmp_mysql);
3501   tmp_mysql.options= mysql->options;
3502   tmp_mysql.options.my_cnf_file= tmp_mysql.options.my_cnf_group= 0;
3503 
3504   /*
3505     If we are automatically re-connecting inside a non-blocking API call, we
3506     may need to suspend and yield to the user application during the reconnect.
3507     If so, the user application will need access to the new VIO already then
3508     so that it can correctly wait for I/O to become ready.
3509     To achieve this, we temporarily install a hook that will temporarily put in
3510     the VIO while we are suspended.
3511     (The vio will be put in the original MYSQL permanently once we successfully
3512     reconnect, or be discarded if we fail to reconnect.)
3513   */
3514   if (mysql->options.extension &&
3515       (ctxt= mysql->options.extension->async_context) &&
3516       mysql->options.extension->async_context->active)
3517   {
3518     hook_data.orig_mysql= mysql;
3519     hook_data.new_mysql= &tmp_mysql;
3520     hook_data.orig_vio= mysql->net.vio;
3521     my_context_install_suspend_resume_hook(ctxt, my_suspend_hook, &hook_data);
3522   }
3523   if (!mysql_real_connect(&tmp_mysql,mysql->host,mysql->user,mysql->passwd,
3524 			  mysql->db, mysql->port, mysql->unix_socket,
3525 			  mysql->client_flag | CLIENT_REMEMBER_OPTIONS))
3526   {
3527     if (ctxt)
3528       my_context_install_suspend_resume_hook(ctxt, NULL, NULL);
3529     mysql->net.last_errno= tmp_mysql.net.last_errno;
3530     strmov(mysql->net.last_error, tmp_mysql.net.last_error);
3531     strmov(mysql->net.sqlstate, tmp_mysql.net.sqlstate);
3532     DBUG_RETURN(1);
3533   }
3534   if (mysql_set_character_set(&tmp_mysql, mysql->charset->csname))
3535   {
3536     DBUG_PRINT("error", ("mysql_set_character_set() failed"));
3537     bzero((char*) &tmp_mysql.options,sizeof(tmp_mysql.options));
3538     mysql_close(&tmp_mysql);
3539     if (ctxt)
3540       my_context_install_suspend_resume_hook(ctxt, NULL, NULL);
3541     mysql->net.last_errno= tmp_mysql.net.last_errno;
3542     strmov(mysql->net.last_error, tmp_mysql.net.last_error);
3543     strmov(mysql->net.sqlstate, tmp_mysql.net.sqlstate);
3544     DBUG_RETURN(1);
3545   }
3546   if (ctxt)
3547     my_context_install_suspend_resume_hook(ctxt, NULL, NULL);
3548 
3549   DBUG_PRINT("info", ("reconnect succeeded"));
3550   tmp_mysql.reconnect= 1;
3551   tmp_mysql.free_me= mysql->free_me;
3552 
3553   /* Move prepared statements (if any) over to the new mysql object */
3554   tmp_mysql.stmts= mysql->stmts;
3555   mysql->stmts= 0;
3556 
3557   /* Don't free options as these are now used in tmp_mysql */
3558   bzero((char*) &mysql->options,sizeof(mysql->options));
3559   mysql->free_me=0;
3560   mysql_close(mysql);
3561   *mysql=tmp_mysql;
3562   net_clear(&mysql->net, 1);
3563   mysql->affected_rows= ~(my_ulonglong) 0;
3564   DBUG_RETURN(0);
3565 }
3566 
3567 
3568 /**************************************************************************
3569   Set current database
3570 **************************************************************************/
3571 
3572 int STDCALL
mysql_select_db(MYSQL * mysql,const char * db)3573 mysql_select_db(MYSQL *mysql, const char *db)
3574 {
3575   int error;
3576   DBUG_ENTER("mysql_select_db");
3577   DBUG_PRINT("enter",("db: '%s'",db));
3578 
3579   if ((error=simple_command(mysql,COM_INIT_DB, (const uchar*) db,
3580                             (ulong) strlen(db),0)))
3581     DBUG_RETURN(error);
3582   my_free(mysql->db);
3583   mysql->db=my_strdup(db,MYF(MY_WME));
3584   DBUG_RETURN(0);
3585 }
3586 
3587 
3588 /*************************************************************************
3589   Send a QUIT to the server and close the connection
3590   If handle is alloced by mysql connect free it.
3591 *************************************************************************/
3592 
mysql_close_free_options(MYSQL * mysql)3593 static void mysql_close_free_options(MYSQL *mysql)
3594 {
3595   DBUG_ENTER("mysql_close_free_options");
3596 
3597   my_free(mysql->options.user);
3598   my_free(mysql->options.host);
3599   my_free(mysql->options.password);
3600   my_free(mysql->options.unix_socket);
3601   my_free(mysql->options.db);
3602   my_free(mysql->options.my_cnf_file);
3603   my_free(mysql->options.my_cnf_group);
3604   my_free(mysql->options.charset_dir);
3605   my_free(mysql->options.charset_name);
3606   my_free(mysql->options.client_ip);
3607   if (mysql->options.init_commands)
3608   {
3609     DYNAMIC_ARRAY *init_commands= mysql->options.init_commands;
3610     char **ptr= (char**)init_commands->buffer;
3611     char **end= ptr + init_commands->elements;
3612     for (; ptr<end; ptr++)
3613       my_free(*ptr);
3614     delete_dynamic(init_commands);
3615     my_free(init_commands);
3616   }
3617 #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
3618   mysql_ssl_free(mysql);
3619 #endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */
3620 #ifdef HAVE_SMEM
3621   if (mysql->options.shared_memory_base_name != def_shared_memory_base_name)
3622     my_free(mysql->options.shared_memory_base_name);
3623 #endif /* HAVE_SMEM */
3624   if (mysql->options.extension)
3625   {
3626     struct mysql_async_context *ctxt= mysql->options.extension->async_context;
3627     my_free(mysql->options.extension->plugin_dir);
3628     my_free(mysql->options.extension->default_auth);
3629     my_hash_free(&mysql->options.extension->connection_attributes);
3630     if (ctxt)
3631     {
3632       my_context_destroy(&ctxt->async_context);
3633       my_free(ctxt);
3634     }
3635     my_free(mysql->options.extension);
3636   }
3637   bzero((char*) &mysql->options,sizeof(mysql->options));
3638   DBUG_VOID_RETURN;
3639 }
3640 
3641 
mysql_close_free(MYSQL * mysql)3642 static void mysql_close_free(MYSQL *mysql)
3643 {
3644   my_free(mysql->host_info);
3645   my_free(mysql->user);
3646   my_free(mysql->passwd);
3647   my_free(mysql->db);
3648 #if defined(EMBEDDED_LIBRARY) || MYSQL_VERSION_ID >= 50100
3649   my_free(mysql->info_buffer);
3650   mysql->info_buffer= 0;
3651 #endif
3652   /* Clear pointers for better safety */
3653   mysql->host_info= mysql->user= mysql->passwd= mysql->db= 0;
3654 }
3655 
3656 
3657 /**
3658   For use when the connection to the server has been lost (in which case
3659   the server has discarded all information about prepared statements
3660   associated with the connection).
3661 
3662   Mark all statements in mysql->stmts by setting stmt->mysql= 0 if the
3663   statement has transitioned beyond the MYSQL_STMT_INIT_DONE state, and
3664   unlink the statement from the mysql->stmts list.
3665 
3666   The remaining pruned list of statements (if any) is kept in mysql->stmts.
3667 
3668   @param mysql       pointer to the MYSQL object
3669 
3670   @return none
3671 */
mysql_prune_stmt_list(MYSQL * mysql)3672 static void mysql_prune_stmt_list(MYSQL *mysql)
3673 {
3674   LIST *element= mysql->stmts;
3675   for (; element; element= element->next)
3676   {
3677     MYSQL_STMT *stmt= (MYSQL_STMT *) element->data;
3678     if (stmt->state != MYSQL_STMT_INIT_DONE)
3679     {
3680       stmt->mysql= 0;
3681       stmt->last_errno= CR_SERVER_LOST;
3682       strmov(stmt->last_error, ER(CR_SERVER_LOST));
3683       strmov(stmt->sqlstate, unknown_sqlstate);
3684       mysql->stmts= list_delete(mysql->stmts, element);
3685     }
3686   }
3687 }
3688 
3689 
3690 /*
3691   Clear connection pointer of every statement: this is necessary
3692   to give error on attempt to use a prepared statement of closed
3693   connection.
3694 
3695   SYNOPSYS
3696     mysql_detach_stmt_list()
3697       stmt_list  pointer to mysql->stmts
3698       func_name  name of calling function
3699 
3700   NOTE
3701     There is similar code in mysql_reconnect(), so changes here
3702     should also be reflected there.
3703 */
3704 
mysql_detach_stmt_list(LIST ** stmt_list,const char * func_name)3705 void mysql_detach_stmt_list(LIST **stmt_list __attribute__((unused)),
3706                             const char *func_name __attribute__((unused)))
3707 {
3708 #ifdef MYSQL_CLIENT
3709   /* Reset connection handle in all prepared statements. */
3710   LIST *element= *stmt_list;
3711   char buff[MYSQL_ERRMSG_SIZE];
3712   DBUG_ENTER("mysql_detach_stmt_list");
3713 
3714   my_snprintf(buff, sizeof(buff)-1, ER(CR_STMT_CLOSED), func_name);
3715   for (; element; element= element->next)
3716   {
3717     MYSQL_STMT *stmt= (MYSQL_STMT *) element->data;
3718     set_stmt_error(stmt, CR_STMT_CLOSED, unknown_sqlstate, buff);
3719     stmt->mysql= 0;
3720     /* No need to call list_delete for statement here */
3721   }
3722   *stmt_list= 0;
3723   DBUG_VOID_RETURN;
3724 #endif /* MYSQL_CLIENT */
3725 }
3726 
3727 
3728 /*
3729   Close a MySQL connection and free all resources attached to it.
3730 
3731   This function is coded in such that it can be called multiple times
3732   (As some clients call this after mysql_real_connect() fails)
3733 */
3734 
3735 /*
3736   mysql_close() can actually block, at least in theory, if the socket buffer
3737   is full when sending the COM_QUIT command.
3738 
3739   On the other hand, the latter part of mysql_close() needs to free the stack
3740   used for non-blocking operation of blocking stuff, so that later part can
3741   _not_ be done non-blocking.
3742 
3743   Therefore, mysql_close_slow_part() is used to run the parts of mysql_close()
3744   that may block. It can be called before mysql_close(), and in that case
3745   mysql_close() is guaranteed not to need to block.  */
mysql_close_slow_part(MYSQL * mysql)3746 void STDCALL mysql_close_slow_part(MYSQL *mysql)
3747 {
3748   /* If connection is still up, send a QUIT message */
3749   if (mysql->net.vio != 0)
3750   {
3751     free_old_query(mysql);
3752     mysql->status=MYSQL_STATUS_READY; /* Force command */
3753     mysql->reconnect=0;
3754     simple_command(mysql,COM_QUIT,(uchar*) 0,0,1);
3755     end_server(mysql);			/* Sets mysql->net.vio= 0 */
3756   }
3757 }
3758 
mysql_close(MYSQL * mysql)3759 void STDCALL mysql_close(MYSQL *mysql)
3760 {
3761   DBUG_ENTER("mysql_close");
3762   DBUG_PRINT("enter", ("mysql: %p",  mysql));
3763 
3764   if (mysql)					/* Some simple safety */
3765   {
3766     mysql_close_slow_part(mysql);
3767     mysql_close_free_options(mysql);
3768     mysql_close_free(mysql);
3769     mysql_detach_stmt_list(&mysql->stmts, "mysql_close");
3770 #ifndef MYSQL_SERVER
3771     if (mysql->thd)
3772     {
3773       (*mysql->methods->free_embedded_thd)(mysql);
3774       mysql->thd= 0;
3775     }
3776 #endif
3777     if (mysql->free_me)
3778       my_free(mysql);
3779   }
3780   DBUG_VOID_RETURN;
3781 }
3782 
3783 
cli_read_query_result(MYSQL * mysql)3784 static my_bool cli_read_query_result(MYSQL *mysql)
3785 {
3786   uchar *pos;
3787   ulong field_count;
3788   MYSQL_DATA *fields;
3789   ulong length;
3790 #ifdef MYSQL_CLIENT
3791   my_bool can_local_infile= mysql->auto_local_infile != WAIT_FOR_QUERY;
3792 #endif
3793   DBUG_ENTER("cli_read_query_result");
3794 
3795   if (mysql->auto_local_infile == ACCEPT_FILE_REQUEST)
3796     mysql->auto_local_infile= WAIT_FOR_QUERY;
3797 
3798   if ((length = cli_safe_read(mysql)) == packet_error)
3799     DBUG_RETURN(1);
3800   free_old_query(mysql);		/* Free old result */
3801 #ifdef MYSQL_CLIENT			/* Avoid warn of unused labels*/
3802 get_info:
3803 #endif
3804   pos=(uchar*) mysql->net.read_pos;
3805   if ((field_count= net_field_length(&pos)) == 0)
3806   {
3807     mysql->affected_rows= net_field_length_ll(&pos);
3808     mysql->insert_id=	  net_field_length_ll(&pos);
3809     DBUG_PRINT("info",("affected_rows: %lu  insert_id: %lu",
3810 		       (ulong) mysql->affected_rows,
3811 		       (ulong) mysql->insert_id));
3812     if (protocol_41(mysql))
3813     {
3814       mysql->server_status=uint2korr(pos); pos+=2;
3815       mysql->warning_count=uint2korr(pos); pos+=2;
3816     }
3817     else if (mysql->server_capabilities & CLIENT_TRANSACTIONS)
3818     {
3819       /* MySQL 4.0 protocol */
3820       mysql->server_status=uint2korr(pos); pos+=2;
3821       mysql->warning_count= 0;
3822     }
3823     DBUG_PRINT("info",("status: %u  warning_count: %u",
3824 		       mysql->server_status, mysql->warning_count));
3825     if (pos < mysql->net.read_pos+length && net_field_length(&pos))
3826       mysql->info=(char*) pos;
3827     DBUG_RETURN(0);
3828   }
3829 #ifdef MYSQL_CLIENT
3830   if (field_count == NULL_LENGTH)		/* LOAD DATA LOCAL INFILE */
3831   {
3832     int error;
3833 
3834     if (!(mysql->options.client_flag & CLIENT_LOCAL_FILES) ||
3835         !can_local_infile)
3836     {
3837       set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
3838       DBUG_RETURN(1);
3839     }
3840 
3841     error= handle_local_infile(mysql,(char*) pos);
3842     if ((length= cli_safe_read(mysql)) == packet_error || error)
3843       DBUG_RETURN(1);
3844     goto get_info;				/* Get info packet */
3845   }
3846 #endif
3847   if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT))
3848     mysql->server_status|= SERVER_STATUS_IN_TRANS;
3849 
3850   if (!(fields=cli_read_rows(mysql,(MYSQL_FIELD*)0, protocol_41(mysql) ? 7:5)))
3851     DBUG_RETURN(1);
3852   if (!(mysql->fields=unpack_fields(mysql, fields,&mysql->field_alloc,
3853 				    (uint) field_count,0,
3854 				    mysql->server_capabilities)))
3855     DBUG_RETURN(1);
3856   mysql->status= MYSQL_STATUS_GET_RESULT;
3857   mysql->field_count= (uint) field_count;
3858   DBUG_PRINT("exit",("ok"));
3859   DBUG_RETURN(0);
3860 }
3861 
3862 
3863 /*
3864   Send the query and return so we can do something else.
3865   Needs to be followed by mysql_read_query_result() when we want to
3866   finish processing it.
3867 */
3868 
3869 int STDCALL
mysql_send_query(MYSQL * mysql,const char * query,ulong length)3870 mysql_send_query(MYSQL* mysql, const char* query, ulong length)
3871 {
3872   DBUG_ENTER("mysql_send_query");
3873   if (mysql->options.client_flag & CLIENT_LOCAL_FILES &&
3874       mysql->auto_local_infile == WAIT_FOR_QUERY &&
3875       (*query == 'l' || *query == 'L'))
3876   {
3877     if (strncasecmp(query, STRING_WITH_LEN("load")) == 0)
3878       mysql->auto_local_infile= ACCEPT_FILE_REQUEST;
3879   }
3880   DBUG_RETURN(simple_command(mysql, COM_QUERY, (uchar*) query, length, 1));
3881 }
3882 
3883 int STDCALL
mysql_real_query(MYSQL * mysql,const char * query,ulong length)3884 mysql_real_query(MYSQL *mysql, const char *query, ulong length)
3885 {
3886   DBUG_ENTER("mysql_real_query");
3887   DBUG_PRINT("enter",("handle: %p", mysql));
3888   DBUG_PRINT("query",("Query = '%-.4096s'",query));
3889 
3890   if (mysql_send_query(mysql,query,length))
3891     DBUG_RETURN(1);
3892   DBUG_RETURN((int) (*mysql->methods->read_query_result)(mysql));
3893 }
3894 
3895 
3896 /**************************************************************************
3897   Alloc result struct for buffered results. All rows are read to buffer.
3898   mysql_data_seek may be used.
3899 **************************************************************************/
3900 
mysql_store_result(MYSQL * mysql)3901 MYSQL_RES * STDCALL mysql_store_result(MYSQL *mysql)
3902 {
3903   MYSQL_RES *result;
3904   DBUG_ENTER("mysql_store_result");
3905 
3906   if (!mysql->fields)
3907     DBUG_RETURN(0);
3908   if (mysql->status != MYSQL_STATUS_GET_RESULT)
3909   {
3910     set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
3911     DBUG_RETURN(0);
3912   }
3913   mysql->status=MYSQL_STATUS_READY;		/* server is ready */
3914   if (!(result=(MYSQL_RES*) my_malloc((uint) (sizeof(MYSQL_RES)+
3915 					      sizeof(ulong) *
3916 					      mysql->field_count),
3917 				      MYF(MY_WME | MY_ZEROFILL))))
3918   {
3919     set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
3920     DBUG_RETURN(0);
3921   }
3922   result->methods= mysql->methods;
3923   result->eof=1;				/* Marker for buffered */
3924   result->lengths=(ulong*) (result+1);
3925   if (!(result->data=
3926 	(*mysql->methods->read_rows)(mysql,mysql->fields,mysql->field_count)))
3927   {
3928     my_free(result);
3929     DBUG_RETURN(0);
3930   }
3931   mysql->affected_rows= result->row_count= result->data->rows;
3932   result->data_cursor=	result->data->data;
3933   result->fields=	mysql->fields;
3934   result->field_alloc=	mysql->field_alloc;
3935   result->field_count=	mysql->field_count;
3936   /* The rest of result members is bzeroed in malloc */
3937   mysql->fields=0;				/* fields is now in result */
3938   clear_alloc_root(&mysql->field_alloc);
3939   /* just in case this was mistakenly called after mysql_stmt_execute() */
3940   mysql->unbuffered_fetch_owner= 0;
3941   DBUG_RETURN(result);				/* Data fetched */
3942 }
3943 
3944 
3945 /**************************************************************************
3946   Alloc struct for use with unbuffered reads. Data is fetched by domand
3947   when calling to mysql_fetch_row.
3948   mysql_data_seek is a noop.
3949 
3950   No other queries may be specified with the same MYSQL handle.
3951   There shouldn't be much processing per row because mysql server shouldn't
3952   have to wait for the client (and will not wait more than 30 sec/packet).
3953 **************************************************************************/
3954 
cli_use_result(MYSQL * mysql)3955 static MYSQL_RES * cli_use_result(MYSQL *mysql)
3956 {
3957   MYSQL_RES *result;
3958   DBUG_ENTER("cli_use_result");
3959 
3960   if (!mysql->fields)
3961     DBUG_RETURN(0);
3962   if (mysql->status != MYSQL_STATUS_GET_RESULT)
3963   {
3964     set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
3965     DBUG_RETURN(0);
3966   }
3967   if (!(result=(MYSQL_RES*) my_malloc(sizeof(*result)+
3968 				      sizeof(ulong)*mysql->field_count,
3969 				      MYF(MY_WME | MY_ZEROFILL))))
3970     DBUG_RETURN(0);
3971   result->lengths=(ulong*) (result+1);
3972   result->methods= mysql->methods;
3973   if (!(result->row=(MYSQL_ROW)
3974 	my_malloc(sizeof(result->row[0])*(mysql->field_count+1), MYF(MY_WME))))
3975   {					/* Ptrs: to one row */
3976     my_free(result);
3977     DBUG_RETURN(0);
3978   }
3979   result->fields=	mysql->fields;
3980   result->field_alloc=	mysql->field_alloc;
3981   result->field_count=	mysql->field_count;
3982   result->current_field=0;
3983   result->handle=	mysql;
3984   result->current_row=	0;
3985   mysql->fields=0;			/* fields is now in result */
3986   clear_alloc_root(&mysql->field_alloc);
3987   mysql->status=MYSQL_STATUS_USE_RESULT;
3988   mysql->unbuffered_fetch_owner= &result->unbuffered_fetch_cancelled;
3989   DBUG_RETURN(result);			/* Data is read to be fetched */
3990 }
3991 
3992 
3993 /**************************************************************************
3994   Return next row of the query results
3995 **************************************************************************/
3996 
3997 MYSQL_ROW STDCALL
mysql_fetch_row(MYSQL_RES * res)3998 mysql_fetch_row(MYSQL_RES *res)
3999 {
4000   DBUG_ENTER("mysql_fetch_row");
4001   if (!res->data)
4002   {						/* Unbufferred fetch */
4003     if (!res->eof)
4004     {
4005       MYSQL *mysql= res->handle;
4006       if (mysql->status != MYSQL_STATUS_USE_RESULT)
4007       {
4008         set_mysql_error(mysql,
4009                         res->unbuffered_fetch_cancelled ?
4010                         CR_FETCH_CANCELED : CR_COMMANDS_OUT_OF_SYNC,
4011                         unknown_sqlstate);
4012       }
4013       else if (!(read_one_row(mysql, res->field_count, res->row, res->lengths)))
4014       {
4015 	res->row_count++;
4016 	DBUG_RETURN(res->current_row=res->row);
4017       }
4018       DBUG_PRINT("info",("end of data"));
4019       res->eof=1;
4020       mysql->status=MYSQL_STATUS_READY;
4021       /*
4022         Reset only if owner points to us: there is a chance that somebody
4023         started new query after mysql_stmt_close():
4024       */
4025       if (mysql->unbuffered_fetch_owner == &res->unbuffered_fetch_cancelled)
4026         mysql->unbuffered_fetch_owner= 0;
4027       /* Don't clear handle in mysql_free_result */
4028       res->handle=0;
4029     }
4030     DBUG_RETURN((MYSQL_ROW) NULL);
4031   }
4032   {
4033     MYSQL_ROW tmp;
4034     if (!res->data_cursor)
4035     {
4036       DBUG_PRINT("info",("end of data"));
4037       DBUG_RETURN(res->current_row=(MYSQL_ROW) NULL);
4038     }
4039     tmp = res->data_cursor->data;
4040     res->data_cursor = res->data_cursor->next;
4041     DBUG_RETURN(res->current_row=tmp);
4042   }
4043 }
4044 
4045 
4046 /**************************************************************************
4047   Get column lengths of the current row
4048   If one uses mysql_use_result, res->lengths contains the length information,
4049   else the lengths are calculated from the offset between pointers.
4050 **************************************************************************/
4051 
4052 ulong * STDCALL
mysql_fetch_lengths(MYSQL_RES * res)4053 mysql_fetch_lengths(MYSQL_RES *res)
4054 {
4055   MYSQL_ROW column;
4056 
4057   if (!(column=res->current_row))
4058     return 0;					/* Something is wrong */
4059   if (res->data)
4060     (*res->methods->fetch_lengths)(res->lengths, column, res->field_count);
4061   return res->lengths;
4062 }
4063 
4064 
4065 #define ASYNC_CONTEXT_DEFAULT_STACK_SIZE (4096*15)
4066 
4067 int STDCALL
mysql_options(MYSQL * mysql,enum mysql_option option,const void * arg)4068 mysql_options(MYSQL *mysql,enum mysql_option option, const void *arg)
4069 {
4070   struct mysql_async_context *ctxt;
4071   size_t stacksize;
4072 
4073   DBUG_ENTER("mysql_options");
4074   DBUG_PRINT("enter",("option: %d",(int) option));
4075   switch (option) {
4076   case MYSQL_OPT_CONNECT_TIMEOUT:
4077     mysql->options.connect_timeout= *(uint*) arg;
4078     break;
4079   case MYSQL_OPT_READ_TIMEOUT:
4080     mysql->options.read_timeout= *(uint*) arg;
4081     break;
4082   case MYSQL_OPT_WRITE_TIMEOUT:
4083     mysql->options.write_timeout= *(uint*) arg;
4084     break;
4085   case MYSQL_OPT_COMPRESS:
4086     mysql->options.compress= 1;			/* Remember for connect */
4087     mysql->options.client_flag|= CLIENT_COMPRESS;
4088     break;
4089   case MYSQL_OPT_NAMED_PIPE:			/* This option is depricated */
4090     mysql->options.protocol=MYSQL_PROTOCOL_PIPE; /* Force named pipe */
4091     break;
4092   case MYSQL_OPT_LOCAL_INFILE:			/* Allow LOAD DATA LOCAL ?*/
4093     if (!arg || *(uint*) arg)
4094       mysql->options.client_flag|= CLIENT_LOCAL_FILES;
4095     else
4096       mysql->options.client_flag&= ~CLIENT_LOCAL_FILES;
4097     mysql->auto_local_infile= arg && *(uint*)arg == LOCAL_INFILE_MODE_AUTO
4098                               ? WAIT_FOR_QUERY : ALWAYS_ACCEPT;
4099     break;
4100   case MYSQL_INIT_COMMAND:
4101     add_init_command(&mysql->options,arg);
4102     break;
4103   case MYSQL_READ_DEFAULT_FILE:
4104     my_free(mysql->options.my_cnf_file);
4105     mysql->options.my_cnf_file=my_strdup(arg,MYF(MY_WME));
4106     break;
4107   case MYSQL_READ_DEFAULT_GROUP:
4108     my_free(mysql->options.my_cnf_group);
4109     mysql->options.my_cnf_group=my_strdup(arg,MYF(MY_WME));
4110     break;
4111   case MYSQL_SET_CHARSET_DIR:
4112     my_free(mysql->options.charset_dir);
4113     mysql->options.charset_dir=my_strdup(arg,MYF(MY_WME));
4114     break;
4115   case MYSQL_SET_CHARSET_NAME:
4116     my_free(mysql->options.charset_name);
4117     mysql->options.charset_name=my_strdup(arg,MYF(MY_WME));
4118     break;
4119   case MYSQL_OPT_PROTOCOL:
4120     mysql->options.protocol= *(uint*) arg;
4121     break;
4122   case MYSQL_SHARED_MEMORY_BASE_NAME:
4123 #ifdef HAVE_SMEM
4124     if (mysql->options.shared_memory_base_name != def_shared_memory_base_name)
4125       my_free(mysql->options.shared_memory_base_name);
4126     mysql->options.shared_memory_base_name=my_strdup(arg,MYF(MY_WME));
4127 #endif
4128     break;
4129   case MYSQL_OPT_USE_REMOTE_CONNECTION:
4130   case MYSQL_OPT_USE_EMBEDDED_CONNECTION:
4131   case MYSQL_OPT_GUESS_CONNECTION:
4132     mysql->options.methods_to_use= option;
4133     break;
4134   case MYSQL_SET_CLIENT_IP:
4135     my_free(mysql->options.client_ip);
4136     mysql->options.client_ip= my_strdup(arg, MYF(MY_WME));
4137     break;
4138   case MYSQL_SECURE_AUTH:
4139     mysql->options.secure_auth= *(my_bool *) arg;
4140     break;
4141   case MYSQL_REPORT_DATA_TRUNCATION:
4142     mysql->options.report_data_truncation= MY_TEST(*(my_bool*) arg);
4143     break;
4144   case MYSQL_OPT_RECONNECT:
4145     mysql->reconnect= *(my_bool *) arg;
4146     break;
4147   case MYSQL_OPT_USE_THREAD_SPECIFIC_MEMORY:
4148     mysql->options.use_thread_specific_memory= *(my_bool *) arg;
4149     break;
4150   case MYSQL_OPT_SSL_VERIFY_SERVER_CERT:
4151     if (*(my_bool*) arg)
4152       mysql->options.client_flag|= CLIENT_SSL_VERIFY_SERVER_CERT;
4153     else
4154       mysql->options.client_flag&= ~CLIENT_SSL_VERIFY_SERVER_CERT;
4155     break;
4156   case MYSQL_PLUGIN_DIR:
4157     EXTENSION_SET_STRING(&mysql->options, plugin_dir, arg);
4158     break;
4159   case MYSQL_DEFAULT_AUTH:
4160     EXTENSION_SET_STRING(&mysql->options, default_auth, arg);
4161     break;
4162   case MYSQL_ENABLE_CLEARTEXT_PLUGIN:
4163     break;
4164   case MYSQL_PROGRESS_CALLBACK:
4165     if (!mysql->options.extension)
4166       mysql->options.extension= (struct st_mysql_options_extention *)
4167         my_malloc(sizeof(struct st_mysql_options_extention),
4168                   MYF(MY_WME | MY_ZEROFILL));
4169     if (mysql->options.extension)
4170       mysql->options.extension->report_progress=
4171         (void (*)(const MYSQL *, uint, uint, double, const char *, uint)) arg;
4172     break;
4173   case MYSQL_OPT_NONBLOCK:
4174     if (mysql->options.extension &&
4175         (ctxt = mysql->options.extension->async_context) != 0)
4176     {
4177       /*
4178         We must not allow changing the stack size while a non-blocking call is
4179         suspended (as the stack is then in use).
4180       */
4181       if (ctxt->suspended)
4182         DBUG_RETURN(1);
4183       my_context_destroy(&ctxt->async_context);
4184       my_free(ctxt);
4185     }
4186     if (!(ctxt= (struct mysql_async_context *)
4187           my_malloc(sizeof(*ctxt), MYF(MY_ZEROFILL))))
4188     {
4189       set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
4190       DBUG_RETURN(1);
4191     }
4192     stacksize= 0;
4193     if (arg)
4194       stacksize= *(const size_t *)arg;
4195     if (!stacksize)
4196       stacksize= ASYNC_CONTEXT_DEFAULT_STACK_SIZE;
4197     if (my_context_init(&ctxt->async_context, stacksize))
4198     {
4199       set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
4200       my_free(ctxt);
4201       DBUG_RETURN(1);
4202     }
4203     ENSURE_EXTENSIONS_PRESENT(&(mysql->options));
4204     mysql->options.extension->async_context= ctxt;
4205     if (mysql->net.vio)
4206       mysql->net.vio->async_context= ctxt;
4207     break;
4208   case MYSQL_OPT_SSL_KEY:
4209     SET_SSL_PATH_OPTION(&mysql->options,ssl_key, arg);
4210     break;
4211   case MYSQL_OPT_SSL_CERT:
4212     SET_SSL_PATH_OPTION(&mysql->options, ssl_cert, arg);
4213     break;
4214   case MYSQL_OPT_SSL_CA:
4215     SET_SSL_PATH_OPTION(&mysql->options,ssl_ca, arg);
4216     break;
4217   case MYSQL_OPT_SSL_CAPATH:
4218     SET_SSL_PATH_OPTION(&mysql->options,ssl_capath, arg);
4219     break;
4220   case MYSQL_OPT_SSL_CIPHER:
4221     SET_SSL_OPTION(&mysql->options,ssl_cipher, arg);
4222     break;
4223   case MYSQL_OPT_SSL_CRL:
4224     EXTENSION_SET_SSL_PATH_STRING(&mysql->options, ssl_crl, arg);
4225     break;
4226   case MYSQL_OPT_SSL_CRLPATH:
4227     EXTENSION_SET_SSL_PATH_STRING(&mysql->options, ssl_crlpath, arg);
4228     break;
4229   case MYSQL_OPT_CONNECT_ATTR_RESET:
4230     ENSURE_EXTENSIONS_PRESENT(&mysql->options);
4231     if (my_hash_inited(&mysql->options.extension->connection_attributes))
4232     {
4233       my_hash_free(&mysql->options.extension->connection_attributes);
4234       mysql->options.extension->connection_attributes_length= 0;
4235     }
4236     break;
4237   case MYSQL_OPT_CONNECT_ATTR_DELETE:
4238     ENSURE_EXTENSIONS_PRESENT(&mysql->options);
4239     if (my_hash_inited(&mysql->options.extension->connection_attributes))
4240     {
4241       size_t len;
4242       uchar *elt;
4243 
4244       len= arg ? strlen(arg) : 0;
4245 
4246       if (len)
4247       {
4248         elt= my_hash_search(&mysql->options.extension->connection_attributes,
4249                             arg, len);
4250         if (elt)
4251         {
4252           LEX_STRING *attr= (LEX_STRING *) elt;
4253           LEX_STRING *key= attr, *value= attr + 1;
4254 
4255           mysql->options.extension->connection_attributes_length-=
4256             get_length_store_length(key->length) + key->length +
4257             get_length_store_length(value->length) + value->length;
4258 
4259           my_hash_delete(&mysql->options.extension->connection_attributes,
4260                          elt);
4261 
4262         }
4263       }
4264     }
4265     break;
4266   default:
4267     break;
4268     DBUG_RETURN(1);
4269   }
4270   DBUG_RETURN(0);
4271 }
4272 /**
4273   A function to return the key from a connection attribute
4274 */
4275 uchar *
get_attr_key(LEX_STRING * part,size_t * length,my_bool not_used)4276 get_attr_key(LEX_STRING *part, size_t *length,
4277              my_bool not_used __attribute__((unused)))
4278 {
4279   *length= part[0].length;
4280   return (uchar *) part[0].str;
4281 }
4282 
4283 int STDCALL
mysql_options4(MYSQL * mysql,enum mysql_option option,const void * arg1,const void * arg2)4284 mysql_options4(MYSQL *mysql,enum mysql_option option,
4285                const void *arg1, const void *arg2)
4286 {
4287   DBUG_ENTER("mysql_option");
4288   DBUG_PRINT("enter",("option: %d",(int) option));
4289 
4290   switch (option)
4291   {
4292   case MYSQL_OPT_CONNECT_ATTR_ADD:
4293     {
4294       LEX_STRING *elt;
4295       char *key, *value;
4296       size_t key_len= arg1 ? strlen(arg1) : 0,
4297              value_len= arg2 ? strlen(arg2) : 0;
4298       size_t attr_storage_length= key_len + value_len;
4299 
4300       /* we can't have a zero length key */
4301       if (!key_len)
4302       {
4303         set_mysql_error(mysql, CR_INVALID_PARAMETER_NO, unknown_sqlstate);
4304         DBUG_RETURN(1);
4305       }
4306 
4307       /* calculate the total storage length of the attribute */
4308       attr_storage_length+= get_length_store_length(key_len);
4309       attr_storage_length+= get_length_store_length(value_len);
4310 
4311       ENSURE_EXTENSIONS_PRESENT(&mysql->options);
4312 
4313       /*
4314         Throw and error if the maximum combined length of the attribute value
4315         will be greater than the maximum that we can safely transmit.
4316       */
4317       if (attr_storage_length +
4318           mysql->options.extension->connection_attributes_length >
4319           MAX_CONNECTION_ATTR_STORAGE_LENGTH)
4320       {
4321         set_mysql_error(mysql, CR_INVALID_PARAMETER_NO, unknown_sqlstate);
4322         DBUG_RETURN(1);
4323       }
4324 
4325       if (!my_hash_inited(&mysql->options.extension->connection_attributes))
4326       {
4327         if (my_hash_init(&mysql->options.extension->connection_attributes,
4328                      &my_charset_bin, 0, 0, 0, (my_hash_get_key) get_attr_key,
4329                      my_free, HASH_UNIQUE))
4330         {
4331           set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
4332           DBUG_RETURN(1);
4333         }
4334       }
4335       if (!my_multi_malloc(MY_WME,
4336                            &elt, 2 * sizeof(LEX_STRING),
4337                            &key, key_len + 1,
4338                            &value, value_len + 1,
4339                            NULL))
4340       {
4341         set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
4342         DBUG_RETURN(1);
4343       }
4344       elt[0].str= key; elt[0].length= key_len;
4345       elt[1].str= value; elt[1].length= value_len;
4346       if (key_len)
4347         memcpy(key, arg1, key_len);
4348       key[key_len]= 0;
4349       if (value_len)
4350         memcpy(value, arg2, value_len);
4351       value[value_len]= 0;
4352       if (my_hash_insert(&mysql->options.extension->connection_attributes,
4353                      (uchar *) elt))
4354       {
4355         /* can't insert the value */
4356         my_free(elt);
4357         set_mysql_error(mysql, CR_DUPLICATE_CONNECTION_ATTR,
4358                         unknown_sqlstate);
4359         DBUG_RETURN(1);
4360       }
4361 
4362       mysql->options.extension->connection_attributes_length+=
4363         attr_storage_length;
4364 
4365       break;
4366     }
4367 
4368   default:
4369     DBUG_RETURN(1);
4370   }
4371   DBUG_RETURN(0);
4372 }
4373 
4374 
4375 /****************************************************************************
4376   Functions to get information from the MySQL structure
4377   These are functions to make shared libraries more usable.
4378 ****************************************************************************/
4379 
4380 /* MYSQL_RES */
mysql_num_rows(MYSQL_RES * res)4381 my_ulonglong STDCALL mysql_num_rows(MYSQL_RES *res)
4382 {
4383   return res->row_count;
4384 }
4385 
mysql_num_fields(MYSQL_RES * res)4386 unsigned int STDCALL mysql_num_fields(MYSQL_RES *res)
4387 {
4388   return res->field_count;
4389 }
4390 
mysql_errno(MYSQL * mysql)4391 uint STDCALL mysql_errno(MYSQL *mysql)
4392 {
4393   return mysql ? mysql->net.last_errno : mysql_server_last_errno;
4394 }
4395 
4396 
mysql_error(MYSQL * mysql)4397 const char * STDCALL mysql_error(MYSQL *mysql)
4398 {
4399   return mysql ? mysql->net.last_error : mysql_server_last_error;
4400 }
4401 
4402 
4403 /*
4404   Get version number for server in a form easy to test on
4405 
4406   SYNOPSIS
4407     mysql_get_server_version()
4408     mysql		Connection
4409 
4410   EXAMPLE
4411     MariaDB-4.1.0-alfa ->  40100
4412 
4413   NOTES
4414     We will ensure that a newer server always has a bigger number.
4415 
4416   RETURN
4417    Signed number > 323000
4418    Zero if there is no connection
4419 */
4420 
4421 ulong STDCALL
mysql_get_server_version(MYSQL * mysql)4422 mysql_get_server_version(MYSQL *mysql)
4423 {
4424   ulong major= 0, minor= 0, version= 0;
4425 
4426   if (mysql->server_version)
4427   {
4428     const char *pos= mysql->server_version;
4429     char *end_pos;
4430     /* Skip possible prefix */
4431     while (*pos && !my_isdigit(&my_charset_latin1, *pos))
4432       pos++;
4433     major=   strtoul(pos, &end_pos, 10);	pos=end_pos+1;
4434     minor=   strtoul(pos, &end_pos, 10);	pos=end_pos+1;
4435     version= strtoul(pos, &end_pos, 10);
4436   }
4437   else
4438   {
4439     set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
4440   }
4441 
4442   return major*10000 + minor*100 + version;
4443 }
4444 
4445 
4446 /*
4447    mysql_set_character_set function sends SET NAMES cs_name to
4448    the server (which changes character_set_client, character_set_result
4449    and character_set_connection) and updates mysql->charset so other
4450    functions like mysql_real_escape will work correctly.
4451 */
mysql_set_character_set(MYSQL * mysql,const char * cs_name)4452 int STDCALL mysql_set_character_set(MYSQL *mysql, const char *cs_name)
4453 {
4454   CHARSET_INFO *cs;
4455   const char *save_csdir= charsets_dir;
4456 
4457   if (mysql->options.charset_dir)
4458     charsets_dir= mysql->options.charset_dir;
4459 
4460   if (strlen(cs_name) < MY_CS_NAME_SIZE &&
4461      (cs= get_charset_by_csname(cs_name, MY_CS_PRIMARY, MYF(0))))
4462   {
4463     char buff[MY_CS_NAME_SIZE + 10];
4464     charsets_dir= save_csdir;
4465     /* Skip execution of "SET NAMES" for pre-4.1 servers */
4466     if (mysql_get_server_version(mysql) < 40100)
4467       return 0;
4468     sprintf(buff, "SET NAMES %s", cs_name);
4469     if (!mysql_real_query(mysql, buff, (uint) strlen(buff)))
4470     {
4471       mysql->charset= cs;
4472     }
4473   }
4474   else
4475   {
4476     char cs_dir_name[FN_REFLEN];
4477     get_charsets_dir(cs_dir_name);
4478     set_mysql_extended_error(mysql, CR_CANT_READ_CHARSET, unknown_sqlstate,
4479                              ER(CR_CANT_READ_CHARSET), cs_name, cs_dir_name);
4480   }
4481   charsets_dir= save_csdir;
4482   return mysql->net.last_errno;
4483 }
4484 
4485 /**
4486   client authentication plugin that does native MySQL authentication
4487   using a 20-byte (4.1+) scramble
4488 */
native_password_auth_client(MYSQL_PLUGIN_VIO * vio,MYSQL * mysql)4489 static int native_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
4490 {
4491   int pkt_len;
4492   uchar *pkt;
4493 
4494   DBUG_ENTER("native_password_auth_client");
4495 
4496 
4497   if (((MCPVIO_EXT *)vio)->mysql_change_user)
4498   {
4499     /*
4500       in mysql_change_user() the client sends the first packet.
4501       we use the old scramble.
4502     */
4503     pkt= (uchar*)mysql->scramble;
4504     pkt_len= SCRAMBLE_LENGTH + 1;
4505   }
4506   else
4507   {
4508     /* read the scramble */
4509     if ((pkt_len= vio->read_packet(vio, &pkt)) < 0)
4510       DBUG_RETURN(CR_ERROR);
4511 
4512     if (pkt_len != SCRAMBLE_LENGTH + 1)
4513       DBUG_RETURN(CR_SERVER_HANDSHAKE_ERR);
4514 
4515     /* save it in MYSQL */
4516     memcpy(mysql->scramble, pkt, SCRAMBLE_LENGTH);
4517     mysql->scramble[SCRAMBLE_LENGTH] = 0;
4518   }
4519 
4520   if (mysql->passwd[0])
4521   {
4522     char scrambled[SCRAMBLE_LENGTH + 1];
4523     DBUG_PRINT("info", ("sending scramble"));
4524     scramble(scrambled, (char*)pkt, mysql->passwd);
4525     if (vio->write_packet(vio, (uchar*)scrambled, SCRAMBLE_LENGTH))
4526       DBUG_RETURN(CR_ERROR);
4527   }
4528   else
4529   {
4530     DBUG_PRINT("info", ("no password"));
4531     if (vio->write_packet(vio, 0, 0)) /* no password */
4532       DBUG_RETURN(CR_ERROR);
4533   }
4534 
4535   DBUG_RETURN(CR_OK);
4536 }
4537 
4538 /**
4539   client authentication plugin that does old MySQL authentication
4540   using an 8-byte (4.0-) scramble
4541 */
old_password_auth_client(MYSQL_PLUGIN_VIO * vio,MYSQL * mysql)4542 static int old_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
4543 {
4544   uchar *pkt;
4545   int pkt_len;
4546 
4547   DBUG_ENTER("old_password_auth_client");
4548 
4549   if (((MCPVIO_EXT *)vio)->mysql_change_user)
4550   {
4551     /*
4552       in mysql_change_user() the client sends the first packet.
4553       we use the old scramble.
4554     */
4555     pkt= (uchar*)mysql->scramble;
4556     pkt_len= SCRAMBLE_LENGTH_323 + 1;
4557   }
4558   else
4559   {
4560     /* read the scramble */
4561     if ((pkt_len= vio->read_packet(vio, &pkt)) < 0)
4562       DBUG_RETURN(CR_ERROR);
4563 
4564     if (pkt_len != SCRAMBLE_LENGTH_323 + 1 &&
4565         pkt_len != SCRAMBLE_LENGTH + 1)
4566         DBUG_RETURN(CR_SERVER_HANDSHAKE_ERR);
4567 
4568     /* save it in MYSQL */
4569     memmove(mysql->scramble, pkt, pkt_len - 1);
4570     mysql->scramble[pkt_len - 1] = 0;
4571   }
4572 
4573   if (mysql->passwd[0])
4574   {
4575     char scrambled[SCRAMBLE_LENGTH_323 + 1];
4576     scramble_323(scrambled, (char*)pkt, mysql->passwd);
4577     if (vio->write_packet(vio, (uchar*)scrambled, SCRAMBLE_LENGTH_323 + 1))
4578       DBUG_RETURN(CR_ERROR);
4579   }
4580   else
4581     if (vio->write_packet(vio, 0, 0)) /* no password */
4582       DBUG_RETURN(CR_ERROR);
4583 
4584   DBUG_RETURN(CR_OK);
4585 }
4586 
4587 
4588 my_socket STDCALL
mysql_get_socket(const MYSQL * mysql)4589 mysql_get_socket(const MYSQL *mysql)
4590 {
4591   if (mysql->net.vio)
4592     return vio_fd(mysql->net.vio);
4593   return INVALID_SOCKET;
4594 }
4595 
4596 
mysql_cancel(MYSQL * mysql)4597 int STDCALL mysql_cancel(MYSQL *mysql)
4598 {
4599   if (mysql->net.vio)
4600 	return vio_shutdown(mysql->net.vio, SHUT_RDWR);
4601   return -1;
4602 }
4603