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