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