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