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